From 52d87368c99e8ceca72d7544e1dbae435143b62e Mon Sep 17 00:00:00 2001 From: loki5512344 Date: Fri, 31 Jul 2026 23:14:14 +0200 Subject: [PATCH] chore(history): squash 10 commit(s) from 2026-07-31 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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) --- .gitignore | 2 +- TODO.md | 264 +- backend/Cargo.lock | 2199 ++++++ backend/Cargo.toml | 44 + backend/TODO.md | 51 + backend/src/main.rs | 30 + backend/src/routes/health.rs | 47 + backend/src/routes/mod.rs | 13 + backend/src/server/config.rs | 120 + backend/src/server/mod.rs | 57 + combatant-client-26.2/TODO.md | 123 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 48462 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 + .../command/impl/ProfilerCommand.java | 10 +- .../loki/lovisual/mixins/ProfilersMixin.java | 2 +- .../profiler/DevFrameStutterProfiler.java | 7 +- .../engine/profiler/DevJfrProfiler.java | 4 +- .../profiler/DevRenderCostProfiler.java | 30 +- .../engine/profiler/DevRenderProfiler2D.java | 15 +- .../engine/profiler/DevRenderProfiler3D.java | 21 +- .../engine/profiler/DevSamplingProfiler.java | 9 +- .../engine/profiler/DevTracyProfiler.java | 4 +- .../java/dev/loki/lovisual/Lifecycle.java | 60 + .../main/java/dev/loki/lovisual/LoVisual.java | 112 +- .../loki/lovisual/addon/AddonDescriptor.java | 2 +- .../dev/loki/lovisual/addon/AddonIssue.java | 2 +- .../dev/loki/lovisual/addon/AddonManager.java | 72 +- .../lovisual/addon/AddonRegistration.java | 2 +- .../addon/AddonRenderPipelineManager.java | 2 +- .../loki/lovisual/addon/AddonSnapshot.java | 2 +- .../loki/lovisual/addon/AddonStateStore.java | 4 +- .../dev/loki/lovisual/addon/AddonStatus.java | 2 +- .../addon/ClickGuiSectionManager.java | 2 +- .../addon/LoVisualAddonContextImpl.java | 6 +- .../LoVisualAddonRuntimeContextImpl.java | 2 +- .../addon/LoVisualModuleLoadContextImpl.java | 2 +- .../addon/ModuleExtensionContextImpl.java | 2 +- .../addon/ModuleExtensionManager.java | 2 +- .../lovisual/api/v0/addon/LoVisualAddon.java | 6 +- .../api/v0/addon/LoVisualAddonContext.java | 2 +- .../v0/addon/LoVisualAddonRuntimeContext.java | 2 +- .../v0/addon/LoVisualModuleLoadContext.java | 4 +- .../LoVisualClickGuiRenderContext.java | 2 +- .../v0/clickgui/LoVisualClickGuiSection.java | 2 +- .../api/v0/client/LoVisualClientApi.java | 2 +- .../v0/module/LoVisualModuleExtension.java | 2 +- .../api/v0/module/ModuleExtensionContext.java | 2 +- .../render/LoVisualPostProcessCallback.java | 2 +- .../v0/render/LoVisualPostProcessContext.java | 2 +- .../api/v0/render/LoVisualRenderCallback.java | 2 +- .../api/v0/render/LoVisualRenderContext.java | 2 +- .../render/LoVisualRenderPipelineBuilder.java | 8 +- .../api/v0/render/LoVisualRenderStage.java | 2 +- .../api/v0/render/LoVisualUniforms.java | 12 +- .../xaero/TriangulatorXaeroMinimapCompat.java | 2 +- .../compat/xaero/TriangulatorXaeroState.java | 4 +- .../TriangulatorXaeroWorldMapCompat.java | 2 +- .../xaero/XaeroCommandWaypointCompat.java | 2 +- .../compat/xaero/XaeroWaypointRuntime.java | 2 +- .../compat/xaero/XaeroWaypointStore.java | 4 +- .../dev/loki/lovisual/config/ConfigLang.java | 30 + .../lovisual/config/ConfigNameProvider.java | 15 + .../loki/lovisual/config/ConfigObject.java | 16 + .../dev/loki/lovisual/config/ConfigPaths.java | 29 + .../lovisual/config/ConfigSerializer.java | 664 ++ .../config/ConfigValueAliasProvider.java | 14 + .../lovisual/config/DisableSettingI18n.java | 25 + .../lovisual/config/JsonConfigObject.java | 14 + .../dev/loki/lovisual/config/MainConfig.java | 477 ++ .../dev/loki/lovisual/config/SettingDef.java | 371 + .../lovisual/config/SettingDefProvider.java | 17 + .../loki/lovisual/config/SettingOwner.java | 24 + .../common/CommonBooleanGroupSchema.java | 14 + .../config/common/CommonSettingSchema.java | 19 + .../config/common/CommonSettingSchemas.java | 200 + .../config/common/impl/CombatPriority.java | 17 + .../impl/CombatProtocolHeuristicSources.java | 25 + .../config/common/impl/CommonKey.java | 46 + .../config/common/impl/FakeLagFlushOn.java | 33 + .../config/common/impl/RotationMode.java | 17 + .../impl/RotationMovementCorrection.java | 17 + .../common/impl/RotationResetThreshold.java | 17 + .../common/impl/RotationResetTicks.java | 17 + .../common/impl/RotationThroughWalls.java | 17 + .../config/common/impl/RotationTiming.java | 17 + .../config/common/impl/TargetFilters.java | 42 + .../config/profile/ConfigProfileApplier.java | 157 + .../profile/ConfigProfileBinaryCodec.java | 152 + .../profile/ConfigProfileCollector.java | 106 + .../profile/ConfigProfileDateFormatter.java | 37 + .../config/profile/ConfigProfileDiff.java | 57 + .../profile/ConfigProfileDiffEngine.java | 64 + .../config/profile/ConfigProfileEntry.java | 26 + .../config/profile/ConfigProfileMeta.java | 39 + .../config/profile/ConfigProfileService.java | 101 + .../config/profile/ConfigProfileSnapshot.java | 24 + .../config/profile/ConfigProfileStorage.java | 179 + .../config/profile/ConfigProfileType.java | 50 + .../profile/ConfigProfileValueCodec.java | 136 + .../loki/lovisual/config/values/BindMode.java | 13 + .../config/values/BooleanMapValue.java | 60 + .../lovisual/config/values/BooleanValue.java | 26 + .../lovisual/config/values/ColorValue.java | 24 + .../lovisual/config/values/ConfigValue.java | 62 + .../loki/lovisual/config/values/EnumIds.java | 19 + .../lovisual/config/values/EnumValue.java | 115 + .../config/values/ItemCooldownRulesValue.java | 326 + .../config/values/ItemIdSetValue.java | 81 + .../lovisual/config/values/KeyBindValue.java | 30 + .../lovisual/config/values/ModeValue.java | 77 + .../lovisual/config/values/NumberValue.java | 72 + .../config/values/RGBAColorValue.java | 181 + .../lovisual/config/values/RGBColorValue.java | 143 + .../loki/lovisual/config/values/SetValue.java | 46 + .../lovisual/config/values/StringValue.java | 26 + .../java/dev/loki/lovisual/events/Event.java | 2 +- .../dev/loki/lovisual/events/EventBus.java | 6 +- .../loki/lovisual/events/EventHandler.java | 2 +- .../java/dev/loki/lovisual/events/Events.java | 2 +- .../loki/lovisual/events/UsedImplicitly.java | 2 +- .../events/impl/AttackEntityEvent.java | 2 +- .../events/impl/BlinkPacketEvent.java | 6 +- .../impl/CombatProtocolBossbarEvent.java | 2 +- .../impl/CrosshairTargetUpdateEvent.java | 2 +- .../lovisual/events/impl/EventBreakBlock.java | 2 +- .../lovisual/events/impl/EventCollision.java | 2 +- .../lovisual/events/impl/EventPostSync.java | 2 +- .../events/impl/EventPushOutOfBlocks.java | 2 +- .../loki/lovisual/events/impl/EventSync.java | 2 +- .../events/impl/EventTargetChanged.java | 2 +- .../lovisual/events/impl/FireworkEvent.java | 2 +- .../lovisual/events/impl/GameTickEvent.java | 2 +- .../impl/I18nPreflightCollectEvent.java | 2 +- .../lovisual/events/impl/KeyInputEvent.java | 2 +- .../events/impl/KeybindIsPressedEvent.java | 2 +- .../lovisual/events/impl/LightmapEvent.java | 2 +- .../events/impl/LightmapModifyEvent.java | 2 +- .../events/impl/MovementInputEvent.java | 6 +- .../lovisual/events/impl/PacketEvent.java | 2 +- .../lovisual/events/impl/PlayerJumpEvent.java | 2 +- .../lovisual/events/impl/PlayerMoveEvent.java | 4 +- .../events/impl/PlayerSafeWalkEvent.java | 2 +- .../lovisual/events/impl/PlayerStepEvent.java | 2 +- .../events/impl/PlayerStepSuccessEvent.java | 2 +- .../events/impl/PlayerVelocityStrafe.java | 2 +- .../events/impl/PostPlayerUpdateEvent.java | 2 +- .../lovisual/events/impl/PvpChatEvent.java | 2 +- .../lovisual/events/impl/PvpOverlayEvent.java | 2 +- .../lovisual/events/impl/PvpTabEvent.java | 2 +- .../impl/RenderPrewarmCollectEvent.java | 2 +- .../events/impl/RotationUpdateEvent.java | 2 +- .../events/impl/SprintControlEvent.java | 2 +- .../features/account/AccountAuthType.java | 2 +- .../features/account/AccountConfig.java | 2 +- .../features/account/AccountEntry.java | 2 +- .../features/account/SkinManager.java | 2 +- .../features/command/ClientCommand.java | 2 +- .../features/command/CommandContext.java | 2 +- .../features/command/CommandInfo.java | 2 +- .../features/command/CommandManager.java | 2 +- .../features/command/CommandMetadata.java | 2 +- .../features/command/CommandOutput.java | 6 - .../command/VanillaChatRuntimeCleanup.java | 25 - .../features/command/impl/AddonsCommand.java | 2 +- .../features/command/impl/BindCommand.java | 2 +- .../features/command/impl/CommandUtils.java | 2 +- .../features/command/impl/ConfigCommand.java | 2 +- .../command/impl/CoordinatesCommand.java | 2 +- .../features/command/impl/HelpCommand.java | 2 +- .../features/command/impl/HideCommand.java | 2 +- .../features/command/impl/IrisCommand.java | 5 +- .../features/command/impl/ModulesCommand.java | 2 +- .../features/command/impl/PingCommand.java | 2 +- .../command/impl/RelationCommand.java | 2 +- .../features/command/impl/RuntimeCommand.java | 78 - .../command/impl/ServerInfoCommand.java | 2 +- .../features/command/impl/ToggleCommand.java | 2 +- .../features/command/impl/TpsCommand.java | 2 +- .../command/impl/UsernameCommand.java | 2 +- .../command/impl/XaeroWaypointCommand.java | 2 +- .../gui/chat/BetterChatCommandMerge.java | 53 + .../chat/BetterChatContextMenuHandler.java | 187 + .../gui/chat/BetterChatContextMenuModel.java | 112 + .../features/gui/chat/BetterChatDrawUtil.java | 201 + .../gui/chat/BetterChatEditBoxUtil.java | 53 + .../features/gui/chat/BetterChatFontUtil.java | 198 + .../gui/chat/BetterChatFrameModel.java | 129 + .../gui/chat/BetterChatFrameRenderer.java | 82 + .../gui/chat/BetterChatGlyphRenderer.java | 148 + .../gui/chat/BetterChatHoverCache.java | 2 +- .../gui/chat/BetterChatInputHandler.java | 160 + .../gui/chat/BetterChatInputRenderer.java | 196 + .../gui/chat/BetterChatLayoutEngine.java | 196 + .../gui/chat/BetterChatLineLayout.java | 180 + .../gui/chat/BetterChatMessageGrouping.java | 2 +- .../gui/chat/BetterChatMessageRenderer.java | 192 + .../features/gui/chat/BetterChatModel.java | 85 + .../gui/chat/BetterChatMouseClickHandler.java | 165 + .../features/gui/chat/BetterChatRenderer.java | 2951 +------ .../features/gui/chat/BetterChatSearch.java | 2 +- .../gui/chat/BetterChatSegmentUtil.java | 72 + .../features/gui/chat/BetterChatStore.java | 2 +- .../gui/chat/BetterChatStoreManager.java | 2 +- .../chat/BetterChatSuggestionRenderer.java | 192 + .../gui/chat/BetterChatSuggestionState.java | 186 + .../gui/chat/BetterChatTooltipRenderer.java | 163 + .../features/gui/chat/BetterChatViewport.java | 190 + .../features/gui/chat/ChatHoverUtil.java | 2 +- .../lovisual/features/gui/chat/ChatLine.java | 2 +- .../gui/chat/CommandSuggestorBridge.java | 16 +- .../gui/clickgui/ClickGuiDrawHelpers.java | 182 + .../gui/clickgui/ClickGuiEditorManager.java | 129 + .../gui/clickgui/ClickGuiEditorScreen.java | 2 +- .../features/gui/clickgui/ClickGuiFonts.java | 55 + .../gui/clickgui/ClickGuiInputHandler.java | 194 + .../gui/clickgui/ClickGuiKeyBindManager.java | 62 + .../gui/clickgui/ClickGuiKeyboardHandler.java | 148 + .../gui/clickgui/ClickGuiLifecycle.java | 156 + .../features/gui/clickgui/ClickGuiModel.java | 37 + .../clickgui/ClickGuiPickerIconManager.java | 138 + .../gui/clickgui/ClickGuiPickerScreen.java | 2 +- .../gui/clickgui/ClickGuiRenderEngine.java | 140 + .../gui/clickgui/ClickGuiRenderer.java | 1686 +--- .../features/gui/clickgui/ClickGuiScreen.java | 2 +- .../gui/clickgui/ClickGuiScreenManager.java | 116 + .../features/gui/clickgui/ClickGuiSearch.java | 2 +- .../features/gui/clickgui/ClickGuiTabBar.java | 195 + .../gui/clickgui/ClickGuiTabState.java | 86 + .../gui/clickgui/ClickGuiTextBatch.java | 194 + .../gui/clickgui/ClickGuiTopLayer.java | 83 + .../editor/ClickGuiTextEditorState.java | 2 +- .../screen/modules/ModulesMenuCategory.java | 2 +- .../screen/modules/ModulesMenuPanel.java | 2 +- .../screen/modules/ModulesMenuResolver.java | 2 +- .../screen/modules/ModulesMenuScreen.java | 2 +- .../screen/modules/ModulesMenuStyle.java | 2 +- .../layout/screen/settings/MenuScreen.java | 2 +- .../screen/settings/MenuSettingsResolver.java | 2 +- .../screen/settings/SettingsGuiPalette.java | 2 +- .../implement/category/CategoryComponent.java | 2 +- .../config/ConfigDiffPanelComponent.java | 400 + .../config/ConfigProfileCardComponent.java | 156 + .../config/ConfigProfilesComponent.java | 791 ++ .../implement/main/MainSettingsComponent.java | 2 +- .../implement/module/ModuleComponent.java | 2 +- .../module/ModuleSettingsWindow.java | 2 +- .../module/SettingsPanelComponent.java | 2 +- .../implement/other/BackgroundComponent.java | 2 +- .../other/CategoryContainerComponent.java | 2 +- .../implement/other/SearchComponent.java | 2 +- .../implement/other/StatusRender.java | 2 +- .../OnlineRelationPlayerPickerComponent.java | 2 +- .../RelationPlayerCardComponent.java | 2 +- .../relations/RelationsComponent.java | 2 +- .../implement/theme/ThemeComponent.java | 2 +- .../theme/ThemeEditorPreviewComponent.java | 4 +- .../settings/render/LayoutRender2D.java | 2 +- .../clickgui/picker/ClickGuiPickerState.java | 2 +- .../gui/clickgui/picker/PickerCatalog.java | 2 +- .../clickgui/picker/PickerCatalogFactory.java | 2 +- .../gui/clickgui/picker/PickerEntryData.java | 2 +- .../CombatProtocolHeuristicsEditorState.java | 2 +- .../clickgui/sections/ClickGuiSection.java | 2 +- .../gui/clickgui/sections/ModulesSection.java | 2 +- .../clickgui/sections/SettingsSection.java | 2 +- .../sections/settings/SettingsTabRuntime.java | 2 +- .../clickgui/settings/BindRendererUtil.java | 192 + .../gui/clickgui/settings/BooleanSetting.java | 2 +- .../settings/BooleanSettingRenderer.java | 128 + .../clickgui/settings/ColorPresetStore.java | 2 +- .../gui/clickgui/settings/ColorSetting.java | 2 +- .../clickgui/settings/ColorSettingDrag.java | 99 + .../settings/ColorSettingHexInput.java | 177 + .../settings/ColorSettingHexState.java | 147 + .../clickgui/settings/ColorSettingLayout.java | 152 + .../clickgui/settings/ColorSettingMath.java | 23 + .../settings/ColorSettingNoAlpha.java | 2 +- .../settings/ColorSettingPresetHandler.java | 95 + .../settings/ColorSettingPresetRenderer.java | 169 + .../settings/ColorSettingRenderer.java | 190 + .../settings/ColorSettingSquareRenderer.java | 86 + .../settings/ConfigColorSettingNoAlpha.java | 2 +- .../settings/CooldownRulesSetting.java | 2 +- .../settings/FunctionBindSetting.java | 2 +- .../settings/FunctionBindSettingRenderer.java | 38 + .../gui/clickgui/settings/GroupSetting.java | 2 +- .../settings/GroupSettingRenderer.java | 120 + .../settings/I18nDuplicateScanner.java | 4 +- .../settings/I18nPreflightContributors.java | 2 +- .../settings/I18nPreflightManager.java | 2 +- .../gui/clickgui/settings/KeyBindSetting.java | 2 +- .../settings/KeyBindSettingRenderer.java | 35 + .../gui/clickgui/settings/ModeSetting.java | 2 +- .../settings/ModeSettingRenderer.java | 100 + .../settings/ModulesSettingsSkin.java | 2 +- .../clickgui/settings/PickerDetailOwner.java | 2 +- .../settings/ProtocolHeuristicsSetting.java | 2 +- .../gui/clickgui/settings/Setting.java | 2 +- .../gui/clickgui/settings/SettingFactory.java | 2 +- .../settings/SettingRenderContext.java | 2 +- .../settings/SettingRenderSurface.java | 2 +- .../settings/SettingRendererBridge.java | 2 +- .../clickgui/settings/SettingSkinUtil.java | 142 + .../settings/SettingTextInputUtil.java | 45 + .../gui/clickgui/settings/SliderSetting.java | 2 +- .../settings/SliderSettingRenderer.java | 191 + .../settings/SliderTextInputHandler.java | 185 + .../settings/SliderTextInputState.java | 125 + .../clickgui/settings/TextEditorOwner.java | 2 +- .../clickgui/settings/TextListSetting.java | 2 +- .../settings/TextListSettingRenderer.java | 181 + .../settings/TextListTextEditHandler.java | 161 + .../gui/clickgui/settings/TextSetting.java | 2 +- .../settings/TextSettingRenderer.java | 103 + .../settings/TextSettingTextInputHandler.java | 171 + .../settings/UnifiedSettingRenderer.java | 2826 +------ .../settings/UnifiedSettingsSkin.java | 2 +- .../clickgui/util/ClickGuiHintOverlay.java | 2 +- .../gui/clickgui/util/ClickGuiI18n.java | 2 +- .../gui/clickgui/util/ClickGuiMath.java | 2 +- .../util/ClickGuiRichTextRenderer.java | 2 +- .../features/gui/hud/AbstractHudElement.java | 2 +- .../features/gui/hud/BaseHudElement.java | 2 +- .../features/gui/hud/CooldownRender.java | 2 +- .../lovisual/features/gui/hud/HudAnchorX.java | 2 +- .../lovisual/features/gui/hud/HudAnchorY.java | 2 +- .../gui/hud/HudElementAutoLoader.java | 2 +- .../features/gui/hud/HudElementInfo.java | 2 +- .../features/gui/hud/HudElementRegister.java | 2 +- .../features/gui/hud/HudElements.java | 2 +- .../features/gui/hud/HudGlobalConfig.java | 2 +- .../features/gui/hud/HudRenderSpace.java | 2 +- .../features/gui/hud/HudRenderUtil.java | 2 +- .../features/gui/hud/HudTextEffects.java | 2 +- .../features/gui/hud/WidgetAnchorSide.java | 2 +- .../hud/draggable/DraggableHudElement.java | 2 +- .../DraggableHudElementRegistry.java | 28 +- .../hud/draggable/DraggableLayoutValue.java | 2 +- .../gui/hud/draggable/impl/Admins.java | 2 +- .../gui/hud/draggable/impl/Armor.java | 2 +- .../gui/hud/draggable/impl/BetterChat.java | 6 +- .../gui/hud/draggable/impl/Cooldowns.java | 2 +- .../gui/hud/draggable/impl/Coordinates.java | 2 +- .../features/gui/hud/draggable/impl/Fps.java | 2 +- .../gui/hud/draggable/impl/GameTime.java | 2 +- .../gui/hud/draggable/impl/HudNotifier.java | 5 +- .../draggable/impl/HudPanelLayoutModes.java | 2 +- .../gui/hud/draggable/impl/Inventory.java | 2 +- .../gui/hud/draggable/impl/Itemizer.java | 4 +- .../gui/hud/draggable/impl/Keybinds.java | 2 +- .../gui/hud/draggable/impl/MediaPlayer.java | 2 +- .../gui/hud/draggable/impl/Memory.java | 2 +- .../gui/hud/draggable/impl/ModuleList.java | 2 +- .../features/gui/hud/draggable/impl/Ping.java | 2 +- .../gui/hud/draggable/impl/Potions.java | 2 +- .../gui/hud/draggable/impl/Radar.java | 2 +- .../gui/hud/draggable/impl/Scoreboard.java | 2 +- .../impl/ScriptedInventoryHudPanel.java | 4 +- .../draggable/impl/ScriptedListHudPanel.java | 4 +- .../impl/ScriptedTriangulatorHudPanel.java | 4 +- .../gui/hud/draggable/impl/SpeedBps.java | 2 +- .../gui/hud/draggable/impl/SystemTime.java | 2 +- .../gui/hud/draggable/impl/TargetHud.java | 1685 +--- .../draggable/impl/TargetHudArcRenderer.java | 179 + .../impl/TargetHudContentRenderer.java | 193 + .../impl/TargetHudEffectsRenderer.java | 173 + .../impl/TargetHudEquipmentRenderer.java | 195 + .../draggable/impl/TargetHudFaceRenderer.java | 187 + .../draggable/impl/TargetHudFormatter.java | 111 + .../hud/draggable/impl/TargetHudModel.java | 29 + .../impl/TargetHudPanelRenderer.java | 118 + .../hud/draggable/impl/TargetHudRenderer.java | 190 + .../impl/TargetHudTargetResolver.java | 69 + .../draggable/impl/TargetHudTextRenderer.java | 101 + .../hud/draggable/impl/TimerIndicator.java | 13 +- .../features/gui/hud/draggable/impl/Tps.java | 2 +- .../gui/hud/draggable/impl/Triangulator.java | 2 +- .../StaticHudElementBootstrap.java | 2 +- .../StaticHudElementRegistry.java | 16 +- .../hud/nondraggable/impl/BetterButtons.java | 15 +- .../hud/nondraggable/impl/BetterTooltips.java | 19 +- .../gui/hud/nondraggable/impl/CustomBar.java | 29 +- .../nondraggable/impl/CustomHealthBar.java | 7 +- .../hud/nondraggable/impl/CustomHotbar.java | 11 +- .../hud/nondraggable/impl/DynamicIsland.java | 14 +- .../hud/nondraggable/impl/SwapTooltip.java | 5 +- .../nondraggable/impl/tab/CustomTabList.java | 16 +- .../impl/tab/TabListAnimator.java | 2 +- .../nondraggable/impl/tab/TabListModel.java | 4 +- .../impl/tab/TabRichTextRenderer.java | 2 +- .../gui/hud/script/CompactHudStatModel.java | 2 +- .../gui/hud/script/HudScriptLayouts.java | 2 +- .../hud/script/ScriptableHudStatWidget.java | 2 +- .../ScriptedCompactHudStatRenderer.java | 4 +- .../mainmenu/LoVisualAddonManagerScreen.java | 64 +- .../mainmenu/LoVisualAltManagerScreen.java | 52 +- .../gui/mainmenu/LoVisualMainMenuScreen.java | 11 +- .../mainmenu/LoVisualProxyManagerScreen.java | 34 +- .../lovisual/features/module/HudPhase.java | 2 +- .../loki/lovisual/features/module/Module.java | 6 +- .../module/ModuleActivationSource.java | 2 +- .../features/module/ModuleAutoLoader.java | 2 +- .../features/module/ModuleCategory.java | 2 +- .../lovisual/features/module/ModuleInfo.java | 2 +- .../features/module/ModuleManager.java | 114 +- .../features/module/ModuleRegister.java | 2 +- .../features/module/ModuleStateListener.java | 2 +- .../lovisual/features/module/Modules.java | 15 +- .../lovisual/features/module/Notifier.java | 2 +- .../features/module/RuntimeControlModule.java | 12 - .../lovisual/features/module/WorldPhase.java | 2 +- .../module/modules/combat/AttributeSwap.java | 1922 ----- .../module/modules/combat/AutoAnchor.java | 1147 --- .../module/modules/combat/AutoAttack.java | 587 -- .../module/modules/combat/AutoBed.java | 1192 --- .../module/modules/combat/AutoBow.java | 1195 --- .../module/modules/combat/AutoCrystal.java | 1516 ---- .../module/modules/combat/Backtrack.java | 410 - .../module/modules/combat/Criticals.java | 766 -- .../module/modules/combat/ElytraTarget.java | 1711 ---- .../module/modules/combat/Hitbox.java | 469 -- .../module/modules/combat/KTLeave.java | 299 - .../module/modules/combat/KillAura.java | 1241 --- .../module/modules/combat/MaceKill.java | 138 - .../modules/combat/ProjectilePuncher.java | 54 +- .../module/modules/combat/PvpCooldowns.java | 2 +- .../features/module/modules/combat/Reach.java | 41 +- .../module/modules/combat/RubberHand.java | 2 +- .../module/modules/combat/SpearAssist.java | 2 +- .../module/modules/combat/TPSSync.java | 2 +- .../autoanchor/AutoAnchorActionUtil.java | 144 - .../autoanchor/AutoAnchorDamageCandidate.java | 16 - .../autoanchor/AutoAnchorDamageRules.java | 88 - .../combat/autoanchor/AutoAnchorData.java | 25 - .../autoanchor/AutoAnchorEntityBlocker.java | 31 - .../autoanchor/AutoAnchorInteractionUtil.java | 306 - .../autoanchor/AutoAnchorPlacementMode.java | 14 - .../combat/autoanchor/AutoAnchorPlanner.java | 332 - .../autoanchor/AutoAnchorRenderUtil.java | 108 - .../combat/autobed/AutoBedActionUtil.java | 103 - .../autobed/AutoBedDamageCandidate.java | 13 - .../combat/autobed/AutoBedDamageRules.java | 88 - .../modules/combat/autobed/AutoBedData.java | 31 - .../combat/autobed/AutoBedEntityBlocker.java | 31 - .../autobed/AutoBedInteractionUtil.java | 348 - .../combat/autobed/AutoBedPlacementMode.java | 14 - .../combat/autobed/AutoBedPlanner.java | 358 - .../combat/autobed/AutoBedRenderUtil.java | 108 - .../autocrystal/AutoCrystalAttempt.java | 37 - .../autocrystal/AutoCrystalBaseEvaluator.java | 103 - .../autocrystal/AutoCrystalBasePlanner.java | 137 - .../autocrystal/AutoCrystalCrystalData.java | 18 - .../AutoCrystalDamageCandidate.java | 16 - .../autocrystal/AutoCrystalDamageRules.java | 78 - .../autocrystal/AutoCrystalEntityBlocker.java | 91 - .../combat/autocrystal/AutoCrystalHand.java | 13 - .../AutoCrystalInteractionUtil.java | 222 - .../autocrystal/AutoCrystalPlaceData.java | 20 - .../AutoCrystalPlaceScanDebug.java | 107 - .../AutoCrystalPlaceValidationResult.java | 15 - .../autocrystal/AutoCrystalPlacementMode.java | 13 - .../AutoCrystalPlacementPlanner.java | 269 - .../autocrystal/AutoCrystalRenderUtil.java | 108 - .../autocrystal/AutoCrystalSelectionUtil.java | 63 - .../autocrystal/AutoCrystalTracker.java | 138 - .../module/modules/misc/BetterMinecraft.java | 7 +- .../module/modules/misc/ClickGui.java | 2 +- .../module/modules/misc/DefineTarget.java | 2 +- .../module/modules/misc/FakePlayer.java | 2 +- .../module/modules/misc/HitSounds.java | 2 +- .../module/modules/misc/MessageFilter.java | 2 +- .../features/module/modules/misc/NoSound.java | 2 +- .../features/module/modules/misc/Panic.java | 82 - .../module/modules/movement/AirJump.java | 116 - .../module/modules/movement/AutoDodge.java | 941 --- .../module/modules/movement/ElytraFly.java | 764 -- .../module/modules/movement/ElytraHelper.java | 498 -- .../module/modules/movement/Flight.java | 459 -- .../module/modules/movement/Freeze.java | 25 - .../modules/movement/InventoryMove.java | 500 -- .../module/modules/movement/NoFall.java | 717 -- .../module/modules/movement/NoPush.java | 81 - .../module/modules/movement/NoStun.java | 570 -- .../module/modules/movement/Parkour.java | 60 - .../module/modules/movement/Phase.java | 367 - .../module/modules/movement/ReverseStep.java | 402 - .../module/modules/movement/SafeWalk.java | 129 - .../module/modules/movement/Speed.java | 304 - .../module/modules/movement/Sprint.java | 396 - .../module/modules/movement/Step.java | 486 -- .../module/modules/movement/Strafe.java | 253 - .../modules/movement/SuperFirework.java | 107 - .../module/modules/movement/TargetStrafe.java | 327 - .../module/modules/movement/Timer.java | 429 -- .../module/modules/movement/Velocity.java | 1079 --- .../module/modules/movement/WindJump.java | 675 -- .../module/modules/player/AirPlace.java | 248 - .../module/modules/player/AutoArmor.java | 221 - .../module/modules/player/AutoEat.java | 384 - .../module/modules/player/AutoTool.java | 6 +- .../module/modules/player/AutoTotem.java | 339 - .../module/modules/player/ClickPearl.java | 14 +- .../module/modules/player/FakeLag.java | 6 +- .../module/modules/player/NoDelay.java | 18 +- .../module/modules/player/NoInteract.java | 8 +- .../module/modules/player/Scaffold.java | 2416 ------ .../module/modules/player/ShitDropper.java | 2 +- .../module/modules/player/XCarry.java | 24 - .../module/modules/visuals/AspectRatio.java | 2 +- .../module/modules/visuals/BedwarsESP.java | 2 +- .../module/modules/visuals/BlockESP.java | 2 +- .../modules/visuals/BlockHighlight.java | 16 +- .../module/modules/visuals/CameraClip.java | 2 +- .../module/modules/visuals/Chams.java | 18 +- .../module/modules/visuals/Crosshair.java | 28 +- .../module/modules/visuals/DamageTint.java | 6 +- .../module/modules/visuals/DropESP.java | 2 +- .../features/module/modules/visuals/ESP.java | 1461 +--- .../module/modules/visuals/Esp2DRenderer.java | 176 + .../module/modules/visuals/Esp3DRenderer.java | 79 + .../module/modules/visuals/EspColorUtil.java | 135 + .../modules/visuals/EspEntityCollector.java | 182 + .../modules/visuals/EspMeshBuilder.java | 124 + .../module/modules/visuals/EspModel.java | 62 + .../modules/visuals/EspOutlineRenderer.java | 116 + .../modules/visuals/EspSearchOverlay.java | 109 + .../modules/visuals/EspShaderColor.java | 198 + .../module/modules/visuals/EspShaderMask.java | 187 + .../modules/visuals/EspShaderRenderer.java | 139 + .../module/modules/visuals/FovControl.java | 2 +- .../module/modules/visuals/Freecam.java | 2 +- .../module/modules/visuals/FullBright.java | 2 +- .../module/modules/visuals/HitEffect.java | 22 +- .../module/modules/visuals/HoleESP.java | 6 +- .../module/modules/visuals/JumpCircles.java | 8 +- .../module/modules/visuals/KillEffect.java | 10 +- .../module/modules/visuals/MotionBlur.java | 10 +- .../module/modules/visuals/NameTagCache.java | 143 + .../visuals/NameTagEffectsRenderer.java | 142 + .../visuals/NameTagEnchantFormatter.java | 105 + .../visuals/NameTagEquipmentRenderer.java | 123 + .../modules/visuals/NameTagFaceRenderer.java | 42 + .../modules/visuals/NameTagLabelBuilder.java | 185 + .../modules/visuals/NameTagLayoutEngine.java | 168 + .../module/modules/visuals/NameTagModel.java | 67 + .../visuals/NameTagOpponentRenderer.java | 125 + .../modules/visuals/NameTagPlateRenderer.java | 200 + .../modules/visuals/NameTagRenderer.java | 196 + .../module/modules/visuals/NameTags.java | 1517 +--- .../module/modules/visuals/NoRender.java | 6 +- .../module/modules/visuals/PostFX.java | 8 +- .../module/modules/visuals/Predictions.java | 28 +- .../modules/visuals/ReimaginedVisual.java | 18 +- .../module/modules/visuals/SeeInvisibles.java | 2 +- .../module/modules/visuals/SoundESP.java | 2 +- .../module/modules/visuals/TargetESP.java | 16 +- .../module/modules/visuals/TazikHat.java | 12 +- .../module/modules/visuals/TotemFX.java | 8 +- .../module/modules/visuals/Tracers.java | 8 +- .../module/modules/visuals/Trails.java | 30 +- .../module/modules/visuals/ViewModel.java | 2 +- .../modules/visuals/WorldParticles.java | 20 +- .../module/modules/visuals/WorldTweaks.java | 10 +- .../features/module/modules/visuals/Zoom.java | 2 +- .../features/relations/CategoryRules.java | 2 +- .../features/relations/CategoryService.java | 2 +- .../features/relations/CategoryType.java | 2 +- .../features/relations/EntityFilters.java | 2 +- .../features/relations/PlayerRelations.java | 2 +- .../features/relations/StaffData.java | 2 +- .../relations/StaffHeuristicsConfig.java | 2 +- .../relations/StaffHeuristicsMatcher.java | 2 +- .../features/relations/StaffTracker.java | 2 +- .../features/security/BackdoorProtection.java | 6 +- .../FilteredTranslatableTextContent.java | 6 +- .../features/theme/EditableClickGuiTheme.java | 2 +- .../loki/lovisual/features/theme/Theme.java | 2 +- .../lovisual/features/theme/ThemeStore.java | 2 +- .../loki/lovisual/features/theme/Themes.java | 2 +- .../loki/lovisual/mixininterface/IEntity.java | 4 +- .../mixininterface/IGlBackendInfo.java | 6 +- .../lovisual/mixininterface/IGpuDevice.java | 6 +- .../lovisual/mixininterface/IGuiGraphics.java | 12 +- .../IItemEntityRenderState.java | 6 +- .../lovisual/mixininterface/ILocalPlayer.java | 10 +- .../lovisual/mixininterface/IMsaaDevice.java | 4 +- .../lovisual/mixininterface/IMsaaTexture.java | 10 +- .../mixininterface/IPlayerAttackCooldown.java | 6 +- .../mixininterface/IRenderPipeline.java | 12 +- .../mixininterface/IRoundedHitbox.java | 10 +- .../mixins/AbstractClientPlayerMixin.java | 16 +- .../mixins/AbstractContainerScreenMixin.java | 12 +- .../mixins/AbstractSelectionListMixin.java | 6 +- .../mixins/AbstractSliderButtonMixin.java | 8 +- .../lovisual/mixins/AbstractWidgetMixin.java | 32 +- .../AtmosphericFogEnvironmentMixin.java | 4 +- .../BatchingRenderCommandQueueMixin.java | 32 +- .../BlockCollisionSpliteratorMixin.java | 4 +- .../dev/loki/lovisual/mixins/BlockMixin.java | 2 +- .../mixins/BossHealthOverlayMixin.java | 2 +- ...ufferManagerDefaultBufferManagerMixin.java | 8 +- .../mixins/ButtonWidgetTextMixin.java | 4 +- .../dev/loki/lovisual/mixins/CameraMixin.java | 28 +- .../lovisual/mixins/ChatComponentMixin.java | 18 +- .../loki/lovisual/mixins/ChatScreenMixin.java | 30 +- .../mixins/ClientClockManagerMixin.java | 4 +- .../ClientCommonPacketListenerImplMixin.java | 17 +- .../lovisual/mixins/ClientLevelMixin.java | 6 +- .../mixins/ClientPacketListenerMixin.java | 61 +- .../lovisual/mixins/CommandEncoderMixin.java | 32 +- .../loki/lovisual/mixins/ConnectionMixin.java | 16 +- .../lovisual/mixins/ContextualBarMixin.java | 8 +- .../lovisual/mixins/CycleButtonMixin.java | 10 +- .../loki/lovisual/mixins/DebugHudMixin.java | 13 +- .../mixins/DynamicUniformStorageMixin.java | 6 +- .../dev/loki/lovisual/mixins/EntityMixin.java | 64 +- .../mixins/EquipmentLayerRendererMixin.java | 4 +- .../lovisual/mixins/ExperienceBarMixin.java | 12 +- .../mixins/FireworkRocketEntityMixin.java | 6 +- .../lovisual/mixins/FlowingFluidMixin.java | 25 +- .../lovisual/mixins/FogRendererMixin.java | 6 +- .../lovisual/mixins/FontManagerMixin.java | 4 +- .../lovisual/mixins/GameRendererMixin.java | 284 +- .../mixins/GameRendererViewEffectsMixin.java | 2 +- .../lovisual/mixins/GlDeviceBackendMixin.java | 6 +- .../lovisual/mixins/GlStateManagerMixin.java | 8 +- .../loki/lovisual/mixins/GlTextureMixin.java | 24 +- .../loki/lovisual/mixins/GpuDeviceMixin.java | 12 +- .../loki/lovisual/mixins/GpuSurfaceMixin.java | 16 +- .../lovisual/mixins/GuiGraphicsMixin.java | 40 +- .../dev/loki/lovisual/mixins/GuiMixin.java | 94 +- .../lovisual/mixins/GuiRendererMixin.java | 88 +- .../loki/lovisual/mixins/GuiScreenMixin.java | 16 +- .../loki/lovisual/mixins/HoneyBlockMixin.java | 2 +- .../dev/loki/lovisual/mixins/InputMixin.java | 15 +- .../lovisual/mixins/ItemCooldownsMixin.java | 23 +- .../mixins/ItemEntityRenderStateMixin.java | 12 +- .../mixins/ItemEntityRendererMixin.java | 10 +- .../mixins/ItemFeatureRendererMixin.java | 20 +- .../mixins/ItemInHandRendererMixin.java | 12 +- .../dev/loki/lovisual/mixins/ItemMixin.java | 4 +- .../loki/lovisual/mixins/ItemStackMixin.java | 4 +- .../mixins/JoinMultiplayerScreenMixin.java | 42 +- .../loki/lovisual/mixins/JumpBarMixin.java | 12 +- .../loki/lovisual/mixins/KeyMappingMixin.java | 4 +- .../lovisual/mixins/KeyboardInputMixin.java | 4 +- .../loki/lovisual/mixins/KeyboardMixin.java | 30 +- .../lovisual/mixins/LavaFogModifierMixin.java | 4 +- .../lovisual/mixins/LevelExtractorMixin.java | 4 +- .../dev/loki/lovisual/mixins/LevelMixin.java | 2 +- .../lovisual/mixins/LevelRendererMixin.java | 64 +- .../loki/lovisual/mixins/LibraryMixin.java | 6 +- .../loki/lovisual/mixins/LightmapMixin.java | 4 +- .../LightmapRenderStateExtractorMixin.java | 4 +- .../lovisual/mixins/LivingEntityMixin.java | 142 +- .../mixins/LivingEntityRenderStateMixin.java | 32 +- .../mixins/LivingEntityRendererMixin.java | 30 +- .../lovisual/mixins/LoVisualMixinPlugin.java | 2 +- .../lovisual/mixins/LocalPlayerMixin.java | 417 +- .../loki/lovisual/mixins/LocatorBarMixin.java | 12 +- .../loki/lovisual/mixins/MinecraftMixin.java | 109 +- .../dev/loki/lovisual/mixins/MouseMixin.java | 42 +- .../mixins/MultiPlayerGameModeMixin.java | 30 +- .../lovisual/mixins/NarratorManagerMixin.java | 20 +- .../lovisual/mixins/OptionsNarratorMixin.java | 10 +- .../lovisual/mixins/ParticleManagerMixin.java | 4 +- .../lovisual/mixins/PauseScreenMixin.java | 42 +- .../lovisual/mixins/PlayerEntityMixin.java | 36 +- .../loki/lovisual/mixins/PlayerInfoMixin.java | 2 +- .../lovisual/mixins/PlayerInventoryMixin.java | 6 +- .../mixins/PlayerTabOverlayMixin.java | 7 +- .../mixins/PowderSnowFogModifierMixin.java | 4 +- .../lovisual/mixins/ProjectileUtilMixin.java | 40 +- .../mixins/RecipeBookScreenMixin.java | 4 +- .../loki/lovisual/mixins/RenderPassMixin.java | 8 +- .../lovisual/mixins/RenderPipelineMixin.java | 24 +- .../mixins/ScreenEffectRendererMixin.java | 6 +- .../dev/loki/lovisual/mixins/ScreenMixin.java | 43 +- .../mixins/ServerboundUseItemPacketMixin.java | 4 +- .../lovisual/mixins/ShaderLoaderMixin.java | 112 +- .../lovisual/mixins/SkyRendererMixin.java | 4 +- .../loki/lovisual/mixins/SlimeBlockMixin.java | 10 +- .../SpriteIconButtonCenteredIconMixin.java | 4 +- .../SpriteIconButtonTextAndIconMixin.java | 4 +- .../lovisual/mixins/TitleScreenMixin.java | 7 +- .../lovisual/mixins/ToastManagerMixin.java | 4 +- .../mixins/TooltipRenderUtilMixin.java | 2 +- .../mixins/VulkanCommandEncoderMixin.java | 12 +- .../lovisual/mixins/VulkanDeviceMixin.java | 32 +- .../mixins/VulkanGpuTextureMixin.java | 28 +- .../mixins/VulkanGpuTextureViewMixin.java | 4 +- .../mixins/VulkanRenderPassMixin.java | 12 +- .../mixins/VulkanRenderPipelineMixin.java | 20 +- .../mixins/WaterFogEnvironmentMixin.java | 4 +- .../accessors/BossHealthOverlayAccessor.java | 2 +- .../accessors/ChatInputSuggestorAccessor.java | 6 +- .../mixins/accessors/ChatScreenAccessor.java | 2 +- .../ChatScreenSuggestorAccessor.java | 4 +- .../accessors/ClickableWidgetAccessor.java | 4 +- .../mixins/accessors/ClientLevelAccessor.java | 4 +- .../ClientboundExplodePacketAccessor.java | 4 +- ...entboundSetEntityMotionPacketAccessor.java | 6 +- .../CyclingButtonWidgetAccessor.java | 8 +- .../EffectParticleEffectAccessor.java | 4 +- .../mixins/accessors/EntityAccessor.java | 8 +- .../mixins/accessors/EntityInvoker.java | 4 +- .../EntityRenderManagerAccessor.java | 6 +- .../accessors/EntityRendererAccessor.java | 6 +- .../accessors/FireworksComponentAccessor.java | 4 +- .../accessors/GameRendererAccessor.java | 16 +- .../mixins/accessors/GlTextureInvoker.java | 4 +- .../mixins/accessors/GpuDeviceAccessor.java | 4 +- .../InGameOverlayRendererAccessor.java | 2 +- .../mixins/accessors/InputAccessor.java | 2 +- .../accessors/ItemCooldownEntryAccessor.java | 2 +- .../ItemCooldownManagerAccessor.java | 2 +- .../ItemRenderStateLayerAccessor.java | 2 +- .../accessors/LevelExtractorAccessor.java | 4 +- .../accessors/LevelRendererAccessor.java | 20 +- .../accessors/LivingEntityAccessor.java | 4 +- .../LivingEntityRenderStateAccessor.java | 8 +- .../mixins/accessors/LocalPlayerAccessor.java | 20 +- .../mixins/accessors/MinecraftAccessor.java | 30 +- .../MultiPlayerGameModeAccessor.java | 18 +- .../PersistentProjectileEntityAccessor.java | 4 +- .../accessors/PlayerInventoryAccessor.java | 6 +- .../accessors/PlayerTabOverlayAccessor.java | 6 +- .../accessors/RenderLayerInvokerAccessor.java | 2 +- .../ServerboundInteractPacketAccessor.java | 4 +- .../ServerboundMovePlayerPacketAccessor.java | 12 +- .../ShaderLoaderDefinitionsAccessor.java | 6 +- .../accessors/ShaderSourceKeyAccessor.java | 6 +- .../accessors/SliderWidgetAccessor.java | 6 +- .../mixins/accessors/SlotAccessor.java | 4 +- .../accessors/SuggestionWindowAccessor.java | 14 +- .../accessors/TextFieldWidgetAccessor.java | 6 +- .../TextIconButtonWidgetAccessor.java | 8 +- .../mixins/accessors/WorldAccessor.java | 12 +- .../mixins/iris/IrisCommonUniformsMixin.java | 8 +- .../iris/IrisGameRendererInteropMixin.java | 8 +- .../mixins/iris/IrisHandRendererAccessor.java | 6 +- .../mixins/iris/IrisHandRendererMixin.java | 6 +- .../iris/IrisIncludeProcessorMixin.java | 24 +- .../IrisRenderingPipelineFinalizeMixin.java | 16 +- .../mixins/iris/IrisShaderPackLoadMixin.java | 6 +- .../iris/IrisVanillaHandInteropMixin.java | 4 +- .../mixins/moreculling/CullingUtilsMixin.java | 8 +- .../security/AbstractSignEditScreenMixin.java | 8 +- .../mixins/security/AnvilScreenMixin.java | 10 +- .../ClientLoginNetworkHandlerMixin.java | 8 +- .../mixins/security/GameOptionsMixin.java | 8 +- .../mixins/security/NetworkUtilsMixin.java | 10 +- .../TranslatableTextContentMixin.java | 10 +- .../security/TranslationStorageMixin.java | 10 +- .../sodium/SodiumBlockRendererMixin.java | 12 +- .../sodium/SodiumBlockVisibilityMixin.java | 18 +- .../SodiumChunkBuilderMeshingTaskMixin.java | 4 +- .../sodium/SodiumChunkMeshFormatsMixin.java | 10 +- .../mixins/sodium/SodiumChunkVertexMixin.java | 24 +- .../SodiumShaderChunkRendererMixin.java | 14 +- .../SodiumVertexConsumerTrackerMixin.java | 8 +- .../SodiumWorldRendererFreecamMixin.java | 4 +- .../AbstractWaypointRenderProviderMixin.java | 4 +- .../worldmap/WaypointRenderProviderMixin.java | 38 +- .../worldmap/WorldMapWaypointAccessor.java | 2 +- ...es.java => LoVisualEntityRenderTypes.java} | 8 +- .../render/ShaderEspRenderContext.java | 2 +- .../render/ViewObstructionFadeContext.java | 6 +- .../render/ViewObstructionFadeState.java | 14 +- .../render/compat/EntityCullingCompat.java | 2 +- .../render/effects/NetherPortalRiftPass.java | 18 +- .../render/effects/SleepOverlayPass.java | 16 +- ...ava => LoVisualRenderEngineBootstrap.java} | 10 +- .../lovisual/render/engine/Projection2D.java | 2 +- .../lovisual/render/engine/RenderState.java | 2 +- .../loki/lovisual/render/engine/Texture.java | 4 +- .../render/engine/TextureStorage.java | 2 +- .../engine/animation/AnimatedClockText.java | 2 +- .../engine/animation/AnimatedGlyphSlot.java | 2 +- .../animation/AnimatedRenderColors.java | 2 +- .../engine/animation/AnimatedTextLine.java | 2 +- .../engine/animation/AnimatedTextStyle.java | 2 +- .../animation/AnimatedTextTransition.java | 2 +- .../engine/animation/AnimationUtility.java | 2 +- .../render/engine/color/ColorBlendMode.java | 2 +- .../render/engine/color/ColorEffects.java | 2 +- .../render/engine/color/ColorUtils.java | 2 +- .../render/engine/color/RenderColor.java | 2 +- .../engine/command/RenderCommandBuffer.java | 2 +- .../engine/command/UiBatchBackendCommand.java | 2 +- .../render/engine/command/UiCommand.java | 2 +- .../engine/command/UiCommandBuffer.java | 6 +- .../render/engine/command/UiCommandKind.java | 2 +- .../render/engine/command/UiCommandStats.java | 2 +- .../engine/command/UiEffectCommand.java | 2 +- .../engine/command/UiEffectRegionCommand.java | 2 +- .../render/engine/command/UiItemCommand.java | 2 +- .../render/engine/command/UiPathCommand.java | 2 +- .../engine/command/UiPrimitiveCommand.java | 2 +- .../render/engine/command/UiShapeCommand.java | 2 +- .../engine/command/UiStatsSnapshot.java | 2 +- .../render/engine/command/UiTextCommand.java | 2 +- .../engine/command/UiTextureCommand.java | 2 +- .../engine/command/UiTextureDrawCommand.java | 2 +- .../engine/command/WorldCommandBuffer.java | 6 +- .../ImmediatelyFastBridge.java | 2 +- .../ImmediatelyFastRuntime.java | 2 +- .../ImmediatelyFastRuntimeSnapshot.java | 2 +- .../render/engine/core/CameraContext.java | 4 +- .../render/engine/core/FrameLifecycle.java | 2 +- .../engine/core/FramebufferContext.java | 2 +- ...rSystem.java => LoVisualRenderSystem.java} | 78 +- ...trices.java => LoVisualWorldMatrices.java} | 4 +- .../engine/core/RenderFrameContext.java | 2 +- .../render/engine/core/RenderPhase.java | 6 +- .../render/engine/core/RenderPhaseScope.java | 4 +- .../render/engine/core/ViewportContext.java | 6 +- .../engine/core/policy/DepthProvider.java | 2 +- .../engine/core/policy/FogProvider.java | 2 +- .../engine/core/policy/LightPolicy.java | 4 +- .../core/policy/VanillaWorldFogProvider.java | 4 +- .../core/policy/VisibilityProvider.java | 2 +- .../engine/core/policy/VisibilityQuery.java | 2 +- .../debug/RenderThread2DDebugRenderer.java | 10 +- .../engine/depth/PreTranslucentDepth.java | 36 +- .../render/engine/depth/WorldSceneDepth.java | 26 +- ...rameGraph.java => LoVisualFrameGraph.java} | 14 +- .../engine/framegraph/PassScheduler.java | 2 +- .../engine/framegraph/RenderPassNode.java | 4 +- .../render/engine/guard/LegacyRenderPath.java | 2 +- .../engine/guard/RenderArchitectureGuard.java | 30 +- .../render/engine/guard/RenderBoundary.java | 2 +- .../engine/guard/RenderBoundaryAudit.java | 8 +- .../engine/guard/RenderBoundaryExempt.java | 2 +- .../render/engine/light/LightmapState.java | 2 +- .../render/engine/math/ColorMath.java | 2 +- .../lovisual/render/engine/math/HudScale.java | 2 +- .../render/engine/math/RenderMath.java | 2 +- .../render/engine/msaa/MsaaFramebuffer.java | 12 +- .../render/engine/msaa/MsaaResolveUtil.java | 6 +- .../engine/msaa/MsaaTextureRegistry.java | 2 +- .../render/engine/msaa/MsaaWorldTarget.java | 42 +- .../engine/pipeline/DepthTestFunction.java | 2 +- .../ExtendedRenderPipelineBuilder.java | 12 +- ...ines.java => LoVisualRenderPipelines.java} | 138 +- .../postprocess/DepthOfFieldDepthSource.java | 2 +- .../postprocess/DepthOfFieldQuality.java | 2 +- .../postprocess/MenuBackgroundRenderer.java | 17 +- .../engine/postprocess/MotionBlurMode.java | 2 +- .../postprocess/MotionBlurResources.java | 8 +- .../postprocess/PostProcessContext.java | 2 +- .../postprocess/PostProcessManager.java | 29 +- .../engine/postprocess/PostProcessPass.java | 2 +- .../graph/HistoryBufferManager.java | 2 +- .../graph/LegacyPostProcessGraphPass.java | 6 +- .../postprocess/graph/PostProcessGraph.java | 6 +- .../graph/PostProcessGraphPass.java | 6 +- .../graph/PostProcessGraphResources.java | 12 +- .../graph/PostProcessResolution.java | 2 +- .../graph/PostProcessResource.java | 2 +- .../prewarm/RenderPrewarmContributors.java | 2 +- .../engine/prewarm/RenderPrewarmManager.java | 10 +- .../engine/profiler/DevProfilerBridge.java | 2 +- .../engine/profiler/FrameStutterProfiler.java | 2 +- .../render/engine/profiler/GlSyncTracker.java | 2 +- .../render/engine/profiler/JfrProfiler.java | 2 +- .../render/engine/profiler/ProfilerLog.java | 2 +- .../render/engine/profiler/ProfilerPhase.java | 2 +- .../engine/profiler/ProfilerSettings.java | 2 +- .../engine/profiler/RenderCostProfiler.java | 2 +- .../engine/profiler/RenderFrameProfiler.java | 2 +- .../engine/profiler/RenderProfiler2D.java | 2 +- .../engine/profiler/RenderProfiler3D.java | 2 +- .../engine/profiler/SamplingProfiler.java | 2 +- .../engine/profiler/TracyGpuProfiler.java | 2 +- .../render/engine/profiler/TracyProfiler.java | 2 +- .../engine/renderer/FullScreenRenderer.java | 20 +- .../render/engine/renderer/MeshRenderer.java | 16 +- .../render/engine/renderer/RenderWarp.java | 2 +- .../engine/renderer/RenderWarpStack.java | 2 +- .../render/engine/renderer/Renderer2D.java | 1454 +--- .../engine/renderer/Renderer2DBlur.java | 157 + .../engine/renderer/Renderer2DChamfered.java | 175 + .../engine/renderer/Renderer2DCircles.java | 152 + .../engine/renderer/Renderer2DConnectors.java | 155 + .../engine/renderer/Renderer2DItems.java | 55 + .../engine/renderer/Renderer2DLines.java | 95 + .../renderer/Renderer2DLiquidGlass.java | 109 + .../engine/renderer/Renderer2DOrbiz.java | 117 + .../engine/renderer/Renderer2DPolygons.java | 183 + .../engine/renderer/Renderer2DRects.java | 152 + .../engine/renderer/Renderer2DRectsExtra.java | 188 + .../engine/renderer/Renderer2DRectsGlow.java | 151 + .../engine/renderer/Renderer2DSmokeFill.java | 105 + .../engine/renderer/Renderer2DTextures.java | 185 + .../render/engine/renderer/Renderer3D.java | 10 +- .../render/engine/renderer/ui/BlurSource.java | 2 +- .../engine/renderer/ui/Deferred2DSubmit.java | 2 +- .../renderer/ui/DeferredActionSubmit.java | 2 +- .../renderer/ui/DeferredOrderedSubmit.java | 2 +- .../renderer/ui/DeferredTexturedSubmit.java | 6 +- .../render/engine/renderer/ui/DrawBatch.java | 2 +- .../renderer/ui/FrameBlurCacheEntry.java | 2 +- .../renderer/ui/HudDeferredGuiElement.java | 4 +- .../render/engine/renderer/ui/ItemBatch.java | 2 +- .../engine/renderer/ui/ItemBatchRenderer.java | 30 +- .../engine/renderer/ui/ItemDrawCommand.java | 2 +- .../engine/renderer/ui/ItemResolveKey.java | 2 +- .../engine/renderer/ui/OrderedUiBatcher.java | 12 +- .../engine/renderer/ui/SharedBlurProfile.java | 2 +- .../render/engine/renderer/ui/TextBatch.java | 4 +- .../engine/renderer/ui/UiBatchPlan.java | 2 +- .../engine/renderer/ui/UiBatchStats.java | 2 +- .../engine/renderer/ui/UiBatchType.java | 54 +- .../render/engine/renderer/ui/UiBatcher.java | 2 +- .../engine/renderer/ui/UiBlurResources.java | 26 +- .../renderer/ui/UiDeferredScheduler.java | 14 +- .../renderer/ui/UiDirectTexturedRenderer.java | 8 +- .../engine/renderer/ui/UiEffectGraph.java | 6 +- .../engine/renderer/ui/UiItemSubmission.java | 2 +- .../engine/renderer/ui/UiPassCompiler.java | 2 +- .../engine/renderer/ui/UiPassExecutor.java | 6 +- .../renderer/ui/UiRenderDispatcher.java | 8 +- .../renderer/ui/UiRendererSubsystem.java | 6 +- .../renderer/ui/draw/UiBoxPathBuilder.java | 2 +- .../engine/renderer/ui/draw/UiBoxShape.java | 2 +- .../renderer/ui/draw/UiChamferRadii.java | 2 +- .../engine/renderer/ui/draw/UiCornerKind.java | 2 +- .../engine/renderer/ui/draw/UiCornerMode.java | 2 +- .../renderer/ui/draw/UiCornerRadii.java | 2 +- .../engine/renderer/ui/draw/UiCornerSpec.java | 2 +- .../engine/renderer/ui/draw/UiEdgeKind.java | 2 +- .../engine/renderer/ui/draw/UiEdgeSpec.java | 2 +- .../engine/renderer/ui/draw/UiEffectKind.java | 2 +- .../engine/renderer/ui/draw/UiEffectSpec.java | 2 +- .../renderer/ui/draw/UiMeshGeometry.java | 2 +- .../engine/renderer/ui/draw/UiPaint.java | 2 +- .../engine/renderer/ui/draw/UiPaintKind.java | 2 +- .../engine/renderer/ui/draw/UiPaints.java | 2 +- .../engine/renderer/ui/draw/UiPathCap.java | 2 +- .../engine/renderer/ui/draw/UiPathJoin.java | 2 +- .../engine/renderer/ui/draw/UiRect.java | 2 +- .../engine/renderer/ui/draw/UiShape.java | 2 +- .../engine/renderer/ui/draw/UiShapeKind.java | 2 +- .../renderer/ui/draw/UiShapeShaderParams.java | 2 +- .../engine/renderer/ui/draw/UiShapes.java | 2 +- .../engine/renderer/ui/draw/UiStroke.java | 2 +- .../renderer/ui/runtime/action/UiAction.java | 2 +- .../ui/runtime/action/UiActionContext.java | 2 +- .../ui/runtime/action/UiActionRef.java | 2 +- .../ui/runtime/action/UiActionRegistry.java | 2 +- .../ui/runtime/animation/UiAnimationSpec.java | 2 +- .../runtime/animation/UiAnimationState.java | 2 +- .../ui/runtime/animation/UiEasing.java | 2 +- .../ui/runtime/asset/UiAssetKind.java | 2 +- .../ui/runtime/asset/UiAssetProvider.java | 2 +- .../renderer/ui/runtime/asset/UiAssetRef.java | 2 +- .../ui/runtime/asset/UiAssetRegistry.java | 2 +- .../ui/runtime/asset/UiAssetResolver.java | 2 +- .../renderer/ui/runtime/core/UiBounds.java | 2 +- .../ui/runtime/core/UiComponentFactory.java | 2 +- .../ui/runtime/core/UiComponentRegistry.java | 2 +- .../renderer/ui/runtime/core/UiDocument.java | 2 +- .../renderer/ui/runtime/core/UiLifecycle.java | 2 +- .../renderer/ui/runtime/core/UiNode.java | 2 +- .../renderer/ui/runtime/core/UiNodeSpec.java | 2 +- .../renderer/ui/runtime/core/UiNodeType.java | 2 +- .../renderer/ui/runtime/core/UiProps.java | 2 +- .../renderer/ui/runtime/core/UiRuntime.java | 2 +- .../ui/runtime/core/UiRuntimeException.java | 2 +- .../renderer/ui/runtime/core/UiState.java | 2 +- .../ui/runtime/debug/UiPerfCounters.java | 2 +- .../runtime/debug/UiRuntimeDiagnostics.java | 2 +- .../ui/runtime/debug/UiTreeDumper.java | 2 +- .../ui/runtime/error/UiErrorPolicy.java | 2 +- .../ui/runtime/input/UiCursorManager.java | 2 +- .../ui/runtime/input/UiFocusManager.java | 2 +- .../ui/runtime/input/UiHitResult.java | 2 +- .../ui/runtime/input/UiHitTester.java | 2 +- .../ui/runtime/input/UiInputDispatcher.java | 2 +- .../ui/runtime/input/UiInputState.java | 2 +- .../ui/runtime/input/UiKeyboardEvent.java | 2 +- .../ui/runtime/input/UiPointerEvent.java | 2 +- .../ui/runtime/input/UiScrollEvent.java | 2 +- .../ui/runtime/layout/UiLayoutEngine.java | 2 +- .../ui/runtime/reconcile/UiDiffStats.java | 2 +- .../ui/runtime/reconcile/UiKeyPath.java | 2 +- .../ui/runtime/reconcile/UiNodeMatcher.java | 2 +- .../runtime/reconcile/UiReconcileContext.java | 2 +- .../ui/runtime/reconcile/UiReconciler.java | 2 +- .../ui/runtime/render/UiBlendSpec.java | 2 +- .../ui/runtime/render/UiClipStack.java | 2 +- .../runtime/render/UiImageRendererBridge.java | 2 +- .../runtime/render/UiItemRendererBridge.java | 2 +- .../runtime/render/UiPrimitiveRenderer.java | 2 +- .../ui/runtime/render/UiProjectionMode.java | 2 +- .../ui/runtime/render/UiRenderContext.java | 2 +- .../ui/runtime/render/UiRenderer.java | 2 +- .../runtime/render/UiTextEffectRenderer.java | 2 +- .../ui/runtime/render/UiTextRenderer.java | 2 +- .../runtime/script/CachedUiScriptRuntime.java | 2 +- .../script/JavetNativeResourceLoader.java | 12 +- .../runtime/script/JavetUiScriptEngine.java | 14 +- .../ui/runtime/script/UiBoundsPatchSet.java | 2 +- .../ui/runtime/script/UiScriptColor.java | 2 +- .../ui/runtime/script/UiScriptComponent.java | 2 +- .../ui/runtime/script/UiScriptEngine.java | 2 +- .../script/UiScriptEngineProvider.java | 2 +- .../ui/runtime/script/UiScriptModule.java | 4 +- .../runtime/script/UiScriptModuleHandle.java | 4 +- .../ui/runtime/script/UiScriptModuleId.java | 8 +- .../runtime/script/UiScriptModuleLoader.java | 6 +- .../script/UiScriptModuleRegistry.java | 4 +- .../script/UiScriptModuleTransform.java | 2 +- .../script/UiScriptObjectConverter.java | 2 +- .../ui/runtime/script/UiScriptPatchSet.java | 2 +- .../ui/runtime/script/UiScriptProps.java | 2 +- .../runtime/script/UiScriptRenderContext.java | 2 +- .../runtime/script/UiScriptRenderResult.java | 2 +- .../runtime/script/UiScriptRuntimeError.java | 2 +- .../runtime/script/UiScriptRuntimeSource.java | 2 +- .../ui/runtime/script/UiScriptSourceKind.java | 2 +- .../runtime/script/UiTypeScriptStripper.java | 2 +- .../renderer/ui/runtime/style/UiAlign.java | 2 +- .../renderer/ui/runtime/style/UiColor.java | 2 +- .../renderer/ui/runtime/style/UiJustify.java | 2 +- .../renderer/ui/runtime/style/UiOverflow.java | 2 +- .../ui/runtime/style/UiResolvedStyle.java | 2 +- .../renderer/ui/runtime/style/UiStyle.java | 2 +- .../ui/runtime/style/UiStyleCache.java | 2 +- .../ui/runtime/style/UiStyleParser.java | 2 +- .../ui/runtime/style/UiStyleResolver.java | 2 +- .../ui/runtime/style/UiStyleToken.java | 2 +- .../renderer/ui/runtime/style/UiTheme.java | 2 +- .../ui/runtime/style/UiThemeRegistry.java | 2 +- .../engine/rhi/FullscreenDrawCommand.java | 2 +- .../render/engine/rhi/GpuMeshHandle.java | 4 +- .../{CombatantRhi.java => LoVisualRhi.java} | 4 +- .../render/engine/rhi/MeshOwnership.java | 2 +- .../render/engine/rhi/RhiDrawCommand.java | 2 +- .../render/engine/rhi/RhiSamplerBinding.java | 2 +- .../lovisual/render/engine/rhi/RhiStats.java | 2 +- .../render/engine/rhi/RhiStatsSnapshot.java | 2 +- .../render/engine/rhi/RhiUniformBinding.java | 2 +- .../engine/rhi/backend/SodiumGlBackend.java | 4 +- .../rhi/backend/gl/GlBackendAccess.java | 4 +- .../gl/clip/GlStencilFramebufferSupport.java | 8 +- .../gl/clip/GlStencilShapeClipBackend.java | 2 +- .../state/SodiumGlPipelineStateBackend.java | 8 +- ...ackend.java => LoVisualVulkanBackend.java} | 8 +- .../vulkan/clip/VulkanShapeClipBackend.java | 4 +- .../vulkan/clip/VulkanShapeClipBridge.java | 4 +- .../clip/VulkanStencilAttachmentManager.java | 4 +- .../vulkan/msaa/VulkanMsaaControl.java | 10 +- .../vulkan/msaa/VulkanMsaaResolveBridge.java | 8 +- .../state/VulkanPipelineStateBackend.java | 6 +- .../vulkan/util/VulkanRenderStateBridge.java | 16 +- .../vulkan/util/VulkanRuntimeGuards.java | 6 +- .../rhi/blit/Blaze3dTextureBlitter.java | 2 +- .../engine/rhi/blit/TextureBlitter.java | 2 +- .../engine/rhi/clip/ShapeClipBackend.java | 2 +- .../rhi/clip/ShapeClipRenderPassContract.java | 2 +- .../fullscreen/Blaze3dFullscreenBackend.java | 6 +- .../rhi/fullscreen/FullscreenBackend.java | 2 +- .../render/engine/rhi/msaa/MsaaControl.java | 2 +- .../engine/rhi/msaa/SodiumGlMsaaControl.java | 8 +- .../engine/rhi/pipeline/BlendPolicy.java | 2 +- .../engine/rhi/pipeline/CullPolicy.java | 2 +- .../engine/rhi/pipeline/DepthPolicy.java | 2 +- .../render/engine/rhi/pipeline/FogPolicy.java | 6 +- .../engine/rhi/pipeline/PipelineDomain.java | 2 +- .../engine/rhi/pipeline/PipelineKey.java | 12 +- .../engine/rhi/pipeline/PipelineMetadata.java | 2 +- .../rhi/pipeline/RenderPipelineRegistry.java | 4 +- .../rhi/pipeline/RenderPipelineSpec.java | 2 +- .../rhi/pipeline/UniformLayoutSpec.java | 2 +- .../engine/rhi/pipeline/VertexLayoutSpec.java | 2 +- .../FrameResourceRetirementQueue.java | 2 +- .../rhi/resource/FramebufferDescriptor.java | 4 +- .../engine/rhi/resource/FramebufferPool.java | 2 +- .../rhi/resource/GlyphAtlasManager.java | 2 +- .../engine/rhi/resource/GlyphAtlasPage.java | 2 +- .../rhi/resource/RenderResourceManager.java | 4 +- .../resource/RenderResourceStatsSnapshot.java | 2 +- .../rhi/resource/ResourceLeakTracker.java | 2 +- .../engine/rhi/resource/SamplerCache.java | 2 +- .../engine/rhi/resource/TexturePool.java | 2 +- .../rhi/scissor/GlobalScissorState.java | 4 +- .../rhi/state/PipelineStateBackend.java | 2 +- .../engine/rhi/uniform/FrameResource.java | 2 +- .../uniform/LegacyUniformFrameResource.java | 4 +- ...tor.java => LoVisualUniformAllocator.java} | 18 +- .../rhi/uniform/UniformAllocatorStats.java | 2 +- .../UniformAllocatorStatsSnapshot.java | 2 +- .../rhi/upload/Blaze3dDynamicMeshBackend.java | 14 +- .../engine/rhi/upload/Blaze3dFrameFence.java | 2 +- .../rhi/upload/Blaze3dMeshAllocation.java | 2 +- .../engine/rhi/upload/Blaze3dMeshArena.java | 2 +- .../engine/rhi/upload/DynamicMeshBackend.java | 2 +- ...ources.java => LoVisualShaderSources.java} | 14 +- .../render/engine/svg/SvgColorMode.java | 2 +- .../render/engine/svg/SvgInlineText.java | 2 +- .../render/engine/svg/SvgMeshBackend.java | 22 +- .../render/engine/svg/SvgMsdfRegistry.java | 6 +- .../render/engine/svg/SvgPathParser.java | 2 +- .../render/engine/svg/SvgRegistry.java | 6 +- .../render/engine/svg/SvgRenderOptions.java | 2 +- .../lovisual/render/engine/svg/SvgStyle.java | 2 +- .../render/engine/svg/SvgStyleUtil.java | 2 +- .../render/engine/text/BuiltinFontFace.java | 4 +- .../engine/text/CustomTextRenderer.java | 14 +- .../render/engine/text/EmptyGlyphFont.java | 2 +- .../lovisual/render/engine/text/Font.java | 4 +- .../render/engine/text/FontDebugStats.java | 2 +- .../lovisual/render/engine/text/FontFace.java | 4 +- .../render/engine/text/FontFamily.java | 4 +- .../lovisual/render/engine/text/FontInfo.java | 4 +- .../render/engine/text/FontUtils.java | 2 +- .../lovisual/render/engine/text/Fonts.java | 4 +- .../render/engine/text/GlyphFont.java | 2 +- .../lovisual/render/engine/text/MsdfFont.java | 2 +- .../render/engine/text/SystemFontFace.java | 4 +- .../engine/text/TextBackendPreference.java | 2 +- .../render/engine/text/TextClipSpec.java | 2 +- .../render/engine/text/TextCommandBuffer.java | 10 +- .../render/engine/text/TextCommandStats.java | 2 +- .../engine/text/TextCommandStatsSnapshot.java | 2 +- .../render/engine/text/TextEffectSpec.java | 2 +- .../render/engine/text/TextGlyphFallback.java | 4 +- .../render/engine/text/TextRenderSystem.java | 20 +- .../render/engine/text/TextRenderer.java | 4 +- .../engine/text/VanillaTextRenderer.java | 4 +- .../render/engine/text/WorldTextRenderer.java | 12 +- .../text/backend/BitmapAtlasTextBackend.java | 10 +- .../text/backend/GlyphAtlasManager.java | 2 +- .../engine/text/backend/GlyphAtlasPage.java | 2 +- .../engine/text/backend/MsdfTextBackend.java | 10 +- .../engine/text/backend/TextBackend.java | 10 +- .../text/backend/TextBackendRouter.java | 8 +- .../engine/text/backend/TextDrawCommand.java | 2 +- .../text/backend/TextPlacementMode.java | 2 +- .../text/backend/TextPlacementResolver.java | 2 +- .../text/backend/TextPlacementTransform.java | 2 +- .../engine/text/backend/TextRenderDomain.java | 2 +- .../backend/VanillaSodiumTextBackend.java | 8 +- .../render/engine/uniform/MeshBuilder.java | 18 +- .../render/engine/uniform/MeshData.java | 4 +- .../uniform/impl/DepthOfFieldUniforms.java | 14 +- .../uniform/impl/HandGlassUniforms.java | 14 +- .../uniform/impl/HandMetallicUniforms.java | 14 +- .../uniform/impl/HandSmokeUniforms.java | 14 +- .../engine/uniform/impl/HeatUniforms.java | 14 +- .../uniform/impl/MenuBackgroundUniforms.java | 14 +- .../engine/uniform/impl/MeshUniforms.java | 16 +- .../uniform/impl/MotionBlurUniforms.java | 14 +- .../engine/uniform/impl/MsdfTextUniforms.java | 14 +- .../engine/uniform/impl/PostFXUniforms.java | 14 +- .../uniform/impl/PostProcessUniforms.java | 14 +- .../uniform/impl/ShaderEspBlurUniforms.java | 14 +- .../impl/ShaderEspGradientUniforms.java | 14 +- .../uniform/impl/ShaderEspSmokeUniforms.java | 14 +- .../engine/uniform/impl/SkySunUniforms.java | 14 +- .../uniform/impl/SkyboxShaderUniforms.java | 14 +- .../uniform/impl/TextureTintUniforms.java | 14 +- .../engine/uniform/impl/UIBatchUniforms.java | 14 +- .../engine/uniform/impl/UIBlurUniforms.java | 14 +- .../uniform/storage/FixedUniformStorage.java | 2 +- .../engine/vertex/CombatantVertexFormats.java | 134 - ...java => LoVisualVertexFormatElements.java} | 4 +- .../engine/vertex/LoVisualVertexFormats.java | 134 + ...ualFrame.java => LoVisualVisualFrame.java} | 6 +- ...isualPass.java => LoVisualVisualPass.java} | 10 +- ...ualPhase.java => LoVisualVisualPhase.java} | 4 +- ...atantVisuals.java => LoVisualVisuals.java} | 42 +- .../render/engine/world/WorldBatcher.java | 6 +- .../engine/world/WorldCommandBuffer.java | 2 +- .../render/engine/world/WorldDrawCommand.java | 2 +- .../engine/world/WorldPassCompiler.java | 18 +- .../render/engine/world/WorldRenderStats.java | 2 +- .../world/WorldRenderStatsSnapshot.java | 2 +- .../world/WorldWideLineMeshCompiler.java | 20 +- .../lovisual/render/helpers/ClipFunction.java | 6 +- .../render/helpers/EffectIconRenderer.java | 2 +- .../render/helpers/GuiSpriteBatch.java | 2 +- .../lovisual/render/helpers/HeadAnchor.java | 2 +- .../render/helpers/MatteHudStyle.java | 2 +- .../lovisual/render/helpers/Particle3D.java | 2 +- .../render/helpers/ParticleTextureMode.java | 2 +- .../render/helpers/PlayerHeadRenderer.java | 4 +- .../render/helpers/ScissorFunction.java | 6 +- .../render/helpers/ScreenProjection.java | 10 +- .../render/helpers/ScreenSpaceOverlay2D.java | 2 +- .../render/helpers/SodiumMaterialFlags.java | 2 +- .../helpers/SodiumSurfaceFlagContext.java | 2 +- .../lovisual/render/helpers/SystemCursor.java | 6 +- .../lovisual/render/helpers/TickDelta.java | 2 +- .../lovisual/render/helpers/TrailPoint.java | 2 +- .../render/iris/IrisCompatibilityFeature.java | 2 +- .../render/iris/IrisCompatibilityGuards.java | 12 +- .../render/iris/IrisCompatibilityProfile.java | 2 +- .../iris/IrisCompatibilityProfiles.java | 2 +- .../iris/IrisFinalizedSceneRenderer.java | 4 +- .../render/iris/IrisHandMaskState.java | 2 +- ...Hooks.java => IrisLoVisualFrameHooks.java} | 8 +- .../lovisual/render/iris/IrisRuntime.java | 8 +- .../render/iris/IrisRuntimeBridge.java | 10 +- .../render/iris/IrisRuntimeSnapshot.java | 2 +- .../lovisual/render/iris/IrisSceneDepth.java | 4 +- .../render/iris/IrisSecondHandScene.java | 2 +- ...niforms.java => LoVisualIrisUniforms.java} | 38 +- .../iris/patch/ShaderPatchCompiler.java | 8 +- .../iris/patch/ShaderPatchCompilerCli.java | 2 +- .../render/iris/patch/ShaderPatchEngine.java | 6 +- .../render/sky/CustomSkyboxRenderer.java | 20 +- .../render/sodium/SodiumFrameContext.java | 4 +- .../render/sodium/SodiumRenderBridge.java | 4 +- .../SodiumSectionVisibilityProvider.java | 2 +- .../sodium/SodiumShaderWorkarounds.java | 12 +- .../render/sodium/SodiumTerrainInterop.java | 4 +- .../SodiumTerrainInteropStatsSnapshot.java | 2 +- .../sodium/SodiumVisibilityStatsSnapshot.java | 2 +- .../CombatantChunkVertexExtension.java | 16 - ....java => LoVisualChunkMeshAttributes.java} | 8 +- ...ats.java => LoVisualChunkMeshFormats.java} | 6 +- .../terrain/LoVisualChunkVertexExtension.java | 16 + ...Type.java => LoVisualModelVertexType.java} | 8 +- ...Vertex.java => LoVisualTerrainVertex.java} | 8 +- .../loki/lovisual/runtime/ClientRuntime.java | 228 - .../lovisual/runtime/ClientRuntimeState.java | 17 - .../runtime/RuntimeCleanupReport.java | 98 - .../lovisual/runtime/RuntimeDiagnostics.java | 71 - .../loki/lovisual/runtime/RuntimeGate.java | 49 - .../runtime/RuntimeResumeParticipant.java | 14 - .../runtime/RuntimeShutdownContext.java | 44 - .../runtime/RuntimeShutdownParticipant.java | 14 - .../loader/JarReplacementCoordinator.java | 16 - .../lovisual/runtime/loader/LoaderBridge.java | 22 - .../PanicOnlyJarReplacementCoordinator.java | 27 - .../loader/RuntimeGateSourcePolicy.java | 27 - .../runtime/loader/RuntimeSourcePolicy.java | 16 - .../loader/StandardFabricLoaderBridge.java | 62 - .../java/dev/loki/lovisual/util/FastFps.java | 2 +- .../loki/lovisual/util/LegacyHudNotifier.java | 2 +- .../loki/lovisual/util/NarratorBlocker.java | 5 +- .../dev/loki/lovisual/util/OmniItemUtils.java | 2 +- .../lovisual/util/aiming/AimPointUtil.java | 6 +- .../lovisual/util/aiming/RequestHandler.java | 6 +- .../aiming/RestrictedSingleUseAction.java | 6 +- .../lovisual/util/aiming/RotationManager.java | 10 +- .../lovisual/util/aiming/RotationTarget.java | 6 +- .../lovisual/util/aiming/RotationUtil.java | 6 +- .../lovisual/util/aiming/data/Rotation.java | 6 +- .../util/aiming/data/RotationDelta.java | 6 +- .../util/aiming/data/RotationWithVector.java | 6 +- .../aiming/features/MovementCorrection.java | 6 +- .../processors/FailRotationProcessor.java | 6 +- .../features/processors/LazyAimProcessor.java | 6 +- .../processors/MovingRotationProcessor.java | 6 +- .../processors/RotationProcessor.java | 6 +- .../processors/ShakeAimProcessor.java | 6 +- .../processors/SnapAssistAimProcessor.java | 6 +- .../processors/anglesmooth/AngleSmooth.java | 6 +- .../anglesmooth/FactorAngleSmooth.java | 6 +- .../anglesmooth/NoneAngleSmooth.java | 6 +- .../impl/AccelerationAngleSmooth.java | 6 +- .../impl/InterpolationAngleSmooth.java | 6 +- .../anglesmooth/impl/LinearAngleSmooth.java | 6 +- .../anglesmooth/impl/SigmoidAngleSmooth.java | 6 +- .../anglesmooth/impl/SmartAngleSmooth.java | 6 +- .../anglesmooth/impl/SpookyAngleSmooth.java | 11 +- .../util/aiming/point/PointInsideBox.java | 6 +- .../util/aiming/point/PointTracker.java | 6 +- .../preference/LeastDifferencePreference.java | 6 +- .../aiming/preference/RotationPreference.java | 6 +- .../aiming/raytrace/RotationRaytrace.java | 8 +- .../util/block/BlockDeobfuscationScanner.java | 2 +- .../BlockEspSodiumCandidateCollector.java | 2 +- .../util/block/BlockObservationHub.java | 2 +- .../util/block/BlockOutlineRenderer.java | 2 +- .../util/block/BlockOutlineShapeMode.java | 2 +- .../lovisual/util/block/BlockScanContext.java | 2 +- .../lovisual/util/block/BlockScanMode.java | 2 +- .../lovisual/util/block/BlockSearchUtil.java | 2 +- .../util/block/RenderSectionBlockScanner.java | 2 +- .../util/block/WorldSectionBlockScanner.java | 2 +- .../lovisual/util/block/bed/BedBlockUtil.java | 2 +- .../util/block/bed/BedwarsTeamColorUtil.java | 2 +- .../lovisual/util/block/bed/SelfBedMode.java | 2 +- .../util/block/bed/SelfBedTracker.java | 2 +- .../util/block/placer/BlockPlacer.java | 486 -- .../scaffold/ScaffoldBlockItemSelection.java | 103 - .../scaffold/ScaffoldFacePositionFactory.java | 546 -- .../scaffold/ScaffoldInteractionTarget.java | 78 - .../ScaffoldInteractionTargetFinder.java | 47 - .../util/block/scaffold/ScaffoldLine.java | 41 - .../scaffold/ScaffoldMovementPlanner.java | 117 - .../scaffold/ScaffoldMovementPrediction.java | 217 - .../block/scaffold/ScaffoldPlacementGate.java | 89 - .../scaffold/ScaffoldPlacementTarget.java | 89 - .../block/scaffold/ScaffoldTargetFinder.java | 321 - .../lovisual/util/click/AttackPressing.java | 2 +- .../lovisual/util/click/ClickHumanizer.java | 2 +- .../lovisual/util/click/ClickScheduler.java | 6 +- .../lovisual/util/combat/AntiBotTracker.java | 2 +- .../loki/lovisual/util/combat/AttackUtil.java | 33 +- .../util/combat/CombatRotationModeUtil.java | 2 +- .../util/combat/CombatStrikeController.java | 19 +- .../util/combat/LethalStrikeCalculator.java | 2 +- .../util/combat/ProtocolAttackExecutor.java | 2 +- .../util/combat/RubberHandUseUtil.java | 2 +- .../util/combat/SprintController.java | 27 +- .../util/combat/VulcanReachController.java | 2 +- .../protocol/ClientProtocolVersion.java | 2 +- .../CombatProtocolHeuristicSource.java | 2 +- .../protocol/CombatProtocolHeuristics.java | 2 +- .../CombatProtocolHeuristicsConfig.java | 2 +- .../util/combat/protocol/ProtocolUtil.java | 6 +- .../combat/protocol/vfp/VfpCompatibility.java | 6 +- .../protocol/vfp/VfpCompatibility1_8.java | 6 +- .../loki/lovisual/util/entity/EagleUtil.java | 2 +- .../lovisual/util/entity/FreecamEntity.java | 2 +- .../simulation/BoatSimulationCache.java | 2 +- .../simulation/MountedEntityPrediction.java | 2 +- .../simulation/PositionExtrapolation.java | 6 +- .../entity/simulation/PositionPredictor.java | 2 +- .../loki/lovisual/util/input/KeyManager.java | 2 +- .../dev/loki/lovisual/util/input/KeyUtil.java | 2 +- .../loki/lovisual/util/item/EnchantMeta.java | 2 +- .../lovisual/util/item/EnchantRegistry.java | 2 +- .../loki/lovisual/util/item/EnchantUtil.java | 2 +- .../dev/loki/lovisual/util/item/FoodUtil.java | 2 +- .../lovisual/util/item/IllegalItemUtil.java | 2 +- .../util/item/ItemRarityColorProvider.java | 2 +- .../lovisual/util/item/RarityColorConfig.java | 2 +- .../lovisual/util/item/RarityColorUtil.java | 2 +- .../lovisual/util/item/TopEnchantUtil.java | 2 +- .../loki/lovisual/util/logging/DebugLog.java | 2 +- .../loki/lovisual/util/logging/DebugMode.java | 2 +- .../lovisual/util/logging/ServerDumpUtil.java | 2 +- .../lovisual/util/map/MapPlayersCache.java | 2 +- .../lovisual/util/media/IMediaSession.java | 8 +- .../loki/lovisual/util/media/MediaInfo.java | 8 +- .../lovisual/util/media/MediaPlayerInfo.java | 8 +- .../util/media/MediaSessionService.java | 10 +- .../loki/lovisual/util/media/RepeatMode.java | 8 +- .../util/media/impl/DummyMediaPlayerInfo.java | 6 +- .../impl/linux/LinuxMediaPlayerInfo.java | 8 +- .../media/impl/linux/LinuxMediaSession.java | 8 +- .../util/media/impl/linux/dbus/Player.java | 8 +- .../impl/win/WindowsMediaPlayerInfo.java | 10 +- .../media/impl/win/WindowsMediaSession.java | 8 +- .../util/network/BacktrackController.java | 6 +- .../lovisual/util/network/BlinkManager.java | 6 +- .../util/network/FakeLagController.java | 6 +- .../lovisual/util/network/PacketSnapshot.java | 6 +- .../lovisual/util/network/TransferOrigin.java | 2 +- .../util/player/ElytraRecastUtil.java | 2 +- .../player/EnvironmentMovementController.java | 38 +- .../lovisual/util/player/InteractionUtil.java | 4 +- .../lovisual/util/player/MovementUtil.java | 6 +- .../util/player/NetworkStatsUtil.java | 2 +- .../util/player/PlayerHealthResolver.java | 2 +- .../util/player/PlayerSkinResolver.java | 2 +- .../lovisual/util/player/PlayerSpeedUtil.java | 2 +- .../util/player/ResetAttackCooldown.java | 2 +- .../lovisual/util/player/ServerFlyUtils.java | 2 +- .../player/effect/StatusEffectAccess.java | 2 +- .../player/effect/StatusEffectHeuristics.java | 4 +- .../player/effect/StatusEffectInference.java | 2 +- .../player/effect/StatusEffectTracker.java | 2 +- .../util/player/effect/StatusEffectView.java | 2 +- .../inventory/FireworkUseController.java | 13 +- .../player/inventory/InventoryActionKind.java | 2 +- .../inventory/InventorySearchScope.java | 2 +- .../util/player/inventory/InventorySwap.java | 14 +- .../player/inventory/InventorySwapMode.java | 2 +- .../player/inventory/InventorySwapPolicy.java | 2 +- .../inventory/InventorySwapRequest.java | 2 +- .../inventory/InventorySwapVisibility.java | 2 +- .../util/player/inventory/SlotResult.java | 2 +- .../simulation/LocalPlayerSimulation.java | 2 +- .../simulation/PlayerMovementSimulation.java | 8 +- .../simulation/PlayerSimulationCache.java | 6 +- .../simulation/RemotePlayerObservation.java | 2 +- .../simulation/RemotePlayerSimulation.java | 2 +- .../player/simulation/SimulatedInput.java | 6 +- .../CydhranianProjectileAngleCalculator.java | 6 +- .../util/projectile/PointFinding.java | 6 +- .../PolynomialProjectileAngleCalculator.java | 6 +- .../projectile/ProjectileAngleCalculator.java | 6 +- .../util/projectile/ProjectileMath.java | 6 +- .../projectile/ProjectilePredictionUtil.java | 6 +- .../util/projectile/ProjectileTarget.java | 6 +- .../ProjectileTargetPointFinder.java | 6 +- .../util/projectile/SimulatedArrow.java | 6 +- .../SituationalProjectileAngleCalculator.java | 6 +- .../util/projectile/TrajectoryData.java | 8 +- .../util/projectile/TrajectoryInfo.java | 6 +- .../util/projectile/TrajectoryType.java | 6 +- .../lovisual/util/proxy/ProxyBackend.java | 2 +- .../loki/lovisual/util/proxy/ProxyConfig.java | 2 +- .../loki/lovisual/util/proxy/ProxyEntry.java | 2 +- .../util/proxy/ProxyHandshakeHandler.java | 2 +- .../util/proxy/ProxyNettyInstaller.java | 4 +- .../loki/lovisual/util/proxy/ProxyType.java | 2 +- .../lovisual/util/pvp/CooldownRegistry.java | 2 +- .../util/pvp/ItemCooldownRuleProvider.java | 2 +- .../util/pvp/ItemCooldownSnapshot.java | 2 +- .../lovisual/util/pvp/ItemUseCooldowns.java | 2 +- .../loki/lovisual/util/pvp/PvpChatParser.java | 2 +- .../lovisual/util/pvp/PvpOverlayParser.java | 2 +- .../dev/loki/lovisual/util/pvp/PvpState.java | 2 +- .../loki/lovisual/util/pvp/PvpTabParser.java | 2 +- .../loki/lovisual/util/pvp/PvpTagSource.java | 2 +- .../lovisual/util/pvp/PvpTargetState.java | 2 +- .../lovisual/util/pvp/PvpTargetTracker.java | 2 +- .../lovisual/util/pvp/PvpTextPatternUtil.java | 2 +- .../loki/lovisual/util/pvp/PvpTracker.java | 2 +- .../util/pvp/client/CooldownManager.java | 2 +- .../util/pvp/client/CooldownsState.java | 2 +- .../util/pvp/client/PendingUseTracker.java | 2 +- .../opponents/OpponentCooldownManager.java | 2 +- .../util/pvp/opponents/TotemPopCounter.java | 2 +- .../util/pvp/opponents/TotemPopSnapshot.java | 2 +- .../lovisual/util/raycast/RaycastUtil.java | 2 +- .../resources/RenderResourceReadiness.java | 2 +- .../util/resources/ResourceReloadHooks.java | 12 +- .../lovisual/util/screen/ClientScreen.java | 2 +- .../lovisual/util/screen/ScreenCatalog.java | 12 +- .../util/session/MicrosoftSessionResult.java | 2 +- .../session/MinecraftGameConfigHolder.java | 4 +- .../lovisual/util/session/SessionChanger.java | 32 +- .../util/session/SessionLoginData.java | 4 +- .../microsoft/DeviceAuthPendingException.java | 2 +- .../microsoft/MicrosoftAuthException.java | 8 +- .../microsoft/MicrosoftAuthService.java | 24 +- .../microsoft/MicrosoftDeviceCode.java | 6 +- .../util/session/microsoft/MicrosoftJson.java | 2 +- .../session/microsoft/MicrosoftTokens.java | 2 +- .../session/microsoft/MinecraftProfile.java | 2 +- .../util/session/microsoft/XboxToken.java | 2 +- .../lovisual/util/target/TargetManager.java | 2 +- .../lovisual/util/target/TargetingUtil.java | 2 +- .../loki/lovisual/util/text/ChatNameUtil.java | 2 +- .../lovisual/util/text/ClipboardUtil.java | 2 +- .../lovisual/util/text/LegacyTextUtil.java | 2 +- .../loki/lovisual/util/text/TextJsonUtil.java | 2 +- .../lovisual/util/text/TextRenderUtil.java | 2 +- .../lovisual/util/text/TextSelection.java | 2 +- .../dev/loki/lovisual/util/time/Timer.java | 2 +- .../lovisual/util/time/TimerController.java | 6 +- .../lovisual/util/wav/ClickGuiSounds.java | 2 +- .../lovisual/util/wav/CustomSoundEngine.java | 2 +- .../loki/lovisual/util/wav/SourcePool.java | 2 +- .../lovisual/util/wav/WavBufferCache.java | 2 +- .../dev/loki/lovisual/util/wav/WavData.java | 2 +- .../loki/lovisual/util/wav/WavDebugStats.java | 2 +- .../dev/loki/lovisual/util/wav/WavLoader.java | 2 +- .../dev/loki/lovisual/util/wav/WavSound.java | 2 +- .../lovisual/util/wav/WavSoundHelper.java | 2 +- .../util/world/ExplosionDamageUtil.java | 2 +- .../src/main/native/mediainfo/main.cpp | 42 +- .../src/main/native/mediainfo/main.h | 36 +- .../resources/assets/lovisual/lang/en_us.json | 3 - .../resources/assets/lovisual/lang/ru_ru.json | 3 - .../assets/lovisual/shaders/arc_batch.frag | 2 +- .../shaders/chamfered_rect_batch.frag | 2 +- .../shaders/chamfered_rect_stroke_batch.frag | 2 +- .../assets/lovisual/shaders/circle_batch.frag | 2 +- .../lovisual/shaders/core/entity_dither.fsh | 14 +- .../lovisual/shaders/core/entity_dither.vsh | 6 +- .../assets/lovisual/shaders/damage_tint.frag | 2 +- .../assets/lovisual/shaders/damage_tint.vert | 2 +- .../lovisual/shaders/depth_of_field.frag | 2 +- .../lovisual/shaders/gui_texture_lookup.frag | 2 +- .../assets/lovisual/shaders/hand_glass.frag | 2 +- .../lovisual/shaders/hand_metallic.frag | 2 +- .../assets/lovisual/shaders/hand_smoke.frag | 2 +- .../assets/lovisual/shaders/heat_fx.frag | 2 +- .../complementary_reimagined/r5/common.patch | 2 +- .../r5/composite1.patch | 80 +- .../r5/composite4.patch | 18 +- .../r5/deferred1.patch | 20 +- .../complementary_reimagined/r5/fog.patch | 62 +- .../r5/lighting.patch | 28 +- .../complementary_reimagined/r5/manifest.json | 16 +- .../complementary_reimagined/r5/water.patch | 28 +- .../iris-patches/photon/v1_3b/c0_vl.patch | 40 +- .../photon/v1_3b/c1_blend_layers.patch | 34 +- .../iris-patches/photon/v1_3b/lighting.patch | 26 +- .../iris-patches/photon/v1_3b/manifest.json | 8 +- .../photon/v1_3b/motion_blur.patch | 20 +- .../shaders/menu_background_aurora.frag | 2 +- .../shaders/menu_background_waves.frag | 4 +- .../assets/lovisual/shaders/metallic.frag | 2 +- .../assets/lovisual/shaders/motion_blur.frag | 2 +- .../lovisual/shaders/orbiz_ring_batch.frag | 2 +- .../assets/lovisual/shaders/portal_rift.frag | 2 +- .../assets/lovisual/shaders/pos_color.frag | 4 +- .../assets/lovisual/shaders/pos_color.vert | 4 +- .../lovisual/shaders/pos_color_fog.frag | 2 +- .../lovisual/shaders/pos_color_fog.vert | 2 +- .../shaders/pos_color_rect_params.vert | 2 +- .../shaders/pos_color_rect_params2.vert | 2 +- .../shaders/pos_color_skybox_shader.vert | 2 +- .../shaders/pos_local_color_rect_params.vert | 2 +- .../shaders/pos_local_color_rect_params2.vert | 2 +- .../shaders/pos_local_color_rect_params5.vert | 2 +- .../pos_local_color_rect_params5_generic.vert | 2 +- .../lovisual/shaders/pos_tex_color.frag | 4 +- .../lovisual/shaders/pos_tex_color.vert | 4 +- .../shaders/pos_tex_color_params2.vert | 2 +- .../shaders/pos_tex_color_rect_params.vert | 2 +- .../shaders/pos_tex_color_rect_params2.vert | 2 +- .../shaders/pos_tex_color_sky_fog.frag | 2 +- .../shaders/pos_tex_color_sky_fog.vert | 2 +- .../pos_tex_color_sky_fog_additive.frag | 2 +- .../lovisual/shaders/pos_tex_color_tint.frag | 2 +- .../pos_tex_local_color_rect_params.vert | 2 +- .../pos_tex_local_color_rect_params2.vert | 2 +- .../assets/lovisual/shaders/post_fx.frag | 2 +- .../lovisual/shaders/radial_glow_batch.frag | 2 +- .../lovisual/shaders/reimagined_skybox.frag | 2 +- .../lovisual/shaders/rounded_rect_batch.frag | 2 +- .../shaders/rounded_rect_corners_batch.frag | 2 +- .../shaders/rounded_rect_glow_batch.frag | 2 +- .../shaders/rounded_rect_shadow_batch.frag | 2 +- .../rounded_rect_soft_shadow_batch.frag | 2 +- .../rounded_rect_stroke_angular_batch.frag | 2 +- .../shaders/rounded_rect_stroke_batch.frag | 2 +- .../rounded_rect_stroke_corners_batch.frag | 2 +- .../shaders/rounded_rect_tex_batch.frag | 2 +- .../shaders/rounded_rect_tex_mask_batch.frag | 2 +- .../lovisual/shaders/shader_esp_gradient.frag | 2 +- .../lovisual/shaders/shader_esp_shadow.frag | 2 +- .../lovisual/shaders/shader_esp_smoke.frag | 2 +- .../assets/lovisual/shaders/sky_sun.frag | 2 +- .../lovisual/shaders/sleep_overlay.frag | 2 +- .../shaders/sodium/block_layer_opaque.fsh | 8 +- .../shaders/sodium/block_layer_opaque.vsh | 52 +- .../assets/lovisual/shaders/svg_msdf.frag | 2 +- .../assets/lovisual/shaders/text.frag | 4 +- .../assets/lovisual/shaders/text.vert | 4 +- .../lovisual/shaders/text_liquid_glass.frag | 2 +- .../shaders/text_liquid_glass_msdf.frag | 2 +- .../assets/lovisual/shaders/text_msdf.frag | 2 +- .../assets/lovisual/shaders/ui_blur.frag | 2 +- .../lovisual/shaders/ui_blur_batch.frag | 2 +- .../shaders/ui_blur_batch_corners.frag | 2 +- .../shaders/ui_liquid_glass_batch.frag | 2 +- .../shaders/ui_rounded_fill_smoke_batch.frag | 2 +- .../lovisual/shaders/ui_shape_batch.frag | 2 +- .../assets/lovisual/shaders/wide_line.vert | 2 +- .../lovisual/shaders/world_decal_sdf.frag | 2 +- .../lovisual/textures/particles/firefly.png | Bin 0 -> 19384 bytes .../assets/lovisual/ui/api/actions.d.ts | 2 +- .../assets/lovisual/ui/api/assets.d.ts | 2 +- .../ui/api/clickgui/settings_panel.js | 2 +- .../lovisual/ui/api/clickgui/theme_preview.js | 2 +- .../ui/api/hud/draggable/compact_stat.js | 2 +- .../ui/api/hud/draggable/inventory_panel.js | 2 +- .../lovisual/ui/api/hud/draggable/itemizer.js | 2 +- .../ui/api/hud/draggable/list_panel.js | 2 +- .../ui/api/hud/draggable/panel_base.js | 2 +- .../ui/api/hud/draggable/triangulator.js | 2 +- .../ui/api/hud/static/custom_health_bar.js | 2 +- .../ui/api/hud/static/dynamic_island.js | 2 +- .../ui/api/hud/static/tooltip_panel.js | 2 +- .../assets/lovisual/ui/api/runtime.d.ts | 2 +- .../assets/lovisual/ui/api/theme.d.ts | 2 +- .../resources/assets/lovisual/ui/api/ui.d.ts | 2 +- .../resources/assets/lovisual/ui/api/ui.js | 2 +- .../command/CommandDiscoveryTest.java | 5 +- .../impl/XaeroWaypointCommandTest.java | 2 +- .../module/modules/player/NoInteractTest.java | 2 +- .../script/JavetUiScriptEngineTest.java | 2 +- .../scaffold/ScaffoldPlacementGateTest.java | 305 - .../CommandEncoderDiagnosticsMixin.java | 44 +- .../RenderPassWrapperDiagnosticsMixin.java | 38 +- .../lovisual/mixins/VulkanBackendMixin.java | 2 +- .../VulkanCheckpointDiagnosticsMixin.java | 2 +- .../VulkanCommandEncoderDiagnosticsMixin.java | 16 +- .../mixins/VulkanDebugMessageMixin.java | 2 +- .../mixins/VulkanDeviceDiagnosticsMixin.java | 2 +- .../mixins/VulkanQueueSubmissionMixin.java | 2 +- .../VulkanRenderPassDiagnosticsMixin.java | 56 +- .../VulkanRenderPipelineDiagnosticsMixin.java | 2 +- .../vulkan/debug/VulkanCrashDiagnostics.java | 20 +- launcher/Cargo.lock | 6855 +++++++++++++++++ launcher/Cargo.toml | 36 + launcher/TODO.md | 37 + launcher/build.rs | 3 + launcher/src/api/mod.rs | 35 + launcher/src/main.rs | 52 + launcher/ui/main.slint | 63 + 1595 files changed, 35857 insertions(+), 51145 deletions(-) create mode 100644 backend/Cargo.lock create mode 100644 backend/Cargo.toml create mode 100644 backend/TODO.md create mode 100644 backend/src/main.rs create mode 100644 backend/src/routes/health.rs create mode 100644 backend/src/routes/mod.rs create mode 100644 backend/src/server/config.rs create mode 100644 backend/src/server/mod.rs create mode 100644 combatant-client-26.2/TODO.md create mode 100644 combatant-client-26.2/gradle/wrapper/gradle-wrapper.jar create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/Lifecycle.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigLang.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigNameProvider.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigObject.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigPaths.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigSerializer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigValueAliasProvider.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/DisableSettingI18n.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/JsonConfigObject.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/MainConfig.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingDef.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingDefProvider.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingOwner.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonBooleanGroupSchema.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonSettingSchema.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonSettingSchemas.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CombatPriority.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CombatProtocolHeuristicSources.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CommonKey.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/FakeLagFlushOn.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationMode.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationMovementCorrection.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationResetThreshold.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationResetTicks.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationThroughWalls.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationTiming.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/TargetFilters.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileApplier.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileBinaryCodec.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileCollector.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDateFormatter.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDiff.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDiffEngine.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileEntry.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileMeta.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileService.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileSnapshot.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileStorage.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileType.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileValueCodec.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BindMode.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BooleanMapValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BooleanValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ColorValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ConfigValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/EnumIds.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/EnumValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ItemCooldownRulesValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ItemIdSetValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/KeyBindValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ModeValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/NumberValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/RGBAColorValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/RGBColorValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/SetValue.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/StringValue.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/VanillaChatRuntimeCleanup.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/RuntimeCommand.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatCommandMerge.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatContextMenuHandler.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatContextMenuModel.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatDrawUtil.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatEditBoxUtil.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFontUtil.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFrameModel.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFrameRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatGlyphRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatInputHandler.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatInputRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatLayoutEngine.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatLineLayout.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMessageRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatModel.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMouseClickHandler.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSegmentUtil.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSuggestionRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSuggestionState.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatTooltipRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatViewport.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiDrawHelpers.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiEditorManager.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiFonts.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiInputHandler.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiKeyBindManager.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiKeyboardHandler.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiLifecycle.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiModel.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiPickerIconManager.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiRenderEngine.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiScreenManager.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTabBar.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTabState.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTextBatch.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTopLayer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigDiffPanelComponent.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigProfileCardComponent.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigProfilesComponent.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BindRendererUtil.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BooleanSettingRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingDrag.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingHexInput.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingHexState.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingLayout.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingMath.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingPresetHandler.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingPresetRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingSquareRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/FunctionBindSettingRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/GroupSettingRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/KeyBindSettingRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModeSettingRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingSkinUtil.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingTextInputUtil.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderSettingRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderTextInputHandler.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderTextInputState.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListSettingRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListTextEditHandler.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSettingRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSettingTextInputHandler.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudArcRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudContentRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudEffectsRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudEquipmentRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudFaceRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudFormatter.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudModel.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudPanelRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudTargetResolver.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudTextRenderer.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/RuntimeControlModule.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AttributeSwap.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoAnchor.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoAttack.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoBed.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoBow.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoCrystal.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Backtrack.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Criticals.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/ElytraTarget.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Hitbox.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/KTLeave.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/KillAura.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/MaceKill.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorActionUtil.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorDamageCandidate.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorDamageRules.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorData.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorEntityBlocker.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorInteractionUtil.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorPlacementMode.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorPlanner.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorRenderUtil.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedActionUtil.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedDamageCandidate.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedDamageRules.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedData.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedEntityBlocker.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedInteractionUtil.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedPlacementMode.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedPlanner.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedRenderUtil.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalAttempt.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalBaseEvaluator.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalBasePlanner.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalCrystalData.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalDamageCandidate.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalDamageRules.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalEntityBlocker.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalHand.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalInteractionUtil.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceData.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceScanDebug.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceValidationResult.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlacementMode.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlacementPlanner.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalRenderUtil.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalSelectionUtil.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalTracker.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/Panic.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/AirJump.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/AutoDodge.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ElytraFly.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ElytraHelper.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Flight.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Freeze.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/InventoryMove.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoFall.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoPush.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoStun.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Parkour.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Phase.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ReverseStep.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/SafeWalk.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Speed.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Sprint.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Step.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Strafe.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/SuperFirework.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/TargetStrafe.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Timer.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Velocity.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/WindJump.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AirPlace.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoArmor.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoEat.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoTotem.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/Scaffold.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/XCarry.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Esp2DRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Esp3DRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspColorUtil.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspEntityCollector.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspMeshBuilder.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspModel.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspOutlineRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspSearchOverlay.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderColor.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderMask.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagCache.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEffectsRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEnchantFormatter.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEquipmentRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagFaceRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagLabelBuilder.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagLayoutEngine.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagModel.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagOpponentRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagPlateRenderer.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagRenderer.java rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/{CombatantEntityRenderTypes.java => LoVisualEntityRenderTypes.java} (93%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/{CombatantRenderEngineBootstrap.java => LoVisualRenderEngineBootstrap.java} (73%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/{CombatantRenderSystem.java => LoVisualRenderSystem.java} (83%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/{CombatantWorldMatrices.java => LoVisualWorldMatrices.java} (95%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/{CombatantFrameGraph.java => LoVisualFrameGraph.java} (71%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/{CombatantRenderPipelines.java => LoVisualRenderPipelines.java} (90%) create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DBlur.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DChamfered.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DCircles.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DConnectors.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DItems.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DLines.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DLiquidGlass.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DOrbiz.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DPolygons.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRects.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRectsExtra.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRectsGlow.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DSmokeFill.java create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DTextures.java rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/{CombatantRhi.java => LoVisualRhi.java} (91%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/{CombatantVulkanBackend.java => LoVisualVulkanBackend.java} (97%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/{CombatantUniformAllocator.java => LoVisualUniformAllocator.java} (94%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/shader/{CombatantShaderSources.java => LoVisualShaderSources.java} (93%) delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/CombatantVertexFormats.java rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/{CombatantVertexFormatElements.java => LoVisualVertexFormatElements.java} (89%) create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/LoVisualVertexFormats.java rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/{CombatantVisualFrame.java => LoVisualVisualFrame.java} (85%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/{CombatantVisualPass.java => LoVisualVisualPass.java} (67%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/{CombatantVisualPhase.java => LoVisualVisualPhase.java} (75%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/{CombatantVisuals.java => LoVisualVisuals.java} (78%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/{IrisCombatantFrameHooks.java => IrisLoVisualFrameHooks.java} (88%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/{CombatantIrisUniforms.java => LoVisualIrisUniforms.java} (67%) delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantChunkVertexExtension.java rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/{CombatantChunkMeshAttributes.java => LoVisualChunkMeshAttributes.java} (69%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/{CombatantChunkMeshFormats.java => LoVisualChunkMeshFormats.java} (56%) create mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualChunkVertexExtension.java rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/{CombatantModelVertexType.java => LoVisualModelVertexType.java} (81%) rename combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/{CombatantTerrainVertex.java => LoVisualTerrainVertex.java} (93%) delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/ClientRuntime.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/ClientRuntimeState.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeCleanupReport.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeDiagnostics.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeGate.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeResumeParticipant.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeShutdownContext.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeShutdownParticipant.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/JarReplacementCoordinator.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/LoaderBridge.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/PanicOnlyJarReplacementCoordinator.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/RuntimeGateSourcePolicy.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/RuntimeSourcePolicy.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/StandardFabricLoaderBridge.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/placer/BlockPlacer.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldBlockItemSelection.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldFacePositionFactory.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldInteractionTarget.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldInteractionTargetFinder.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldLine.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldMovementPlanner.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldMovementPrediction.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementGate.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementTarget.java delete mode 100644 combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldTargetFinder.java create mode 100644 combatant-client-26.2/src/main/resources/assets/lovisual/textures/particles/firefly.png delete mode 100644 combatant-client-26.2/src/test/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementGateTest.java create mode 100644 launcher/Cargo.lock create mode 100644 launcher/Cargo.toml create mode 100644 launcher/TODO.md create mode 100644 launcher/build.rs create mode 100644 launcher/src/api/mod.rs create mode 100644 launcher/src/main.rs create mode 100644 launcher/ui/main.slint diff --git a/.gitignore b/.gitignore index 3624a1e..663e2d0 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,7 @@ Thumbs.db */run/ # Config -config/ +/config/ # Logs *.log diff --git a/TODO.md b/TODO.md index ea3190c..55349e1 100644 --- a/TODO.md +++ b/TODO.md @@ -1,248 +1,36 @@ -# LoVisual — План разработки с нуля +# LoVisual — структура проекта -## Принципы (в отличие от прошлого кала) -- **Никаких пустышек** — файл без реализации не создаётся -- **Никаких this-escape** — конструктор не публикует this -- **Никакого статика** — `Minecraft.getInstance()` только лениво, никогда в поле -- **Никаких мёртвых миксинов** — миксин только если он реально нужен -- **Каждый этап компилируется** — перед переходом к следующему -- **Никаких 140 папок** — плоская структура, группировка только по смыслу +Репозиторий разбит на 3 независимых компонента. **У каждого свой TODO, корневой TODO больше не ведётся.** + +| Компонент | Стек | TODO | +|-----------|------|------| +| `combatant-client-26.2/` | Java 25, Fabric (MC 26.2) | [`combatant-client-26.2/TODO.md`](combatant-client-26.2/TODO.md) | +| `backend/` | Rust 2024 + axum | [`backend/TODO.md`](backend/TODO.md) | +| `launcher/` | Rust 2024 + Slint | [`launcher/TODO.md`](launcher/TODO.md) | --- -## База: что осталось -- `ref/` — ~415 референс-модулей из 8 клиентов (не трогать) -- `.omo/` — конфиги opencode -- `.git/`, `.gitignore`, `.gitattributes` -- `SYSTEM.md` — описание архитектуры (актуализировать по ходу) +## Общие правила для Rust-компонентов (backend + launcher) +- KISS / DRY / SOLID +- Макс. 200 строк на файл +- Макс. 3 файла на папку +- Обязательно: `cargo fmt` + `cargo clippy --all-targets` + `cargo test` +- Запрещено `#[allow(dead_code)]` +- Запрещено `unsafe` в собственной логике +- Без пустышек: модуль создаётся только с рабочей реализацией +- Каждый этап компилируется --- -## Фаза 0: Project Setup -- [ ] Создать `mod/` (NeoForge 1.21.1, Gradle, Java 21) - - build.gradle.kts (userdev, checkstyle) - - settings.gradle.kts - - META-INF/neoforge.mods.toml - - access_transformer.cfg (только нужные записи) - - mixins.json (только файлы, которые реально есть) - - LoVisual.java — entry point - - LoVisualClient.java — client init -- [ ] Создать `backend/` (Go 1.24) - - go.mod - - cmd/server/main.go - - internal/config/config.go (!! существует до main.go) -- [ ] Создать `launcher/` (Rust) - - Cargo.toml - - src/main.rs +## Статус -### Проверка: `./gradlew build`, `go build ./cmd/server`, `cargo build` +### Backend +- [x] Каркас: config, /health, graceful shutdown, CORS +- [ ] Auth (argon2 + JWT), профили, конфиги, IRC — см. `backend/TODO.md` ---- - -## Фаза 1: Core Systems (мод) -- [ ] EventBus — свой, нестатический, с поддержкой cancellation - - Event.java (abstract), EventBus.java - - EventHandler аннотация - - post() прекращает итерацию при cancel -- [ ] Module base — без `Minecraft.getInstance()` в статике - - Module.java: lazy getMc(), рефлексия для settings, toggle/enable/disable - - ModuleInfo аннотация - - ModuleCategory enum (COMBAT, MOVEMENT, RENDER, PLAYER, MISC) -- [ ] Setting system — 6 типов: - - Setting, BooleanSetting, SliderSetting, ModeSetting, ColorSetting, BindSetting, MultiSelectSetting -- [ ] ModuleManager — регистрация, получение по имени/категории -- [ ] Command system — toggle, bind, help, config -- [ ] ConfigManager — .loconf, профили, автосейв (только после полной инициализации) -- [ ] Theme / ThemeManager — без garbage (Color кэш или прямые int) - -### Проверка: мод запускается, не падает, `/lovisual help` работает - ---- - -## Фаза 2: Mixins (только нужные) -- [ ] MinecraftClientMixin — runTick() → TickEvent -- [ ] InGameHudMixin — render → Render2DEvent -- [ ] GameRendererMixin — renderLevel → Render3DEvent -- [ ] ClientConnectionMixin — send/receive → PacketEvent -- [ ] KeyboardHandlerMixin — keyPress → KeyPressEvent -- [ ] MouseHandlerMixin — click → MouseClickEvent -- [ ] ClientPlayerEntityMixin — travel → MoveEvent (если нужен) - -### НИКАКИХ пустых миксинов. Никаких `cancellable=true` без cancel. - -### Проверка: все события постится, можно залогировать из любого модуля - ---- - -## Фаза 3: Первый рабочий модуль -- [ ] Sprint (MOVEMENT) — полный цикл: - - Вкл/выкл через `/lovisual toggle Sprint` - - onEnable → подписка, onDisable → отписка - - TickEvent → зажим CTRL - - Сохраняется в конфиг - - Клавиша привязывается через `/lovisual bind Sprint 29` - -### Проверка: модуль работает, конфиг сохраняется/грузится - ---- - -## Фаза 4: Modules — по одному, каждый рабочий - -### Combat (4) -- [ ] AutoClicker — CPS на клик, не юзать System.currentTimeMillis() -- [ ] Trajectories — Render3DEvent, предсказание траектории -- [ ] Criticals — фолл-криты -- [ ] Velocity — анти-отбрасывание - -### Movement (3) -- [ ] Sprint ↑ (готов) -- [ ] Speed — страф/вода/эйр -- [ ] AutoWalk — зажим W - -### Render (12) -- [ ] FullBright — гамма -- [ ] NoHurtCam — отмена тряски -- [ ] NoWeather — отмена погоды -- [ ] NoBobbing — отмена качания -- [ ] Zoom — FOV smooth (без глитча при disable) -- [ ] Crosshair — кастомный -- [ ] Nametags — ники над игроками -- [ ] HealthTags — хп под никами -- [ ] HitParticles — частицы при ударе -- [ ] Chams — подсветка (миксин читает настройки модуля) -- [ ] Animations — свайпы/рука -- [ ] CustomGlint — кастомный глинт - -### Player (8) -- [ ] AutoTool — автосмена инструмента -- [ ] ExpThrower — авто-бросок опыта -- [ ] InvManager — сортировка/мусор -- [ ] MiddleClickFriend — добавить в друзья -- [ ] InventorySort — сортировка по клику -- [ ] Refill — авто-заполнение стаков -- [ ] NoInteract — блокировка кликов по сущностям -- [ ] Friends — список друзей - -### Misc (6) -- [ ] AntiAFK — анти-афк -- [ ] AutoRespawn — авто-респавн -- [ ] AutoReconnect — авто-переподключение -- [ ] IRC — WebSocket чат -- [ ] Spammer — авто-спам в чат -- [ ] NameProtect — защита ника - -### Extra (из ref/: только если реально нужны) -- [ ] KillAura -- [ ] ESP -- [ ] Scaffold -- [ ] Freecam -- [ ] Blink -- [ ] ElytraFlight -- [ ] AntiBot -- [ ] HitBox -- [ ] Tracers -- [ ] ItemPhysics -- [ ] ChestStealer -- [ ] AutoFish -- [ ] AutoEat - -### Проверка после каждого: модуль компилируется, включается/выключается, не крашит - ---- - -## Фаза 5: GUI - -### ClickGUI -- [ ] ClickGuiScreen — Screen -- [ ] CategoryPanel — чипсы категорий + поиск -- [ ] ModuleGrid — сетка модулей (ЛКМ toggle, ПКМ настройки, СКМ бинд) -- [ ] SettingsPanel — рендер настроек -- [ ] ThemePanel — слайдеры цветов - -### HUD (10 элементов) -- [ ] Watermark -- [ ] ModuleList -- [ ] TargetHUD -- [ ] ArmorHUD -- [ ] PotionsHUD -- [ ] Keystrokes -- [ ] Scoreboard -- [ ] Coords -- [ ] ComboCounter -- [ ] Notifications - -### MainMenu -- [ ] LoVisualMainMenu — кастомный экран - -### Проверка: GUI рендерится, кликабельно, модули togglятся - ---- - -## Фаза 6: Backend (Go) - -### Config (существует до main.go) -- [ ] internal/config/config.go — Port, DB.Path, JWT.Secret, CORS origins - -### DB -- [ ] internal/repository/db.go — SQLite, миграции -- [ ] internal/repository/users.go -- [ ] internal/repository/configs.go -- [ ] internal/repository/profiles.go - -### Auth -- [ ] internal/service/auth.go — bcrypt, JWT (не SHA256) -- [ ] internal/handler/auth.go — register/login/logout -- [ ] internal/middleware/auth.go — Bearer token (не panic, возвращает 401) - -### Profile -- [ ] internal/service/profile.go -- [ ] internal/handler/profile.go — get/update/playtime/search/friends -- [ ] JSON decode errors НЕ игнорировать - -### Configs API -- [ ] internal/handler/config.go — upload/download (auth check, user_id из токена, не из тела) -- [ ] 16-byte share keys (минимум) - -### IRC -- [ ] internal/irc/hub.go — WebSocket хаб (gorilla/websocket, не deprecated x/net) - -### Middleware -- [ ] CORS — настраиваемые origins -- [ ] RateLimit — с cleanup горутиной (без утечки) -- [ ] Log — запросы - -### Проверка: `go build ./cmd/server` проходит, сервер стартует, эндпоинты отвечают - ---- - -## Фаза 7: Launcher (Rust) - -### API клиент -- [ ] api.rs — reqwest, таймауты, десериализация с rename_all -- [ ] Версия читается из Cargo.toml (не хардкод) - -### Экраны -- [ ] login.rs — регистрация/логин -- [ ] dashboard.rs — профиль, playtime, version check -- [ ] settings.rs — кастомная команда (ЧИТАЕТСЯ на Play, не stale) - -### Launch -- [ ] launch.rs — запуск MC (команда из настроек, защита от пустой строки) -- [ ] save_session — только при логине, при logout удалять - -### Проверка: `cargo run` — лаунчер открывается, логин/регистрация работают - ---- - -## Фаза 8: Polish - -- [ ] Sound system (49 звуков из ref/) -- [ ] Animation system (SpringAnimator) -- [ ] Style system (6 стилей для HUD) -- [ ] Cloud config sharing (если бэкенд готов) -- [ ] Auto-updater -- [ ] Loading screen -- [ ] AltManager - ---- +### Launcher +- [x] Каркас: окно логина, фоновая проверка /health +- [ ] Auth, dashboard, settings, launch — см. `launcher/TODO.md` +### Мод (combatant-client-26.2) +- [ ] Полный rewrite: ребрендинг (1464 `combatant`), разбивка 12 файлов >1500 строк, выкинуть Runtime/JarReplacement, тесты — см. `combatant-client-26.2/TODO.md` diff --git a/backend/Cargo.lock b/backend/Cargo.lock new file mode 100644 index 0000000..fc3351a --- /dev/null +++ b/backend/Cargo.lock @@ -0,0 +1,2199 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures 0.2.17", + "password-hash", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +dependencies = [ + "serde_core", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cc" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crossbeam-queue" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "803d13fb3b09d88be9f4dbc29062c66b19bf7170867ceb746d2a8689bf6c7a26" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common 0.1.7", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "ctutils", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +dependencies = [ + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "etcetera" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" +dependencies = [ + "cfg-if", + "windows-sys", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flume" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" + +[[package]] +name = "futures-executor" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" + +[[package]] +name = "futures-sink" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" + +[[package]] +name = "futures-task" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" + +[[package]] +name = "futures-util" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core 0.10.1", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hashlink" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hybrid-array" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" +dependencies = [ + "typenum", +] + +[[package]] +name = "hyper" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "bytes", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881733cbc631fc9e472e24447ce32a64bedf2da498d6d8570b08edc87de71f65" +dependencies = [ + "base64", + "getrandom 0.2.17", + "js-sys", + "pem", + "serde", + "serde_json", + "signature", + "simple_asn1", + "zeroize", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "lovisual-backend" +version = "0.1.0" +dependencies = [ + "anyhow", + "argon2", + "axum", + "chrono", + "jsonwebtoken", + "serde", + "serde_json", + "sqlx", + "thiserror", + "tokio", + "tower", + "tower-http", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.3", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "mio" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex-automata" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] + +[[package]] +name = "sqlx" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb" +dependencies = [ + "base64", + "bytes", + "cfg-if", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.16.1", + "hashlink", + "indexmap", + "log", + "memchr", + "percent-encoding", + "serde", + "serde_json", + "sha2 0.10.9", + "smallvec", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.119", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3" +dependencies = [ + "cfg-if", + "dotenvy", + "either", + "heck", + "hex", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.119", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27" +dependencies = [ + "bitflags", + "byteorder", + "bytes", + "chrono", + "crc", + "digest 0.11.3", + "dotenvy", + "either", + "futures-core", + "futures-util", + "generic-array", + "log", + "percent-encoding", + "serde", + "sha1", + "sha2 0.11.0", + "sqlx-core", + "thiserror", + "tracing", +] + +[[package]] +name = "sqlx-postgres" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "rand", + "serde", + "serde_json", + "sha2 0.11.0", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c" +dependencies = [ + "atoi", + "chrono", + "flume", + "form_urlencoded", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "thiserror", + "tracing", + "url", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "thread_local" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "tokio-stream" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "whoami" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998767ef88740d1f5b0682a9c53c24431453923962269c2db68ee43788c5a40d" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/backend/Cargo.toml b/backend/Cargo.toml new file mode 100644 index 0000000..8c05998 --- /dev/null +++ b/backend/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "lovisual-backend" +version = "0.1.0" +edition = "2024" +rust-version = "1.85" +description = "LoVisual backend: auth, profiles, friends, cloud configs, IRC" +license = "GPL-3.0" + +[dependencies] +axum = "0.8.9" +tokio = { version = "1.53", features = ["full"] } +tower-http = { version = "0.7", features = ["cors", "trace", "fs"] } +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +sqlx = { version = "0.9", features = ["runtime-tokio", "sqlite", "chrono"] } +chrono = { version = "0.4", features = ["serde"] } +thiserror = "2" +anyhow = "1" +argon2 = "0.5" +jsonwebtoken = "11" +uuid = { version = "1", features = ["v4", "serde"] } + +[dev-dependencies] +tower = { version = "0.5", features = ["util"] } + +[lints.rust] +unsafe_code = "forbid" +dead_code = "deny" + +[lints.clippy] +correctness = "deny" +suspicious = "deny" +style = "deny" +complexity = "deny" +perf = "deny" + +[profile.release] +opt-level = 3 +lto = "fat" +codegen-units = 1 +panic = "abort" +strip = true diff --git a/backend/TODO.md b/backend/TODO.md new file mode 100644 index 0000000..a10d02e --- /dev/null +++ b/backend/TODO.md @@ -0,0 +1,51 @@ +# LoVisual Backend (Rust + axum) + +## Правила (ОБЯЗАТЕЛЬНЫЕ, нарушение = откат) +- **KISS / DRY / SOLID** — простая структура, без оверинжиниринга +- **Макс. 200 строк на файл** — превышение = разбить на модули +- **Макс. 3 файла на папку** — больше = новая подпапка по смыслу +- **Обязательное прохождение:** `cargo fmt` + `cargo clippy --all-targets` (ноль ошибок) + `cargo test` +- **Запрещено `#[allow(dead_code)]`** — мёртвый код удаляется, не прячется +- **Запрещено `unsafe`** (в собственной логике; lints: `unsafe_code = "forbid"`) +- **Без пустышек** — модуль создаётся только с рабочей реализацией +- **Каждый этап компилируется** — перед переходом к следующему +- **Ошибки JSON-декода не игнорировать** — всегда `.context()`/`?` +- **`user_id` из токена, не из тела запроса** + +--- + +## Сделано +- [x] Каркас: main.rs + server/{mod,config} + routes/{mod,health} +- [x] `GET /health` + graceful shutdown (SIGTERM/SIGINT) +- [x] Config из env (LOVISUAL_HOST/PORT/CORS_ORIGINS), валидация на старте +- [x] CORS (настраиваемые origins) + tower TraceLayer +- [x] Rust 2024 edition, актуальные версии пакетов + +--- + +## Фаза 1: DB (SQLite, sqlx) +- [ ] `src/db/mod.rs` — подключение, миграции +- [ ] `src/db/users.rs` — таблица users +- [ ] `src/db/configs.rs` — облачные конфиги +- [ ] `src/db/profiles.rs` — профили, playtime, friends + +## Фаза 2: Auth +- [ ] `src/auth/mod.rs` — argon2 + JWT (jsonwebtoken) +- [ ] `src/auth/handlers.rs` — register/login/logout +- [ ] `src/auth/middleware.rs` — Bearer token → 401, не panic + +## Фаза 3: Profile API +- [ ] `src/profile/mod.rs` — get/update/playtime/search/friends + +## Фаза 4: Configs API +- [ ] `src/config_api/mod.rs` — upload/download +- [ ] 16-byte share keys (минимум) + +## Фаза 5: IRC +- [ ] `src/irc/mod.rs` — WebSocket хаб (axum + tokio-tungstenite) + +## Фаза 6: Middleware +- [ ] RateLimit — с cleanup-задачей (без утечки) +- [ ] Request logging через tracing + +### Проверка после каждой фазы: `cargo fmt && cargo clippy --all-targets && cargo test` diff --git a/backend/src/main.rs b/backend/src/main.rs new file mode 100644 index 0000000..14f8465 --- /dev/null +++ b/backend/src/main.rs @@ -0,0 +1,30 @@ +//! LoVisual backend server entry point. + +mod routes; +mod server; + +use std::net::SocketAddr; + +use anyhow::Context as _; + +use server::config::Config; +use server::serve; + +fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| "lovisual_backend=info,tower_http=info".into()), + ) + .init(); + + let config = Config::from_env().context("failed to load config")?; + let addr: SocketAddr = config.listen_addr(); + tracing::info!(%addr, "starting lovisual backend"); + + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .context("failed to build tokio runtime")? + .block_on(serve(config)) +} diff --git a/backend/src/routes/health.rs b/backend/src/routes/health.rs new file mode 100644 index 0000000..9259410 --- /dev/null +++ b/backend/src/routes/health.rs @@ -0,0 +1,47 @@ +//! Health/liveness endpoints. + +use axum::Router; +use axum::routing::get; +use serde::Serialize; + +/// Health response body. +#[derive(Debug, Serialize)] +pub struct Health { + pub status: &'static str, + pub version: &'static str, +} + +/// Build the health router. +pub fn router() -> Router { + Router::new().route("/health", get(health)) +} + +async fn health() -> axum::Json { + axum::Json(Health { + status: "ok", + version: env!("CARGO_PKG_VERSION"), + }) +} + +#[cfg(test)] +mod tests { + use axum::body::Body; + use axum::http::{Request, StatusCode}; + use tower::ServiceExt as _; + + use super::*; + + #[tokio::test] + async fn health_returns_ok() { + let response = router() + .oneshot( + Request::builder() + .uri("/health") + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + } +} diff --git a/backend/src/routes/mod.rs b/backend/src/routes/mod.rs new file mode 100644 index 0000000..81ce5d2 --- /dev/null +++ b/backend/src/routes/mod.rs @@ -0,0 +1,13 @@ +//! Route definitions. +//! +//! Top-level router; each domain (auth, profile, configs, irc) will add its +//! own sub-router here. + +pub mod health; + +use axum::Router; + +/// Compose the full route tree. +pub fn router() -> Router { + Router::new().merge(health::router()) +} diff --git a/backend/src/server/config.rs b/backend/src/server/config.rs new file mode 100644 index 0000000..9ce8b1a --- /dev/null +++ b/backend/src/server/config.rs @@ -0,0 +1,120 @@ +//! Runtime configuration, loaded from environment variables. +//! +//! Parsed into validated types at the boundary; invalid values fail fast +//! at startup instead of blowing up mid-request. + +use std::env; +use std::net::{IpAddr, SocketAddr}; + +use anyhow::{Context as _, Result, bail}; +use axum::http::HeaderValue; +use tower_http::cors::AllowOrigin; + +/// Application configuration. +#[derive(Debug, Clone)] +pub struct Config { + pub host: IpAddr, + pub port: u16, + pub cors_origins: AllowOrigin, +} + +impl Config { + /// Default host for local development. + pub const DEFAULT_HOST: &'static str = "127.0.0.1"; + /// Default port for local development. + pub const DEFAULT_PORT: u16 = 8765; + + /// Load configuration from the environment. + pub fn from_env() -> Result { + Self::from_vars( + env::var("LOVISUAL_HOST").ok(), + env::var("LOVISUAL_PORT").ok(), + env::var("LOVISUAL_CORS_ORIGINS").ok(), + ) + } + + /// Build config from raw option values (injectable for tests). + fn from_vars(host: Option, port: Option, cors: Option) -> Result { + let host = host + .unwrap_or_else(|| Self::DEFAULT_HOST.to_owned()) + .parse() + .context("LOVISUAL_HOST is not a valid IP address")?; + let port: u16 = match port { + Some(p) => p + .parse() + .context("LOVISUAL_PORT is not a valid port number")?, + None => Self::DEFAULT_PORT, + }; + let origins = parse_origins(&cors)?; + + Ok(Self { + host, + port, + cors_origins: origins, + }) + } + + /// Resolved listen address. + pub fn listen_addr(&self) -> SocketAddr { + SocketAddr::new(self.host, self.port) + } +} + +fn parse_origins(raw: &Option) -> Result { + let Some(raw) = raw else { + // No origins configured: allow same-origin requests only. + return Ok(AllowOrigin::any()); + }; + + let origins = raw + .split(',') + .map(str::trim) + .filter(|s| !s.is_empty()) + .collect::>(); + if origins.is_empty() { + bail!("LOVISUAL_CORS_ORIGINS is set but contains no origins"); + } + + Ok(AllowOrigin::list( + origins + .into_iter() + .map(|o| o.parse::().context("invalid CORS origin")) + .collect::, _>>()?, + )) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn empty_origins_allows_any() { + assert!(parse_origins(&None).is_ok()); + } + + #[test] + fn empty_list_origin_string_fails() { + assert!(parse_origins(&Some(String::from(",,"))).is_err()); + } + + #[test] + fn invalid_port_fails() { + let result = Config::from_vars(None, Some("not-a-port".into()), None); + assert!(result.is_err()); + } + + #[test] + fn invalid_host_fails() { + let result = Config::from_vars(Some("not-an-ip".into()), None, None); + assert!(result.is_err()); + } + + #[test] + fn defaults_apply_when_empty() { + let config = Config::from_vars(None, None, None).unwrap(); + assert_eq!( + config.listen_addr(), + SocketAddr::from(([127, 0, 0, 1], 8765)) + ); + } +} diff --git a/backend/src/server/mod.rs b/backend/src/server/mod.rs new file mode 100644 index 0000000..09b3099 --- /dev/null +++ b/backend/src/server/mod.rs @@ -0,0 +1,57 @@ +//! Server assembly: router, listener, graceful shutdown. + +use anyhow::Context as _; +use axum::Router; +use tokio::net::TcpListener; +use tower_http::cors::CorsLayer; +use tower_http::trace::TraceLayer; + +use super::routes; +use config::Config; + +pub mod config; + +/// Build the application router for a given config. +pub fn app(config: &Config) -> Router { + Router::new() + .merge(routes::router()) + .layer(CorsLayer::new().allow_origin(config.cors_origins.clone())) + .layer(TraceLayer::new_for_http()) +} + +/// Bind and serve the application until a shutdown signal arrives. +pub async fn serve(config: Config) -> anyhow::Result<()> { + let listener = TcpListener::bind(config.listen_addr()) + .await + .context("failed to bind listener")?; + + axum::serve(listener, app(&config)) + .with_graceful_shutdown(shutdown_signal()) + .await + .context("server error") +} + +/// Resolves on SIGTERM/SIGINT. +async fn shutdown_signal() { + let ctrl_c = async { + tokio::signal::ctrl_c() + .await + .expect("failed to install ctrl-c handler"); + }; + + #[cfg(unix)] + let terminate = async { + tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) + .expect("failed to install SIGTERM handler") + .recv() + .await; + }; + + #[cfg(not(unix))] + let terminate = std::future::pending::<()>(); + + tokio::select! { + _ = ctrl_c => {}, + _ = terminate => {}, + } +} diff --git a/combatant-client-26.2/TODO.md b/combatant-client-26.2/TODO.md new file mode 100644 index 0000000..348fad4 --- /dev/null +++ b/combatant-client-26.2/TODO.md @@ -0,0 +1,123 @@ +# LoVisual Mod (combatant-client-26.2) — план переписи + +Мод — форк Combatant Client, переписываем под LoVisual. + +## Правила (ОБЯЗАТЕЛЬНЫЕ, нарушение = откат) +- **KISS / DRY / SOLID** — простая структура, без оверинжиниринга +- **Макс. 200 строк на файл** (было >1500) — превышение = разбить на модули +- **Макс. 3 файла на папку** — больше = новая подпапка по смыслу +- **Никакого статика** — `Minecraft.getInstance()` только лениво, никогда в поле +- **Никаких this-escape** — конструктор не публикует `this` +- **Никаких мёртвых миксинов** — миксин только если реально нужен; `cancellable=true` только при реальном cancel +- **Без пустышек** — файл без реализации не создаётся +- **Каждый этап компилируется** — `./gradlew build` перед переходом к следующему +- **Тесты обязательны** для новых модулей (JUnit) + +--- + +## СТАТУС ПРОБЛЕМ (что вижу сейчас) + +### 1. Ребрендинг не закончен (пункт 2) +- 288 файлов / **1464 упоминания** `combatant` в main-коде +- Классы: `CombatantRenderSystem`, `CombatantRenderEngineBootstrap`, `CombatantRenderPipelines`, `CombatantVulkanBackend`, `CombatantFrameGraph`, `CombatantTerrainVertex` и др. +- Заголовки файлов: «This file is part of the Combatant Client distribution» / `copyright (c) pivosos2007` + +### 2. Файлы-гиганты (пункт 3) — 12 файлов > 1500 строк +| Файл | Строк | +|------|-------| +| render/engine/renderer/Renderer2D.java | 3379 | +| features/gui/chat/BetterChatRenderer.java | 2870 | +| features/gui/clickgui/settings/UnifiedSettingRenderer.java | 2798 | +| features/module/modules/player/Scaffold.java | 2416 | +| features/module/modules/combat/AttributeSwap.java | 1922 | +| features/gui/clickgui/ClickGuiRenderer.java | 1900 | +| features/module/modules/visuals/NameTags.java | 1791 | +| features/module/modules/combat/ElytraTarget.java | 1711 | +| features/gui/hud/draggable/impl/TargetHud.java | 1687 | +| features/module/modules/visuals/ESP.java | 1520 | +| features/module/modules/combat/AutoCrystal.java | 1516 | +| features/gui/hud/nondraggable/impl/CustomBar.java | 1496 | + +### 3. Runtime / JarReplacement (пункт 4) +- `runtime/` (ClientRuntime, RuntimeGate, ClientRuntimeState, SOFT_PANIC/JAR_REPLACEMENT_PANIC, shutdown/resume-участники) +- `runtime/loader/` (JarReplacementCoordinator, LoaderBridge, PanicOnlyJarReplacementCoordinator) +- **Моё предложение: выкинуть.** Живая замена jar в памяти — источник classloader-утечек, хрупкая, для клиента не нужна (обновление делает лаунчер). Заменить на простой Lifecycle. + +### 4. Security (пункт 7) +- `features/security/BackdoorProtection` — на деле защита от SSRF/translate-инъекций (порт ExploitPreventer, MIT). Полезное, но `enum`-синглтон со статикой. +- `features/relations/StaffTracker` + `StaffHeuristicsMatcher` — детект «стафа» по эвристикам TAB. Сомнительно, решить оставить/выкинуть. + +### 5. Тесты (пункт 6) +- 5 тестов на ~213k строк. Добавлять по мере переписи модулей. + +--- + +## Фаза 1: Ребрендинг (пункт 2) +- [x] **Восстановлен `config/`-пакет** (55+3 файла) из `ref/zip/combatant-client-26.2 (1).zip` — он отсутствовал в форке, без него проект не собирался. Переименован `combatant.client.config` → `dev.loki.lovisual.config`. `compileJava` ✓ +- [x] Заменить `combatant` → `lovisual` в main-коде (1464 вхождения, 288 файлов) +- [x] Переименовать классы `Combatant*` → `LoVisual*` (23 шт., включая `IrisCombatantFrameHooks` → `IrisLoVisualFrameHooks`) +- [x] Заголовки файлов → LoVisual, пересобрать копирайты (GPLv3 форка) +- [x] Проверить `fabric.mod.json` / `lovisual.mixins.json` на остатки +- [x] Проверить строки/сообщения/логи на «combatant» +- [x] JNI-имена в native: `Java_combatant_client_` → `Java_dev_loki_lovisual_` (34 шт.) + FindClass-пути + +### Проверка: `rg -i combatant src` → 0 ✓, `./gradlew build` ✓ (1406 файлов изменено) + +## Фаза 2: Выкинуть Runtime/JarReplacement (пункт 4) +> **Вместе с рантаймом удалить и модуль Panic** (`features/module/modules/misc/Panic.java`), +> интерфейс `RuntimeControlModule`, команду `RuntimeCommand` и все ветки на них +> в `ModuleManager`/`Module`. Panic — единственная реализация `RuntimeControlModule`, +> без него они становятся мёртвым кодом. +- [x] Удалить `runtime/` и `runtime/loader/` (14 файлов) +- [x] Удалить `Panic.java` + `RuntimeControlModule.java` + `RuntimeCommand.java` +- [x] Убрать ветки `instanceof RuntimeControlModule` и `tickRuntimeControllers()` из ModuleManager/Module +- [x] Убрать `RuntimeGate` из точек входа (LoVisual.java, модули, рендер) — заменён на `Lifecycle` +- [x] Заменить на простой Lifecycle-класс (`dev.loki.lovisual.Lifecycle`: INIT → ACTIVE → SHUTDOWN, гейты `canRunRender/Hud/ShaderBridge` + `RenderResourceReadiness`) +- [x] Panic-фичи удалены; `ModuleManager.disableAll()` оставлен как простая утилита +- [x] Мёртвые cleanup-методы удалены (`shutdownForRuntime`, `clearRuntimeReferences`, `VanillaChatRuntimeCleanup`, i18n-ключи panic/runtime) + +### Проверка: `./gradlew build` ✓, тесты ✓ (13), `rg runtime-подсистема` → 0 + +## Фаза 3: Разбивка файлов-гигантов (пункт 3) — ОТЛОЖЕНА, сначала чистка модулей +- [ ] Сначала удалены читерские модули (см. Фазу 3.5) — рефакторить удалённые файлы не нужно +- [ ] Renderer2D (3379) → renderer + пакеты (текст, примитивы, deferred-слои) +- [ ] BetterChatRenderer (2870) → рендер, парсинг, кэш +- [ ] UnifiedSettingRenderer (2798) → по типам настроек +- [ ] ClickGuiRenderer (1900), NameTags (1791), TargetHud (1687), ESP (1538), CustomBar (1495) + +### Проверка: после каждого файла `./gradlew build`; цель ≤200 строк/файл + +## Фаза 3.5: Удаление читерских модулей (легит-направление) +> Пользователь решил: LoVisual — легитное приложение. Все читерские модули удаляются. +- [x] combat: удалены AttributeSwap, AutoAnchor, AutoAttack, AutoBed, AutoBow, AutoCrystal, Backtrack, + Criticals, ElytraTarget, Hitbox, KillAura, KTLeave, MaceKill. **Оставлены:** ProjectilePuncher, + PvpCooldowns, Reach, RubberHand, SpearAssist, TPSSync +- [x] movement: удалены ВСЕ модули (AirJump, AutoDodge, ElytraFly, ElytraHelper, Flight, Freeze, + InventoryMove, NoFall, NoPush, NoStun, Parkour, Phase, ReverseStep, SafeWalk, Speed, Sprint, + Step, Strafe, SuperFirework, TargetStrafe, Timer, Velocity, WindJump) — 22 файла +- [x] player: удалены AirPlace, AutoArmor, AutoEat, AutoTotem, Scaffold, XCarry. + **Оставлены:** AutoTool, ClickPearl, FakeLag, NoDelay, NoInteract, ShitDropper +- [x] Осиротевшие хелпер-пакеты: удалены `combat/autocrystal/` (17), `combat/autobed/` (9), + `combat/autoanchor/` (9), `util/block/scaffold/` (10), `BlockPlacer` + тест ScaffoldPlacementGateTest +- [x] Enum-заглушки: `KillAura.RaycastMode/RotationTiming/AngleSmoothMode` → локальные enum в + ProjectilePuncher/Reach; `Criticals.SelectionMode` → удалено; `Hitbox`-зависимость убрана из ESP +- [x] ESP переписан под легит: новые настройки `only_visible` (LOS-луч от камеры), `skip_invisible`, + `only_armor` (без брони не подсвечивать) — по умолчанию `true`, только для игроков + +### Проверка: `./gradlew build` ✓, тесты ✓ (13), остатки только в комментариях/строках + +## Фаза 4: Security (пункт 7) +- [ ] BackdoorProtection: убрать `enum`-синглтон, сделать инстансный сервис, ленивый `Minecraft.getInstance()` +- [ ] Решить судьбу StaffTracker/StaffHeuristics — согласовать и выкинуть или переписать +- [ ] Покрыть логику фильтров тестами + +## Фаза 5: Модули — нормализация под правила +- [ ] Прочесать все 131 модуль: убрать `static final Minecraft` в полях (6 шт. уже найдено) +- [ ] Проверить модули на `System.currentTimeMillis()` → заменить на игровое время +- [ ] Разнести addon/events/mixininterface по смыслу + +## Фаза 6: Тесты (пункт 6) +- [ ] Юнит-тесты: EventBus, конфиг, утилиты (игровые классы — mock) +- [ ] По мере переписи модулей — тест на каждый + +### Проверка: `./gradlew test` зелёный diff --git a/combatant-client-26.2/gradle/wrapper/gradle-wrapper.jar b/combatant-client-26.2/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..b1b8ef56b44f16b14dc800fa8103a6d89abb526f GIT binary patch literal 48462 zcma&NV{|3jwk;gnwr$(CRk3Z`Sy9Ed?Nn^ruGlsztklcC=e7I2x9>aqJFB(1eyu-q z%|3b`eLzVT6buar3JMAc2#EOW{C^)LAZQ?YaW!FjX$1*JIcZUG1yyl%HEd!6f#E+}*Jo*NafvM<-FbE0;-_L#rp}qdn%JEoAVNlEB#J^Oq`mU_#*ev4HLmc> zjXz_hFft^><#omb;Zer-%wm4hxo!wjuX3hBldg(^-RiOleKin`>KHfL3P*{k?(rji(#j2Cc0K509#>qu=-T&B!-5EBi(+ zIuTD-qfcAYgS@`Fb2^-p)4#o6A3z0&fp?~cV=CRsAeCmO4ZQ5kKgC%0el=Q&Rhd#k zaGmAbUW8uKC}-C0s~2);d{;mpsNBx9rn__66W{AhaSvJEK+c0b6ARO+l(CI7E|S5x zhaYP--@F<|99X&)9`q^2(^-Zu^Tzfm)v|gkTJHQ!G*zIg5hzoygeXZoYUEJ;iFkE# zq^r$*c|>Hmn3GapzcDYnjgSFiO^NFyTR5AH#mh%zRToMpEi(r)1$5)h455DuV}0al z!*psWuL@Ke-2gvftfMEGf9YEi^<{B@qru zINgo+YsE&LN?)1qItJoNhISp-fZ86`XR#*6xcvM~_7=JHUX;K9*=Gu5X~ zix|O2d=&C#u_w{=B$eCpJ4L*6i7={j+{Og~`Emz@&98}6s<-p^)`0fXE4cJBP{>)Ltb>JwcqI>yz z0-r-SEhC@p)XOoh|1|XgjFaREHfsu4dAGVz*k#m+V<4 zHqvlud6=;#QWHUoTR_a8Y8+heN?M%n1@0YLiaN@GuOPNd26tik7eKulTx?mM-R!1H znB6+H{^krFXg_b{y=QeCT~qR3T4}l+b!Oz9;~|3*6F<3?#|DYYW&1RtFE)ILZ!`85 zVmvrZkLTzf31unH7Cc5E0iFShqlBE9hgEnRJH1juII*vyp&xd!g`q}X_6WT6E$hhQ`Vdp9k^<)VS?lj!cTh z7FQcQAVA@jL^cXod8cnhKG2TS9+;QU6Kq>}UOY3&TL9gXbl{Fv8@WsF=z7>X0To@$ zY@Oi1uc|MdJ$>Kn{@!g_e`-I&Tpwfg9cr>(iakDX1qciCG_1y!Di#4_)lE!bWJbrp z5aUonb6m-?tiQyR_`P#~SOu+tb_ev6JO>EbEhHK@KbeT0_FDo>dl9bMg)>xmCNB*g zG5NC8ABavuTEZVGW6jP*nAqRt3W?7Iigc-EE~zpNJXRAE z>`~RO9$892j&I1kV;9U)xT8^}IeV`n{}QDtj2o-RBt`DGZUOO;O*lFCb_vpyGh*;95PfeGu!dyrmZ9VJ3Z*upg z6R-3Lr%_55$Hw1^{+KWx0#z`T7O6sXo1h;m?B_ur`X2bFz-SzDrL zpk^@B<+I6imc@7vip za%1jMB7q@1j# zz{u?YojZMW{5j$@h=v4iu2mTu7IzI|)Sxn!74=*J>1a&?Xjt z2%JhSi#4huEcD9qdR9Lj4vwmfnL{%+vQ{f-KgYeqin(OPd8+(g*Uq#TLxQjD4 zLCL%ul(V&PAPlAx8D`@K8Rc`{GPecQ<)d=KWel0ejFeeXGQ6o7601B!!I@RY&eDriADD6wP6DcFKDLZ|lO#YwnrNCZ)zRJpdxX_nPZa4j#$j6v!h|6p!dH}MY6#B`@%6=) z-HigguDACKBULnon^FKzazF|Y1{t(U5rUGnEU|}djVsWT-F>@@mNx?_$kF51QF4C5 zStKR$^3(fw85(4HGs9{mUTtn1)3PwxTN?6}j;32&vJ^BiPHfndLkdU5sOemXKGyCZ z@<7j(k>DNeo~QXyJkFWk!7(y1SB%nA3{v~P2c8ooKa4auM!el!Q_=;lJ$c5ADqE+^ zX8*|A99v;jWPrm(8=h;2ZAj|(vVbx~wQ{N%v;eYLD_BB2LAEWCs@xauyBDl(_HIBvA(XJ7B1E;O zJYCJ8xFJh7f5sr;Y#Wp_`$4Z_H4e9bGiBp?Qu&2!@%Bl2dT5evfFO*^hLDiBu2%Jl z*WAlL5PaQ7skJa(qVysky}DQquZ8U?2@UyJ8zB#=U_E>MgE%XA$CtfL31m$rATJvC zs@!crc0=128PM=Zp zW_5Czv9))n_8Ru?{pxM2F8^r%*O41}RnONbSj*piG%`nyF>6ky=|;B&k8iot(J=kyoU3p<_zaAX(1ijzf*uXA zZ_5jeC{Lks+&QeFIlmzZi3+fsF4fNW^~kvC4Q*T-vrNP!x9xnen12lZQM=1_MdW76LKX(GuW`%T~dM^YX6+ras|Xy4Qhfcq=D+z-P-ea z`T;^gj3+grr3^hwqcNTJErl$z+k>{bYFm6QV%7Opth?9+>|Dn)O@`7F@=j-XSqGPW zjUAu%b3Er@;j1%RZxVDhI3sakg-gvTLOSV7;FV6ED=(5;UG??=WADZw^=$4AyFh#}VMe3afM^pF zFa}-nM8X=K?Jy02*o02@6k{ z%O!hBhjXlXKdhy3A{xGB<##e|j3^dFv~~%v2_H{t(mN7NVeS~51?D&Ozbxa`qwZ_4 z;C#Q#fL1sua%ggucgIEHZtcY=Ag&GgE|h7Q{77D!WUq`;SSGEE0pU;aoj<7-JCAvf zduN=(tx3Mb+EUXKoax|v;8b@#HJ&Q|!g4ryrl|R>WlAv?IH`bk)I24;eE4NIq@SLK31LD4+w~#3iN{=<`<1R!t^$@K5>U6%W=%8_ANuR5 zs(IDuI18ftirTDARnGmF%;iz+4{MlMihJw_l!0Y)NttXC_t+s)V<EY>=Xin*nGX79k6vQ?beRk zy_J>@YSC_gMIG$yjO-y&o>S6xtfT27aSs>e|`x(f2R1bM}*518~%x>1Yct=18b&Z>GiS*>VB$+i2876zL)1cT zN33g=g|>xWE2)dds5m2+8Vy)m-u@NHOlGYxxjam21r1;xWtT0TgqKZrl}*LSkqFt4 zNTI1=3o%C*!-i;iWnlca$stRdwITA1?#fD~5OIqIQAM18BwO_u>hqL&OAANiF|8rG z_IZ9mp?FA-{Gq9+Ky<#NgL1gWJixfO0ziP$4T4G>vsvqC-NQh+A64F4! z-(t<=AbPSG%`mTl6BJtH~3RmvPhQlE-EUkEoBIP(_WMN zK~Fe!siee{M*ns1hkp5(2}vX#%u+T!Abh=<_gEx_QW?h4V@B>uOCEetEe01tl)^`V z(=cOLmuOB;8&&m%_6pcyrt83UXkJ`f9I&0KxY09}RTTs!l^_7~8$tPA%Hm#&$k0;# zF;O0zCGo0IN)X~SyKDoY1DW{Ulce|V9w=ld;U`z$t$>8U!Gu8V?_LAJAudt3eI#*! z2i9~F=kP5m>!bmb%1e~b1!1gz01Py(Yw5gOsFN#o1a&d|=PpgN(#UVreY9^99I0iG zaYE@>(C^V7pnoB~#w$2C1_TIb1N5Je&iao?S2A*TF>@vpHg`31{uk<9{zf_}s&z%dL-Fo)C$yl$%pAdqU!HJgp zh_{m1imk{&{ScyeuziqZHu5cto0{S}^BlXu% z0~;>_yHGd#?Kt8ErxK)z6ojj5SacQobw)-8`c!$HOI*V6eyqou{1Upm%_p!BY^t(D zDtn(oQ!jff`ddGSD;P8Hes!v)OKW-*>mS&#i0ow87;h>(=Cu0>b4)|=EegbN5=Xkh z9Ge13=3z#sk+fT<)PuUUf_%Nx@l!P?t*mni^94p^Ax6b2SVL5U>9dHH!H4DL4}@?@ z?Gpq$C**OmWliYA{5s<|EZ@QI2{-K#brFxfA~AIqq&-WSALHWQ8}%mvaNFasrtnE{ zg=sB4-RF!?)nf{>Wo~kNFgYefoFHBcSr*;iF9B!R=5Np|jv>Uf+mcarG-XGy*kP{z zISVyoPcl_9cOg-@613Qx16OGF#sH&2NTHDa_}vyidmxS~pMfY#AeQvu?AXpWNzi7A z*6&7a7!C9HRU+N{>WYTh0GXoBnXw{lQby^XShgDOw@e8TP}9Y*oFV4MVF#@Ds2A+A zXBEt3a@-IIl)TOcXx;0P;|ihR%Tq@DXeG5p-O{!T7Sg$s1 z8OA4iOx-!>6eK^x{jU-0SvByimK|nZik5zKIvvWVGE)4=x^&5Nx%Qgje!k3VoizaB zip#?$u(R8u{wUFC>tVR8oA%7fs?xEu(gYn>y6BB%vwPR9&RoZE%%RK! zl#Qnkl^+Y*Y4L{Xk(YX&aGj|zSpqO_;C3CTepA!L#4EXO|(eA`Fi+2EQ3!C zo^SpVP?{chQ3uaxu7y>w213e22cdA#l-M2kStPE%sq6vE4M*?3At!S7tIp(tQg(Ml zECjeJw8)*#LYYk_+Txv3rxsH9jJZBRrHp29yJ(^;_PEdn%#U1q`r89}38;XeF{ee& zsZEsUbJ{LtwOjU{vjL(Wvs2!Bx;#^Mzld&TjS@oo3kk=0P36MC-Ie6eHNN&{8b^s z0@jcbdejrrj!>r#Wu=3H1dgjeOI}NkhmE}K+UK&M>%7b!n&{0Zixk%^)6#@=V~IZN zxG>9kl&STQth}qScidfg58d2dF|v_U<@+V^eE@$4x;7oS3)MvWusA?9+%rN>aY#eA_6 zic@S(@e9$9tQM-&-7>X8~#n{5G}nuOu=dSyN+b~jA;_SExZ1H9Q1A}}Rz;XtXUIOP0~ zZzS|~T+%de-nGI$s?wxaJoe+99vmo%xm8o8SNEsAqAE)4LNvHc-1AX24C4k4u3vZmov^_VcxgGxapV(8)_K(^8= z2d{xCrmk(x&514Ly?e{Mf6}h3=oeP7+ZE{%B^c-kK8g0W{tYw3q%zty_Rd@1nbnyHMwabNp-sSyzpV4v>QsnKcQjF67%g~n&3t^1MesVxCzfJ5b=SOI#YfPP^^JGQw=9L1RCMFbrU{8O0LWOUdBK#j&{`tzXX zpe2_{+-8$a+o#%8MUlL4$yK`*--z&3{@Y?jP!m{g5nM+Ht=bD3o}Ok~sBQ_!^!->! z?NDVtyLXzmGYCEmjSCDK*q?Aq1;8fz9l9|z@~l{)R6GfKELc^(nV+TjjI^n0M+S0i z@YOu*Tk>|M6a0_n$(E;#^1Zgif<-CpYiMvyT+Y*9Z?&~IKSwsLa5Q#p_?FqK3lKIw zlp6Hk%lio6)yq>m-`QT2Nj-q!aX7~Hlm^Xh6FNbw z$#ri(Kk*GUHXORu@`aYQU@ zB~S-oIO^~abRPocemkm!W73dbb!j^_xgo_@#W#6p12>w^{){VfeX?U71Xyn9&E zHa1#*!4c;?r}jv7dMN`g#&R_S215)dccDOJr=uz%LIz@zia+LIFjRakROr?P zQ|Xw0Pa8o7&W=fw17`+SqepsQ-Os5v3ncD5|N?N(AHH&`>hLY+CLOluJ z_ErpaT49zK(UcdNmQ%iA-`jS`A_1c|$W86{d_T_T2V-HH3xUqpX0QJSH%i>1i>#vK z&y{;5)^pMB=u;&_DEWakQU>j&+opIrBf~2GUh{`kG{|Z&2Z}5dwG}>Y{W_uQHaR$_ zYH%}$c`CGC-FGCetRdQ@RZ2-%ucC_|R?mHzYEnqC%u9zRBH8wx7po`=EVPMpq+hL2 zTdjVhQn$)++17^cn;<3=bxJy0Z$U;i3AqJMPJO&SuieU&0eVX?eLEEI7Av@#PV_ZQ zsa>I>B5HE996O$z6HyJfhEt^aC><@AnzeN`xs@lv>^pPFtcodrcGyqPSB?#C`Piu0 zh5=hAW|OtT9hs*G?7}@*mG_f7ae@-Nz4{qvne66kco^uD$(JbCo2ttqUm-SMy@kx% z!eDt?5>w5)M!E#C!b#Iu9GqyhUs|QoYWHtR{4espRS-LUt=viY2iygF=-j3kcU#uF z{ka2=zsOuLR}s;&PbbrB`zty&NfZpV*Y;~i*W$EH0JOGS&FMS%VK@)f*%OOrcU3P9 zq4zjhMpx}oc`PWtP!o5Bdlp=(A***TZwVwuZbuB1Pibv5uiHvW{PsE-k5IfCgUz~l z0nMeZU0R>(ajoQ0G%Il)z0BgRR*bsdz5NcqJ<)niF6|PUO0i}<4)q>6wx4K(5>Y_I z4$WMkbCOQFs(krBnl zx85i0*7%Zm(&nKNP?AQ}d~6@?D9dO%@}ouN2paSR;zyUqJuw)1SRy=g%o;g(BD|Bh ztnKV(4fcBgDJ~M@%}n-6ow3xOhnC>C^d?PbS(9=TnO)k5p+W;pu2F4eiG7ts zJVL4M(NiZPQDy*9`H>-P0GWY#=UTnh8feiNF}hCs`8^ZDKy;XIL^9K4Ps&y^#DQSE z-?J z@YOQ9NQi>ZP>^ix5K`R07kWj?`R(B?E*OyR1$Vd;8p%2Y2zEYt4CJM~gVX%MO(E1B zzXhsHn~R1ifq9~dtzuH!*3&W;r`D(Sjrc)m#EI%`Car;CMWcU0c+0r?O!)HpjEvyP zb^;pO-Bn6e-+>dS^o{q&8yEH9v}vuXX`W;NPRlwJdX|59`z?~z{pFE!^u{3k{KkJ55^ zD;F0ldy9W*`d5YP|0(E6|K%}9|D^SIq>wO)4^cJ+yCa&xl*3}hpvcQ1eP_k;@>tz= zOZnw)#fxHc81jPcTM#)jgy|0?n0(jd3IPu-lJ&Tm`#F1)o$GTwYp@dlqy-qiHFCHS zKgikMUx|%x=_%B)>n_y^+HvD2=nP`}-G_0A7)I$yc4`tXS-On8qOkNp>Q^$|Ew%Jm zYx34*(*Z3SF}xw$CA?nG9O3ZH7l)@Dp4EyH>8eXDb}AFz)k*T53iA~gRu&e15u@|% z9Rw?69nQOeJhv^^unjd-VGFwbDzf9K{i(U{xxHyM@-aI+0qP{TU0G~w+Fs>taL#Ik z4+92(Z7n%+okd478;__0GkE`&(C`k8h@?UNnM=F%A~2|TKo)q9F<5`s)KwxJRw~k; z4giS~|8AIVG;rde6I^W6m9fliR^7YT*>&x7wv^?xu(5p45n{|2F>x%?9Jq+~Tqo9# zChbeGm@9!(s;uIKae_4h@`~yIj`Tqct+-M>d>~2PCiQ?UmFUioyy&~h_DTBQ--W|q zqA^UaJMTz4tEggQ*_cQ_LA7j7bLyz8#cpGggy;YBVk!%oSdufoh5-FYAQ)v=d$Bi`G$^~ zm!O;En#M9uCykPzLZ5SHa%?hDHP5P;T4HN0L6J*r9DAvC1WWPOrd{*obfr3yJ?Kl3 z^_6dnXRoi4<$Tr!=4mhHg6ig~BatHR zv%ZMJr-`8w_JyFEzUSQdp0HT>|9QQG?IXj$7Rbx4E)%HauDyY!tedHP ztIbq;D)ckd-eirAHOG7icBH23*ApHA@nG*Jdh}~G?L5C^Xw^+nLWG+>hRi&(fnpY5 z?^hj4si6I{m1u^%i_yk$tco}28X8|}g5*tAEZYF37$f(+xT%XvO^`i^Ig}%cydrwF zlpL!xdO->&@q|8MiJrAxt;z2CP*a+EvV`_2& z<1=p{zjhmmYVkpx#RV=#zuy&7^2Trn=H$nT{OBVF*0z|QH!NxBF%gbqT!BEx zKB!SsSUwSo1Zr?kMM%N)@hG=&m`vRQ6QK6=oIvnUI+|C)dGKM@jNwqG2Xi8;YCUHYRh? zbl@DN-za)+0F9kw>Yv=ioL)01uFp7@AVEB0AH-nmB%j$RC_totFy4BKd;OPCMUMBb zu3oUUK`|{AvkM+@KPZD4Tn$(VlQi&aWV*Uf@DO|FQjLOoVw&C@z~Um*h%Ka-C=n4H z@(Lf&MDJXNS{3Hs@J)11(zo9tGp>wS^b9{Q1WN=Ktn>ZieRZS?k`gb7P4n?cl^7^* zG5-oARAG#i<*z`J0ski%;QCLD-T$AbOHq<{KxIb4=QJRn@MGj=ns0WhZX+uX z=oTjz`o-VviMt1mB0W1vA*7oq1ENz{<*-EU)U;r*ODfV!G-?hdnzhM@rRZ=|qaFTN zX*t~$gc-)M7GS{#34R-n`B)eAPfebN46~61R?j^(Pg3TXR1PyQrO7Mf@xf<3VL0`4 zh(i?-SktJu8Oj?KIy4p@%5ZH;P&p5LB8 z^}7P)9h}vUP+1Hd3nNzNcbR`%1>dSZbWhiXe-CcB+s9e)_w<{bypZ(@cQT`P@ch=d zSOPhExgI31MVFPsClEXe>$~qYQ+d}7(!BE*9y%AjQ47BMDt=#>`1ie)|ES{pFFdHa zI)CK`f3x>)DtZnm!f5=e@g;3iK^jf!RU6hpjYu^V#q0uWLuJ-6={Ua3gDi9#*P7;- z`rm*5)n{2QE{UZ01PVy@_9(amogzzOwYcVgp2>LsJ(}hKbX_!ayZ7=U{!p{BHussVj(W z2z3$zu7h$KK<%}P0YBJ+)0unV*xD&6GusXqs=M=Cl&fP@Ttzfq?>H9TW#qDId+C7? zhD;;HOxDJR4dc_xI7-b6N6nZ@bUWueDk<_9Rju2I*o(i)M0&~%C^ zc)a<25M<^NrsjAccydV2HJu_-1W>b;xrB~Mi@c7FrW-94$-GnKXvF7( zA68!d!gkIo8(URS{(u{zRtrF}B$9@*)KH9POqOW-B$za4Sg-A&PM*on$>$o#L7pH~ z&YW8oJX3T!!@2r4Rr6ac0ZDbtB1b5yc$5}7oZSDvGF0FWTpZ#r7@GfM^MmC-p{9Qj z_JmmlTxO(^(NHqBc$ECU$jQp^;)%xnyr$qvNTd`R@j$8JppDCGQAHQ7?fja9McCUZ^;``VW$1+G#=<;K{_OfH- z_$fp~S3K`;jPNNZnkB@=DFQy3{6+Bq9nOf3~dr4q8zD_t{P4-^%<4kj!U z0aj`=#@G*w?!4fpM? z8Pwb15(Ka*TtDN-2aWK>*hh{R_C}*e*vSTkHdM(ETM!JrJ=1h?(_WL}2p#QXjrKZ_ z0k_yu^;~)#*r>sQP7d_4VBRvWJCzw#TxA{*hktwQI3ST{8{>3$KHJIgMGK6I!d}Q zinmfq&RLRxX8P)_@@vVr0gPu7*)uU<%xS{|Eg;*w1}2=C&?7B zSX?OLt-gZO+<4@tLeF+K0~*|xwMD__KxWgGfsUpj)KyeCM3J-f*uxe|xk;Dlqq%1< zL(PaY@U(>Z#k!C!B45JlmE^~wHSH;r1c^kWTG9_VT~1LN6$a6Yg@kNF?&b0hs+5Dw=0j zR(wcEYmdfgojx+Hzu89*C}4$I7^?^vYKhF(`>=MC)VeeFR}}?j#XeLnp8OhW9%9ND zt6utD8DHnQj5@YJv+$USdN{8apQir2)Z{8_s!BABmG2O#pz5lSh|gf#CI8X4I|U4g zhQwk=VEV+j+-KNxuIk96Bi%^(Sf9}A7o$zHJ5mV~)qP))QQY&^>9}z9z9)PWpw>8T z7#NWNEtnUoUl{DP5(lmy<3;tpLJ3hG|;CGB`3**uH0tf9>;7w;Aq9SRVg1FDpI5y~rY#B|eCNpAXD z9692@_%$t2^nu&4lU~(~_iVf|Cs|mXs-xKlY$-~FZB$!oDK#)JgHZCG)ySDURM=@(i zCpd{Er89|l&)(&5>L6LuWY3yC6)`jPz(Po8pY=AYIBnx3y2Qx6*sT42mpR$zwx!!< zHHCc~tbF^-bje?bo#~Q59Dmw_-VcliCn^FfI*EV)U1NkNA`6Cm=^%j`%M?1Zxa=1U zn#DPNc32&XHHfUfmPx*J+3_GA&g-_pd#wO=Q^5bdhzmm)>s@yO0q|>ROV(hkhJWf@ zqWjI#+9Wx%C+!kp&kxX|XPS5m9CBC&3r>}SwdFd#YF_W78A*CN6mFC)qzOjM);Z&v z#MjdXXMw63v*tbvY+$tDmuHNFunOlRM#qe|eV&|$98!xy{n)-=N?lrkr0_}U^sz|x zs0y);(2Dooa;(9zHzRi=I{GSVcv!6jl%ck@)>JODfR? z%aI)0HvbhzY9K7eYsntq#JvWzj$WCuoyGoPY7;LSPfZlFiWU)X?(-p}s4FXQcpIp00;%Jv;k0t@2vBu4i;rh-?{z}cHTLL9Rz zT8r(1Ws*H~EyH+adP$cGv|7HkeS9p6eOEI*`idH3twkEJ*72|ey4JgISglGV0Vo@qe#)f-=|g%l$S&Onwl@mmdn|sjXXYaQ4MlfzjiK1* zY&hWQyc9?G2}2s1fYnQ}LXpq{!&Kr97d?=a?_xXAU0SXrZE?T+=9os2*v9%Csph*M zW{}m4+PIRmHEI;<=c5$PMrfg#MTs);4Tb_0**o}*cimSWRcxo(;G&&NV+-?W7v*%4ACG#t5J zQP=$g-(mN*;B6s)d9JNkF0#Zz_WA>J;{=2a!IJsiqCV!YLjJ(wUJ`3b$>qcZ!HjDT z2xm;fMSbtJ|3o~tc!jJ+U8a)vX@NcxU8y#u!Puq%R~{sps0msRFO2!GM4}786S7* zxgNmf{q@|Sdnf6_he>gEGX7Hn)uih5nL&&t4`O{?V;;bdl1U~9RAnjNmt~1UPC3mh zrR8ZtHzz1(yOYSK$OjKf;InJ+7mH$WfqI^OG3dhA+S!YmIgRv>2H78?<6A=~%E{ug^P+^b*+f=j32&Nv&Ypq?DcH&Busg^AUDE|p; z8(tQxZs1+0gUX<5~Ah zT0cGckI5%nM~d`uaMJ$o%2bt^##I0UdaQ2>-bpsP4P1Vk8r7EOSr+a!D*Z4shiKFL z35Lvs^i;#;G{%ksUUo8(Nj2DY?u5->J8kqS_#{B`HqS(UkzR|K5&6XI_#FH4?$ znMXeTb$nmr1`|{n*#5H1T%vtU4-H)vrtAchme!ZG#@c+Hrf4uxx$;VU(Dr~N-ich4 zMKpdwot^bPY#kBILFgi?i3W_kV%vn2J+%R5x}TL8I?B~o#VXlmr?i=y`yJi-><;X* zPCDrsU51x;mkr+t18lPs=6)r^gEh2$saaA!qv_< zKQP13J}ptHaUjT_(*x+P}wfV-}57aU3rp#3AB&~e3%y}0ju#22u5@mUIT!GA{* zd%-e2DTmr#$(P6^$&N0oCgR)F9IPR~!Q!x6YI*7dx6LR6n8tj(#1~!0rofeMtT#g* zW%-p@V09>&o>iz0j66K^soJWg(o9#T(8Xx-P3?;J|t~nIDSGPq(?-B zOoNnc5HZhsW(m6!J+yj~kjmjV6GKvhO>%^v5`O2I@4B$Z!~DgelYWdC4P>YfmI$TR zq`atDEhIt5ua)PS;Yz1`FX@3Na6j^uBx_rNKTmgboWGwE6O5;iQiN6Q8>ZX%ApVJS zTEf6oj=@?7klS(JaijG|(gO@dTgxB3#H)4&?+@VWkTc)dl;qK|uv;WRI*cG2`6PiF z4+svy+Bfn&Fs57Jz6i!C(w$w@VWPAbRGak~oN>3vUg|Mmk0NpfURt0*DSJ_e*Gi8I zqshW4F}L&aS8x~4*#{4vOc`gKW99cx*L^69fgPj#?++q9LidItd}<@&#E{ZGz7g|c zFX$uKJ;Qv^NpN*e&EL;l@1br8j8oxO3e`g<911L_jr~Xb0)t$x$A~dFay9(}gt4&L zyb=1<`|)_7(!^xJ14xLBGKXO3`R^_;F01 zG70TiF<5(=pRsJYj!^XjLl_vFJOQPhN#Pkr#G0-m#xG>q)GAHjE4WFhe7Zi83;gte zdDv6+)qrgh3F0}$gPmtb9-Ff1m|xDD$6jX)Dcd5Ms-(@nKM_3)2+hfh6@Cs@-=%Z_ zIinf|ck6rN{EOadGmJ-rzvxZnAL)(mf108HL2v&m)%=a*?3CnX2ZfOQY?ha_11m@UzRqlkhrVbQ@0M(tSSTerx}IH@Dn2={w$iGqU#`v}PuV7I&A9JYNP%sqMn z1bTq*Ok{V>SlVH8H*4X-lO?VzaDQzAaLvc1tTL+To)YOuj^V8mQ?)K-FT(s_!ds-O zeb$rKRR-~g^+_aiGtH6kbJ)!K^ie;ipJ8e;>iy2}73i(1RY-~!(tk2zPj;pwB4k1a zVa~7lF^EE`UH=#eb**88zBH%!WkO0S?_Zu0KpRtXN+XMsAwfT56IZI}&cs+R5N~p3 zlQH7o$(zsQQBPIRmD)i>TfdcgCSKbVVD;VCmO3l1VNbV&rWc9o>Pk>ex!)Nap%NtP z&kKIFMm@k9-HeXj2$((SmG+a-dXvl7q(7n=8)cELHf!@Le+X)=++(}pKC*dcns?>G zVa*fV{2FDIJNaK_jq)WE9MvxiTm6sI%YUn|S=oP0Z`vE#GMZa`4V5byxmv0@8@Zb~ zyBOJuTAG>Im^uIL@!ZrWJy6xL{%n;pEwY87Y^xYSfmmgRcgcEDfz4TJ#{;n|g>8(> zv$(RLnp4oD1Mj>H@ar|0RCy}E{GwvuKOf1FS}O&z-Q)MmCVEK{p~b2xFj@lTn}#s4xg7h+r;n$TZDlT2AXAv z7R^$J?R|*xL^>7HI}e>7{HszA#Y_e8=~8*3zy_J$ejuhByeI0I!w-&%MW7Q-FGMKU z8qPm&IdU3w#^#`d%Vcn&q^w;EEr|w2F@ax^`R;a@p>l`U-T%~f&^`#zG}qdSV)A<0 z^*U=#=#o&gd{o+*s#j$xf+2y^t1Wj9_h}(DNi^aK#jI}z)v1rk-H)gocbgc`wB*?$ zfg~22r!^VEN+n>U8|3{Ebe#!9k|dF8lV*9c&9H~&g|$Ymc-2O^j9w$Q^I)ldd}5zv zQkBFDS2TxDn`p}-{-`br?tUCgyfr0Wbf3QeATbp=9sN|e90U^eVOu0~VT$1A5))@C zPcwzUn7bP^Gd~hLA@8EwiklMmlc^(;uPE%tLecC-iZ$_~jNJnZYn1A%r}=VE(-LG; znh6Q+b;zKz_N7)0SH7t~u#)e>Pr194w7xp;V&CpmJw5j6zBO%yB zjVf*iveYaWlrE~+p8YYym=-QmTd_F!`)ATishn6(oD}hTE2AqnVPF_os`ca^ET@@Z zoo~4YJASOBn<;8#(#3G>n1E)&@JA^3LV7mK^kaJ$((~ASWup3G(%#8O%xFX8XSiN~ zUF0&gDyT`FzIjtA`<-+9RXEKbwu%RtcrG!#-aoN0aj)i z(G|=#b_!z{o1}cIyw#n=j~Ac|NnR@<-CW$c%JFBFTi5JW0BX#4k2o2w{L0EglSN7E zFUcmFVF&U6NBA7!t`Lut>faDk>pW>Lz9BSzsqWvnI<+L#wg=zw+aeL6=70S773#Rq zG@fVM9=1ZibB`>L>hKz>rHG}`pX;dZD>I!_x~u>jsx3;0d$`Q%t7d<8^lkl8w0WZ3 z(HGiok6h^#G2EzIH}G*;!U8FW>@|C+wE+z{@e{wwWEkzUEiT0aDJo2JwZR{zcX$Bz ze2pzE&vKCc6@vE*GIv1LZ=qSg~HR)Jf|ljt#^m2hZF4z|32*7{hd|u`C7{C zjG>}`{SC3Dnc~5%D4yBa!V@}xSBtQ$ZWY^qs3)9jTuIXYMgPF5E0*&A0B(=JEntcVgC%ZO4UKHyuzuSblKNHWJ}OzVpeS z?8|{P8FtkJ=~%YMf1h*@o-YsZkLVQU!43cY~nWEmBt#&Ar%7WClZK8 zSe-!M)B8((tj^wSIm3?e5oe&mQs6BAE#Y7K*^boU^Z#aITL%-H zul5Gx*FKM}n~RnE*Ko3}nXrk8nTw0Ok-d?{|KMda<$n9cFHzkfb4wa&Dp0x>XjayP zg-KZ^Ayey*gb`NecHls@$a-2|Z!Xe^@P`uYYo`Q*jKzDQGPFf^GDQ5rd(-X3n)&f|bD>?`-DktKL<0hWK!cPS>L^@|VH6## zG*0#NtGfzpZpt+e{yL@K$|Lg*JfO%I+hp&kR;NxOJ+y2H49xZA7=^RKObPZi6 zL&R70!l_{PTFcxI#h+WsO^Y<`hE*z1vg9n7nG-6n0xBU8F8yDd}=?${Kl$qim3(S98@^W*vvSs{l zU}!oUIXap-i#nT`er(?avm4Q4-snuM&-cwu#-M{K8n;l1gP$ z3sw?`ls1z%eb%&mNBvLuEci8}-Q`|kUw6;F0-pHb?+A)+BLSn7_@my}6u%J=Ub~(* zU1n~wcfO|73IBZF;|Bhy$0FeO^>lmmZz?ZuZC8$p6<>B{Lsp-*mS05IVU00ergKWv z(LIsLS=?(>QLLQQ?bdTpyO?iiEL`;>(XJw^lA*7FCd|$g@c3VRy#tUf-Lfs*_HNs@ zZQC|>+qT`k+qP}nwz1o`ZNC1_y*J{2=fCentcZ%LwW?M`<;L&dcdwa@4GT@LCkltq=Xfy+OasOLT!lXrqy` zEW9YuDcfQtJ$oJ|Ln|b|q*_a|YPgCbBBfQ|5;-1(P3R`sK~3T`TtVV6yrtDbioJKI zPDV1BAaj#O~V^ll>$# zNC?nv_r5RiH^A2t<)qzcvns9Qd$_UU$`jN;KUSNqMCQiCFCi3A$*D#(v=FXCqz$SB zyC8vjHyJhMy$5kCi}FBy0NdSCJa6{q(|*9I^zwX1NHX*dHOIDB8bsI3_{(*-kkQV@ng|lWd*nWx!(xQ1stGMcRDjH=YUQvY2^uCZuO%-0Jw5az*F1nW_|h zR~z5DT4j&Z7527|#z9b}pmRW}p^|OrU(TWox^&Kn>YUn%%JlZJ^16vzy|O|GnZsf3 zSXEMjOhuYZlh*ikE0&zHt5va@6&GI{1&D+NPop@Tss&f!V4;}nqX@iOvdonoDa}J_ zE-u%qrrUpYVYSGU5NeXJr?#B#3dkObD8uk*U|u*zS;T2YgAk;_kdF0s4A6A*YGO4)#dKwYLQi+*i=C3N85d93 zAe#Lng7EX?@}-FPvIdp0y!`J@^1tg|IHwZ=C-i6LW7u!d>#==7<(?=6?caFCo;)AM zwwV6XHIU7}%D3 z75#&7SiVq=f6k4N*gy{?o~K9`+fsId8Co*62ksPHLm=SB>G)@44I(Fbs1stfE==|e z5WM)k7Hs~OwT#*$%<~0|BEb_6HV0F0=kYy;P zdAZbN(@{*9FL}4bSi-&#J^2;N`G{J?KFD@i^8BEXQq3$Q#~shvw_cx5r%ZlgHz2&Y z*cU<9UD1(G6qg=Yx{LRix``xh^Yi7@j|r7hm00t{(0ei78ZQbt`JV={$XlXvX91YH zxbI<;-YQG@9xrY>Ar~yWklR>hQ-X6TUxD-S!;~b9lu;Tu@f59S=euifnkTO2C*G;S z@TJZ5{$VG<^ThBbq_74=9q9r7DxC6VBngr@olJ}~W87-NEagn(;M*)7Oj2!(TG+}U zsLu!TV4B7DH{}gtanAHawLkpH5_$jk$0~;0`rM1Hjkl;4D-KsjXTl<*z|E`_8Nlb6 zroi&vNu(socja8wZ}9J>;D}esqgs4BR?_u7ZyELz2k%GQjtG%Vx+yeS&QI*AK1Q~e z;1-8)WjT?WqB>et(n%42u5UPI+!F^B7Hx#oW{i;??}{9#vpvk}lwvHPB$=-+pnIAL zGBd3sTO%TRGFw?`Nh>DzU#VeO7C?`w!-QT4ZgBE!WsS1clJ&i=m$ zHn^;?BNx^_wESMCsSKfxi542WFvUJUh%GpT-JP-b+D|wh`H$h4?*AT6uKyK)=>%&^oOXr5Al10+ld z9x<66pEk?hlV|$s!otJ~_Kz3DcB~XFzWq<@HMwvNFc2}VQuS$6g{U$+nN4G0`E zua0)-H1D8k;mm6E{(!pNomCz*qxv$pI3NvG>(+Q4AcJvK#K8 zb9SOKS@GC!pN|JW#<}*37GFj>D1wi~_)k#-N5izNy0%(q7hMm?oL_Ju8jMFGA9bKb zv$!gbC9lC0>Unx?+*3GF(6ZZH<(4j|5-Om02Y2z2IG_&xn+2Z`6;N1An(~^lQwwUQ zOiKj)?fuj7EGlb8nv@wDs4us&o=Bt%l*TAhB{h=R+Pddpm83-ms{V0T&ofYt=D7dS=Kr=V{~wzR|1=j_+3Fh+3mcp0J6k#Z&$+yVt*OJ$s$BYK zRx!5u|IH#%N;9@dV#r@$o(;Dy3GBon{2-)SK+R!>`0yL(nq~lFeelQy_)_BZt2i}m z8rSXb0|MpaMQpG<_IaUCD@=+=`KtLmC}H1)-vV;8Y!fw&`K2B6oou$QOj%XL`Ye$dX*5~GV? zjoCc8{4m*B_lFn=K@#mp@(*Vga>;sjA3Ds|(a_aGGbuFi)9-z>)&hY^h=PM>jvvAt z$Q7Zfbr%lPeu2OFHW3uNyavs`ezAXnB`OuCGx+U1e%!gwF?S3T3XLaG+BzOfiLB-f zLsTI!R2nT{#3)Z+EHpqiKXE$CK-~2S!*Tvgi)l{*o7SZiuHQf&N=jK$gt6|+nF)`Gm z!Txq?dNfctW^}=z-436nDud8w974=Iuf~cqED93ykXqf1w8FZK9fiO>iyHhGH6`Xa zy99CYP)x3@)FSqPdVt-Br1$H%x6;EwpuBzZ?#_D^RUI0KPMzf^_Q2rPhK)0jFB8Xm zlV*;2seylEHqM|s4!E5>k-zx$17R0R2*LcwM(ea^%K>Rf92id$mc6SChy+Lhh?+zh zvO6({dx7GOFjsuW1#TIks9C3Y1NS^K;IL#Bmt5WRAnNcc>QhlO{Vj2vmon)s*asQd z33&IEDekAAXHibwHHW4Kjin6FB;UgbL))#+*%fRgjq!Uy)J$xt^A4P* z=wpGU$DPMXW)DL%DW!nu39E+G5tKB@YM$r#?rOf~PwEaIWOZ?-rZteokPGZsqWYS4;B z|0LjjIbp)2Q9#;HApIi0rAAv&MKYgXU3KhsoOYe|YT)zr{({<}EXL67@nFgE$g8n) zlwsHK7H3m?1l)9j7MVEeKIFU&$Urel=||l_I+%2%vpEWGJ4%Ae=4~9emV-GN((dey zu%{X&7)-JZ@$2L0Yqtni7;-H%fWs%8= z=kT2S6oOA<-_q!hTShh=6tYB`my{cf^+Lx>yzS~3hAy^=8Fn4^M9*a;F$7-pPb`5WTTi>BH<(hQt<2d>L}bEO@qeR~R5CV6M#}U~hOs$t?sI z7o&N-naKA!$TJ z>&^XTo(>zGjv|b*XTI$ut5?7&&KtRH*Xif1`>gBEp7*Joo(B{{&6%EYr?;2euFLC6 zyxINGDCvA&Z9Ke6+p?I9Q!BMcUI`b0h}(?yqWH@VsM zQOR!?^5j*fLK3_B=$34i3+r{u7IgD)M~W2q7y3L-307k;BupXtBuqlRxD3=-rhwa9 z?bS^@iS*Hnd^;p2cOp}nC~VDSN?;3$3z!yI^$)`1W?UAhtCjjqn>M&ph0;8EaiL{z zu|C4KQm1Ko&6~iXk*x&^ph_a+*qDsevtmcT;T0k>1Tvc@2_|YU#phijBjGm~(FAS> zlUlF>J!lV+cX^mbgNt|q+%c)}o#I2L8tL)BII4PpHABevx1oqq4Fk=enLf)lPJppehzt;iO9UQ2qK{ycJZ}25$Em8#QCj@IGeY)Ih;t1C_j5#Indn9> z?q%Mr*&t<`FGYDnXUw!Q9F(&(vc=j2NyA|}`{O%(aBk4&ic|F*CyG^zcJTh7Jbkku znj-MdZ0aPz3?=kXncCW=-<;dP;J9T1y-C;{aJj^)J(P2N6H-0wO?ZvS=U!GHKVCK< z=aWv?u%5>H&8MwXa49`eLmGW<%;nt}*#2=)K*`axE(dLvH|fGa6F34#8tRY?cr_y0 ze3Ys0rp;JgADiP65s|!r+v;Bhhv}`Vm{n>M24Hc%zOJ&UhG2A;(vSJbsM4>fU{u2_ z-6VIhEcV`qxROML_k8tmxBr)-{ z0Nki4Ka!>@`U^UZ)eJ*+dVEKh%hU52puWKbEG44AD>zWsBPQobQCa)OTlz41wS`U5 zA(_e!#MIkQ_D?<^L@2G~TpSiQGc{2i*D?M}9=ed6<%52)rPN_&_Zz}kJyQ*xrss+n z+*}R)Uzw_8MN}8>Nin$jkrHrz;R3n*HT*JD&M9fIRS?wRHq#A#i(f4q5+z;_5Ij)k z55fi>(u^$A=GCiS!o_k6hWVWf;@9>(C^LB-^lw%JYn+7v`}UC04jw=#dbI?>PxGb< z^hYM;a|^$Xv8HwRyEFBlC0EGDeVFD zsI=F15ChE=aHP6tL~Ao9#WHh`H@ZcicgWiJi5Wg12JkaFg6%fLuw^#2^+FGSBYJC) zcLQaBfXhJJeIf<*h>U>kVP9*cRCfKc<$@qO~wd*)<>-)SK6P zJ@I^4#us1Hf$yt#&=?VaIkhDY^^W;!&OFd#L5S3wEK(42b#OVRSI3Yn=DLC>djb3m zOx*FMX7ymI4;B56>=L7Cv?Opmx_j#kUAIX{b-S2c8Z$v=gOMvo?-ij^Qg7+-IsiMdRFM)v7G{O9O zb{zD!lmDA*H)}70ZFQ4xTkLM$F*jknM@CK!9fA;1rEyA1T;kT|rRhl7MQ@3Z8K3<$ zthbXo^c6w1sy3usEhrD|+wtJ{DqW>!SzzMAYG&n5P_48!FI7^!mt^UsJ=Ii%VFz|f zC`{_0n8zVxPB%8P&U9wpG3=awF3lq(pY)ZY+X0iPX>u?nXvOVKqHlZ!kPr!p?==9sB_~DS`Wz) z-C{l?ZU7>v`xhem*b=STWhZXwe7a@WUN>CeYu(sj2^yMe+X__p(O0XKfx z%AXEQxVFsfTzy)ozm#eCQhr*;4iF$jVCn@40VgXeH%1E z29UQ3y$aVZ3TOp-E~*g`Gz^slv`Lf|RO$MFBa@P)tKRuI=cc?XxIqzmXgmw~OWv_3 z79M~sk*g{jtNxD4ShkFGO@d3`N{)-(L`+B$P3o{T)|L%BE`c71nj=koezdtBY4~a%t^5r3-m!3Kj%V`9dB?v%w?BxOI$&~!jUNWa z@o8Q~I6n%f3*aDLLYK<|4FU2X@*``7jnlDRq5+VebLwb4vJVL_1XDYFTUc;$dW3relP0}p?81NZ&{!uRJU{&9)O%uEL4Mkts~ z&T=;)Kjl_c^Tc3YX*8y9Lb`*cpyU^wFHkn{Z--k1SA~|n0bO2_YwyEVv91paW(>>D z5A?fn$`0!!94mEWTUFmE5+yocu&wZDj;aE3+jOFJ95*T%`pKWaqKNiaixt!T^#`@p zHlA$6Fj^5&7!Hb19 zHyE9zQWe<12XmH)8IDIOtwPeM zHRd&LKn-qMRQRtyy5LYzR9#*8JDBD2K-E^^INa=#S{XA+rW5XKtg>7Nn^Of&Vhir! z+P>KycTUF|e~Hw_vAX%ap<+u9o9)jcAVaw~|4zkmS zZa8>nl~i|D8zjQ^%<{;ZR6cbVD>%?nlBzUD&(9h}VOpBkVW!AuVW!MGuz;OfTWE_| z{yi!0mE#74$DH%4$iv357s-5PS(g3aXJUS?=I-+Jz4Y{Czu2{VMepL1!wV0l8b0k) zSH~&|HJ~YYm{WKY&gKO*WNzB=l|JE3C?T`VIh$Fi$wHFx68QWYRy%ziF%z4Zc<{>B zjkGSyv*i{+F*O@tKQ!EDM%7xw!z{Yx)~Woo$kr{Z7+t7ve;X$MoE{R-LVe22TZY;% zOIFYRqSw}4;Mcno^z?O*G8Q`&wbgNV%>E*DX{fnqK*lP#K0dvcU3endLW%GugLOH< z>Y{oG#ECe$UPvO#$t@?@GA5JFE*6oY@?+$jRxnx(BiZ8q{AuRkwymR+;{*D6-bh*) z-5@PC8lo`?K**Ec9*n$U>OJRjK0H$J@vnMoQZa4ti zMegzJ2oft=1Y+aEG$4JE9{t_I{tH*SwKVixk$IyL|hvQq*qu&_4C6X zp>36)v+qAXl|OfXL8koN-RrhNjjA36)N;pjmTkOO>jg}c>35j<2gH)fb7QYv#8VV2-AXJ1-O{Vpi$uIz3lMp3dl`?Wwpp>|6_$}|ROmbQ- z+O3VID2pdMNR%dc(_#%+-P-%bNIb5Irk&d>rOY(_mq8%P;dkWuH0mR4vhl=r?rV5g z%=n2Yz2%@f5#I6!(KxF>D%1-3IyJU|VW-!(l$}cWBQtobb>#9D+>HlD>@kp+qgiCj zU_Y+2nP+9m^gw~vIRygs?R~aXBZ*Vk8cFZj_&b8(pTaY{Y}cTT z*fRuKeL3=89rk16#2TNQ%KL}Ryx)%5M0MHy=A(uL9M*f_;^wBL-FO~J+@|(7I)GQF zGxu8y$fzRDE)xoI0MCR3S^FKd3Mzir$&35HZu)9V$~5*Kk^r{%vt!7ISD#%fswRS1 z7x8ugQ&u(usOPXbN5Z5URhEFc|NLc;g}f4JzVjlUxu&$T#yH-Omy4s=$~b=B<)v}= z;R7RHY}oe#TExRVjM2_)jF*Q3%G{)3ZZqgSTa^}wnjk_InITrx)tW> zN_A5pLZ9CogVv`5^1_9Jm_n4I&Od-1kC6YSPp-Oxyt0!D zIplg&zC_?4NKvoQui_?BUY3EYOP5n0W0#hYf21a%4Fg1xeEs;w-CE2d_X6pd9A`2e zuiIRY)}Lqe0J(eXdpq{`UG}5w@h=I2qwDlnybY&n3-F)3(mWK*z~Y1=sqQ352UCF4 zQlI=T^y5Lp>gG~>1T94`()}Z4=w<|*zIWTL=+#(!PT$k6nPOoI-RVk#s?iWB=$tTc z;v`#9_oLoCy7W1j8Mn^hfr?}kDKcERb3jxH4>hafqve(?N%m6{o48;*Aj`VQb5)Ul zHK-31_Fm*+OH8EXSzh8{$7fljqN=ahTv<75(Rp-SR$Zz#EMGFOcXfT5%J^HHx8x@r zP2)nIWHes~>%OVy%4>O3(0{X?N*ukyQv5>kKb>M|32-D&p%1(V8j7s?3w|Lp63nOV z937ts^a~AioVI92W$?353}~XMK~{A}5JkKH5b=n9Ciq@IDBAB;Z!IUAV+ciiDvH*j zMD^3Dk+a${QM5$azio{#f^OHOx>LnJ+5kbRm4^N`5ii4(4>XD|b?3s1jrWv1Z}MFy zT9v+!?Ds9SiLUpcRnr?JG+C=^SKkC=BwXt~F8Tyir)=)czcAl$Z)2R5pR!H;e=OVl z8*}D=$~ONscK(|=^G~^sSitaqkw<2U?vov$hY7)fa=I8~62|7IuK10w(qZq9BnSjK zt$S9yI^QU{77(-&cteiu27n8-8*tNC&-dMPS#upD2hi$Q=J$O0#Os?xwTN{WtSzZC zp0+5nsTrDO-C3RykP7Y)6z8U{uiQ@973Pg|STBrbPO4R4VU>jA3ZJD%OK)mD`u%Bq zjUA|-$B9L(11X}nY*naJ%@8ESe`WsFWU8vR= z2;2}9@)$?_zbc_riw26%Kg!e8Kd<=z-OEDxpIr0*^LqcyFQ+uzy_6rD_)MF*+Au)L zK+sV!gc8RX!}1A93BeHY86igj>{s@tCS@2Inb@Wg|3Ir$G(TxPHZ`*>y-_zsskEEv zlcqu`YL%;Yn6XuOyEIg6vQ;HLymz>grb&Gw(*q#A5?6USh=@|D2=%(`I*cmsk7f^9^}}P? z?OW5EW$5ivagZURMyiQ!)dSTd0?Cq6Pu{r&OKRfiuu+&nj(M|bhppFk4ze_}sSz1;);PvKNiaE=q^G|5w^Vy2SN zBs0Xts91C^d0dq<=JmXesd8D;1K5UvF9?WTYl6d%lJqXxN`Pj}5LxPgSRE$%)Se9Nn;^;MLmXCiH$)23AiNRlj3 zB5S`@U11=y{xj(rqgS3zSUD^dhUILAwb|IZt>UN#gv=Rm63ig{MK*6HQPQQC{?1ODO*flB7}Q(AO3hFI}(g&O+0tS_v* zssss=fjAF6c7M%h{bJFcbm>-<=R>Xa4X{qGb3|a97zk+R8pO+p(k2^QM<;%(sz0y~ zRB?%#!Lct8vXEtAzqvF2#xo$NsieLB9TCSs^E_?X{@2BD7<@uv#vvJzQhJD^v3!dT zl|$vIA|g+p5nMz|Au5{UAyp|$2kfI)S~hhN0%yOnr(#(o-&bKg$Y+VeF{*sx3Du~N znZWwrE{QHx{GA?2J*uLTQ+AKA)Nbt+N2AXvftlF`pev3SOJ$4`MSDf=HiGkA5i0UO zd~$T7PLbVXMt2^U57wmD5}@X1U>&QO#B&jZ0J18_+exP+Z@5Me9xd0Jbq&L^e7(>X zNNZ(5fx4(0i?cEE=!j+2!b@EfJXIo&j};GwfS*019h#N=Yt|*|0J4`!D5 zN_q7;3^d-)FNmK&7&H^rwGK+yh}q{Hpt?|PFC?Fm#mlG5xknmlrQ>IgB05c3KF~=a zh6K*nAvP~CiOXlXY$wlxYQ8_)WN;>NeiQS5Mb-&Nuox?GER-8$-`li(QhmzUy}Keq zW@+_RPM`C|bx|r{2{VLpv4kQKehI>QOprT%3zknCxVb_F`5u!3W#trOn>06Z6D*XH z=M)M2!jWK4RGLfuttE%E2P@F6hVZljI&jmjn43^ zPJ~{D)br75_H1XB8(ej-Emk3-$#Qk8x9>hEB<9vjxJQ=EG&)&*v=3TD&pvVnxeR-) z?Lb+YlOky39f%jYERz8;%h7@zQH?O%8>!r^nUZ(>IPqq+lbCHA8Ax24#IZ@dwzGe_ zNr{+ocSoD-L2*Xdg%@t^OiJbgq#@1W&4(>T_SLJKpM5HrJSQaRRfbG&uyI9+T~>My zyWR{C12~~%bhg$$vJk%xRx<*^v~v)B^3%hV33i~-tUvA5Sfb|5i=rmc9n>)2!GqKa z^P&<_F>DtK$|77CJ5xuKX-Q%!OtxP3n%EsDQrn82M%6F*?l55XtzSVcMPQG0ZuQjl zmq*Ic&aackwk$S6PqbQ!TT;VJDSX~x&h0RoXfrD8&a{@qUZfVn6$ilU9V(GVzCpk^ zP$Zf;Ui%dnVGK2;ueF6kZ zFhW{mY7j^Tftei%owFtP`AO&4M?tOT( z;Htw$hS6rDA9#f<0l{2DA~U)NOfScqg!^m^q#5Caibizsnh)JfGIIAiSiC=S%J|_X-AWeS|ich7A5v3!>zaS0qG@+}6 zF+61ADkXR}zFbZ1mX?PdOp=@C9DI^|;2Tz^0qedK3>_4z?WYMY85qL(rt=Zq14q`G zmX)L~hGa0K_F1zeK5O`YjYkt&x-#C=rX%}-v%xC}Z95zssU#Mk{YR8Je z@U4Wha=tl!xo6aPg=VsfWT-Uw*s!bATd!Jrcam6JES#?b>09?3j3HtW9zjdZo{@vm z;Qsw!K~TU*LK!uvRJbS;OkNH2Wt%Y^x3I4&v!zodO!!r6#`%hm7yl~tBXG|sE%(t= zztYj^vC$ivB^+7S$l7s@do8-L_omu&g;hi4Q7^#p%DB);DAqKLC_yf{M--fbVCW4Q zpLSAJpyR=Jw|FpZ7!OY9&`o&H;FE5C-006%H7z?V^+c?EUl19l4m+%pxM%W-d$e~- zt(|&Ex@CFK^ihfbnmM|@OUuO+x=YOaa6Up`MZSv=z+ zj&v;Xfs>|(JoZyyf*n#2H&qEvkEBqz1th01TIY?cy1siJEZd%upf04|88q_e^UcqIJI$qO^tX{0Q=;ytn*d0;d>W zpbMg2hvsXQ_P18QOkwPq?4dM+V|(uRBPZ<<$bpw08v0vS$9$VUpbm=Fv(IMqMe~ij zM>0rOq>iZMoC}d%y?jB;97(AMLyv&6Zzi(5LIvB?<#Ywf0)mZ_~Rdangdl z&@8jcCHuwoEo63_;{rqY2HFx=n@YZylX9a} zl&P9Yv{)Lgc|b3Q1o2l|SANshLidoYfmF5?I`bsF`E$9kGP};}K?$qva#L^~CH` z!TFGfb4WF(Bq_ENC#V_OREgx>tR!Qa(Jg2?b%7g;M5AE-&>&(JHfZkcmN2s4eJeN!nCrcl9Way`gTk=o|nGo|BD1pGHLvB0ih$H-WM^@K##RBrgEQ`4$CSNzg z8QjInTy|bpvXE2PqeM9*$mGvZ!Ps7Fn?$@*V_0OIlsGq$7xq#m0A&oC)8WX5OB{I{& z&m4D92ULj=J&5P>4A>lRn(KPS@|aiq-&TfHnOC`uYpkgbZ!za!sgrKX&HmC&DR$Qw znLUwmqe#(ab!;OBsne)NG--Cm>qV#<+25uf(vCyt?AGIMoJse#4t}n3bFn42(girok)X zsLlF0m3f3uPV@^VjN3J zs7vW$dREOUH=t;vnxK-_6qp*ejG&zM*m*>v9wu&xniWe@+eJ-67VZtoVET-b0X5{6 zr(c*Y=7z@KB`=B#zMR8)M_(&sn@t?LtNkyD`lrk0nJapT+`Ued`PVEyOY{v7f2Alh zxP{mY>C3kmqt~@Sx9=weAH3PUD&9e;-4Z?DM%u2JrA~7?nOo3Fg!@?ilHRb~Q9Vh0 zS~k)vttP$Xy9A>{?$-j{oKIM^!~^qOk9nFfO9U;uX<{Z}MGPU&T0}pPw4d7EHF*^c z(1Qo888T#p5hW(|Q-(yg#r6vVzhg0gpd>56bb9oH0wu}%3M)p2fxFLEy>QG4R_-h8 zU+Al?!eBv?3%sHzLA?4>j0E@%7$S|RYf_S$ylY+ z4n%*ot_mG#p83HvVERPUjJRH!Ay-9T%yQe2biJr+b%|?XeE(`??bZyWEqp{h5`F<$ z|26&q>X&o$0crC>TI-zNN~}*w7-kFnefLs z2fQs{{%-wM-9ryBgJ*Iuv&{5yuKy+Eoc^si>??Jju|gyAn_Uf`ajXB1%g`EBtwiQ1 zx^awk%lc*V?-yf2mx&<2oHk?3d{TaxpMu&Sc>d+t2h>+*DNg;iw%P+Pbq56MHt1{8 zuC!j;1YlpBL2hXi-rks7|L=db0Mz7?nWiEF08stMZRP$Sn6!kAqm#as74d%`|J5u1 zZ`hY{-1iNNl z1=2bj@r1^~3~TeQTAAId%fY2ha|!FRU6VMpiAkkk@VViqVwhBxz8SBI0v70InyyD6 z3Bn|Jj3nVomoatTh{xa7jx;yvi_UnW_#l*M<|9E)rOc4j#iVycL>cKHTtp3#k-nKL z+7?|mS#aSINetxl?nE8)%Zyk>!C1k`<{`huyPwZD2`YbK4!99|Okznl56^r1}88nU&cpyn*~f zRP2FGaX0@#FpvKuii!WfqnQ6~#DBA2l_uoxjK6W&?wmdns)%IKg2?m;9KE4d3H+J4 z{P-@21_oU4WQ76zv4`7rf2c8VBqkLlTWX8sn;VP7*r9$|Zvr<123Vyh&st-dNnOt) zxtL4AjW-w3bde9fPrdt&)f0toUJ2&UdD?Duy5Ap7dEF=0V82i93p+Kxkri{*^!QAa z`)V#?MO?Egc}EaN?0rV`N9>*U}noU~6E-WouZiR;Mgh z;i}OVBurvrDpRj7!i%ICbMj)VT&(w5JB7dEWs8$MSfbZaa1D^jw$rlh41JSI!*+g5 zc`HjldKt~dEdKiq-t`OW#SHiFi#h4kU3|pR`S;CF5SvpIp|Cl8#>|qEO zL6o_yj`uN0$wSqXQfj)_qWIKrnS3$j-u8y`GrF8k5xy*m3E_xC>4xG+3@28lsi2dl zG->G?bNPxG)$u+RlKOK*4722EnDvKFTfCP}MVn#i1AP7T_HVVXeMTs4JO zpT_!OPG@)cEQ+es9a7Q~8ZJxuwg`RN6PqI_ZGrR{=g#vc28nWQy+I8dcb5dFR^-u; z&&P%sTVJJ;F`R;9s*$hDbF31St>mkHWdp=P*}5fF!x?lQhPw$TMi}e=#xDm^PWJok zBklIX+F!cN8)z!@No~Er@9ywmEwj?-&7I}xh?Aw0SPtK(3EQ+5LHqwwu+}k1p;#vH zrvh`dw3QgL-4@kIQ!Av--?{@#~s8|+dQ;(;Mo#ndpY6spn{3TJBv8{Ee0%vgX2)N zCCV1=Y(p9TH+hpYR^mG9QF6nF>tHb9wDPpXRlL7F+QvVV*IK(W=+D|wiR-*I;elS7 zY`O=x^{a5b-2CDtug6c%+y!Jb>;Y$1|5k+KbP-$ndnLz+PK~0IJ6_kenCmP!NG!nT z0oX@l4sD#DBU$@kjnc{sh4baeOf!mqY{x0?+@X-P%tFTkGt+fK8Xnl}SW!g#bX7&^ z+2;eo?q}&im*rirs}E*eubvzp8ZZ##(eDL0O^$sfaX!0;rmj^d#vG<0v5$vbadqkM z;c@S>jXq)Rz%lvuo_XtEk0U!0-X%0LG%_Oo&y;sC!y!Vzbv!1e%gjo7+E(!P5CXQg zglw~&%zv|GAITU4^EUXYL*ba5L|+fG{n2f#<$P`;XXQzw!rFG>1xIQtjYXPCx$0Tg z_y1H9*k8*NMu;cG(T9I5k|_z+!6-KvLctWLG?awCF`Wto6>5{_B*kX_J!#TlRfW|Q zTxT2;H#0}=YR;55U1N;$dTp5H%;k}GCmbbyfA00QK5!SnK;wWT_=y7G3YX(F_2ej zekKG-;-FFYlnsInfBS-ue-l(=JyzlnCV;dv+bFa!pd>$1xZyr37BgGGzr|0+^O~0j z15^}t&e-E6dU|#)QNVmuka5beLq1^$=n5hx6Mg@fLV!rjf(f07zjUyE!{MRr^$O81 z9c&-SdtEZ{pn(T}h6ZnUS7wPMBn?d!5HMe!BHRBbb05=@24O?2h_`+1 zSkky=Y6p<;hK&MFs_UV3Pi4-ZFlQ5qOdAaJ4>=1O04Q<~*!bCF?FPS~o{er4?b z@BAktYAQF=_~SF#TF%vAsN~HdgBetV+7Sn}tl<@KS7SOg0f&fC(;da%oL1YWSL+*m zGM#5P_te#*^#`lcd2E#Bzrd<*Ozyihcs6GM{UIN@;iOnS-MRs~qr?3IfIIow<-ibm z1axfeXk3WdOtrvL9~RrkL@RPE27Wm{vO5xg=Y{Si6xRMyB}nHWVL(7VUs(tiyCf+=eFX z^v*e{k1Tj6MkZdZ0LiaYY^zFpCUo+Dxx=bBlNeU*IS#VeeOAzI)Vt^$zh$j^EZMHM z**h+Kz~xZ6N@mz-#ETTbxO`K|Nr-N;@=2jQ#7ZgkFx(W;GWygjB|Jx@jU+qS`t!IrL_@Mh#X_TZx%@ z^4p_*L+-*ol_Bw(5gpCY^}j0qLkVl4eKqJivQEuSwK~_wQU=a?(Pr}B&EB% zySux)K|s1&x?55}O1is2>5>k~O$h(?yyyFj*W>Z~9|mI&_Fz2Mnsd!nbFSyU4NmP* zk_r34gxePNOJ$h6cykvyCw$qW0>}3|r&9U*AFcQWu@^Z90;YM#zVCO^+rx zNH@pXoqevqr|SqP@$wvXr8J@&d_JP>=uXmMSW8G@sN0shx}NXhJ^U;k3^P3*Y9*{X zT_){Q>`WUL%w79gi?=u4Dq=QB^rnC>Qexc!1mCKET58qi_4>ylhJterN@VVP&{9R} zf`VGjgzL=<92XlYXsi4V{!C1%tpasaKFas6LJV)K-=vfm;P_v(pq!FX4Y?&YsVKhO zR%%faHzRDbQ!M3E;64T2WnRzcuczPxKYjJ4E?oK+r6|}!&xa}zY4)CB2A?|sZ9Z0a z|7}5bo3I!eu5axh5J}j*49lzaa_Zc8rw3g>pdb(cSDK@($H8DyJ~4-_*`cwZ$s? ze5h6-?o%Yb`5-tXa|0?FF6Y2tk6?PhbB~VSfa6cTW01)6;9^4dE+jka44m<(+qOx| zS7+%A4{cV1vYAlL_6DE@7TAVxXLfPEJy)0APHnPc=nL6sYxCkc(#=FY#J=VU)@bgA z0_~_L;7&Dz1PtGWxfn&<4}Ma94p>_udw=f*7k4kv58VQ0lC!J^kehlmGtWV4Mi6UiYHz1L*lE`k@;g5_yK$-= zZtu<-NFGqxlm4JpB#T7g%Ex-iNmQO!&y7g$cHfwbO|=&7md}4l4Mn9|n24rEQ^>Ux zYO+gTedMAD(2~_1Q6k*FOpy38A*yn7gLcbXj?+s+U;2tl$BG4xn$@hHmfNzSfuA*V zDR8OI{FbT?yi6r34Q}@hSTAGKo2ggB19-#DmV2x|Zadz2|rHCQV8f=qYq3S-XQKr)V!L{fbjC(JB{i1oZ ziF#JsGKmxT>@0|5a3}*}b2#dWUIr!i`8n>4;r7E*)&qvB!SvEbZkC%_T$i>HF_iTK znSw(apn9nYdcK)KaXd!E__$?es}T}>(H*ztldjGo3~FxJOQHIwDEbA;V7L2u0y+iR zI z`Ta|+1SVzj1fro-ACvhOxw!`lkeVnt+5zUv+2Q>l6W3DEHS!?GkLeUc=jF=*DYi;4 zgAmXvqwtL98S&@oBP*(OL2;6Q!{jJ!x!SIzc(UKP=n25KVnzea3MJKb=3u8Cm>iLlc zo>?@$-95+WQf~)EAZt_5R=Kx&-+eesXf5(h%iWVsgV-k<5sR4Bt?SzA!_Si!Vs17{ z{6tvfF)5Sptk|88Zta~Yi^wNgFB3D>72<4rA$j}O^elvaJgTjo4ShF~YmiNpHeGbr zyKXGp)-!&Ibd!z^zbI+4QbF?)fGbwcwDyLFza9Z}=ghoEC1>_-5DRf*_-4`0`D_3% z-j$9^NUELnMfu|?&hgFGHu3n@;Oi!chfyGFC1tj zysM2L<;pVB&eZILeivP-DG6^E!_0P@Pv$*0)yMcNP8S ztipdgy#t~iDVyOeruzZb?;xzt0NZ53utk9^3ZvN}(iFQco`XI5+!2~Bt*g7s$UI9V zqTk}E=N|5KTZK~u!6+3ngR++0rc2UcL~b2^1ySOpH^5EkBa;19dk^IoLT_D(^eYV? zh)u!~KjQmm97L8GO!T6q$6zM-+4)P@I(QCal||#8B$YWzh+EnD6~{;lGD;KM(2Z~x zbfm^>#(c>3<`9QS(Mb$0_NoT37Om8`p*ft5u4+)-eY&scXqIdG8ph(=r%k3w~PVLOXd zvY%SJgzTUS)}20bSmIE#Ku2ArE#^+hFkz~5s)Jq}y~;DcyBxahE*PlD`+}A(u^rn<&8zczVDn%^A5dk-Vy_mr0qL*uM z+kH(G>dhnCDc>o`r?(AIs+^*rfe)ECTkV3CYD3Q#19fXQhe<>BD4P`WFJ{4fglrGp zMC#o(hLNzR_6BG%EOWFS0kBYlhLR^aX`ly0}L;y&ATq9Kgir+g(JSTR7eC^Kd70rtk@Qwh@u3M8?jc zvgkQ+ER2q@6iY?Es?2yUOPXy52HHmmw09OlCy8i1JSX$cFQ?Kz?WxLaD*;xXXdOZ= zBkjariS2=U=4{ztOD4WdLby%7@-N=%81G7r_onmAC}*~wh&dH`ElcXAaT1YCg!*3c zydPyIQxoLY1}B)t!AYV-sVm|=v@yqXQI~?W4Le?d1`+uZEGOQ|ee*VGf zrT|&74wW?}lFB{`V02N9RseY6=RHwR+vczuOFPU6KW$IutXl`cwNkIGa12qG zrJ%bP3TNk7J?}yS3x6XEWxoN1EKl;n-Jr)OR82@8A-lLcqJ0m!DhivFnJu)P!CIZozRj3Dupfu>UuxP6njtRWN0x(t)#GPjJ(W*QX;@KZebajIc;dm zCW~hL0jRsrD=aVq-P|3Oy{?-lW2lzd!ihrjVFr)oLbOS5oQOiE*S-!;?Lbx&bB@wB zIBCNkoH#5Y8I#5PlHx>EpLUEIfBnTV;pU3R%nfkZ z!YFhE-!>M@7lKEDX})s?nHWmd;*DDNM6GEm7PaY{ePtQ7vU*E6^Yo7t_xmKXg?pIw zLetbL($kGYR?TwDFJ{6?y@??DP->A;k*WI-u5h`r_Fj=a1?c8CaYv_fx+w3Y&sz)# z5l!Eerg8T>?FtY$ym)%@xf}a@V)bx@rCghzp-=;#(K|s@NOO*IZA)NzB23n8Oyp`N z6Y_)!pjq5GpOl;|9mspLVAjuk4Swf>dB>Z+oWGfksTiJHt6LL8{)`TN&}5mlo&S@f zn?k$j;4E88b8ms}U06xznINvR%znonws$*X0nXu~KR;D&0=; zq1MxLBj~1VFmZ3_rpJ&0B|edG0LL4z$TA%JtOE-~IHfCXompV+wy z8-&6rt-RaR;6BG2HZ5IoYkQ!W1K80!*5H1C5|T&@US7!VmLWU9nG%2IR0sf%g(q;p zir%R2#OCiM-FRbfu?u|_l)-Q7I{}F_K#B)nXF9wXSLm-9xO`&}clEL58GaMK6`1Uo zQKob~3zs=o{h-kD;27bhfCkdw{8=X?mD$rB(iIfJLV2z}Inma$btemM>{3VY_dH`c zRmH*W_;0{4Bi*0y!=kq3gCg}!KzsqQv(?<&2%Y|52_E_JZZE7axCF6;pWKz-h9;(1 zFEg|lBDp{TkLtU9pc8X{8!)$h;lT}wYiX`cFvH{sCC$IJ1nrkGsX1R-c54t zLc9jBHVaK(PZqQAK)*w|rQxaCi@4yDsR;BKp_0+QMY4^V@oQdty=y?g5jigp7$EqZ zjDUR~x@7qfAlguTFi<0JZx{E(?05$3ZrE!(`+7JwC(6-O)0zPfL-;9#k~GMZLtGy?nM#)>2+T`kNj ze-Cd%!Vd{3rx0cOIo+1L-plN7F!@)*0?vWum?{xsvwILKF<=UycOWzqNrt^1DAHo{ z&>l4+Ab^}}aY{#leq4;cq6#<-V$Ho7UKVZ81@Wh+CFOY)SxBEZUOMd5^n&4mJBI5y zhiL&%RP$EK=dU%dsx>v_%dKWSAnH{~OU>To6_twC8@+RTFwOV zjN#5sZh{G`WWFrn$+vV8xa_EdxGegTh$iG5fdf8|IkR2eF_u{^F!2%tv7EYty{ytY zfTzxF4)ngPoP_WTG|Fer08u&Q$%>o}_7yWw_VUke{^I-nDIPLL`#{~ep5)0hW*8ez z$=vvIc7ys0bTt^Z4cC$pSAr8jP+)*}S0n5;J4~41b{%cIM*fv_$1_a{7~CzEGF*%a zmo!~DyV(mH=a!>N6aTXY|l>8fd_G+w#(nF|q5jcLBA z13?#dl>PPCA}RNzqD6oVO(@OKym{I-Pa5JmLRwqW$FBiUBnL+P2)@~J(ec|s_sm!R2@$OKicGYN*2GqU(J&T z{Lqn)*=vxuAX1Gv0Dk!C`pCTtlDrGq_gKcHI?^jian>rS^UL?G0{-ilaNK#DTyw56 z{Mo5FbQ?Hew~5Kllovle5o!-n7?EA%~9 z%jQnBip8H@%a9KGo;gZW59-6s%P>_Y62@fk&z9tt_3vec<8wZNl}y-DPVJOG|Iin_ z626Fx(_8z21@R?Y6h3=m$wyZ(m0~u^gGm$C_>_E9bIWd}w}}Fi6`vO0&SEgSdVWB! z70oGSTwI5)%Dq)n3w0Upp_=|g;_;3OZw=}>WJUsdX*M=A4EsAwYD>0ZPrKc^Y`%(P zR4QJgyJNu4aNup&3279U6_ zdbsfLmw#jb+-(ai0SJf=$M4ESh--^XS307Zgwt`pJ8{}aNm%u@LRcdGx zw~H)F7#NIpX{7#kW5V(1H5 zz5AdL#5;!Xs~elu2h{fX{pR6_V=3+&^ruJ{iTx$`s^O_)RYD@?{ol+}(o43PDCFcy z>6@z&ig(9lnQ&Je#^YG*qG0nV5izc-nDi1Oya!vptC5L&xq!LbWas62!Jk9@Hgg$u zcf|NzytpAfC_?Eo)ZG&ywyD+)KyrtAk@F|5=o#Mda4t2W8yW1la)U@5zE9jn2t8L( zX81%5B2%>F4iIQQ*!=|^;t?PSN?@8gFwrSJ@S3$#y8xt&xUbuD-u=7}9#eLWR72-qTT@xu+BTcA6}iClYMq3D|3PS&w~_olnHK zbbUG}X3XIIUV2VpcbYSqR^lWK`E;G4pb|N_JYdhO-P9g;3Pq zx#XGZHE!5Xc?m~}&3$AbIXJZLI=xQV><&VT5CXbQ&*Kz10ue(bo$2A61QOcN*>`p;EOKRNXLPtn*{8w3F-Cleb(>;Dq;Q;C(4 zd?J7xq=(1C&}V+H(IjuWE!QWIPhSF^7YZk!fUfOIo+QzqwU^5k7P>3Y8U%-;?GA!O zHYcntF5ohIP^By2K2uO|W-gA~czK@O*61M(U{K*rXX`j+=FR!L5*bC z8%ZNoC}V;XL!Kpb>sP)JkSj_sf;rwMx2$<+g%bK77T7~8tSw-VD@GV=JA)2g5Hs@& zN(X^2sMAj;J;5fpbBvQ$s%Wr@mKo`t|+60qbQv%_fRc(1N8*2fDS zc~Y)?i3pyo`Y`?2GK=TmHMB1Sk?@)-KhzR}Oj=qWo(Ut-uUx}_lC%xNatZzBfmEBJ zSB2ILfPtS-VxP5RivoeD?|F1}MKFC}S2DXwe+>&i*)@^(pNc<0Ylm@t;ENoizkQkG z#jnpbKyf#qNVcsT*VPwT{GWW9AfDFmg(z^eN2;&JR3~wRYIg?8~`b z6w+Q}ETeZ#j>1Z?z5425VK$AnXI=J;)o?YW1AC@*n=7rc0xy8rmLo~Jcb!bgn3ceG zv1@S2g~rpP*}ia;hD~CRV%Kn2XA_Ux$o_4-22CZ*sM5r!eGy6Peeyw==5WHgAUBr! zfvRYibkq^Pj~pB0`BIi)Xx#xu3H)+%OM`sS+HY@3+2tFUh{#~*CgyA#2A6>lqfn z6S5O{6{Wk3D3`MS+HG^VfwulGBaN;h`#huNIg<4%zjQE;0edb^GBt_26eM9Eg~2<= z%x&8wNd;sz2J(b`T`Vn+b%GZu!pg_&@u44I_b|jc_M^Ast*GX% z~cER`C{E`DzN*%y4r>@ti4A$Le2~6EEK|BE&%nFopIQQ zN!-D9pX<=ija}?3M}Wur)SnR4!Q^=N{TZI>K-5OX+PuZ@ecEdP)O|3 z;Z49IgbEtgSJg(*(Aa^$Aoi=5ZV6^_E4HzP)mn?bbRzqSk-Q@}P! zU^@l7uS{R0FQ1#*uh%#!jP+VDBI7|deK+xz-o;cMwsFQa_N6oU`m|HL^uTLD=QXI? zqFiDND9*>fT!W9Zuh{5;R})jH-(6Au;dQ~kD`bIM)20??E{+DjC_(m7K9a=~L+3%m zmtNX7LSUw(wb78YdD4gQYKDwb0w6BK=Xyc%RRPAvWSvJs>w0h2R385!%w)PxhWr&M01bMie zx>a1ez2u_4;Q$qR#^a%(z`bD;W}PcbW;gZp$;XJ(jj16;20aY3xp5(V_)^EWM`}Gr zK#ADYB0DVWY&9JP_oH)FDL~K(Y0HNT%jo5+7MAC6`q*B*BqP)IfOA zSs1}p4ht#5?g87B?XYTl`HxLvWh($kg4e|Fz2Zvohr;hXR?n)(=s&V%ugp%$J_YTVFooJk<#&j9b704}aM+b!QM* zY2B{6NUDF@2GpzM?B-{6Ghg#rk|qw*Qr=FO%CA^HN`cxwni?*?^I8;o%^2I|#b!@H z!~kFZVrVLm*xR}zG$0!nJB)j{!+gufR3EieNl0$mvb9e%%PXc-huMH^XTw*p?1 zYyBDhW(uaF%N2hMyCTWakzvUi@hY_+R8p{u`b*vcrP^U z_*g|+yWK|d2olI`sQ^ThBwo*25*7;P@yH3tB(f9HU$-isz0RnuWHIEzUyNIb?n@Re zv$Du(b|ul3b3Fq0U>?6%DxBrqHZ@M!(Q9Sr<$XXSD&RZR=lmi8#WaVOpR03FJ!gJX7}xq)vi!L65L~h`COI7w7PQN!xMG^TmKZsOTAK%u z#7EYSymBa>Y&`4@Ffm&lxog|JGhG>BPx$u;Ig zhanra)@5TBV{@8(le)od=MZScTHK2=8cikHIuNW>^0PQLiQ-@U95r?P0sc?spnX8XB-Fwp8ZN9nk*gQNY==j2)0kCP> zDS3wH9LV%ani_3bU2|xy#zAU$rwL<`uAe~6y>{(&G8kQVUiZh>m`rur~bZ0XVL~QQ(q<_ClM)5o8+`+95hA?X0lOj&2f6?i%}xEm~y3R zZA1w3h^*;MJ*GFdRrP9o(a}EeSy$0MRB1H>ND#EI?o(ILX|D1yXsML7Jz;PiQelZ+ zp!i9t0BZQ}Y0c!zH|4A21GdDR7i)Cpg{XY}^=@lm1vWb9>y^p4F^Fj{5|XH~U(`1y zf0U&kUb4c0uQ(#`!MNRwE;%*DP}`saRhM}Q@8)WSInEKkDq_N)ih@A^4cDIuzpTR1 zg1^TRqQx;vVRq~}7XnA(a3&`_p-X}Rp+M!R82&a9yRuU2)qbcH!*(OuBG-ZxL$7^3 zk&b$I^~5I@OdQRRR`nvwa|Z8Ax*#R#RSH|9#$u7?>1oDhG*RHFDlwSr4bi&61QLwz zDLzl|vh{cbR+{+2Riced&uLkYy9`dK_ScE8u`N&ueqg2cUruA%=)P)#35CF58vwV> zIFPBlmMmvWShXzwjAC;X9Q9dnE`&F@@U8Utn=nx1ySEfLX(0((;LiiMhO*{o z332vyIVs;A+_1A?y(oW|?Fl2oUa(^_iON_+oYqiYgd}-iq2eyFl8e*2C7b|Q$7#)w zm1s2=sH^Fdv2u>d+BWU{?4KqFr-5CP>KbEH1xpYDVVij6M-c8AG=ym^@?d!I(P`9u z(W@77VDq{wy0<#R`)C@Tr;x*YPD61$^u=U&KnFrtLk+}c7XYQ}!}&%5t49-o8#I6j z8$BWc@|_PmISg)MZFq}`=(Tu&Y0*gn=!zUT%R6}HnzGC1I3zr#o#GHqMQG@>OzQj7okNAF z(psjhjkl6sE-6TI^GhnVg0K&Qnd~;28l$D{!$=pSZL9m)_hz5f__8{k;McQxsl7yL zoV4+ZL@DetHhsB+u&|Sr*#=j%+t!eitu!F$RMK>tLL_&GeKR_!oe^eQ=FnS3U9fs4 zI?FrCXlH>RT``+eW}G!(+Yec7JR&Y?WJi( zmoa%r*|6?kWI2MyMWFR&UR94W?=gsTJxJ}_*g_YkdUWL!owBrj-lX=Hx;)8+BIbFr zftcCqOWQ7{96mH7cGBrD==xgg7+$j^gyKT_a)O9QZ?{T>TX!jrkd>J#Cm|;2;tO2| z=43{SY5NJhTQKQ*&oeNy$u#WO!de&b$r+usOzH|f+vA&o_9PCcYXVad((7s>b=O!Z zxvTY)LL%1i&SDV@+C7(o`!I)3_ln}{m?q?=Y~@fKh>zj!lY5>N_O3$Ml2U5KPx+(7 zN0LYrf4JaN?NRvbXSVht{+PCc8`(XyfG??_f2D8e;jKH>`WI|T!;WbjqP9zrm*ZR7KW`bM%aMZ4>;lijsSslVlc+pT}&WfxFuQSMv0}uM1%mqJA$7GWa z6pIIode$f6LrBHlm1tMmunGE`=P4W`HIGYvT#t8kYINF0AA{{c=jGrCMA7YO`<&7m znPRW=3T+R(iyAEZD5LAgt+0a^)JQ95Y} zArV<65fxQBr;(Bl?f2HlYs0 ziGdJ%;O|#epl^W;RG_kRG@~>7OHhi=$l8MLJ1b@ZM>7{2pdviba?Qm47dPlXx4gn5 zAS((u#k2^#&-gl#^es}6f5-WyC+g41pS(8g(F7)M06uYiwe0*BfoQ)={+9!*<1+zM zpe4zFKtG#={Y zWh|VWfPQ@cp#n$BpCHi$Fq3A1NJ*f0`j5@bc=iX#zgcbujwXNJ%$8|Sv|Ql8_W^R* zf9Tq6-~sy2ga7Yw^MCDC&}KYbVj#*CIDmc}rk9j|j8g*IG1;2^%l?~tkPAUa! zoPSK-#rj{#|LUpVSk(V~Fn@15{M8crTjX;6d-DGbxPRIH@BK7?9A#=eKOijruWrUa zH|Ben#;-;|-(p?xH>CfwTj$T*@7>LQyk=br|G@pFquD<@LjKJ8-uCLNSK7B=k^Fbg zA3CS~4E^4B>8qpGw|FJ}1N48^U;fBn>u1XM)-XTrI(OM$QvTNt=KtpC^fUK+i;S=aQLge^)V~~G-zzMBoxuDS=O(|*`v;1gKX3c@GJ`*k za60qfF#ev4`Df+EpE=)Gb$=Bt{1(v`f5!Qj&icO6_{Yu)@%|;?4@$*8G>EADkeqE{m7WL`BO#91q`=2-V`_;N1uP(+}zs&l(<<*~)e?RN~b;0jj z5a;|l`5!F*{S5hjw(!SY+EDOI$ls&#chmVlGroU@`a19UEsRQj$M}a?NO>s;-~$;5 R2np~f1o-$>Q}y+){|A@R9n$~+ literal 0 HcmV?d00001 diff --git a/combatant-client-26.2/gradle/wrapper/gradle-wrapper.properties b/combatant-client-26.2/gradle/wrapper/gradle-wrapper.properties index 1a70468..b52fb7e 100644 --- a/combatant-client-26.2/gradle/wrapper/gradle-wrapper.properties +++ b/combatant-client-26.2/gradle/wrapper/gradle-wrapper.properties @@ -2,6 +2,8 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/features/command/impl/ProfilerCommand.java b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/features/command/impl/ProfilerCommand.java index 59b5596..c62462b 100644 --- a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/features/command/impl/ProfilerCommand.java +++ b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/features/command/impl/ProfilerCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,7 +15,7 @@ import dev.loki.lovisual.render.engine.profiler.FrameStutterProfiler; import dev.loki.lovisual.render.engine.profiler.JfrProfiler; import dev.loki.lovisual.render.engine.profiler.ProfilerSettings; import dev.loki.lovisual.render.engine.profiler.TracyProfiler; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import java.nio.file.Path; import java.time.Duration; @@ -32,13 +32,13 @@ public final class ProfilerCommand implements ClientCommand { @Override public boolean isAvailable() { - return RuntimeGate.canRunClientLogic(); + return Lifecycle.isActive(); } @Override public boolean execute(CommandContext ctx) { - if (!RuntimeGate.canRunClientLogic()) { - CommandOutput.send("Profiler: disabled in Panic mode."); + if (!Lifecycle.isActive()) { + CommandOutput.send("Profiler: disabled until client is active."); return true; } String target = ctx.arg(0); diff --git a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/mixins/ProfilersMixin.java b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/mixins/ProfilersMixin.java index 518fdad..189128c 100644 --- a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/mixins/ProfilersMixin.java +++ b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/mixins/ProfilersMixin.java @@ -13,7 +13,7 @@ import dev.loki.lovisual.render.engine.profiler.DevTracyProfiler; public abstract class ProfilersMixin { @Inject(method = "getDefaultFiller", at = @At("HEAD"), cancellable = true) - private static void combatant$limitVanillaTracyToRenderThread(CallbackInfoReturnable cir) { + private static void lovisual$limitVanillaTracyToRenderThread(CallbackInfoReturnable cir) { if (!DevTracyProfiler.isEnabled()) { return; } diff --git a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevFrameStutterProfiler.java b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevFrameStutterProfiler.java index 5b68327..3603cb9 100644 --- a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevFrameStutterProfiler.java +++ b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevFrameStutterProfiler.java @@ -8,7 +8,6 @@ import net.minecraft.network.chat.Component; import dev.loki.lovisual.render.engine.rhi.RhiStatsSnapshot; import dev.loki.lovisual.render.engine.rhi.resource.RenderResourceStatsSnapshot; import dev.loki.lovisual.render.engine.rhi.uniform.UniformAllocatorStatsSnapshot; -import dev.loki.lovisual.runtime.RuntimeGate; import javax.management.Notification; import javax.management.NotificationEmitter; @@ -85,7 +84,7 @@ public enum DevFrameStutterProfiler { RenderResourceStatsSnapshot resources) { try { if (!isEnabled()) return; - if (RuntimeGate.isPanic()) return; + renderThread = Thread.currentThread(); ensureSampler(); @@ -258,7 +257,7 @@ public enum DevFrameStutterProfiler { private static void ensureSampler() { if (running || output == ProfilerSettings.OutputMode.OFF) return; running = true; - samplerThread = new Thread(DevFrameStutterProfiler::sampleLoop, "Combatant-DevFrameStutterProfiler"); + samplerThread = new Thread(DevFrameStutterProfiler::sampleLoop, "LoVisual-DevFrameStutterProfiler"); samplerThread.setDaemon(true); samplerThread.start(); } @@ -276,7 +275,7 @@ public enum DevFrameStutterProfiler { private static void sampleLoop() { long lastSampleNs = 0L; while (running) { - if (output == ProfilerSettings.OutputMode.OFF || RuntimeGate.isPanic()) { + if (output == ProfilerSettings.OutputMode.OFF) { sleepMs(20L); continue; } diff --git a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevJfrProfiler.java b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevJfrProfiler.java index 7a45537..667e784 100644 --- a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevJfrProfiler.java +++ b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevJfrProfiler.java @@ -32,7 +32,7 @@ public enum DevJfrProfiler { Path file = dir.resolve(defaultFileName(preset, false)); Recording next = new Recording(); - next.setName("Combatant " + preset.getId()); + next.setName("LoVisual " + preset.getId()); next.setToDisk(true); next.setDumpOnExit(false); configure(next, preset); @@ -159,7 +159,7 @@ public enum DevJfrProfiler { private static String defaultFileName(Preset preset, boolean snapshot) { String timestamp = FILE_TIME.format(LocalDateTime.now(ZoneId.systemDefault())); String suffix = snapshot ? "-snapshot" : ""; - return "combatant-" + preset.getId() + suffix + "-" + timestamp + ".jfr"; + return "lovisual-" + preset.getId() + suffix + "-" + timestamp + ".jfr"; } private static String formatDuration(long totalSeconds) { diff --git a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderCostProfiler.java b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderCostProfiler.java index 66bf6e1..3c5e21f 100644 --- a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderCostProfiler.java +++ b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderCostProfiler.java @@ -1,6 +1,6 @@ package dev.loki.lovisual.render.engine.profiler; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import java.util.*; @@ -19,11 +19,11 @@ public enum DevRenderCostProfiler { private static final int DEFAULT_LOG_TOP = 20; private static final double DEFAULT_LOG_MIN_MS = 0.02; - private static final String PROP_ENABLED = "combatant.profiler.renderCost"; - private static final String PROP_LOG = "combatant.profiler.renderCost.log"; - private static final String PROP_INTERVAL = "combatant.profiler.renderCost.interval"; - private static final String PROP_TOP = "combatant.profiler.renderCost.top"; - private static final String PROP_MIN_MS = "combatant.profiler.renderCost.minMs"; + private static final String PROP_ENABLED = "lovisual.profiler.renderCost"; + private static final String PROP_LOG = "lovisual.profiler.renderCost.log"; + private static final String PROP_INTERVAL = "lovisual.profiler.renderCost.interval"; + private static final String PROP_TOP = "lovisual.profiler.renderCost.top"; + private static final String PROP_MIN_MS = "lovisual.profiler.renderCost.minMs"; private static final LinkedHashMap buckets = new LinkedHashMap<>(); private static final HashMap labelCache = new HashMap<>(256); @@ -351,17 +351,17 @@ public enum DevRenderCostProfiler { static Counters capture() { try { - long uploaded = CombatantRenderSystem.rhi().stats().uploadedVertexBytes() - + CombatantRenderSystem.rhi().stats().uploadedIndexBytes(); + long uploaded = LoVisualRenderSystem.rhi().stats().uploadedVertexBytes() + + LoVisualRenderSystem.rhi().stats().uploadedIndexBytes(); return new Counters( - CombatantRenderSystem.rhi().stats().drawCalls(), - CombatantRenderSystem.rhi().stats().meshUploads(), - CombatantRenderSystem.rhi().stats().fullscreenPasses(), - CombatantRenderSystem.rhi().stats().textureFastCopies(), - CombatantRenderSystem.rhi().stats().textureShaderCopies(), + LoVisualRenderSystem.rhi().stats().drawCalls(), + LoVisualRenderSystem.rhi().stats().meshUploads(), + LoVisualRenderSystem.rhi().stats().fullscreenPasses(), + LoVisualRenderSystem.rhi().stats().textureFastCopies(), + LoVisualRenderSystem.rhi().stats().textureShaderCopies(), uploaded, - CombatantRenderSystem.uniforms().stats().writes(), - CombatantRenderSystem.uniforms().stats().uploadedBytes() + LoVisualRenderSystem.uniforms().stats().writes(), + LoVisualRenderSystem.uniforms().stats().uploadedBytes() ); } catch (Throwable ignored) { return ZERO; diff --git a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderProfiler2D.java b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderProfiler2D.java index f7d5ff2..18a2295 100644 --- a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderProfiler2D.java +++ b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderProfiler2D.java @@ -3,7 +3,7 @@ package dev.loki.lovisual.render.engine.profiler; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import dev.loki.lovisual.render.engine.command.UiStatsSnapshot; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.renderer.ui.runtime.script.CachedUiScriptRuntime; import dev.loki.lovisual.render.engine.rhi.RhiStatsSnapshot; @@ -12,7 +12,6 @@ import dev.loki.lovisual.render.engine.rhi.uniform.UniformAllocatorStatsSnapshot import dev.loki.lovisual.render.engine.text.TextCommandStatsSnapshot; import dev.loki.lovisual.render.engine.text.TextRenderSystem; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; -import dev.loki.lovisual.runtime.RuntimeGate; import java.util.*; @@ -168,7 +167,7 @@ public enum DevRenderProfiler2D { )); } - TextCommandStatsSnapshot textStats = CombatantRenderSystem.textStatsSnapshot(); + TextCommandStatsSnapshot textStats = LoVisualRenderSystem.textStatsSnapshot(); if (textStats.recorded() > 0 || textStats.meshUploads() > 0 || textStats.glyphs() > 0) { lines.add(String.format( "text: rec/sub %d/%d, backend vanilla/bitmap/msdf/world %d/%d/%d/%d, effect/clip %d/%d, glyphs %d, meshUploads %d, router hit/miss/fallback %d/%d/%d, adjacent %d, uploaded v/i %s/%s", @@ -256,7 +255,7 @@ public enum DevRenderProfiler2D { } appendRhiCounters(lines); - var immediatelyFast = CombatantRenderSystem.immediatelyFastSnapshot(); + var immediatelyFast = LoVisualRenderSystem.immediatelyFastSnapshot(); if (immediatelyFast.modLoaded()) { lines.add(immediatelyFast.shortLine()); } @@ -290,8 +289,8 @@ public enum DevRenderProfiler2D { } private static void appendRhiCounters(List lines) { - RhiStatsSnapshot rhi = CombatantRenderSystem.rhiStatsSnapshot(); - UniformAllocatorStatsSnapshot uniforms = CombatantRenderSystem.uniformStatsSnapshot(); + RhiStatsSnapshot rhi = LoVisualRenderSystem.rhiStatsSnapshot(); + UniformAllocatorStatsSnapshot uniforms = LoVisualRenderSystem.uniformStatsSnapshot(); if (rhi.drawCalls() > 0 || rhi.renderPasses() > 0 || rhi.meshUploads() > 0 || rhi.fullscreenPasses() > 0 || rhi.textureFastCopies() > 0 || rhi.textureShaderCopies() > 0) { lines.add(String.format( @@ -331,7 +330,7 @@ public enum DevRenderProfiler2D { uniforms.staleReadMisses() )); } - RenderResourceStatsSnapshot resources = CombatantRenderSystem.resourceStatsSnapshot(); + RenderResourceStatsSnapshot resources = LoVisualRenderSystem.resourceStatsSnapshot(); if (resources.persistentFramebuffers() > 0 || resources.temporaryFramebuffers() > 0 || resources.retirementBacklog() > 0 || resources.leakedResources() > 0) { lines.add(String.format( @@ -383,7 +382,7 @@ public enum DevRenderProfiler2D { private static void emitIfDue(long nowNs) { ProfilerSettings.OutputMode mode = getOutputMode(); if (mode == ProfilerSettings.OutputMode.OFF) return; - if (RuntimeGate.isPanic()) return; + if (nowNs - lastEmitNs < DEFAULT_EMIT_INTERVAL_NS) return; lastEmitNs = nowNs; diff --git a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderProfiler3D.java b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderProfiler3D.java index f556300..c4210b0 100644 --- a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderProfiler3D.java +++ b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevRenderProfiler3D.java @@ -2,7 +2,7 @@ package dev.loki.lovisual.render.engine.profiler; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.rhi.RhiStatsSnapshot; import dev.loki.lovisual.render.engine.rhi.resource.RenderResourceStatsSnapshot; import dev.loki.lovisual.render.engine.rhi.uniform.UniformAllocatorStatsSnapshot; @@ -10,7 +10,6 @@ import dev.loki.lovisual.render.engine.world.WorldRenderStatsSnapshot; import dev.loki.lovisual.render.iris.IrisRuntimeSnapshot; import dev.loki.lovisual.render.sodium.SodiumTerrainInteropStatsSnapshot; import dev.loki.lovisual.render.sodium.SodiumVisibilityStatsSnapshot; -import dev.loki.lovisual.runtime.RuntimeGate; import java.util.*; @@ -160,8 +159,8 @@ public enum DevRenderProfiler3D { } private static void appendRhiCounters(List lines) { - RhiStatsSnapshot rhi = CombatantRenderSystem.rhiStatsSnapshot(); - UniformAllocatorStatsSnapshot uniforms = CombatantRenderSystem.uniformStatsSnapshot(); + RhiStatsSnapshot rhi = LoVisualRenderSystem.rhiStatsSnapshot(); + UniformAllocatorStatsSnapshot uniforms = LoVisualRenderSystem.uniformStatsSnapshot(); if (rhi.drawCalls() > 0 || rhi.renderPasses() > 0 || rhi.meshUploads() > 0 || rhi.fullscreenPasses() > 0 || rhi.textureFastCopies() > 0 || rhi.textureShaderCopies() > 0) { lines.add(String.format( @@ -177,7 +176,7 @@ public enum DevRenderProfiler3D { formatBytes(rhi.uploadedIndexBytes()) )); } - WorldRenderStatsSnapshot world = CombatantRenderSystem.worldRenderStatsSnapshot(); + WorldRenderStatsSnapshot world = LoVisualRenderSystem.worldRenderStatsSnapshot(); if (world.recordedCommands() > 0 || world.submittedCommands() > 0 || world.skippedEmptyCommands() > 0) { lines.add(String.format( "world3d: commands rec/sub/skip %d/%d/%d, vertices/indices %d/%d, fog %d, depth pre/main/none %d/%d/%d", @@ -217,7 +216,7 @@ public enum DevRenderProfiler3D { uniforms.staleReadMisses() )); } - RenderResourceStatsSnapshot resources = CombatantRenderSystem.resourceStatsSnapshot(); + RenderResourceStatsSnapshot resources = LoVisualRenderSystem.resourceStatsSnapshot(); if (resources.persistentFramebuffers() > 0 || resources.temporaryFramebuffers() > 0 || resources.retirementBacklog() > 0 || resources.leakedResources() > 0) { lines.add(String.format( @@ -233,17 +232,17 @@ public enum DevRenderProfiler3D { )); } - IrisRuntimeSnapshot iris = CombatantRenderSystem.irisSnapshot(); + IrisRuntimeSnapshot iris = LoVisualRenderSystem.irisSnapshot(); if (iris.modLoaded() || iris.shaderpackInUse()) { lines.add(iris.shortLine()); } - var immediatelyFast = CombatantRenderSystem.immediatelyFastSnapshot(); + var immediatelyFast = LoVisualRenderSystem.immediatelyFastSnapshot(); if (immediatelyFast.modLoaded()) { lines.add(immediatelyFast.shortLine()); } - SodiumVisibilityStatsSnapshot sodiumVisibility = CombatantRenderSystem.sodiumVisibilityStatsSnapshot(); + SodiumVisibilityStatsSnapshot sodiumVisibility = LoVisualRenderSystem.sodiumVisibilityStatsSnapshot(); if (sodiumVisibility.queries() > 0 || sodiumVisibility.errors() > 0) { lines.add(String.format( "sodium vis: queries %d, accepts/rejects %d/%d, bypass %d (unavail %d, optout %d), errors %d", @@ -257,7 +256,7 @@ public enum DevRenderProfiler3D { )); } - SodiumTerrainInteropStatsSnapshot sodiumTerrain = CombatantRenderSystem.sodiumTerrainStatsSnapshot(); + SodiumTerrainInteropStatsSnapshot sodiumTerrain = LoVisualRenderSystem.sodiumTerrainStatsSnapshot(); if (sodiumTerrain.terrainUpdatesScheduled() > 0 || sodiumTerrain.rebuildsScheduled() > 0 || sodiumTerrain.interopErrors() > 0) { @@ -305,7 +304,7 @@ public enum DevRenderProfiler3D { private static void emitIfDue(long nowNs) { ProfilerSettings.OutputMode mode = getOutputMode(); if (mode == ProfilerSettings.OutputMode.OFF) return; - if (RuntimeGate.isPanic()) return; + if (nowNs - lastEmitNs < DEFAULT_EMIT_INTERVAL_NS) return; lastEmitNs = nowNs; diff --git a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevSamplingProfiler.java b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevSamplingProfiler.java index da6c4cc..3dd6484 100644 --- a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevSamplingProfiler.java +++ b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevSamplingProfiler.java @@ -2,7 +2,6 @@ package dev.loki.lovisual.render.engine.profiler; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; -import dev.loki.lovisual.runtime.RuntimeGate; import java.util.ArrayList; import java.util.HashMap; @@ -37,7 +36,7 @@ public enum DevSamplingProfiler { stopIfRunning(); return; } - if (RuntimeGate.isPanic()) return; + lastSource = source; flushPendingChat(); if (!matchesTarget(source)) return; @@ -56,7 +55,7 @@ public enum DevSamplingProfiler { private static void ensureRunning() { if (running) return; running = true; - samplerThread = new Thread(DevSamplingProfiler::runLoop, "Combatant-DevSamplingProfiler"); + samplerThread = new Thread(DevSamplingProfiler::runLoop, "LoVisual-DevSamplingProfiler"); samplerThread.setDaemon(true); samplerThread.start(); } @@ -88,10 +87,6 @@ public enum DevSamplingProfiler { pendingChatLines = null; break; } - if (RuntimeGate.isPanic()) { - sleepMs(20); - continue; - } Thread t = targetThread; if (t == null) { sleepMs(10); diff --git a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevTracyProfiler.java b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevTracyProfiler.java index de6dd8b..529eee0 100644 --- a/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevTracyProfiler.java +++ b/combatant-client-26.2/src/dev/java/dev/loki/lovisual/render/engine/profiler/DevTracyProfiler.java @@ -40,7 +40,7 @@ public enum DevTracyProfiler { boolean active = isAvailable(); if (active) { ProfilerLog.info("Tracy enabled; data is streamed to the external Tracy viewer, not latest.log"); - TracyClient.message("Combatant Tracy enabled"); + TracyClient.message("LoVisual Tracy enabled"); } return active; } @@ -105,7 +105,7 @@ public enum DevTracyProfiler { loadAttempted = true; try { TracyClient.load(); - TracyClient.reportAppInfo("Combatant render profiler"); + TracyClient.reportAppInfo("LoVisual render profiler"); available = TracyClient.isAvailable(); if (available) { ProfilerLog.info("Tracy client loaded"); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/Lifecycle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/Lifecycle.java new file mode 100644 index 0000000..51ec8b1 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/Lifecycle.java @@ -0,0 +1,60 @@ +/* + * 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; + +import dev.loki.lovisual.util.logging.DebugLog; +import dev.loki.lovisual.util.resources.RenderResourceReadiness; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * Minimal client lifecycle: INIT until explicitly activated, then ACTIVE. + * Replaces the former Runtime/JarReplacement state machine. + */ +public enum Lifecycle { + ; + + private enum State { + INIT, + ACTIVE, + SHUTDOWN + } + + private static final AtomicReference STATE = new AtomicReference<>(State.INIT); + + private Lifecycle() { + } + + public static void activate() { + if (STATE.compareAndSet(State.INIT, State.ACTIVE)) { + DebugLog.info("Lifecycle: INIT -> ACTIVE"); + } + } + + public static void shutdown() { + if (STATE.getAndSet(State.SHUTDOWN) != State.SHUTDOWN) { + DebugLog.info("Lifecycle: -> SHUTDOWN"); + } + } + + public static boolean isActive() { + return STATE.get() == State.ACTIVE; + } + + public static boolean canRunRender() { + return isActive() && RenderResourceReadiness.isReady(); + } + + public static boolean canRunHud() { + return canRunRender(); + } + + public static boolean canRunShaderBridge() { + return canRunRender(); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/LoVisual.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/LoVisual.java index e9b159b..1fe3b4a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/LoVisual.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/LoVisual.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,6 @@ package dev.loki.lovisual; import dev.loki.lovisual.events.impl.GameTickEvent; -import dev.loki.lovisual.runtime.*; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; @@ -25,7 +24,6 @@ import dev.loki.lovisual.config.MainConfig; import dev.loki.lovisual.events.Events; import dev.loki.lovisual.features.account.AccountConfig; import dev.loki.lovisual.features.command.CommandManager; -import dev.loki.lovisual.features.command.VanillaChatRuntimeCleanup; import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; import dev.loki.lovisual.features.gui.clickgui.settings.I18nPreflightContributors; import dev.loki.lovisual.features.gui.hud.HudElements; @@ -41,8 +39,8 @@ import dev.loki.lovisual.features.module.WorldPhase; import dev.loki.lovisual.mixininterface.IGuiGraphics; import dev.loki.lovisual.render.effects.NetherPortalRiftPass; import dev.loki.lovisual.render.effects.SleepOverlayPass; -import dev.loki.lovisual.render.engine.CombatantRenderEngineBootstrap; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.LoVisualRenderEngineBootstrap; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.RenderPhaseScope; import dev.loki.lovisual.render.engine.core.ViewportContext; @@ -78,90 +76,10 @@ import dev.loki.lovisual.util.time.TimerController; public class LoVisual implements ClientModInitializer { - private static void registerRuntimeLifecycle() { - AddonManager.registerRuntimeLifecycle(); - ClientRuntime.setCallbackCounter(Events.BUS::listenerCount); - ClientRuntime.setModuleCounter(ModuleManager::registeredCount); - - ClientRuntime.registerParticipant(new RuntimeShutdownParticipant() { - @Override - public String id() { - return "modules"; - } - - @Override - public void shutdown(RuntimeShutdownContext context) { - ModuleManager.shutdownForRuntime(context); - } - }); - ClientRuntime.registerResumeParticipant(new RuntimeResumeParticipant() { - @Override - public String id() { - return "modules"; - } - - @Override - public void resume(String reason) { - ModuleManager.restoreAfterSoftPanic(reason); - } - }); - ClientRuntime.registerParticipant(new RuntimeShutdownParticipant() { - @Override - public String id() { - return "clickgui"; - } - - @Override - public void shutdown(RuntimeShutdownContext context) { - ClickGuiRenderer.shutdownForRuntime(); - } - }); - ClientRuntime.registerParticipant(new RuntimeShutdownParticipant() { - @Override - public String id() { - return "vanilla_chat"; - } - - @Override - public void shutdown(RuntimeShutdownContext context) { - VanillaChatRuntimeCleanup.clearVanillaChatCache(); - context.increment("vanillaChatCleared", 1); - } - }); - ClientRuntime.registerParticipant(new RuntimeShutdownParticipant() { - @Override - public String id() { - return "hud"; - } - - @Override - public void shutdown(RuntimeShutdownContext context) { - if (context.jarReplacement()) { - DraggableHudElementRegistry.clearRuntimeReferences(); - StaticHudElementRegistry.clearRuntimeReferences(); - } - } - }); - ClientRuntime.registerParticipant(new RuntimeShutdownParticipant() { - @Override - public String id() { - return "render"; - } - - @Override - public void shutdown(RuntimeShutdownContext context) { - if (context.jarReplacement()) { - PostProcessManager.shutdownForRuntime(); - CombatantRenderSystem.shutdown(); - } - } - }); - } - private static void renderWorldPhase(WorldPhase phase, com.mojang.blaze3d.vertex.PoseStack matrices, net.minecraft.client.renderer.SubmitNodeCollector consumers) { - if (!RuntimeGate.canRunRender()) return; + if (!Lifecycle.canRunRender()) return; ModuleManager.renderWorld( phase, @@ -172,7 +90,7 @@ public class LoVisual implements ClientModInitializer { } private static void refreshHudFrameTiming(DeltaTracker tickCounter) { - CombatantRenderSystem.updateFrameTiming( + LoVisualRenderSystem.updateFrameTiming( TickDelta.tickProgress(tickCounter, false), TickDelta.frameDeltaTicks(tickCounter), TickDelta.fixedDeltaTicks(tickCounter) @@ -180,7 +98,7 @@ public class LoVisual implements ClientModInitializer { } private static void renderHudPhase(HudPhase phase, GuiGraphicsExtractor ctx, DeltaTracker tickCounter) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; float tickProgress = TickDelta.tickProgress(tickCounter, false); ModuleManager.renderHud(phase, ctx, tickProgress); Renderer2D.Deferred2DLayer layer = deferredLayerForHudPhase(phase); @@ -218,7 +136,7 @@ public class LoVisual implements ClientModInitializer { Renderer2D.withDeferredLayer(layer, () -> { SystemCursor.beginFrame(ctx); - try (RenderPhaseScope hudPhase = CombatantRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:phase:" + phase.name())) { + try (RenderPhaseScope hudPhase = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:phase:" + phase.name())) { // Raw HUD pass if (rawMain) { Renderer2D.COLOR.begin(); @@ -284,7 +202,7 @@ public class LoVisual implements ClientModInitializer { } private static void renderHudAfterHotbar(GuiGraphicsExtractor ctx, DeltaTracker tickCounter) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; boolean swapTooltipWork = SwapTooltip.hasWork(); boolean targetHudWork = DraggableHudElementRegistry.hasEngineWidgetWork("target_hud"); if (!swapTooltipWork && !targetHudWork) return; @@ -299,7 +217,7 @@ public class LoVisual implements ClientModInitializer { Renderer2D.withDeferredLayer(layer, () -> { SystemCursor.beginFrame(ctx); - try (RenderPhaseScope hudPhase = CombatantRenderSystem.phase(RenderPhase.HUD_EFFECTS, "2d:after_hotbar")) { + try (RenderPhaseScope hudPhase = LoVisualRenderSystem.phase(RenderPhase.HUD_EFFECTS, "2d:after_hotbar")) { // Raw pass if (swapTooltipWork) { try (ProfilerPhase.Scope tooltipsScope = ProfilerPhase.scope("2d:after_hotbar:swap_tooltip"); @@ -337,7 +255,7 @@ public class LoVisual implements ClientModInitializer { private static void appendHudDeferredMarker(Renderer2D.Deferred2DLayer layer, GuiGraphicsExtractor ctx) { if (!(ctx instanceof IGuiGraphics graphics)) return; ctx.nextStratum(); - graphics.combatant$addDeferredHudMarker(layer); + graphics.lovisual$addDeferredHudMarker(layer); ctx.nextStratum(); } @@ -372,7 +290,7 @@ public class LoVisual implements ClientModInitializer { @Override public void onInitializeClient() { - CombatantRenderEngineBootstrap.init(); + LoVisualRenderEngineBootstrap.init(); PostProcessManager.register(new NetherPortalRiftPass()); PostProcessManager.register(new SleepOverlayPass()); MainConfig.get(); // Load global settings (debug flag) @@ -419,13 +337,12 @@ public class LoVisual implements ClientModInitializer { ClientTickEvents.START_CLIENT_TICK.register(client -> { if (client.player == null) return; - if (!RuntimeGate.canRunClientLogic()) return; + if (!Lifecycle.isActive()) return; Events.BUS.post(new GameTickEvent()); }); ClientTickEvents.END_CLIENT_TICK.register(client -> { - ModuleManager.tickRuntimeControllers(); - if (!RuntimeGate.canRunClientLogic()) return; + if (!Lifecycle.isActive()) return; if (!ClickGuiRenderer.isBlockingModuleKeybinds()) { ModuleManager.handleModuleKeybinds(); @@ -518,8 +435,7 @@ public class LoVisual implements ClientModInitializer { (ctx, tc) -> renderHudAfterHotbar(ctx, tc) ); - registerRuntimeLifecycle(); - ClientRuntime.markActive("client initialized"); + Lifecycle.activate(); RenderPrewarmManager.prewarm("client initialized"); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonDescriptor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonDescriptor.java index 9bd5a59..0eeedb5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonDescriptor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonDescriptor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonIssue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonIssue.java index e4645dc..4f107e3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonIssue.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonIssue.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonManager.java index af0c427..2463662 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,10 +15,6 @@ import dev.loki.lovisual.features.gui.hud.nondraggable.StaticHudElementRegistry; import dev.loki.lovisual.features.module.Module; import dev.loki.lovisual.features.module.ModuleAutoLoader; import dev.loki.lovisual.features.module.ModuleManager; -import dev.loki.lovisual.runtime.ClientRuntime; -import dev.loki.lovisual.runtime.RuntimeResumeParticipant; -import dev.loki.lovisual.runtime.RuntimeShutdownContext; -import dev.loki.lovisual.runtime.RuntimeShutdownParticipant; import dev.loki.lovisual.util.logging.DebugLog; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.metadata.CustomValue; @@ -34,7 +30,7 @@ import java.util.Map; public enum AddonManager { ; - public static final String ADDON_METADATA_KEY = "combatant:addon"; + public static final String ADDON_METADATA_KEY = "lovisual:addon"; private static final Map ADDONS = new LinkedHashMap<>(); private static final Map ENABLED_OVERRIDES = new LinkedHashMap<>(); @@ -88,32 +84,6 @@ public enum AddonManager { discoverEntrypoints(); } - public static void registerRuntimeLifecycle() { - ClientRuntime.setAddonCounter(AddonManager::activeCount); - ClientRuntime.registerParticipant(new RuntimeShutdownParticipant() { - @Override - public String id() { - return "addons"; - } - - @Override - public void shutdown(RuntimeShutdownContext context) { - suspendForRuntime(context); - } - }); - ClientRuntime.registerResumeParticipant(new RuntimeResumeParticipant() { - @Override - public String id() { - return "addons"; - } - - @Override - public void resume(String reason) { - resumeAfterRuntime(reason); - } - }); - } - public static List snapshots() { init(); return ADDONS.values().stream() @@ -142,7 +112,7 @@ public enum AddonManager { out.addAll(registration.issues); } if (out.isEmpty()) { - out.add(new AddonIssue("combatant", AddonIssue.Severity.INFO, "No addon errors found", "")); + out.add(new AddonIssue("lovisual", AddonIssue.Severity.INFO, "No addon errors found", "")); } return List.copyOf(out); } @@ -349,42 +319,6 @@ public enum AddonManager { return addon; } - private static void suspendForRuntime(RuntimeShutdownContext context) { - int suspended = 0; - for (AddonRegistration registration : ADDONS.values()) { - if (registration.addon == null || registration.status != AddonStatus.ACTIVE) continue; - try { - if (context.jarReplacement()) { - shutdownAddon(registration, context.reason()); - registration.status = AddonStatus.SHUTDOWN; - } else { - registration.addon.onRuntimeSuspended( - new LoVisualAddonRuntimeContextImpl(registration.descriptor.id()) - ); - registration.status = AddonStatus.SUSPENDED; - } - suspended++; - } catch (Throwable t) { - registration.status = AddonStatus.ERROR; - registration.issue(AddonIssue.Severity.ERROR, "Runtime suspend failed", t.toString()); - DebugLog.error("Addon runtime suspend failed: %s", t, registration.descriptor.id()); - } - } - context.increment("addons_suspended", suspended); - } - - private static void resumeAfterRuntime(String reason) { - for (AddonRegistration registration : ADDONS.values()) { - if (registration.addon == null || registration.status != AddonStatus.SUSPENDED || !registration.enabled) { - continue; - } - resumeAddon(registration, reason); - if (registration.status != AddonStatus.ERROR) { - registration.status = AddonStatus.ACTIVE; - } - } - } - private static void suspendAddon(AddonRegistration registration, String reason) { if (registration.addon == null) return; try { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonRegistration.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonRegistration.java index 2cb2cf7..7e98580 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonRegistration.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonRegistration.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonRenderPipelineManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonRenderPipelineManager.java index 67e8751..323d5d2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonRenderPipelineManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonRenderPipelineManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonSnapshot.java index ee410ba..efcc6c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonStateStore.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonStateStore.java index f5afb94..2112003 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonStateStore.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonStateStore.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -53,7 +53,7 @@ final class AddonStateStore { private static Path stateFile() { return FabricLoader.getInstance().getConfigDir() - .resolve("combatant") + .resolve("lovisual") .resolve("addons.json"); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonStatus.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonStatus.java index 28b0c4a..281b63b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonStatus.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/AddonStatus.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ClickGuiSectionManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ClickGuiSectionManager.java index 9a25d4b..d5f1e58 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ClickGuiSectionManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ClickGuiSectionManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualAddonContextImpl.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualAddonContextImpl.java index 8c06fa4..88c3366 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualAddonContextImpl.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualAddonContextImpl.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -22,7 +22,7 @@ import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElement; import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; import dev.loki.lovisual.features.gui.hud.nondraggable.StaticHudElementRegistry; import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; import dev.loki.lovisual.render.iris.patch.ShaderPatchEngine; import net.fabricmc.loader.api.FabricLoader; @@ -149,7 +149,7 @@ final class LoVisualAddonContextImpl implements LoVisualAddonContext { @Override public RenderPipeline registerRenderPipeline(RenderPipeline pipeline) { if (pipeline == null) return null; - RenderPipeline registered = CombatantRenderPipelines.registerAddonPipeline(pipeline); + RenderPipeline registered = LoVisualRenderPipelines.registerAddonPipeline(pipeline); registration.renderCallbacks.add("pipeline:" + pipeline.getLocation()); return registered; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualAddonRuntimeContextImpl.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualAddonRuntimeContextImpl.java index 6679f06..0f5b3bc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualAddonRuntimeContextImpl.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualAddonRuntimeContextImpl.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualModuleLoadContextImpl.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualModuleLoadContextImpl.java index a875d68..750d29d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualModuleLoadContextImpl.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/LoVisualModuleLoadContextImpl.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ModuleExtensionContextImpl.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ModuleExtensionContextImpl.java index bdd8e2a..8aae912 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ModuleExtensionContextImpl.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ModuleExtensionContextImpl.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ModuleExtensionManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ModuleExtensionManager.java index 29decab..516f2d7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ModuleExtensionManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/addon/ModuleExtensionManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddon.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddon.java index d1d0aa5..b50048c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddon.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddon.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,12 +8,12 @@ package dev.loki.lovisual.api.v0.addon; /** - * Fabric entrypoint contract for Combatant addons. + * Fabric entrypoint contract for LoVisual addons. * *

Declare it in fabric.mod.json under the {@value #ENTRYPOINT_KEY} entrypoint. */ public interface LoVisualAddon { - String ENTRYPOINT_KEY = "combatant:addon"; + String ENTRYPOINT_KEY = "lovisual:addon"; int API_VERSION = 0; /** diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddonContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddonContext.java index 35215c4..7426073 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddonContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddonContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddonRuntimeContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddonRuntimeContext.java index 7ac4b80..e057033 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddonRuntimeContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualAddonRuntimeContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualModuleLoadContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualModuleLoadContext.java index 2cd62cf..9dd1fdb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualModuleLoadContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/addon/LoVisualModuleLoadContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import dev.loki.lovisual.events.UsedImplicitly; import dev.loki.lovisual.features.module.Module; /** - * Early addon context used before Combatant's built-in modules are instantiated. + * Early addon context used before LoVisual's built-in modules are instantiated. * *

Only enabled addons receive this callback. Exclusions are startup-only: changing * an addon's enabled state after module discovery requires a client restart for the diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/clickgui/LoVisualClickGuiRenderContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/clickgui/LoVisualClickGuiRenderContext.java index a8db800..53439f1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/clickgui/LoVisualClickGuiRenderContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/clickgui/LoVisualClickGuiRenderContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/clickgui/LoVisualClickGuiSection.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/clickgui/LoVisualClickGuiSection.java index d5f35ff..000a0a4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/clickgui/LoVisualClickGuiSection.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/clickgui/LoVisualClickGuiSection.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/client/LoVisualClientApi.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/client/LoVisualClientApi.java index 4479094..8f63876 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/client/LoVisualClientApi.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/client/LoVisualClientApi.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/module/LoVisualModuleExtension.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/module/LoVisualModuleExtension.java index 8d585cc..3477739 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/module/LoVisualModuleExtension.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/module/LoVisualModuleExtension.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/module/ModuleExtensionContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/module/ModuleExtensionContext.java index 0973931..6103fb8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/module/ModuleExtensionContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/module/ModuleExtensionContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualPostProcessCallback.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualPostProcessCallback.java index e6da276..b3a1752 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualPostProcessCallback.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualPostProcessCallback.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualPostProcessContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualPostProcessContext.java index b32282a..4862f90 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualPostProcessContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualPostProcessContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderCallback.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderCallback.java index 1849f78..ff0f417 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderCallback.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderCallback.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderContext.java index e738981..c07efe8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderPipelineBuilder.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderPipelineBuilder.java index 706c8b6..2a9692e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderPipelineBuilder.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderPipelineBuilder.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import com.mojang.blaze3d.pipeline.BlendFunction; import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.shaders.UniformType; import com.mojang.blaze3d.vertex.VertexFormat; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.pipeline.DepthTestFunction; import dev.loki.lovisual.render.engine.pipeline.ExtendedRenderPipelineBuilder; import dev.loki.lovisual.render.engine.rhi.clip.ShapeClipRenderPassContract; @@ -31,7 +31,7 @@ public final class LoVisualRenderPipelineBuilder { } public static RenderPipeline.Snippet meshUniforms() { - return CombatantRenderPipelines.meshUniforms(); + return LoVisualRenderPipelines.meshUniforms(); } public LoVisualRenderPipelineBuilder location(Identifier id) { @@ -104,6 +104,6 @@ public final class LoVisualRenderPipelineBuilder { } public RenderPipeline buildAndRegister() { - return CombatantRenderPipelines.registerAddonPipeline(build()); + return LoVisualRenderPipelines.registerAddonPipeline(build()); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderStage.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderStage.java index 5a89d0e..1430de7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderStage.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualRenderStage.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualUniforms.java index e3d2c56..02e1b5c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/api/v0/render/LoVisualUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.api.v0.render; import com.mojang.blaze3d.buffers.GpuBufferSlice; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import java.nio.ByteBuffer; @@ -29,7 +29,7 @@ public enum LoVisualUniforms { if (writer == null) { throw new IllegalArgumentException("Uniform writer cannot be null"); } - return CombatantRenderSystem.uniforms().write(name, std140Size, expectedWritesPerFrame, writer::write); + return LoVisualRenderSystem.uniforms().write(name, std140Size, expectedWritesPerFrame, writer::write); } public static GpuBufferSlice writeCached(String name, @@ -47,7 +47,7 @@ public enum LoVisualUniforms { if (writer == null) { throw new IllegalArgumentException("Uniform writer cannot be null"); } - return CombatantRenderSystem.uniforms().writeCached( + return LoVisualRenderSystem.uniforms().writeCached( name, std140Size, expectedWritesPerFrame, @@ -59,12 +59,12 @@ public enum LoVisualUniforms { public static GpuBufferSlice current(String name) { if (name == null || name.isBlank()) return null; - return CombatantRenderSystem.uniforms().current(name); + return LoVisualRenderSystem.uniforms().current(name); } public static void invalidate(String name) { if (name == null || name.isBlank()) return; - CombatantRenderSystem.uniforms().invalidate(name); + LoVisualRenderSystem.uniforms().invalidate(name); } @FunctionalInterface diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroMinimapCompat.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroMinimapCompat.java index 84febeb..5c562cf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroMinimapCompat.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroMinimapCompat.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroState.java index 3926f0b..01e79d7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -19,7 +19,7 @@ public enum TriangulatorXaeroState { ; public static final String NAME = "Stronghold"; public static final String SYMBOL = "S"; - public static final String SET = "combatant"; + public static final String SET = "lovisual"; public static final int DEFAULT_Y = 64; @Nullable diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroWorldMapCompat.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroWorldMapCompat.java index 4db4e95..56fac2a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroWorldMapCompat.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/TriangulatorXaeroWorldMapCompat.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroCommandWaypointCompat.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroCommandWaypointCompat.java index 7ec6ffd..eb8bb44 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroCommandWaypointCompat.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroCommandWaypointCompat.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroWaypointRuntime.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroWaypointRuntime.java index e3ed0b2..32297df 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroWaypointRuntime.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroWaypointRuntime.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroWaypointStore.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroWaypointStore.java index 131b858..d730cce 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroWaypointStore.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/compat/xaero/XaeroWaypointStore.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicLong; public enum XaeroWaypointStore { ; - public static final String SET = "combatant"; + public static final String SET = "lovisual"; public static final String DEFAULT_NAME = "LoVisual"; public static final String DEFAULT_SYMBOL = "C"; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigLang.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigLang.java new file mode 100644 index 0000000..9967a9f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigLang.java @@ -0,0 +1,30 @@ +/* + * 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.config; + +import net.minecraft.client.resources.language.I18n; +import dev.loki.lovisual.config.values.ConfigValue; + +public enum ConfigLang { + ; + + public static String getName(ConfigValue v) { + String key = "config." + v.getName() + ".name"; + return translateOrFallback(key, v.getName()); + } + + public static String getDesc(ConfigValue v) { + String key = "config." + v.getName() + ".desc"; + return translateOrFallback(key, ""); + } + + private static String translateOrFallback(String key, String fallback) { + String translated = I18n.get(key); + return translated.equals(key) ? fallback : translated; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigNameProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigNameProvider.java new file mode 100644 index 0000000..99a3750 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigNameProvider.java @@ -0,0 +1,15 @@ +/* + * 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.config; + +/** + * Optional stable config name override (used for file names). + */ +public interface ConfigNameProvider { + String getConfigName(); +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigObject.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigObject.java new file mode 100644 index 0000000..736997b --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigObject.java @@ -0,0 +1,16 @@ +/* + * 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.config; + +import dev.loki.lovisual.config.values.ConfigValue; + +import java.util.List; + +public interface ConfigObject { + List> getConfigValues(); +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigPaths.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigPaths.java new file mode 100644 index 0000000..18bf02e --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigPaths.java @@ -0,0 +1,29 @@ +/* + * 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.config; + +import java.nio.file.Path; +import java.nio.file.Paths; + +public enum ConfigPaths { + ; + + // TODO: make the user config root configurable, including base directory and visible folder name. + // Keep config/lovisual as the default for compatibility with existing installs. + public static Path root() { + return Paths.get("config", legacyNamespaceName()); + } + + public static Path profilesRoot() { + return root().resolve("profiles"); + } + + public static String legacyNamespaceName() { + return new String(new char[]{'l', 'o', 'v', 'i', 's', 'u', 'a', 'l'}); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigSerializer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigSerializer.java new file mode 100644 index 0000000..eb04ce5 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigSerializer.java @@ -0,0 +1,664 @@ +/* + * 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.config; + +import com.google.gson.*; +import de.marhali.json5.*; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; +import dev.loki.lovisual.config.values.ConfigValue; +import dev.loki.lovisual.features.gui.hud.AbstractHudElement; +import dev.loki.lovisual.features.gui.hud.HudGlobalConfig; +import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElement; +import dev.loki.lovisual.features.module.Module; +import dev.loki.lovisual.features.relations.EntityFilters; +import dev.loki.lovisual.util.logging.DebugLog; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public enum ConfigSerializer { + ; + + private static final Path CONFIG_DIR = ConfigPaths.root(); + private static final long SAVE_DEBOUNCE_MS = 220L; + private static final ScheduledExecutorService SAVE_EXECUTOR = + Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "LoVisual-ConfigSaver"); + t.setDaemon(true); + return t; + }); + private static final Object SAVE_LOCK = new Object(); + private static final Map PENDING_TEXT = new HashMap<>(); + private static final Map> PENDING_TASKS = new HashMap<>(); + private static final Map PENDING_TOKENS = new HashMap<>(); + // One Json5 instance for utilities (player relations, filters, debug config, etc.) + private static final Json5 JSON5 = Json5.builder(builder -> builder + .trailingComma() // allow trailing commas + .indentFactor(2) // pretty output + .quoteSingle() // use " quotes + .build() + ); + // Gson serializer for modules (strict JSON) + private static final Gson GSON = new GsonBuilder() + .setPrettyPrinting() + .disableHtmlEscaping() + .create(); + private static long SAVE_TOKEN_SEQ = 0L; + + // ============================================================= + // Bulk load / save helpers + // ============================================================= + + @SuppressWarnings("unused") // kept for bulk-loading singletons via ClassGraph + public static void loadAll() { + try (ScanResult sc = new ClassGraph() + .enableClassInfo() + .acceptPackages("dev.loki.lovisual") + .scan()) { + + for (ClassInfo ci : sc.getClassesImplementing(ConfigObject.class)) { + Class cls = ci.loadClass(); + ConfigObject inst = singletonConfigObjectFor(cls); + if (inst != null) { + load(inst); + } + } + + } catch (Exception e) { + DebugLog.error("ConfigSerializer.loadAll failed", e); + } + } + + public static void saveAll() { + try (ScanResult sc = new ClassGraph() + .enableClassInfo() + .acceptPackages("dev.loki.lovisual") + .scan()) { + + for (ClassInfo ci : sc.getClassesImplementing(ConfigObject.class)) { + Class cls = ci.loadClass(); + ConfigObject inst = singletonConfigObjectFor(cls); + if (inst != null) { + save(inst); + } + } + + } catch (Exception e) { + DebugLog.error("ConfigSerializer.saveAll failed", e); + } + } + + private static ConfigObject singletonConfigObjectFor(Class cls) throws IllegalAccessException { + if (cls == null) return null; + + for (Field field : cls.getDeclaredFields()) { + if (!Modifier.isStatic(field.getModifiers())) continue; + if (!ConfigObject.class.isAssignableFrom(field.getType())) continue; + + field.setAccessible(true); + Object value = field.get(null); + if (value instanceof ConfigObject configObject) { + return configObject; + } + } + + return null; + } + + // ============================================================= + // Dispatch + // ============================================================= + + public static void save(ConfigObject obj) { + if (obj instanceof HudGlobalConfig) return; + saveNow(obj); + } + + public static void requestSave(ConfigObject obj) { + if (obj == null || obj instanceof HudGlobalConfig) return; + PendingWrite write; + try { + write = buildWrite(obj); + } catch (Exception e) { + DebugLog.error("Failed to serialize config %s", e, fileOf(obj).toAbsolutePath()); + return; + } + if (write == null) return; + + long token; + synchronized (SAVE_LOCK) { + token = ++SAVE_TOKEN_SEQ; + PENDING_TEXT.put(write.path, write.text); + PENDING_TOKENS.put(write.path, token); + + ScheduledFuture prev = PENDING_TASKS.get(write.path); + if (prev != null) prev.cancel(false); + + ScheduledFuture task = SAVE_EXECUTOR.schedule( + () -> flushPending(write.path, token), + SAVE_DEBOUNCE_MS, + TimeUnit.MILLISECONDS + ); + PENDING_TASKS.put(write.path, task); + } + } + + public static void load(ConfigObject obj) { + if (obj instanceof HudGlobalConfig) return; + if (isModule(obj)) { + loadModule(obj); + } else if (isJsonConfig(obj)) { + loadJson(obj); + } else { + loadJson5(obj); + } + } + + private static boolean isModule(ConfigObject obj) { + return obj instanceof Module; + } + + private static boolean isJsonConfig(ConfigObject obj) { + return obj instanceof JsonConfigObject; + } + + private static String configNameOf(ConfigObject obj) { + String name = null; + if (obj instanceof ConfigNameProvider provider) { + name = provider.getConfigName(); + } + if (name == null || name.isBlank()) { + name = obj.getClass().getSimpleName(); + } + return sanitizeConfigName(name); + } + + private static String sanitizeConfigName(String name) { + if (name == null) return "config"; + String base = name.trim().toLowerCase(Locale.ROOT); + if (base.isEmpty()) return "config"; + StringBuilder out = new StringBuilder(base.length()); + for (int i = 0; i < base.length(); i++) { + char c = base.charAt(i); + if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '.') { + out.append(c); + } else { + out.append('_'); + } + } + return out.toString(); + } + + private static Path namedJsonFile(String configName) { + return CONFIG_DIR.resolve(sanitizeConfigName(configName) + ".json"); + } + + private static Path namedJson5File(String configName) { + return CONFIG_DIR.resolve(sanitizeConfigName(configName) + ".json5"); + } + + private static Path moduleFile(ConfigObject obj) { + String category = "uncategorized"; + if (obj instanceof Module module && module.getCategory() != null) { + category = sanitizeConfigName(module.getCategory().name()); + } + return CONFIG_DIR.resolve("modules") + .resolve(category) + .resolve(configNameOf(obj) + ".json"); + } + + private static Path jsonFile(ConfigObject obj) { + if (obj instanceof DraggableHudElement) { + return CONFIG_DIR.resolve("hud") + .resolve("draggable") + .resolve(configNameOf(obj) + ".json"); + } + if (obj instanceof AbstractHudElement) { + return CONFIG_DIR.resolve("hud") + .resolve("nondraggable") + .resolve(configNameOf(obj) + ".json"); + } + return namedJsonFile(configNameOf(obj)); + } + + private static Path utilFile(ConfigObject obj) { + return isJsonConfig(obj) + ? jsonFile(obj) + : namedJson5File(configNameOf(obj)); + } + + private static Path fileOf(ConfigObject obj) { + return isModule(obj) ? moduleFile(obj) : utilFile(obj); + } + + // ============================================================= + // Module (Gson JSON) + // ============================================================= + + private static PendingWrite buildModuleWrite(ConfigObject obj) { + try { + JsonObject root = new JsonObject(); + for (ConfigValue v : obj.getConfigValues()) { + root.add(v.getName(), toJsonElement(v.toJson())); + } + + String text = GSON.toJson(root) + "\n"; + Path out = moduleFile(obj); + return new PendingWrite(out, text); + } catch (Exception e) { + DebugLog.error("Failed to serialize config %s", e, fileOf(obj).toAbsolutePath()); + return null; + } + } + + private static void loadModule(ConfigObject obj) { + try { + Path path = moduleFile(obj); + + if (!Files.exists(path)) { + DebugLog.config("Config defaults created: %s", path.toAbsolutePath()); + save(obj); + return; + } + + DebugLog.config("Config loading: %s", path.toAbsolutePath()); + + String txt = Files.readString(path); + JsonElement parsed = GSON.fromJson(txt, JsonElement.class); + if (!(parsed instanceof JsonObject root)) return; + + Module module = (Module) obj; + + JsonElement legacySettings = root.get("settings"); + if (legacySettings != null) { + module.applyLegacySettings(unwrapJsonElement(legacySettings)); + } + + boolean usedLegacyAlias = false; + for (ConfigValue v : obj.getConfigValues()) { + JsonLookup lookup = findJsonElement(obj, root, v.getName()); + if (lookup.element() != null) { + v.fromJson(unwrapJsonElement(lookup.element())); + usedLegacyAlias |= lookup.alias(); + } + } + + module.syncSettingsAfterLoad(); + if (usedLegacyAlias) { + requestSave(obj); + } + + } catch (Exception e) { + DebugLog.error("Failed to load config %s", e, fileOf(obj).toAbsolutePath()); + } + } + + // ============================================================= + // JSON (Gson) for non-Module configs + // ============================================================= + + private static PendingWrite buildJsonWrite(ConfigObject obj) { + try { + JsonObject root = new JsonObject(); + for (ConfigValue v : obj.getConfigValues()) { + root.add(v.getName(), toJsonElement(v.toJson())); + } + + String text = GSON.toJson(root) + "\n"; + Path out = jsonFile(obj); + return new PendingWrite(out, text); + } catch (Exception e) { + DebugLog.error("Failed to serialize config %s", e, fileOf(obj).toAbsolutePath()); + return null; + } + } + + private static void loadJson(ConfigObject obj) { + try { + Path path = jsonFile(obj); + if (!Files.exists(path)) { + DebugLog.config("Config defaults created: %s", path.toAbsolutePath()); + save(obj); + return; + } + + DebugLog.config("Config loading: %s", path.toAbsolutePath()); + + String txt = Files.readString(path); + JsonElement parsed = GSON.fromJson(txt, JsonElement.class); + if (!(parsed instanceof JsonObject root)) return; + + boolean missing = false; + boolean usedLegacyAlias = false; + for (ConfigValue v : obj.getConfigValues()) { + JsonLookup lookup = findJsonElement(obj, root, v.getName()); + if (lookup.element() != null) { + v.fromJson(unwrapJsonElement(lookup.element())); + usedLegacyAlias |= lookup.alias(); + } else { + missing = true; + } + } + + if (missing || usedLegacyAlias) { + requestSave(obj); + } + + } catch (Exception e) { + DebugLog.error("Failed to load config %s", e, fileOf(obj).toAbsolutePath()); + } + } + + // ============================================================= + // Utilities (Json5) + // ============================================================= + + private static PendingWrite buildJson5Write(ConfigObject obj) { + try { + Json5Object root = new Json5Object(); + + for (ConfigValue v : obj.getConfigValues()) { + Object raw = v.toJson(); + root.add(v.getName(), toJson5Element(raw)); + } + + String text = JSON5.serialize(root); + + String sb = text + "\n"; + + Path out = utilFile(obj); + if (obj instanceof EntityFilters) { + DebugLog.config("[EntityFilters][SAVE] to=%s data=%s", out.toAbsolutePath(), text); + } + return new PendingWrite(out, sb); + } catch (Exception e) { + DebugLog.error("Failed to serialize config %s", e, fileOf(obj).toAbsolutePath()); + return null; + } + } + + private static void loadJson5(ConfigObject obj) { + try { + Path path = utilFile(obj); + if (!Files.exists(path)) { + DebugLog.config("Config defaults created: %s", path.toAbsolutePath()); + save(obj); + return; + } + + DebugLog.config("Config loading: %s", path.toAbsolutePath()); + + String txt = Files.readString(path); + Json5Element parsed = JSON5.parse(txt); + + if (!(parsed instanceof Json5Object root)) { + return; + } + + Map map = root.asMap(); + + boolean missing = false; + boolean usedLegacyAlias = false; + for (ConfigValue v : obj.getConfigValues()) { + Json5Lookup lookup = findJson5Element(obj, map, v.getName()); + if (lookup.element() != null) { + v.fromJson(unwrapJson5(lookup.element())); + usedLegacyAlias |= lookup.alias(); + } else { + missing = true; + } + } + + if (obj instanceof Module module) { + module.syncSettingsAfterLoad(); + } + if (missing || usedLegacyAlias) { + requestSave(obj); + } + + } catch (Exception e) { + DebugLog.error("Failed to load config %s", e, fileOf(obj).toAbsolutePath()); + } + } + + + private static JsonLookup findJsonElement(ConfigObject obj, JsonObject root, String valueName) { + if (root == null || valueName == null) return JsonLookup.missing(); + JsonElement direct = root.get(valueName); + if (direct != null && !direct.isJsonNull()) { + return new JsonLookup(direct, false); + } + if (obj instanceof ConfigValueAliasProvider provider) { + List aliases = provider.getLegacyValueNames(valueName); + if (aliases != null) { + for (String alias : aliases) { + if (alias == null || alias.isBlank()) continue; + JsonElement legacy = root.get(alias); + if (legacy != null && !legacy.isJsonNull()) { + return new JsonLookup(legacy, true); + } + } + } + } + return JsonLookup.missing(); + } + + private static Json5Lookup findJson5Element(ConfigObject obj, Map map, String valueName) { + if (map == null || valueName == null) return Json5Lookup.missing(); + Json5Element direct = map.get(valueName); + if (direct != null) { + return new Json5Lookup(direct, false); + } + if (obj instanceof ConfigValueAliasProvider provider) { + List aliases = provider.getLegacyValueNames(valueName); + if (aliases != null) { + for (String alias : aliases) { + if (alias == null || alias.isBlank()) continue; + Json5Element legacy = map.get(alias); + if (legacy != null) { + return new Json5Lookup(legacy, true); + } + } + } + } + return Json5Lookup.missing(); + } + + private static JsonElement toJsonElement(Object v) { + if (v == null) return JsonNull.INSTANCE; + if (v instanceof JsonElement el) return el; + if (v instanceof Boolean b) return new JsonPrimitive(b); + if (v instanceof Number n) return new JsonPrimitive(n); + if (v instanceof CharSequence s) return new JsonPrimitive(s.toString()); + if (v instanceof Map map) { + JsonObject obj = new JsonObject(); + for (var e : map.entrySet()) { + obj.add(String.valueOf(e.getKey()), toJsonElement(e.getValue())); + } + return obj; + } + if (v instanceof Iterable it) { + JsonArray arr = new JsonArray(); + for (Object el : it) arr.add(toJsonElement(el)); + return arr; + } + return new JsonPrimitive(String.valueOf(v)); + } + + private static Json5Element toJson5Element(Object v) { + if (v == null) { + return Json5Primitive.fromNull(); + } + if (v instanceof Json5Element el) { + return el; + } + if (v instanceof Boolean b) { + return Json5Primitive.fromBoolean(b); + } + if (v instanceof Number n) { + return Json5Primitive.fromNumber(n); + } + if (v instanceof CharSequence s) { + return Json5Primitive.fromString(s.toString()); + } + if (v instanceof Map map) { + Json5Object obj = new Json5Object(); + for (var e : map.entrySet()) { + String key = String.valueOf(e.getKey()); + obj.add(key, toJson5Element(e.getValue())); + } + return obj; + } + if (v instanceof Iterable it) { + Json5Array arr = new Json5Array(); + for (Object el : it) { + arr.add(toJson5Element(el)); + } + return arr; + } + + return Json5Primitive.fromString(String.valueOf(v)); + } + + // ============================================================= + // Helpers + // ============================================================= + + private static Object unwrapJsonElement(JsonElement el) { + if (el == null || el.isJsonNull()) return null; + if (el.isJsonPrimitive()) { + JsonPrimitive p = el.getAsJsonPrimitive(); + if (p.isBoolean()) return p.getAsBoolean(); + if (p.isNumber()) return p.getAsNumber(); + return p.getAsString(); + } + if (el.isJsonArray()) { + List out = new ArrayList<>(); + for (JsonElement child : el.getAsJsonArray()) { + out.add(unwrapJsonElement(child)); + } + return out; + } + if (el.isJsonObject()) { + Map out = new LinkedHashMap<>(); + for (var e : el.getAsJsonObject().entrySet()) { + out.put(e.getKey(), unwrapJsonElement(e.getValue())); + } + return out; + } + return null; + } + + private static Object unwrapJson5(Json5Element el) { + if (el == null || el.isJson5Null()) return null; + if (el.isJson5Primitive()) { + Json5Primitive p = el.getAsJson5Primitive(); + if (p.isBoolean()) return p.getAsBoolean(); + if (p.isNumber()) return p.getAsNumber(); + return p.getAsString(); + } + if (el.isJson5Array()) { + List out = new ArrayList<>(); + for (Json5Element child : el.getAsJson5Array()) { + out.add(unwrapJson5(child)); + } + return out; + } + if (el.isJson5Object()) { + Map out = new LinkedHashMap<>(); + for (var e : el.getAsJson5Object().asMap().entrySet()) { + out.put(e.getKey(), unwrapJson5(e.getValue())); + } + return out; + } + return null; + } + + private static PendingWrite buildWrite(ConfigObject obj) { + if (obj == null) return null; + if (isModule(obj)) return buildModuleWrite(obj); + if (isJsonConfig(obj)) return buildJsonWrite(obj); + return buildJson5Write(obj); + } + + private static void saveNow(ConfigObject obj) { + PendingWrite write; + try { + write = buildWrite(obj); + } catch (Exception e) { + DebugLog.error("Failed to serialize config %s", e, fileOf(obj).toAbsolutePath()); + return; + } + if (write == null) return; + clearPending(write.path); + writeConfig(write.path, write.text); + } + + // ============================================================= + // Async write helpers + // ============================================================= + + private static void flushPending(Path path, long token) { + String text; + synchronized (SAVE_LOCK) { + Long current = PENDING_TOKENS.get(path); + if (current == null || current != token) return; + text = PENDING_TEXT.remove(path); + PENDING_TOKENS.remove(path); + PENDING_TASKS.remove(path); + } + if (text != null) { + writeConfig(path, text); + } + } + + private static void clearPending(Path path) { + synchronized (SAVE_LOCK) { + ScheduledFuture prev = PENDING_TASKS.remove(path); + if (prev != null) prev.cancel(false); + PENDING_TEXT.remove(path); + PENDING_TOKENS.remove(path); + } + } + + private static void writeConfig(Path out, String text) { + try { + Path parent = out.getParent(); + Files.createDirectories(parent != null ? parent : CONFIG_DIR); + Files.writeString(out, text); + DebugLog.config("Config saved: %s", out.toAbsolutePath()); + } catch (IOException e) { + DebugLog.error("Failed to save config %s", e, out.toAbsolutePath()); + } + } + + private record JsonLookup(JsonElement element, boolean alias) { + static JsonLookup missing() { + return new JsonLookup(null, false); + } + } + + private record Json5Lookup(Json5Element element, boolean alias) { + static Json5Lookup missing() { + return new Json5Lookup(null, false); + } + } + + private record PendingWrite(Path path, String text) { + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigValueAliasProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigValueAliasProvider.java new file mode 100644 index 0000000..1bf644a --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/ConfigValueAliasProvider.java @@ -0,0 +1,14 @@ +/* + * 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.config; + +import java.util.List; + +public interface ConfigValueAliasProvider { + List getLegacyValueNames(String currentValueName); +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/DisableSettingI18n.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/DisableSettingI18n.java new file mode 100644 index 0000000..dce4cfe --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/DisableSettingI18n.java @@ -0,0 +1,25 @@ +/* + * 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.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Opts a setting out of i18n lookup. Use this for user/content values where raw ids + * are the intended labels, for example selectable sound ids. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface DisableSettingI18n { + boolean name() default true; + + boolean options() default true; +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/JsonConfigObject.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/JsonConfigObject.java new file mode 100644 index 0000000..edb4ae1 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/JsonConfigObject.java @@ -0,0 +1,14 @@ +/* + * 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.config; + +/** + * Marker for config objects that must be stored as JSON (not JSON5). + */ +public interface JsonConfigObject extends ConfigObject { +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/MainConfig.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/MainConfig.java new file mode 100644 index 0000000..9df85f2 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/MainConfig.java @@ -0,0 +1,477 @@ +/* + * 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.config; + +import dev.loki.lovisual.config.values.*; +import dev.loki.lovisual.config.values.*; +import dev.loki.lovisual.render.iris.IrisRuntime; +import dev.loki.lovisual.util.logging.DebugLog; +import dev.loki.lovisual.util.logging.DebugMode; +import dev.loki.lovisual.util.player.inventory.InventorySearchScope; +import dev.loki.lovisual.util.player.inventory.InventorySwap; +import dev.loki.lovisual.util.player.inventory.InventorySwapPolicy; +import dev.loki.lovisual.util.player.inventory.InventorySwapVisibility; +import net.minecraft.client.resources.language.I18n; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +public final class MainConfig implements ConfigObject, ConfigNameProvider, SettingOwner { + + public static final MainConfig INSTANCE = new MainConfig(); + private static final String IRIS_MSAA_REASON_KEY = "setting.main_config.msaa3d.iris_blocked"; + private static final String IRIS_MSAA_REASON_FALLBACK = "Iris shaderpack pipeline is active."; + + //@CFGComment("Debug logging mode: off / error_only / error_and_warnings / info / config / render_thread / stencil / serverdebug / all") + private final ModeValue debug = + new ModeValue("debug", "off", "off", "error_only", "error_and_warnings", "info", "config", "render_thread", "stencil", "serverdebug", "all"); + + //@CFGComment("Force PvP mode ON everywhere (dev/testing only)") + private final BooleanValue forcePvp = + new BooleanValue("forcePvp", false); + + //@CFGComment("Menu background shader: off / waves / aurora") + private final ModeValue menuBg = + new ModeValue("menuBg", "off", "off", "waves", "aurora"); + + //@CFGComment("Use ClickGUI theme colors for menu background shader") + private final BooleanValue menuBgUseTheme = + new BooleanValue("menuBgUseTheme", false); + + //@CFGComment("Show seconds in the custom main menu clock") + private final BooleanValue menuClockShowSeconds = + new BooleanValue("menuClockShowSeconds", false); + + //@CFGComment("MSAA for world render: off / 2x / 4x") + private final ModeValue msaa3d = + new ModeValue("msaa3d", "off", "off", "2x", "4x"); + + //@CFGComment("Show ClickGUI modules hotkey hints") + private final BooleanValue clickGuiModulesHints = + new BooleanValue("clickGuiModulesHints", true); + + //@CFGComment("Show ClickGUI HUD editor hotkey hints") + private final BooleanValue clickGuiHudEditorHints = + new BooleanValue("clickGuiHudEditorHints", true); + + //@CFGComment("Default inventory swap safety policy: none / grim_strict / legit") + private final EnumValue inventorySwapPolicy = + new EnumValue<>("inventorySwapPolicy", InventorySwapPolicy.NONE, InventorySwapPolicy.class); + + //@CFGComment("Default inventory swap search scope: hotbar / inventory / full") + private final EnumValue inventorySwapScope = + new EnumValue<>("inventorySwapScope", InventorySearchScope.FULL, InventorySearchScope.class); + + //@CFGComment("Default inventory swap visibility: normal / silent") + private final EnumValue inventorySwapVisibility = + new EnumValue<>("inventorySwapVisibility", InventorySwapVisibility.SILENT, InventorySwapVisibility.class); + + //@CFGComment("Restore the original hotbar slot after default swap requests") + private final BooleanValue inventorySwapRestore = + new BooleanValue("inventorySwapRestore", true); + + //@CFGComment("Prefer hotbar matches before inventory matches for full-scope swap requests") + private final BooleanValue inventorySwapPreferHotbar = + new BooleanValue("inventorySwapPreferHotbar", true); + + //@CFGComment("Extra delay before queued legit inventory swap actions") + private final NumberValue inventorySwapLegitWaitTicks = + new NumberValue<>("inventorySwapLegitWaitTicks", 2, 0, 20); + + // @CFGComment("Extra delay before queued Grim-strict inventory click/close actions") + private final NumberValue inventorySwapStrictInventoryWaitTicks = + new NumberValue<>("inventorySwapStrictInventoryWaitTicks", 1, 0, 20); + + //@CFGComment("Movement input lock duration while waiting for Grim-strict inventory actions") + private final NumberValue inventorySwapStrictMovementLockTicks = + new NumberValue<>("inventorySwapStrictMovementLockTicks", 2, 0, 20); + + //@CFGComment("Hard-disable narrator and narrator hotkey") + private final BooleanValue disableNarrator = + new BooleanValue("disableNarrator", true); + + //@CFGComment("Always-on backdoor protection master switch") + private final BooleanValue backdoorProtection = + new BooleanValue("backdoorProtection", true); + + //@CFGComment("Filter non-whitelisted translation keys in server-controlled sign/anvil text") + private final BooleanValue backdoorTranslationFilter = + new BooleanValue("backdoorTranslationFilter", true); + + //@CFGComment("Filter non-vanilla keybind text keys in server-controlled text") + private final BooleanValue backdoorKeybindFilter = + new BooleanValue("backdoorKeybindFilter", true); + + //@CFGComment("Block remote servers from redirecting resource-pack downloads into local/private network addresses") + private final BooleanValue backdoorLocalHttpGuard = + new BooleanValue("backdoorLocalHttpGuard", true); + + //@CFGComment("Isolate downloaded server-pack cache by account UUID to reduce pack-cache fingerprinting") + private final BooleanValue backdoorPackCacheIsolation = + new BooleanValue("backdoorPackCacheIsolation", true); + + //@CFGComment("Allow local/private HTTP requests when connected to local/integrated server") + private final BooleanValue backdoorAllowLocalHttpWhenServerLocal = + new BooleanValue("backdoorAllowLocalHttpWhenServerLocal", true); + + //@CFGComment("Extra allowed translation resource-pack ids for server-controlled text") + private final SetValue backdoorAllowedTranslationPacks = + new SetValue("backdoorAllowedTranslationPacks", defaultAllowedTranslationPacks()); + + //@CFGComment("Extra allowed keybind ids for server-controlled text") + private final SetValue backdoorAllowedKeybinds = + new SetValue("backdoorAllowedKeybinds"); + + private MainConfig() { + ConfigSerializer.load(this); + applyDebugMode(); + applyInventorySwapSettings(); + } + + public static MainConfig get() { + return INSTANCE; + } + + private static Set defaultAllowedTranslationPacks() { + LinkedHashSet out = new LinkedHashSet<>(); + out.add("vanilla"); + return out; + } + + @Override + public String getConfigName() { + return "mainconfig"; + } + + @Override + public String name() { + return "main_config"; + } + + // ================= DEBUG ================= + + @Override + public void saveConfig() { + applyDebugMode(); + applyInventorySwapSettings(); + ConfigSerializer.requestSave(this); + } + + public DebugMode getDebugMode() { + try { + return DebugMode.valueOf(debug.get().toUpperCase()); + } catch (IllegalArgumentException e) { + return DebugMode.OFF; + } + } + + public void setDebugMode(DebugMode mode) { + if (mode == null) mode = DebugMode.OFF; + debug.set(mode.name().toLowerCase()); + applyDebugMode(); + ConfigSerializer.requestSave(this); + } + + private void applyDebugMode() { + DebugLog.setMode(getDebugMode()); + } + + public boolean isForcePvp() { + return forcePvp.get(); + } + + public String getMenuBackgroundMode() { + return menuBg.get(); + } + + public boolean isMenuBackgroundUseTheme() { + return menuBgUseTheme.get(); + } + + public boolean isMenuClockShowSeconds() { + return menuClockShowSeconds.get(); + } + + public int getMsaa3dSamples() { + if (IrisRuntime.isShaderpackRendererActive()) return 0; + String v = msaa3d.get(); + if (v == null) return 0; + if (v.equalsIgnoreCase("2x")) return 2; + if (v.equalsIgnoreCase("4x")) return 4; + return 0; + } + + public boolean isClickGuiModulesHintsEnabled() { + return clickGuiModulesHints.get(); + } + + public boolean isClickGuiHintsEnabled() { + return clickGuiModulesHints.get(); + } + + public void setClickGuiModulesHintsEnabled(boolean enabled) { + clickGuiModulesHints.set(enabled); + ConfigSerializer.requestSave(this); + } + + public void setClickGuiHintsEnabled(boolean enabled) { + setClickGuiModulesHintsEnabled(enabled); + } + + public boolean isClickGuiHudEditorHintsEnabled() { + return clickGuiHudEditorHints.get(); + } + + public void setClickGuiHudEditorHintsEnabled(boolean enabled) { + clickGuiHudEditorHints.set(enabled); + ConfigSerializer.requestSave(this); + } + + public InventorySwapPolicy getInventorySwapPolicy() { + return inventorySwapPolicy.get(); + } + + public void setInventorySwapPolicy(InventorySwapPolicy policy) { + inventorySwapPolicy.set(policy != null ? policy : InventorySwapPolicy.NONE); + saveAndApplyInventorySwapSettings(); + } + + public InventorySearchScope getInventorySwapScope() { + return inventorySwapScope.get(); + } + + public void setInventorySwapScope(InventorySearchScope scope) { + inventorySwapScope.set(scope != null ? scope : InventorySearchScope.FULL); + saveAndApplyInventorySwapSettings(); + } + + public InventorySwapVisibility getInventorySwapVisibility() { + return inventorySwapVisibility.get(); + } + + public void setInventorySwapVisibility(InventorySwapVisibility visibility) { + inventorySwapVisibility.set(visibility != null ? visibility : InventorySwapVisibility.SILENT); + saveAndApplyInventorySwapSettings(); + } + + public boolean isInventorySwapRestore() { + return inventorySwapRestore.get(); + } + + public void setInventorySwapRestore(boolean restore) { + inventorySwapRestore.set(restore); + saveAndApplyInventorySwapSettings(); + } + + public boolean isInventorySwapPreferHotbar() { + return inventorySwapPreferHotbar.get(); + } + + public void setInventorySwapPreferHotbar(boolean preferHotbar) { + inventorySwapPreferHotbar.set(preferHotbar); + saveAndApplyInventorySwapSettings(); + } + + public int getInventorySwapLegitWaitTicks() { + return inventorySwapLegitWaitTicks.get(); + } + + public void setInventorySwapLegitWaitTicks(int ticks) { + inventorySwapLegitWaitTicks.fromJson(ticks); + saveAndApplyInventorySwapSettings(); + } + + public int getInventorySwapStrictInventoryWaitTicks() { + return inventorySwapStrictInventoryWaitTicks.get(); + } + + public void setInventorySwapStrictInventoryWaitTicks(int ticks) { + inventorySwapStrictInventoryWaitTicks.fromJson(ticks); + saveAndApplyInventorySwapSettings(); + } + + public int getInventorySwapStrictMovementLockTicks() { + return inventorySwapStrictMovementLockTicks.get(); + } + + public void setInventorySwapStrictMovementLockTicks(int ticks) { + inventorySwapStrictMovementLockTicks.fromJson(ticks); + saveAndApplyInventorySwapSettings(); + } + + public EnumValue inventorySwapPolicyValue() { + return inventorySwapPolicy; + } + + public EnumValue inventorySwapScopeValue() { + return inventorySwapScope; + } + + public EnumValue inventorySwapVisibilityValue() { + return inventorySwapVisibility; + } + + public BooleanValue inventorySwapRestoreValue() { + return inventorySwapRestore; + } + + public BooleanValue inventorySwapPreferHotbarValue() { + return inventorySwapPreferHotbar; + } + + public NumberValue inventorySwapLegitWaitTicksValue() { + return inventorySwapLegitWaitTicks; + } + + public NumberValue inventorySwapStrictInventoryWaitTicksValue() { + return inventorySwapStrictInventoryWaitTicks; + } + + public NumberValue inventorySwapStrictMovementLockTicksValue() { + return inventorySwapStrictMovementLockTicks; + } + + public List getImageSettingDefs() { + List list = new ArrayList<>(); + list.add(SettingDef.mode(msaa3d) + .unavailableWhen(IrisRuntime::isShaderpackRendererActive, MainConfig::irisMsaaReason)); + list.add(SettingDef.mode(menuBg)); + list.add(SettingDef.bool(menuClockShowSeconds)); + list.add(SettingDef.bool(menuBgUseTheme)); + return list; + } + + private static String irisMsaaReason() { + String translated = I18n.get(IRIS_MSAA_REASON_KEY); + return IRIS_MSAA_REASON_KEY.equals(translated) ? IRIS_MSAA_REASON_FALLBACK : translated; + } + + public List getMiscellaneousSettingDefs() { + List list = new ArrayList<>(); + list.add(SettingDef.mode(debug)); + list.add(SettingDef.bool(forcePvp)); + list.add(SettingDef.bool(disableNarrator)); + return list; + } + + public List getSecuritySettingDefs() { + List list = new ArrayList<>(); + list.add(SettingDef.bool(backdoorProtection)); + list.add(SettingDef.bool(backdoorTranslationFilter).visibleWhen(backdoorProtection::get)); + list.add(SettingDef.bool(backdoorKeybindFilter).visibleWhen(backdoorProtection::get)); + list.add(SettingDef.bool(backdoorLocalHttpGuard).visibleWhen(backdoorProtection::get)); + list.add(SettingDef.bool(backdoorPackCacheIsolation).visibleWhen(backdoorProtection::get)); + list.add(SettingDef.bool(backdoorAllowLocalHttpWhenServerLocal).visibleWhen(backdoorProtection::get)); + list.add(SettingDef.textList(backdoorAllowedTranslationPacks) + .visibleWhen(() -> backdoorProtection.get() && backdoorTranslationFilter.get())); + list.add(SettingDef.textList(backdoorAllowedKeybinds) + .visibleWhen(() -> backdoorProtection.get() && backdoorKeybindFilter.get())); + return list; + } + + public List getUtilitySettingDefs() { + List list = new ArrayList<>(); + list.add(SettingDef.mode(inventorySwapPolicy).common("inventory.swap_policy")); + list.add(SettingDef.mode(inventorySwapScope).common("inventory.search_scope")); + list.add(SettingDef.mode(inventorySwapVisibility).common("inventory.swap_visibility")); + list.add(SettingDef.bool(inventorySwapRestore).common("inventory.restore_item")); + list.add(SettingDef.bool(inventorySwapPreferHotbar).common("inventory.prefer_hotbar")); + list.add(SettingDef.number(inventorySwapLegitWaitTicks).common("inventory.legit_wait_ticks")); + list.add(SettingDef.number(inventorySwapStrictInventoryWaitTicks).common("inventory.strict_inventory_wait_ticks")); + list.add(SettingDef.number(inventorySwapStrictMovementLockTicks).common("inventory.strict_movement_lock_ticks")); + return list; + } + + public boolean isNarratorDisabled() { + return disableNarrator.get(); + } + + public boolean isBackdoorProtectionEnabled() { + return backdoorProtection.get(); + } + + public boolean isBackdoorTranslationFilterEnabled() { + return backdoorProtection.get() && backdoorTranslationFilter.get(); + } + + public boolean isBackdoorKeybindFilterEnabled() { + return backdoorProtection.get() && backdoorKeybindFilter.get(); + } + + public boolean isBackdoorLocalHttpGuardEnabled() { + return backdoorProtection.get() && backdoorLocalHttpGuard.get(); + } + + public boolean isBackdoorPackCacheIsolationEnabled() { + return backdoorProtection.get() && backdoorPackCacheIsolation.get(); + } + + public boolean isBackdoorAllowLocalHttpWhenServerLocal() { + return backdoorAllowLocalHttpWhenServerLocal.get(); + } + + public Set getBackdoorAllowedTranslationPacks() { + return new LinkedHashSet<>(backdoorAllowedTranslationPacks.get()); + } + + // ================= CONFIG ================= + + public Set getBackdoorAllowedKeybinds() { + return new LinkedHashSet<>(backdoorAllowedKeybinds.get()); + } + + @Override + public List> getConfigValues() { + List> list = new ArrayList<>(); + list.add(debug); + list.add(forcePvp); + list.add(menuBg); + list.add(menuClockShowSeconds); + list.add(menuBgUseTheme); + list.add(msaa3d); + list.add(clickGuiModulesHints); + list.add(clickGuiHudEditorHints); + list.add(inventorySwapPolicy); + list.add(inventorySwapScope); + list.add(inventorySwapVisibility); + list.add(inventorySwapRestore); + list.add(inventorySwapPreferHotbar); + list.add(inventorySwapLegitWaitTicks); + list.add(inventorySwapStrictInventoryWaitTicks); + list.add(inventorySwapStrictMovementLockTicks); + list.add(disableNarrator); + list.add(backdoorProtection); + list.add(backdoorTranslationFilter); + list.add(backdoorKeybindFilter); + list.add(backdoorLocalHttpGuard); + list.add(backdoorPackCacheIsolation); + list.add(backdoorAllowLocalHttpWhenServerLocal); + list.add(backdoorAllowedTranslationPacks); + list.add(backdoorAllowedKeybinds); + return list; + } + + private void saveAndApplyInventorySwapSettings() { + applyInventorySwapSettings(); + ConfigSerializer.requestSave(this); + } + + private void applyInventorySwapSettings() { + InventorySwap swap = InventorySwap.INSTANCE; + swap.setDefaultPolicy(inventorySwapPolicy.get()); + swap.setDefaultScope(inventorySwapScope.get()); + swap.setDefaultVisibility(inventorySwapVisibility.get()); + swap.setRestoreByDefault(inventorySwapRestore.get()); + swap.setPreferHotbar(inventorySwapPreferHotbar.get()); + swap.setLegitWaitTicks(inventorySwapLegitWaitTicks.get()); + swap.setStrictInventoryWaitTicks(inventorySwapStrictInventoryWaitTicks.get()); + swap.setStrictMovementLockTicks(inventorySwapStrictMovementLockTicks.get()); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingDef.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingDef.java new file mode 100644 index 0000000..547cfa0 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingDef.java @@ -0,0 +1,371 @@ +/* + * 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.config; + +import dev.loki.lovisual.config.common.CommonSettingSchema; +import dev.loki.lovisual.config.values.*; +import dev.loki.lovisual.features.gui.clickgui.settings.TextListSetting; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +/** + * GUI-neutral setting descriptor. UI layer can build actual widgets from these. + */ +public final class SettingDef { + + private final Kind kind; + private final String id; + private final ConfigValue value; + private final BindMode bindMode; + private final TextListSetting.PickerMode pickerMode; + private Supplier visibility; + private Supplier unavailableReason; + private final List commonI18nKeys = new ArrayList<>(); + private boolean i18nNameEnabled = true; + private boolean i18nOptionsEnabled = true; + private SettingDef(Kind kind, String id, ConfigValue value) { + this(kind, id, value, null, null); + } + + private SettingDef(Kind kind, String id, ConfigValue value, BindMode bindMode) { + this(kind, id, value, bindMode, null); + } + + private SettingDef(Kind kind, + String id, + ConfigValue value, + BindMode bindMode, + TextListSetting.PickerMode pickerMode) { + this.kind = kind; + this.id = id; + this.value = value; + this.bindMode = bindMode; + this.pickerMode = pickerMode; + } + + public static SettingDef bool(String id, BooleanValue value) { + return new SettingDef(Kind.BOOLEAN, id, value); + } + + public static SettingDef bool(BooleanValue value) { + return new SettingDef(Kind.BOOLEAN, value.getName(), value); + } + + public static SettingDef number(String id, NumberValue value) { + return new SettingDef(Kind.NUMBER, id, value); + } + + public static SettingDef number(NumberValue value) { + return new SettingDef(Kind.NUMBER, value.getName(), value); + } + + public static SettingDef mode(String id, ModeValue value) { + return new SettingDef(Kind.MODE, id, value); + } + + public static SettingDef mode(String id, EnumValue value) { + return new SettingDef(Kind.MODE, id, value); + } + + public static SettingDef mode(ModeValue value) { + return new SettingDef(Kind.MODE, value.getName(), value); + } + + public static SettingDef mode(EnumValue value) { + return new SettingDef(Kind.MODE, value.getName(), value); + } + + public static SettingDef color(String id, RGBAColorValue value) { + return new SettingDef(Kind.COLOR, id, value); + } + + public static SettingDef color(RGBAColorValue value) { + return new SettingDef(Kind.COLOR, value.getName(), value); + } + + public static SettingDef colorNoAlpha(String id, RGBColorValue value) { + return new SettingDef(Kind.COLOR_NO_ALPHA, id, value); + } + + public static SettingDef colorNoAlpha(RGBColorValue value) { + return new SettingDef(Kind.COLOR_NO_ALPHA, value.getName(), value); + } + + public static SettingDef text(String id, StringValue value) { + return new SettingDef(Kind.TEXT, id, value); + } + + public static SettingDef text(StringValue value) { + return new SettingDef(Kind.TEXT, value.getName(), value); + } + + public static SettingDef textList(String id, SetValue value) { + return new SettingDef(Kind.TEXT_LIST, id, value); + } + + public static SettingDef textList(String id, + SetValue value, + TextListSetting.PickerMode pickerMode) { + return new SettingDef(Kind.TEXT_LIST, id, value, null, pickerMode); + } + + public static SettingDef textList(SetValue value) { + return new SettingDef(Kind.TEXT_LIST, value.getName(), value); + } + + public static SettingDef textList(SetValue value, + TextListSetting.PickerMode pickerMode) { + return new SettingDef(Kind.TEXT_LIST, value.getName(), value, null, pickerMode); + } + + public static SettingDef textList(String id, ItemIdSetValue value) { + return new SettingDef(Kind.TEXT_LIST, id, value); + } + + public static SettingDef textList(String id, + ItemIdSetValue value, + TextListSetting.PickerMode pickerMode) { + return new SettingDef(Kind.TEXT_LIST, id, value, null, pickerMode); + } + + public static SettingDef textList(ItemIdSetValue value) { + return new SettingDef(Kind.TEXT_LIST, value.getName(), value); + } + + public static SettingDef textList(ItemIdSetValue value, + TextListSetting.PickerMode pickerMode) { + return new SettingDef(Kind.TEXT_LIST, value.getName(), value, null, pickerMode); + } + + public static SettingDef cooldownRules(String id, ItemCooldownRulesValue value) { + return new SettingDef(Kind.COOLDOWN_RULES, id, value); + } + + public static SettingDef cooldownRules(ItemCooldownRulesValue value) { + return new SettingDef(Kind.COOLDOWN_RULES, value.getName(), value); + } + + public static SettingDef protocolHeuristics(String id, BooleanMapValue value) { + return new SettingDef(Kind.PROTOCOL_HEURISTICS, id, value); + } + + public static SettingDef protocolHeuristics(BooleanMapValue value) { + return new SettingDef(Kind.PROTOCOL_HEURISTICS, value.getName(), value); + } + + public static SettingDef group(String id, BooleanMapValue value) { + return new SettingDef(Kind.GROUP, id, value); + } + + public static SettingDef group(BooleanMapValue value) { + return new SettingDef(Kind.GROUP, value.getName(), value); + } + + public static SettingDef bind(String id, KeyBindValue value, BindMode mode) { + return new SettingDef(Kind.BIND, id, value, mode); + } + + public static SettingDef bind(KeyBindValue value, BindMode mode) { + return new SettingDef(Kind.BIND, value.getName(), value, mode); + } + + public static SettingDef bind(String id, KeyBindValue value) { + return new SettingDef(Kind.BIND, id, value, BindMode.PRESS); + } + + public static SettingDef bind(KeyBindValue value) { + return new SettingDef(Kind.BIND, value.getName(), value, BindMode.PRESS); + } + + public static void applyI18nAnnotations(Object owner, Iterable defs) { + if (owner == null || defs == null) return; + + Map, SettingDef> defsByValue = new IdentityHashMap<>(); + for (SettingDef def : defs) { + if (def != null && def.value() != null) { + defsByValue.put(def.value(), def); + } + } + if (defsByValue.isEmpty()) return; + + Class type = owner.getClass(); + while (type != null && type != Object.class) { + for (Field field : type.getDeclaredFields()) { + DisableSettingI18n annotation = field.getAnnotation(DisableSettingI18n.class); + if (annotation == null) continue; + if (!ConfigValue.class.isAssignableFrom(field.getType())) continue; + + boolean accessible = field.canAccess(owner); + try { + if (!accessible) { + field.setAccessible(true); + } + if (field.get(owner) instanceof ConfigValue value) { + SettingDef def = defsByValue.get(value); + if (def != null) { + def.disableI18n(annotation.name(), annotation.options()); + } + } + } catch (Throwable ignored) { + } finally { + if (!accessible) { + try { + field.setAccessible(false); + } catch (Throwable ignored) { + } + } + } + } + type = type.getSuperclass(); + } + } + + public Kind kind() { + return kind; + } + + public String id() { + return id; + } + + public String getId() { + return id; + } + + public ConfigValue value() { + return value; + } + + public BindMode bindMode() { + return bindMode; + } + + public TextListSetting.PickerMode pickerMode() { + return pickerMode; + } + + public Supplier visibility() { + return visibility; + } + + public Supplier unavailableReason() { + return unavailableReason; + } + + public String commonI18nKey() { + return commonI18nKeys.isEmpty() ? null : commonI18nKeys.get(0); + } + + public List commonI18nKeys() { + return List.copyOf(commonI18nKeys); + } + + public boolean i18nNameEnabled() { + return i18nNameEnabled; + } + + public boolean i18nOptionsEnabled() { + return i18nOptionsEnabled; + } + + public SettingDef visibleWhen(Supplier supplier) { + this.visibility = supplier; + return this; + } + + public SettingDef unavailableWhen(Supplier supplier, String reason) { + return unavailableWhen(supplier, () -> reason); + } + + public SettingDef unavailableWhen(Supplier supplier, Supplier reason) { + if (supplier == null) { + this.unavailableReason = null; + return this; + } + this.unavailableReason = () -> { + boolean unavailable; + try { + unavailable = supplier.get(); + } catch (Exception ignored) { + unavailable = false; + } + if (!unavailable) { + return null; + } + try { + return reason == null ? "" : reason.get(); + } catch (Exception ignored) { + return ""; + } + }; + return this; + } + + public SettingDef availableWhen(Supplier supplier, String reasonWhenUnavailable) { + return availableWhen(supplier, () -> reasonWhenUnavailable); + } + + public SettingDef availableWhen(Supplier supplier, Supplier reasonWhenUnavailable) { + if (supplier == null) { + this.unavailableReason = null; + return this; + } + return unavailableWhen(() -> !supplier.get(), reasonWhenUnavailable); + } + + public SettingDef common(String key) { + addCommonKey(key); + return this; + } + + public SettingDef common(CommonSettingSchema schema) { + if (schema != null) { + for (String key : schema.commonI18nKeys()) { + addCommonKey(key); + } + } + return this; + } + + private void addCommonKey(String key) { + if (key == null) return; + String normalized = key.trim(); + if (!normalized.isBlank() && !commonI18nKeys.contains(normalized)) { + commonI18nKeys.add(normalized); + } + } + + public SettingDef disableI18n(boolean name, boolean options) { + if (name) { + this.i18nNameEnabled = false; + } + if (options) { + this.i18nOptionsEnabled = false; + } + return this; + } + + public enum Kind { + BOOLEAN, + NUMBER, + MODE, + COLOR, + COLOR_NO_ALPHA, + TEXT, + TEXT_LIST, + COOLDOWN_RULES, + PROTOCOL_HEURISTICS, + GROUP, + BIND + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingDefProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingDefProvider.java new file mode 100644 index 0000000..bd0051f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingDefProvider.java @@ -0,0 +1,17 @@ +/* + * 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.config; + +import java.util.List; + +/** + * Provides GUI-neutral setting definitions. + */ +public interface SettingDefProvider { + List getSettingDefs(); +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingOwner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingOwner.java new file mode 100644 index 0000000..6bed304 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/SettingOwner.java @@ -0,0 +1,24 @@ +/* + * 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.config; + +/** + * Owner of GUI settings. Allows settings to save config and build i18n keys + * without tying them to Module. + */ +public interface SettingOwner { + String name(); + + void saveConfig(); + + default String getTranslationKeyPrefix() { + String name = name(); + if (name == null || name.isBlank()) return null; + return "setting." + name; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonBooleanGroupSchema.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonBooleanGroupSchema.java new file mode 100644 index 0000000..d93dbbe --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonBooleanGroupSchema.java @@ -0,0 +1,14 @@ +/* + * 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.config.common; + +import java.util.Map; + +public interface CommonBooleanGroupSchema extends CommonSettingSchema { + Map defaults(); +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonSettingSchema.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonSettingSchema.java new file mode 100644 index 0000000..d325854 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonSettingSchema.java @@ -0,0 +1,19 @@ +/* + * 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.config.common; + +import java.util.List; + +public interface CommonSettingSchema { + String commonI18nKey(); + + default List commonI18nKeys() { + String key = commonI18nKey(); + return key == null || key.isBlank() ? List.of() : List.of(key); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonSettingSchemas.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonSettingSchemas.java new file mode 100644 index 0000000..ecda2ba --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/CommonSettingSchemas.java @@ -0,0 +1,200 @@ +/* + * 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.config.common; + +import dev.loki.lovisual.config.common.impl.*; + +public enum CommonSettingSchemas { + ; + + public static final TargetFilters TARGET_FILTERS = new TargetFilters(); + + public static final CombatPriority COMBAT_PRIORITY = new CombatPriority(); + + public static final RotationMovementCorrection ROTATION_MOVEMENT_CORRECTION = new RotationMovementCorrection(); + public static final RotationResetTicks ROTATION_RESET_TICKS = new RotationResetTicks(); + public static final RotationResetThreshold ROTATION_RESET_THRESHOLD = new RotationResetThreshold(); + public static final RotationTiming ROTATION_TIMING = new RotationTiming(); + public static final RotationMode ROTATION_MODE = new RotationMode(); + public static final RotationThroughWalls ROTATION_THROUGH_WALLS = new RotationThroughWalls(); + + // Generic repeated combat/action labels. + public static final CommonSettingSchema PLACE = key("place"); + public static final CommonSettingSchema EXPLODE = key("explode"); + public static final CommonSettingSchema BREAK = key("break"); + public static final CommonSettingSchema TIMING = key("timing"); + public static final CommonSettingSchema CALC_DELAY = key("calc_delay"); + public static final CommonSettingSchema LOW_PLACE_DELAY = key("low_place_delay"); + public static final CommonSettingSchema LOW_EXPLODE_DELAY = key("low_explode_delay"); + public static final CommonSettingSchema AIR_PLACE = key("air_place"); + public static final CommonSettingSchema MIN_DAMAGE = key("min_damage"); + public static final CommonSettingSchema FACEPLACE_HEALTH = key("faceplace_health"); + public static final CommonSettingSchema MAX_SELF_DAMAGE = key("max_self_damage"); + public static final CommonSettingSchema SELF_PREDICT_TICKS = key("self_predict_ticks"); + public static final CommonSettingSchema UNSAFE_DIMENSION_ONLY = key("unsafe_dimension_only"); + public static final CommonSettingSchema PAUSE_MINING = key("pause_mining"); + public static final CommonSettingSchema PAUSE_EATING = key("pause_eating"); + public static final CommonSettingSchema RENDER_SELF_DAMAGE = key("render_self_damage"); + public static final CommonSettingSchema RENDER_DAMAGE = key("render_damage"); + public static final CommonSettingSchema FILL_COLOR = key("fill_color"); + public static final CommonSettingSchema LINE_COLOR = key("line_color"); + public static final CommonSettingSchema LINE_WIDTH = key("line_width"); + public static final CommonSettingSchema TEXT_COLOR = key("text_color"); + public static final CommonSettingSchema SLIDE_DELAY = key("slide_delay"); + public static final CommonSettingSchema FADE_TIME = key("fade_time"); + public static final CommonSettingSchema MODE = key("mode"); + + // Sprint Reset + public static final CommonSettingSchema COMBAT_CRITICALS = key("combat.criticals"); + public static final CommonSettingSchema COMBAT_SPRINT_RESET = key("combat.sprint_reset"); + public static final CommonSettingSchema COMBAT_WHEN_SPRINTING = key("combat.when_sprinting"); + public static final CommonSettingSchema COMBAT_STOP_SPRINTING = key("combat.stop_sprinting"); + public static final CommonSettingSchema COMBAT_ATTACK_MODE = key("combat.attack_mode"); + public static final CommonSettingSchema COMBAT_CPS_MIN = key("combat.cps_min"); + public static final CommonSettingSchema COMBAT_CPS_MAX = key("combat.cps_max"); + public static final CommonSettingSchema COMBAT_PROTOCOL = key("combat.protocol"); + public static final CombatProtocolHeuristicSources COMBAT_PROTOCOL_HEURISTICS = new CombatProtocolHeuristicSources(); + public static final CommonSettingSchema COMBAT_RANGE = key("combat.range", "target_range", "range"); + public static final CommonSettingSchema COMBAT_REACH_MODE = key("combat.reach_mode"); + public static final CommonSettingSchema COMBAT_RANGE_INCREMENT = key("combat.range_increment"); + public static final CommonSettingSchema COMBAT_WALL_RANGE = key("combat.wall_range"); + public static final CommonSettingSchema COMBAT_FOV = key("combat.fov", "target_fov", "fov"); + public static final CommonSettingSchema COMBAT_CORRECTION_TYPE = key("combat.correction_type"); + public static final CommonSettingSchema COMBAT_RAYCAST = key("combat.raycast"); + public static final CommonSettingSchema COMBAT_BACKTRACK_TARGET_MODE = key("combat.backtrack.target_mode", "target_mode"); + public static final CommonSettingSchema COMBAT_BACKTRACK_RANGE_MIN = key("combat.backtrack.range_min", "range_min"); + public static final CommonSettingSchema COMBAT_BACKTRACK_RANGE_MAX = key("combat.backtrack.range_max", "range_max"); + public static final CommonSettingSchema COMBAT_BACKTRACK_DELAY_MIN = key("combat.backtrack.delay_min", "delay_min"); + public static final CommonSettingSchema COMBAT_BACKTRACK_DELAY_MAX = key("combat.backtrack.delay_max", "delay_max"); + public static final CommonSettingSchema COMBAT_BACKTRACK_NEXT_DELAY_MIN = key("combat.backtrack.next_delay_min", "next_delay_min"); + public static final CommonSettingSchema COMBAT_BACKTRACK_NEXT_DELAY_MAX = key("combat.backtrack.next_delay_max", "next_delay_max"); + public static final CommonSettingSchema COMBAT_BACKTRACK_TRACKING_BUFFER = key("combat.backtrack.tracking_buffer", "tracking_buffer"); + public static final CommonSettingSchema COMBAT_BACKTRACK_CHANCE = key("combat.backtrack.chance", "chance"); + public static final CommonSettingSchema COMBAT_BACKTRACK_PAUSE_ON_HURT_TIME = key("combat.backtrack.pause_on_hurt_time", "pause_on_hurt_time"); + public static final CommonSettingSchema COMBAT_BACKTRACK_HURT_TIME = key("combat.backtrack.hurt_time", "hurt_time"); + public static final CommonSettingSchema COMBAT_BACKTRACK_LAST_ATTACK_TIME = key("combat.backtrack.last_attack_time", "last_attack_time"); + public static final CommonSettingSchema COMBAT_BACKTRACK_RENDER = key("combat.backtrack.render", "render"); + public static final CommonSettingSchema COMBAT_BACKTRACK_LINE_WIDTH = key("combat.backtrack.line_width", "line_width"); + public static final CommonSettingSchema COMBAT_WEAPON = key("combat.weapon"); + public static final CommonSettingSchema COMBAT_OBJECTIVE = key("combat.objective"); + public static final CommonSettingSchema COMBAT_ON_ITEM_USE = key("combat.on_item_use"); + public static final CommonSettingSchema COMBAT_CRYSTAL_DISTANCE = key("combat.crystal_distance"); + public static final CommonSettingSchema COMBAT_BREAK_SHIELDS = key("combat.break_shields"); + public static final CommonSettingSchema INVENTORY_SEARCH_SCOPE = key("inventory.search_scope", "swap_scope"); + public static final CommonSettingSchema INVENTORY_SWAP_VISIBILITY = key("inventory.swap_visibility", "swap_visibility"); + public static final CommonSettingSchema INVENTORY_RESTORE_ITEM = key("inventory.restore_item", "restore_item"); + public static final CommonSettingSchema INVENTORY_PREFER_HOTBAR = key("inventory.prefer_hotbar", "prefer_hotbar"); + public static final CommonSettingSchema INTERACTION_IGNORE_OPEN_INVENTORY = key("interaction.ignore_open_inventory", "ignore_open_inventory"); + public static final CommonSettingSchema COMBAT_ONLY_PLAYERS = key("combat.only_players"); + public static final CommonSettingSchema COMBAT_ONLY_BLOCKING = key("combat.only_blocking"); + public static final CommonSettingSchema COMBAT_MIN_FALL_DISTANCE = key("combat.min_fall_distance", "min_fall_distance"); + public static final CommonSettingSchema COMBAT_RESPECT_COOLDOWN = key("combat.respect_cooldown"); + public static final CommonSettingSchema ITEMS_PROJECTILES = key("items.projectiles"); + public static final CommonSettingSchema ITEMS_SAVE_UNENCHANTED = key("items.save_unenchanted"); + //Placement + public static final CommonSettingSchema PLACEMENT_RANGE = key("placement.range", "place_range"); + public static final CommonSettingSchema PLACEMENT_WALL_RANGE = key("placement.wall_range", "wall_range"); + public static final CommonSettingSchema PLACEMENT_BREAK_RANGE = key("placement.break_range", "break_range"); + public static final CommonSettingSchema PLACEMENT_BREAK_WALL_RANGE = key("placement.break_wall_range", "break_wall_range"); + public static final CommonSettingSchema PLACEMENT_MODE = key("placement.mode", "placement_mode"); + public static final CommonSettingSchema PLACEMENT_SPEED = key("placement.speed", "placement_speed"); + public static final CommonSettingSchema PLACEMENT_DELAY = key("placement.delay", "place_delay"); + public static final CommonSettingSchema PLACEMENT_BREAK_DELAY = key("placement.break_delay", "break_delay", "explode_delay"); + public static final CommonSettingSchema PLACEMENT_PREDICTION = key("placement.prediction", "predict_ticks"); + public static final CommonSettingSchema PLACEMENT_RENDER = key("placement.render", "render"); + public static final CommonSettingSchema PLACEMENT_RENDER_MODE = key("placement.render_mode", "render_mode"); + public static final CommonSettingSchema PLACEMENT_ROTATION_TIMING = key("placement.rotation_timing", "rotation.rotation_timing", "rotation_timing"); + public static final CommonSettingSchema PLACEMENT_MOVEMENT_CORRECTION = key("placement.movement_correction", "rotation.movement_correction", "movement_correction"); + public static final CommonSettingSchema PLACEMENT_ROTATION_RESET_TICKS = key("placement.rotation_reset_ticks", "rotation.rotation_reset_ticks", "rotation_reset_ticks"); + public static final CommonSettingSchema PLACEMENT_ROTATION_RESET_THRESHOLD = key("placement.rotation_reset_threshold", "rotation.rotation_reset_threshold", "rotation_reset_threshold"); + public static final CommonSettingSchema INVENTORY_SWAP_MODE = key("inventory.swap_mode", "swap_mode"); + public static final CommonSettingSchema PLAYER_HEALTH_THRESHOLD = key("player.health_threshold", "pause_health", "health_threshold"); + public static final CommonSettingSchema PLAYER_ELYTRA_HEALTH = key("player.elytra_health"); + public static final CommonSettingSchema PLAYER_FALL_CHECK = key("player.fall_check"); + public static final CommonSettingSchema PLAYER_USE_RELATIONS = key("player.use_relations"); + public static final CommonSettingSchema TOTEM_POP_COUNTER = key("totem_pop.counter", "totem_pop_counter"); + public static final CommonSettingSchema TOTEM_POP_RESET_SECONDS = key("totem_pop.reset_seconds", "totem_pop_reset_seconds"); + public static final CommonSettingSchema PLAYER_FAKELAG_MODE = key("player.fakelag.mode"); + public static final CommonSettingSchema PLAYER_FAKELAG_RANGE_MIN = key("player.fakelag.range_min", "min_range", "range_min"); + public static final CommonSettingSchema PLAYER_FAKELAG_RANGE_MAX = key("player.fakelag.range_max", "max_range", "range_max"); + public static final CommonSettingSchema PLAYER_FAKELAG_DELAY_MIN = key("player.fakelag.delay_min", "delay_min"); + public static final CommonSettingSchema PLAYER_FAKELAG_DELAY_MAX = key("player.fakelag.delay_max", "delay_max"); + public static final CommonSettingSchema PLAYER_FAKELAG_RECOIL_TIME = key("player.fakelag.recoil_time", "recoil_time"); + public static final FakeLagFlushOn PLAYER_FAKELAG_FLUSH_ON = new FakeLagFlushOn(); + // Elytra target / fireworks + public static final CommonSettingSchema ELYTRA_HITBOX_EXPAND = key("elytra.hitbox_expand"); + public static final CommonSettingSchema ELYTRA_EXPAND_WHEN_READY = key("elytra.expand_when_ready"); + public static final CommonSettingSchema ELYTRA_FIREWORK_SPEED = key("elytra.firework_speed", "firework_speed"); + public static final CommonSettingSchema ELYTRA_TARGET_MUST_FLY = key("elytra.target_must_fly"); + public static final CommonSettingSchema ELYTRA_PREPARE_ROTATIONS = key("elytra.prepare_rotations", "prepare_rotations"); + public static final CommonSettingSchema ELYTRA_VELOCITY_TUNE = key("elytra.velocity_tune"); + public static final CommonSettingSchema ELYTRA_CUSTOM_VELOCITY_TABLE = key("elytra.custom_velocity_table"); + public static final CommonSettingSchema ELYTRA_FIREWORK_SILENT_SWAP = key("elytra.firework_silent_swap", "silent_swap", "firework_silent_swap"); + // ESP / world scan + public static final CommonSettingSchema ESP_SCAN_MODE = key("esp.scan_mode"); + public static final CommonSettingSchema ESP_LIMIT_DISTANCE = key("esp.limit_distance"); + public static final CommonSettingSchema ESP_MAX_DISTANCE = key("esp.max_distance", "max_distance"); + public static final CommonSettingSchema ESP_SCAN_DELAY = key("esp.scan_delay", "scan_delay"); + public static final CommonSettingSchema ESP_MAX_TARGETS = key("esp.max_targets", "max_targets"); + public static final CommonSettingSchema ESP_USE_TRACERS = key("esp.use_tracers"); + public static final CommonSettingSchema ESP_LINE_WIDTH = key("esp.line_width", "line_width"); + public static final CommonSettingSchema ESP_OUTLINE_SHAPE = key("esp.outline_shape", "outline_shape"); + public static final CommonSettingSchema ESP_BOX_MODE = key("esp.box_mode"); + public static final CommonSettingSchema ESP_HEALTH_BAR = key("esp.health_bar"); + public static final CommonSettingSchema ESP_HEALTH_BAR_GRADIENT = key("esp.health_bar_gradient"); + public static final CommonSettingSchema ESP_HEALTH_BAR_DISTANCE = key("esp.health_bar_distance", "health_bar_distance"); + // AngleSmooth generic + public static final CommonSettingSchema ANGLESMOOTH_HORIZONTAL_MIN = key("rotation.anglesmooth.horizontal_min"); + public static final CommonSettingSchema ANGLESMOOTH_HORIZONTAL_MAX = key("rotation.anglesmooth.horizontal_max"); + public static final CommonSettingSchema ANGLESMOOTH_VERTICAL_MIN = key("rotation.anglesmooth.vertical_min"); + public static final CommonSettingSchema ANGLESMOOTH_VERTICAL_MAX = key("rotation.anglesmooth.vertical_max"); + // Sigmoid + public static final CommonSettingSchema ANGLESMOOTH_STEEPNESS = key("rotation.anglesmooth.steepness"); + public static final CommonSettingSchema ANGLESMOOTH_MIDPOINT = key("rotation.anglesmooth.midpoint"); + // Smart + public static final CommonSettingSchema ANGLESMOOTH_YAW_MIN = key("rotation.anglesmooth.yaw_min"); + public static final CommonSettingSchema ANGLESMOOTH_YAW_MAX = key("rotation.anglesmooth.yaw_max"); + public static final CommonSettingSchema ANGLESMOOTH_PITCH_MIN = key("rotation.anglesmooth.pitch_min"); + public static final CommonSettingSchema ANGLESMOOTH_PITCH_MAX = key("rotation.anglesmooth.pitch_max"); + public static final CommonSettingSchema ANGLESMOOTH_SNAP_THRESHOLD = key("rotation.anglesmooth.snap_threshold"); + public static final CommonSettingSchema ANGLESMOOTH_JITTER_YAW = key("rotation.anglesmooth.jitter_yaw"); + public static final CommonSettingSchema ANGLESMOOTH_JITTER_PITCH = key("rotation.anglesmooth.jitter_pitch"); + public static final CommonSettingSchema ANGLESMOOTH_DECELERATE_ENABLED = key("rotation.anglesmooth.decelerate_enabled"); + public static final CommonSettingSchema ANGLESMOOTH_DECELERATE_ANGLE = key("rotation.anglesmooth.decelerate_angle"); + public static final CommonSettingSchema ANGLESMOOTH_DECELERATE_MIN_FACTOR = key("rotation.anglesmooth.decelerate_min_factor"); + // Lazy aim + public static final CommonSettingSchema LAZY_AIM_ENABLED = key("rotation.lazy_aim.enabled"); + public static final CommonSettingSchema LAZY_AIM_THRESHOLD = key("rotation.lazy_aim.threshold"); + public static final CommonSettingSchema LAZY_AIM_FOLLOW_FACTOR = key("rotation.lazy_aim.follow_factor"); + // Shake aim + public static final CommonSettingSchema SHAKE_AIM_ENABLED = key("rotation.shake_aim.enabled"); + public static final CommonSettingSchema SHAKE_AIM_YAW_AMPLITUDE = key("rotation.shake_aim.yaw_amplitude"); + public static final CommonSettingSchema SHAKE_AIM_PITCH_AMPLITUDE = key("rotation.shake_aim.pitch_amplitude"); + public static final CommonSettingSchema SHAKE_AIM_SPEED = key("rotation.shake_aim.speed"); + // Fail + public static final CommonSettingSchema FAIL_ENABLED = key("rotation.fail.enabled"); + public static final CommonSettingSchema FAIL_RATE = key("rotation.fail.rate"); + public static final CommonSettingSchema FAIL_FACTOR = key("rotation.fail.factor"); + public static final CommonSettingSchema FAIL_STRENGTH_HORIZONTAL_MIN = key("rotation.fail.strength_horizontal_min"); + public static final CommonSettingSchema FAIL_STRENGTH_HORIZONTAL_MAX = key("rotation.fail.strength_horizontal_max"); + public static final CommonSettingSchema FAIL_STRENGTH_VERTICAL_MIN = key("rotation.fail.strength_vertical_min"); + public static final CommonSettingSchema FAIL_STRENGTH_VERTICAL_MAX = key("rotation.fail.strength_vertical_max"); + public static final CommonSettingSchema FAIL_TRANSITION_MIN = key("rotation.fail.transition_min"); + public static final CommonSettingSchema FAIL_TRANSITION_MAX = key("rotation.fail.transition_max"); + public static final CommonSettingSchema ANTICHEAT_MODE = key("anticheat.mode"); + public static final CommonSettingSchema RENDER_COLOR_MODE = key("render.color_mode", "color_mode"); + public static final CommonSettingSchema RENDER_COLOR_SPEED = key("render.color_speed", "color_speed"); + public static final CommonSettingSchema RENDER_PRIMARY_COLOR = key("render.primary_color", "primary_color"); + public static final CommonSettingSchema RENDER_SECONDARY_COLOR = key("render.secondary_color", "secondary_color"); + public static final CommonSettingSchema RENDER_DEPTH_TEST = key("render.depth_test", "depth_test"); + public static final CommonSettingSchema RENDER_SCALE = key("render.scale", "scale"); + + private static CommonSettingSchema key(String key, String... aliases) { + return new CommonKey(key, aliases); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CombatPriority.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CombatPriority.java new file mode 100644 index 0000000..4a201f5 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CombatPriority.java @@ -0,0 +1,17 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonSettingSchema; + +public final class CombatPriority implements CommonSettingSchema { + @Override + public String commonI18nKey() { + return "combat.priority"; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CombatProtocolHeuristicSources.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CombatProtocolHeuristicSources.java new file mode 100644 index 0000000..13fb8b2 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CombatProtocolHeuristicSources.java @@ -0,0 +1,25 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonBooleanGroupSchema; +import dev.loki.lovisual.util.combat.protocol.CombatProtocolHeuristics; + +import java.util.Map; + +public final class CombatProtocolHeuristicSources implements CommonBooleanGroupSchema { + @Override + public String commonI18nKey() { + return "combat.protocol_heuristics"; + } + + @Override + public Map defaults() { + return CombatProtocolHeuristics.defaultSourceToggles(); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CommonKey.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CommonKey.java new file mode 100644 index 0000000..38b51c5 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/CommonKey.java @@ -0,0 +1,46 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonSettingSchema; + +import java.util.ArrayList; +import java.util.List; + +public final class CommonKey implements CommonSettingSchema { + private final List keys; + + public CommonKey(String key, String... aliases) { + ArrayList out = new ArrayList<>(); + add(out, key); + if (aliases != null) { + for (String alias : aliases) { + add(out, alias); + } + } + this.keys = List.copyOf(out); + } + + @Override + public String commonI18nKey() { + return keys.isEmpty() ? null : keys.get(0); + } + + @Override + public List commonI18nKeys() { + return keys; + } + + private static void add(ArrayList out, String key) { + if (key == null) return; + String normalized = key.trim(); + if (!normalized.isBlank() && !out.contains(normalized)) { + out.add(normalized); + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/FakeLagFlushOn.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/FakeLagFlushOn.java new file mode 100644 index 0000000..872265d --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/FakeLagFlushOn.java @@ -0,0 +1,33 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonBooleanGroupSchema; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class FakeLagFlushOn implements CommonBooleanGroupSchema { + public static final String ENTITY_INTERACT = "entity_interact"; + public static final String BLOCK_INTERACT = "block_interact"; + public static final String ACTION = "action"; + + @Override + public String commonI18nKey() { + return "fakelag.flush_on"; + } + + @Override + public Map defaults() { + Map defaults = new LinkedHashMap<>(); + defaults.put(ENTITY_INTERACT, false); + defaults.put(BLOCK_INTERACT, false); + defaults.put(ACTION, false); + return defaults; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationMode.java new file mode 100644 index 0000000..aae2b5a --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationMode.java @@ -0,0 +1,17 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonSettingSchema; + +public final class RotationMode implements CommonSettingSchema { + @Override + public String commonI18nKey() { + return "rotation.rotation_mode"; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationMovementCorrection.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationMovementCorrection.java new file mode 100644 index 0000000..0fb5222 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationMovementCorrection.java @@ -0,0 +1,17 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonSettingSchema; + +public final class RotationMovementCorrection implements CommonSettingSchema { + @Override + public String commonI18nKey() { + return "rotation.movement_correction"; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationResetThreshold.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationResetThreshold.java new file mode 100644 index 0000000..465fbdf --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationResetThreshold.java @@ -0,0 +1,17 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonSettingSchema; + +public final class RotationResetThreshold implements CommonSettingSchema { + @Override + public String commonI18nKey() { + return "rotation.rotation_reset_threshold"; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationResetTicks.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationResetTicks.java new file mode 100644 index 0000000..bd1be7f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationResetTicks.java @@ -0,0 +1,17 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonSettingSchema; + +public final class RotationResetTicks implements CommonSettingSchema { + @Override + public String commonI18nKey() { + return "rotation.rotation_reset_ticks"; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationThroughWalls.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationThroughWalls.java new file mode 100644 index 0000000..b5c74cc --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationThroughWalls.java @@ -0,0 +1,17 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonSettingSchema; + +public final class RotationThroughWalls implements CommonSettingSchema { + @Override + public String commonI18nKey() { + return "rotation.rotation_through_walls"; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationTiming.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationTiming.java new file mode 100644 index 0000000..00fdd0a --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/RotationTiming.java @@ -0,0 +1,17 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonSettingSchema; + +public final class RotationTiming implements CommonSettingSchema { + @Override + public String commonI18nKey() { + return "rotation.rotation_timing"; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/TargetFilters.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/TargetFilters.java new file mode 100644 index 0000000..f546b89 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/common/impl/TargetFilters.java @@ -0,0 +1,42 @@ +/* + * 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.config.common.impl; + +import dev.loki.lovisual.config.common.CommonBooleanGroupSchema; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class TargetFilters implements CommonBooleanGroupSchema { + + public static final String PLAYERS_ONLY = "players_only"; + public static final String IGNORE_FRIENDS = "ignore_friends"; + public static final String IGNORE_STAFF = "ignore_staff"; + public static final String IGNORE_ENEMIES = "ignore_enemies"; + public static final String IGNORE_NAKED = "ignore_naked"; + public static final String IGNORE_ENTITIES = "ignore_entities"; + public static final String VISIBLE_ONLY = "visible_only"; + + @Override + public String commonI18nKey() { + return "target"; + } + + @Override + public Map defaults() { + Map defaults = new LinkedHashMap<>(); + defaults.put(PLAYERS_ONLY, true); + defaults.put(IGNORE_FRIENDS, true); + defaults.put(IGNORE_STAFF, true); + defaults.put(IGNORE_ENEMIES, false); + defaults.put(IGNORE_NAKED, false); + defaults.put(IGNORE_ENTITIES, false); + defaults.put(VISIBLE_ONLY, false); + return defaults; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileApplier.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileApplier.java new file mode 100644 index 0000000..5b20a27 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileApplier.java @@ -0,0 +1,157 @@ +/* + * 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.config.profile; + + +import dev.loki.lovisual.features.theme.Theme; +import dev.loki.lovisual.config.ConfigObject; +import dev.loki.lovisual.config.values.ConfigValue; +import dev.loki.lovisual.addon.AddonManager; +import dev.loki.lovisual.features.gui.hud.BaseHudElement; +import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; +import dev.loki.lovisual.features.gui.hud.nondraggable.StaticHudElementRegistry; +import dev.loki.lovisual.features.theme.Themes; +import dev.loki.lovisual.features.module.Module; +import dev.loki.lovisual.features.module.ModuleManager; +import dev.loki.lovisual.util.logging.DebugLog; + +import java.util.HashMap; +import java.util.Map; + +public final class ConfigProfileApplier { + public ApplyResult apply(ConfigProfileSnapshot snapshot) { + if (snapshot == null) return new ApplyResult(0, 0, 0); + ApplyCounter counter = new ApplyCounter(); + if (snapshot.meta().type() == ConfigProfileType.MODULES) { + ModuleManager.runSilentConfigApply(() -> applyEntries(snapshot, counter)); + } else { + applyEntries(snapshot, counter); + } + return new ApplyResult(counter.appliedOwners, counter.missingOwners, counter.missingValues); + } + + private void applyEntries(ConfigProfileSnapshot snapshot, ApplyCounter counter) { + if (snapshot.meta().type() == ConfigProfileType.THEMES) { + applyThemeEntries(snapshot, counter); + return; + } + for (ConfigProfileEntry entry : snapshot.entries()) { + ConfigObject owner = resolveOwner(entry.ownerId()); + if (owner == null) { + counter.missingOwners++; + DebugLog.config("Config profile missing owner: %s", entry.ownerId()); + continue; + } + applyValues(owner, entry, counter); + counter.appliedOwners++; + afterOwnerApplied(owner); + } + } + + private void applyThemeEntries(ConfigProfileSnapshot snapshot, ApplyCounter counter) { + String currentId = null; + for (ConfigProfileEntry entry : snapshot.entries()) { + String ownerId = entry.ownerId(); + if (ownerId == null) { + counter.missingOwners++; + continue; + } + if (ownerId.equals("theme-state:current")) { + Object current = entry.values().get("current"); + if (current instanceof CharSequence s && !s.toString().isBlank()) { + currentId = s.toString(); + } + counter.appliedOwners++; + continue; + } + if (!ownerId.startsWith("theme:")) { + counter.missingOwners++; + continue; + } + String id = ownerId.substring("theme:".length()); + try { + Themes.importProfileValues(id, entry.displayName(), entry.values()); + counter.appliedOwners++; + } catch (Throwable t) { + counter.missingValues++; + DebugLog.error("Failed to apply theme profile entry %s", t, ownerId); + } + } + if (currentId != null) { + String selectedId = currentId.toLowerCase(java.util.Locale.ROOT); + if (Theme.themes().stream().anyMatch(theme -> theme.getId().equals(selectedId))) { + Theme.setTheme(selectedId); + } + } + } + + private void applyValues(ConfigObject owner, ConfigProfileEntry entry, ApplyCounter counter) { + Map> byName = new HashMap<>(); + for (ConfigValue value : owner.getConfigValues()) { + if (value != null && value.getName() != null) byName.put(value.getName(), value); + } + for (Map.Entry saved : entry.values().entrySet()) { + ConfigValue value = byName.get(saved.getKey()); + if (value == null) { + counter.missingValues++; + continue; + } + try { + value.fromJson(saved.getValue()); + } catch (Throwable t) { + counter.missingValues++; + DebugLog.error("Failed to apply profile value %s.%s", t, entry.ownerId(), saved.getKey()); + } + } + } + + private ConfigObject resolveOwner(String ownerId) { + if (ownerId == null) return null; + if (ownerId.startsWith("addon:")) { + return resolveOwner(stripAddonPrefix(ownerId)); + } + if (ownerId.startsWith("module:")) return ModuleManager.get(ownerId.substring("module:".length())); + if (ownerId.startsWith("hud.draggable:")) { + return DraggableHudElementRegistry.getById(ownerId.substring("hud.draggable:".length())); + } + if (ownerId.startsWith("hud.static:")) { + return StaticHudElementRegistry.getById(ownerId.substring("hud.static:".length())); + } + return null; + } + + private String stripAddonPrefix(String ownerId) { + String addonId = AddonManager.addonIdFromProfileOwner(ownerId); + if (addonId == null) return ""; + String prefix = "addon:" + addonId + ":"; + if (!ownerId.startsWith(prefix)) return ""; + return ownerId.substring(prefix.length()); + } + + private void afterOwnerApplied(ConfigObject owner) { + if (owner instanceof Module module) { + module.applyConfiguredEnabledState(); + module.syncSettingsAfterLoad(); + module.saveConfig(); + return; + } + if (owner instanceof BaseHudElement hud) { + hud.saveConfig(); + return; + } + } + + private static final class ApplyCounter { + int appliedOwners; + int missingOwners; + int missingValues; + } + + public record ApplyResult(int appliedOwners, int missingOwners, int missingValues) { + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileBinaryCodec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileBinaryCodec.java new file mode 100644 index 0000000..ba1913c --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileBinaryCodec.java @@ -0,0 +1,152 @@ +/* + * 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.config.profile; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.zip.CRC32; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +public final class ConfigProfileBinaryCodec { + public static final int VERSION = 1; + static final int MAGIC = 0x43424346; // CBCF + private static final int FLAG_COMPRESSED = 1; + + public ConfigProfileBinaryCodec() { + } + + public byte[] write(ConfigProfileSnapshot snapshot) throws IOException { + if (snapshot == null) throw new IllegalArgumentException("snapshot is null"); + ByteArrayOutputStream payloadRaw = new ByteArrayOutputStream(); + try (DataOutputStream payload = new DataOutputStream(payloadRaw)) { + writePayload(payload, snapshot.entries()); + } + + byte[] payloadBytes = compress(payloadRaw.toByteArray()); + CRC32 crc = new CRC32(); + crc.update(payloadBytes); + + ByteArrayOutputStream fileRaw = new ByteArrayOutputStream(); + try (DataOutputStream out = new DataOutputStream(fileRaw)) { + ConfigProfileMeta meta = snapshot.meta(); + out.writeInt(MAGIC); + out.writeByte(VERSION); + out.writeByte(meta.type().wireId()); + out.writeShort(FLAG_COMPRESSED); + out.writeLong(meta.createdAt()); + out.writeLong(meta.updatedAt()); + ConfigProfileValueCodec.writeString(out, meta.author()); + ConfigProfileValueCodec.writeString(out, meta.name()); + ConfigProfileValueCodec.writeString(out, meta.getId()); + ConfigProfileValueCodec.writeVarInt(out, payloadBytes.length); + out.write(payloadBytes); + out.writeInt((int) crc.getValue()); + } + return fileRaw.toByteArray(); + } + + public ConfigProfileMeta readMeta(byte[] bytes) throws IOException { + try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes))) { + Header header = readHeader(in); + return header.meta(); + } + } + + public ConfigProfileSnapshot read(byte[] bytes) throws IOException { + try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes))) { + Header header = readHeader(in); + byte[] payload = new byte[header.payloadLength()]; + in.readFully(payload); + int expectedCrc = in.readInt(); + CRC32 crc = new CRC32(); + crc.update(payload); + if ((int) crc.getValue() != expectedCrc) { + throw new IOException("Config profile checksum mismatch: " + header.meta().name()); + } + byte[] rawPayload = (header.flags() & FLAG_COMPRESSED) != 0 ? decompress(payload) : payload; + List entries; + try (DataInputStream payloadIn = new DataInputStream(new ByteArrayInputStream(rawPayload))) { + entries = readPayload(payloadIn); + } + return new ConfigProfileSnapshot(header.meta(), entries); + } + } + + private Header readHeader(DataInputStream in) throws IOException { + int magic = in.readInt(); + if (magic != MAGIC) throw new IOException("Invalid profile magic"); + int version = in.readUnsignedByte(); + if (version != VERSION) throw new IOException("Unsupported profile version: " + version); + ConfigProfileType type = ConfigProfileType.fromWireId(in.readUnsignedByte()); + int flags = in.readUnsignedShort(); + long createdAt = in.readLong(); + long updatedAt = in.readLong(); + String author = ConfigProfileValueCodec.readString(in); + String name = ConfigProfileValueCodec.readString(in); + String id = ConfigProfileValueCodec.readString(in); + int payloadLength = ConfigProfileValueCodec.readVarInt(in); + if (payloadLength < 0) throw new IOException("Negative payload length"); + ConfigProfileMeta meta = new ConfigProfileMeta(id, name, type, author, createdAt, updatedAt, version); + return new Header(meta, flags, payloadLength); + } + + private void writePayload(DataOutputStream out, List entries) throws IOException { + ConfigProfileValueCodec.writeVarInt(out, entries.size()); + for (ConfigProfileEntry entry : entries) { + ConfigProfileValueCodec.writeString(out, entry.ownerId()); + ConfigProfileValueCodec.writeString(out, entry.displayName()); + ConfigProfileValueCodec.writeVarInt(out, entry.values().size()); + for (Map.Entry value : entry.values().entrySet()) { + ConfigProfileValueCodec.writeString(out, value.getKey()); + ConfigProfileValueCodec.writeValue(out, value.getValue()); + } + } + } + + private List readPayload(DataInputStream in) throws IOException { + int entryCount = ConfigProfileValueCodec.readVarInt(in); + List entries = new ArrayList<>(Math.max(0, entryCount)); + for (int i = 0; i < entryCount; i++) { + String ownerId = ConfigProfileValueCodec.readString(in); + String displayName = ConfigProfileValueCodec.readString(in); + int valueCount = ConfigProfileValueCodec.readVarInt(in); + java.util.Map values = new java.util.LinkedHashMap<>(); + for (int j = 0; j < valueCount; j++) { + values.put(ConfigProfileValueCodec.readString(in), ConfigProfileValueCodec.readValue(in)); + } + entries.add(new ConfigProfileEntry(ownerId, displayName, values)); + } + return entries; + } + + private byte[] compress(byte[] bytes) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Deflater deflater = new Deflater(Deflater.BEST_SPEED); + try (DeflaterOutputStream zip = new DeflaterOutputStream(out, deflater)) { + zip.write(bytes); + } finally { + deflater.end(); + } + return out.toByteArray(); + } + + private byte[] decompress(byte[] bytes) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (InflaterInputStream zip = new InflaterInputStream(new ByteArrayInputStream(bytes))) { + zip.transferTo(out); + } + return out.toByteArray(); + } + + private record Header(ConfigProfileMeta meta, int flags, int payloadLength) { + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileCollector.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileCollector.java new file mode 100644 index 0000000..36201bf --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileCollector.java @@ -0,0 +1,106 @@ +/* + * 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.config.profile; + + +import dev.loki.lovisual.features.theme.Theme; +import net.minecraft.client.Minecraft; +import dev.loki.lovisual.config.ConfigObject; +import dev.loki.lovisual.config.values.ConfigValue; +import dev.loki.lovisual.addon.AddonManager; +import dev.loki.lovisual.features.gui.hud.AbstractHudElement; +import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElement; +import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; +import dev.loki.lovisual.features.gui.hud.nondraggable.StaticHudElementRegistry; +import dev.loki.lovisual.features.theme.Themes; +import dev.loki.lovisual.features.module.Module; +import dev.loki.lovisual.features.module.ModuleManager; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class ConfigProfileCollector { + public ConfigProfileSnapshot collect(ConfigProfileType type, String name) { + long now = System.currentTimeMillis(); + String safeName = (name == null || name.isBlank()) ? defaultName(type) : name.trim(); + String id = ConfigProfileStorage.sanitizeFileName(safeName); + ConfigProfileMeta meta = new ConfigProfileMeta( + id, + safeName, + type, + currentAuthorName(), + now, + now, + ConfigProfileBinaryCodec.VERSION + ); + return new ConfigProfileSnapshot(meta, collectEntries(type)); + } + + public ConfigProfileSnapshot collectWithMeta(ConfigProfileMeta meta) { + if (meta == null) throw new IllegalArgumentException("profile meta is null"); + return new ConfigProfileSnapshot(meta, collectEntries(meta.type())); + } + + public List collectEntries(ConfigProfileType type) { + List entries = new ArrayList<>(); + if (type == ConfigProfileType.HUD) { + for (DraggableHudElement widget : DraggableHudElementRegistry.getWidgets()) { + String ownerId = AddonManager.draggableHudProfileOwnerId(widget.getId()); + entries.add(entry(ownerId, AddonManager.profileDisplayName(ownerId, widget.getTitle()), widget)); + } + for (AbstractHudElement element : StaticHudElementRegistry.getAll()) { + String ownerId = AddonManager.staticHudProfileOwnerId(element.getId()); + entries.add(entry(ownerId, AddonManager.profileDisplayName(ownerId, element.getTitle()), element)); + } + } else if (type == ConfigProfileType.THEMES) { + Map state = new LinkedHashMap<>(); + state.put("current", Theme.currentId()); + entries.add(new ConfigProfileEntry("theme-state:current", "Current Theme", state)); + for (Themes.ThemeEntry theme : Theme.customThemes()) { + entries.add(new ConfigProfileEntry("theme:" + theme.getId(), theme.name(), Themes.toProfileValues(theme))); + } + } else { + for (Module module : ModuleManager.getModules()) { + String ownerId = AddonManager.moduleProfileOwnerId(module.name()); + entries.add(entry(ownerId, AddonManager.profileDisplayName(ownerId, module.getDisplayName()), module)); + } + } + return entries; + } + + private ConfigProfileEntry entry(String ownerId, String displayName, ConfigObject owner) { + Map values = new LinkedHashMap<>(); + if (owner != null) { + for (ConfigValue value : owner.getConfigValues()) { + if (value != null && value.getName() != null) { + values.put(value.getName(), value.toJson()); + } + } + } + return new ConfigProfileEntry(ownerId, displayName, values); + } + + private String currentAuthorName() { + try { + Minecraft mc = Minecraft.getInstance(); + if (mc != null && mc.getUser() != null) { + String username = mc.getUser().getName(); + if (username != null && !username.isBlank()) return username; + } + } catch (Throwable ignored) { + } + // TODO: use Discord RPC nickname/avatar when Discord integration is ready. + return "Unknown"; + } + + private String defaultName(ConfigProfileType type) { + return type == ConfigProfileType.HUD ? "Hud Config" : type == ConfigProfileType.THEMES ? "Themes Config" : "Modules Config"; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDateFormatter.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDateFormatter.java new file mode 100644 index 0000000..10ed18f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDateFormatter.java @@ -0,0 +1,37 @@ +/* + * 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.config.profile; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; + +public enum ConfigProfileDateFormatter { + ; + private static final DateTimeFormatter DATE = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + private static final DateTimeFormatter TIME = DateTimeFormatter.ofPattern("HH:mm"); + + public static String created(ConfigProfileMeta meta) { + return DATE.format(toDate(meta.createdAt())); + } + + public static String updated(ConfigProfileMeta meta) { + LocalDate created = toDate(meta.createdAt()); + LocalDate updated = toDate(meta.updatedAt()); + String text = DATE.format(updated); + if (created.equals(updated)) { + text += " (" + TIME.format(Instant.ofEpochMilli(meta.updatedAt()).atZone(ZoneId.systemDefault())) + ")"; + } + return text; + } + + private static LocalDate toDate(long epochMillis) { + return Instant.ofEpochMilli(epochMillis).atZone(ZoneId.systemDefault()).toLocalDate(); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDiff.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDiff.java new file mode 100644 index 0000000..862ac8c --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDiff.java @@ -0,0 +1,57 @@ +/* + * 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.config.profile; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public record ConfigProfileDiff( + ConfigProfileType type, + List entries +) { + public ConfigProfileDiff { + if (type == null) type = ConfigProfileType.MODULES; + List copy = new ArrayList<>(); + if (entries != null) copy.addAll(entries); + entries = Collections.unmodifiableList(copy); + } + + public boolean isEmpty() { + return entries.isEmpty(); + } + + public int valueChangeCount() { + int count = 0; + for (Entry entry : entries) count += entry.values().size(); + return count; + } + + public enum Kind { + ADDED, + REMOVED, + CHANGED + } + + public record Entry(String ownerId, String displayName, List values) { + public Entry { + if (ownerId == null) ownerId = ""; + if (displayName == null || displayName.isBlank()) displayName = ownerId; + List copy = new ArrayList<>(); + if (values != null) copy.addAll(values); + values = Collections.unmodifiableList(copy); + } + } + + public record Value(String key, Object currentValue, Object selectedValue, Kind kind) { + public Value { + if (key == null) key = ""; + if (kind == null) kind = Kind.CHANGED; + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDiffEngine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDiffEngine.java new file mode 100644 index 0000000..3869a3a --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileDiffEngine.java @@ -0,0 +1,64 @@ +/* + * 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.config.profile; + +import java.util.*; + +public final class ConfigProfileDiffEngine { + public ConfigProfileDiff compare(ConfigProfileSnapshot current, ConfigProfileSnapshot selected) { + if (current == null || selected == null) { + return new ConfigProfileDiff(ConfigProfileType.MODULES, List.of()); + } + ConfigProfileType type = selected.meta().type(); + Map currentMap = mapByOwner(current); + Map selectedMap = mapByOwner(selected); + + Set owners = new LinkedHashSet<>(); + owners.addAll(currentMap.keySet()); + owners.addAll(selectedMap.keySet()); + + List entries = new ArrayList<>(); + for (String ownerId : owners) { + ConfigProfileEntry c = currentMap.get(ownerId); + ConfigProfileEntry s = selectedMap.get(ownerId); + String displayName = s != null ? s.displayName() : c != null ? c.displayName() : ownerId; + Map cv = c != null ? c.values() : Map.of(); + Map sv = s != null ? s.values() : Map.of(); + + Set keys = new LinkedHashSet<>(); + keys.addAll(cv.keySet()); + keys.addAll(sv.keySet()); + + List values = new ArrayList<>(); + for (String key : keys) { + boolean hasCurrent = cv.containsKey(key); + boolean hasSelected = sv.containsKey(key); + Object currentValue = cv.get(key); + Object selectedValue = sv.get(key); + if (hasCurrent && hasSelected && Objects.equals(currentValue, selectedValue)) continue; + ConfigProfileDiff.Kind kind; + if (!hasCurrent) kind = ConfigProfileDiff.Kind.ADDED; + else if (!hasSelected) kind = ConfigProfileDiff.Kind.REMOVED; + else kind = ConfigProfileDiff.Kind.CHANGED; + values.add(new ConfigProfileDiff.Value(key, currentValue, selectedValue, kind)); + } + if (!values.isEmpty()) { + entries.add(new ConfigProfileDiff.Entry(ownerId, displayName, values)); + } + } + return new ConfigProfileDiff(type, entries); + } + + private Map mapByOwner(ConfigProfileSnapshot snapshot) { + Map map = new LinkedHashMap<>(); + for (ConfigProfileEntry entry : snapshot.entries()) { + map.put(entry.ownerId(), entry); + } + return map; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileEntry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileEntry.java new file mode 100644 index 0000000..9eafbae --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileEntry.java @@ -0,0 +1,26 @@ +/* + * 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.config.profile; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +public record ConfigProfileEntry( + String ownerId, + String displayName, + Map values +) { + public ConfigProfileEntry { + if (ownerId == null) ownerId = ""; + if (displayName == null || displayName.isBlank()) displayName = ownerId; + Map copy = new LinkedHashMap<>(); + if (values != null) copy.putAll(values); + values = Collections.unmodifiableMap(copy); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileMeta.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileMeta.java new file mode 100644 index 0000000..2e7b074 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileMeta.java @@ -0,0 +1,39 @@ +/* + * 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.config.profile; + +public record ConfigProfileMeta( + String id, + String name, + ConfigProfileType type, + String author, + long createdAt, + long updatedAt, + int version +) { + public ConfigProfileMeta { + if (id == null || id.isBlank()) id = ConfigProfileStorage.sanitizeFileName(name); + if (name == null || name.isBlank()) name = id; + if (type == null) type = ConfigProfileType.MODULES; + if (author == null || author.isBlank()) author = "Unknown"; + if (version <= 0) version = ConfigProfileBinaryCodec.VERSION; + } + + public ConfigProfileMeta withUpdatedAt(long timestamp) { + return new ConfigProfileMeta(id, name, type, author, createdAt, timestamp, version); + } + + public String getId() { + return id; + } + + public ConfigProfileMeta withName(String nextName, long timestamp) { + String nextId = ConfigProfileStorage.sanitizeFileName(nextName); + return new ConfigProfileMeta(nextId, nextName, type, author, createdAt, timestamp, version); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileService.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileService.java new file mode 100644 index 0000000..475f75d --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileService.java @@ -0,0 +1,101 @@ +/* + * 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.config.profile; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +public final class ConfigProfileService { + public static final ConfigProfileService INSTANCE = new ConfigProfileService(); + + private final ConfigProfileStorage storage = new ConfigProfileStorage(); + private final ConfigProfileCollector collector = new ConfigProfileCollector(); + private final ConfigProfileApplier applier = new ConfigProfileApplier(); + private final ConfigProfileDiffEngine diffEngine = new ConfigProfileDiffEngine(); + + private ConfigProfileService() { + } + + public ConfigProfileStorage storage() { + return storage; + } + + public List list(ConfigProfileType type) { + return storage.list(type); + } + + public ConfigProfileSnapshot saveCurrent(ConfigProfileType type, String name) throws IOException { + ConfigProfileMeta old = find(type, name); + ConfigProfileSnapshot snapshot = collector.collect(type, name); + if (old != null) { + ConfigProfileMeta meta = new ConfigProfileMeta( + old.getId(), + old.name(), + old.type(), + old.author(), + old.createdAt(), + System.currentTimeMillis(), + ConfigProfileBinaryCodec.VERSION + ); + snapshot = collector.collectWithMeta(meta); + } + storage.save(snapshot); + return snapshot; + } + + public ConfigProfileSnapshot overwriteCurrent(ConfigProfileMeta target) throws IOException { + if (target == null) throw new IllegalArgumentException("profile meta is null"); + ConfigProfileMeta meta = target.withUpdatedAt(System.currentTimeMillis()); + ConfigProfileSnapshot snapshot = collector.collectWithMeta(meta); + storage.save(snapshot); + return snapshot; + } + + public ConfigProfileSnapshot read(ConfigProfileType type, String idOrName) throws IOException { + return storage.read(type, idOrName); + } + + public ConfigProfileApplier.ApplyResult apply(ConfigProfileType type, String idOrName) throws IOException { + return applier.apply(storage.read(type, idOrName)); + } + + public ConfigProfileDiff diffWithCurrent(ConfigProfileType type, String idOrName) throws IOException { + ConfigProfileSnapshot selected = storage.read(type, idOrName); + ConfigProfileSnapshot current = collector.collectWithMeta(new ConfigProfileMeta( + "__current__", + "Current", + type, + "Runtime", + System.currentTimeMillis(), + System.currentTimeMillis(), + ConfigProfileBinaryCodec.VERSION + )); + return diffEngine.compare(current, selected); + } + + public ConfigProfileSnapshot rename(ConfigProfileType type, String idOrName, String newName) throws IOException { + return storage.rename(type, idOrName, newName); + } + + public boolean delete(ConfigProfileType type, String idOrName) throws IOException { + return storage.delete(type, idOrName); + } + + public ConfigProfileStorage.ImportResult importProfileFile(Path source, boolean moveSource) throws IOException { + return storage.importProfileFile(source, moveSource); + } + + private ConfigProfileMeta find(ConfigProfileType type, String name) { + String id = ConfigProfileStorage.sanitizeFileName(name); + for (ConfigProfileMeta meta : storage.list(type)) { + if (meta.getId().equals(id)) return meta; + } + return null; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileSnapshot.java new file mode 100644 index 0000000..2c46342 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileSnapshot.java @@ -0,0 +1,24 @@ +/* + * 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.config.profile; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public record ConfigProfileSnapshot( + ConfigProfileMeta meta, + List entries +) { + public ConfigProfileSnapshot { + if (meta == null) throw new IllegalArgumentException("profile meta is null"); + List copy = new ArrayList<>(); + if (entries != null) copy.addAll(entries); + entries = Collections.unmodifiableList(copy); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileStorage.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileStorage.java new file mode 100644 index 0000000..1ecb8c4 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileStorage.java @@ -0,0 +1,179 @@ +/* + * 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.config.profile; + +import dev.loki.lovisual.config.ConfigPaths; +import dev.loki.lovisual.util.logging.DebugLog; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; + +public final class ConfigProfileStorage { + public static final String EXTENSION = ".cbcfg"; + private static final Path ROOT = ConfigPaths.profilesRoot(); + + private final ConfigProfileBinaryCodec codec = new ConfigProfileBinaryCodec(); + + public static String sanitizeFileName(String name) { + if (name == null) return "config"; + String base = name.trim().toLowerCase(Locale.ROOT); + if (base.endsWith(EXTENSION)) base = base.substring(0, base.length() - EXTENSION.length()); + if (base.isEmpty()) return "config"; + StringBuilder out = new StringBuilder(base.length()); + for (int i = 0; i < base.length(); i++) { + char c = base.charAt(i); + if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '.') { + out.append(c); + } else { + out.append('_'); + } + } + return out.length() == 0 ? "config" : out.toString(); + } + + public Path root() { + return ROOT; + } + + public Path directory(ConfigProfileType type) { + return ROOT.resolve(type.folderName()); + } + + public List list(ConfigProfileType type) { + normalizeLooseProfiles(); + List out = new ArrayList<>(); + Path dir = directory(type); + if (!Files.isDirectory(dir)) return out; + try (var stream = Files.list(dir)) { + stream.filter(path -> Files.isRegularFile(path) && path.getFileName().toString().endsWith(EXTENSION)) + .forEach(path -> { + try { + ConfigProfileMeta meta = codec.readMeta(Files.readAllBytes(path)); + out.add(meta); + } catch (Exception e) { + DebugLog.error("Failed to read profile meta %s", e, path.toAbsolutePath()); + } + }); + } catch (IOException e) { + DebugLog.error("Failed to list profiles %s", e, dir.toAbsolutePath()); + } + out.sort(Comparator.comparingLong(ConfigProfileMeta::updatedAt).reversed()); + return out; + } + + public ImportResult importProfileFile(Path source, boolean moveSource) throws IOException { + if (source == null) throw new IllegalArgumentException("profile path is null"); + if (!Files.isRegularFile(source)) throw new IOException("profile is not a regular file: " + source); + String fileName = source.getFileName() == null ? "" : source.getFileName().toString(); + if (!fileName.toLowerCase(Locale.ROOT).endsWith(EXTENSION)) { + throw new IOException("not a " + EXTENSION + " profile: " + source); + } + + byte[] bytes = Files.readAllBytes(source); + ConfigProfileMeta meta = codec.read(bytes).meta(); + Path dest = file(meta.type(), meta.getId()); + Files.createDirectories(dest.getParent()); + + Path sourceAbs = source.toAbsolutePath().normalize(); + Path destAbs = dest.toAbsolutePath().normalize(); + if (!sourceAbs.equals(destAbs)) { + if (moveSource) { + Files.move(source, dest, StandardCopyOption.REPLACE_EXISTING); + } else { + Files.write(dest, bytes); + } + } + return new ImportResult(meta, dest); + } + + public ConfigProfileSnapshot read(ConfigProfileType type, String idOrName) throws IOException { + Path path = file(type, idOrName); + return codec.read(Files.readAllBytes(path)); + } + + public ConfigProfileSnapshot read(ConfigProfileMeta meta) throws IOException { + if (meta == null) throw new IllegalArgumentException("profile meta is null"); + return read(meta.type(), meta.getId()); + } + + public void save(ConfigProfileSnapshot snapshot) throws IOException { + if (snapshot == null) throw new IllegalArgumentException("snapshot is null"); + Files.createDirectories(directory(snapshot.meta().type())); + Path path = file(snapshot.meta().type(), snapshot.meta().getId()); + Files.write(path, codec.write(snapshot)); + DebugLog.config("Config profile saved: %s", path.toAbsolutePath()); + } + + public boolean delete(ConfigProfileType type, String idOrName) throws IOException { + Path path = file(type, idOrName); + return Files.deleteIfExists(path); + } + + public ConfigProfileSnapshot rename(ConfigProfileType type, String idOrName, String newName) throws IOException { + if (newName == null || newName.isBlank()) throw new IllegalArgumentException("profile name is blank"); + ConfigProfileSnapshot old = read(type, idOrName); + ConfigProfileMeta oldMeta = old.meta(); + ConfigProfileMeta newMeta = oldMeta.withName(newName.trim(), System.currentTimeMillis()); + Path oldPath = file(type, oldMeta.getId()); + Path newPath = file(type, newMeta.getId()); + if (!oldMeta.getId().equals(newMeta.getId()) && Files.exists(newPath)) { + throw new IOException("profile already exists: " + newMeta.name()); + } + ConfigProfileSnapshot renamed = new ConfigProfileSnapshot(newMeta, old.entries()); + save(renamed); + if (!oldPath.equals(newPath)) Files.deleteIfExists(oldPath); + return renamed; + } + + public boolean exists(ConfigProfileType type, String idOrName) { + return Files.exists(file(type, idOrName)); + } + + public Path file(ConfigProfileType type, String idOrName) { + String id = sanitizeFileName(idOrName); + if (!id.endsWith(EXTENSION)) id += EXTENSION; + return directory(type).resolve(id); + } + + private void normalizeLooseProfiles() { + if (!Files.isDirectory(ROOT)) return; + List candidates = new ArrayList<>(); + try (var stream = Files.walk(ROOT)) { + stream.filter(Files::isRegularFile) + .filter(path -> path.getFileName().toString().toLowerCase(Locale.ROOT).endsWith(EXTENSION)) + .forEach(candidates::add); + } catch (IOException e) { + DebugLog.error("Failed to scan loose config profiles %s", e, ROOT.toAbsolutePath()); + return; + } + + for (Path candidate : candidates) { + try { + ConfigProfileMeta meta = codec.read(Files.readAllBytes(candidate)).meta(); + Path dest = file(meta.type(), meta.getId()); + Path candidateAbs = candidate.toAbsolutePath().normalize(); + Path destAbs = dest.toAbsolutePath().normalize(); + if (candidateAbs.equals(destAbs)) continue; + Files.createDirectories(dest.getParent()); + Files.move(candidate, dest, StandardCopyOption.REPLACE_EXISTING); + DebugLog.config("Moved config profile %s -> %s", candidateAbs, destAbs); + } catch (Exception e) { + DebugLog.error("Failed to normalize config profile %s", e, candidate.toAbsolutePath()); + } + } + } + + public record ImportResult(ConfigProfileMeta meta, Path path) { + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileType.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileType.java new file mode 100644 index 0000000..28f7fe6 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileType.java @@ -0,0 +1,50 @@ +/* + * 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.config.profile; + +import java.util.Locale; + +public enum ConfigProfileType { + MODULES((byte) 0, "modules"), + HUD((byte) 1, "hud"), + THEMES((byte) 2, "themes"); + + private final byte wireId; + private final String folderName; + + ConfigProfileType(byte wireId, String folderName) { + this.wireId = wireId; + this.folderName = folderName; + } + + public static ConfigProfileType fromWireId(int id) { + for (ConfigProfileType type : values()) { + if ((type.wireId & 0xFF) == id) return type; + } + throw new IllegalArgumentException("Unknown profile type id: " + id); + } + + public static ConfigProfileType fromName(String name) { + if (name == null) return MODULES; + String normalized = name.trim().toLowerCase(Locale.ROOT); + for (ConfigProfileType type : values()) { + if (type.name().toLowerCase(Locale.ROOT).equals(normalized) || type.folderName.equals(normalized)) { + return type; + } + } + return MODULES; + } + + public byte wireId() { + return wireId; + } + + public String folderName() { + return folderName; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileValueCodec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileValueCodec.java new file mode 100644 index 0000000..ec84439 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/profile/ConfigProfileValueCodec.java @@ -0,0 +1,136 @@ +/* + * 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.config.profile; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +enum ConfigProfileValueCodec { + ; + private static final byte NULL = 0; + private static final byte BOOLEAN = 1; + private static final byte INT = 2; + private static final byte LONG = 3; + private static final byte FLOAT = 4; + private static final byte DOUBLE = 5; + private static final byte STRING = 6; + private static final byte LIST = 7; + private static final byte MAP = 8; + + static void writeValue(DataOutputStream out, Object value) throws IOException { + if (value == null) { + out.writeByte(NULL); + } else if (value instanceof Boolean b) { + out.writeByte(BOOLEAN); + out.writeBoolean(b); + } else if (value instanceof Integer i) { + out.writeByte(INT); + writeVarInt(out, i); + } else if (value instanceof Long l) { + out.writeByte(LONG); + out.writeLong(l); + } else if (value instanceof Float f) { + out.writeByte(FLOAT); + out.writeFloat(f); + } else if (value instanceof Number n) { + out.writeByte(DOUBLE); + out.writeDouble(n.doubleValue()); + } else if (value instanceof CharSequence s) { + out.writeByte(STRING); + writeString(out, s.toString()); + } else if (value instanceof Iterable iterable) { + out.writeByte(LIST); + List list = new ArrayList<>(); + for (Object item : iterable) list.add(item); + writeVarInt(out, list.size()); + for (Object item : list) writeValue(out, item); + } else if (value instanceof Map map) { + out.writeByte(MAP); + writeVarInt(out, map.size()); + for (Map.Entry entry : map.entrySet()) { + writeString(out, String.valueOf(entry.getKey())); + writeValue(out, entry.getValue()); + } + } else { + out.writeByte(STRING); + writeString(out, String.valueOf(value)); + } + } + + static Object readValue(DataInputStream in) throws IOException { + int type = in.readUnsignedByte(); + return switch (type) { + case NULL -> null; + case BOOLEAN -> in.readBoolean(); + case INT -> readVarInt(in); + case LONG -> in.readLong(); + case FLOAT -> in.readFloat(); + case DOUBLE -> in.readDouble(); + case STRING -> readString(in); + case LIST -> { + int size = readVarInt(in); + List list = new ArrayList<>(Math.max(0, size)); + for (int i = 0; i < size; i++) list.add(readValue(in)); + yield list; + } + case MAP -> { + int size = readVarInt(in); + Map map = new LinkedHashMap<>(); + for (int i = 0; i < size; i++) { + map.put(readString(in), readValue(in)); + } + yield map; + } + default -> throw new IOException("Unknown profile value type: " + type); + }; + } + + static void writeString(DataOutputStream out, String value) throws IOException { + if (value == null) value = ""; + byte[] bytes = value.getBytes(StandardCharsets.UTF_8); + writeVarInt(out, bytes.length); + out.write(bytes); + } + + static String readString(DataInputStream in) throws IOException { + int length = readVarInt(in); + if (length < 0) throw new IOException("Negative string length: " + length); + byte[] bytes = new byte[length]; + in.readFully(bytes); + return new String(bytes, StandardCharsets.UTF_8); + } + + static void writeVarInt(DataOutputStream out, int value) throws IOException { + int v = value; + while ((v & 0xFFFFFF80) != 0L) { + out.writeByte((v & 0x7F) | 0x80); + v >>>= 7; + } + out.writeByte(v & 0x7F); + } + + static int readVarInt(DataInputStream in) throws IOException { + int numRead = 0; + int result = 0; + byte read; + do { + read = in.readByte(); + int value = (read & 0x7F); + result |= (value << (7 * numRead)); + numRead++; + if (numRead > 5) throw new IOException("VarInt is too big"); + } while ((read & 0x80) != 0); + return result; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BindMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BindMode.java new file mode 100644 index 0000000..5653127 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BindMode.java @@ -0,0 +1,13 @@ +/* + * 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.config.values; + +public enum BindMode { + PRESS, + HOLD +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BooleanMapValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BooleanMapValue.java new file mode 100644 index 0000000..fda8e31 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BooleanMapValue.java @@ -0,0 +1,60 @@ +/* + * 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.config.values; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class BooleanMapValue extends ConfigValue> { + + private final Map defaults = new LinkedHashMap<>(); + + public BooleanMapValue(String name, Map defaults) { + super(name, new LinkedHashMap<>()); + this.defaults.putAll(defaults); + value.putAll(defaults); + } + + public Map getAll() { + return value; + } + + public boolean get(String key) { + return value.getOrDefault(key, false); + } + + public void set(String key, boolean val) { + value.put(key, val); + } + + @Override + public Object toJson() { + return new LinkedHashMap<>(value); + } + + @Override + public void fromJson(Object json) { + value.clear(); + // start with defaults so new keys always exist + value.putAll(defaults); + if (json instanceof Map map) { + for (var entry : map.entrySet()) { + if (entry.getKey() instanceof String key && + entry.getValue() instanceof Boolean b && + defaults.containsKey(key)) { + value.put(key, b); + } + } + } + } + + @Override + public String toDisplay() { + return value.toString(); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BooleanValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BooleanValue.java new file mode 100644 index 0000000..4fa7c46 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/BooleanValue.java @@ -0,0 +1,26 @@ +/* + * 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.config.values; + +public class BooleanValue extends ConfigValue { + + public BooleanValue(String name, boolean def) { + super(name, def); + } + + @Override + public Object toJson() { + return value; + } + + @Override + public void fromJson(Object json) { + if (json instanceof Boolean b) + value = b; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ColorValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ColorValue.java new file mode 100644 index 0000000..28d9571 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ColorValue.java @@ -0,0 +1,24 @@ +/* + * 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.config.values; + +public interface ColorValue { + String get(); + + void set(String value); + + int getArgb(); + + boolean supportsAlpha(); + + boolean isRainbow(); + + String toRainbowValue(); + + String rainbowFallbackHex(); +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ConfigValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ConfigValue.java new file mode 100644 index 0000000..9dfe61f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ConfigValue.java @@ -0,0 +1,62 @@ +/* + * 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.config.values; + +/** + * Базовый тип для всех конфиг-значений. + */ +public abstract class ConfigValue { + + private final String name; // <---- ЭТО ТЕБЕ НУЖНО + protected T value; + + public ConfigValue(String name, T def) { + this.name = name; + this.value = def; + } + + /** + * ключ в конфиге + */ + public String getName() { + return name; + } + + /** + * Текущее значение + */ + public T get() { + return value; + } + + /** + * Установить новое значение + */ + public void set(T v) { + this.value = v; + } + + /** + * Сериализация: + * Возвращает примитив (Boolean, Number, String) или структуру (Map/List). + */ + public abstract Object toJson(); + + /** + * Десериализация: + * На вход прилетает то же самое, что было возвращено в toJson(). + */ + public abstract void fromJson(Object json); + + /** + * Для UI + */ + public String toDisplay() { + return String.valueOf(value); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/EnumIds.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/EnumIds.java new file mode 100644 index 0000000..07dbc58 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/EnumIds.java @@ -0,0 +1,19 @@ +/* + * 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.config.values; + +import java.util.Locale; + +public enum EnumIds { + ; + + public static String defaultId(Enum value) { + if (value == null) return ""; + return value.name().toLowerCase(Locale.ROOT); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/EnumValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/EnumValue.java new file mode 100644 index 0000000..bbe9234 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/EnumValue.java @@ -0,0 +1,115 @@ +/* + * 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.config.values; + +import java.util.*; + +public class EnumValue> extends ConfigValue { + + private final List options; + private final List optionIds; + private final Map lookup; + public EnumValue(String name, E def, Class enumClass) { + this(name, def, enumClass.getEnumConstants()); + } + @SafeVarargs + public EnumValue(String name, E def, E... opts) { + super(name, def); + this.options = List.of(opts); + this.optionIds = new ArrayList<>(options.size()); + this.lookup = new HashMap<>(); + + for (E opt : options) { + String id = idOf(opt); + optionIds.add(id); + lookup.put(normalize(id), opt); + } + + for (E opt : options) { + if (!(opt instanceof AliasProvider aliasProvider)) continue; + List aliases = aliasProvider.aliases(); + if (aliases == null) continue; + for (String alias : aliases) { + if (alias == null || alias.isBlank()) continue; + lookup.putIfAbsent(normalize(alias), opt); + } + } + + if (!options.contains(def) && !options.isEmpty()) { + this.value = options.get(0); + } + } + + private static String normalize(String id) { + return id == null ? "" : id.toLowerCase(Locale.ROOT); + } + + public List getOptions() { + return optionIds; + } + + public String getId() { + return idOf(value); + } + + public void setById(String id) { + if (id == null) return; + E resolved = lookup.get(normalize(id)); + if (resolved != null) { + value = resolved; + } + } + + @Override + public Object toJson() { + return getId(); + } + + @Override + public void fromJson(Object json) { + if (json instanceof String s) { + setById(s); + } + } + + private String idOf(E value) { + if (value instanceof IdProvider idProvider) { + return idProvider.getId(); + } + return EnumIds.defaultId(value); + } + + public interface IdProvider { + default String getId() { + return id(); + } + + default String id() { + try { + var method = getClass().getMethod("getId"); + if (method.getReturnType() == String.class && method.getParameterCount() == 0) { + return (String) method.invoke(this); + } + } catch (ReflectiveOperationException ignored) { + // Fall back to the enum name below. + } + + if (this instanceof Enum enumValue) { + return EnumIds.defaultId(enumValue); + } + + return ""; + } + } + + public interface AliasProvider { + default List aliases() { + return List.of(); + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ItemCooldownRulesValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ItemCooldownRulesValue.java new file mode 100644 index 0000000..4e48cc3 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ItemCooldownRulesValue.java @@ -0,0 +1,326 @@ +/* + * 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.config.values; + +import java.util.*; + +/** + * Object-shaped per-item PvP cooldown rules. + *

+ * JSON shape: + * { + * "minecraft:golden_apple": { + * "enabled": false, + * "seconds": 30, + * "uses": 2, + * "window_seconds": 10, + * "scope": "pvp_grace", + * "trigger": "consume_finish", + * "block_use": false, + * "block_mode": "none" + * } + * } + */ +public class ItemCooldownRulesValue extends ConfigValue> { + + private final Map defaults = new LinkedHashMap<>(); + + public ItemCooldownRulesValue(String name, Map defaults) { + super(name, new LinkedHashMap<>()); + if (defaults != null) { + for (var entry : defaults.entrySet()) { + String id = normalizeItemId(entry.getKey()); + Rule rule = entry.getValue(); + if (id != null && rule != null) { + this.defaults.put(id, rule.normalized()); + } + } + } + value.putAll(this.defaults); + } + + public static String normalizeItemId(String id) { + if (id == null) return null; + String s = id.trim().toLowerCase(Locale.ROOT); + if (s.isEmpty()) return null; + if (!s.contains(":")) s = "minecraft:" + s; + return s; + } + + public Rule getRule(String itemId) { + String normalized = normalizeItemId(itemId); + if (normalized == null) return null; + return value.get(normalized); + } + + public Rule getDefaultRule(String itemId) { + String normalized = normalizeItemId(itemId); + if (normalized != null) { + Rule configuredDefault = defaults.get(normalized); + if (configuredDefault != null) return configuredDefault; + } + return new Rule(false, 30, 1, 0, Scope.PVP_GRACE, Trigger.CONSUME_FINISH, UseBlockMode.NONE); + } + + public Rule ensureRule(String itemId) { + String normalized = normalizeItemId(itemId); + if (normalized == null) return null; + Rule existing = value.get(normalized); + if (existing != null) return existing; + Rule created = getDefaultRule(normalized).normalized(); + value.put(normalized, created); + return created; + } + + public void putRule(String itemId, Rule rule) { + String normalized = normalizeItemId(itemId); + if (normalized == null || rule == null) return; + value.put(normalized, rule.normalized()); + } + + public void removeRule(String itemId) { + String normalized = normalizeItemId(itemId); + if (normalized == null) return; + value.remove(normalized); + } + + public boolean containsRule(String itemId) { + String normalized = normalizeItemId(itemId); + return normalized != null && value.containsKey(normalized); + } + + public Map getRules() { + return value; + } + + public Set getItemIds() { + return new LinkedHashSet<>(value.keySet()); + } + + @Override + public Object toJson() { + Map out = new LinkedHashMap<>(); + for (var entry : value.entrySet()) { + if (entry.getKey() == null || entry.getValue() == null) continue; + out.put(entry.getKey(), entry.getValue().toJson()); + } + return out; + } + + @Override + public void fromJson(Object json) { + value.clear(); + value.putAll(defaults); + + if (!(json instanceof Map map)) return; + + for (var entry : map.entrySet()) { + if (!(entry.getKey() instanceof String rawKey)) continue; + String itemId = normalizeItemId(rawKey); + if (itemId == null) continue; + + Rule base = value.getOrDefault(itemId, Rule.DEFAULT); + Rule parsed = Rule.fromJson(entry.getValue(), base); + if (parsed != null) { + value.put(itemId, parsed.normalized()); + } + } + } + + @Override + public String toDisplay() { + return value.toString(); + } + + public enum Scope implements EnumValue.IdProvider { + ALWAYS("always"), + PVP_ONLY("pvp_only"), + PVP_GRACE("pvp_grace"); + + private final String id; + + Scope(String id) { + this.id = id; + } + + static Scope parse(Object value, Scope fallback) { + if (value instanceof String s) { + String normalized = s.trim().toLowerCase(Locale.ROOT); + for (Scope scope : values()) { + if (scope.id.equals(normalized) || scope.name().equalsIgnoreCase(normalized)) { + return scope; + } + } + } + return fallback; + } + + @Override + public String id() { + return id; + } + } + + public enum Trigger implements EnumValue.IdProvider { + INTERACT_ACCEPT("interact_accept"), + CONSUME_FINISH("consume_finish"), + TOTEM_POP("totem_pop"); + + private final String id; + + Trigger(String id) { + this.id = id; + } + + static Trigger parse(Object value, Trigger fallback) { + if (value instanceof String s) { + String normalized = s.trim().toLowerCase(Locale.ROOT); + for (Trigger trigger : values()) { + if (trigger.id.equals(normalized) || trigger.name().equalsIgnoreCase(normalized)) { + return trigger; + } + } + } + return fallback; + } + + @Override + public String id() { + return id; + } + } + + public enum UseBlockMode implements EnumValue.IdProvider { + NONE("none"), + COOLDOWN("cooldown"), + WINDOW("window"), + ANY("any"); + + private final String id; + + UseBlockMode(String id) { + this.id = id; + } + + static UseBlockMode parse(Object value, UseBlockMode fallback) { + if (value instanceof String s) { + String normalized = s.trim().toLowerCase(Locale.ROOT); + for (UseBlockMode mode : values()) { + if (mode.id.equals(normalized) || mode.name().equalsIgnoreCase(normalized)) { + return mode; + } + } + } + return fallback; + } + + @Override + public String id() { + return id; + } + + public UseBlockMode next() { + UseBlockMode[] modes = values(); + return modes[(ordinal() + 1) % modes.length]; + } + } + + public record Rule(boolean enabled, + int seconds, + int uses, + int windowSeconds, + Scope scope, + Trigger trigger, + UseBlockMode blockMode) { + public static final Rule DEFAULT = new Rule(false, 0, 1, 0, Scope.PVP_GRACE, Trigger.CONSUME_FINISH, UseBlockMode.NONE); + + public Rule(boolean enabled, + int seconds, + int uses, + int windowSeconds, + Scope scope, + Trigger trigger, + boolean blockUse) { + this(enabled, seconds, uses, windowSeconds, scope, trigger, blockUse ? UseBlockMode.COOLDOWN : UseBlockMode.NONE); + } + + static Rule fromJson(Object json, Rule fallback) { + Rule base = fallback != null ? fallback : DEFAULT; + if (!(json instanceof Map map)) return base; + + boolean enabled = readBoolean(map, "enabled", base.enabled); + int seconds = readInt(map, "seconds", base.seconds); + int uses = readInt(map, "uses", base.uses); + int windowSeconds = readInt(map, "window_seconds", base.windowSeconds); + Scope scope = Scope.parse(map.get("scope"), base.scope); + Trigger trigger = Trigger.parse(map.get("trigger"), base.trigger); + UseBlockMode blockMode = UseBlockMode.parse(map.get("block_mode"), null); + if (blockMode == null) { + blockMode = readBoolean(map, "block_use", base.blockUse()) ? UseBlockMode.COOLDOWN : UseBlockMode.NONE; + } + + return new Rule(enabled, seconds, uses, windowSeconds, scope, trigger, blockMode); + } + + private static boolean readBoolean(Map map, String key, boolean fallback) { + Object value = map.get(key); + if (value instanceof Boolean b) return b; + if (value instanceof String s) return Boolean.parseBoolean(s.trim()); + return fallback; + } + + private static int readInt(Map map, String key, int fallback) { + Object value = map.get(key); + if (value instanceof Number n) return n.intValue(); + if (value instanceof String s) { + try { + return Integer.parseInt(s.trim()); + } catch (NumberFormatException ignored) { + return fallback; + } + } + return fallback; + } + + public Rule normalized() { + int safeSeconds = Math.max(0, Math.min(3600, seconds)); + int safeUses = Math.max(1, Math.min(64, uses)); + int safeWindow = Math.max(0, Math.min(3600, windowSeconds)); + return new Rule( + enabled, + safeSeconds, + safeUses, + safeWindow, + scope != null ? scope : Scope.PVP_GRACE, + trigger != null ? trigger : Trigger.CONSUME_FINISH, + blockMode != null ? blockMode : UseBlockMode.NONE + ); + } + + public boolean hasUseWindow() { + return uses > 1; + } + + public boolean blockUse() { + return blockMode != null && blockMode != UseBlockMode.NONE; + } + + Map toJson() { + Map out = new LinkedHashMap<>(); + out.put("enabled", enabled); + out.put("seconds", seconds); + out.put("uses", uses); + out.put("window_seconds", windowSeconds); + out.put("scope", scope.getId()); + out.put("trigger", trigger.getId()); + out.put("block_use", blockUse()); + out.put("block_mode", (blockMode != null ? blockMode : UseBlockMode.NONE).getId()); + return out; + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ItemIdSetValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ItemIdSetValue.java new file mode 100644 index 0000000..55ce55b --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ItemIdSetValue.java @@ -0,0 +1,81 @@ +/* + * 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.config.values; + +import dev.loki.lovisual.util.logging.DebugLog; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * Хранит набор item-id в формате namespace:path (minecraft:xxx). + */ +public class ItemIdSetValue extends ConfigValue> { + + public ItemIdSetValue(String name) { + super(name, new LinkedHashSet<>()); + } + + public ItemIdSetValue(String name, Set def) { + super(name, normalizeCopy(def)); + } + + private static LinkedHashSet normalizeCopy(Set source) { + LinkedHashSet copy = new LinkedHashSet<>(); + if (source == null) return copy; + + for (String s : source) { + String norm = normalizeStatic(s); + if (norm != null) copy.add(norm); + } + return copy; + } + + private static String normalizeStatic(String s) { + if (s == null || s.isBlank()) return null; + s = s.trim().toLowerCase(); + if (!s.contains(":")) s = "minecraft:" + s; + return s; + } + + @Override + public void set(Set v) { + super.set(normalizeCopy(v)); + log("set()", value); + } + + private String normalize(String s) { + return normalizeStatic(s); + } + + @Override + public Object toJson() { + log("toJson()", value); + return new java.util.ArrayList<>(value); + } + + @Override + public void fromJson(Object json) { + if (json instanceof List list) { + LinkedHashSet copy = new LinkedHashSet<>(); + for (Object o : list) { + if (o instanceof String s) { + String norm = normalize(s); + if (norm != null) copy.add(norm); + } + } + value = copy; + log("fromJson()", value); + } + } + + private void log(String stage, Set data) { + DebugLog.config("[ItemIdSetValue %s] %s -> %s", getName(), stage, data); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/KeyBindValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/KeyBindValue.java new file mode 100644 index 0000000..15e94df --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/KeyBindValue.java @@ -0,0 +1,30 @@ +/* + * 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.config.values; + +public class KeyBindValue extends ConfigValue { + + public KeyBindValue(String name, String def) { + super(name, def == null ? "NONE" : def); + } + + @Override + public Object toJson() { + return value; + } + + @Override + public void fromJson(Object json) { + if (json instanceof String s) + this.value = s.toUpperCase(); + } + + public boolean isNone() { + return "NONE".equalsIgnoreCase(value); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ModeValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ModeValue.java new file mode 100644 index 0000000..3a4da98 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/ModeValue.java @@ -0,0 +1,77 @@ +/* + * 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.config.values; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +public class ModeValue extends ConfigValue { + + private final List options; + + public ModeValue(String name, String def, String... opts) { + super(name, def); + this.options = new ArrayList<>(Arrays.asList(opts)); + + // если default не валидный → ставим первый вариант + if (!options.contains(def)) { + this.value = options.get(0); + } + } + + public List getOptions() { + return List.copyOf(options); + } + + public boolean addOption(String option) { + String normalized = normalizeOption(option); + if (normalized.isEmpty() || options.contains(normalized)) return false; + options.add(normalized); + return true; + } + + public int addOptions(Collection values) { + if (values == null || values.isEmpty()) return 0; + int added = 0; + for (String value : values) { + if (addOption(value)) added++; + } + return added; + } + + public boolean removeOption(String option) { + String normalized = normalizeOption(option); + if (normalized.isEmpty()) return false; + if (Objects.equals(value, normalized)) return false; + return options.remove(normalized); + } + + public void next() { + int i = options.indexOf(value); + value = options.get((i + 1) % options.size()); + } + + @Override + public Object toJson() { + return value; + } + + @Override + public void fromJson(Object json) { + if (json instanceof String s && options.contains(s)) { + value = s; + } + } + + private static String normalizeOption(String option) { + return option == null ? "" : option.trim(); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/NumberValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/NumberValue.java new file mode 100644 index 0000000..42f4407 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/NumberValue.java @@ -0,0 +1,72 @@ +/* + * 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.config.values; + +import java.text.DecimalFormat; + +public class NumberValue extends ConfigValue { + + private final N min, max; + + public NumberValue(String name, N def, N min, N max) { + super(name, def); + this.min = min; + this.max = max; + clamp(); + } + + public N getMin() { + return min; + } + + public N getMax() { + return max; + } + + private void clamp() { + double v = value.doubleValue(); + double lo = min.doubleValue(); + double hi = max.doubleValue(); + + if (v < lo) value = castToType(lo); + else if (v > hi) value = castToType(hi); + } + + @SuppressWarnings("unchecked") + public N castToType(double v) { + if (value instanceof Integer) return (N) Integer.valueOf((int) v); + if (value instanceof Float) return (N) Float.valueOf((float) v); + if (value instanceof Long) return (N) Long.valueOf((long) v); + return (N) Double.valueOf(v); + } + + @Override + public Object toJson() { + double v = value.doubleValue(); + if (value instanceof Float || value instanceof Double) { + v = Math.round(v * 100d) / 100d; + } + return v; + } + + @Override + public void fromJson(Object json) { + if (json instanceof Number n) { + value = castToType(n.doubleValue()); + clamp(); + } + } + + @Override + public String toDisplay() { + if (value instanceof Float || value instanceof Double) { + return new DecimalFormat("0.##").format(value.doubleValue()); + } + return super.toDisplay(); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/RGBAColorValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/RGBAColorValue.java new file mode 100644 index 0000000..8b2563d --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/RGBAColorValue.java @@ -0,0 +1,181 @@ +/* + * 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.config.values; + +import dev.loki.lovisual.render.engine.color.ColorUtils; + +/** + * Keeps color as hex-string and provides access as ARGB int. + * Supported formats: #RRGGBB, #AARRGGBB, 0xRRGGBB, 0xAARRGGBB. + */ +public class RGBAColorValue extends ConfigValue implements ColorValue { + + private static final int RAINBOW_SPEED = 18; + + public RGBAColorValue(String name, String defHex) { + super(name, normalize(defHex)); + } + + public static boolean isRainbowValue(String s) { + if (s == null) return false; + String t = s.trim().toUpperCase(); + return t.startsWith("RNB") || t.startsWith("RAINBOW"); + } + + public static boolean isRgbaValue(String s) { + if (s == null) return false; + String t = s.trim().toUpperCase(); + return t.startsWith("RGBA"); + } + + public static String toRainbow(String hex) { + int argb = parseToArgb(hex); + return "RNB#" + String.format("%08X", argb); + } + + public static String rainbowFallbackHex(String s) { + int argb = rainbowFallbackArgb(s); + return String.format("#%02X%02X%02X%02X", + (argb >>> 24) & 0xFF, + (argb >>> 16) & 0xFF, + (argb >>> 8) & 0xFF, + argb & 0xFF); + } + + private static String normalize(String s) { + if (s == null || s.isEmpty()) return "#FFFFFFFF"; // white + s = s.trim(); + if (isRainbowValue(s)) return normalizeRainbow(s); + boolean rgba = isRgbaValue(s); + if (rgba) { + s = stripRgbaPrefix(s); + } + if (s.startsWith("0x") || s.startsWith("0X")) s = s.substring(2); + if (!s.startsWith("#")) s = "#" + s; + s = s.toUpperCase(); + return rgba ? "RGBA" + s : s; + } + + private static String normalizeRainbow(String s) { + if (s == null) return "RNB"; + String upper = s.trim().toUpperCase(); + String tail = upper.startsWith("RAINBOW") ? upper.substring(7) : upper.substring(3); + tail = tail.trim(); + if (!tail.isEmpty() && (tail.charAt(0) == ':' || tail.charAt(0) == '=')) { + tail = tail.substring(1).trim(); + } + if (tail.startsWith("#")) tail = tail.substring(1); + if (tail.startsWith("0X")) tail = tail.substring(2); + StringBuilder hex = new StringBuilder(); + for (int i = 0; i < tail.length(); i++) { + char c = tail.charAt(i); + boolean digit = (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'); + if (digit) hex.append(c); + } + if (hex.length() == 6) hex.insert(0, "FF"); + if (hex.length() == 8) { + return "RNB#" + hex; + } + return "RNB"; + } + + private static int rainbowFallbackArgb(String s) { + if (s == null) return 0xFFFFFFFF; + int hash = s.indexOf('#'); + if (hash >= 0 && hash + 1 < s.length()) { + return parseToArgb(s.substring(hash)); + } + return 0xFFFFFFFF; + } + + private static int parseToArgb(String hex) { + if (hex == null || hex.isEmpty()) return 0xFFFFFFFF; + boolean rgba = isRgbaValue(hex); + String cleaned = rgba ? stripRgbaPrefix(hex) : hex; + String s = cleaned.startsWith("#") ? cleaned.substring(1) : cleaned; + if (s.startsWith("0x") || s.startsWith("0X")) s = s.substring(2); + long v; + try { + v = Long.parseUnsignedLong(s, 16); + } catch (NumberFormatException e) { + return 0xFFFFFFFF; + } + + if (s.length() == 6) { + return (int) (0xFF000000L | v); // add full alpha + } else if (s.length() == 8) { + int value = (int) v; + if (!rgba) { + return value; // AARRGGBB + } + int r = (value >>> 24) & 0xFF; + int g = (value >>> 16) & 0xFF; + int b = (value >>> 8) & 0xFF; + int a = value & 0xFF; + return (a << 24) | (r << 16) | (g << 8) | b; + } + return 0xFFFFFFFF; + } + + private static String stripRgbaPrefix(String s) { + if (s == null) return ""; + String t = s.trim(); + if (t.length() >= 4 && t.substring(0, 4).equalsIgnoreCase("RGBA")) { + t = t.substring(4).trim(); + if (!t.isEmpty()) { + char c = t.charAt(0); + if (c == ':' || c == '=') { + t = t.substring(1).trim(); + } + } + } + return t; + } + + @Override + public Object toJson() { + return value; + } + + @Override + public void fromJson(Object json) { + if (json instanceof String s) value = normalize(s); + } + + public int getArgb() { + if (isRainbowValue(value)) { + int fallback = rainbowFallbackArgb(value); + int alpha = (fallback >>> 24) & 0xFF; + float opacity = alpha / 255.0f; + return ColorUtils + .rainbow(RAINBOW_SPEED, 0, 1f, 1f, opacity) + .getRGB(); + } + return parseToArgb(value); + } + + @Override + public boolean supportsAlpha() { + return true; + } + + @Override + public boolean isRainbow() { + return isRainbowValue(value); + } + + @Override + public String toRainbowValue() { + return toRainbow(value); + } + + @Override + public String rainbowFallbackHex() { + return rainbowFallbackHex(value); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/RGBColorValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/RGBColorValue.java new file mode 100644 index 0000000..2ffcfda --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/RGBColorValue.java @@ -0,0 +1,143 @@ +/* + * 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.config.values; + +import dev.loki.lovisual.render.engine.color.ColorUtils; + +/** + * Цвет без альфы. Хранится как hex "#RRGGBB" и возвращается с полной альфой (0xFF) при запросе ARGB. + * Допустимые входные форматы: #RRGGBB, #AARRGGBB, 0xRRGGBB, 0xAARRGGBB. + */ +public class RGBColorValue extends ConfigValue implements ColorValue { + + private static final int RAINBOW_SPEED = 18; + + public RGBColorValue(String name, String defHex) { + super(name, normalize(defHex)); + } + + public static boolean isRainbowValue(String s) { + if (s == null) return false; + String t = s.trim().toUpperCase(); + return t.startsWith("RNB") || t.startsWith("RAINBOW"); + } + + public static String toRainbow(String hex) { + int rgb = parseRgb(hex); + return "RNB#" + String.format("%06X", rgb & 0xFFFFFF); + } + + public static String rainbowFallbackHex(String s) { + int rgb = rainbowFallbackRgb(s); + return String.format("#%02X%02X%02X", + (rgb >>> 16) & 0xFF, + (rgb >>> 8) & 0xFF, + rgb & 0xFF); + } + + private static String normalize(String s) { + if (s == null || s.isEmpty()) return "#FFFFFF"; // white RGB + s = s.trim(); + if (isRainbowValue(s)) return normalizeRainbow(s); + if (s.startsWith("0x") || s.startsWith("0X")) s = s.substring(2); + if (s.startsWith("#")) s = s.substring(1); + + // s is now hex without prefix; allow 6 or 8 digits, drop alpha if present + if (s.length() == 8) { + s = s.substring(2); // drop AA + } + if (s.length() != 6) { + return "#FFFFFF"; + } + return ("#" + s).toUpperCase(); + } + + private static String normalizeRainbow(String s) { + if (s == null) return "RNB"; + String upper = s.trim().toUpperCase(); + String tail = upper.startsWith("RAINBOW") ? upper.substring(7) : upper.substring(3); + tail = tail.trim(); + if (!tail.isEmpty() && (tail.charAt(0) == ':' || tail.charAt(0) == '=')) { + tail = tail.substring(1).trim(); + } + if (tail.startsWith("#")) tail = tail.substring(1); + if (tail.startsWith("0X")) tail = tail.substring(2); + StringBuilder hex = new StringBuilder(); + for (int i = 0; i < tail.length(); i++) { + char c = tail.charAt(i); + boolean digit = (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'); + if (digit) hex.append(c); + } + if (hex.length() >= 6) { + String tail6 = hex.substring(hex.length() - 6); + return "RNB#" + tail6; + } + return "RNB"; + } + + private static int rainbowFallbackRgb(String s) { + if (s == null) return 0xFFFFFF; + int hash = s.indexOf('#'); + if (hash >= 0 && hash + 1 < s.length()) { + return parseRgb(s.substring(hash)); + } + return 0xFFFFFF; + } + + private static int parseRgb(String hex) { + if (hex == null || hex.isEmpty()) return 0xFFFFFF; + String s = hex.startsWith("#") ? hex.substring(1) : hex; + try { + return Integer.parseUnsignedInt(s, 16); + } catch (NumberFormatException e) { + return 0xFFFFFF; + } + } + + @Override + public Object toJson() { + return value; + } + + @Override + public void fromJson(Object json) { + if (json instanceof String s) value = normalize(s); + } + + /** + * Возвращает цвет как ARGB с полной альфой (0xFF). + */ + public int getArgb() { + if (isRainbowValue(value)) { + return ColorUtils + .rainbow(RAINBOW_SPEED, 0, 1f, 1f, 1f) + .getRGB(); + } + return 0xFF000000 | parseRgb(value); + } + + @Override + public boolean supportsAlpha() { + return false; + } + + @Override + public boolean isRainbow() { + return isRainbowValue(value); + } + + @Override + public String toRainbowValue() { + return toRainbow(value); + } + + @Override + public String rainbowFallbackHex() { + return rainbowFallbackHex(value); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/SetValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/SetValue.java new file mode 100644 index 0000000..a2e5665 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/SetValue.java @@ -0,0 +1,46 @@ +/* + * 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.config.values; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +public class SetValue extends ConfigValue> { + + public SetValue(String name) { + super(name, new LinkedHashSet<>()); + } + + public SetValue(String name, Set def) { + super(name, new LinkedHashSet<>(def)); + } + + @Override + public void set(Set v) { + value = v == null ? new LinkedHashSet<>() : new LinkedHashSet<>(v); + } + + @Override + public Object toJson() { + return new ArrayList<>(value); // JSON array + } + + @Override + public void fromJson(Object json) { + if (json instanceof List list) { + LinkedHashSet copy = new LinkedHashSet<>(); + for (Object o : list) { + if (o instanceof String s) + copy.add(s); + } + value = copy; + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/StringValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/StringValue.java new file mode 100644 index 0000000..ec7aa7d --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/config/values/StringValue.java @@ -0,0 +1,26 @@ +/* + * 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.config.values; + +public class StringValue extends ConfigValue { + + public StringValue(String name, String def) { + super(name, def); + } + + @Override + public Object toJson() { + return value; + } + + @Override + public void fromJson(Object json) { + if (json instanceof String s) + this.value = s; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/Event.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/Event.java index 1f7e4dd..b489117 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/Event.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/Event.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/EventBus.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/EventBus.java index 4dde1f6..2dd4de4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/EventBus.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/EventBus.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -9,7 +9,7 @@ package dev.loki.lovisual.events; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import dev.loki.lovisual.util.logging.DebugLog; import java.lang.invoke.MethodHandle; @@ -118,7 +118,7 @@ public final class EventBus { public T post(T event) { if (event == null) return null; - if (!RuntimeGate.canRunClientLogic()) return event; + if (!Lifecycle.isActive()) return event; Subscriber[] subscribers = subscribersFor(event.getClass()); for (Subscriber sub : subscribers) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/EventHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/EventHandler.java index bc76170..52d3887 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/EventHandler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/EventHandler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/Events.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/Events.java index c4712cc..d6ebd30 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/Events.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/Events.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/UsedImplicitly.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/UsedImplicitly.java index c425489..88f40a9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/UsedImplicitly.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/UsedImplicitly.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/AttackEntityEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/AttackEntityEvent.java index 18ae4bf..8395a7e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/AttackEntityEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/AttackEntityEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/BlinkPacketEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/BlinkPacketEvent.java index 8918e30..fee8b32 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/BlinkPacketEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/BlinkPacketEvent.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/CombatProtocolBossbarEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/CombatProtocolBossbarEvent.java index d04d994..701fa80 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/CombatProtocolBossbarEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/CombatProtocolBossbarEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/CrosshairTargetUpdateEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/CrosshairTargetUpdateEvent.java index 93fc262..e229591 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/CrosshairTargetUpdateEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/CrosshairTargetUpdateEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventBreakBlock.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventBreakBlock.java index 172af19..6ce91bb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventBreakBlock.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventBreakBlock.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventCollision.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventCollision.java index 7f97ebb..1620296 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventCollision.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventCollision.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventPostSync.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventPostSync.java index 224651a..b3d648a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventPostSync.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventPostSync.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventPushOutOfBlocks.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventPushOutOfBlocks.java index bf63e22..f805382 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventPushOutOfBlocks.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventPushOutOfBlocks.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventSync.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventSync.java index 225e795..6eb78f7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventSync.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventSync.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventTargetChanged.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventTargetChanged.java index 62de841..5b070d8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventTargetChanged.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/EventTargetChanged.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/FireworkEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/FireworkEvent.java index d8cde6e..14a7100 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/FireworkEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/FireworkEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/GameTickEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/GameTickEvent.java index f57bca8..eaa99f2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/GameTickEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/GameTickEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/I18nPreflightCollectEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/I18nPreflightCollectEvent.java index d5ee4d5..78dfd87 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/I18nPreflightCollectEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/I18nPreflightCollectEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/KeyInputEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/KeyInputEvent.java index 68eb243..937f3c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/KeyInputEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/KeyInputEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/KeybindIsPressedEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/KeybindIsPressedEvent.java index eefb91d..9312d37 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/KeybindIsPressedEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/KeybindIsPressedEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/LightmapEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/LightmapEvent.java index b0d4670..ccf8aac 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/LightmapEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/LightmapEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/LightmapModifyEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/LightmapModifyEvent.java index 6f112ef..5a0ef5e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/LightmapModifyEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/LightmapModifyEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/MovementInputEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/MovementInputEvent.java index 73491e6..f2070e6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/MovementInputEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/MovementInputEvent.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PacketEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PacketEvent.java index 5d6bab9..d9b0acf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PacketEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PacketEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerJumpEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerJumpEvent.java index 7255976..4b046a2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerJumpEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerJumpEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerMoveEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerMoveEvent.java index bcf6a85..f105cdf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerMoveEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerMoveEvent.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerSafeWalkEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerSafeWalkEvent.java index c3dc5e1..4db3358 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerSafeWalkEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerSafeWalkEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerStepEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerStepEvent.java index 794f737..3df3814 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerStepEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerStepEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerStepSuccessEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerStepSuccessEvent.java index 19672d0..292f601 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerStepSuccessEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerStepSuccessEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerVelocityStrafe.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerVelocityStrafe.java index f6f5ca8..f40ad44 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerVelocityStrafe.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PlayerVelocityStrafe.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PostPlayerUpdateEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PostPlayerUpdateEvent.java index 5322c51..01965ea 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PostPlayerUpdateEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PostPlayerUpdateEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpChatEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpChatEvent.java index ec9f17f..01cfc02 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpChatEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpChatEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpOverlayEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpOverlayEvent.java index 2331791..a3d4cc9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpOverlayEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpOverlayEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpTabEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpTabEvent.java index 20f1f7e..9b7f8ce 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpTabEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/PvpTabEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/RenderPrewarmCollectEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/RenderPrewarmCollectEvent.java index 73112cc..8687c79 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/RenderPrewarmCollectEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/RenderPrewarmCollectEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/RotationUpdateEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/RotationUpdateEvent.java index 4ac6841..43494d4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/RotationUpdateEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/RotationUpdateEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/SprintControlEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/SprintControlEvent.java index 8227de4..27d81b7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/SprintControlEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/events/impl/SprintControlEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountAuthType.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountAuthType.java index 839bca6..7201edb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountAuthType.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountAuthType.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountConfig.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountConfig.java index 40568df..86814d5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountConfig.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountConfig.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountEntry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountEntry.java index 5787c29..218f8fb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountEntry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/AccountEntry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/SkinManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/SkinManager.java index f962797..45fc99f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/SkinManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/account/SkinManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/ClientCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/ClientCommand.java index 9e5b656..da4b5c9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/ClientCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/ClientCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandContext.java index 416fd2f..5353b38 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandInfo.java index 5a50461..5226c10 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandInfo.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandManager.java index 32dab89..fb1a9f9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandMetadata.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandMetadata.java index 30991b0..6e4d37e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandMetadata.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandMetadata.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandOutput.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandOutput.java index e6a586f..b14f1c8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandOutput.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/CommandOutput.java @@ -98,12 +98,6 @@ public enum CommandOutput { } } - public static void clearRecentMessages() { - synchronized (RECENT_MESSAGES) { - RECENT_MESSAGES.clear(); - } - } - private static void remember(Component text, Tone tone) { synchronized (RECENT_MESSAGES) { RECENT_MESSAGES.addLast(new MessageLine(text, System.currentTimeMillis(), tone)); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/VanillaChatRuntimeCleanup.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/VanillaChatRuntimeCleanup.java deleted file mode 100644 index df1b4a8..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/VanillaChatRuntimeCleanup.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.command; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.ChatComponent; - -public enum VanillaChatRuntimeCleanup { - ; - - public static void clearVanillaChatCache() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.gui == null || mc.gui.hud == null) return; - ChatComponent chat = mc.gui.hud.getChat(); - if (chat != null) { - chat.clearMessages(true); - } - CommandOutput.clearRecentMessages(); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/AddonsCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/AddonsCommand.java index 8c6f089..2196f10 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/AddonsCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/AddonsCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/BindCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/BindCommand.java index 5727fb6..ce71610 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/BindCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/BindCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/CommandUtils.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/CommandUtils.java index 9ea8b7c..445c66b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/CommandUtils.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/CommandUtils.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ConfigCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ConfigCommand.java index fc9d8af..d311680 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ConfigCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ConfigCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/CoordinatesCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/CoordinatesCommand.java index b9978bf..7dd956e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/CoordinatesCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/CoordinatesCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/HelpCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/HelpCommand.java index f0842b0..f7eab87 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/HelpCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/HelpCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/HideCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/HideCommand.java index 93cd50c..b5c6141 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/HideCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/HideCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/IrisCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/IrisCommand.java index de65b4e..136a068 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/IrisCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/IrisCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,7 +16,6 @@ import dev.loki.lovisual.render.iris.IrisCompatibilityProfile; import dev.loki.lovisual.render.iris.IrisRuntime; import dev.loki.lovisual.render.iris.IrisRuntimeSnapshot; import dev.loki.lovisual.render.iris.patch.ShaderPatchEngine; -import dev.loki.lovisual.runtime.RuntimeGate; import java.util.List; import java.util.stream.Collectors; @@ -34,7 +33,7 @@ public final class IrisCommand implements ClientCommand { @Override public boolean isAvailable() { - return !RuntimeGate.isPanic(); + return true; } @Override diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ModulesCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ModulesCommand.java index 2712ab2..1887f26 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ModulesCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ModulesCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/PingCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/PingCommand.java index 5266c46..f248598 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/PingCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/PingCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/RelationCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/RelationCommand.java index 5f3dd72..609a2ab 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/RelationCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/RelationCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/RuntimeCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/RuntimeCommand.java deleted file mode 100644 index 54b2b27..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/RuntimeCommand.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.command.impl; - -import dev.loki.lovisual.features.command.ClientCommand; -import dev.loki.lovisual.features.command.CommandContext; -import dev.loki.lovisual.features.command.CommandInfo; -import dev.loki.lovisual.features.command.CommandOutput; -import dev.loki.lovisual.runtime.ClientRuntime; -import dev.loki.lovisual.runtime.ClientRuntimeState; - -import java.nio.file.Path; -import java.util.List; - -@CommandInfo( - id = "runtime", - aliases = {"panic", "jarreplace"}, - usage = "@runtime [status|panic|resume|jar|source]", - descriptionKey = "command.runtime.description" -) -public final class RuntimeCommand implements ClientCommand { - @Override - public boolean execute(CommandContext ctx) { - String action = ctx.arg(0); - if (action == null || action.equalsIgnoreCase("status")) { - sendStatus(); - return true; - } - if (action.equalsIgnoreCase("panic")) { - ClientRuntime.toggleSoftPanic("runtime command"); - CommandOutput.send("Runtime state: " + ClientRuntime.state()); - return true; - } - if (action.equalsIgnoreCase("resume")) { - if (ClientRuntime.state() == ClientRuntimeState.SOFT_PANIC) { - ClientRuntime.exitSoftPanic("runtime command"); - } - CommandOutput.send("Runtime state: " + ClientRuntime.state()); - return true; - } - if (action.equalsIgnoreCase("jar") || action.equalsIgnoreCase("replace")) { - ClientRuntime.prepareJarReplacement("runtime command"); - CommandOutput.send("Client is fully disabled for safe JAR replacement. Restart Minecraft to use the new JAR."); - return true; - } - if (action.equalsIgnoreCase("source")) { - Path jar = ClientRuntime.loaderBridge().currentModJarPath(); - CommandOutput.send("Loader: standardFabric=" + ClientRuntime.loaderBridge().isStandardFabric() - + ", safeJarReplacement=" + ClientRuntime.loaderBridge().supportsSafeJarReplacement()); - CommandOutput.send("Current mod source: " + (jar == null ? "" : jar.toAbsolutePath())); - CommandOutput.send("LoVisual class source: " - + ClientRuntime.loaderBridge().describeClassSource("dev.loki.lovisual.LoVisual")); - return true; - } - CommandOutput.send("Usage: " + metadata().usage()); - return true; - } - - @Override - public List suggest(CommandContext ctx, int argIndex, String token) { - if (argIndex != 1) return List.of(); - String lower = token == null ? "" : token.toLowerCase(); - return List.of("status", "panic", "resume", "jar", "source").stream() - .filter(value -> lower.isEmpty() || value.startsWith(lower)) - .toList(); - } - - private void sendStatus() { - for (String line : ClientRuntime.diagnostics().lines()) { - CommandOutput.send(line); - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ServerInfoCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ServerInfoCommand.java index 7640f6c..968361f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ServerInfoCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ServerInfoCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ToggleCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ToggleCommand.java index d734e44..3a3fa21 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ToggleCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/ToggleCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/TpsCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/TpsCommand.java index 899fdca..0bd06cb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/TpsCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/TpsCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/UsernameCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/UsernameCommand.java index 9df5328..17c2ce8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/UsernameCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/UsernameCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/XaeroWaypointCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/XaeroWaypointCommand.java index 0926ef6..5a17313 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/XaeroWaypointCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/command/impl/XaeroWaypointCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatCommandMerge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatCommandMerge.java new file mode 100644 index 0000000..ad4688d --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatCommandMerge.java @@ -0,0 +1,53 @@ +/* + * 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.features.gui.chat; + +import dev.loki.lovisual.features.command.CommandOutput; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.IdentityHashMap; +import java.util.List; + +/** + * Merges command-output lines into the visible chat tail, sharing the identity-keyed + * command-line cache held on {@link BetterChatRenderer}. + */ +final class BetterChatCommandMerge { + private BetterChatCommandMerge() { + } + + static List mergeCommandOutput(List storeLines, + List commandLines, + int needed) { + if (commandLines == null || commandLines.isEmpty()) { + return storeLines; + } + List out = new ArrayList<>(storeLines.size() + commandLines.size()); + out.addAll(storeLines); + for (CommandOutput.MessageLine line : commandLines) { + if (line == null || line.text() == null) continue; + out.add(BetterChatRenderer.COMMAND_LINE_CACHE.computeIfAbsent(line, key -> new ChatLine(key.text(), key.timestampMs()))); + } + out.sort(Comparator.comparingLong(ChatLine::timestampMs)); + trimCommandLineCache(commandLines); + if (needed > 0 && out.size() > needed) { + return new ArrayList<>(out.subList(out.size() - needed, out.size())); + } + return out; + } + + static void trimCommandLineCache(List liveLines) { + if (BetterChatRenderer.COMMAND_LINE_CACHE.size() <= 160) return; + IdentityHashMap live = new IdentityHashMap<>(); + for (CommandOutput.MessageLine line : liveLines) { + live.put(line, Boolean.TRUE); + } + BetterChatRenderer.COMMAND_LINE_CACHE.keySet().removeIf(line -> !live.containsKey(line)); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatContextMenuHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatContextMenuHandler.java new file mode 100644 index 0000000..19acd56 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatContextMenuHandler.java @@ -0,0 +1,187 @@ +/* + * 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.features.gui.chat; +import dev.loki.lovisual.features.command.CommandManager; +import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; +import dev.loki.lovisual.mixins.accessors.ChatScreenAccessor; +import dev.loki.lovisual.util.screen.ClientScreen; +import dev.loki.lovisual.util.text.ChatNameUtil; +import dev.loki.lovisual.util.text.ClipboardUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.screens.ChatScreen; +import net.minecraft.client.gui.screens.ConfirmLinkScreen; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.util.Mth; +import net.minecraft.util.Util; +import java.util.ArrayList; +import java.util.List; +/** + * Right-click context menu construction, click-event handling and chat prefill actions. + */ +final class BetterChatContextMenuHandler { + private BetterChatContextMenuHandler() { + } + static void openContextMenu(BetterChatModel.PickResult pick, double mx, double my) { + List entries = new ArrayList<>(); + ChatLine msg = pick.line().message(); + String full = msg.text().getString(); + BetterChat settings = BetterChat.get(); + long ts = msg.timestampMs(); + boolean tsEnabled = settings != null && settings.timestampEnabled(); + boolean tsUnix = settings != null && settings.timestampToggles().get("hover_unix"); + if (BetterChatRenderer.selection.appliesTo(pick.line().messageIndex()) && BetterChatRenderer.selection.hasRange()) { + String selected = selectedText(); + entries.add(new BetterChatContextMenuModel.ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_selection"), () -> ClipboardUtil.copy(selected))); + } else { + entries.add(new BetterChatContextMenuModel.ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_message"), () -> ClipboardUtil.copy(full))); + } + List nickCandidates = ChatNameUtil.extractNicks(full); + String hovered = ChatNameUtil.normalizeNickCandidate(BetterChatEditBoxUtil.wordAt(full, pick.glyph().charIndex())); + String targetNick = null; + if (!hovered.isEmpty() + && ChatNameUtil.isNickLike(hovered) + && nickCandidates.stream().anyMatch(n -> n.equalsIgnoreCase(hovered))) { + targetNick = hovered; + } else if (nickCandidates.size() == 1) { + targetNick = nickCandidates.getFirst(); + } + if (isOnlinePlayer(targetNick)) { + String nickToTell = targetNick; + entries.add(new BetterChatContextMenuModel.ContextMenu.MenuEntry(I18n.get("better_chat.context.reply"), () -> prefillTell(nickToTell))); + } + if (BetterChatRenderer.hoverEntityUuid != null && !BetterChatRenderer.hoverEntityUuid.isEmpty()) { + String uuidToCopy = BetterChatRenderer.hoverEntityUuid; + entries.add(new BetterChatContextMenuModel.ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_uuid"), () -> ClipboardUtil.copy(uuidToCopy))); + } + if (tsEnabled) { + entries.add(new BetterChatContextMenuModel.ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_time"), () -> ClipboardUtil.copy(BetterChatTooltipRenderer.formatTimestamp(ts, settings.timestampSeconds())))); + entries.add(new BetterChatContextMenuModel.ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_date"), () -> ClipboardUtil.copy(BetterChatTooltipRenderer.formatDate(ts)))); + if (tsUnix) { + entries.add(new BetterChatContextMenuModel.ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_unix"), () -> ClipboardUtil.copy(String.valueOf(ts / 1000L)))); + } + } + BetterChatRenderer.contextMenu = BetterChatContextMenuModel.ContextMenu.open((float) mx, (float) my, entries); + } + static void copySelectionToClipboard() { + String selected = selectedText(); + if (selected.isEmpty()) return; + ClipboardUtil.copy(selected); + } + static String selectedText() { + if (!BetterChatRenderer.selection.hasRange()) return ""; + if (BetterChatRenderer.lastMessages == null || BetterChatRenderer.lastMessages.isEmpty()) return ""; + int startMsg = Mth.clamp(BetterChatRenderer.selection.startContext(), 0, BetterChatRenderer.lastMessages.size() - 1); + int endMsg = Mth.clamp(BetterChatRenderer.selection.endContext(), 0, BetterChatRenderer.lastMessages.size() - 1); + if (endMsg < startMsg) return ""; + StringBuilder out = new StringBuilder(); + for (int msgIdx = startMsg; msgIdx <= endMsg; msgIdx++) { + ChatLine line = BetterChatRenderer.lastMessages.get(msgIdx); + if (line == null || line.text() == null) continue; + String full = line.text().getString(); + int len = full.length(); + int start = BetterChatRenderer.selection.startForLine(msgIdx); + int end = BetterChatRenderer.selection.endForLine(msgIdx); + int from = start == Integer.MIN_VALUE ? 0 : Mth.clamp(start, 0, len); + int toInclusive = end == Integer.MAX_VALUE ? Math.max(0, len - 1) : Mth.clamp(end, 0, Math.max(0, len - 1)); + int to = Mth.clamp(toInclusive + 1, 0, len); + if (to > from) { + if (!out.isEmpty()) out.append(' '); + out.append(BetterChatFontUtil.safeSub(full, from, to)); + } + } + return out.toString(); + } + static boolean handleClickEvent(net.minecraft.network.chat.Style style, boolean ctrlDown) { + if (style == null) return false; + ClickEvent evt = style.getClickEvent(); + if (evt == null) return false; + String val = switch (evt) { + case ClickEvent.OpenUrl openUrl -> openUrl.uri().toString(); + case ClickEvent.OpenFile openFile -> openFile.path(); + case ClickEvent.RunCommand run -> run.command(); + case ClickEvent.SuggestCommand sug -> sug.command(); + case ClickEvent.CopyToClipboard copy -> copy.value(); + case ClickEvent.ShowDialog showDialog -> showDialog.dialog().value().toString(); + case ClickEvent.ChangePage changePage -> String.valueOf(changePage.page()); + case ClickEvent.Custom custom -> custom.id().toString(); + default -> null; + }; + if (val == null || val.isEmpty()) return false; + try { + if (evt instanceof ClickEvent.OpenUrl || evt instanceof ClickEvent.OpenFile) { + Minecraft mc = Minecraft.getInstance(); + if (ClientScreen.current() instanceof ChatScreen chat) { + ClientScreen.show(mc, new ConfirmLinkScreen(confirm -> { + if (confirm) Util.getPlatform().openUri(val); + ClientScreen.show(mc, chat); + }, val, false)); + } else { + Util.getPlatform().openUri(val); + } + return true; + } else if (evt instanceof ClickEvent.CopyToClipboard) { + ClipboardUtil.copy(val); + return true; + } else if (evt instanceof ClickEvent.RunCommand && val.startsWith("@")) { + return CommandManager.handle(val); + } else if (evt instanceof ClickEvent.SuggestCommand || evt instanceof ClickEvent.RunCommand) { + if (!ctrlDown) return false; + prefillChat(val); + return true; + } else { + return false; + } + } catch (Exception e) { + return false; + } + } + static boolean tryPrefillTellFromClick(int msgIndex, int charIndex) { + if (msgIndex < 0 || msgIndex >= BetterChatRenderer.lastMessages.size()) return false; + String full = BetterChatRenderer.lastMessages.get(msgIndex).text().getString(); + List nickCandidates = ChatNameUtil.extractNicks(full); + if (nickCandidates.isEmpty()) return false; + String hovered = ChatNameUtil.normalizeNickCandidate(BetterChatEditBoxUtil.wordAt(full, charIndex)); + String targetNick = null; + if (!hovered.isEmpty() + && ChatNameUtil.isNickLike(hovered) + && nickCandidates.stream().anyMatch(n -> n.equalsIgnoreCase(hovered))) { + targetNick = hovered; + } else if (nickCandidates.size() == 1) { + targetNick = nickCandidates.getFirst(); + } + if (!isOnlinePlayer(targetNick)) return false; + prefillTell(targetNick); + return true; + } + static void prefillChat(String value) { + if (value == null) return; + Minecraft mc = Minecraft.getInstance(); + if (!(ClientScreen.current() instanceof ChatScreen chatScreen)) return; + EditBox field = ((ChatScreenAccessor) chatScreen).getChatField(); + if (field == null) return; + field.setValue(value); + BetterChatEditBoxUtil.setCursorSafe(field, value.length()); + } + static void prefillTell(String nick) { + Minecraft mc = Minecraft.getInstance(); + if (!(ClientScreen.current() instanceof ChatScreen chatScreen)) return; + if (!isOnlinePlayer(nick)) return; + EditBox field = ((ChatScreenAccessor) chatScreen).getChatField(); + if (field == null) return; + String value = "/tell " + nick + " "; + field.setValue(value); + } + static boolean isOnlinePlayer(String nick) { + if (nick == null || nick.isEmpty()) return false; + Minecraft mc = Minecraft.getInstance(); + if (mc == null || mc.player == null || mc.player.connection == null) return false; + return mc.player.connection.getOnlinePlayers().stream() + .anyMatch(e -> e.getProfile() != null && nick.equalsIgnoreCase(e.getProfile().name())); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatContextMenuModel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatContextMenuModel.java new file mode 100644 index 0000000..ba92181 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatContextMenuModel.java @@ -0,0 +1,112 @@ +/* + * 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.features.gui.chat; + +import java.util.Collections; +import java.util.List; + +import static dev.loki.lovisual.features.theme.Theme.theme; + +/** + * Right-click context menu record + entry record, extracted from the renderer facade. + * Rendering leans on {@link BetterChatDrawUtil} and {@link BetterChatFontUtil}. + */ +final class BetterChatContextMenuModel { + private BetterChatContextMenuModel() { + } + + record ContextMenu(boolean open, float x, float y, List entries) { + private static final float MENU_PAD_X = 8f; + private static final float MENU_PAD_Y = 7f; + private static final float MENU_RADIUS = 9f; + + static ContextMenu closed() { + return new ContextMenu(false, 0, 0, Collections.emptyList()); + } + + static ContextMenu open(float x, float y, List entries) { + return new ContextMenu(true, x, y, entries); + } + + private static float itemHeight(float fontSize) { + return Math.max(20f, fontSize + 7f); + } + + boolean contains(double mx, double my) { + if (!open) return false; + float fontSize = BetterChatRenderer.lastFontSizeForUi * 0.92f; + return mx >= x && mx <= x + width(fontSize) && my >= y && my <= y + height(fontSize); + } + + MenuEntry pick(double my) { + if (!open) return null; + float fontSize = BetterChatRenderer.lastFontSizeForUi * 0.92f; + float itemH = itemHeight(fontSize); + float cy = y + MENU_PAD_Y; + for (int i = 0; i < entries.size(); i++) { + float top = cy + i * itemH; + float bottom = top + itemH; + if (my >= top && my <= bottom) { + return entries.get(i); + } + } + return null; + } + + void render(float mouseX, float mouseY, float fontSize) { + if (!open || entries.isEmpty()) return; + float fs = Math.max(12f, fontSize * 0.92f); + float itemH = itemHeight(fs); + float w = width(fs); + float h = height(fs); + + BetterChatDrawUtil.drawGlassPill(x, y, w, h, MENU_RADIUS, 0.94f, true); + + float accentX = x + 5f; + BetterChatDrawUtil.drawRoundedRect(accentX, y + MENU_PAD_Y + 2f, 2f, h - MENU_PAD_Y * 2f - 4f, 1f, BetterChatDrawUtil.withAlpha(theme().accent(), 0x72)); + + float cy = y + MENU_PAD_Y; + for (MenuEntry entry : entries) { + boolean hover = mouseX >= x && mouseX <= x + w && mouseY >= cy && mouseY <= cy + itemH; + if (hover) { + BetterChatDrawUtil.drawRoundedRect(x + 8f, cy + 1f, w - 16f, itemH - 2f, itemH * 0.5f, BetterChatDrawUtil.withAlpha(theme().surfaceHover(), 0xAA)); + BetterChatDrawUtil.drawRoundedRectStrokeGradient( + x + 8f, cy + 1f, w - 16f, itemH - 2f, itemH * 0.5f, + 0.55f, + BetterChatDrawUtil.withAlpha(theme().accent(), 0x66), + BetterChatDrawUtil.withAlpha(theme().accentSoft(), 0x38) + ); + } + + float dot = 3.2f; + int dotColor = hover ? BetterChatDrawUtil.withAlpha(theme().accent(), 0xE0) : BetterChatDrawUtil.withAlpha(theme().textMuted(), 0x70); + BetterChatDrawUtil.drawRoundedRect(x + 14f, cy + (itemH - dot) * 0.5f, dot, dot, dot * 0.5f, dotColor); + + float textY = cy + (itemH - BetterChatFontUtil.textHeight(BetterChatFontUtil.getIosevkaRegular(), fs)) * 0.5f; + int textColor = hover ? theme().textPrimary() : BetterChatDrawUtil.withAlpha(theme().textPrimary(), 0xE4); + BetterChatFontUtil.drawText(BetterChatFontUtil.getIosevkaRegular(), entry.label(), x + 24f, textY, fs, textColor, true); + cy += itemH; + } + } + + private float width(float fontSize) { + float maxText = 0f; + for (MenuEntry e : entries) { + maxText = Math.max(maxText, BetterChatFontUtil.textWidth(BetterChatFontUtil.getIosevkaRegular(), e.label(), fontSize)); + } + return Math.max(168f, maxText + MENU_PAD_X * 2f + 34f); + } + + private float height(float fontSize) { + return MENU_PAD_Y * 2f + entries.size() * itemHeight(fontSize); + } + + record MenuEntry(String label, Runnable action) { + } + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatDrawUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatDrawUtil.java new file mode 100644 index 0000000..3a058b3 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatDrawUtil.java @@ -0,0 +1,201 @@ +/* + * 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.features.gui.chat; + +import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.SettingsGuiPalette; +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.helpers.SystemCursor; +import net.minecraft.util.Mth; + +import static dev.loki.lovisual.features.theme.Theme.theme; + +/** + * Low-level draw primitives + color helpers shared by the chat renderer helpers. + */ +final class BetterChatDrawUtil { + private BetterChatDrawUtil() { + } + + static int withAlpha(int argb, int alpha) { + return (argb & 0x00FFFFFF) | ((alpha & 0xFF) << 24); + } + + static int mulAlpha(int argb, float a) { + int alpha = (int) (((argb >>> 24) & 0xFF) * a); + return (argb & 0x00FFFFFF) | (Mth.clamp(alpha, 0, 255) << 24); + } + + static void applyColor(int argb) { + BetterChatRenderer.TMP_COLOR.a = (argb >>> 24) & 0xFF; + BetterChatRenderer.TMP_COLOR.r = (argb >>> 16) & 0xFF; + BetterChatRenderer.TMP_COLOR.g = (argb >>> 8) & 0xFF; + BetterChatRenderer.TMP_COLOR.b = argb & 0xFF; + } + + static void drawRoundedRect(float x, float y, float w, float h, float radius, int argb) { + if (BetterChatRenderer.renderer == null) return; + if (((argb >>> 24) & 0xFF) <= 0) return; + BetterChat cfg = BetterChat.get(); + boolean useGradient = cfg != null && cfg.gradientEnabled(); + HudRenderUtil.drawHudBackground(BetterChatRenderer.renderer, x, y, w, h, radius, 1.1f, argb, useGradient); + } + + static void drawRoundedRectStrokeGradient(float x, float y, float w, float h, float radius, float thickness, + int startArgb, int endArgb) { + if (BetterChatRenderer.renderer == null) return; + if (((startArgb >>> 24) & 0xFF) <= 0 && ((endArgb >>> 24) & 0xFF) <= 0) return; + BetterChatRenderer.renderer.roundedRectStrokeGradient(x, y, w, h, radius, 1.1f, thickness, startArgb, endArgb, (float) 0.0); + } + + static void drawRect(float x, float y, float w, float h, int argb) { + if (BetterChatRenderer.renderer == null) return; + if (((argb >>> 24) & 0xFF) <= 0) return; + BetterChatRenderer.renderer.quad(x, y, w, h, argb); + } + + static void flushRenderer() { + if (BetterChatRenderer.renderer == null) return; + if (Renderer2D.isBatching()) { + Renderer2D.flushBatch(); + } else { + BetterChatRenderer.renderer.begin(); + } + } + + static void drawGlassPill(float x, float y, float w, float h, float radius, float alpha, boolean softPanel) { + if (BetterChatRenderer.renderer == null || w <= 0f || h <= 0f) return; + BetterChat settings = BetterChat.get(); + float drawAlpha = Mth.clamp(alpha, 0.0f, 1.0f); + if (drawAlpha <= 0.001f) return; + float configuredAlpha = settings != null ? settings.liquidGlassAlphaFactor() : (230f / 255f); + float blurStrength = configuredAlpha * drawAlpha; + float materialAlpha = Mth.clamp(0.72f + configuredAlpha * 0.28f, 0.0f, 1.0f) * drawAlpha; + float glassRadius = Math.max(2f, radius); + float thickness = softPanel ? 15.5f : 12.5f; + float fresnelPower = softPanel ? -26.0f : -20.0f; + float fresnelAlpha = Mth.clamp(0.72f + configuredAlpha * 0.28f, 0.0f, 1.0f) * drawAlpha; + float baseAlpha = Mth.clamp((softPanel ? 0.66f : 0.68f) + configuredAlpha * (softPanel ? 0.34f : 0.32f), 0.0f, 1.0f); + float fresnelMix = softPanel ? 0.46f : 0.44f; + float distortPx = (softPanel ? 0.172f : 0.145f) * drawAlpha; + + flushRenderer(); + BetterChatRenderer.renderer.liquidGlassRect( + x, y, w, h, + glassRadius, + thickness, + theme().accent(), + materialAlpha, + blurStrength, + fresnelPower, + fresnelAlpha, + baseAlpha, + fresnelMix, + distortPx, + softPanel ? 2.65f : 2.25f + ); + + int veilAlpha = Math.round((softPanel ? 0x16 : 0x0C) * drawAlpha); + if (veilAlpha > 0) { + drawRoundedRect(x, y, w, h, glassRadius, withAlpha(theme().windowBg(), veilAlpha)); + } + } + + static void drawLiquidHoverPill(float x, float y, float w, float h, float radius, float alpha) { + if (BetterChatRenderer.renderer == null || w <= 0f || h <= 0f || alpha <= 0.001f) return; + flushRenderer(); + BetterChatRenderer.renderer.liquidGlassRect( + x, y, w, h, + Math.max(1.0f, radius), + 10.5f, + theme().accentSoft(), + Mth.clamp(alpha, 0.0f, 1.0f), + 0.08f, + -18.0f, + 0.82f, + 0.72f, + 0.34f, + 0.095f, + 1.2f + ); + drawRoundedRect(x, y, w, h, radius, withAlpha(theme().surfaceHover(), 0x32)); + drawRoundedRectStrokeGradient(x, y, w, h, radius, 0.55f, + withAlpha(theme().accentSoft(), 0x50), + withAlpha(theme().accent(), 0x34)); + } + + static void drawScrollbarGlass(float trackX, float trackY, float trackW, float trackH, + float thumbY, float thumbH, boolean hot, int trackAlpha, int thumbAlpha) { + if (BetterChatRenderer.renderer == null || trackW <= 0f || trackH <= 0f || thumbH <= 0f) return; + SettingsGuiPalette palette = SettingsGuiPalette.current(); + int trackA = withAlpha(palette.moduleScrollTrackA(), trackAlpha); + int trackB = withAlpha(palette.moduleScrollTrackB(), Math.min(255, trackAlpha + 0x18)); + int handleA = withAlpha(palette.moduleScrollHandleA(), thumbAlpha); + int handleB = withAlpha(palette.moduleScrollHandleB(), Math.min(255, thumbAlpha + 0x0C)); + float radius = trackW * 0.5f; + BetterChatRenderer.renderer.roundedRectGradientQuad(trackX, trackY, trackW, trackH, radius, 1.0f, trackA, trackB, trackB, trackA); + BetterChatRenderer.renderer.roundedRectGradientQuad(trackX, thumbY, trackW, thumbH, radius, 1.0f, handleA, handleB, handleB, handleA); + } + + static void renderScrollbar(float boxX, float boxY, float boxW, float boxH, + int startLine, int visibleLines, int totalLines, double mouseX, double mouseY) { + if (visibleLines <= 0 || totalLines <= visibleLines) { + BetterChatRenderer.sbEnabled = false; + BetterChatRenderer.draggingScrollbar = false; + return; + } + int scrollable = Math.max(1, totalLines - visibleLines); + boolean hot = BetterChatRenderer.draggingScrollbar || isScrollbarHovered(mouseX, mouseY); + boolean recently = System.currentTimeMillis() - BetterChatRenderer.lastScrollInteractionMs < 850L; + float trackW = 5.0f; + float trackX = boxX - trackW - 7f; + float trackY = boxY + 10f; + float trackH = Math.max(16f, boxH - 20f); + float thumbH = Math.max(18f, trackH * ((float) visibleLines / (float) totalLines)); + float ratio = (float) startLine / (float) scrollable; + float thumbY = trackY + (trackH - thumbH) * Mth.clamp(ratio, 0f, 1f); + + BetterChatRenderer.sbTrackX = trackX; + BetterChatRenderer.sbTrackY = trackY; + BetterChatRenderer.sbTrackW = trackW; + BetterChatRenderer.sbTrackH = trackH; + BetterChatRenderer.sbThumbY = thumbY; + BetterChatRenderer.sbThumbH = thumbH; + BetterChatRenderer.sbEnabled = true; + + if (hot || BetterChatRenderer.draggingScrollbar) { + SystemCursor.set(SystemCursor.CursorType.SCROLL); + } + int trackAlpha = hot ? 0xB8 : (recently ? 0x9C : 0x84); + int thumbAlpha = hot ? 0xFF : (recently ? 0xEC : 0xD4); + drawScrollbarGlass(trackX, trackY, trackW, trackH, thumbY, thumbH, hot, trackAlpha, thumbAlpha); + } + + static boolean isScrollbarHovered(double mx, double my) { + float hitPad = 5f; + return BetterChatRenderer.sbEnabled && + mx >= BetterChatRenderer.sbTrackX - hitPad && + mx <= BetterChatRenderer.sbTrackX + BetterChatRenderer.sbTrackW + hitPad && + my >= BetterChatRenderer.sbTrackY - hitPad && + my <= BetterChatRenderer.sbTrackY + BetterChatRenderer.sbTrackH + hitPad; + } + + static void scrollToPosition(double my) { + if (!BetterChatRenderer.sbEnabled || BetterChatRenderer.sbVisibleLines <= 0 || BetterChatRenderer.sbTotalLines <= BetterChatRenderer.sbVisibleLines) + return; + float trackSpan = BetterChatRenderer.sbTrackH - BetterChatRenderer.sbThumbH; + if (trackSpan <= 0f) return; + float rel = (float) (my - BetterChatRenderer.sbTrackY - BetterChatRenderer.sbDragOffset); + float t = Mth.clamp(rel / trackSpan, 0f, 1f); + int scrollable = Math.max(0, BetterChatRenderer.sbTotalLines - BetterChatRenderer.sbVisibleLines); + int targetStart = Math.round(t * scrollable); + BetterChatRenderer.scrollOffsetLines = Mth.clamp(BetterChatRenderer.sbTotalLines - BetterChatRenderer.sbVisibleLines - targetStart, 0, scrollable); + BetterChatRenderer.lastScrollInteractionMs = System.currentTimeMillis(); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatEditBoxUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatEditBoxUtil.java new file mode 100644 index 0000000..2f5d481 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatEditBoxUtil.java @@ -0,0 +1,53 @@ +/* + * 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.features.gui.chat; + +import dev.loki.lovisual.mixins.accessors.TextFieldWidgetAccessor; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.util.Mth; + +/** + * EditBox selection introspection + word-boundary helper, independent of the chat renderer. + */ +final class BetterChatEditBoxUtil { + private BetterChatEditBoxUtil() { + } + + static int selectionStart(EditBox field, int fallback) { + if (field == null) return fallback; + return Mth.clamp(field.getCursorPosition(), 0, field.getValue().length()); + } + + static int selectionEnd(EditBox field, int fallback) { + if (field == null) return fallback; + try { + return Mth.clamp(((TextFieldWidgetAccessor) field).lovisual$getSelectionEnd(), 0, field.getValue().length()); + } catch (Throwable ignored) { + String selected = field.getHighlighted(); + int cursor = selectionStart(field, fallback); + if (selected == null || selected.isEmpty()) return cursor; + return Mth.clamp(cursor + selected.length(), 0, field.getValue().length()); + } + } + + static void setCursorSafe(EditBox field, int pos) { + if (field == null) return; + field.moveCursorTo(Mth.clamp(pos, 0, field.getValue().length()), false); + } + + static String wordAt(String text, int charIndex) { + if (text == null || text.isEmpty()) return ""; + int idx = Mth.clamp(charIndex, 0, Math.max(0, text.length() - 1)); + int start = idx; + while (start > 0 && !Character.isWhitespace(text.charAt(start - 1))) start--; + int end = idx; + while (end < text.length() && !Character.isWhitespace(text.charAt(end))) end++; + if (end <= start) return ""; + return text.substring(start, end).replaceAll("[<>:\\[\\]]", ""); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFontUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFontUtil.java new file mode 100644 index 0000000..d19f389 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFontUtil.java @@ -0,0 +1,198 @@ +/* + * 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.features.gui.chat; + +import dev.loki.lovisual.render.engine.text.FontInfo; +import dev.loki.lovisual.render.engine.text.Fonts; +import dev.loki.lovisual.render.engine.text.TextGlyphFallback; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.engine.text.VanillaTextRenderer; +import net.minecraft.network.chat.Style; +import net.minecraft.util.Mth; + +/** + * Font resolution, glyph sizing and plain-text draw helpers for the chat renderer. + * All public-facing metrics share the renderer singleton held on {@link BetterChatRenderer}. + */ +final class BetterChatFontUtil { + private BetterChatFontUtil() { + } + + static TextRenderer getInterRegular() { + return Fonts.renderer("Inter", FontInfo.Type.Regular, TextRenderer.get()); + } + + static TextRenderer getIosevkaRegular() { + return Fonts.renderer("Iosevka", FontInfo.Type.Regular, TextRenderer.get()); + } + + static TextRenderer getIosevkaItalic() { + return Fonts.renderer("Iosevka", FontInfo.Type.Italic, getIosevkaRegular()); + } + + static TextRenderer getIosevkaBold() { + return Fonts.renderer("Iosevka", FontInfo.Type.Bold, getIosevkaRegular()); + } + + static TextRenderer getIosevkaBoldItalic() { + return Fonts.renderer("Iosevka", FontInfo.Type.BoldItalic, getIosevkaBold()); + } + + static TextRenderer fontRenderer(String key) { + if (key == null) return getIosevkaRegular(); + return switch (key) { + case "iosevka_bold" -> getIosevkaBold(); + case "iosevka_bold_italic" -> getIosevkaBoldItalic(); + case "iosevka_medium_italic" -> getIosevkaItalic(); + case "vanilla_symbols" -> TextGlyphFallback.vanillaSymbols(getIosevkaRegular()); + case "vanilla" -> VanillaTextRenderer.INSTANCE; + default -> getIosevkaRegular(); + }; + } + + static TextRenderer rendererForGlyph(TextRenderer preferred, int codePoint) { + return TextGlyphFallback.rendererForGlyph(preferred, codePoint); + } + + static String fontForGlyph(String baseFont, int codePoint) { + TextRenderer preferred = fontRenderer(baseFont); + return TextGlyphFallback.fontKeyForGlyph(baseFont, preferred, codePoint, "iosevka_medium"); + } + + static String fontForStyle(Style style) { + boolean bold = style.isBold(); + boolean italic = style.isItalic(); + if (bold && italic) return "iosevka_bold_italic"; + if (bold) return "iosevka_bold"; + if (italic) return "iosevka_medium_italic"; + return "iosevka_medium"; + } + + static float scaleForSize(float size) { + return size / 18.0f; + } + + static float svgGlyphSize(TextRenderer tr, float size, boolean shadow) { + return Math.max(1.0f, textHeight(tr, size)) * 0.92f; + } + + static float textHeight(TextRenderer tr, float size) { + if (tr == null) return 0f; + float scale = scaleForSize(size); + tr.begin(scale, true, false); + try { + return (float) tr.getHeight(false); + } finally { + tr.end(); + } + } + + static float textWidth(TextRenderer tr, String text, float size) { + if (tr == null || text == null || text.isEmpty()) return 0f; + float scale = scaleForSize(size); + float svgAdvance = svgGlyphSize(tr, size, false); + TextRenderer current = null; + float width = 0f; + try { + for (int i = 0; i < text.length(); ) { + int cp = text.codePointAt(i); + if (TextGlyphFallback.shouldUseVanillaSvg(tr, cp)) { + if (current != null) { + current.end(); + current = null; + } + width += svgAdvance; + i += Character.charCount(cp); + continue; + } + String glyph = new String(Character.toChars(cp)); + TextRenderer next = rendererForGlyph(tr, cp); + if (next != current) { + if (current != null) current.end(); + current = next; + current.begin(scale, true, false); + } + width += (float) current.getWidth(glyph, false); + i += Character.charCount(cp); + } + return width; + } finally { + if (current != null) current.end(); + } + } + + static void drawText(TextRenderer tr, String text, float x, float y, float size, int argb, boolean shadow) { + if (tr == null || text == null || text.isEmpty()) return; + if (((argb >>> 24) & 0xFF) <= 0) return; + float scale = scaleForSize(size); + float svgSize = svgGlyphSize(tr, size, shadow); + float svgY = y + (textHeight(tr, size) - svgSize) * 0.5f; + BetterChatDrawUtil.applyColor(argb); + TextRenderer current = null; + float cursorX = x; + try { + for (int i = 0; i < text.length(); ) { + int cp = text.codePointAt(i); + if (TextGlyphFallback.shouldUseVanillaSvg(tr, cp)) { + if (current != null) { + current.end(); + current = null; + } + String svgName = TextGlyphFallback.vanillaSvgName(cp); + if (BetterChatRenderer.renderer != null && svgName != null) { + BetterChatRenderer.renderer.svg(svgName, cursorX, svgY, svgSize, svgSize, + dev.loki.lovisual.render.engine.svg.SvgRenderOptions.fromFile().withAlpha(((argb >>> 24) & 0xFF) / 255.0f)); + } + cursorX += svgSize; + i += Character.charCount(cp); + continue; + } + String glyph = new String(Character.toChars(cp)); + TextRenderer next = rendererForGlyph(tr, cp); + if (next != current) { + if (current != null) current.end(); + current = next; + current.begin(scale, false, false); + } + cursorX = (float) current.render(glyph, cursorX, y, BetterChatRenderer.TMP_COLOR, shadow); + i += Character.charCount(cp); + } + } finally { + if (current != null) current.end(); + } + } + + static String fitText(TextRenderer font, String text, float size, float maxWidth) { + if (text == null) return ""; + if (textWidth(font, text, size) <= maxWidth) return text; + String suffix = "..."; + float suffixW = textWidth(font, suffix, size); + int end = text.length(); + while (end > 0 && textWidth(font, text.substring(0, end), size) + suffixW > maxWidth) { + end--; + } + return end <= 0 ? suffix : text.substring(0, end) + suffix; + } + + static String safeSub(String s, int start, int end) { + if (s == null) return ""; + int len = s.length(); + start = Math.max(0, Math.min(len, start)); + end = Math.max(0, Math.min(len, end)); + if (end < start) { + int t = start; + start = end; + end = t; + } + return s.substring(start, end); + } + + static int clampIndex(int idx, int len) { + return Mth.clamp(idx, 0, Math.max(0, len)); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFrameModel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFrameModel.java new file mode 100644 index 0000000..cc8ad9b --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFrameModel.java @@ -0,0 +1,129 @@ +/* + * 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.features.gui.chat; + +import net.minecraft.util.Mth; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Frame layout record: builds screen-space line/bubble geometry from laid-out visual lines. + * Pure geometry + picking, no rendering or font work. + */ +final class BetterChatFrameModel { + private BetterChatFrameModel() { + } + + record FrameLayout(float x, float y, float w, float h, List lines, List bubbles) { + static FrameLayout empty() { + return new FrameLayout(0, 0, 0, 0, Collections.emptyList(), Collections.emptyList()); + } + + static FrameLayout build(List lines, float x, float y, float w, float h, float fontSize, float lineHeight, float yOffset, float timestampReserve) { + List list = new ArrayList<>(lines.size()); + float cursorY = y + BetterChatRenderer.MESSAGE_PAD_Y + yOffset; + int lastMessageGroup = Integer.MIN_VALUE; + for (int i = 0; i < lines.size(); i++) { + BetterChatModel.VisualLine vl = lines.get(i); + if (i > 0 && vl.messageGroup() != lastMessageGroup) { + cursorY += BetterChatRenderer.MESSAGE_GAP; + } + lastMessageGroup = vl.messageGroup(); + float y0 = cursorY; + float y1 = y0 + fontSize; + List boxes = new ArrayList<>(vl.glyphs().size()); + for (BetterChatModel.Glyph g : vl.glyphs()) { + boxes.add(new BetterChatModel.GlyphBox( + x + BetterChatRenderer.PADDING + BetterChatRenderer.MESSAGE_PAD_X + g.x0(), + y0, + x + BetterChatRenderer.PADDING + BetterChatRenderer.MESSAGE_PAD_X + g.x1(), + y1, + g.charIndex(), + g.charEndExclusive(), + g.color(), + g.font(), + g.hover(), + g.text(), + g.style() + )); + } + list.add(new BetterChatModel.FrameLine(vl.message(), vl.messageIndex(), vl.messageGroup(), y0, y1, boxes)); + cursorY += lineHeight; + } + return new FrameLayout(x, y, w, h, list, buildBubbles(list, x, w, timestampReserve)); + } + + private static List buildBubbles(List lines, float x, float w, float timestampReserve) { + if (lines.isEmpty()) return Collections.emptyList(); + List bubbles = new ArrayList<>(); + int start = 0; + while (start < lines.size()) { + BetterChatModel.FrameLine first = lines.get(start); + int end = start; + float maxRight = x + BetterChatRenderer.PADDING + BetterChatRenderer.MESSAGE_PAD_X; + while (end + 1 < lines.size() && lines.get(end + 1).messageGroup() == first.messageGroup()) { + end++; + } + for (int i = start; i <= end; i++) { + BetterChatModel.FrameLine line = lines.get(i); + if (!line.glyphs().isEmpty()) { + maxRight = Math.max(maxRight, line.glyphs().getLast().x1()); + } + } + BetterChatModel.FrameLine last = lines.get(end); + float bubbleX = x + BetterChatRenderer.PADDING; + float bubbleY = first.y0() - BetterChatRenderer.MESSAGE_PAD_Y; + float maxBubbleW = Math.max(32f, w - BetterChatRenderer.PADDING * 2f); + float desiredW = maxRight - bubbleX + BetterChatRenderer.MESSAGE_PAD_X + Math.max(0f, timestampReserve); + float bubbleW = Mth.clamp(desiredW, 76f, maxBubbleW); + float bubbleH = last.y1() - first.y0() + BetterChatRenderer.MESSAGE_PAD_Y * 2f; + bubbles.add(new BetterChatModel.MessageBubble(last.message(), first.messageGroup(), bubbleX, bubbleY, bubbleW, bubbleH, first, last)); + start = end + 1; + } + return bubbles; + } + + BetterChatModel.MessageClipBounds messageClipBounds() { + if (lines.isEmpty() || h <= 0f) return null; + float clipX = x + BetterChatRenderer.PADDING; + float clipW = Math.max(1f, w - BetterChatRenderer.PADDING * 2f); + return new BetterChatModel.MessageClipBounds(clipX, y, clipW, h); + } + + boolean contains(double mx, double my) { + return mx >= x && mx <= x + w && my >= y && my <= y + h; + } + + BetterChatModel.PickResult pick(double mx, double my) { + if (!contains(mx, my)) return null; + for (BetterChatModel.FrameLine line : lines) { + if (my < line.y0() || my > line.y1() + BetterChatRenderer.LINE_SPACING) continue; + if (line.glyphs().isEmpty()) continue; + float minX = line.glyphs().getFirst().x0(); + float maxX = line.glyphs().getLast().x1(); + float margin = 2f; + if (mx < minX - margin || mx > maxX + margin) continue; + BetterChatModel.GlyphBox closest = null; + for (BetterChatModel.GlyphBox g : line.glyphs()) { + if (mx >= g.x0() && mx <= g.x1()) { + return new BetterChatModel.PickResult(line, g); + } + if (closest == null || Math.abs(mx - g.x1()) < Math.abs(mx - closest.x1())) { + closest = g; + } + } + if (closest != null) { + return new BetterChatModel.PickResult(line, closest); + } + } + return null; + } + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFrameRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFrameRenderer.java new file mode 100644 index 0000000..3d3b9be --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatFrameRenderer.java @@ -0,0 +1,82 @@ +/* + * 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.features.gui.chat; + +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.SystemCursor; +import net.minecraft.client.gui.GuiGraphicsExtractor; + +/** + * Single entry point for the chat HUD render pass; orchestrates the layout, message, input, + * suggestion, scrollbar and tooltip phases. All real work lives in the other package-private helpers. + */ +final class BetterChatFrameRenderer { + private BetterChatFrameRenderer() { + } + + static void renderEngine(Renderer2D rendererIn, + TextRenderer fallback, + GuiGraphicsExtractor ctx, + int screenW, + float baseX, + float baseY) { + BetterChatRenderer.renderer = rendererIn; + SystemCursor.beginFrame(ctx); + try { + renderInternal(ctx, screenW, baseX, baseY); + } finally { + SystemCursor.endFrame(); + } + } + + private static void renderInternal(GuiGraphicsExtractor ctx, int screenW, float baseX, float baseY) { + if (!BetterChatLayoutEngine.prepareFrame(ctx, screenW, baseX, baseY)) return; + BetterChatViewport.composeFrame(); + + BetterChatRenderer.searchHit = false; + if (!BetterChatRenderer.ctxChatOpen) { + BetterChatSearch.deactivate(); + } + BetterChatSuggestionState.updateSearchHotkey(BetterChatRenderer.ctxMc, BetterChatRenderer.ctxChatOpen); + + BetterChatModel.MousePos mouse = BetterChatInputHandler.resolveMouse( + BetterChatRenderer.ctxMc.mouseHandler.xpos(), BetterChatRenderer.ctxMc.mouseHandler.ypos()); + BetterChatRenderer.lastMouseFx = mouse.fx(); + BetterChatRenderer.lastMouseFy = mouse.fy(); + BetterChatRenderer.lastMouseValid = true; + BetterChatRenderer.hoverEntityUuid = null; + BetterChatRenderer.ctxHoverTip = null; + + BetterChatModel.PickResult hover = BetterChatMessageRenderer.drawPhase(); + BetterChatTooltipRenderer.resolveHover(hover, BetterChatRenderer.ctxMc); + + if (BetterChatRenderer.ctxChatOpen) { + BetterChatInputRenderer.renderInput(BetterChatRenderer.ctxMc, BetterChatRenderer.lastFontSizeForUi, BetterChatRenderer.ctxWidth, BetterChatRenderer.ctxBaseX, BetterChatRenderer.ctxFixedInputY); + BetterChatInputHandler.updateChatHit(); + BetterChatSuggestionRenderer.renderSuggestions(); + } else { + BetterChatInputHandler.clearChatHit(); + } + + if (BetterChatRenderer.ctxChatOpen && BetterChatRenderer.maxScrollLines > 0) { + int scrollbarStart = BetterChatRenderer.ctxAutoFollow + ? Math.max(0, BetterChatRenderer.sbTotalLines - BetterChatRenderer.ctxVisibleLimit) + : Math.max(0, BetterChatRenderer.sbTotalLines - BetterChatRenderer.ctxVisibleLimit - BetterChatRenderer.scrollOffsetLines); + BetterChatDrawUtil.renderScrollbar(BetterChatRenderer.frame.x(), BetterChatRenderer.frame.y(), BetterChatRenderer.frame.w(), BetterChatRenderer.frame.h(), scrollbarStart, BetterChatRenderer.ctxVisibleLimit, BetterChatRenderer.sbTotalLines, BetterChatRenderer.lastMouseFx, BetterChatRenderer.lastMouseFy); + } + + if (BetterChatRenderer.ctxChatOpen && BetterChatRenderer.ctxHoverTip != null) { + BetterChatTooltipRenderer.captureTooltip(BetterChatRenderer.ctxHoverTip, (float) BetterChatRenderer.lastMouseFx + BetterChatRenderer.CHAT_TOOLTIP_OFFSET_X, (float) BetterChatRenderer.lastMouseFy + BetterChatRenderer.CHAT_TOOLTIP_OFFSET_Y, ctx); + } + + if (BetterChatRenderer.contextMenu.open()) { + BetterChatRenderer.contextMenu.render((float) BetterChatRenderer.lastMouseFx, (float) BetterChatRenderer.lastMouseFy, BetterChatRenderer.lastFontSizeForUi); + } + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatGlyphRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatGlyphRenderer.java new file mode 100644 index 0000000..802e46f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatGlyphRenderer.java @@ -0,0 +1,148 @@ +/* + * 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.features.gui.chat; + +import dev.loki.lovisual.features.command.CommandOutput; +import dev.loki.lovisual.render.engine.svg.SvgRenderOptions; +import dev.loki.lovisual.render.engine.text.TextGlyphFallback; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import net.minecraft.network.chat.Component; + +import java.util.List; + +/** + * Glyph + command-prefix gradient rendering for laid-out frame lines. + */ +final class BetterChatGlyphRenderer { + private BetterChatGlyphRenderer() { + } + + static void renderGlyphs(List lines, float fontSize, float lineHeight, boolean activeChatSurface) { + if (lines == null || lines.isEmpty()) return; + float scale = BetterChatFontUtil.scaleForSize(fontSize); + TextRenderer current = null; + float currentHeight = 0f; + float shadowOffset = Math.max(1f, fontSize * (activeChatSurface ? 0.06f : 0.08f)); + float shadowAlpha = activeChatSurface ? 0.48f : 0.68f; + for (BetterChatModel.FrameLine line : lines) { + float alpha = activeChatSurface ? 1f : BetterChatMessageRenderer.fade(line.message().ageSeconds()); + if (alpha <= 0.01f) continue; + float baseY = line.y0(); + float reveal = BetterChatMessageRenderer.newMessageReveal(line.message()); + float xOffset = -(1f - reveal) * BetterChatRenderer.NEW_MESSAGE_SLIDE_PX; + boolean commandLine = CommandOutput.isLoVisualMessage(line.message().text()); + List glyphs = line.glyphs(); + for (int gi = 0; gi < glyphs.size(); gi++) { + BetterChatModel.GlyphBox g = glyphs.get(gi); + if (commandLine && g.charIndex() < CommandOutput.PREFIX.length() && !TextGlyphFallback.isSvgFontKey(g.font())) { + if (current != null) { + current.end(); + current = null; + } + int runEnd = gi + 1; + while (runEnd < glyphs.size()) { + BetterChatModel.GlyphBox next = glyphs.get(runEnd); + if (next.charIndex() >= CommandOutput.PREFIX.length()) break; + if (TextGlyphFallback.isSvgFontKey(next.font())) break; + if (!java.util.Objects.equals(next.font(), g.font())) break; + runEnd++; + } + renderCommandPrefixRun(glyphs, gi, runEnd, baseY, lineHeight, xOffset, scale, alpha, shadowOffset, shadowAlpha, line.message().text()); + gi = runEnd - 1; + continue; + } + if (TextGlyphFallback.isSvgFontKey(g.font())) { + if (current != null) { + current.end(); + current = null; + } + String svgName = TextGlyphFallback.svgNameFromFontKey(g.font()); + float gx = g.x0() + xOffset; + float iconSize = Math.max(1.0f, g.x1() - g.x0()); + float iconY = baseY + (lineHeight - iconSize) * 0.5f; + if (svgName != null) { + BetterChatRenderer.renderer.svg(svgName, gx, iconY, iconSize, iconSize, SvgRenderOptions.fromFile().withAlpha(alpha)); + } + continue; + } + TextRenderer tr = BetterChatFontUtil.fontRenderer(g.font()); + if (tr != current) { + if (current != null) { + current.end(); + } + current = tr; + current.begin(scale, false, false); + currentHeight = (float) current.getHeight(false); + } + float textY = baseY + (lineHeight - currentHeight) * 0.5f; + float gx = g.x0() + xOffset; + int shadowColor = BetterChatDrawUtil.mulAlpha(0xFF000000, alpha * shadowAlpha); + BetterChatDrawUtil.applyColor(shadowColor); + current.render(g.text(), gx + shadowOffset, textY, BetterChatRenderer.TMP_COLOR, false); + current.render(g.text(), gx - shadowOffset, textY, BetterChatRenderer.TMP_COLOR, false); + current.render(g.text(), gx, textY + shadowOffset, BetterChatRenderer.TMP_COLOR, false); + current.render(g.text(), gx, textY - shadowOffset, BetterChatRenderer.TMP_COLOR, false); + BetterChatDrawUtil.applyColor(BetterChatDrawUtil.mulAlpha(g.color(), alpha)); + current.render(g.text(), gx, textY, BetterChatRenderer.TMP_COLOR, false); + } + } + if (current != null) { + current.end(); + } + } + + private static void renderCommandPrefixRun(List glyphs, + int from, int to, + float baseY, float lineHeight, float xOffset, + float scale, float alpha, float shadowOffset, float shadowAlpha, + Component source) { + if (from < 0 || to <= from || to > glyphs.size()) return; + BetterChatModel.GlyphBox first = glyphs.get(from); + BetterChatModel.GlyphBox last = glyphs.get(to - 1); + TextRenderer tr = BetterChatFontUtil.fontRenderer(first.font()); + if (tr == null) return; + + StringBuilder text = new StringBuilder(); + for (int i = from; i < to; i++) { + text.append(glyphs.get(i).text()); + } + if (text.isEmpty()) return; + + float runX = first.x0() + xOffset; + float runW = Math.max(1.0f, last.x1() - first.x0()); + CommandOutput.Tone tone = CommandOutput.toneOf(source); + int start = CommandOutput.prefixStartColor(tone); + int end = CommandOutput.prefixEndColor(tone); + int bottomMix = CommandOutput.mixRgb(end, 0xFFFFFFFF, 0.10f); + + tr.begin(scale, false, false); + try { + float textY = baseY + (lineHeight - (float) tr.getHeight(false)) * 0.5f; + int shadowColor = BetterChatDrawUtil.mulAlpha(0xFF000000, alpha * shadowAlpha); + BetterChatDrawUtil.applyColor(shadowColor); + tr.render(text.toString(), runX + shadowOffset, textY, BetterChatRenderer.TMP_COLOR, false); + tr.render(text.toString(), runX - shadowOffset, textY, BetterChatRenderer.TMP_COLOR, false); + tr.render(text.toString(), runX, textY + shadowOffset, BetterChatRenderer.TMP_COLOR, false); + tr.render(text.toString(), runX, textY - shadowOffset, BetterChatRenderer.TMP_COLOR, false); + tr.renderQuadGradient(text.toString(), runX, textY, (idx, cp, x0, y0, x1, y1, out) -> { + float t0 = (float) ((x0 - runX) / runW); + float t1 = (float) ((x1 - runX) / runW); + int leftTop = BetterChatDrawUtil.mulAlpha(CommandOutput.mixRgb(start, end, t0), alpha); + int rightTop = BetterChatDrawUtil.mulAlpha(CommandOutput.mixRgb(start, end, t1), alpha); + int leftBottom = BetterChatDrawUtil.mulAlpha(CommandOutput.mixRgb(start, bottomMix, t0), alpha); + int rightBottom = BetterChatDrawUtil.mulAlpha(CommandOutput.mixRgb(start, bottomMix, t1), alpha); + out[0] = leftTop; + out[1] = leftBottom; + out[2] = rightBottom; + out[3] = rightTop; + }, false); + } finally { + tr.end(); + } + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatHoverCache.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatHoverCache.java index 4665580..76abe99 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatHoverCache.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatHoverCache.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatInputHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatInputHandler.java new file mode 100644 index 0000000..622ba5f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatInputHandler.java @@ -0,0 +1,160 @@ +/* + * 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.features.gui.chat; + +import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; +import dev.loki.lovisual.util.screen.ClientScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.ChatScreen; +import org.lwjgl.glfw.GLFW; + +/** + * Chat-surface interaction: scroll, drag-selection movement, scrollbar drag and hit-testing. + * The mouse-button dispatch lives in {@link BetterChatMouseClickHandler}. + */ +final class BetterChatInputHandler { + private BetterChatInputHandler() { + } + + static BetterChatModel.MousePos resolveMouse(double rawX, double rawY) { + return new BetterChatModel.MousePos(rawX, rawY, rawX, rawY); + } + + static int selectionCaretIndex(BetterChatModel.GlyphBox glyph) { + if (glyph == null) return 0; + return Math.max(glyph.charIndex(), glyph.charEndExclusive() - 1); + } + + static BetterChatModel.PickResult nearestFramePick(double mx, double my) { + if (BetterChatRenderer.frame == null || BetterChatRenderer.frame.lines() == null || BetterChatRenderer.frame.lines().isEmpty()) + return null; + + BetterChatModel.FrameLine bestLine = null; + float bestDist = Float.MAX_VALUE; + for (BetterChatModel.FrameLine line : BetterChatRenderer.frame.lines()) { + float dy; + if (my < line.y0()) { + dy = (float) (line.y0() - my); + } else if (my > line.y1() + BetterChatRenderer.LINE_SPACING) { + dy = (float) (my - (line.y1() + BetterChatRenderer.LINE_SPACING)); + } else { + dy = 0.0f; + } + if (dy < bestDist) { + bestDist = dy; + bestLine = line; + } + } + + if (bestLine == null || bestLine.glyphs().isEmpty()) return null; + BetterChatModel.GlyphBox first = bestLine.glyphs().getFirst(); + BetterChatModel.GlyphBox last = bestLine.glyphs().getLast(); + BetterChatModel.GlyphBox glyph = mx <= first.x0() ? first : last; + return new BetterChatModel.PickResult(bestLine, glyph); + } + + static boolean onScroll(double delta) { + Minecraft mc = Minecraft.getInstance(); + if (!BetterChat.isActive()) return false; + if (!(ClientScreen.current() instanceof ChatScreen)) return false; + BetterChatModel.MousePos mouse = resolveMouse(mc.mouseHandler.xpos(), mc.mouseHandler.ypos()); + double mx = mouse.fx(); + double my = mouse.fy(); + double rawX = mouse.rawX(); + double rawY = mouse.rawY(); + boolean insideSuggest = BetterChatSuggestionState.isInsideSuggestWindow(mx, my, rawX, rawY); + if (insideSuggest) { + int step = delta > 0 ? -1 : 1; + int scrollable = Math.max(0, BetterChatRenderer.suggestTotal - BetterChatRenderer.suggestVisible); + BetterChatRenderer.suggestCurrentStart = net.minecraft.util.Mth.clamp(BetterChatRenderer.suggestCurrentStart + step, 0, scrollable); + BetterChatSuggestionState.applySuggestionWindowState(BetterChatRenderer.suggestCurrentStart, BetterChatRenderer.suggestCurrentSelection); + return true; + } + int step = delta > 0 ? 3 : -3; + BetterChatRenderer.scrollOffsetLines = net.minecraft.util.Mth.clamp(BetterChatRenderer.scrollOffsetLines + step, 0, BetterChatRenderer.maxScrollLines); + BetterChatRenderer.lastScrollInteractionMs = System.currentTimeMillis(); + return false; + } + + static void onMouseMove(double mx, double my) { + if (!BetterChat.isActive()) return; + BetterChatModel.MousePos mouse = resolveMouse(mx, my); + double fx = mouse.fx(); + double fy = mouse.fy(); + if (BetterChatRenderer.draggingScrollbar) { + BetterChatDrawUtil.scrollToPosition(fy); + return; + } + if (BetterChatRenderer.suggestDraggingScrollbar) { + BetterChatSuggestionState.scrollSuggestToPosition(fy); + return; + } + if (BetterChatSuggestionState.isInsideSuggestWindow(fx, fy, mouse.rawX(), mouse.rawY())) return; + + if (BetterChatRenderer.leftPending && !BetterChatRenderer.selecting) { + double dx = fx - BetterChatRenderer.leftDownFx; + double dy = fy - BetterChatRenderer.leftDownFy; + if (dx * dx + dy * dy >= BetterChatRenderer.DRAG_SELECT_THRESHOLD * BetterChatRenderer.DRAG_SELECT_THRESHOLD) { + BetterChatRenderer.selection.update(BetterChatRenderer.leftDownMsgIndex, BetterChatRenderer.leftDownCharIndex); + BetterChatRenderer.selecting = true; + } else { + return; + } + } + + if (!BetterChatRenderer.selecting) return; + BetterChatModel.PickResult pick = BetterChatRenderer.frame.pick(mouse.fx(), mouse.fy()); + if (pick == null) { + pick = nearestFramePick(mouse.fx(), mouse.fy()); + } + if (pick == null) return; + BetterChatRenderer.selection.updateCaret(pick.line().messageIndex(), selectionCaretIndex(pick.glyph())); + } + + static void resetScroll() { + BetterChatRenderer.scrollOffsetLines = 0; + BetterChatRenderer.smoothScrollOffsetLines = 0f; + BetterChatRenderer.draggingScrollbar = false; + BetterChatRenderer.sbEnabled = false; + BetterChatRenderer.sbDragOffset = 0f; + } + + static void onNewMessage() { + if (BetterChatRenderer.scrollOffsetLines > 0 && BetterChatRenderer.scrollOffsetLines <= 2) { + BetterChatRenderer.scrollOffsetLines = 0; + BetterChatRenderer.smoothScrollOffsetLines = 0f; + } + } + + static boolean isInteractive(float mx, float my) { + boolean inChat = BetterChatRenderer.chatHitW > 0f && mx >= BetterChatRenderer.chatHitX && mx <= BetterChatRenderer.chatHitX + BetterChatRenderer.chatHitW && my >= BetterChatRenderer.chatHitY && my <= BetterChatRenderer.chatHitY + BetterChatRenderer.chatHitH; + boolean inSearch = BetterChatRenderer.searchHit && mx >= BetterChatRenderer.searchRectX && mx <= BetterChatRenderer.searchRectX + BetterChatRenderer.searchRectW && my >= BetterChatRenderer.searchRectY && my <= BetterChatRenderer.searchRectY + BetterChatRenderer.searchRectH; + boolean inInput = BetterChatRenderer.hasInputBox && mx >= BetterChatRenderer.inputBoxX && mx <= BetterChatRenderer.inputBoxX + BetterChatRenderer.inputBoxW && my >= BetterChatRenderer.inputBoxY && my <= BetterChatRenderer.inputBoxY + BetterChatRenderer.inputBoxH; + boolean inSuggest = BetterChatSuggestionState.isInsideSuggestWindow(mx, my); + boolean inContext = BetterChatRenderer.contextMenu.open() && BetterChatRenderer.contextMenu.contains(mx, my); + boolean inScrollbar = BetterChatRenderer.sbEnabled && BetterChatDrawUtil.isScrollbarHovered(mx, my); + return inChat || inSearch || inInput || inSuggest || inContext || inScrollbar; + } + + static boolean contains(float mx, float my) { + return isInteractive(mx, my); + } + + static void updateChatHit() { + float hitBottom = BetterChatRenderer.hasInputBox ? BetterChatRenderer.inputBoxY + BetterChatRenderer.inputBoxH : BetterChatRenderer.ctxFixedInputY; + BetterChatRenderer.chatHitX = BetterChatRenderer.ctxBaseX; + BetterChatRenderer.chatHitY = BetterChatRenderer.frame.y(); + BetterChatRenderer.chatHitW = BetterChatRenderer.ctxWidth; + BetterChatRenderer.chatHitH = Math.max(BetterChatRenderer.ctxBoxHeight, hitBottom - BetterChatRenderer.chatHitY); + } + + static void clearChatHit() { + BetterChatRenderer.chatHitX = BetterChatRenderer.chatHitY = BetterChatRenderer.chatHitW = BetterChatRenderer.chatHitH = 0f; + BetterChatRenderer.lastMouseValid = false; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatInputRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatInputRenderer.java new file mode 100644 index 0000000..4730432 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatInputRenderer.java @@ -0,0 +1,196 @@ +/* + * 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.features.gui.chat; +import dev.loki.lovisual.mixins.accessors.ChatScreenAccessor; +import dev.loki.lovisual.render.engine.text.FontInfo; +import dev.loki.lovisual.render.engine.text.Fonts; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ScissorFunction; +import dev.loki.lovisual.util.screen.ClientScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.screens.ChatScreen; +import java.util.ArrayList; +import java.util.List; +import static dev.loki.lovisual.features.theme.Theme.theme; +/** + * Input-field rendering: wrapping, caret, selection highlight, char counter and search chip. + */ +final class BetterChatInputRenderer { + private BetterChatInputRenderer() { + } + static void renderInput(Minecraft mc, float fontSize, float boxW, float x, float inputY) { + if (!(ClientScreen.current() instanceof ChatScreen chatScreen)) return; + EditBox field = ((ChatScreenAccessor) chatScreen).getChatField(); + if (field == null) return; + String fieldText = field.getValue(); + boolean searchMode = BetterChatSearch.isActive(); + String text = searchMode ? BetterChatSearch.getText() : fieldText; + int cursor = searchMode ? text.length() : field.getCursorPosition(); + int selStart = searchMode ? cursor : BetterChatEditBoxUtil.selectionStart(field, cursor); + int selEnd = searchMode ? cursor : BetterChatEditBoxUtil.selectionEnd(field, cursor); + float padX = 12f; + float padY = 7f; + float lineHeight = fontSize + 2f; + float iconGap = 8f; + float searchBoxW = BetterChatRenderer.SEARCH_ICON_WIDTH; + float searchBoxH = BetterChatRenderer.SEARCH_ICON_HEIGHT; + float counterReserve = (!searchMode && text.length() >= BetterChatRenderer.MAX_MESSAGE_CHARS - 20) ? 34f : 0f; + float modeReserve = (searchMode || BetterChatSearch.hasQuery()) ? 74f : 0f; + float rightReserve = counterReserve + modeReserve; + if (!searchMode && text.length() > BetterChatRenderer.MAX_MESSAGE_CHARS) { + text = text.substring(0, BetterChatRenderer.MAX_MESSAGE_CHARS); + field.setValue(text); + BetterChatEditBoxUtil.setCursorSafe(field, text.length()); + } + int remaining = searchMode ? Integer.MAX_VALUE : BetterChatRenderer.MAX_MESSAGE_CHARS - text.length(); + float maxLineWidth = Math.max(32f, boxW - padX * 2f - searchBoxW - iconGap - rightReserve); + List lines = wrapInput(text, fontSize, maxLineWidth); + if (lines.isEmpty()) { + lines = List.of(new BetterChatModel.InputLine(0, 0, 0f)); + } + float contentHeight = lines.size() * lineHeight; + float h = Math.max(36f, contentHeight + padY * 2f); + BetterChatRenderer.inputBoxX = x; + BetterChatRenderer.inputBoxY = inputY; + BetterChatRenderer.inputBoxW = boxW; + BetterChatRenderer.inputBoxH = h; + BetterChatRenderer.hasInputBox = true; + BetterChatDrawUtil.drawGlassPill(x, inputY, boxW, h, Math.min(BetterChatRenderer.INPUT_RADIUS, h * 0.5f), 0.92f, false); + float searchX = x + padX; + float searchY = inputY + (h - searchBoxH) * 0.5f; + renderSearchIcon(searchX, searchY, searchBoxW, searchBoxH, BetterChatSearch.isActive(), BetterChatSearch.hasQuery()); + BetterChatRenderer.searchRectX = searchX; + BetterChatRenderer.searchRectY = searchY; + BetterChatRenderer.searchRectW = searchBoxW; + BetterChatRenderer.searchRectH = searchBoxH; + BetterChatRenderer.searchHit = true; + float textX = searchX + searchBoxW + iconGap; + float textClipW = Math.max(20f, x + boxW - padX - textX - rightReserve); + TextRenderer tr = BetterChatFontUtil.getIosevkaRegular(); + float textScale = BetterChatFontUtil.scaleForSize(fontSize); + boolean clipped = ScissorFunction.pushRaw(textX, inputY, textClipW, h); + if (tr != null) { + tr.begin(textScale, false, false); + float textH = (float) tr.getHeight(false); + tr.end(); + float textYOffset = (lineHeight - textH) * 0.5f; + float lineY = inputY + padY + textYOffset; + if (text.isEmpty()) { + BetterChatFontUtil.drawText(tr, searchMode ? "Search chat..." : "Message...", textX, lineY, fontSize, theme().textMuted(), false); + } else { + for (BetterChatModel.InputLine line : lines) { + String slice = BetterChatFontUtil.safeSub(text, line.start(), line.end()); + BetterChatFontUtil.drawText(tr, slice, textX, lineY, fontSize, theme().textPrimary(), true); + lineY += lineHeight; + } + } + } + int min = Math.min(selStart, selEnd); + int max = Math.max(selStart, selEnd); + if (max > min) { + for (int i = 0; i < lines.size(); i++) { + BetterChatModel.InputLine line = lines.get(i); + int lineStart = line.start(); + int lineEnd = line.end(); + int selA = Math.max(min, lineStart); + int selB = Math.min(max, lineEnd); + if (selB > selA) { + float selX = textX + BetterChatFontUtil.textWidth(BetterChatFontUtil.getIosevkaRegular(), BetterChatFontUtil.safeSub(text, lineStart, selA), fontSize); + float selW = BetterChatFontUtil.textWidth(BetterChatFontUtil.getIosevkaRegular(), BetterChatFontUtil.safeSub(text, selA, selB), fontSize); + float sy = inputY + padY + i * lineHeight; + BetterChatDrawUtil.drawRoundedRect(selX, sy, selW, lineHeight, 3.5f, BetterChatDrawUtil.withAlpha(theme().accent(), 0x4A)); + } + } + } + int caretLine = 0; + for (int i = 0; i < lines.size(); i++) { + BetterChatModel.InputLine line = lines.get(i); + if (cursor >= line.start() && cursor <= line.end()) { + caretLine = i; + break; + } + } + float caretX = textX + widthTo(text, lines, cursor, fontSize); + float caretY = inputY + padY + caretLine * lineHeight; + boolean blink = (System.currentTimeMillis() / 500L) % 2 == 0; + if (blink) { + BetterChatDrawUtil.drawRoundedRect(caretX, caretY + 1f, 1.35f, Math.max(8f, lineHeight - 2f), 0.8f, BetterChatDrawUtil.withAlpha(theme().textPrimary(), 0xD8)); + } + if (clipped) ScissorFunction.pop(); + if (BetterChatSearch.isActive() || BetterChatSearch.hasQuery()) { + String q = BetterChatSearch.isActive() ? "Search" : BetterChatSearch.getText(); + float chipFont = Math.max(10f, fontSize * 0.72f); + String chipText = BetterChatFontUtil.fitText(BetterChatFontUtil.getInterRegular(), q, chipFont, Math.max(36f, boxW * 0.28f)); + float chipW = BetterChatFontUtil.textWidth(BetterChatFontUtil.getInterRegular(), chipText, chipFont) + 14f; + float chipH = Math.min(22f, h - 8f); + float chipX = x + boxW - padX - chipW - counterReserve; + float chipY = inputY + (h - chipH) * 0.5f; + BetterChatDrawUtil.drawRoundedRect(chipX, chipY, chipW, chipH, chipH * 0.5f, BetterChatDrawUtil.withAlpha(theme().accentSoft(), BetterChatSearch.isActive() ? 0x66 : 0x40)); + BetterChatFontUtil.drawText(BetterChatFontUtil.getInterRegular(), chipText, chipX + 7f, chipY + (chipH - BetterChatFontUtil.textHeight(BetterChatFontUtil.getInterRegular(), chipFont)) * 0.5f, chipFont, + BetterChatSearch.hasQuery() ? theme().textPrimary() : theme().textMuted(), false); + } + if (!searchMode && remaining <= 20) { + String remStr = String.valueOf(Math.max(0, remaining)); + float remSize = fontSize * 0.74f; + int remColor = remaining <= 5 ? BetterChatDrawUtil.withAlpha(theme().accent(), 0xFF) : BetterChatDrawUtil.withAlpha(theme().textMuted(), 0xCC); + BetterChatFontUtil.drawText(BetterChatFontUtil.getIosevkaRegular(), remStr, searchX + 2.0f, + inputY + h + 3.0f, + remSize, remColor, false); + } + } + private static List wrapInput(String text, float fontSize, float maxWidth) { + List lines = new ArrayList<>(); + int start = 0; + float width = 0f; + for (int i = 0; i < text.length(); ) { + int cp = text.codePointAt(i); + int cpLen = Character.charCount(cp); + String glyphText = new String(Character.toChars(cp)); + float cw = BetterChatFontUtil.textWidth(BetterChatFontUtil.getIosevkaRegular(), glyphText, fontSize); + if (width + cw > maxWidth && width > 0f) { + lines.add(new BetterChatModel.InputLine(start, i, width)); + start = i; + width = 0f; + } + width += cw; + i += cpLen; + } + lines.add(new BetterChatModel.InputLine(start, text.length(), width)); + return lines; + } + private static float widthTo(String text, List lines, int cursorIndex, float fontSize) { + if (lines.isEmpty()) return 0f; + for (BetterChatModel.InputLine line : lines) { + if (cursorIndex >= line.start() && cursorIndex <= line.end()) { + return BetterChatFontUtil.textWidth(BetterChatFontUtil.getIosevkaRegular(), BetterChatFontUtil.safeSub(text, line.start(), cursorIndex), fontSize); + } + } + BetterChatModel.InputLine last = lines.getLast(); + return BetterChatFontUtil.textWidth(BetterChatFontUtil.getIosevkaRegular(), BetterChatFontUtil.safeSub(text, last.start(), last.end()), fontSize); + } + static void renderSearchIcon(float x, float y, float w, float h, boolean active, boolean hasQuery) { + boolean hover = BetterChatRenderer.lastMouseValid && BetterChatRenderer.lastMouseFx >= x && BetterChatRenderer.lastMouseFx <= x + w && BetterChatRenderer.lastMouseFy >= y && BetterChatRenderer.lastMouseFy <= y + h; + float radius = h * 0.5f; + int bg = active + ? BetterChatDrawUtil.withAlpha(theme().accent(), 0x8E) + : (hasQuery ? BetterChatDrawUtil.withAlpha(theme().accentSoft(), 0x8A) : BetterChatDrawUtil.withAlpha(theme().surface(), hover ? 0xC0 : 0xA2)); + int tint = BetterChatDrawUtil.withAlpha(theme().accent(), active ? 0x30 : (hasQuery ? 0x24 : 0x18)); + int strokeA = active ? BetterChatDrawUtil.withAlpha(theme().accent(), 0xC8) : BetterChatDrawUtil.withAlpha(theme().textPrimary(), hover ? 0x38 : 0x24); + int strokeB = BetterChatDrawUtil.withAlpha(theme().accentSoft(), active ? 0x86 : (hasQuery ? 0x66 : 0x40)); + BetterChatDrawUtil.drawRoundedRect(x, y, w, h, radius, bg); + BetterChatDrawUtil.drawRoundedRect(x + 1f, y + 1f, w - 2f, h - 2f, Math.max(0f, radius - 1f), tint); + BetterChatDrawUtil.drawRoundedRectStrokeGradient(x, y, w, h, radius, 0.7f, strokeA, strokeB); + TextRenderer icons = Fonts.renderer("Icons", FontInfo.Type.Regular, BetterChatFontUtil.getInterRegular()); + String icon = "s"; + float iconSize = h * 0.50f; + float iconW = BetterChatFontUtil.textWidth(icons, icon, iconSize); + float iconH = BetterChatFontUtil.textHeight(icons, iconSize); + int iconColor = active || hasQuery ? theme().textPrimary() : BetterChatDrawUtil.withAlpha(theme().textPrimary(), hover ? 0xD8 : 0xB8); + BetterChatFontUtil.drawText(icons, icon, x + (w - iconW) * 0.5f, y + (h - iconH) * 0.5f - h * 0.015f, iconSize, iconColor, false); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatLayoutEngine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatLayoutEngine.java new file mode 100644 index 0000000..84d0dd7 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatLayoutEngine.java @@ -0,0 +1,196 @@ +/* + * 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.features.gui.chat; +import dev.loki.lovisual.features.command.CommandOutput; +import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; +import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; +import dev.loki.lovisual.features.gui.hud.nondraggable.impl.BetterTooltips; +import dev.loki.lovisual.util.screen.ClientScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.screens.ChatScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import java.util.Collections; +import java.util.List; +final class BetterChatLayoutEngine { + private BetterChatLayoutEngine() { + } + static void markLayoutDirty() { + } + static BetterChatModel.LayoutResult layoutLinesTailCached(List messages, int[] messageGroups, float fontSize, float maxWidth, int maxLines) { + if (messages.isEmpty()) return new BetterChatModel.LayoutResult(Collections.emptyList(), 0); + List lines = new java.util.ArrayList<>(); + int seenMessages = 0; + for (int mi = messages.size() - 1; mi >= 0; mi--) { + ChatLine msg = messages.get(mi); + int messageGroup = messageGroups != null && mi >= 0 && mi < messageGroups.length ? messageGroups[mi] : mi; + List cached = BetterChatLineLayout.cachedMessageLines(msg, fontSize, maxWidth); + for (int j = cached.size() - 1; j >= 0; j--) { + BetterChatModel.CachedLine cl = cached.get(j); + lines.addFirst(new BetterChatModel.VisualLine(msg, mi, messageGroup, cl.startChar(), cl.endChar(), cl.glyphs())); + } + seenMessages++; + if (lines.size() >= maxLines) break; + } + return new BetterChatModel.LayoutResult(lines, seenMessages); + } + static float computeWidth(int screenW, float ratio) { + float clamped = Mth.clamp(ratio, 0.2f, 0.8f); + float w = screenW * clamped; + return Mth.clamp(w, 320f, 560f); + } + static BetterChatStore buildPreviewStore() { + if (BetterChatRenderer.previewStore == null) { + BetterChatStore store = new BetterChatStore(); + store.add(Component.literal("Better Chat")); + store.add(Component.literal("Drag to position")); + store.add(Component.literal("Messages appear here")); + BetterChatRenderer.previewStore = store; + } + return BetterChatRenderer.previewStore; + } + /** + * @return false when there is nothing to render this frame (caller must bail before draw phase). + */ + static boolean prepareFrame(GuiGraphicsExtractor ctx, int screenW, float baseX, float baseY) { + BetterChatRenderer.ctxGui = ctx; + BetterChatRenderer.ctxBaseX = baseX; + BetterChatRenderer.ctxBaseY = baseY; + BetterChat settings = BetterChat.get(); + boolean preview = DraggableHudElementRegistry.isForceVisible(); + if (settings == null || (!settings.isEnabled() && !preview)) { + BetterChatRenderer.lastRenderWidth = 0f; + BetterChatRenderer.lastRenderHeight = 0f; + return false; + } + Minecraft mc = Minecraft.getInstance(); + if (mc == null || (mc.player == null && !preview)) { + BetterChatRenderer.lastRenderWidth = 0f; + BetterChatRenderer.lastRenderHeight = 0f; + return false; + } + if (!preview && mc.isPaused()) { + BetterChatRenderer.selection.clear(); + BetterChatRenderer.contextMenu = BetterChatContextMenuModel.ContextMenu.closed(); + BetterChatRenderer.selecting = false; + BetterChatRenderer.lastRenderWidth = 0f; + BetterChatRenderer.lastRenderHeight = 0f; + return false; + } + BetterChatStore store = (preview && mc.player == null) + ? buildPreviewStore() + : BetterChatStoreManager.getActiveStore(mc); + if (store == null) { + if (preview) { + store = buildPreviewStore(); + } else { + BetterChatRenderer.lastRenderWidth = 0f; + BetterChatRenderer.lastRenderHeight = 0f; + return false; + } + } + boolean chatOpen = ClientScreen.current() instanceof ChatScreen; + boolean activeChatSurface = chatOpen || preview; + if (!chatOpen && store.size() == 0) { + if (preview) { + store = buildPreviewStore(); + } else { + BetterChatRenderer.selection.clear(); + BetterChatRenderer.contextMenu = BetterChatContextMenuModel.ContextMenu.closed(); + BetterChatRenderer.lastRenderWidth = 0f; + BetterChatRenderer.lastRenderHeight = 0f; + return false; + } + } + if (!chatOpen) { + BetterChatRenderer.selection.clear(); + BetterChatRenderer.contextMenu = BetterChatContextMenuModel.ContextMenu.closed(); + BetterChatRenderer.selecting = false; + BetterChatRenderer.storedScreen = null; + BetterChatRenderer.draggingScrollbar = false; + BetterChatRenderer.sbEnabled = false; + BetterChatRenderer.scrollOffsetLines = 0; + BetterChatSearch.deactivate(); + BetterChatSuggestionState.resetSuggestionTracking(); + } + if (chatOpen && ctx != null) { + BetterTooltips.beginTooltipFrame(); + BetterTooltips.setDrawContext(ctx); + } + BetterChatRenderer.tooltipCaptured = false; + int visibleLimit = Math.max(1, chatOpen ? settings.maxLines() : Math.min(settings.maxLines(), 12)); + List commandOutputMessages = settings.hideVanilla() + ? CommandOutput.recentMessages() + : List.of(); + int totalMessages = store.size() + commandOutputMessages.size(); + boolean autoFollow = BetterChatRenderer.scrollOffsetLines == 0; + boolean tsEnabled = settings.timestampEnabled(); + boolean tsSeconds = settings.timestampSeconds(); + int tsColor = settings.timestampColor(); + boolean tsActiveOnly = settings.timestampToggles().get("active_only"); + boolean tsTipDate = settings.timestampToggles().get("hover_date"); + boolean tsTipUnix = settings.timestampToggles().get("hover_unix"); + boolean showTs = tsEnabled && (!tsActiveOnly || chatOpen); + List messages; + if (BetterChatSearch.hasQuery() && BetterChatSearch.results() != null && chatOpen) { + List res = BetterChatSearch.results(); + totalMessages = res.size(); + int maxScrollSearch = Math.max(0, totalMessages - visibleLimit); + BetterChatRenderer.scrollOffsetLines = Mth.clamp(BetterChatRenderer.scrollOffsetLines, 0, maxScrollSearch); + int tailBudget = Math.min(totalMessages, Math.max(visibleLimit + BetterChatRenderer.scrollOffsetLines + 20, visibleLimit + 10)); + int endIdx = Math.min(totalMessages, Math.max(0, totalMessages - BetterChatRenderer.scrollOffsetLines)); + int startIdx = Math.max(0, endIdx - tailBudget); + if (startIdx > endIdx) startIdx = endIdx; + messages = res.subList(startIdx, endIdx); + } else { + int tailBudget = chatOpen + ? Math.max(visibleLimit + BetterChatRenderer.scrollOffsetLines + 80, visibleLimit) + : Math.max(visibleLimit + 8, visibleLimit); + int needed = Math.min(BetterChatRenderer.MAX_HISTORY, Math.min(totalMessages, tailBudget)); + messages = BetterChatCommandMerge.mergeCommandOutput(store.tail(Math.min(store.size(), needed)), commandOutputMessages, needed); + } + BetterChatRenderer.lastMessages = messages; + int[] messageGroups = BetterChatMessageGrouping.groupIds(messages); + float fontSize = 16f * settings.fontScale(); + float width = computeWidth(screenW, settings.widthRatio()); + float tsWidth = 0f; + if (showTs) { + String sampleTs = tsSeconds ? "00:00:00" : "00:00"; + tsWidth = BetterChatFontUtil.textWidth(BetterChatFontUtil.getInterRegular(), sampleTs, Math.max(9f, fontSize * 0.72f)) + BetterChatRenderer.MESSAGE_TS_GAP; + } + float contentWidth = Math.max(32f, width - BetterChatRenderer.PADDING * 2f - BetterChatRenderer.MESSAGE_PAD_X * 2f - tsWidth); + BetterChatRenderer.lastFontSizeForUi = fontSize; + int lineTarget = visibleLimit + BetterChatRenderer.scrollOffsetLines + Math.max(10, visibleLimit / 2) + 2; + long perfT0 = System.nanoTime(); + BetterChatModel.LayoutResult layoutResult = layoutLinesTailCached(messages, messageGroups, fontSize, contentWidth, lineTarget); + long perfT1 = System.nanoTime(); + BetterChatRenderer.ctxSettings = settings; + BetterChatRenderer.ctxMc = mc; + BetterChatRenderer.ctxPreview = preview; + BetterChatRenderer.ctxChatOpen = chatOpen; + BetterChatRenderer.ctxActiveSurface = activeChatSurface; + BetterChatRenderer.ctxShowTs = showTs; + BetterChatRenderer.ctxHasSeconds = tsSeconds; + BetterChatRenderer.ctxTsColor = tsColor; + BetterChatRenderer.ctxTipDate = tsTipDate; + BetterChatRenderer.ctxTipUnix = tsTipUnix; + BetterChatRenderer.ctxAutoFollow = autoFollow; + BetterChatRenderer.ctxWidth = width; + BetterChatRenderer.ctxContentWidth = contentWidth; + BetterChatRenderer.ctxTsWidth = tsWidth; + BetterChatRenderer.ctxTotalMessages = totalMessages; + BetterChatRenderer.ctxVisibleLimit = visibleLimit; + BetterChatRenderer.ctxMessageGroups = messageGroups; + BetterChatRenderer.ctxAllLines = layoutResult.lines(); + BetterChatRenderer.ctxMessagesSeen = layoutResult.messagesSeen(); + BetterChatRenderer.ctxPerfT0 = perfT0; + BetterChatRenderer.ctxPerfT1 = perfT1; + BetterChatRenderer.hasInputBox = false; + return true; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatLineLayout.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatLineLayout.java new file mode 100644 index 0000000..1a1e45f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatLineLayout.java @@ -0,0 +1,180 @@ +/* + * 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.features.gui.chat; + +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.Style; + +import java.util.ArrayList; +import java.util.List; + +import dev.loki.lovisual.render.engine.text.TextGlyphFallback; +import dev.loki.lovisual.render.engine.text.TextRenderer; + +import static dev.loki.lovisual.features.theme.Theme.theme; + +/** + * Builds per-message wrapped glyph lines (cached on identity maps held by the facade). + * Extracted from {@link BetterChatRenderer}; behavior unchanged. + */ +final class BetterChatLineLayout { + private BetterChatLineLayout() { + } + + static List cachedMessageLines(ChatLine msg, float fontSize, float maxWidth) { + BetterChatModel.CachedMessageLayout cached = BetterChatRenderer.MESSAGE_LAYOUT_CACHE.get(msg); + if (cached != null && Math.abs(cached.fontSize() - fontSize) < 0.01f && Math.abs(cached.maxWidth() - maxWidth) < 0.5f) { + return cached.lines(); + } + + List segments = BetterChatRenderer.SEGMENT_CACHE.computeIfAbsent(msg, m -> BetterChatSegmentUtil.flatten(m.text())); + List rebuilt = new ArrayList<>(); + TextRenderer activeRenderer = null; + String activeFont = null; + float scale = BetterChatFontUtil.scaleForSize(fontSize); + + int charIndex = 0; + float lineX = 0f; + List glyphs = new ArrayList<>(); + int lineStartIndex = 0; + int breakGlyphIdx = -1; + int breakCharIdx = -1; + + for (BetterChatModel.Segment seg : segments) { + Style style = seg.style(); + String font = BetterChatFontUtil.fontForStyle(style); + int color = BetterChatSegmentUtil.resolveSegmentColor(seg, style, style.getHoverEvent()); + HoverEvent hover = style.getHoverEvent(); + String txt = seg.text(); + + for (int c = 0; c < txt.length(); ) { + int cp = txt.codePointAt(c); + int cpLen = Character.charCount(cp); + + if (cp == '\n') { + rebuilt.add(new BetterChatModel.CachedLine(lineStartIndex, Math.max(lineStartIndex, charIndex - 1), glyphs)); + glyphs = new ArrayList<>(); + lineX = 0f; + lineStartIndex = charIndex; + breakGlyphIdx = -1; + breakCharIdx = -1; + charIndex += 1; + c += 1; + continue; + } + + String glyphText = new String(Character.toChars(cp)); + + String resolvedFont = BetterChatFontUtil.fontForGlyph(font, cp); + boolean svgGlyph = TextGlyphFallback.isSvgFontKey(resolvedFont); + TextRenderer tr = svgGlyph ? null : BetterChatFontUtil.fontRenderer(resolvedFont); + + if (svgGlyph) { + if (activeRenderer != null) { + activeRenderer.end(); + activeRenderer = null; + } + activeFont = resolvedFont; + } else if (tr != activeRenderer) { + if (activeRenderer != null) { + activeRenderer.end(); + } + activeRenderer = tr; + activeFont = resolvedFont; + if (activeRenderer != null) { + activeRenderer.begin(scale, true, false); + } + } + float cw = svgGlyph + ? BetterChatFontUtil.svgGlyphSize(BetterChatFontUtil.fontRenderer(font), fontSize, false) + : activeRenderer != null ? (float) activeRenderer.getWidth(glyphText, false) : 0f; + int glyphCharIndex = charIndex; + + if (lineX + cw > maxWidth && lineX > 0f) { + if (breakGlyphIdx >= 0) { + List before = new ArrayList<>(glyphs.subList(0, breakGlyphIdx)); + int endChar = Math.max(lineStartIndex, breakCharIdx - 1); + rebuilt.add(new BetterChatModel.CachedLine(lineStartIndex, endChar, before)); + + List remaining = glyphs.subList(breakGlyphIdx + 1, glyphs.size()); + glyphs = new ArrayList<>(remaining.size()); + float nx = 0f; + for (BetterChatModel.Glyph g : remaining) { + float gw = g.x1() - g.x0(); + glyphs.add(new BetterChatModel.Glyph( + nx, + nx + gw, + g.charIndex(), + g.charEndExclusive(), + g.color(), + g.hover(), + g.font(), + g.text(), + g.style() + )); + nx += gw; + } + lineX = nx; + lineStartIndex = breakCharIdx + 1; + breakGlyphIdx = -1; + breakCharIdx = -1; + } else { + rebuilt.add(new BetterChatModel.CachedLine(lineStartIndex, Math.max(lineStartIndex, charIndex - 1), glyphs)); + glyphs = new ArrayList<>(); + lineX = 0f; + lineStartIndex = charIndex; + } + } + + glyphs.add(new BetterChatModel.Glyph( + lineX, + lineX + cw, + glyphCharIndex, + glyphCharIndex + cpLen, + color, + hover, + activeFont != null ? activeFont : resolvedFont, + glyphText, + style + )); + lineX += cw; + + charIndex += cpLen; + + if (cp == ' ') { + breakGlyphIdx = glyphs.size() - 1; + breakCharIdx = glyphCharIndex; + } + + c += cpLen; + } + } + + if (!glyphs.isEmpty()) { + rebuilt.add(new BetterChatModel.CachedLine(lineStartIndex, charIndex - 1, glyphs)); + } else if (charIndex == 0) { + rebuilt.add(new BetterChatModel.CachedLine(0, 0, List.of(new BetterChatModel.Glyph( + 0f, + 2f, + 0, + 1, + theme().textPrimary(), + null, + "iosevka_medium", + " ", + Style.EMPTY + )))); + } + + if (activeRenderer != null) { + activeRenderer.end(); + } + BetterChatRenderer.MESSAGE_LAYOUT_CACHE.put(msg, new BetterChatModel.CachedMessageLayout(fontSize, maxWidth, rebuilt)); + return rebuilt; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMessageGrouping.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMessageGrouping.java index 2dd34f5..b1c04cf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMessageGrouping.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMessageGrouping.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMessageRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMessageRenderer.java new file mode 100644 index 0000000..c2e583c --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMessageRenderer.java @@ -0,0 +1,192 @@ +/* + * 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.features.gui.chat; +import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ClipFunction; +import net.minecraft.util.Mth; +import java.util.List; +import static dev.loki.lovisual.render.engine.text.TextGlyphFallback.isSvgFontKey; +import static dev.loki.lovisual.features.theme.Theme.theme; +import static dev.loki.lovisual.features.gui.chat.ChatHoverUtil.HoverTip; +/** + * Message-area drawing: glass bubbles, selection rectangles, timestamp overlays and glyph pickup. + * Extracted from {@link BetterChatRenderer}; behavior unchanged. + */ +final class BetterChatMessageRenderer { + private BetterChatMessageRenderer() { + } + static float fade(float ageSeconds) { + BetterChat cfg = BetterChat.get(); + float life = cfg != null ? cfg.fadeSeconds() : 12f; + if (life <= 0f) return 0f; + float fadeDur = Math.min(2.0f, Math.max(0.35f, life * 0.18f)); + float holdDur = Math.max(0f, life - fadeDur); + if (ageSeconds <= holdDur) return 1f; + float t = (ageSeconds - holdDur) / fadeDur; + t = Mth.clamp(t, 0f, 1f); + float inv = 1f - t; + return inv * inv * inv; + } + static float newMessageReveal(ChatLine message) { + if (message == null) return 1f; + float age = message.ageSeconds(); + if (age <= 0f) return 0f; + if (age >= BetterChatRenderer.NEW_MESSAGE_REVEAL_SECONDS) return 1f; + float t = Mth.clamp(age / BetterChatRenderer.NEW_MESSAGE_REVEAL_SECONDS, 0f, 1f); + float inv = 1f - t; + return 1f - inv * inv * inv; + } + static BetterChatModel.PickResult drawPhase() { + BetterChatFrameModel.FrameLayout frame = BetterChatRenderer.frame; + boolean activeChatSurface = BetterChatRenderer.ctxActiveSurface; + boolean showTs = BetterChatRenderer.ctxShowTs; + TextRenderer tsRenderer = showTs ? BetterChatFontUtil.getInterRegular() : null; + float tsFontSize = Math.max(9f, BetterChatRenderer.lastFontSizeForUi * 0.72f); + float tsTextHeight = 0f; + if (showTs && tsRenderer != null) { + float tsScale = BetterChatFontUtil.scaleForSize(tsFontSize); + tsRenderer.begin(tsScale, false, false); + tsTextHeight = (float) tsRenderer.getHeight(false); + tsRenderer.end(); + } + boolean chatClip = false; + BetterChatModel.MessageClipBounds clipBounds = frame.messageClipBounds(); + if (clipBounds != null) { + if (!frame.bubbles().isEmpty()) { + Renderer2D.requestLiquidGlassBlurBeforeNextShapeClip(); + } + float clipRadius = Math.min(BetterChatRenderer.RADIUS, clipBounds.h() * 0.5f); + chatClip = ClipFunction.pushRoundedRect( + clipBounds.x(), clipBounds.y(), clipBounds.w(), clipBounds.h(), + clipRadius, clipRadius, 0.0f, 0.0f + ); + } + drawMessageBubbles(frame.bubbles(), activeChatSurface); + for (BetterChatModel.FrameLine line : frame.lines()) { + float alpha = activeChatSurface ? 1f : fade(line.message().ageSeconds()); + if (alpha <= 0.01f) continue; + drawSelection(line, alpha, BetterChatRenderer.ctxLineHeight); + } + BetterChatGlyphRenderer.renderGlyphs(frame.lines(), BetterChatRenderer.lastFontSizeForUi, BetterChatRenderer.ctxLineHeight, activeChatSurface); + if (showTs && tsRenderer != null) { + BetterChatRenderer.ctxHoverTip = renderBubbleTimestamps( + tsRenderer, + frame.bubbles(), + tsFontSize, + tsTextHeight, + BetterChatRenderer.ctxHasSeconds, + BetterChatRenderer.ctxTsColor, + BetterChatRenderer.ctxTipDate, + BetterChatRenderer.ctxTipUnix, + activeChatSurface, + BetterChatRenderer.ctxChatOpen, + BetterChatRenderer.ctxHoverTip + ); + } + if (chatClip) ClipFunction.pop(); + return frame.pick(BetterChatRenderer.lastMouseFx, BetterChatRenderer.lastMouseFy); + } + private static void drawMessageBubbles(List bubbles, boolean activeChatSurface) { + if (bubbles == null || bubbles.isEmpty()) return; + for (BetterChatModel.MessageBubble bubble : bubbles) { + float alpha = activeChatSurface ? 1f : fade(bubble.message().ageSeconds()); + if (alpha <= 0.01f) continue; + float reveal = newMessageReveal(bubble.message()); + float x = bubble.x() - (1f - reveal) * BetterChatRenderer.NEW_MESSAGE_SLIDE_PX; + float y = bubble.y(); + float w = bubble.w(); + float h = bubble.h(); + drawMessageBubbleGlass(x, y, w, h, Math.min(BetterChatRenderer.MESSAGE_RADIUS, h * 0.5f), alpha); + } + } + private static void drawMessageBubbleGlass(float x, float y, float w, float h, float radius, float alpha) { + if (BetterChatRenderer.renderer == null || w <= 0f || h <= 0f) return; + float drawAlpha = Mth.clamp(alpha, 0.0f, 1.0f); + if (drawAlpha <= 0.001f) return; + BetterChat settings = BetterChat.get(); + float configuredAlpha = settings != null ? settings.liquidGlassAlphaFactor() : (230f / 255f); + float blurStrength = configuredAlpha * drawAlpha; + float glassScale = BetterChatRenderer.MESSAGE_RADIUS <= 0.0f ? 1.0f : radius / BetterChatRenderer.MESSAGE_RADIUS; + HudRenderUtil.drawLiquidGlassCorners( + x, y, w, h, + radius, radius, radius, radius, + glassScale, false, + blurStrength, drawAlpha * 0.74f, + theme().accent() + ); + BetterChatDrawUtil.drawRoundedRect(x, y, w, h, radius, + BetterChatDrawUtil.withAlpha(theme().windowBg(), Math.round(0x08 * drawAlpha))); + } + static HoverTip renderBubbleTimestamps(TextRenderer tsRenderer, + List bubbles, + float tsFontSize, + float tsTextHeight, + boolean withSeconds, + int tsColor, + boolean tsTipDate, + boolean tsTipUnix, + boolean activeChatSurface, + boolean chatOpen, + HoverTip currentHover) { + if (bubbles == null || bubbles.isEmpty()) return currentHover; + HoverTip hover = currentHover; + float tsScale = BetterChatFontUtil.scaleForSize(tsFontSize); + float shadowOffset = Math.max(0.75f, tsFontSize * 0.07f); + tsRenderer.begin(tsScale, false, false); + try { + for (BetterChatModel.MessageBubble bubble : bubbles) { + float alpha = activeChatSurface ? 1f : fade(bubble.message().ageSeconds()); + if (alpha <= 0.01f) continue; + String ts = BetterChatTooltipRenderer.formatTimestamp(bubble.message().timestampMs(), withSeconds); + float textW = (float) tsRenderer.getWidth(ts, false); + float reveal = newMessageReveal(bubble.message()); + float tx = bubble.x() + bubble.w() - BetterChatRenderer.MESSAGE_PAD_X - textW - (1f - reveal) * BetterChatRenderer.NEW_MESSAGE_SLIDE_PX; + float ty = bubble.lastLine().y0() + (bubble.lastLine().y1() - bubble.lastLine().y0() - tsTextHeight) * 0.5f; + int shadowColor = BetterChatDrawUtil.mulAlpha(0xFF000000, alpha * 0.46f); + BetterChatDrawUtil.applyColor(shadowColor); + tsRenderer.render(ts, tx + shadowOffset, ty, BetterChatRenderer.TMP_COLOR, false); + tsRenderer.render(ts, tx, ty + shadowOffset, BetterChatRenderer.TMP_COLOR, false); + BetterChatDrawUtil.applyColor(BetterChatDrawUtil.mulAlpha(tsColor, alpha * 0.82f)); + tsRenderer.render(ts, tx, ty, BetterChatRenderer.TMP_COLOR, false); + if (hover == null && chatOpen && BetterChatRenderer.lastMouseValid) { + float hitPad = 2f; + if (BetterChatRenderer.lastMouseFx >= tx - hitPad && BetterChatRenderer.lastMouseFx <= tx + textW + hitPad + && BetterChatRenderer.lastMouseFy >= ty - hitPad && BetterChatRenderer.lastMouseFy <= ty + tsTextHeight + hitPad) { + hover = BetterChatTooltipRenderer.buildTimestampTooltip(bubble.message().timestampMs(), tsTipDate, tsTipUnix); + } + } + } + } finally { + tsRenderer.end(); + } + return hover; + } + private static void drawSelection(BetterChatModel.FrameLine line, float alpha, float lineHeight) { + if (!BetterChatRenderer.selection.appliesToLine(line.messageIndex())) return; + int selStart = BetterChatRenderer.selection.startForLine(line.messageIndex()); + int selEnd = BetterChatRenderer.selection.endForLine(line.messageIndex()); + if (selStart < 0 && selEnd < 0) return; + float y0 = line.y0() - 1.5f; + float h = lineHeight + 3f; + float startX = Float.NaN; + float endX = Float.NaN; + for (BetterChatModel.GlyphBox g : line.glyphs()) { + if (g.charEndExclusive() <= selStart || g.charIndex() > selEnd) continue; + if (Float.isNaN(startX)) startX = g.x0(); + endX = g.x1(); + } + if (Float.isNaN(startX) || Float.isNaN(endX)) return; + float w = Math.max(1f, endX - startX); + BetterChatDrawUtil.drawRoundedRect(startX, y0, w, h, 1.8f, BetterChatDrawUtil.mulAlpha(theme().accent(), alpha * 0.55f)); + } + static boolean isSvgGlyphKey(String fontKey) { + return isSvgFontKey(fontKey); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatModel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatModel.java new file mode 100644 index 0000000..d93a456 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatModel.java @@ -0,0 +1,85 @@ +/* + * 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.features.gui.chat; + +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.Style; + +import java.util.List; + +/** + * Shared package-private records extracted from {@link BetterChatRenderer}. + * The only public-facing record kept nested on the facade is {@link BetterChatRenderer.Layout}. + * Records that own non-trivial rendering logic ({@code FrameLayout}, {@code ContextMenu}) live in + * their own files ({@link BetterChatFrameModel}, {@link BetterChatContextMenuModel}). + */ +final class BetterChatModel { + private BetterChatModel() { + } + + record MousePos(double rawX, double rawY, double fx, double fy) { + } + + record InputLine(int start, int end, float width) { + } + + record Segment(String text, Style style) { + } + + record VisualLine(ChatLine message, int messageIndex, int messageGroup, int startChar, int endChar, List glyphs) { + } + + record Glyph( + float x0, + float x1, + int charIndex, + int charEndExclusive, + int color, + HoverEvent hover, + String font, + String text, + Style style + ) { + } + + record GlyphBox( + float x0, + float y0, + float x1, + float y1, + int charIndex, + int charEndExclusive, + int color, + String font, + HoverEvent hover, + String text, + Style style + ) { + } + + record CachedLine(int startChar, int endChar, List glyphs) { + } + + record CachedMessageLayout(float fontSize, float maxWidth, List lines) { + } + + record FrameLine(ChatLine message, int messageIndex, int messageGroup, float y0, float y1, List glyphs) { + } + + record MessageBubble(ChatLine message, int messageGroup, float x, float y, float w, float h, FrameLine firstLine, FrameLine lastLine) { + } + + record MessageClipBounds(float x, float y, float w, float h) { + } + + record PickResult(FrameLine line, GlyphBox glyph) { + } + + record LayoutResult(List lines, int messagesSeen) { + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMouseClickHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMouseClickHandler.java new file mode 100644 index 0000000..fa8a67c --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatMouseClickHandler.java @@ -0,0 +1,165 @@ +/* + * 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.features.gui.chat; + +import com.mojang.blaze3d.platform.InputConstants; +import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; +import dev.loki.lovisual.util.screen.ClientScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.ChatScreen; +import net.minecraft.util.Mth; +import org.lwjgl.glfw.GLFW; + +/** + * Mouse-button dispatch over the chat surface: scrollbar drag, suggest rows, search icon, + * context menu and click/selection logic. Delegates textual actions to {@link BetterChatContextMenuHandler}. + */ +final class BetterChatMouseClickHandler { + private BetterChatMouseClickHandler() { + } + + static boolean onMouseButton(double mx, double my, int button, boolean pressed) { + Minecraft mc = Minecraft.getInstance(); + if (!BetterChat.isActive()) return false; + if (!(ClientScreen.current() instanceof ChatScreen)) return false; + + BetterChatModel.MousePos mouse = BetterChatInputHandler.resolveMouse(mx, my); + double fx = mouse.fx(); + double fy = mouse.fy(); + boolean leftUp = button == GLFW.GLFW_MOUSE_BUTTON_LEFT && !pressed; + + boolean overSuggestWindow = BetterChatSuggestionState.isInsideSuggestWindow(fx, fy, mouse.rawX(), mouse.rawY()); + + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && BetterChatRenderer.sbEnabled && BetterChatDrawUtil.isScrollbarHovered(fx, fy)) { + if (pressed) { + BetterChatRenderer.draggingScrollbar = true; + BetterChatRenderer.sbDragOffset = (fy >= BetterChatRenderer.sbThumbY && fy <= BetterChatRenderer.sbThumbY + BetterChatRenderer.sbThumbH) + ? (float) fy - BetterChatRenderer.sbThumbY + : BetterChatRenderer.sbThumbH * 0.5f; + BetterChatDrawUtil.scrollToPosition(fy); + } else { + BetterChatRenderer.draggingScrollbar = false; + } + return true; + } + if (BetterChatRenderer.draggingScrollbar) { + if (leftUp) BetterChatRenderer.draggingScrollbar = false; + return true; + } + + float sTop = BetterChatRenderer.suggestRowsY; + boolean overSuggestRows = BetterChatSuggestionState.isInsideSuggestRows(fx, fy, mouse.rawX(), mouse.rawY()); + + if (BetterChatRenderer.suggestDraggingScrollbar) { + if (leftUp) BetterChatRenderer.suggestDraggingScrollbar = false; + return true; + } + + if (BetterChatRenderer.suggestHasScrollbar && BetterChatSuggestionState.isInsideSuggestScrollbar(fx, fy)) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + if (pressed) { + BetterChatRenderer.suggestDraggingScrollbar = true; + BetterChatSuggestionState.scrollSuggestToPosition(fy); + } + } + return true; + } + + if (overSuggestRows) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && pressed) { + int row = (int) ((fy - sTop) / BetterChatRenderer.suggestItemH); + row = Mth.clamp(row, 0, Math.max(0, BetterChatRenderer.suggestVisible - 1)); + int idx = Mth.clamp(BetterChatRenderer.suggestStart + row, 0, Math.max(0, BetterChatRenderer.suggestTotal - 1)); + BetterChatSuggestionState.applySuggestion(idx); + return true; + } + return true; + } + + if (overSuggestWindow) { + return true; + } + + if (BetterChatRenderer.searchHit) { + boolean inside = fx >= BetterChatRenderer.searchRectX && fx <= BetterChatRenderer.searchRectX + BetterChatRenderer.searchRectW && fy >= BetterChatRenderer.searchRectY && fy <= BetterChatRenderer.searchRectY + BetterChatRenderer.searchRectH; + if (inside && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + if (pressed) { + BetterChatSuggestionState.toggleSearchMode(); + } + return true; + } + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && pressed) { + BetterChatSearch.setActive(false); + } + } + + if (BetterChatRenderer.contextMenu.open()) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + if (pressed && BetterChatRenderer.contextMenu.contains(fx, fy)) { + BetterChatContextMenuModel.ContextMenu.MenuEntry entry = BetterChatRenderer.contextMenu.pick(fy); + if (entry != null) entry.action().run(); + } + BetterChatRenderer.contextMenu = BetterChatContextMenuModel.ContextMenu.closed(); + return true; + } + } + + BetterChatModel.PickResult pick = BetterChatRenderer.frame.pick(fx, fy); + if (pick == null) { + if (pressed && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + BetterChatRenderer.selection.clear(); + BetterChatRenderer.selecting = false; + BetterChatRenderer.leftPending = false; + } + if (!pressed && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + BetterChatRenderer.selecting = false; + } + BetterChatRenderer.contextMenu = BetterChatContextMenuModel.ContextMenu.closed(); + return false; + } + + boolean ctrlDown = InputConstants.isKeyDown(mc.getWindow(), GLFW.GLFW_KEY_LEFT_CONTROL) + || InputConstants.isKeyDown(mc.getWindow(), GLFW.GLFW_KEY_RIGHT_CONTROL); + + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + if (pressed) { + BetterChatRenderer.leftPending = true; + BetterChatRenderer.leftDownFx = fx; + BetterChatRenderer.leftDownFy = fy; + BetterChatRenderer.leftDownMsgIndex = pick.line().messageIndex(); + BetterChatRenderer.leftDownCharIndex = pick.glyph().charIndex(); + BetterChatRenderer.leftDownStyle = pick.glyph().style(); + + BetterChatRenderer.selecting = false; + BetterChatRenderer.contextMenu = BetterChatContextMenuModel.ContextMenu.closed(); + return true; + } else { + if (BetterChatRenderer.leftPending) { + BetterChatRenderer.leftPending = false; + + if (BetterChatRenderer.selecting) { + BetterChatRenderer.selecting = false; + return true; + } + + boolean handled = BetterChatContextMenuHandler.handleClickEvent(BetterChatRenderer.leftDownStyle, ctrlDown); + if (!handled && ctrlDown) { + handled = BetterChatContextMenuHandler.tryPrefillTellFromClick(BetterChatRenderer.leftDownMsgIndex, BetterChatRenderer.leftDownCharIndex); + } + if (!handled) BetterChatRenderer.selection.clear(); + return true; + } + } + } else if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { + if (pressed) { + BetterChatContextMenuHandler.openContextMenu(pick, mx, my); + } + } + return false; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatRenderer.java index 50286a3..6d62622 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,2137 +7,187 @@ package dev.loki.lovisual.features.gui.chat; -import com.mojang.blaze3d.platform.InputConstants; -import dev.loki.lovisual.mixins.accessors.SuggestionWindowAccessor; -import dev.loki.lovisual.render.engine.text.VanillaTextRenderer; -import dev.loki.lovisual.util.item.IllegalItemUtil; -import dev.loki.lovisual.util.item.TopEnchantUtil; -import dev.loki.lovisual.util.screen.ClientScreen; -import net.minecraft.client.Minecraft; +import com.mojang.brigadier.suggestion.Suggestion; +import dev.loki.lovisual.features.command.CommandOutput; +import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.screens.ChatScreen; -import net.minecraft.client.gui.screens.ConfirmLinkScreen; -import net.minecraft.client.gui.screens.inventory.tooltip.DefaultTooltipPositioner; -import net.minecraft.client.resources.language.I18n; -import net.minecraft.network.chat.ClickEvent; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.Style; -import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.Mth; -import net.minecraft.util.Util; -import org.lwjgl.glfw.GLFW; -import dev.loki.lovisual.features.command.CommandManager; -import dev.loki.lovisual.features.command.CommandOutput; -import dev.loki.lovisual.features.gui.chat.ChatHoverUtil.HoverTip; -import dev.loki.lovisual.features.gui.hud.HudRenderUtil; -import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.SettingsGuiPalette; -import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; -import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; -import dev.loki.lovisual.features.gui.hud.nondraggable.impl.BetterTooltips; -import dev.loki.lovisual.mixins.accessors.ChatScreenAccessor; -import dev.loki.lovisual.mixins.accessors.TextFieldWidgetAccessor; -import dev.loki.lovisual.render.engine.animation.AnimationUtility; -import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.renderer.Renderer2D; -import dev.loki.lovisual.render.engine.svg.SvgRenderOptions; -import dev.loki.lovisual.render.engine.text.FontInfo; -import dev.loki.lovisual.render.engine.text.Fonts; -import dev.loki.lovisual.render.engine.text.TextGlyphFallback; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.render.helpers.ClipFunction; -import dev.loki.lovisual.render.helpers.ScissorFunction; -import dev.loki.lovisual.render.helpers.SystemCursor; -import dev.loki.lovisual.util.text.ChatNameUtil; -import dev.loki.lovisual.util.text.ClipboardUtil; + +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.List; + import dev.loki.lovisual.util.text.TextSelection; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -import static org.lwjgl.glfw.GLFW.GLFW_PRESS; -import static org.lwjgl.glfw.GLFW.glfwGetKey; -import static dev.loki.lovisual.features.theme.Theme.theme; - +/** + * Facade for the BetterChat HUD renderer. This enum singleton is now a thin delegation point: + * it owns the shared per-frame state and constants read/written by the package-private helpers, + * and re-exports the original public API exactly as before so no caller changes. + */ public enum BetterChatRenderer { ; - private static final int MAX_MESSAGE_CHARS = 256; // vanilla chat input limit - private static final float PADDING = 8f; - private static final float LINE_SPACING = 3f; - private static final float RADIUS = 24f; - private static final float MESSAGE_PAD_X = 8f; - private static final float MESSAGE_PAD_Y = 5f; - private static final float MESSAGE_GAP = 4f; - private static final float MESSAGE_INPUT_GAP = 8f; - private static final float MESSAGE_RADIUS = 9f; - private static final float MESSAGE_TS_GAP = 8f; - private static final float INPUT_RADIUS = 12f; - private static final float SEARCH_ICON_WIDTH = 34f; - private static final float SEARCH_ICON_HEIGHT = 22f; - private static final float NEW_MESSAGE_REVEAL_SECONDS = 0.34f; - private static final float NEW_MESSAGE_SLIDE_PX = 18f; - private static final int MAX_HISTORY = 32000; - private static final float CHAT_TOOLTIP_OFFSET_X = 6f; - private static final float CHAT_TOOLTIP_OFFSET_Y = 12f; - private static final RenderColor TMP_COLOR = new RenderColor(0xFFFFFFFF); - private static final java.util.IdentityHashMap MESSAGE_LAYOUT_CACHE = new java.util.IdentityHashMap<>(); - private static final java.util.IdentityHashMap> SEGMENT_CACHE = new java.util.IdentityHashMap<>(); - private static final java.util.IdentityHashMap COMMAND_LINE_CACHE = new java.util.IdentityHashMap<>(); - private static final TextSelection selection = new TextSelection(); - private static final double DRAG_SELECT_THRESHOLD = 4.0; // px - private static Renderer2D renderer; - private static float lastRenderWidth = 0f; - private static float lastRenderHeight = 0f; - private static int scrollOffsetLines = 0; - private static float smoothScrollOffsetLines = 0f; - private static int maxScrollLines = 0; - private static float lastFontSizeForUi = 16f; - private static List lastMessages = Collections.emptyList(); - private static boolean draggingScrollbar = false; - private static float sbTrackX, sbTrackY, sbTrackW, sbTrackH; - private static float sbThumbY, sbThumbH; - private static float sbDragOffset = 0f; - private static long lastScrollInteractionMs = 0L; - private static boolean sbEnabled = false; - private static int sbTotalLines = 0; - private static int sbVisibleLines = 0; - private static float inputBoxX = 0f, inputBoxY = 0f, inputBoxW = 0f, inputBoxH = 0f; - private static boolean hasInputBox = false; - // Suggest UI hitbox - private static boolean suggestActive = false; - private static float suggestX, suggestY, suggestW, suggestH, suggestItemH; - private static float suggestRowsX, suggestRowsY, suggestRowsW, suggestRowsH; - private static int suggestStart, suggestVisible, suggestTotal; - private static net.minecraft.client.gui.components.CommandSuggestions.SuggestionsList suggestWindow; - private static List suggestEntries = Collections.emptyList(); - private static boolean lastHoverWasOutsideSuggest = true; - private static boolean suggestHasScrollbar = false; - private static boolean suggestDraggingScrollbar = false; - private static float suggestTrackX, suggestTrackY, suggestTrackW, suggestTrackH, suggestThumbH; - private static int suggestCurrentStart = -1; - private static int suggestCurrentSelection = -1; - private static double lastMouseFx = 0.0; - private static double lastMouseFy = 0.0; - private static boolean lastMouseValid = false; - private static boolean tooltipCaptured = false; - private static String lastSuggestInput = ""; - private static int lastSuggestCursor = -1; - private static int lastSuggestSelStart = -1; - private static int lastSuggestSelEnd = -1; - private static CommandSuggestorBridge.SuggestionSnapshot lastSnapshot = null; - private static long debugPerfWindowStartNs = 0L; - private static long debugPerfAccumLayoutNs = 0L; - private static long debugPerfAccumBuildNs = 0L; - private static int debugPerfAccumFrames = 0; - private static FrameLayout frame = FrameLayout.empty(); - private static ContextMenu contextMenu = ContextMenu.closed(); - private static boolean selecting = false; - private static boolean searchHit = false; - private static float searchRectX = 0f, searchRectY = 0f, searchRectW = 0f, searchRectH = 0f; - private static boolean searchHotkeyDown = false; - private static float chatHitX = 0f, chatHitY = 0f, chatHitW = 0f, chatHitH = 0f; - private static String hoverEntityUuid = null; - private static ChatScreen storedScreen; - private static BetterChatStore previewStore; - private static int lastSuggestionHash = 0; - private static boolean leftPending = false; - private static double leftDownFx = 0.0, leftDownFy = 0.0; - private static int leftDownMsgIndex = -1; - private static int leftDownCharIndex = -1; - private static Style leftDownStyle = null; + + // ---- Constants (package-private; read by helpers) ---- + static final int MAX_MESSAGE_CHARS = 256; + static final float PADDING = 8f; + static final float LINE_SPACING = 3f; + static final float RADIUS = 24f; + static final float MESSAGE_PAD_X = 8f; + static final float MESSAGE_PAD_Y = 5f; + static final float MESSAGE_GAP = 4f; + static final float MESSAGE_INPUT_GAP = 8f; + static final float MESSAGE_RADIUS = 9f; + static final float MESSAGE_TS_GAP = 8f; + static final float INPUT_RADIUS = 12f; + static final float SEARCH_ICON_WIDTH = 34f; + static final float SEARCH_ICON_HEIGHT = 22f; + static final float NEW_MESSAGE_REVEAL_SECONDS = 0.34f; + static final float NEW_MESSAGE_SLIDE_PX = 18f; + static final int MAX_HISTORY = 32000; + static final float CHAT_TOOLTIP_OFFSET_X = 6f; + static final float CHAT_TOOLTIP_OFFSET_Y = 12f; + static final double DRAG_SELECT_THRESHOLD = 4.0; + static final RenderColor TMP_COLOR = new RenderColor(0xFFFFFFFF); + + // ---- Layout caches (package-private) ---- + static final IdentityHashMap MESSAGE_LAYOUT_CACHE = new IdentityHashMap<>(); + static final IdentityHashMap> SEGMENT_CACHE = new IdentityHashMap<>(); + static final IdentityHashMap COMMAND_LINE_CACHE = new IdentityHashMap<>(); + static final TextSelection selection = new TextSelection(); + + // ---- Persistent UI state (package-private) ---- + static Renderer2D renderer; + static float lastRenderWidth = 0f; + static float lastRenderHeight = 0f; + static int scrollOffsetLines = 0; + static float smoothScrollOffsetLines = 0f; + static int maxScrollLines = 0; + static float lastFontSizeForUi = 16f; + static List lastMessages = Collections.emptyList(); + static boolean draggingScrollbar = false; + static float sbTrackX, sbTrackY, sbTrackW, sbTrackH; + static float sbThumbY, sbThumbH; + static float sbDragOffset = 0f; + static long lastScrollInteractionMs = 0L; + static boolean sbEnabled = false; + static int sbTotalLines = 0; + static int sbVisibleLines = 0; + static float inputBoxX = 0f, inputBoxY = 0f, inputBoxW = 0f, inputBoxH = 0f; + static boolean hasInputBox = false; + static boolean suggestActive = false; + static float suggestX, suggestY, suggestW, suggestH, suggestItemH; + static float suggestRowsX, suggestRowsY, suggestRowsW, suggestRowsH; + static int suggestStart, suggestVisible, suggestTotal; + static net.minecraft.client.gui.components.CommandSuggestions.SuggestionsList suggestWindow; + static List suggestEntries = Collections.emptyList(); + static boolean lastHoverWasOutsideSuggest = true; + static boolean suggestHasScrollbar = false; + static boolean suggestDraggingScrollbar = false; + static float suggestTrackX, suggestTrackY, suggestTrackW, suggestTrackH, suggestThumbH; + static int suggestCurrentStart = -1; + static int suggestCurrentSelection = -1; + static double lastMouseFx = 0.0; + static double lastMouseFy = 0.0; + static boolean lastMouseValid = false; + static boolean tooltipCaptured = false; + static String lastSuggestInput = ""; + static int lastSuggestCursor = -1; + static int lastSuggestSelStart = -1; + static int lastSuggestSelEnd = -1; + static CommandSuggestorBridge.SuggestionSnapshot lastSnapshot = null; + static long debugPerfWindowStartNs = 0L; + static long debugPerfAccumLayoutNs = 0L; + static long debugPerfAccumBuildNs = 0L; + static int debugPerfAccumFrames = 0; + static BetterChatFrameModel.FrameLayout frame = BetterChatFrameModel.FrameLayout.empty(); + static BetterChatContextMenuModel.ContextMenu contextMenu = BetterChatContextMenuModel.ContextMenu.closed(); + static boolean selecting = false; + static boolean searchHit = false; + static float searchRectX = 0f, searchRectY = 0f, searchRectW = 0f, searchRectH = 0f; + static boolean searchHotkeyDown = false; + static float chatHitX = 0f, chatHitY = 0f, chatHitW = 0f, chatHitH = 0f; + static String hoverEntityUuid = null; + static ChatScreen storedScreen; + static BetterChatStore previewStore; + static int lastSuggestionHash = 0; + static boolean leftPending = false; + static double leftDownFx = 0.0, leftDownFy = 0.0; + static int leftDownMsgIndex = -1; + static int leftDownCharIndex = -1; + static Style leftDownStyle = null; + + // ---- Per-frame transient context (package-private; populated by the phased helpers) ---- + static GuiGraphicsExtractor ctxGui; + static float ctxBaseX, ctxBaseY; + static BetterChat ctxSettings; + static net.minecraft.client.Minecraft ctxMc; + static boolean ctxPreview, ctxChatOpen, ctxActiveSurface; + static boolean ctxShowTs, ctxHasSeconds, ctxTipDate, ctxTipUnix, ctxAutoFollow; + static int ctxTsColor, ctxTotalMessages, ctxVisibleLimit, ctxMessagesSeen; + static float ctxWidth, ctxContentWidth, ctxTsWidth; + static float ctxLineHeight, ctxBoxHeight, ctxLineYOffset, ctxTargetVisible; + static float ctxStableBoxHeight, ctxFixedInputY, ctxFrameY; + static int[] ctxMessageGroups; + static List ctxAllLines; + static List ctxVisible; + static long ctxPerfT0, ctxPerfT1; + static ChatHoverUtil.HoverTip ctxHoverTip; + + // ---- Public API (delegating) ---- public static void markLayoutDirty() { + BetterChatLayoutEngine.markLayoutDirty(); } public static void renderEngine(Renderer2D rendererIn, - TextRenderer fallback, - GuiGraphicsExtractor ctx, - int screenW, - float baseX, - float baseY) { - SystemCursor.beginFrame(ctx); - try { - renderEngineInternal(rendererIn, fallback, ctx, screenW, baseX, baseY); - } finally { - SystemCursor.endFrame(); - } - } - - private static void renderEngineInternal(Renderer2D rendererIn, - TextRenderer fallback, - GuiGraphicsExtractor ctx, - int screenW, - float baseX, - float baseY) { - renderer = rendererIn; - BetterChat settings = BetterChat.get(); - boolean preview = DraggableHudElementRegistry.isForceVisible(); - if (settings == null || (!settings.isEnabled() && !preview)) { - lastRenderWidth = 0f; - lastRenderHeight = 0f; - return; - } - - Minecraft mc = Minecraft.getInstance(); - if (mc == null || (mc.player == null && !preview)) { - lastRenderWidth = 0f; - lastRenderHeight = 0f; - return; - } - if (!preview && mc.isPaused()) { - selection.clear(); - contextMenu = ContextMenu.closed(); - selecting = false; - lastRenderWidth = 0f; - lastRenderHeight = 0f; - return; - } - - BetterChatStore store = (preview && mc.player == null) - ? buildPreviewStore() - : BetterChatStoreManager.getActiveStore(mc); - if (store == null) { - if (preview) { - store = buildPreviewStore(); - } else { - lastRenderWidth = 0f; - lastRenderHeight = 0f; - return; - } - } - - boolean chatOpen = ClientScreen.current() instanceof ChatScreen; - boolean activeChatSurface = chatOpen || preview; - if (!chatOpen && store.size() == 0) { - if (preview) { - store = buildPreviewStore(); - } else { - selection.clear(); - contextMenu = ContextMenu.closed(); - lastRenderWidth = 0f; - lastRenderHeight = 0f; - return; - } - } - if (!chatOpen) { - selection.clear(); - contextMenu = ContextMenu.closed(); - selecting = false; - storedScreen = null; - draggingScrollbar = false; - sbEnabled = false; - scrollOffsetLines = 0; - BetterChatSearch.deactivate(); - resetSuggestionTracking(); - } - if (chatOpen && ctx != null) { - BetterTooltips.beginTooltipFrame(); - BetterTooltips.setDrawContext(ctx); - } - tooltipCaptured = false; - - int visibleLimit = Math.max(1, chatOpen ? settings.maxLines() : Math.min(settings.maxLines(), 12)); - List commandOutputMessages = settings.hideVanilla() - ? CommandOutput.recentMessages() - : List.of(); - int totalMessages = store.size() + commandOutputMessages.size(); - boolean autoFollow = scrollOffsetLines == 0; - boolean tsEnabled = settings.timestampEnabled(); - boolean tsSeconds = settings.timestampSeconds(); - int tsColor = settings.timestampColor(); - boolean tsActiveOnly = settings.timestampToggles().get("active_only"); - boolean tsTipDate = settings.timestampToggles().get("hover_date"); - boolean tsTipUnix = settings.timestampToggles().get("hover_unix"); - boolean showTs = tsEnabled && (!tsActiveOnly || chatOpen); - - List messages; - if (BetterChatSearch.hasQuery() && BetterChatSearch.results() != null && chatOpen) { - List res = BetterChatSearch.results(); - totalMessages = res.size(); - int maxScrollSearch = Math.max(0, totalMessages - visibleLimit); - scrollOffsetLines = Mth.clamp(scrollOffsetLines, 0, maxScrollSearch); - int tailBudget = Math.min(totalMessages, Math.max(visibleLimit + scrollOffsetLines + 20, visibleLimit + 10)); - int endIdx = Math.min(totalMessages, Math.max(0, totalMessages - scrollOffsetLines)); - int startIdx = Math.max(0, endIdx - tailBudget); - if (startIdx > endIdx) startIdx = endIdx; - messages = res.subList(startIdx, endIdx); - } else { - int tailBudget = chatOpen - ? Math.max(visibleLimit + scrollOffsetLines + 80, visibleLimit) - : Math.max(visibleLimit + 8, visibleLimit); - int needed = Math.min(MAX_HISTORY, Math.min(totalMessages, tailBudget)); - messages = mergeCommandOutput(store.tail(Math.min(store.size(), needed)), commandOutputMessages, needed); - } - lastMessages = messages; - int[] messageGroups = BetterChatMessageGrouping.groupIds(messages); - - float fontSize = 16f * settings.fontScale(); - float width = computeWidth(screenW, settings.widthRatio()); - float tsWidth = 0f; - if (showTs) { - String sampleTs = tsSeconds ? "00:00:00" : "00:00"; - tsWidth = textWidth(getInterRegular(), sampleTs, Math.max(9f, fontSize * 0.72f)) + MESSAGE_TS_GAP; - } - float contentWidth = Math.max(32f, width - PADDING * 2f - MESSAGE_PAD_X * 2f - tsWidth); - lastFontSizeForUi = fontSize; - - int lineTarget = visibleLimit + scrollOffsetLines + Math.max(10, visibleLimit / 2) + 2; - long perfT0 = System.nanoTime(); - LayoutResult layoutResult = layoutLinesTailCached(messages, messageGroups, fontSize, contentWidth, lineTarget); - long perfT1 = System.nanoTime(); - List allLines = layoutResult.lines(); - float lineHeight = fontSize + LINE_SPACING; - float boxHeight; - List visible; - int localStart; - hasInputBox = false; // reset per-frame before renderInput fills it - float lineYOffset = 0f; - int targetVisibleForBox = visibleLimit; - if (allLines.isEmpty()) { - maxScrollLines = 0; - sbTotalLines = 0; - sbVisibleLines = 0; - boxHeight = 0f; - visible = Collections.emptyList(); - smoothScrollOffsetLines = 0f; - } else { - int lineCount = allLines.size(); - int observedMessages = Math.max(1, layoutResult.messagesSeen()); - float avgLinesPerMsg = Math.max(1f, (float) lineCount / (float) observedMessages); - int estimatedTotalLines = Math.max(lineCount, (int) Math.ceil(avgLinesPerMsg * totalMessages)); - maxScrollLines = Math.max(0, estimatedTotalLines - visibleLimit); - scrollOffsetLines = Mth.clamp(scrollOffsetLines, 0, maxScrollLines); - if (autoFollow) { - smoothScrollOffsetLines = 0f; - } else { - smoothScrollOffsetLines = Mth.clamp(smoothScrollOffsetLines, 0f, maxScrollLines); - smoothScrollOffsetLines = AnimationUtility.approach( - smoothScrollOffsetLines, - scrollOffsetLines, - draggingScrollbar ? 0.55f : 0.22f - ); - smoothScrollOffsetLines = AnimationUtility.snap( - smoothScrollOffsetLines, - scrollOffsetLines, - draggingScrollbar ? 0.01f : 0.035f - ); - } - - int lastMsgIndex = messages.isEmpty() ? -1 : messages.size() - 1; - int linesInLastMsg = 0; - if (lastMsgIndex >= 0) { - for (int i = lineCount - 1; i >= 0; i--) { - if (allLines.get(i).messageIndex() == lastMsgIndex) { - linesInLastMsg++; - } else if (linesInLastMsg > 0) { - break; - } - } - } - int targetVisible = autoFollow ? Math.max(visibleLimit, linesInLastMsg) : visibleLimit; - targetVisibleForBox = Math.max(1, Math.min(targetVisible, lineCount)); - - float globalStartFloat = autoFollow - ? Math.max(0f, lineCount - targetVisible) - : Math.max(0f, lineCount - visibleLimit - smoothScrollOffsetLines); - int globalStart = Math.max(0, (int) Math.floor(globalStartFloat) - (autoFollow ? 0 : 1)); - int viewportStart = autoFollow - ? Math.max(0, lineCount - targetVisibleForBox) - : Mth.clamp((int) Math.floor(globalStartFloat), 0, Math.max(0, lineCount - 1)); - int viewportEnd = Math.min(lineCount, viewportStart + targetVisibleForBox); - int groupsForBox = countMessageGroups(allLines.subList(viewportStart, viewportEnd), targetVisibleForBox); - - localStart = Math.max(0, Math.min(globalStart, Math.max(0, lineCount - 1))); - int endLine = Math.min(lineCount, localStart + targetVisibleForBox + (autoFollow ? 0 : 3)); - localStart = expandStartToGroup(allLines, localStart); - endLine = expandEndToGroup(allLines, endLine); - visible = allLines.subList(localStart, endLine); - sbTotalLines = lineCount; - sbVisibleLines = targetVisibleForBox; - - boxHeight = messageStackHeight(targetVisibleForBox, groupsForBox, lineHeight); - if (autoFollow) { - int actualGroups = countMessageGroups(visible, visible.size()); - float actualHeight = messageStackHeight(visible.size(), actualGroups, lineHeight); - // expandStartToGroup() may prepend overscan lines. Keep the newest bubble pinned to - // the viewport bottom instead of allowing those prepended lines to push it down. - lineYOffset = boxHeight - actualHeight; - } else { - lineYOffset = (localStart - globalStartFloat) * lineHeight; - } - } - float stableBoxHeight = messageStackHeight(visibleLimit, visibleLimit, lineHeight); - float fixedInputY = baseY + stableBoxHeight + MESSAGE_INPUT_GAP; - float frameY = baseY + stableBoxHeight - boxHeight; - float visualTop = Math.min(baseY, frameY); - float visualBottom = chatOpen ? fixedInputY + Math.max(36f, fontSize + 16f) : frameY + boxHeight; - float totalHeight = Math.max(0f, visualBottom - visualTop); - lastRenderWidth = width; - lastRenderHeight = totalHeight; - - long perfT2Start = System.nanoTime(); - frame = FrameLayout.build(visible, baseX, frameY, width, boxHeight, fontSize, lineHeight, lineYOffset, showTs ? tsWidth : 0f); - long perfT2 = System.nanoTime(); - debugPerfAccumLayoutNs += (perfT1 - perfT0); - debugPerfAccumBuildNs += (perfT2 - perfT2Start); - debugPerfAccumFrames++; - if (debugPerfWindowStartNs == 0L) debugPerfWindowStartNs = perfT2; - long windowNs = perfT2 - debugPerfWindowStartNs; - if (windowNs >= 1_000_000_000L && debugPerfAccumFrames > 0 && chatOpen) { - double layoutMs = (debugPerfAccumLayoutNs / (double) debugPerfAccumFrames) / 1_000_000.0; - double buildMs = (debugPerfAccumBuildNs / (double) debugPerfAccumFrames) / 1_000_000.0; - /*DebugLog.info("[BetterChat][Perf] layout=%.2f ms build=%.2f ms lines=%d msgs=%d scroll=%d/%d vis=%d", - layoutMs, buildMs, allLines.size(), messages.size(), scrollOffsetLines, maxScrollLines, visibleLimit);*/ - debugPerfWindowStartNs = perfT2; - debugPerfAccumLayoutNs = 0L; - debugPerfAccumBuildNs = 0L; - debugPerfAccumFrames = 0; - } - - searchHit = false; - if (!chatOpen) { - BetterChatSearch.deactivate(); - } - updateSearchHotkey(mc, chatOpen); - - MousePos mouse = resolveMouse(mc.mouseHandler.xpos(), mc.mouseHandler.ypos()); - double mouseX = mouse.fx(); - double mouseY = mouse.fy(); - lastMouseFx = mouseX; - lastMouseFy = mouseY; - lastMouseValid = true; - HoverTip hoverTip = null; - hoverEntityUuid = null; - - TextRenderer tsRenderer = showTs ? getInterRegular() : null; - float tsFontSize = Math.max(9f, fontSize * 0.72f); - float tsTextHeight = 0f; - if (showTs && tsRenderer != null) { - float tsScale = scaleForSize(tsFontSize); - tsRenderer.begin(tsScale, false, false); - tsTextHeight = (float) tsRenderer.getHeight(false); - tsRenderer.end(); - } - - boolean chatClip = false; - MessageClipBounds clipBounds = frame.messageClipBounds(); - if (clipBounds != null) { - if (!frame.bubbles().isEmpty()) { - Renderer2D.requestLiquidGlassBlurBeforeNextShapeClip(); - } - float clipRadius = Math.min(RADIUS, clipBounds.h() * 0.5f); - chatClip = ClipFunction.pushRoundedRect( - clipBounds.x(), clipBounds.y(), clipBounds.w(), clipBounds.h(), - clipRadius, clipRadius, 0.0f, 0.0f - ); - } - drawMessageBubbles(frame.bubbles(), activeChatSurface); - for (FrameLine line : frame.lines()) { - float alpha = activeChatSurface ? 1f : fade(line.message().ageSeconds()); - if (alpha <= 0.01f) continue; - drawSelection(line, alpha, lineHeight); - } - - renderGlyphs(frame.lines(), fontSize, lineHeight, activeChatSurface); - if (showTs && tsRenderer != null) { - hoverTip = renderBubbleTimestamps( - tsRenderer, - frame.bubbles(), - tsFontSize, - tsTextHeight, - tsSeconds, - tsColor, - tsTipDate, - tsTipUnix, - activeChatSurface, - chatOpen, - hoverTip - ); - } - if (chatClip) ClipFunction.pop(); - PickResult hover = frame.pick(mouseX, mouseY); - boolean overSuggestWindow = isInsideSuggestWindow(mouse.fx(), mouse.fy(), mouse.rawX(), mouse.rawY()); - if (overSuggestWindow && lastHoverWasOutsideSuggest) { - /*DebugLog.info("[BetterChat][Suggest] hover enter mx=%.1f my=%.1f raw=(%.1f,%.1f) box=(%.1f,%.1f,%.1f,%.1f)", - mouse.fx(), mouse.fy(), mouse.rawX(), mouse.rawY(), suggestX, suggestY, suggestW, suggestH)*/ - lastHoverWasOutsideSuggest = false; - } else if (!overSuggestWindow && !lastHoverWasOutsideSuggest) { - lastHoverWasOutsideSuggest = true; - } - - if (hover != null && hover.glyph().hover() != null && !overSuggestWindow) { - hoverTip = ChatHoverUtil.fromHover(hover.glyph().hover(), mc); - if (hoverTip != null) hoverEntityUuid = hoverTip.uuid(); - } - - // Fallback heuristic: if no hover info was provided (e.g., from persisted history), try to infer from cache or nickname. - if (selecting) { - hoverTip = null; - hoverEntityUuid = null; - } - - if (!selecting && !overSuggestWindow && hoverTip == null && hover != null) { - String raw = hover.line().message().text().getString(); - String word = wordAt(raw, hover.glyph().charIndex()); - if (!word.isEmpty()) { - boolean looksLikeItem = (word.startsWith("[") && word.contains("]")); - HoverTip cached = ChatHoverUtil.inferFromDisplay(word, looksLikeItem, mc); - if (cached != null) { - hoverTip = cached; - hoverEntityUuid = cached.uuid(); - } - } - if (hoverTip == null) { - List nickCandidates = ChatNameUtil.extractNicks(raw); - String normalized = ChatNameUtil.normalizeNickCandidate(word); - String targetNick = null; - if (!normalized.isEmpty() - && ChatNameUtil.isNickLike(normalized) - && nickCandidates.stream().anyMatch(n -> n.equalsIgnoreCase(normalized))) { - targetNick = normalized; - } else if (nickCandidates.size() == 1) { - targetNick = nickCandidates.getFirst(); - } - if (targetNick != null) { - hoverTip = ChatHoverUtil.inferFromNick(targetNick, mc); - if (hoverTip != null) hoverEntityUuid = hoverTip.uuid(); - } - } - } - - if (overSuggestWindow || contextMenu.open) { - hoverTip = null; - hoverEntityUuid = null; - } - - if (chatOpen) { - renderInput(mc, fontSize, width, baseX, fixedInputY); - float hitBottom = hasInputBox ? inputBoxY + inputBoxH : fixedInputY; - chatHitX = baseX; - chatHitY = frame.y(); - chatHitW = width; - chatHitH = Math.max(boxHeight, hitBottom - chatHitY); - renderSuggestions(); - } else { - chatHitX = chatHitY = chatHitW = chatHitH = 0f; - lastMouseValid = false; - } - - if (chatOpen && maxScrollLines > 0) { - int scrollbarStart = autoFollow - ? Math.max(0, sbTotalLines - visibleLimit) - : Math.max(0, sbTotalLines - visibleLimit - scrollOffsetLines); - renderScrollbar(frame.x(), frame.y(), frame.w(), frame.h(), scrollbarStart, visibleLimit, sbTotalLines, mouseX, mouseY); - } - - if (chatOpen && hoverTip != null) { - captureTooltip(hoverTip, (float) mouseX + CHAT_TOOLTIP_OFFSET_X, (float) mouseY + CHAT_TOOLTIP_OFFSET_Y, ctx); - } - - if (contextMenu.open) { - contextMenu.render((float) mouseX, (float) mouseY, fontSize); - } - } - - private static int countMessageGroups(List lines, int maxLines) { - if (lines == null || lines.isEmpty() || maxLines <= 0) return 0; - int groups = 0; - int lastMessage = Integer.MIN_VALUE; - int limit = Math.min(lines.size(), maxLines); - for (int i = 0; i < limit; i++) { - int messageGroup = lines.get(i).messageGroup(); - if (messageGroup != lastMessage) { - groups++; - lastMessage = messageGroup; - } - } - return groups; - } - - private static float messageStackHeight(int lineCount, int groupCount, float lineHeight) { - if (lineCount <= 0) return 0f; - return lineCount * lineHeight - - LINE_SPACING - + Math.max(0, groupCount - 1) * MESSAGE_GAP - + MESSAGE_PAD_Y * 2f; - } - - private static int expandStartToGroup(List lines, int start) { - if (lines == null || lines.isEmpty()) return 0; - int safe = Mth.clamp(start, 0, lines.size()); - if (safe <= 0 || safe >= lines.size()) return safe; - int group = lines.get(safe).messageGroup(); - while (safe > 0 && lines.get(safe - 1).messageGroup() == group) { - safe--; - } - return safe; - } - - private static int expandEndToGroup(List lines, int end) { - if (lines == null || lines.isEmpty()) return 0; - int safe = Mth.clamp(end, 0, lines.size()); - if (safe <= 0 || safe >= lines.size()) return safe; - int group = lines.get(safe - 1).messageGroup(); - while (safe < lines.size() && lines.get(safe).messageGroup() == group) { - safe++; - } - return safe; - } - - private static void drawMessageBubbles(List bubbles, boolean activeChatSurface) { - if (bubbles == null || bubbles.isEmpty()) return; - for (MessageBubble bubble : bubbles) { - float alpha = activeChatSurface ? 1f : fade(bubble.message().ageSeconds()); - if (alpha <= 0.01f) continue; - float reveal = newMessageReveal(bubble.message()); - float x = bubble.x() - (1f - reveal) * NEW_MESSAGE_SLIDE_PX; - float y = bubble.y(); - float w = bubble.w(); - float h = bubble.h(); - drawMessageBubbleGlass(x, y, w, h, Math.min(MESSAGE_RADIUS, h * 0.5f), alpha); - } - } - - private static void drawMessageBubbleGlass(float x, float y, float w, float h, float radius, float alpha) { - if (renderer == null || w <= 0f || h <= 0f) return; - float drawAlpha = Mth.clamp(alpha, 0.0f, 1.0f); - if (drawAlpha <= 0.001f) return; - BetterChat settings = BetterChat.get(); - float configuredAlpha = settings != null ? settings.liquidGlassAlphaFactor() : (230f / 255f); - float blurStrength = configuredAlpha * drawAlpha; - float glassScale = MESSAGE_RADIUS <= 0.0f ? 1.0f : radius / MESSAGE_RADIUS; - // Use the same theme tint family as the input field, but keep message material weaker. - // The previous extra accent fill + bright stroke stacked on top of the glass shader and - // made bubbles visibly more saturated than the input. - HudRenderUtil.drawLiquidGlassCorners( - x, y, w, h, - radius, radius, radius, radius, - glassScale, false, - blurStrength, drawAlpha * 0.74f, - theme().accent() - ); - drawRoundedRect(x, y, w, h, radius, - withAlpha(theme().windowBg(), Math.round(0x08 * drawAlpha))); - } - - private static HoverTip renderBubbleTimestamps(TextRenderer tsRenderer, - List bubbles, - float tsFontSize, - float tsTextHeight, - boolean withSeconds, - int tsColor, - boolean tsTipDate, - boolean tsTipUnix, - boolean activeChatSurface, - boolean chatOpen, - HoverTip currentHover) { - if (bubbles == null || bubbles.isEmpty()) return currentHover; - HoverTip hover = currentHover; - float tsScale = scaleForSize(tsFontSize); - float shadowOffset = Math.max(0.75f, tsFontSize * 0.07f); - tsRenderer.begin(tsScale, false, false); - try { - for (MessageBubble bubble : bubbles) { - float alpha = activeChatSurface ? 1f : fade(bubble.message().ageSeconds()); - if (alpha <= 0.01f) continue; - - String ts = formatTimestamp(bubble.message().timestampMs(), withSeconds); - float textW = (float) tsRenderer.getWidth(ts, false); - float reveal = newMessageReveal(bubble.message()); - float tx = bubble.x() + bubble.w() - MESSAGE_PAD_X - textW - (1f - reveal) * NEW_MESSAGE_SLIDE_PX; - float ty = bubble.lastLine().y0() + (bubble.lastLine().y1() - bubble.lastLine().y0() - tsTextHeight) * 0.5f; - int shadowColor = mulAlpha(0xFF000000, alpha * 0.46f); - applyColor(shadowColor); - tsRenderer.render(ts, tx + shadowOffset, ty, TMP_COLOR, false); - tsRenderer.render(ts, tx, ty + shadowOffset, TMP_COLOR, false); - applyColor(mulAlpha(tsColor, alpha * 0.82f)); - tsRenderer.render(ts, tx, ty, TMP_COLOR, false); - - if (hover == null && chatOpen && lastMouseValid) { - float hitPad = 2f; - if (lastMouseFx >= tx - hitPad && lastMouseFx <= tx + textW + hitPad - && lastMouseFy >= ty - hitPad && lastMouseFy <= ty + tsTextHeight + hitPad) { - hover = buildTimestampTooltip(bubble.message().timestampMs(), tsTipDate, tsTipUnix); - } - } - } - } finally { - tsRenderer.end(); - } - return hover; - } - - private static float fade(float ageSeconds) { - BetterChat cfg = BetterChat.get(); - float life = cfg != null ? cfg.fadeSeconds() : 12f; - if (life <= 0f) return 0f; - - // Держим сообщение полностью видимым, затем быстро гасим в конце. - float fadeDur = Math.min(2.0f, Math.max(0.35f, life * 0.18f)); // быстрое затухание (0.35..2.0с) - float holdDur = Math.max(0f, life - fadeDur); - - if (ageSeconds <= holdDur) return 1f; - - float t = (ageSeconds - holdDur) / fadeDur; // 0..1 - t = Mth.clamp(t, 0f, 1f); - - // Быстрое “падение” в конце (кубическая кривая) - float inv = 1f - t; - return inv * inv * inv; - } - - private static void drawSelection(FrameLine line, float alpha, float lineHeight) { - if (!selection.appliesToLine(line.messageIndex())) return; - - int selStart = selection.startForLine(line.messageIndex()); - int selEnd = selection.endForLine(line.messageIndex()); - if (selStart < 0 && selEnd < 0) return; - - float y0 = line.y0() - 1.5f; - float h = lineHeight + 3f; - float startX = Float.NaN; - float endX = Float.NaN; - for (GlyphBox g : line.glyphs()) { - if (g.charEndExclusive() <= selStart || g.charIndex() > selEnd) continue; - if (Float.isNaN(startX)) startX = g.x0(); - endX = g.x1(); - } - if (Float.isNaN(startX) || Float.isNaN(endX)) return; - float w = Math.max(1f, endX - startX); - drawRoundedRect(startX, y0, w, h, 1.8f, mulAlpha(theme().accent(), alpha * 0.55f)); - } - - private static void renderGlyphs(List lines, float fontSize, float lineHeight, boolean activeChatSurface) { - if (lines == null || lines.isEmpty()) return; - float scale = scaleForSize(fontSize); - TextRenderer current = null; - float currentHeight = 0f; - float shadowOffset = Math.max(1f, fontSize * (activeChatSurface ? 0.06f : 0.08f)); - float shadowAlpha = activeChatSurface ? 0.48f : 0.68f; - for (FrameLine line : lines) { - float alpha = activeChatSurface ? 1f : fade(line.message().ageSeconds()); - if (alpha <= 0.01f) continue; - float baseY = line.y0(); - float reveal = newMessageReveal(line.message()); - float xOffset = -(1f - reveal) * NEW_MESSAGE_SLIDE_PX; - boolean commandLine = CommandOutput.isLoVisualMessage(line.message().text()); - // New-message animation is translation-only. Do not create a nested rectangular - // clip here: every arrival used to push/pop GPU scissor state for ~340 ms, forcing - // batch flushes and briefly invalidating lower HUD phases. - List glyphs = line.glyphs(); - for (int gi = 0; gi < glyphs.size(); gi++) { - GlyphBox g = glyphs.get(gi); - if (commandLine && g.charIndex() < CommandOutput.PREFIX.length() && !TextGlyphFallback.isSvgFontKey(g.font())) { - if (current != null) { - current.end(); - current = null; - } - int runEnd = gi + 1; - while (runEnd < glyphs.size()) { - GlyphBox next = glyphs.get(runEnd); - if (next.charIndex() >= CommandOutput.PREFIX.length()) break; - if (TextGlyphFallback.isSvgFontKey(next.font())) break; - if (!java.util.Objects.equals(next.font(), g.font())) break; - runEnd++; - } - renderCommandPrefixRun(glyphs, gi, runEnd, baseY, lineHeight, xOffset, scale, alpha, shadowOffset, shadowAlpha, line.message().text()); - gi = runEnd - 1; - continue; - } - if (TextGlyphFallback.isSvgFontKey(g.font())) { - if (current != null) { - current.end(); - current = null; - } - String svgName = TextGlyphFallback.svgNameFromFontKey(g.font()); - float gx = g.x0() + xOffset; - float iconSize = Math.max(1.0f, g.x1() - g.x0()); - float iconY = baseY + (lineHeight - iconSize) * 0.5f; - if (svgName != null) { - renderer.svg(svgName, gx, iconY, iconSize, iconSize, SvgRenderOptions.fromFile().withAlpha(alpha)); - } - continue; - } - TextRenderer tr = fontRenderer(g.font()); - if (tr != current) { - if (current != null) { - current.end(); - } - current = tr; - current.begin(scale, false, false); - currentHeight = (float) current.getHeight(false); - } - float textY = baseY + (lineHeight - currentHeight) * 0.5f; - float gx = g.x0() + xOffset; - int shadowColor = mulAlpha(0xFF000000, alpha * shadowAlpha); - applyColor(shadowColor); - current.render(g.text(), gx + shadowOffset, textY, TMP_COLOR, false); - current.render(g.text(), gx - shadowOffset, textY, TMP_COLOR, false); - current.render(g.text(), gx, textY + shadowOffset, TMP_COLOR, false); - current.render(g.text(), gx, textY - shadowOffset, TMP_COLOR, false); - applyColor(mulAlpha(g.color(), alpha)); - current.render(g.text(), gx, textY, TMP_COLOR, false); - } - } - if (current != null) { - current.end(); - } - } - - private static void renderCommandPrefixRun(List glyphs, - int from, - int to, - float baseY, - float lineHeight, - float xOffset, - float scale, - float alpha, - float shadowOffset, - float shadowAlpha, - Component source) { - if (from < 0 || to <= from || to > glyphs.size()) return; - GlyphBox first = glyphs.get(from); - GlyphBox last = glyphs.get(to - 1); - TextRenderer tr = fontRenderer(first.font()); - if (tr == null) return; - - StringBuilder text = new StringBuilder(); - for (int i = from; i < to; i++) { - text.append(glyphs.get(i).text()); - } - if (text.isEmpty()) return; - - float runX = first.x0() + xOffset; - float runW = Math.max(1.0f, last.x1() - first.x0()); - CommandOutput.Tone tone = CommandOutput.toneOf(source); - int start = CommandOutput.prefixStartColor(tone); - int end = CommandOutput.prefixEndColor(tone); - int bottomMix = CommandOutput.mixRgb(end, 0xFFFFFFFF, 0.10f); - - tr.begin(scale, false, false); - try { - float textY = baseY + (lineHeight - (float) tr.getHeight(false)) * 0.5f; - int shadowColor = mulAlpha(0xFF000000, alpha * shadowAlpha); - applyColor(shadowColor); - tr.render(text.toString(), runX + shadowOffset, textY, TMP_COLOR, false); - tr.render(text.toString(), runX - shadowOffset, textY, TMP_COLOR, false); - tr.render(text.toString(), runX, textY + shadowOffset, TMP_COLOR, false); - tr.render(text.toString(), runX, textY - shadowOffset, TMP_COLOR, false); - - tr.renderQuadGradient(text.toString(), runX, textY, (idx, cp, x0, y0, x1, y1, out) -> { - float t0 = (float) ((x0 - runX) / runW); - float t1 = (float) ((x1 - runX) / runW); - int leftTop = mulAlpha(CommandOutput.mixRgb(start, end, t0), alpha); - int rightTop = mulAlpha(CommandOutput.mixRgb(start, end, t1), alpha); - int leftBottom = mulAlpha(CommandOutput.mixRgb(start, bottomMix, t0), alpha); - int rightBottom = mulAlpha(CommandOutput.mixRgb(start, bottomMix, t1), alpha); - out[0] = leftTop; - out[1] = leftBottom; - out[2] = rightBottom; - out[3] = rightTop; - }, false); - } finally { - tr.end(); - } - } - - private static List mergeCommandOutput(List storeLines, - List commandLines, - int needed) { - if (commandLines == null || commandLines.isEmpty()) { - return storeLines; - } - List out = new ArrayList<>(storeLines.size() + commandLines.size()); - out.addAll(storeLines); - for (CommandOutput.MessageLine line : commandLines) { - if (line == null || line.text() == null) continue; - out.add(COMMAND_LINE_CACHE.computeIfAbsent(line, key -> new ChatLine(key.text(), key.timestampMs()))); - } - out.sort(java.util.Comparator.comparingLong(ChatLine::timestampMs)); - trimCommandLineCache(commandLines); - if (needed > 0 && out.size() > needed) { - return new ArrayList<>(out.subList(out.size() - needed, out.size())); - } - return out; - } - - private static void trimCommandLineCache(List liveLines) { - if (COMMAND_LINE_CACHE.size() <= 160) return; - java.util.IdentityHashMap live = new java.util.IdentityHashMap<>(); - for (CommandOutput.MessageLine line : liveLines) { - live.put(line, Boolean.TRUE); - } - COMMAND_LINE_CACHE.keySet().removeIf(line -> !live.containsKey(line)); - } - - private static float newMessageReveal(ChatLine message) { - if (message == null) return 1f; - float age = message.ageSeconds(); - if (age <= 0f) return 0f; - if (age >= NEW_MESSAGE_REVEAL_SECONDS) return 1f; - float t = Mth.clamp(age / NEW_MESSAGE_REVEAL_SECONDS, 0f, 1f); - float inv = 1f - t; - return 1f - inv * inv * inv; - } - - private static void captureTooltip(HoverTip tip, float x, float y, GuiGraphicsExtractor ctx) { - if (tip == null || ctx == null) return; - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.getWindow() == null) return; - float scale = (float) mc.getWindow().getGuiScale(); - int mx = Math.round(x / scale); - int my = Math.round(y / scale); - List lines = buildOrderedTooltipLines(tip); - if (lines.isEmpty()) return; - - BetterTooltips.setTooltipScaleOverride(0.8f); - if (tip.item() != null && !tip.item().isEmpty()) { - BetterTooltips.captureItemTooltipOrdered(lines, DefaultTooltipPositioner.INSTANCE, mx, my, tip.item(), ctx); - } else { - BetterTooltips.captureTooltipOrdered(lines, DefaultTooltipPositioner.INSTANCE, mx, my); - } - tooltipCaptured = true; + TextRenderer fallback, + GuiGraphicsExtractor ctx, + int screenW, + float baseX, + float baseY) { + BetterChatFrameRenderer.renderEngine(rendererIn, fallback, ctx, screenW, baseX, baseY); } public static void renderCapturedTooltip(GuiGraphicsExtractor ctx) { - if (!tooltipCaptured) return; - BetterTooltips.renderTooltipWithContext(ctx); - BetterTooltips.resetTooltipScaleOverride(); - tooltipCaptured = false; - } - - private static List buildOrderedTooltipLines(HoverTip tip) { - if (tip == null || tip.lines() == null || tip.lines().isEmpty()) return Collections.emptyList(); - List out = new ArrayList<>(tip.lines().size()); - for (ChatHoverUtil.ColoredLine line : tip.lines()) { - int argb = line.color() != 0 ? line.color() : theme().textPrimary(); - int rgb = argb & 0x00FFFFFF; - Component text = Component.literal(line.text()).setStyle(Style.EMPTY.withColor(net.minecraft.network.chat.TextColor.fromRgb(rgb))); - out.add(text.getVisualOrderText()); - } - return out; - } - - private static LayoutResult layoutLinesTailCached(List messages, int[] messageGroups, float fontSize, float maxWidth, int maxLines) { - if (messages.isEmpty()) return new LayoutResult(Collections.emptyList(), 0); - List lines = new ArrayList<>(); - int seenMessages = 0; - for (int mi = messages.size() - 1; mi >= 0; mi--) { - ChatLine msg = messages.get(mi); - int messageGroup = messageGroups != null && mi >= 0 && mi < messageGroups.length ? messageGroups[mi] : mi; - List cached = cachedMessageLines(msg, fontSize, maxWidth); - for (int j = cached.size() - 1; j >= 0; j--) { - CachedLine cl = cached.get(j); - lines.addFirst(new VisualLine(msg, mi, messageGroup, cl.startChar(), cl.endChar(), cl.glyphs())); - } - seenMessages++; - if (lines.size() >= maxLines) break; - } - return new LayoutResult(lines, seenMessages); - } - - private static List cachedMessageLines(ChatLine msg, float fontSize, float maxWidth) { - CachedMessageLayout cached = MESSAGE_LAYOUT_CACHE.get(msg); - if (cached != null && Math.abs(cached.fontSize() - fontSize) < 0.01f && Math.abs(cached.maxWidth() - maxWidth) < 0.5f) { - return cached.lines(); - } - - List segments = SEGMENT_CACHE.computeIfAbsent(msg, m -> flatten(m.text())); - List rebuilt = new ArrayList<>(); - TextRenderer activeRenderer = null; - String activeFont = null; - float scale = scaleForSize(fontSize); - - int charIndex = 0; - float lineX = 0f; - List glyphs = new ArrayList<>(); - int lineStartIndex = 0; - int breakGlyphIdx = -1; - int breakCharIdx = -1; - - for (Segment seg : segments) { - Style style = seg.style(); - String font = fontForStyle(style); - int color = style.getColor() != null ? (0xFF << 24) | style.getColor().getValue() : theme().textPrimary(); - HoverEvent hover = style.getHoverEvent(); - - if (hover instanceof HoverEvent.ShowItem(net.minecraft.world.item.ItemStackTemplate itemTemplate)) { - net.minecraft.world.item.ItemStack item = itemTemplate.create(); - net.minecraft.world.item.ItemStack stack = item.copy(); - - BetterChatHoverCache cache = BetterChatStoreManager.getActiveCache(); - if (cache != null) { - String keyId = BetterChatStoreManager.hoverItemKey(stack); - String itemId = net.minecraft.core.registries.BuiltInRegistries.ITEM.getKey(stack.getItem()).toString(); - net.minecraft.world.item.ItemStack cachedStack = cache.getItemByKeyOrId(keyId, itemId); - if (!cachedStack.isEmpty()) stack = cachedStack; - } - - if (IllegalItemUtil.isIllegal(stack)) { - color = IllegalItemUtil.illegalColor(); - } else if (TopEnchantUtil.hasTopEnchant(stack)) { - color = TopEnchantUtil.topColor(); - } - } - - if (color == theme().textPrimary()) { - if (!(hover instanceof HoverEvent.ShowItem)) { - BetterChatHoverCache cache = BetterChatStoreManager.getActiveCache(); - if (cache != null) { - String cleaned = seg.text().replaceAll("[\\[\\]<>‚]", "").trim(); - if (!cleaned.isEmpty()) { - cache.findItemByDisplayNameWithMeta(cleaned); - } - } - } - } - - String txt = seg.text(); - - for (int c = 0; c < txt.length(); ) { - int cp = txt.codePointAt(c); - int cpLen = Character.charCount(cp); - - if (cp == '\n') { - rebuilt.add(new CachedLine(lineStartIndex, Math.max(lineStartIndex, charIndex - 1), glyphs)); - glyphs = new ArrayList<>(); - lineX = 0f; - lineStartIndex = charIndex; - breakGlyphIdx = -1; - breakCharIdx = -1; - charIndex += 1; - c += 1; - continue; - } - - String glyphText = new String(Character.toChars(cp)); - - String resolvedFont = fontForGlyph(font, cp); - boolean svgGlyph = TextGlyphFallback.isSvgFontKey(resolvedFont); - TextRenderer tr = svgGlyph ? null : fontRenderer(resolvedFont); - - if (svgGlyph) { - if (activeRenderer != null) { - activeRenderer.end(); - activeRenderer = null; - } - activeFont = resolvedFont; - } else if (tr != activeRenderer) { - if (activeRenderer != null) { - activeRenderer.end(); - } - activeRenderer = tr; - activeFont = resolvedFont; - if (activeRenderer != null) { - activeRenderer.begin(scale, true, false); - } - } - float cw = svgGlyph - ? svgGlyphSize(fontRenderer(font), fontSize, false) - : activeRenderer != null ? (float) activeRenderer.getWidth(glyphText, false) : 0f; - int glyphCharIndex = charIndex; - - if (lineX + cw > maxWidth && lineX > 0f) { - if (breakGlyphIdx >= 0) { - List before = new ArrayList<>(glyphs.subList(0, breakGlyphIdx)); - int endChar = Math.max(lineStartIndex, breakCharIdx - 1); - rebuilt.add(new CachedLine(lineStartIndex, endChar, before)); - - List remaining = glyphs.subList(breakGlyphIdx + 1, glyphs.size()); - glyphs = new ArrayList<>(remaining.size()); - float nx = 0f; - for (Glyph g : remaining) { - float gw = g.x1() - g.x0(); - glyphs.add(new Glyph( - nx, - nx + gw, - g.charIndex(), - g.charEndExclusive(), - g.color(), - g.hover(), - g.font(), - g.text(), - g.style() - )); - nx += gw; - } - lineX = nx; - lineStartIndex = breakCharIdx + 1; - breakGlyphIdx = -1; - breakCharIdx = -1; - } else { - rebuilt.add(new CachedLine(lineStartIndex, Math.max(lineStartIndex, charIndex - 1), glyphs)); - glyphs = new ArrayList<>(); - lineX = 0f; - lineStartIndex = charIndex; - } - } - - glyphs.add(new Glyph( - lineX, - lineX + cw, - glyphCharIndex, - glyphCharIndex + cpLen, - color, - hover, - activeFont != null ? activeFont : resolvedFont, - glyphText, - style - )); - lineX += cw; - - charIndex += cpLen; - - if (cp == ' ') { - breakGlyphIdx = glyphs.size() - 1; - breakCharIdx = glyphCharIndex; - } - - c += cpLen; - } - } - - if (!glyphs.isEmpty()) { - rebuilt.add(new CachedLine(lineStartIndex, charIndex - 1, glyphs)); - } else if (charIndex == 0) { - rebuilt.add(new CachedLine(0, 0, List.of(new Glyph( - 0f, - 2f, - 0, - 1, - theme().textPrimary(), - null, - "iosevka_medium", - " ", - Style.EMPTY - )))); - } - - if (activeRenderer != null) { - activeRenderer.end(); - } - MESSAGE_LAYOUT_CACHE.put(msg, new CachedMessageLayout(fontSize, maxWidth, rebuilt)); - return rebuilt; - } - - private static List flatten(Component text) { - List segments = new ArrayList<>(); - text.visit((style, string) -> { - if (string != null && !string.isEmpty()) { - segments.add(new Segment(string, style == null ? Style.EMPTY : style)); - } - return Optional.empty(); - }, Style.EMPTY); - return segments; - } - - private static void updateSearchHotkey(Minecraft mc, boolean chatOpen) { - if (!chatOpen || mc == null || mc.getWindow() == null) { - searchHotkeyDown = false; - return; - } - - long handle = mc.getWindow().handle(); - - boolean ctrl = - glfwGetKey(handle, GLFW.GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || - glfwGetKey(handle, GLFW.GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS; - - boolean f = - glfwGetKey(handle, GLFW.GLFW_KEY_F) == GLFW_PRESS; - - boolean down = ctrl && f; - - if (down && !searchHotkeyDown) { - toggleSearchMode(); - } - - searchHotkeyDown = down; - } - - private static void toggleSearchMode() { - if (BetterChatSearch.isActive() || BetterChatSearch.hasQuery()) { - BetterChatSearch.deactivate(); - } else { - BetterChatSearch.setActive(true); - } - } - - private static void renderInput(Minecraft mc, float fontSize, float boxW, float x, float inputY) { - if (!(ClientScreen.current() instanceof ChatScreen chatScreen)) return; - EditBox field = ((ChatScreenAccessor) chatScreen).getChatField(); - if (field == null) return; - - String fieldText = field.getValue(); - boolean searchMode = BetterChatSearch.isActive(); - String text = searchMode ? BetterChatSearch.getText() : fieldText; - int cursor = searchMode ? text.length() : field.getCursorPosition(); - int selStart = searchMode ? cursor : selectionStart(field, cursor); - int selEnd = searchMode ? cursor : selectionEnd(field, cursor); - - float padX = 12f; - float padY = 7f; - float lineHeight = fontSize + 2f; - float iconGap = 8f; - float searchBoxW = SEARCH_ICON_WIDTH; - float searchBoxH = SEARCH_ICON_HEIGHT; - float counterReserve = (!searchMode && text.length() >= MAX_MESSAGE_CHARS - 20) ? 34f : 0f; - float modeReserve = (searchMode || BetterChatSearch.hasQuery()) ? 74f : 0f; - float rightReserve = counterReserve + modeReserve; - - if (!searchMode && text.length() > MAX_MESSAGE_CHARS) { - text = text.substring(0, MAX_MESSAGE_CHARS); - field.setValue(text); - setCursorSafe(field, text.length()); - } - int remaining = searchMode ? Integer.MAX_VALUE : MAX_MESSAGE_CHARS - text.length(); - - float maxLineWidth = Math.max(32f, boxW - padX * 2f - searchBoxW - iconGap - rightReserve); - List lines = wrapInput(text, fontSize, maxLineWidth); - if (lines.isEmpty()) { - lines = List.of(new InputLine(0, 0, 0f)); - } - float contentHeight = lines.size() * lineHeight; - float h = Math.max(36f, contentHeight + padY * 2f); - inputBoxX = x; - inputBoxY = inputY; - inputBoxW = boxW; - inputBoxH = h; - hasInputBox = true; - - drawGlassPill(x, inputY, boxW, h, Math.min(INPUT_RADIUS, h * 0.5f), 0.92f, false); - - float searchX = x + padX; - float searchY = inputY + (h - searchBoxH) * 0.5f; - renderSearchIcon(searchX, searchY, searchBoxW, searchBoxH, BetterChatSearch.isActive(), BetterChatSearch.hasQuery()); - searchRectX = searchX; - searchRectY = searchY; - searchRectW = searchBoxW; - searchRectH = searchBoxH; - searchHit = true; - - float textX = searchX + searchBoxW + iconGap; - float textClipW = Math.max(20f, x + boxW - padX - textX - rightReserve); - TextRenderer tr = getIosevkaRegular(); - float textScale = scaleForSize(fontSize); - boolean clipped = ScissorFunction.pushRaw(textX, inputY, textClipW, h); - if (tr != null) { - tr.begin(textScale, false, false); - float textH = (float) tr.getHeight(false); - tr.end(); - float textYOffset = (lineHeight - textH) * 0.5f; - float lineY = inputY + padY + textYOffset; - if (text.isEmpty()) { - drawText(tr, searchMode ? "Search chat..." : "Message...", textX, lineY, fontSize, theme().textMuted(), false); - } else { - for (InputLine line : lines) { - String slice = safeSub(text, line.start(), line.end()); - drawText(tr, slice, textX, lineY, fontSize, theme().textPrimary(), true); - lineY += lineHeight; - } - } - } - - int min = Math.min(selStart, selEnd); - int max = Math.max(selStart, selEnd); - if (max > min) { - for (int i = 0; i < lines.size(); i++) { - InputLine line = lines.get(i); - int lineStart = line.start(); - int lineEnd = line.end(); - int selA = Math.max(min, lineStart); - int selB = Math.min(max, lineEnd); - if (selB > selA) { - float selX = textX + textWidth(getIosevkaRegular(), safeSub(text, lineStart, selA), fontSize); - float selW = textWidth(getIosevkaRegular(), safeSub(text, selA, selB), fontSize); - float sy = inputY + padY + i * lineHeight; - drawRoundedRect(selX, sy, selW, lineHeight, 3.5f, withAlpha(theme().accent(), 0x4A)); - } - } - } - - int caretLine = 0; - for (int i = 0; i < lines.size(); i++) { - InputLine line = lines.get(i); - if (cursor >= line.start() && cursor <= line.end()) { - caretLine = i; - break; - } - } - - float caretX = textX + widthTo(text, lines, cursor, fontSize); - float caretY = inputY + padY + caretLine * lineHeight; - boolean blink = (System.currentTimeMillis() / 500L) % 2 == 0; - if (blink) { - drawRoundedRect(caretX, caretY + 1f, 1.35f, Math.max(8f, lineHeight - 2f), 0.8f, withAlpha(theme().textPrimary(), 0xD8)); - } - if (clipped) ScissorFunction.pop(); - - if (BetterChatSearch.isActive() || BetterChatSearch.hasQuery()) { - String q = BetterChatSearch.isActive() ? "Search" : BetterChatSearch.getText(); - float chipFont = Math.max(10f, fontSize * 0.72f); - String chipText = fitText(getInterRegular(), q, chipFont, Math.max(36f, boxW * 0.28f)); - float chipW = textWidth(getInterRegular(), chipText, chipFont) + 14f; - float chipH = Math.min(22f, h - 8f); - float chipX = x + boxW - padX - chipW - counterReserve; - float chipY = inputY + (h - chipH) * 0.5f; - drawRoundedRect(chipX, chipY, chipW, chipH, chipH * 0.5f, withAlpha(theme().accentSoft(), BetterChatSearch.isActive() ? 0x66 : 0x40)); - drawText(getInterRegular(), chipText, chipX + 7f, chipY + (chipH - textHeight(getInterRegular(), chipFont)) * 0.5f, chipFont, - BetterChatSearch.hasQuery() ? theme().textPrimary() : theme().textMuted(), false); - } - - if (!searchMode && remaining <= 20) { - String remStr = String.valueOf(Math.max(0, remaining)); - float remSize = fontSize * 0.74f; - int remColor = remaining <= 5 ? withAlpha(theme().accent(), 0xFF) : withAlpha(theme().textMuted(), 0xCC); - drawText(getIosevkaRegular(), remStr, searchX + 2.0f, - inputY + h + 3.0f, - remSize, remColor, false); - } - } - - private static List wrapInput(String text, float fontSize, float maxWidth) { - List lines = new ArrayList<>(); - int start = 0; - float width = 0f; - - for (int i = 0; i < text.length(); ) { - int cp = text.codePointAt(i); - int cpLen = Character.charCount(cp); - - String glyphText = new String(Character.toChars(cp)); - float cw = textWidth(getIosevkaRegular(), glyphText, fontSize); - - if (width + cw > maxWidth && width > 0f) { - lines.add(new InputLine(start, i, width)); - start = i; - width = 0f; - } - - width += cw; - i += cpLen; - } - - lines.add(new InputLine(start, text.length(), width)); - return lines; - } - - private static float widthTo(String text, List lines, int cursorIndex, float fontSize) { - if (lines.isEmpty()) return 0f; - for (InputLine line : lines) { - if (cursorIndex >= line.start() && cursorIndex <= line.end()) { - return textWidth(getIosevkaRegular(), safeSub(text, line.start(), cursorIndex), fontSize); - } - } - InputLine last = lines.getLast(); - return textWidth(getIosevkaRegular(), safeSub(text, last.start(), last.end()), fontSize); + BetterChatTooltipRenderer.renderCapturedTooltip(ctx); } public static boolean onScroll(double delta) { - Minecraft mc = Minecraft.getInstance(); - if (!BetterChat.isActive()) return false; - if (!(ClientScreen.current() instanceof ChatScreen)) return false; - MousePos mouse = resolveMouse(mc.mouseHandler.xpos(), mc.mouseHandler.ypos()); - double mx = mouse.fx(); - double my = mouse.fy(); - double rawX = mouse.rawX(); - double rawY = mouse.rawY(); - boolean insideSuggest = isInsideSuggestWindow(mx, my, rawX, rawY); - if (insideSuggest) { - int step = delta > 0 ? -1 : 1; - int scrollable = Math.max(0, suggestTotal - suggestVisible); - suggestCurrentStart = Mth.clamp(suggestCurrentStart + step, 0, scrollable); - applySuggestionWindowState(suggestCurrentStart, suggestCurrentSelection); - //DebugLog.info("[BetterChat][Suggest] scroll handled start=%d total=%d visible=%d mx=%.1f my=%.1f box=(%.1f,%.1f,%.1f,%.1f)", suggestStart, suggestTotal, suggestVisible, mx, my, suggestX, suggestY, suggestW, suggestH); - return true; - } - int step = delta > 0 ? 3 : -3; - scrollOffsetLines = Mth.clamp(scrollOffsetLines + step, 0, maxScrollLines); - lastScrollInteractionMs = System.currentTimeMillis(); - return false; + return BetterChatInputHandler.onScroll(delta); } public static boolean onMouseButton(double mx, double my, int button, boolean pressed) { - Minecraft mc = Minecraft.getInstance(); - if (!BetterChat.isActive()) return false; - if (!(ClientScreen.current() instanceof ChatScreen)) return false; - - MousePos mouse = resolveMouse(mx, my); - double fx = mouse.fx(); - double fy = mouse.fy(); - boolean leftUp = button == GLFW.GLFW_MOUSE_BUTTON_LEFT && !pressed; - - boolean overSuggestWindow = isInsideSuggestWindow(fx, fy, mouse.rawX(), mouse.rawY()); - - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && sbEnabled && isScrollbarHovered(fx, fy)) { - if (pressed) { - draggingScrollbar = true; - sbDragOffset = (fy >= sbThumbY && fy <= sbThumbY + sbThumbH) - ? (float) fy - sbThumbY - : sbThumbH * 0.5f; - scrollToPosition(fy); - } else { - draggingScrollbar = false; - } - return true; - } - if (draggingScrollbar) { - if (leftUp) draggingScrollbar = false; - return true; - } - - float sTop = suggestRowsY; - boolean overSuggestRows = isInsideSuggestRows(fx, fy, mouse.rawX(), mouse.rawY()); - - if (suggestDraggingScrollbar) { - if (leftUp) suggestDraggingScrollbar = false; - return true; - } - - if (suggestHasScrollbar && isInsideSuggestScrollbar(fx, fy)) { - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { - if (pressed) { - suggestDraggingScrollbar = true; - scrollSuggestToPosition(fy); - } - } - return true; - } - - if (overSuggestRows) { - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && pressed) { - int row = (int) ((fy - sTop) / suggestItemH); - row = Mth.clamp(row, 0, Math.max(0, suggestVisible - 1)); - int idx = Mth.clamp(suggestStart + row, 0, Math.max(0, suggestTotal - 1)); - applySuggestion(idx); - //DebugLog.info("[BetterChat][Suggest] click row=%d idx=%d mx=%.1f my=%.1f raw=(%.1f,%.1f) box=(%.1f,%.1f,%.1f,%.1f)", row, idx, fx, fy, mouse.rawX(), mouse.rawY(), suggestX, suggestY, suggestW, suggestH); - return true; - } - // block other clicks while over suggest box - return true; - } - - if (overSuggestWindow) { - return true; - } - - if (searchHit) { - boolean inside = fx >= searchRectX && fx <= searchRectX + searchRectW && fy >= searchRectY && fy <= searchRectY + searchRectH; - if (inside && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { - if (pressed) { - toggleSearchMode(); - } - return true; - } - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && pressed) { - BetterChatSearch.setActive(false); - } - } - - if (contextMenu.open) { - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { - if (pressed && contextMenu.contains(fx, fy)) { - ContextMenu.MenuEntry entry = contextMenu.pick(fy); - if (entry != null) entry.action().run(); - } - contextMenu = ContextMenu.closed(); - return true; - } - } - - PickResult pick = frame.pick(fx, fy); - if (pick == null) { - if (pressed && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { - selection.clear(); - selecting = false; - leftPending = false; - } - if (!pressed && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { - selecting = false; - } - contextMenu = ContextMenu.closed(); - return false; - } - - boolean ctrlDown = InputConstants.isKeyDown(mc.getWindow(), GLFW.GLFW_KEY_LEFT_CONTROL) - || InputConstants.isKeyDown(mc.getWindow(), GLFW.GLFW_KEY_RIGHT_CONTROL); - - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { - if (pressed) { - // Кандидат на клик/выделение. Выделение начнём только при drag. - leftPending = true; - leftDownFx = fx; - leftDownFy = fy; - leftDownMsgIndex = pick.line().messageIndex(); - leftDownCharIndex = pick.glyph().charIndex(); - leftDownStyle = pick.glyph().style(); - - selecting = false; // не выделяем сразу - contextMenu = ContextMenu.closed(); - return true; // важно: блокируем ванильный suggest по клику - } else { - // отпускание ЛКМ - if (leftPending) { - leftPending = false; - - if (selecting) { - // закончили drag-выделение - selecting = false; - return true; - } - - // одиночный клик (без drag) - boolean handled = handleClickEvent(leftDownStyle, ctrlDown); - if (!handled && ctrlDown) { - handled = tryPrefillTellFromClick(leftDownMsgIndex, leftDownCharIndex); - } - if (!handled) selection.clear(); - return true; // блокируем ванильную обработку кликов по чату - } - } - } else if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { - if (pressed) { - openContextMenu(pick, mx, my); - } - } - return false; + return BetterChatMouseClickHandler.onMouseButton(mx, my, button, pressed); } public static void onMouseMove(double mx, double my) { - if (!BetterChat.isActive()) return; - MousePos mouse = resolveMouse(mx, my); - double fx = mouse.fx(); - double fy = mouse.fy(); - if (draggingScrollbar) { - scrollToPosition(fy); - return; - } - if (suggestDraggingScrollbar) { - scrollSuggestToPosition(fy); - return; - } - if (isInsideSuggestWindow(fx, fy, mouse.rawX(), mouse.rawY())) return; - - if (leftPending && !selecting) { - double dx = fx - leftDownFx; - double dy = fy - leftDownFy; - if (dx * dx + dy * dy >= DRAG_SELECT_THRESHOLD * DRAG_SELECT_THRESHOLD) { - selection.update(leftDownMsgIndex, leftDownCharIndex); - selecting = true; - } else { - // пока не потащили — не начинаем выделение - return; - } - } - - if (!selecting) return; - PickResult pick = frame.pick(mouse.fx(), mouse.fy()); - if (pick == null) { - pick = nearestFramePick(mouse.fx(), mouse.fy()); - } - if (pick == null) return; - selection.updateCaret(pick.line().messageIndex(), selectionCaretIndex(pick.glyph())); - } - - private static int selectionCaretIndex(GlyphBox glyph) { - if (glyph == null) return 0; - return Math.max(glyph.charIndex(), glyph.charEndExclusive() - 1); - } - - private static PickResult nearestFramePick(double mx, double my) { - if (frame == null || frame.lines() == null || frame.lines().isEmpty()) return null; - - FrameLine bestLine = null; - float bestDist = Float.MAX_VALUE; - for (FrameLine line : frame.lines()) { - float dy; - if (my < line.y0()) { - dy = (float) (line.y0() - my); - } else if (my > line.y1() + LINE_SPACING) { - dy = (float) (my - (line.y1() + LINE_SPACING)); - } else { - dy = 0.0f; - } - - if (dy < bestDist) { - bestDist = dy; - bestLine = line; - } - } - - if (bestLine == null || bestLine.glyphs().isEmpty()) return null; - GlyphBox first = bestLine.glyphs().getFirst(); - GlyphBox last = bestLine.glyphs().getLast(); - GlyphBox glyph = mx <= first.x0() ? first : last; - return new PickResult(bestLine, glyph); - } - - private static void openContextMenu(PickResult pick, double mx, double my) { - List entries = new ArrayList<>(); - ChatLine msg = pick.line().message(); - String full = msg.text().getString(); - int safeLen = full.length(); - BetterChat settings = BetterChat.get(); - long ts = msg.timestampMs(); - boolean tsEnabled = settings != null && settings.timestampEnabled(); - boolean tsUnix = settings != null && settings.timestampToggles().get("hover_unix"); - - if (selection.appliesTo(pick.line().messageIndex()) && selection.hasRange()) { - String selected = selectedText(); - entries.add(new ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_selection"), () -> ClipboardUtil.copy(selected))); - } else { - entries.add(new ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_message"), () -> ClipboardUtil.copy(full))); - } - - List nickCandidates = ChatNameUtil.extractNicks(full); - String hovered = ChatNameUtil.normalizeNickCandidate(wordAt(full, pick.glyph().charIndex())); - String targetNick = null; - if (!hovered.isEmpty() - && ChatNameUtil.isNickLike(hovered) - && nickCandidates.stream().anyMatch(n -> n.equalsIgnoreCase(hovered))) { - targetNick = hovered; - } else if (nickCandidates.size() == 1) { - targetNick = nickCandidates.getFirst(); - } - if (isOnlinePlayer(targetNick)) { - String nickToTell = targetNick; - entries.add(new ContextMenu.MenuEntry(I18n.get("better_chat.context.reply"), () -> prefillTell(nickToTell))); - } - - if (hoverEntityUuid != null && !hoverEntityUuid.isEmpty()) { - String uuidToCopy = hoverEntityUuid; - entries.add(new ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_uuid"), () -> ClipboardUtil.copy(uuidToCopy))); - } - - if (tsEnabled) { - entries.add(new ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_time"), () -> ClipboardUtil.copy(formatTimestamp(ts, settings.timestampSeconds())))); - entries.add(new ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_date"), () -> ClipboardUtil.copy(formatDate(ts)))); - if (tsUnix) { - entries.add(new ContextMenu.MenuEntry(I18n.get("better_chat.context.copy_unix"), () -> ClipboardUtil.copy(String.valueOf(ts / 1000L)))); - } - } - - contextMenu = ContextMenu.open((float) mx, (float) my, entries); + BetterChatInputHandler.onMouseMove(mx, my); } public static void copySelectionToClipboard() { - String selected = selectedText(); - if (selected.isEmpty()) return; - ClipboardUtil.copy(selected); + BetterChatContextMenuHandler.copySelectionToClipboard(); } - private static String selectedText() { - if (!selection.hasRange()) return ""; - if (lastMessages == null || lastMessages.isEmpty()) return ""; - - int startMsg = Mth.clamp(selection.startContext(), 0, lastMessages.size() - 1); - int endMsg = Mth.clamp(selection.endContext(), 0, lastMessages.size() - 1); - if (endMsg < startMsg) return ""; - - StringBuilder out = new StringBuilder(); - for (int msgIdx = startMsg; msgIdx <= endMsg; msgIdx++) { - ChatLine line = lastMessages.get(msgIdx); - if (line == null || line.text() == null) continue; - - String full = line.text().getString(); - int len = full.length(); - int start = selection.startForLine(msgIdx); - int end = selection.endForLine(msgIdx); - - int from = start == Integer.MIN_VALUE ? 0 : Mth.clamp(start, 0, len); - int toInclusive = end == Integer.MAX_VALUE ? Math.max(0, len - 1) : Mth.clamp(end, 0, Math.max(0, len - 1)); - int to = Mth.clamp(toInclusive + 1, 0, len); - - if (to > from) { - if (!out.isEmpty()) out.append(' '); - out.append(safeSub(full, from, to)); - } - } - return out.toString(); - } - - private static boolean handleClickEvent(Style style, boolean ctrlDown) { - if (style == null) return false; - ClickEvent evt = style.getClickEvent(); - if (evt == null) return false; - String val = switch (evt) { - case ClickEvent.OpenUrl openUrl -> openUrl.uri().toString(); - case ClickEvent.OpenFile openFile -> openFile.path(); - case ClickEvent.RunCommand run -> run.command(); - case ClickEvent.SuggestCommand sug -> sug.command(); - case ClickEvent.CopyToClipboard copy -> copy.value(); - case ClickEvent.ShowDialog showDialog -> showDialog.dialog().value().toString(); - case ClickEvent.ChangePage changePage -> String.valueOf(changePage.page()); - case ClickEvent.Custom custom -> custom.id().toString(); - default -> null; - }; - if (val == null || val.isEmpty()) return false; - try { - if (evt instanceof ClickEvent.OpenUrl || evt instanceof ClickEvent.OpenFile) { - Minecraft mc = Minecraft.getInstance(); - if (ClientScreen.current() instanceof ChatScreen chat) { - ClientScreen.show(mc, new ConfirmLinkScreen(confirm -> { - if (confirm) Util.getPlatform().openUri(val); - ClientScreen.show(mc, chat); - }, val, false)); - } else { - Util.getPlatform().openUri(val); - } - return true; - } else if (evt instanceof ClickEvent.CopyToClipboard) { - ClipboardUtil.copy(val); - return true; - } else if (evt instanceof ClickEvent.RunCommand && val.startsWith("@")) { - return CommandManager.handle(val); - } else if (evt instanceof ClickEvent.SuggestCommand || evt instanceof ClickEvent.RunCommand) { - // Убираем нежелательный автокомплит: без Ctrl не подставляем команды в поле ввода. - if (!ctrlDown) return false; - prefillChat(val); - return true; - } else { - return false; - } - } catch (Exception e) { - //DebugLog.error("[BetterChat] click action failed", e); - return false; - } - } - - private static boolean tryPrefillTellFromClick(int msgIndex, int charIndex) { - if (msgIndex < 0 || msgIndex >= lastMessages.size()) return false; - String full = lastMessages.get(msgIndex).text().getString(); - List nickCandidates = ChatNameUtil.extractNicks(full); - if (nickCandidates.isEmpty()) return false; - - String hovered = ChatNameUtil.normalizeNickCandidate(wordAt(full, charIndex)); - String targetNick = null; - if (!hovered.isEmpty() - && ChatNameUtil.isNickLike(hovered) - && nickCandidates.stream().anyMatch(n -> n.equalsIgnoreCase(hovered))) { - targetNick = hovered; - } else if (nickCandidates.size() == 1) { - targetNick = nickCandidates.getFirst(); - } - if (!isOnlinePlayer(targetNick)) return false; - prefillTell(targetNick); - return true; - } - - private static void prefillChat(String value) { - if (value == null) return; - Minecraft mc = Minecraft.getInstance(); - if (!(ClientScreen.current() instanceof ChatScreen chatScreen)) return; - EditBox field = ((ChatScreenAccessor) chatScreen).getChatField(); - if (field == null) return; - field.setValue(value); - setCursorSafe(field, value.length()); - } - - private static void prefillTell(String nick) { - Minecraft mc = Minecraft.getInstance(); - if (!(ClientScreen.current() instanceof ChatScreen chatScreen)) return; - if (!isOnlinePlayer(nick)) return; - EditBox field = ((ChatScreenAccessor) chatScreen).getChatField(); - if (field == null) return; - String value = "/tell " + nick + " "; - field.setValue(value); + public static void resetScroll() { + BetterChatInputHandler.resetScroll(); } public static void applyAutoPrefixIfNeeded(EditBox field) { // Compact BetterChat no longer owns chat-prefix chips; hook kept for compatibility. } - private static boolean isOnlinePlayer(String nick) { - if (nick == null || nick.isEmpty()) return false; - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || mc.player.connection == null) return false; - return mc.player.connection.getOnlinePlayers().stream() - .anyMatch(e -> e.getProfile() != null && nick.equalsIgnoreCase(e.getProfile().name())); + public static void setSuggestionContext(ChatScreen screen, GuiGraphicsExtractor context, int mouseX, int mouseY) { + storedScreen = screen; } - private static int withAlpha(int argb, int alpha) { - return (argb & 0x00FFFFFF) | ((alpha & 0xFF) << 24); - } - - private static int mulAlpha(int argb, float a) { - int alpha = (int) (((argb >>> 24) & 0xFF) * a); - return (argb & 0x00FFFFFF) | (Mth.clamp(alpha, 0, 255) << 24); - } - - private static void renderSearchIcon(float x, float y, float w, float h, boolean active, boolean hasQuery) { - boolean hover = lastMouseValid && lastMouseFx >= x && lastMouseFx <= x + w && lastMouseFy >= y && lastMouseFy <= y + h; - float radius = h * 0.5f; - int bg = active - ? withAlpha(theme().accent(), 0x8E) - : (hasQuery ? withAlpha(theme().accentSoft(), 0x8A) : withAlpha(theme().surface(), hover ? 0xC0 : 0xA2)); - int tint = withAlpha(theme().accent(), active ? 0x30 : (hasQuery ? 0x24 : 0x18)); - int strokeA = active ? withAlpha(theme().accent(), 0xC8) : withAlpha(theme().textPrimary(), hover ? 0x38 : 0x24); - int strokeB = withAlpha(theme().accentSoft(), active ? 0x86 : (hasQuery ? 0x66 : 0x40)); - - drawRoundedRect(x, y, w, h, radius, bg); - drawRoundedRect(x + 1f, y + 1f, w - 2f, h - 2f, Math.max(0f, radius - 1f), tint); - drawRoundedRectStrokeGradient(x, y, w, h, radius, 0.7f, strokeA, strokeB); - - TextRenderer icons = Fonts.renderer("Icons", FontInfo.Type.Regular, getInterRegular()); - String icon = "s"; - float iconSize = h * 0.50f; - float iconW = textWidth(icons, icon, iconSize); - float iconH = textHeight(icons, iconSize); - int iconColor = active || hasQuery ? theme().textPrimary() : withAlpha(theme().textPrimary(), hover ? 0xD8 : 0xB8); - drawText(icons, icon, x + (w - iconW) * 0.5f, y + (h - iconH) * 0.5f - h * 0.015f, iconSize, iconColor, false); - } - - private static void drawLiquidHoverPill(float x, float y, float w, float h, float radius, float alpha) { - if (renderer == null || w <= 0f || h <= 0f || alpha <= 0.001f) return; - flushRenderer(); - renderer.liquidGlassRect( - x, y, w, h, - Math.max(1.0f, radius), - 10.5f, - theme().accentSoft(), - Mth.clamp(alpha, 0.0f, 1.0f), - 0.08f, - -18.0f, - 0.82f, - 0.72f, - 0.34f, - 0.095f, - 1.2f - ); - drawRoundedRect(x, y, w, h, radius, withAlpha(theme().surfaceHover(), 0x32)); - drawRoundedRectStrokeGradient(x, y, w, h, radius, 0.55f, - withAlpha(theme().accentSoft(), 0x50), - withAlpha(theme().accent(), 0x34)); - } - - private static void drawScrollbarGlass(float trackX, - float trackY, - float trackW, - float trackH, - float thumbY, - float thumbH, - boolean hot, - int trackAlpha, - int thumbAlpha) { - if (renderer == null || trackW <= 0f || trackH <= 0f || thumbH <= 0f) return; - - SettingsGuiPalette palette = SettingsGuiPalette.current(); - int trackA = withAlpha(palette.moduleScrollTrackA(), trackAlpha); - int trackB = withAlpha(palette.moduleScrollTrackB(), Math.min(255, trackAlpha + 0x18)); - int handleA = withAlpha(palette.moduleScrollHandleA(), thumbAlpha); - int handleB = withAlpha(palette.moduleScrollHandleB(), Math.min(255, thumbAlpha + 0x0C)); - float radius = trackW * 0.5f; - - // Identical structure to ClickGui Modules/Settings: one vertical gradient for the track - // and one for the handle. No rail, highlight, stroke or hover-width decoration. - renderer.roundedRectGradientQuad( - trackX, trackY, trackW, trackH, radius, 1.0f, - trackA, trackB, trackB, trackA - ); - renderer.roundedRectGradientQuad( - trackX, thumbY, trackW, thumbH, radius, 1.0f, - handleA, handleB, handleB, handleA - ); - } - - private static void drawGlassPill(float x, float y, float w, float h, float radius, float alpha, boolean softPanel) { - if (renderer == null || w <= 0f || h <= 0f) return; - - // BetterChat uses liquid glass as a background material only. Text is rendered later - // and is not touched here. Blur strength is separate from the glass veil opacity. - BetterChat settings = BetterChat.get(); - float drawAlpha = Mth.clamp(alpha, 0.0f, 1.0f); - if (drawAlpha <= 0.001f) return; - float configuredAlpha = settings != null ? settings.liquidGlassAlphaFactor() : (230f / 255f); - float blurStrength = configuredAlpha * drawAlpha; - float materialAlpha = Mth.clamp(0.72f + configuredAlpha * 0.28f, 0.0f, 1.0f) * drawAlpha; - float glassRadius = Math.max(2f, radius); - float thickness = softPanel ? 15.5f : 12.5f; - float fresnelPower = softPanel ? -26.0f : -20.0f; - float fresnelAlpha = Mth.clamp(0.72f + configuredAlpha * 0.28f, 0.0f, 1.0f) * drawAlpha; - float baseAlpha = Mth.clamp((softPanel ? 0.66f : 0.68f) + configuredAlpha * (softPanel ? 0.34f : 0.32f), 0.0f, 1.0f); - float fresnelMix = softPanel ? 0.46f : 0.44f; - float distortPx = (softPanel ? 0.172f : 0.145f) * drawAlpha; - - flushRenderer(); - renderer.liquidGlassRect( - x, y, w, h, - glassRadius, - thickness, - theme().accent(), - materialAlpha, - blurStrength, - fresnelPower, - fresnelAlpha, - baseAlpha, - fresnelMix, - distortPx, - softPanel ? 2.65f : 2.25f - ); - - int veilAlpha = Math.round((softPanel ? 0x16 : 0x0C) * drawAlpha); - if (veilAlpha > 0) { - drawRoundedRect(x, y, w, h, glassRadius, withAlpha(theme().windowBg(), veilAlpha)); - } - } - - private static String fitText(TextRenderer font, String text, float size, float maxWidth) { - if (text == null) return ""; - if (textWidth(font, text, size) <= maxWidth) return text; - String suffix = "..."; - float suffixW = textWidth(font, suffix, size); - int end = text.length(); - while (end > 0 && textWidth(font, text.substring(0, end), size) + suffixW > maxWidth) { - end--; - } - return end <= 0 ? suffix : text.substring(0, end) + suffix; - } - - private static TextRenderer getInterRegular() { - return Fonts.renderer("Inter", FontInfo.Type.Regular, TextRenderer.get()); - } - - private static TextRenderer getIosevkaRegular() { - return Fonts.renderer("Iosevka", FontInfo.Type.Regular, TextRenderer.get()); - } - - private static TextRenderer getIosevkaItalic() { - return Fonts.renderer("Iosevka", FontInfo.Type.Italic, getIosevkaRegular()); - } - - private static TextRenderer getIosevkaBold() { - return Fonts.renderer("Iosevka", FontInfo.Type.Bold, getIosevkaRegular()); - } - - private static TextRenderer getIosevkaBoldItalic() { - return Fonts.renderer("Iosevka", FontInfo.Type.BoldItalic, getIosevkaBold()); - } - - private static TextRenderer fontRenderer(String key) { - if (key == null) return getIosevkaRegular(); - return switch (key) { - case "iosevka_bold" -> getIosevkaBold(); - case "iosevka_bold_italic" -> getIosevkaBoldItalic(); - case "iosevka_medium_italic" -> getIosevkaItalic(); - case "vanilla_symbols" -> TextGlyphFallback.vanillaSymbols(getIosevkaRegular()); - case "vanilla" -> VanillaTextRenderer.INSTANCE; - default -> getIosevkaRegular(); - }; - } - - private static String fontForGlyph(String baseFont, int codePoint) { - TextRenderer preferred = fontRenderer(baseFont); - return TextGlyphFallback.fontKeyForGlyph(baseFont, preferred, codePoint, "iosevka_medium"); - } - - private static TextRenderer rendererForGlyph(TextRenderer preferred, int codePoint) { - return TextGlyphFallback.rendererForGlyph(preferred, codePoint); - } - - private static float scaleForSize(float size) { - return size / 18.0f; - } - - private static float textWidth(TextRenderer tr, String text, float size) { - if (tr == null || text == null || text.isEmpty()) return 0f; - float scale = scaleForSize(size); - float svgAdvance = svgGlyphSize(tr, size, false); - TextRenderer current = null; - float width = 0f; - try { - for (int i = 0; i < text.length(); ) { - int cp = text.codePointAt(i); - if (TextGlyphFallback.shouldUseVanillaSvg(tr, cp)) { - if (current != null) { - current.end(); - current = null; - } - width += svgAdvance; - i += Character.charCount(cp); - continue; - } - String glyph = new String(Character.toChars(cp)); - TextRenderer next = rendererForGlyph(tr, cp); - if (next != current) { - if (current != null) current.end(); - current = next; - current.begin(scale, true, false); - } - width += (float) current.getWidth(glyph, false); - i += Character.charCount(cp); - } - return width; - } finally { - if (current != null) current.end(); - } - } - - private static float textHeight(TextRenderer tr, float size) { - if (tr == null) return 0f; - float scale = scaleForSize(size); - tr.begin(scale, true, false); - try { - return (float) tr.getHeight(false); - } finally { - tr.end(); - } - } - - private static void drawText(TextRenderer tr, String text, float x, float y, float size, int argb, boolean shadow) { - if (tr == null || text == null || text.isEmpty()) return; - if (((argb >>> 24) & 0xFF) <= 0) return; - float scale = scaleForSize(size); - float svgSize = svgGlyphSize(tr, size, shadow); - float svgY = y + (textHeight(tr, size) - svgSize) * 0.5f; - applyColor(argb); - TextRenderer current = null; - float cursorX = x; - try { - for (int i = 0; i < text.length(); ) { - int cp = text.codePointAt(i); - if (TextGlyphFallback.shouldUseVanillaSvg(tr, cp)) { - if (current != null) { - current.end(); - current = null; - } - String svgName = TextGlyphFallback.vanillaSvgName(cp); - if (renderer != null && svgName != null) { - renderer.svg(svgName, cursorX, svgY, svgSize, svgSize, - SvgRenderOptions.fromFile().withAlpha(((argb >>> 24) & 0xFF) / 255.0f)); - } - cursorX += svgSize; - i += Character.charCount(cp); - continue; - } - String glyph = new String(Character.toChars(cp)); - TextRenderer next = rendererForGlyph(tr, cp); - if (next != current) { - if (current != null) current.end(); - current = next; - current.begin(scale, false, false); - } - cursorX = (float) current.render(glyph, cursorX, y, TMP_COLOR, shadow); - i += Character.charCount(cp); - } - } finally { - if (current != null) current.end(); - } - } - - private static float svgGlyphSize(TextRenderer tr, float size, boolean shadow) { - return Math.max(1.0f, textHeight(tr, size)) * 0.92f; - } - - private static void drawRoundedRect(float x, float y, float w, float h, float radius, int argb) { - if (renderer == null) return; - if (((argb >>> 24) & 0xFF) <= 0) return; - BetterChat cfg = BetterChat.get(); - boolean useGradient = cfg != null && cfg.gradientEnabled(); - HudRenderUtil.drawHudBackground(renderer, x, y, w, h, radius, 1.1f, argb, useGradient); - } - - private static void drawRoundedRectStrokeGradient(float x, float y, float w, float h, float radius, float thickness, - int startArgb, int endArgb) { - if (renderer == null) return; - if (((startArgb >>> 24) & 0xFF) <= 0 && ((endArgb >>> 24) & 0xFF) <= 0) return; - renderer.roundedRectStrokeGradient(x, y, w, h, radius, 1.1f, thickness, startArgb, endArgb, (float) 0.0); - } - - private static void drawRect(float x, float y, float w, float h, int argb) { - if (renderer == null) return; - if (((argb >>> 24) & 0xFF) <= 0) return; - renderer.quad(x, y, w, h, argb); - } - - private static void flushRenderer() { - if (renderer == null) return; - if (Renderer2D.isBatching()) { - Renderer2D.flushBatch(); - } else { - renderer.begin(); - } - } - - private static void applyColor(int argb) { - BetterChatRenderer.TMP_COLOR.a = (argb >>> 24) & 0xFF; - BetterChatRenderer.TMP_COLOR.r = (argb >>> 16) & 0xFF; - BetterChatRenderer.TMP_COLOR.g = (argb >>> 8) & 0xFF; - BetterChatRenderer.TMP_COLOR.b = argb & 0xFF; - } - - private static String fontForStyle(Style style) { - boolean bold = style.isBold(); - boolean italic = style.isItalic(); - if (bold && italic) return "iosevka_bold_italic"; - if (bold) return "iosevka_bold"; - if (italic) return "iosevka_medium_italic"; - return "iosevka_medium"; - } - - private static String safeSub(String s, int start, int end) { - if (s == null) return ""; - int len = s.length(); - start = Math.max(0, Math.min(len, start)); - end = Math.max(0, Math.min(len, end)); - if (end < start) { - int t = start; - start = end; - end = t; - } - return s.substring(start, end); - } - - private static int selectionStart(EditBox field, int fallback) { - if (field == null) return fallback; - return Mth.clamp(field.getCursorPosition(), 0, field.getValue().length()); - } - - private static int selectionEnd(EditBox field, int fallback) { - if (field == null) return fallback; - try { - return Mth.clamp(((TextFieldWidgetAccessor) field).combatant$getSelectionEnd(), 0, field.getValue().length()); - } catch (Throwable ignored) { - String selected = field.getHighlighted(); - int cursor = selectionStart(field, fallback); - if (selected == null || selected.isEmpty()) return cursor; - return Mth.clamp(cursor + selected.length(), 0, field.getValue().length()); - } - } - - private static void setCursorSafe(EditBox field, int pos) { - if (field == null) return; - field.moveCursorTo(Mth.clamp(pos, 0, field.getValue().length()), false); - } - - private static String wordAt(String text, int charIndex) { - if (text == null || text.isEmpty()) return ""; - int idx = Mth.clamp(charIndex, 0, Math.max(0, text.length() - 1)); - int start = idx; - while (start > 0 && !Character.isWhitespace(text.charAt(start - 1))) start--; - int end = idx; - while (end < text.length() && !Character.isWhitespace(text.charAt(end))) end++; - if (end <= start) return ""; - return text.substring(start, end).replaceAll("[<>:\\[\\]]", ""); - } - - private static MousePos resolveMouse(double rawX, double rawY) { - // No scaling; keep raw and framebuffer identical. - return new MousePos(rawX, rawY, rawX, rawY); - } - - public static void resetScroll() { - scrollOffsetLines = 0; - smoothScrollOffsetLines = 0f; - draggingScrollbar = false; - sbEnabled = false; - sbDragOffset = 0f; + public static void onNewMessage() { + BetterChatInputHandler.onNewMessage(); } public static float getLastWidth() { @@ -2149,722 +199,13 @@ public enum BetterChatRenderer { } public static boolean contains(float mx, float my) { - return isInteractive(mx, my); + return BetterChatInputHandler.contains(mx, my); } public static boolean isInteractive(float mx, float my) { - boolean inChat = chatHitW > 0f && mx >= chatHitX && mx <= chatHitX + chatHitW && my >= chatHitY && my <= chatHitY + chatHitH; - boolean inSearch = searchHit && mx >= searchRectX && mx <= searchRectX + searchRectW && my >= searchRectY && my <= searchRectY + searchRectH; - boolean inInput = hasInputBox && mx >= inputBoxX && mx <= inputBoxX + inputBoxW && my >= inputBoxY && my <= inputBoxY + inputBoxH; - boolean inSuggest = isInsideSuggestWindow(mx, my); - boolean inContext = contextMenu.open && contextMenu.contains(mx, my); - boolean inScrollbar = sbEnabled && isScrollbarHovered(mx, my); - return inChat || inSearch || inInput || inSuggest || inContext || inScrollbar; - } - - public static void onNewMessage() { - if (scrollOffsetLines > 0 && scrollOffsetLines <= 2) { - scrollOffsetLines = 0; - smoothScrollOffsetLines = 0f; - } - } - - private static boolean isInsideSuggestRows(double mx, double my) { - if (!suggestActive) return false; - return mx >= suggestRowsX && mx <= suggestRowsX + suggestRowsW - && my >= suggestRowsY && my <= suggestRowsY + suggestRowsH; - } - - private static boolean isInsideSuggestRows(double mx, double my, double rawX, double rawY) { - return isInsideSuggestRows(mx, my) || isInsideSuggestRows(rawX, rawY); - } - - private static boolean isInsideSuggestWindow(double mx, double my) { - if (!suggestActive) return false; - return mx >= suggestX && mx <= suggestX + suggestW && my >= suggestY && my <= suggestY + suggestH; - } - - private static boolean isInsideSuggestWindow(double mx, double my, double rawX, double rawY) { - return isInsideSuggestWindow(mx, my) || isInsideSuggestWindow(rawX, rawY); - } - - private static boolean isInsideSuggestScrollbar(double mx, double my) { - if (!suggestActive || !suggestHasScrollbar) return false; - float hitPad = 4f; - return mx >= suggestTrackX - hitPad && - mx <= suggestTrackX + suggestTrackW + hitPad && - my >= suggestTrackY - hitPad && - my <= suggestTrackY + suggestTrackH + hitPad; - } - - private static float computeWidth(int screenW, float ratio) { - float clamped = Mth.clamp(ratio, 0.2f, 0.8f); - float w = screenW * clamped; - return Mth.clamp(w, 320f, 560f); - } - - private static BetterChatStore buildPreviewStore() { - if (previewStore == null) { - BetterChatStore store = new BetterChatStore(); - store.add(Component.literal("Better Chat")); - store.add(Component.literal("Drag to position")); - store.add(Component.literal("Messages appear here")); - previewStore = store; - } - return previewStore; - } - - private static void renderScrollbar( - float boxX, - float boxY, - float boxW, - float boxH, - int startLine, - int visibleLines, - int totalLines, - double mouseX, - double mouseY) { - if (visibleLines <= 0 || totalLines <= visibleLines) { - sbEnabled = false; - draggingScrollbar = false; - return; - } - - int scrollable = Math.max(1, totalLines - visibleLines); - boolean hot = draggingScrollbar || isScrollbarHovered(mouseX, mouseY); - boolean recently = System.currentTimeMillis() - lastScrollInteractionMs < 850L; - float trackW = 5.0f; - float trackX = boxX - trackW - 7f; - float trackY = boxY + 10f; - float trackH = Math.max(16f, boxH - 20f); - float thumbH = Math.max(18f, trackH * ((float) visibleLines / (float) totalLines)); - float ratio = (float) startLine / (float) scrollable; - float thumbY = trackY + (trackH - thumbH) * Mth.clamp(ratio, 0f, 1f); - - sbTrackX = trackX; - sbTrackY = trackY; - sbTrackW = trackW; - sbTrackH = trackH; - sbThumbY = thumbY; - sbThumbH = thumbH; - sbEnabled = true; - - if (hot || draggingScrollbar) { - SystemCursor.set(SystemCursor.CursorType.SCROLL); - } - - int trackAlpha = hot ? 0xB8 : (recently ? 0x9C : 0x84); - int thumbAlpha = hot ? 0xFF : (recently ? 0xEC : 0xD4); - drawScrollbarGlass(trackX, trackY, trackW, trackH, thumbY, thumbH, hot, trackAlpha, thumbAlpha); - } - - private static boolean isScrollbarHovered(double mx, double my) { - float hitPad = 5f; - return sbEnabled && - mx >= sbTrackX - hitPad && - mx <= sbTrackX + sbTrackW + hitPad && - my >= sbTrackY - hitPad && - my <= sbTrackY + sbTrackH + hitPad; - } - - private static void scrollToPosition(double my) { - if (!sbEnabled || sbVisibleLines <= 0 || sbTotalLines <= sbVisibleLines) return; - float trackSpan = sbTrackH - sbThumbH; - if (trackSpan <= 0f) return; - float rel = (float) (my - sbTrackY - sbDragOffset); - float t = Mth.clamp(rel / trackSpan, 0f, 1f); - int scrollable = Math.max(0, sbTotalLines - sbVisibleLines); - int targetStart = Math.round(t * scrollable); - scrollOffsetLines = Mth.clamp(sbTotalLines - sbVisibleLines - targetStart, 0, scrollable); - lastScrollInteractionMs = System.currentTimeMillis(); - } - - private static void scrollSuggestToPosition(double my) { - if (!suggestHasScrollbar || suggestVisible <= 0 || suggestTotal <= suggestVisible) return; - float trackSpan = suggestTrackH - suggestThumbH; - if (trackSpan <= 0f) return; - float rel = (float) (my - suggestTrackY - suggestThumbH * 0.5f); - float t = Mth.clamp(rel / trackSpan, 0f, 1f); - int scrollable = Math.max(0, suggestTotal - suggestVisible); - int targetStart = Math.round(t * scrollable); - suggestCurrentStart = Mth.clamp(targetStart, 0, scrollable); - applySuggestionWindowState(suggestCurrentStart, suggestCurrentSelection); - } - - private static void applySuggestionWindowState(int start, int selection) { - if (suggestWindow == null) return; - SuggestionWindowAccessor acc = (SuggestionWindowAccessor) suggestWindow; - acc.setCombatant$inWindowIndex(Math.max(0, start)); - if (selection >= 0) { - acc.setCombatant$selection(selection); - } - } - - private static void applySuggestion(int idx) { - Minecraft mc = Minecraft.getInstance(); - if (!(ClientScreen.current() instanceof ChatScreen chatScreen)) return; - EditBox field = ((ChatScreenAccessor) chatScreen).getChatField(); - if (field == null) return; - - // Update vanilla selection state for completeness - if (suggestWindow != null) { - SuggestionWindowAccessor acc = (SuggestionWindowAccessor) suggestWindow; - acc.setCombatant$selection(idx); - } - - if (idx < 0 || idx >= suggestEntries.size()) return; - com.mojang.brigadier.suggestion.Suggestion suggestion = suggestEntries.get(idx); - String current = field.getValue(); - try { - String applied = suggestion.apply(current); - field.setValue(applied); - setCursorSafe(field, applied.length()); - suggestCurrentSelection = idx; - applySuggestionWindowState(suggestCurrentStart, suggestCurrentSelection); - } catch (Exception e) { - //DebugLog.error("[BetterChat][Suggest] apply failed", e); - } - } - - private static CommandSuggestorBridge.SuggestionSnapshot buildCustomSnapshot(String text, int cursor) { - List suggestions = CommandManager.suggest(text, cursor); - if (suggestions == null || suggestions.isEmpty()) return null; - List texts = new ArrayList<>(suggestions.size()); - for (com.mojang.brigadier.suggestion.Suggestion s : suggestions) { - texts.add(s.getText()); - } - int selection = 0; - int start = 0; - int visible = Math.min(5, Math.max(1, suggestions.size())); - return new CommandSuggestorBridge.SuggestionSnapshot(0, 0, 0, 0, texts, suggestions, selection, start, visible); - } - - @SuppressWarnings("unused") - public static void setSuggestionContext(ChatScreen screen, GuiGraphicsExtractor context, int mouseX, int mouseY) { - storedScreen = screen; - } - - private static char commandPrefix(String text) { - if (text == null) return 0; - for (int i = 0; i < text.length(); i++) { - char c = text.charAt(i); - if (Character.isWhitespace(c)) continue; - if (c == '/' || c == '@') return c; - return 0; - } - return 0; - } - - private static boolean refreshSuggestionsIfNeeded(String text, int cursor, int selStart, int selEnd) { - if (text.equals(lastSuggestInput) - && cursor == lastSuggestCursor - && selStart == lastSuggestSelStart - && selEnd == lastSuggestSelEnd) { - return false; - } - lastSuggestInput = text; - lastSuggestCursor = cursor; - lastSuggestSelStart = selStart; - lastSuggestSelEnd = selEnd; - return true; - } - - private static void resetSuggestionTracking() { - lastSuggestInput = ""; - lastSuggestCursor = -1; - lastSuggestSelStart = -1; - lastSuggestSelEnd = -1; - lastSnapshot = null; - lastSuggestionHash = 0; - suggestWindow = null; - suggestEntries = Collections.emptyList(); - suggestRowsX = suggestRowsY = suggestRowsW = suggestRowsH = 0f; - suggestCurrentStart = -1; - suggestCurrentSelection = -1; - } - - private static void renderSuggestions() { - suggestActive = false; - suggestHasScrollbar = false; - if (storedScreen == null) return; - EditBox field = ((ChatScreenAccessor) storedScreen).getChatField(); - String text = field != null ? field.getValue() : null; - if (field == null || text == null || text.isEmpty()) { - storedScreen = null; - resetSuggestionTracking(); - return; - } - - int cursor = field.getCursorPosition(); - int selStart = selectionStart(field, cursor); - int selEnd = selectionEnd(field, cursor); - - char prefix = commandPrefix(text); - if (prefix == 0) { - storedScreen = null; - resetSuggestionTracking(); - return; - } - - boolean inputChanged = refreshSuggestionsIfNeeded(text, cursor, selStart, selEnd); - boolean windowChanged = false; - if (prefix == '/') { - windowChanged = CommandSuggestorBridge.peekWindow(storedScreen) != CommandSuggestorBridge.lastWindow(); - } - if (inputChanged || windowChanged || lastSnapshot == null) { - if (prefix == '@') { - lastSnapshot = buildCustomSnapshot(text, cursor); - } else { - lastSnapshot = CommandSuggestorBridge.snapshot(storedScreen); - } - } - CommandSuggestorBridge.SuggestionSnapshot snap = lastSnapshot; - if (snap == null) { - storedScreen = null; - resetSuggestionTracking(); - return; - } - if (prefix == '@') { - suggestWindow = null; - } - - // Debug logging once per snapshot content to confirm suggestions arrive - int hash = snap.texts().hashCode() ^ snap.selection() ^ snap.startIndex(); - boolean snapshotChanged = hash != lastSuggestionHash; - if (snapshotChanged) { - lastSuggestionHash = hash; - /*DebugLog.info( - "[BetterChat][Suggest] snapshot texts=%d sel=%d start=%d vis=%d", - snap.texts().size(), - snap.selection(), - snap.startIndex(), - snap.visibleCount() - );*/ - } - suggestEntries = snap.suggestions(); - - int total = snap.texts().size(); - int visible = Math.min(5, Math.max(1, total - snap.startIndex())); - int scrollable = Math.max(0, total - visible); - - if (snapshotChanged) { - suggestCurrentStart = Mth.clamp(snap.startIndex(), 0, scrollable); - suggestCurrentSelection = Mth.clamp(snap.selection(), 0, Math.max(0, total - 1)); - } - if (suggestCurrentStart < 0) { - suggestCurrentStart = Mth.clamp(snap.startIndex(), 0, scrollable); - } else { - suggestCurrentStart = Mth.clamp(suggestCurrentStart, 0, scrollable); - } - if (suggestCurrentSelection < 0) { - suggestCurrentSelection = Mth.clamp(snap.selection(), 0, Math.max(0, total - 1)); - } else { - suggestCurrentSelection = Mth.clamp(suggestCurrentSelection, 0, Math.max(0, total - 1)); - } - applySuggestionWindowState(suggestCurrentStart, suggestCurrentSelection); - - float baseFont = Math.max(10f, lastFontSizeForUi * 0.95f); - float itemH = baseFont + 6f; - - float screenW = Minecraft.getInstance().getWindow().getWidth(); - float h = itemH * visible + 6f; - float x; - float w; - float y; - - if (hasInputBox && inputBoxW > 0f) { - x = inputBoxX; - float needed = textWidthRange(snap.texts(), snap.startIndex(), visible, baseFont) + 18f; - w = Math.max(140f, Math.min(inputBoxW, Math.max(needed, 0f))); - y = inputBoxY - h - 4f; - } else { - double scale = Minecraft.getInstance().getWindow().getGuiScale(); - x = Math.max(4f, (float) (snap.x() * scale)); - float snapW = snap.w() > 0 ? (float) (snap.w() * scale) : 200f; - float needed = textWidthRange(snap.texts(), snap.startIndex(), visible, baseFont) + 18f; - w = Math.max(140f, Math.max(needed, snapW)); - y = (float) (snap.y() * scale) - h - 2f; - } - if (y < 4f) y = 4f; - if (x + w > screenW - 4f) x = screenW - w - 4f; - - // avoid zero-size windows - if (w <= 2f || h <= 2f || snap.texts().isEmpty()) { - storedScreen = null; - return; - } - - boolean hasScrollbar = total > visible; - float scrollbarReserve = hasScrollbar ? 13f : 0f; - float maxTextWidth = textWidthRange(snap.texts(), snap.startIndex(), visible, baseFont); - w = Math.max(w, maxTextWidth + 18f + scrollbarReserve); - - drawGlassPill(x, y, w, h, 7f, 0.82f, true); - - float trackW = hasScrollbar ? 4.8f : 0f; - float trackX = x + w - trackW - 5f; - float trackY = y + 3.5f; - float trackH = h - 7f; - float thumbH = hasScrollbar ? Math.max(12f, trackH * ((float) visible / (float) total)) : 0f; - float thumbY = hasScrollbar ? trackY + (trackH - thumbH) * ((float) suggestCurrentStart / (float) (Math.max(1, total - visible))) : trackY; - float rowX = x + 3f; - float rowY = y + 3f; - float rowW = Math.max(0f, (hasScrollbar ? trackX - 3f : x + w - 3f) - rowX); - float rowH = visible * itemH; - - for (int i = 0; i < visible; i++) { - int idx = suggestCurrentStart + i; - if (idx < 0 || idx >= snap.texts().size()) break; - float top = rowY + i * itemH; - boolean hoverRow = lastMouseValid && - lastMouseFx >= rowX && lastMouseFx <= rowX + rowW && - lastMouseFy >= top && lastMouseFy <= top + itemH; - if (hoverRow) { - drawLiquidHoverPill(rowX, top + 0.6f, rowW, itemH - 1.2f, 4.5f, 0.46f); - } - float textH = textHeight(getIosevkaRegular(), baseFont); - float textY = top + (itemH - textH) * 0.5f; - drawText(getIosevkaRegular(), snap.texts().get(idx), rowX + 4f, textY, baseFont, theme().textPrimary(), true); - } - - if (hasScrollbar) { - boolean hotScroll = suggestDraggingScrollbar || (lastMouseValid - && lastMouseFx >= trackX - 4f && lastMouseFx <= trackX + trackW + 4f - && lastMouseFy >= trackY - 4f && lastMouseFy <= trackY + trackH + 4f); - if (hotScroll) { - SystemCursor.set(SystemCursor.CursorType.SCROLL); - } - drawScrollbarGlass(trackX, trackY, trackW, trackH, thumbY, thumbH, hotScroll, hotScroll ? 0xB0 : 0x88, hotScroll ? 0xFF : 0xD8); - } - - suggestActive = true; - suggestX = x; - suggestY = y; - suggestW = w; - suggestH = h; - suggestItemH = itemH; - suggestRowsX = rowX; - suggestRowsY = rowY; - suggestRowsW = rowW; - suggestRowsH = rowH; - suggestStart = suggestCurrentStart; - suggestVisible = visible; - suggestTotal = total; - suggestWindow = CommandSuggestorBridge.lastWindow(); - suggestHasScrollbar = hasScrollbar; - suggestTrackX = trackX; - suggestTrackY = trackY; - suggestTrackW = trackW; - suggestTrackH = trackH; - suggestThumbH = thumbH; - if (!hasScrollbar) suggestDraggingScrollbar = false; - //DebugLog.info("[BetterChat][Suggest] box x=%.1f y=%.1f w=%.1f h=%.1f start=%d vis=%d total=%d", x, y, w, h, suggestStart, suggestVisible, suggestTotal); - storedScreen = null; - } - - private static float textWidthRange(List list, int start, int count, float fontSize) { - float max = 0f; - for (int i = 0; i < count; i++) { - int idx = start + i; - if (idx < 0 || idx >= list.size()) break; - max = Math.max(max, textWidth(getIosevkaRegular(), list.get(idx), fontSize)); - } - return max; - } - - private static String formatTimestamp(long ms, boolean withSeconds) { - LocalDateTime dt = LocalDateTime.ofInstant(Instant.ofEpochMilli(ms), ZoneId.systemDefault()); - DateTimeFormatter fmt = DateTimeFormatter.ofPattern(withSeconds ? "HH:mm:ss" : "HH:mm"); - return dt.format(fmt); - } - - private static String formatDate(long ms) { - LocalDateTime dt = LocalDateTime.ofInstant(Instant.ofEpochMilli(ms), ZoneId.systemDefault()); - return dt.format(DateTimeFormatter.ofPattern("dd.MM.yyyy")); - } - - private static HoverTip buildTimestampTooltip(long ms, boolean showDate, boolean showUnix) { - List lines = new ArrayList<>(); - LocalDateTime dt = LocalDateTime.ofInstant(Instant.ofEpochMilli(ms), ZoneId.systemDefault()); - if (showDate) { - lines.add(new ChatHoverUtil.ColoredLine(I18n.get( - "better_chat.hover.date", - dt.format(DateTimeFormatter.ofPattern("dd.MM.yyyy")) - ), 0)); - } - if (showUnix) { - lines.add(new ChatHoverUtil.ColoredLine("Unix: " + (ms / 1000L), 0xFF888888)); - } - if (lines.isEmpty()) return null; - return new HoverTip(lines, null, false, net.minecraft.world.item.ItemStack.EMPTY); - } - - private record MousePos(double rawX, double rawY, double fx, double fy) { - } - - private record InputLine(int start, int end, float width) { - } - - private record Segment(String text, Style style) { - } - - private record VisualLine(ChatLine message, int messageIndex, int messageGroup, int startChar, int endChar, List glyphs) { - } - - private record Glyph( - float x0, - float x1, - int charIndex, - int charEndExclusive, - int color, - HoverEvent hover, - String font, - String text, - Style style - ) { - } - - private record GlyphBox( - float x0, - float y0, - float x1, - float y1, - int charIndex, - int charEndExclusive, - int color, - String font, - HoverEvent hover, - String text, - Style style - ) { - } - - private record CachedLine(int startChar, int endChar, List glyphs) { - } - - private record CachedMessageLayout(float fontSize, float maxWidth, List lines) { - } - - private record FrameLine(ChatLine message, int messageIndex, int messageGroup, float y0, float y1, List glyphs) { - } - - private record MessageBubble(ChatLine message, int messageGroup, float x, float y, float w, float h, FrameLine firstLine, FrameLine lastLine) { - } - - private record MessageClipBounds(float x, float y, float w, float h) { - } - - private record FrameLayout(float x, float y, float w, float h, List lines, List bubbles) { - static FrameLayout empty() { - return new FrameLayout(0, 0, 0, 0, Collections.emptyList(), Collections.emptyList()); - } - - static FrameLayout build(List lines, float x, float y, float w, float h, float fontSize, float lineHeight, float yOffset, float timestampReserve) { - List list = new ArrayList<>(lines.size()); - float cursorY = y + BetterChatRenderer.MESSAGE_PAD_Y + yOffset; - int lastMessageGroup = Integer.MIN_VALUE; - for (int i = 0; i < lines.size(); i++) { - VisualLine vl = lines.get(i); - if (i > 0 && vl.messageGroup() != lastMessageGroup) { - cursorY += BetterChatRenderer.MESSAGE_GAP; - } - lastMessageGroup = vl.messageGroup(); - float y0 = cursorY; - float y1 = y0 + fontSize; - List boxes = new ArrayList<>(vl.glyphs().size()); - for (Glyph g : vl.glyphs()) { - boxes.add(new GlyphBox( - x + BetterChatRenderer.PADDING + BetterChatRenderer.MESSAGE_PAD_X + g.x0(), - y0, - x + BetterChatRenderer.PADDING + BetterChatRenderer.MESSAGE_PAD_X + g.x1(), - y1, - g.charIndex(), - g.charEndExclusive(), - g.color(), - g.font(), - g.hover(), - g.text(), - g.style() - )); - } - list.add(new FrameLine(vl.message(), vl.messageIndex(), vl.messageGroup(), y0, y1, boxes)); - cursorY += lineHeight; - } - return new FrameLayout(x, y, w, h, list, buildBubbles(list, x, w, timestampReserve)); - } - - private static List buildBubbles(List lines, float x, float w, float timestampReserve) { - if (lines.isEmpty()) return Collections.emptyList(); - List bubbles = new ArrayList<>(); - int start = 0; - while (start < lines.size()) { - FrameLine first = lines.get(start); - int end = start; - float maxRight = x + BetterChatRenderer.PADDING + BetterChatRenderer.MESSAGE_PAD_X; - while (end + 1 < lines.size() && lines.get(end + 1).messageGroup() == first.messageGroup()) { - end++; - } - for (int i = start; i <= end; i++) { - FrameLine line = lines.get(i); - if (!line.glyphs().isEmpty()) { - maxRight = Math.max(maxRight, line.glyphs().getLast().x1()); - } - } - FrameLine last = lines.get(end); - float bubbleX = x + BetterChatRenderer.PADDING; - float bubbleY = first.y0() - BetterChatRenderer.MESSAGE_PAD_Y; - float maxBubbleW = Math.max(32f, w - BetterChatRenderer.PADDING * 2f); - float desiredW = maxRight - bubbleX + BetterChatRenderer.MESSAGE_PAD_X + Math.max(0f, timestampReserve); - float bubbleW = Mth.clamp(desiredW, 76f, maxBubbleW); - float bubbleH = last.y1() - first.y0() + BetterChatRenderer.MESSAGE_PAD_Y * 2f; - bubbles.add(new MessageBubble(last.message(), first.messageGroup(), bubbleX, bubbleY, bubbleW, bubbleH, first, last)); - start = end + 1; - } - return bubbles; - } - - MessageClipBounds messageClipBounds() { - if (lines.isEmpty() || h <= 0f) return null; - /* - * Match the mask horizontally to the message bubbles, not to the outer draggable HUD - * bounds. Bubbles begin at x + PADDING; using the outer x left almost the whole top-left - * radius in empty padding, so the remaining visible cut looked rectangular even though - * the stencil polygon itself was rounded. - * - * The Y/H stay viewport-fixed: overscan/group expansion may move bubbles through this - * shape, but must never expand the clipping shape with them. - */ - float clipX = x + BetterChatRenderer.PADDING; - float clipW = Math.max(1f, w - BetterChatRenderer.PADDING * 2f); - return new MessageClipBounds(clipX, y, clipW, h); - } - - boolean contains(double mx, double my) { - return mx >= x && mx <= x + w && my >= y && my <= y + h; - } - - PickResult pick(double mx, double my) { - if (!contains(mx, my)) return null; - for (FrameLine line : lines) { - if (my < line.y0() || my > line.y1() + LINE_SPACING) continue; - if (line.glyphs().isEmpty()) continue; - float minX = line.glyphs().getFirst().x0(); - float maxX = line.glyphs().getLast().x1(); - float margin = 2f; - if (mx < minX - margin || mx > maxX + margin) continue; - GlyphBox closest = null; - for (GlyphBox g : line.glyphs()) { - if (mx >= g.x0() && mx <= g.x1()) { - return new PickResult(line, g); - } - if (closest == null || Math.abs(mx - g.x1()) < Math.abs(mx - closest.x1())) { - closest = g; - } - } - if (closest != null) { - return new PickResult(line, closest); - } - } - return null; - } - } - - private record PickResult(FrameLine line, GlyphBox glyph) { - } - - private record ContextMenu(boolean open, float x, float y, List entries) { - private static final float MENU_PAD_X = 8f; - private static final float MENU_PAD_Y = 7f; - private static final float MENU_RADIUS = 9f; - - static ContextMenu closed() { - return new ContextMenu(false, 0, 0, Collections.emptyList()); - } - - static ContextMenu open(float x, float y, List entries) { - return new ContextMenu(true, x, y, entries); - } - - private static float itemHeight(float fontSize) { - return Math.max(20f, fontSize + 7f); - } - - boolean contains(double mx, double my) { - if (!open) return false; - float fontSize = lastFontSizeForUi * 0.92f; - return mx >= x && mx <= x + width(fontSize) && my >= y && my <= y + height(fontSize); - } - - MenuEntry pick(double my) { - if (!open) return null; - float fontSize = lastFontSizeForUi * 0.92f; - float itemH = itemHeight(fontSize); - float cy = y + MENU_PAD_Y; - for (int i = 0; i < entries.size(); i++) { - float top = cy + i * itemH; - float bottom = top + itemH; - if (my >= top && my <= bottom) { - return entries.get(i); - } - } - return null; - } - - void render(float mouseX, float mouseY, float fontSize) { - if (!open || entries.isEmpty()) return; - float fs = Math.max(12f, fontSize * 0.92f); - float itemH = itemHeight(fs); - float w = width(fs); - float h = height(fs); - - drawGlassPill(x, y, w, h, MENU_RADIUS, 0.94f, true); - - float accentX = x + 5f; - drawRoundedRect(accentX, y + MENU_PAD_Y + 2f, 2f, h - MENU_PAD_Y * 2f - 4f, 1f, withAlpha(theme().accent(), 0x72)); - - float cy = y + MENU_PAD_Y; - for (MenuEntry entry : entries) { - boolean hover = mouseX >= x && mouseX <= x + w && mouseY >= cy && mouseY <= cy + itemH; - if (hover) { - drawRoundedRect(x + 8f, cy + 1f, w - 16f, itemH - 2f, itemH * 0.5f, withAlpha(theme().surfaceHover(), 0xAA)); - drawRoundedRectStrokeGradient( - x + 8f, cy + 1f, w - 16f, itemH - 2f, itemH * 0.5f, - 0.55f, - withAlpha(theme().accent(), 0x66), - withAlpha(theme().accentSoft(), 0x38) - ); - } - - float dot = 3.2f; - int dotColor = hover ? withAlpha(theme().accent(), 0xE0) : withAlpha(theme().textMuted(), 0x70); - drawRoundedRect(x + 14f, cy + (itemH - dot) * 0.5f, dot, dot, dot * 0.5f, dotColor); - - float textY = cy + (itemH - textHeight(getIosevkaRegular(), fs)) * 0.5f; - int textColor = hover ? theme().textPrimary() : withAlpha(theme().textPrimary(), 0xE4); - drawText(getIosevkaRegular(), entry.label(), x + 24f, textY, fs, textColor, true); - cy += itemH; - } - } - - private float width(float fontSize) { - float maxText = 0f; - for (MenuEntry e : entries) { - maxText = Math.max(maxText, textWidth(getIosevkaRegular(), e.label(), fontSize)); - } - return Math.max(168f, maxText + MENU_PAD_X * 2f + 34f); - } - - private float height(float fontSize) { - return MENU_PAD_Y * 2f + entries.size() * itemHeight(fontSize); - } - - record MenuEntry(String label, Runnable action) { - } + return BetterChatInputHandler.isInteractive(mx, my); } public record Layout(float x, float y) { } - - private record LayoutResult(List lines, int messagesSeen) { - } -} +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSearch.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSearch.java index 9aea7d9..6d7b284 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSearch.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSearch.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSegmentUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSegmentUtil.java new file mode 100644 index 0000000..40a681a --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSegmentUtil.java @@ -0,0 +1,72 @@ +/* + * 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.features.gui.chat; + +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.Style; +import net.minecraft.world.item.ItemStack; + +import dev.loki.lovisual.util.item.IllegalItemUtil; +import dev.loki.lovisual.util.item.TopEnchantUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static dev.loki.lovisual.features.theme.Theme.theme; + +/** + * Segment flattening and per-segment color resolution for the chat line layout. + */ +final class BetterChatSegmentUtil { + private BetterChatSegmentUtil() { + } + + static List flatten(Component text) { + List segments = new ArrayList<>(); + text.visit((style, string) -> { + if (string != null && !string.isEmpty()) { + segments.add(new BetterChatModel.Segment(string, style == null ? Style.EMPTY : style)); + } + return Optional.empty(); + }, Style.EMPTY); + return segments; + } + + static int resolveSegmentColor(BetterChatModel.Segment seg, Style style, HoverEvent hover) { + int color = style.getColor() != null ? (0xFF << 24) | style.getColor().getValue() : theme().textPrimary(); + if (hover instanceof HoverEvent.ShowItem(net.minecraft.world.item.ItemStackTemplate itemTemplate)) { + ItemStack item = itemTemplate.create(); + ItemStack stack = item.copy(); + + BetterChatHoverCache cache = BetterChatStoreManager.getActiveCache(); + if (cache != null) { + String keyId = BetterChatStoreManager.hoverItemKey(stack); + String itemId = net.minecraft.core.registries.BuiltInRegistries.ITEM.getKey(stack.getItem()).toString(); + ItemStack cachedStack = cache.getItemByKeyOrId(keyId, itemId); + if (!cachedStack.isEmpty()) stack = cachedStack; + } + if (IllegalItemUtil.isIllegal(stack)) { + color = IllegalItemUtil.illegalColor(); + } else if (TopEnchantUtil.hasTopEnchant(stack)) { + color = TopEnchantUtil.topColor(); + } + } + if (color == theme().textPrimary() && !(hover instanceof HoverEvent.ShowItem)) { + BetterChatHoverCache cache = BetterChatStoreManager.getActiveCache(); + if (cache != null) { + String cleaned = seg.text().replaceAll("[\\[\\]<>‚]", "").trim(); + if (!cleaned.isEmpty()) { + cache.findItemByDisplayNameWithMeta(cleaned); + } + } + } + return color; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatStore.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatStore.java index bc9ac5f..9213646 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatStore.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatStore.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatStoreManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatStoreManager.java index 67efef2..0c26de7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatStoreManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatStoreManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSuggestionRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSuggestionRenderer.java new file mode 100644 index 0000000..26c34a2 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSuggestionRenderer.java @@ -0,0 +1,192 @@ +/* + * 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.features.gui.chat; +import dev.loki.lovisual.mixins.accessors.ChatScreenAccessor; +import dev.loki.lovisual.render.helpers.SystemCursor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.util.Mth; +import java.util.List; +import static dev.loki.lovisual.features.theme.Theme.theme; +/** + * Draws the autocomplete suggestion popup above the input field each frame. + */ +final class BetterChatSuggestionRenderer { + private BetterChatSuggestionRenderer() { + } + static void renderSuggestions() { + BetterChatRenderer.suggestActive = false; + BetterChatRenderer.suggestHasScrollbar = false; + if (BetterChatRenderer.storedScreen == null) return; + EditBox field = ((ChatScreenAccessor) BetterChatRenderer.storedScreen).getChatField(); + String text = field != null ? field.getValue() : null; + if (field == null || text == null || text.isEmpty()) { + BetterChatRenderer.storedScreen = null; + BetterChatSuggestionState.resetSuggestionTracking(); + return; + } + int cursor = field.getCursorPosition(); + int selStart = BetterChatEditBoxUtil.selectionStart(field, cursor); + int selEnd = BetterChatEditBoxUtil.selectionEnd(field, cursor); + char prefix = BetterChatSuggestionState.commandPrefix(text); + if (prefix == 0) { + BetterChatRenderer.storedScreen = null; + BetterChatSuggestionState.resetSuggestionTracking(); + return; + } + boolean inputChanged = BetterChatSuggestionState.refreshSuggestionsIfNeeded(text, cursor, selStart, selEnd); + boolean windowChanged = false; + if (prefix == '/') { + windowChanged = CommandSuggestorBridge.peekWindow(BetterChatRenderer.storedScreen) != CommandSuggestorBridge.lastWindow(); + } + if (inputChanged || windowChanged || BetterChatRenderer.lastSnapshot == null) { + if (prefix == '@') { + BetterChatRenderer.lastSnapshot = BetterChatSuggestionState.buildCustomSnapshot(text, cursor); + } else { + BetterChatRenderer.lastSnapshot = CommandSuggestorBridge.snapshot(BetterChatRenderer.storedScreen); + } + } + CommandSuggestorBridge.SuggestionSnapshot snap = BetterChatRenderer.lastSnapshot; + if (snap == null) { + BetterChatRenderer.storedScreen = null; + BetterChatSuggestionState.resetSuggestionTracking(); + return; + } + if (prefix == '@') { + BetterChatRenderer.suggestWindow = null; + } + int hash = snap.texts().hashCode() ^ snap.selection() ^ snap.startIndex(); + boolean snapshotChanged = hash != BetterChatRenderer.lastSuggestionHash; + if (snapshotChanged) { + BetterChatRenderer.lastSuggestionHash = hash; + } + BetterChatRenderer.suggestEntries = snap.suggestions(); + int total = snap.texts().size(); + int visible = Math.min(5, Math.max(1, total - snap.startIndex())); + int scrollable = Math.max(0, total - visible); + if (snapshotChanged) { + BetterChatRenderer.suggestCurrentStart = Mth.clamp(snap.startIndex(), 0, scrollable); + BetterChatRenderer.suggestCurrentSelection = Mth.clamp(snap.selection(), 0, Math.max(0, total - 1)); + } + if (BetterChatRenderer.suggestCurrentStart < 0) { + BetterChatRenderer.suggestCurrentStart = Mth.clamp(snap.startIndex(), 0, scrollable); + } else { + BetterChatRenderer.suggestCurrentStart = Mth.clamp(BetterChatRenderer.suggestCurrentStart, 0, scrollable); + } + if (BetterChatRenderer.suggestCurrentSelection < 0) { + BetterChatRenderer.suggestCurrentSelection = Mth.clamp(snap.selection(), 0, Math.max(0, total - 1)); + } else { + BetterChatRenderer.suggestCurrentSelection = Mth.clamp(BetterChatRenderer.suggestCurrentSelection, 0, Math.max(0, total - 1)); + } + BetterChatSuggestionState.applySuggestionWindowState(BetterChatRenderer.suggestCurrentStart, BetterChatRenderer.suggestCurrentSelection); + float baseFont = Math.max(10f, BetterChatRenderer.lastFontSizeForUi * 0.95f); + float itemH = baseFont + 6f; + ScreenRect rect = computeBox(snap, baseFont, visible, itemH); + float x = rect.x; + float w = rect.w; + float h = rect.h; + float y = rect.y; + if (w <= 2f || h <= 2f || snap.texts().isEmpty()) { + BetterChatRenderer.storedScreen = null; + return; + } + boolean hasScrollbar = total > visible; + float scrollbarReserve = hasScrollbar ? 13f : 0f; + float maxTextWidth = textWidthRange(snap.texts(), snap.startIndex(), visible, baseFont); + w = Math.max(w, maxTextWidth + 18f + scrollbarReserve); + BetterChatDrawUtil.drawGlassPill(x, y, w, h, 7f, 0.82f, true); + float trackW = hasScrollbar ? 4.8f : 0f; + float trackX = x + w - trackW - 5f; + float trackY = y + 3.5f; + float trackH = h - 7f; + float thumbH = hasScrollbar ? Math.max(12f, trackH * ((float) visible / (float) total)) : 0f; + float thumbY = hasScrollbar ? trackY + (trackH - thumbH) * ((float) BetterChatRenderer.suggestCurrentStart / (float) (Math.max(1, total - visible))) : trackY; + float rowX = x + 3f; + float rowY = y + 3f; + float rowW = Math.max(0f, (hasScrollbar ? trackX - 3f : x + w - 3f) - rowX); + float rowH = visible * itemH; + for (int i = 0; i < visible; i++) { + int idx = BetterChatRenderer.suggestCurrentStart + i; + if (idx < 0 || idx >= snap.texts().size()) break; + float top = rowY + i * itemH; + boolean hoverRow = BetterChatRenderer.lastMouseValid && + BetterChatRenderer.lastMouseFx >= rowX && BetterChatRenderer.lastMouseFx <= rowX + rowW && + BetterChatRenderer.lastMouseFy >= top && BetterChatRenderer.lastMouseFy <= top + itemH; + if (hoverRow) { + BetterChatDrawUtil.drawLiquidHoverPill(rowX, top + 0.6f, rowW, itemH - 1.2f, 4.5f, 0.46f); + } + float textHh = BetterChatFontUtil.textHeight(BetterChatFontUtil.getIosevkaRegular(), baseFont); + float textY = top + (itemH - textHh) * 0.5f; + BetterChatFontUtil.drawText(BetterChatFontUtil.getIosevkaRegular(), snap.texts().get(idx), rowX + 4f, textY, baseFont, theme().textPrimary(), true); + } + if (hasScrollbar) { + boolean hotScroll = BetterChatRenderer.suggestDraggingScrollbar || (BetterChatRenderer.lastMouseValid + && BetterChatRenderer.lastMouseFx >= trackX - 4f && BetterChatRenderer.lastMouseFx <= trackX + trackW + 4f + && BetterChatRenderer.lastMouseFy >= trackY - 4f && BetterChatRenderer.lastMouseFy <= trackY + trackH + 4f); + if (hotScroll) { + SystemCursor.set(SystemCursor.CursorType.SCROLL); + } + BetterChatDrawUtil.drawScrollbarGlass(trackX, trackY, trackW, trackH, thumbY, thumbH, hotScroll, hotScroll ? 0xB0 : 0x88, hotScroll ? 0xFF : 0xD8); + } + BetterChatRenderer.suggestActive = true; + BetterChatRenderer.suggestX = x; + BetterChatRenderer.suggestY = y; + BetterChatRenderer.suggestW = w; + BetterChatRenderer.suggestH = h; + BetterChatRenderer.suggestItemH = itemH; + BetterChatRenderer.suggestRowsX = rowX; + BetterChatRenderer.suggestRowsY = rowY; + BetterChatRenderer.suggestRowsW = rowW; + BetterChatRenderer.suggestRowsH = rowH; + BetterChatRenderer.suggestStart = BetterChatRenderer.suggestCurrentStart; + BetterChatRenderer.suggestVisible = visible; + BetterChatRenderer.suggestTotal = total; + BetterChatRenderer.suggestWindow = CommandSuggestorBridge.lastWindow(); + BetterChatRenderer.suggestHasScrollbar = hasScrollbar; + BetterChatRenderer.suggestTrackX = trackX; + BetterChatRenderer.suggestTrackY = trackY; + BetterChatRenderer.suggestTrackW = trackW; + BetterChatRenderer.suggestTrackH = trackH; + BetterChatRenderer.suggestThumbH = thumbH; + if (!hasScrollbar) BetterChatRenderer.suggestDraggingScrollbar = false; + BetterChatRenderer.storedScreen = null; + } + private static ScreenRect computeBox(CommandSuggestorBridge.SuggestionSnapshot snap, float baseFont, int visible, float itemH) { + float screenW = Minecraft.getInstance().getWindow().getWidth(); + float h = itemH * visible + 6f; + float x; + float w; + float y; + if (BetterChatRenderer.hasInputBox && BetterChatRenderer.inputBoxW > 0f) { + x = BetterChatRenderer.inputBoxX; + float needed = textWidthRange(snap.texts(), snap.startIndex(), visible, baseFont) + 18f; + w = Math.max(140f, Math.min(BetterChatRenderer.inputBoxW, Math.max(needed, 0f))); + y = BetterChatRenderer.inputBoxY - h - 4f; + } else { + double scale = Minecraft.getInstance().getWindow().getGuiScale(); + x = Math.max(4f, (float) (snap.x() * scale)); + float snapW = snap.w() > 0 ? (float) (snap.w() * scale) : 200f; + float needed = textWidthRange(snap.texts(), snap.startIndex(), visible, baseFont) + 18f; + w = Math.max(140f, Math.max(needed, snapW)); + y = (float) (snap.y() * scale) - h - 2f; + } + if (y < 4f) y = 4f; + if (x + w > screenW - 4f) x = screenW - w - 4f; + return new ScreenRect(x, y, w, h); + } + private static float textWidthRange(List list, int start, int count, float fontSize) { + float max = 0f; + for (int i = 0; i < count; i++) { + int idx = start + i; + if (idx < 0 || idx >= list.size()) break; + max = Math.max(max, BetterChatFontUtil.textWidth(BetterChatFontUtil.getIosevkaRegular(), list.get(idx), fontSize)); + } + return max; + } + private record ScreenRect(float x, float y, float w, float h) { + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSuggestionState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSuggestionState.java new file mode 100644 index 0000000..1f3bd33 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatSuggestionState.java @@ -0,0 +1,186 @@ +/* + * 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.features.gui.chat; + +import dev.loki.lovisual.features.command.CommandManager; +import dev.loki.lovisual.mixins.accessors.ChatScreenAccessor; +import dev.loki.lovisual.mixins.accessors.SuggestionWindowAccessor; +import dev.loki.lovisual.util.screen.ClientScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.screens.ChatScreen; +import net.minecraft.util.Mth; +import org.lwjgl.glfw.GLFW; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.lwjgl.glfw.GLFW.GLFW_PRESS; +import static org.lwjgl.glfw.GLFW.glfwGetKey; + +/** + * Autocomplete suggestion window state: hotkey, snapshot capture, window dragging and hit-test. + * Rendering lives in {@link BetterChatSuggestionRenderer}. + */ +final class BetterChatSuggestionState { + private BetterChatSuggestionState() { + } + + static boolean isInsideSuggestRows(double mx, double my) { + if (!BetterChatRenderer.suggestActive) return false; + return mx >= BetterChatRenderer.suggestRowsX && mx <= BetterChatRenderer.suggestRowsX + BetterChatRenderer.suggestRowsW + && my >= BetterChatRenderer.suggestRowsY && my <= BetterChatRenderer.suggestRowsY + BetterChatRenderer.suggestRowsH; + } + + static boolean isInsideSuggestRows(double mx, double my, double rawX, double rawY) { + return isInsideSuggestRows(mx, my) || isInsideSuggestRows(rawX, rawY); + } + + static boolean isInsideSuggestWindow(double mx, double my) { + if (!BetterChatRenderer.suggestActive) return false; + return mx >= BetterChatRenderer.suggestX && mx <= BetterChatRenderer.suggestX + BetterChatRenderer.suggestW + && my >= BetterChatRenderer.suggestY && my <= BetterChatRenderer.suggestY + BetterChatRenderer.suggestH; + } + + static boolean isInsideSuggestWindow(double mx, double my, double rawX, double rawY) { + return isInsideSuggestWindow(mx, my) || isInsideSuggestWindow(rawX, rawY); + } + + static boolean isInsideSuggestScrollbar(double mx, double my) { + if (!BetterChatRenderer.suggestActive || !BetterChatRenderer.suggestHasScrollbar) return false; + float hitPad = 4f; + return mx >= BetterChatRenderer.suggestTrackX - hitPad && + mx <= BetterChatRenderer.suggestTrackX + BetterChatRenderer.suggestTrackW + hitPad && + my >= BetterChatRenderer.suggestTrackY - hitPad && + my <= BetterChatRenderer.suggestTrackY + BetterChatRenderer.suggestTrackH + hitPad; + } + + static void resetSuggestionTracking() { + BetterChatRenderer.lastSuggestInput = ""; + BetterChatRenderer.lastSuggestCursor = -1; + BetterChatRenderer.lastSuggestSelStart = -1; + BetterChatRenderer.lastSuggestSelEnd = -1; + BetterChatRenderer.lastSnapshot = null; + BetterChatRenderer.lastSuggestionHash = 0; + BetterChatRenderer.suggestWindow = null; + BetterChatRenderer.suggestEntries = Collections.emptyList(); + BetterChatRenderer.suggestRowsX = BetterChatRenderer.suggestRowsY = BetterChatRenderer.suggestRowsW = BetterChatRenderer.suggestRowsH = 0f; + BetterChatRenderer.suggestCurrentStart = -1; + BetterChatRenderer.suggestCurrentSelection = -1; + } + + static char commandPrefix(String text) { + if (text == null) return 0; + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (Character.isWhitespace(c)) continue; + if (c == '/' || c == '@') return c; + return 0; + } + return 0; + } + + static boolean refreshSuggestionsIfNeeded(String text, int cursor, int selStart, int selEnd) { + if (text.equals(BetterChatRenderer.lastSuggestInput) + && cursor == BetterChatRenderer.lastSuggestCursor + && selStart == BetterChatRenderer.lastSuggestSelStart + && selEnd == BetterChatRenderer.lastSuggestSelEnd) { + return false; + } + BetterChatRenderer.lastSuggestInput = text; + BetterChatRenderer.lastSuggestCursor = cursor; + BetterChatRenderer.lastSuggestSelStart = selStart; + BetterChatRenderer.lastSuggestSelEnd = selEnd; + return true; + } + + static void applySuggestionWindowState(int start, int selection) { + if (BetterChatRenderer.suggestWindow == null) return; + SuggestionWindowAccessor acc = (SuggestionWindowAccessor) BetterChatRenderer.suggestWindow; + acc.setLoVisual$inWindowIndex(Math.max(0, start)); + if (selection >= 0) { + acc.setLoVisual$selection(selection); + } + } + + static void applySuggestion(int idx) { + Minecraft mc = Minecraft.getInstance(); + if (!(ClientScreen.current() instanceof ChatScreen chatScreen)) return; + EditBox field = ((ChatScreenAccessor) chatScreen).getChatField(); + if (field == null) return; + + if (BetterChatRenderer.suggestWindow != null) { + SuggestionWindowAccessor acc = (SuggestionWindowAccessor) BetterChatRenderer.suggestWindow; + acc.setLoVisual$selection(idx); + } + + if (idx < 0 || idx >= BetterChatRenderer.suggestEntries.size()) return; + com.mojang.brigadier.suggestion.Suggestion suggestion = BetterChatRenderer.suggestEntries.get(idx); + String current = field.getValue(); + try { + String applied = suggestion.apply(current); + field.setValue(applied); + BetterChatEditBoxUtil.setCursorSafe(field, applied.length()); + BetterChatRenderer.suggestCurrentSelection = idx; + applySuggestionWindowState(BetterChatRenderer.suggestCurrentStart, BetterChatRenderer.suggestCurrentSelection); + } catch (Exception ignored) { + } + } + + static void scrollSuggestToPosition(double my) { + if (!BetterChatRenderer.suggestHasScrollbar || BetterChatRenderer.suggestVisible <= 0 || BetterChatRenderer.suggestTotal <= BetterChatRenderer.suggestVisible) + return; + float trackSpan = BetterChatRenderer.suggestTrackH - BetterChatRenderer.suggestThumbH; + if (trackSpan <= 0f) return; + float rel = (float) (my - BetterChatRenderer.suggestTrackY - BetterChatRenderer.suggestThumbH * 0.5f); + float t = Mth.clamp(rel / trackSpan, 0f, 1f); + int scrollable = Math.max(0, BetterChatRenderer.suggestTotal - BetterChatRenderer.suggestVisible); + int targetStart = Math.round(t * scrollable); + BetterChatRenderer.suggestCurrentStart = Mth.clamp(targetStart, 0, scrollable); + applySuggestionWindowState(BetterChatRenderer.suggestCurrentStart, BetterChatRenderer.suggestCurrentSelection); + } + + static CommandSuggestorBridge.SuggestionSnapshot buildCustomSnapshot(String text, int cursor) { + List suggestions = CommandManager.suggest(text, cursor); + if (suggestions == null || suggestions.isEmpty()) return null; + List texts = new ArrayList<>(suggestions.size()); + for (com.mojang.brigadier.suggestion.Suggestion s : suggestions) { + texts.add(s.getText()); + } + int selection = 0; + int start = 0; + int visible = Math.min(5, Math.max(1, suggestions.size())); + return new CommandSuggestorBridge.SuggestionSnapshot(0, 0, 0, 0, texts, suggestions, selection, start, visible); + } + + static void updateSearchHotkey(Minecraft mc, boolean chatOpen) { + if (!chatOpen || mc == null || mc.getWindow() == null) { + BetterChatRenderer.searchHotkeyDown = false; + return; + } + long handle = mc.getWindow().handle(); + boolean ctrl = + glfwGetKey(handle, GLFW.GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || + glfwGetKey(handle, GLFW.GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS; + boolean f = glfwGetKey(handle, GLFW.GLFW_KEY_F) == GLFW_PRESS; + boolean down = ctrl && f; + if (down && !BetterChatRenderer.searchHotkeyDown) { + toggleSearchMode(); + } + BetterChatRenderer.searchHotkeyDown = down; + } + + static void toggleSearchMode() { + if (BetterChatSearch.isActive() || BetterChatSearch.hasQuery()) { + BetterChatSearch.deactivate(); + } else { + BetterChatSearch.setActive(true); + } + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatTooltipRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatTooltipRenderer.java new file mode 100644 index 0000000..13fd7c9 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatTooltipRenderer.java @@ -0,0 +1,163 @@ +/* + * 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.features.gui.chat; + +import dev.loki.lovisual.features.gui.hud.nondraggable.impl.BetterTooltips; +import dev.loki.lovisual.util.text.ChatNameUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.screens.inventory.tooltip.DefaultTooltipPositioner; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextColor; +import net.minecraft.util.FormattedCharSequence; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static dev.loki.lovisual.features.gui.chat.ChatHoverUtil.HoverTip; +import static dev.loki.lovisual.features.theme.Theme.theme; + +/** + * Tooltip capture/render, timestamp formatting and post-pick hover inference. + */ +final class BetterChatTooltipRenderer { + private BetterChatTooltipRenderer() { + } + + static String formatTimestamp(long ms, boolean withSeconds) { + LocalDateTime dt = LocalDateTime.ofInstant(Instant.ofEpochMilli(ms), ZoneId.systemDefault()); + DateTimeFormatter fmt = DateTimeFormatter.ofPattern(withSeconds ? "HH:mm:ss" : "HH:mm"); + return dt.format(fmt); + } + + static String formatDate(long ms) { + LocalDateTime dt = LocalDateTime.ofInstant(Instant.ofEpochMilli(ms), ZoneId.systemDefault()); + return dt.format(DateTimeFormatter.ofPattern("dd.MM.yyyy")); + } + + static HoverTip buildTimestampTooltip(long ms, boolean showDate, boolean showUnix) { + List lines = new ArrayList<>(); + LocalDateTime dt = LocalDateTime.ofInstant(Instant.ofEpochMilli(ms), ZoneId.systemDefault()); + if (showDate) { + lines.add(new ChatHoverUtil.ColoredLine(net.minecraft.client.resources.language.I18n.get( + "better_chat.hover.date", + dt.format(DateTimeFormatter.ofPattern("dd.MM.yyyy")) + ), 0)); + } + if (showUnix) { + lines.add(new ChatHoverUtil.ColoredLine("Unix: " + (ms / 1000L), 0xFF888888)); + } + if (lines.isEmpty()) return null; + return new HoverTip(lines, null, false, net.minecraft.world.item.ItemStack.EMPTY); + } + + static void captureTooltip(HoverTip tip, float x, float y, GuiGraphicsExtractor ctx) { + if (tip == null || ctx == null) return; + Minecraft mc = Minecraft.getInstance(); + if (mc == null || mc.getWindow() == null) return; + float scale = (float) mc.getWindow().getGuiScale(); + int mx = Math.round(x / scale); + int my = Math.round(y / scale); + List lines = buildOrderedTooltipLines(tip); + if (lines.isEmpty()) return; + + BetterTooltips.setTooltipScaleOverride(0.8f); + if (tip.item() != null && !tip.item().isEmpty()) { + BetterTooltips.captureItemTooltipOrdered(lines, DefaultTooltipPositioner.INSTANCE, mx, my, tip.item(), ctx); + } else { + BetterTooltips.captureTooltipOrdered(lines, DefaultTooltipPositioner.INSTANCE, mx, my); + } + BetterChatRenderer.tooltipCaptured = true; + } + + static void renderCapturedTooltip(GuiGraphicsExtractor ctx) { + if (!BetterChatRenderer.tooltipCaptured) return; + BetterTooltips.renderTooltipWithContext(ctx); + BetterTooltips.resetTooltipScaleOverride(); + BetterChatRenderer.tooltipCaptured = false; + } + + private static List buildOrderedTooltipLines(HoverTip tip) { + if (tip == null || tip.lines() == null || tip.lines().isEmpty()) return Collections.emptyList(); + List out = new ArrayList<>(tip.lines().size()); + for (ChatHoverUtil.ColoredLine line : tip.lines()) { + int argb = line.color() != 0 ? line.color() : theme().textPrimary(); + int rgb = argb & 0x00FFFFFF; + Component text = Component.literal(line.text()).setStyle(Style.EMPTY.withColor(TextColor.fromRgb(rgb))); + out.add(text.getVisualOrderText()); + } + return out; + } + + /** + * Mirror of the original post-pick hover/suggest-inference block (lines 466-518). + */ + static void resolveHover(BetterChatModel.PickResult hover, Minecraft mc) { + boolean overSuggestWindow = BetterChatSuggestionState.isInsideSuggestWindow( + BetterChatRenderer.lastMouseFx, BetterChatRenderer.lastMouseFy, + BetterChatRenderer.lastMouseFx, BetterChatRenderer.lastMouseFy); + if (overSuggestWindow && BetterChatRenderer.lastHoverWasOutsideSuggest) { + BetterChatRenderer.lastHoverWasOutsideSuggest = false; + } else if (!overSuggestWindow && !BetterChatRenderer.lastHoverWasOutsideSuggest) { + BetterChatRenderer.lastHoverWasOutsideSuggest = true; + } + + HoverTip hoverTip = BetterChatRenderer.ctxHoverTip; + if (hover != null && hover.glyph().hover() != null && !overSuggestWindow) { + hoverTip = ChatHoverUtil.fromHover(hover.glyph().hover(), mc); + if (hoverTip != null) BetterChatRenderer.hoverEntityUuid = hoverTip.uuid(); + } + + if (BetterChatRenderer.selecting) { + hoverTip = null; + BetterChatRenderer.hoverEntityUuid = null; + } + + if (!BetterChatRenderer.selecting && !overSuggestWindow && hoverTip == null && hover != null) { + String raw = hover.line().message().text().getString(); + String word = BetterChatEditBoxUtil.wordAt(raw, hover.glyph().charIndex()); + if (!word.isEmpty()) { + boolean looksLikeItem = (word.startsWith("[") && word.contains("]")); + HoverTip cached = ChatHoverUtil.inferFromDisplay(word, looksLikeItem, mc); + if (cached != null) { + hoverTip = cached; + BetterChatRenderer.hoverEntityUuid = cached.uuid(); + } + } + if (hoverTip == null) { + List nickCandidates = ChatNameUtil.extractNicks(raw); + String normalized = ChatNameUtil.normalizeNickCandidate(word); + String targetNick = null; + if (!normalized.isEmpty() + && ChatNameUtil.isNickLike(normalized) + && nickCandidates.stream().anyMatch(n -> n.equalsIgnoreCase(normalized))) { + targetNick = normalized; + } else if (nickCandidates.size() == 1) { + targetNick = nickCandidates.getFirst(); + } + if (targetNick != null) { + hoverTip = ChatHoverUtil.inferFromNick(targetNick, mc); + if (hoverTip != null) BetterChatRenderer.hoverEntityUuid = hoverTip.uuid(); + } + } + } + + if (overSuggestWindow || BetterChatRenderer.contextMenu.open()) { + hoverTip = null; + BetterChatRenderer.hoverEntityUuid = null; + } + + BetterChatRenderer.ctxHoverTip = hoverTip; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatViewport.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatViewport.java new file mode 100644 index 0000000..ceee67f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/BetterChatViewport.java @@ -0,0 +1,190 @@ +/* + * 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.features.gui.chat; + +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import net.minecraft.util.Mth; + +import java.util.Collections; +import java.util.List; + +/** + * Second render phase: turns the laid-out visual lines into a viewport + frame layout + * (bubbles/lines) and animates smooth scrolling. Writes the resulting {@link BetterChatFrameModel.FrameLayout} + * back onto the facade and populates the per-frame sizing context used by every later phase. + */ +final class BetterChatViewport { + private BetterChatViewport() { + } + + static int countMessageGroups(List lines, int maxLines) { + if (lines == null || lines.isEmpty() || maxLines <= 0) return 0; + int groups = 0; + int lastMessage = Integer.MIN_VALUE; + int limit = Math.min(lines.size(), maxLines); + for (int i = 0; i < limit; i++) { + int messageGroup = lines.get(i).messageGroup(); + if (messageGroup != lastMessage) { + groups++; + lastMessage = messageGroup; + } + } + return groups; + } + + static float messageStackHeight(int lineCount, int groupCount, float lineHeight) { + if (lineCount <= 0) return 0f; + return lineCount * lineHeight + - BetterChatRenderer.LINE_SPACING + + Math.max(0, groupCount - 1) * BetterChatRenderer.MESSAGE_GAP + + BetterChatRenderer.MESSAGE_PAD_Y * 2f; + } + + static int expandStartToGroup(List lines, int start) { + if (lines == null || lines.isEmpty()) return 0; + int safe = Mth.clamp(start, 0, lines.size()); + if (safe <= 0 || safe >= lines.size()) return safe; + int group = lines.get(safe).messageGroup(); + while (safe > 0 && lines.get(safe - 1).messageGroup() == group) { + safe--; + } + return safe; + } + + static int expandEndToGroup(List lines, int end) { + if (lines == null || lines.isEmpty()) return 0; + int safe = Mth.clamp(end, 0, lines.size()); + if (safe <= 0 || safe >= lines.size()) return safe; + int group = lines.get(safe - 1).messageGroup(); + while (safe < lines.size() && lines.get(safe).messageGroup() == group) { + safe++; + } + return safe; + } + + static void composeFrame() { + List allLines = BetterChatRenderer.ctxAllLines; + BetterChatModel.LayoutResult layoutResult = new BetterChatModel.LayoutResult(allLines, BetterChatRenderer.ctxMessagesSeen); + List messages = BetterChatRenderer.lastMessages; + int totalMessages = BetterChatRenderer.ctxTotalMessages; + int visibleLimit = BetterChatRenderer.ctxVisibleLimit; + boolean autoFollow = BetterChatRenderer.ctxAutoFollow; + boolean showTs = BetterChatRenderer.ctxShowTs; + float tsWidth = BetterChatRenderer.ctxTsWidth; + float width = BetterChatRenderer.ctxWidth; + float fontSize = BetterChatRenderer.lastFontSizeForUi; + float baseX = BetterChatRenderer.ctxBaseX; + float baseY = BetterChatRenderer.ctxBaseY; + boolean chatOpen = BetterChatRenderer.ctxChatOpen; + long perfT1 = BetterChatRenderer.ctxPerfT1; + long perfT0 = BetterChatRenderer.ctxPerfT0; + + float lineHeight = fontSize + BetterChatRenderer.LINE_SPACING; + float boxHeight; + List visible; + int localStart; + float lineYOffset = 0f; + int targetVisibleForBox = visibleLimit; + if (allLines.isEmpty()) { + BetterChatRenderer.maxScrollLines = 0; + BetterChatRenderer.sbTotalLines = 0; + BetterChatRenderer.sbVisibleLines = 0; + boxHeight = 0f; + visible = Collections.emptyList(); + BetterChatRenderer.smoothScrollOffsetLines = 0f; + } else { + int lineCount = allLines.size(); + int observedMessages = Math.max(1, layoutResult.messagesSeen()); + float avgLinesPerMsg = Math.max(1f, (float) lineCount / (float) observedMessages); + int estimatedTotalLines = Math.max(lineCount, (int) Math.ceil(avgLinesPerMsg * totalMessages)); + BetterChatRenderer.maxScrollLines = Math.max(0, estimatedTotalLines - visibleLimit); + BetterChatRenderer.scrollOffsetLines = Mth.clamp(BetterChatRenderer.scrollOffsetLines, 0, BetterChatRenderer.maxScrollLines); + if (autoFollow) { + BetterChatRenderer.smoothScrollOffsetLines = 0f; + } else { + float s = Mth.clamp(BetterChatRenderer.smoothScrollOffsetLines, 0f, BetterChatRenderer.maxScrollLines); + s = AnimationUtility.approach(s, BetterChatRenderer.scrollOffsetLines, BetterChatRenderer.draggingScrollbar ? 0.55f : 0.22f); + s = AnimationUtility.snap(s, BetterChatRenderer.scrollOffsetLines, BetterChatRenderer.draggingScrollbar ? 0.01f : 0.035f); + BetterChatRenderer.smoothScrollOffsetLines = s; + } + + int lastMsgIndex = messages.isEmpty() ? -1 : messages.size() - 1; + int linesInLastMsg = 0; + if (lastMsgIndex >= 0) { + for (int i = lineCount - 1; i >= 0; i--) { + if (allLines.get(i).messageIndex() == lastMsgIndex) { + linesInLastMsg++; + } else if (linesInLastMsg > 0) { + break; + } + } + } + int targetVisible = autoFollow ? Math.max(visibleLimit, linesInLastMsg) : visibleLimit; + targetVisibleForBox = Math.max(1, Math.min(targetVisible, lineCount)); + + float globalStartFloat = autoFollow + ? Math.max(0f, lineCount - targetVisible) + : Math.max(0f, lineCount - visibleLimit - BetterChatRenderer.smoothScrollOffsetLines); + int globalStart = Math.max(0, (int) Math.floor(globalStartFloat) - (autoFollow ? 0 : 1)); + int viewportStart = autoFollow + ? Math.max(0, lineCount - targetVisibleForBox) + : Mth.clamp((int) Math.floor(globalStartFloat), 0, Math.max(0, lineCount - 1)); + int viewportEnd = Math.min(lineCount, viewportStart + targetVisibleForBox); + int groupsForBox = countMessageGroups(allLines.subList(viewportStart, viewportEnd), targetVisibleForBox); + + localStart = Math.max(0, Math.min(globalStart, Math.max(0, lineCount - 1))); + int endLine = Math.min(lineCount, localStart + targetVisibleForBox + (autoFollow ? 0 : 3)); + localStart = expandStartToGroup(allLines, localStart); + endLine = expandEndToGroup(allLines, endLine); + visible = allLines.subList(localStart, endLine); + BetterChatRenderer.sbTotalLines = lineCount; + BetterChatRenderer.sbVisibleLines = targetVisibleForBox; + + boxHeight = messageStackHeight(targetVisibleForBox, groupsForBox, lineHeight); + if (autoFollow) { + int actualGroups = countMessageGroups(visible, visible.size()); + float actualHeight = messageStackHeight(visible.size(), actualGroups, lineHeight); + lineYOffset = boxHeight - actualHeight; + } else { + lineYOffset = (localStart - globalStartFloat) * lineHeight; + } + } + float stableBoxHeight = messageStackHeight(visibleLimit, visibleLimit, lineHeight); + float fixedInputY = baseY + stableBoxHeight + BetterChatRenderer.MESSAGE_INPUT_GAP; + float frameY = baseY + stableBoxHeight - boxHeight; + float visualTop = Math.min(baseY, frameY); + float visualBottom = chatOpen ? fixedInputY + Math.max(36f, fontSize + 16f) : frameY + boxHeight; + float totalHeight = Math.max(0f, visualBottom - visualTop); + BetterChatRenderer.lastRenderWidth = width; + BetterChatRenderer.lastRenderHeight = totalHeight; + + long perfT2Start = System.nanoTime(); + BetterChatRenderer.frame = BetterChatFrameModel.FrameLayout.build(visible, baseX, frameY, width, boxHeight, fontSize, lineHeight, lineYOffset, showTs ? tsWidth : 0f); + long perfT2 = System.nanoTime(); + BetterChatRenderer.debugPerfAccumLayoutNs += (perfT1 - perfT0); + BetterChatRenderer.debugPerfAccumBuildNs += (perfT2 - perfT2Start); + BetterChatRenderer.debugPerfAccumFrames++; + if (BetterChatRenderer.debugPerfWindowStartNs == 0L) BetterChatRenderer.debugPerfWindowStartNs = perfT2; + long windowNs = perfT2 - BetterChatRenderer.debugPerfWindowStartNs; + if (windowNs >= 1_000_000_000L && BetterChatRenderer.debugPerfAccumFrames > 0 && chatOpen) { + BetterChatRenderer.debugPerfWindowStartNs = perfT2; + BetterChatRenderer.debugPerfAccumLayoutNs = 0L; + BetterChatRenderer.debugPerfAccumBuildNs = 0L; + BetterChatRenderer.debugPerfAccumFrames = 0; + } + + BetterChatRenderer.ctxLineHeight = lineHeight; + BetterChatRenderer.ctxBoxHeight = boxHeight; + BetterChatRenderer.ctxVisible = visible; + BetterChatRenderer.ctxLineYOffset = lineYOffset; + BetterChatRenderer.ctxTargetVisible = targetVisibleForBox; + BetterChatRenderer.ctxStableBoxHeight = stableBoxHeight; + BetterChatRenderer.ctxFixedInputY = fixedInputY; + BetterChatRenderer.ctxFrameY = frameY; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/ChatHoverUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/ChatHoverUtil.java index 935af13..b6c05c8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/ChatHoverUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/ChatHoverUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/ChatLine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/ChatLine.java index 8859d79..1535f80 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/ChatLine.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/ChatLine.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/CommandSuggestorBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/CommandSuggestorBridge.java index 662c990..8a69b5e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/CommandSuggestorBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/chat/CommandSuggestorBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -43,7 +43,7 @@ public enum CommandSuggestorBridge { Object suggestor = findSuggestor(screen); if (suggestor == null) return null; CommandSuggestions s = (CommandSuggestions) suggestor; - return ((ChatInputSuggestorAccessor) s).getCombatant$window(); + return ((ChatInputSuggestorAccessor) s).getLoVisual$window(); } catch (Throwable ignored) { return null; } @@ -57,7 +57,7 @@ public enum CommandSuggestorBridge { return null; } CommandSuggestions s = (CommandSuggestions) suggestor; - CommandSuggestions.SuggestionsList window = ((ChatInputSuggestorAccessor) s).getCombatant$window(); + CommandSuggestions.SuggestionsList window = ((ChatInputSuggestorAccessor) s).getLoVisual$window(); CommandContext ctx = commandContext(screen); List manual = buildTellLikeSuggestions(ctx); @@ -78,17 +78,17 @@ public enum CommandSuggestorBridge { } SuggestionWindowAccessor acc = (SuggestionWindowAccessor) window; - Rect2i area = acc.getCombatant$area(); + Rect2i area = acc.getLoVisual$area(); int x = area.getX(); int y = area.getY(); int w = area.getWidth(); int h = area.getHeight(); - List suggestions = collectSuggestions(acc.getCombatant$suggestions(), currentToken(screen), isCommand(screen)); + List suggestions = collectSuggestions(acc.getLoVisual$suggestions(), currentToken(screen), isCommand(screen)); suggestions = mergeSuggestions(suggestions, manual); List texts = collectTexts(suggestions); - int selection = clamp(acc.getCombatant$selection(), suggestions.size()); - int start = clamp(acc.getCombatant$inWindowIndex(), suggestions.size()); + int selection = clamp(acc.getLoVisual$selection(), suggestions.size()); + int start = clamp(acc.getLoVisual$inWindowIndex(), suggestions.size()); int visible = Math.max(1, h / 12); note("ok"); @@ -109,7 +109,7 @@ public enum CommandSuggestorBridge { private static Object findSuggestor(ChatScreen screen) { if (screen instanceof ChatScreenSuggestorAccessor acc) { - return acc.getCombatant$suggestor(); + return acc.getLoVisual$suggestor(); } return null; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiDrawHelpers.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiDrawHelpers.java new file mode 100644 index 0000000..0af903c --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiDrawHelpers.java @@ -0,0 +1,182 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; + +final class ClickGuiDrawHelpers { + + private ClickGuiDrawHelpers() { + } + static int mixColor(int from, int to, float t) { + t = Math.max(0f, Math.min(1f, t)); + int a = (int) (((from >>> 24) & 0xFF) * (1 - t) + ((to >>> 24) & 0xFF) * t); + int r = (int) (((from >>> 16) & 0xFF) * (1 - t) + ((to >>> 16) & 0xFF) * t); + int g = (int) (((from >>> 8) & 0xFF) * (1 - t) + ((to >>> 8) & 0xFF) * t); + int b = (int) (((from) & 0xFF) * (1 - t) + ((to) & 0xFF) * t); + return (a << 24) | (r << 16) | (g << 8) | b; + } + static int scaleAlpha(int color, float factor) { + int a = (color >>> 24) & 0xFF; + int na = (int) (a * Math.max(0f, Math.min(1f, factor))); + return (color & 0x00FFFFFF) | (na << 24); + } + static int withAlpha(int color, int alpha) { + int a = Math.max(0, Math.min(255, alpha)); + return (color & 0x00FFFFFF) | (a << 24); + } + static int applyAlpha(int argb) { + if (ClickGuiRenderer.renderAlphaMultiplier >= 0.999f) return argb; + int a = (argb >>> 24) & 0xFF; + int na = Math.round(a * ClickGuiRenderer.renderAlphaMultiplier); + return (argb & 0x00FFFFFF) | ((na & 0xFF) << 24); + } + static float setRenderAlphaMultiplier(float alpha) { + float previous = ClickGuiRenderer.renderAlphaMultiplier; + ClickGuiRenderer.renderAlphaMultiplier = Math.max(0.0f, Math.min(1.0f, alpha)); + return previous; + } + static float getRenderAlphaMultiplier() { + return ClickGuiRenderer.renderAlphaMultiplier; + } + static void restoreRenderAlphaMultiplier(float previous) { + ClickGuiRenderer.renderAlphaMultiplier = Math.max(0.0f, Math.min(1.0f, previous)); + } + static void drawRoundedRect(float x, float y, float w, float h, float radius, int argb) { + if (ClickGuiRenderer.renderer == null) return; + argb = applyAlpha(argb); + if (((argb >>> 24) & 0xFF) <= 0) return; + ClickGuiRenderer.renderer.roundedRect(x, y, w, h, radius, 1.1f, argb); + } + static void drawRoundedRectStroke(float x, float y, float w, float h, float radius, float thickness, int argb) { + if (ClickGuiRenderer.renderer == null) return; + argb = applyAlpha(argb); + if (((argb >>> 24) & 0xFF) <= 0) return; + ClickGuiRenderer.renderer.roundedRectStroke(x, y, w, h, radius, 1.1f, thickness, argb); + } + static void drawRoundedRectGlow(float x, float y, float w, float h, + float radius, float glow, int argb) { + if (ClickGuiRenderer.renderer == null) return; + argb = applyAlpha(argb); + if (((argb >>> 24) & 0xFF) <= 0) return; + ClickGuiRenderer.renderer.roundedRectGlow(x, y, w, h, radius, 1.1f, glow, argb); + } + static void drawRoundedRectShadow(float x, float y, float w, float h, + float radius, float softness, float spread, int argb) { + if (ClickGuiRenderer.renderer == null) return; + argb = applyAlpha(argb); + if (((argb >>> 24) & 0xFF) <= 0) return; + ClickGuiRenderer.renderer.roundedRectShadow(x, y, w, h, radius, softness, spread, argb); + } + static void drawRoundedRectGradient(float x, float y, float w, float h, float radius, + int startArgb, int endArgb, float angleDeg) { + if (ClickGuiRenderer.renderer == null) return; + startArgb = applyAlpha(startArgb); + endArgb = applyAlpha(endArgb); + if (((startArgb >>> 24) & 0xFF) <= 0 && ((endArgb >>> 24) & 0xFF) <= 0) return; + ClickGuiRenderer.renderer.roundedRectGradient(x, y, w, h, radius, 1.1f, startArgb, endArgb, angleDeg); + } + static void drawRoundedRectStrokeGradient(float x, float y, float w, float h, float radius, float thickness, + int startArgb, int endArgb, float angleDeg) { + if (ClickGuiRenderer.renderer == null) return; + startArgb = applyAlpha(startArgb); + endArgb = applyAlpha(endArgb); + if (((startArgb >>> 24) & 0xFF) <= 0 && ((endArgb >>> 24) & 0xFF) <= 0) return; + ClickGuiRenderer.renderer.roundedRectStrokeGradient(x, y, w, h, radius, 1.1f, thickness, startArgb, endArgb, angleDeg); + } + static void drawRoundedRectCorners(float x, float y, float w, float h, + float radiusTL, float radiusTR, float radiusBR, float radiusBL, + int argb) { + if (ClickGuiRenderer.renderer == null) return; + argb = applyAlpha(argb); + if (((argb >>> 24) & 0xFF) <= 0) return; + ClickGuiRenderer.renderer.roundedRectCorners(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, 1.1f, argb); + } + static void drawRect(float x, float y, float w, float h, int argb) { + if (ClickGuiRenderer.renderer == null) return; + argb = applyAlpha(argb); + if (((argb >>> 24) & 0xFF) <= 0) return; + ClickGuiRenderer.renderer.quad(x, y, w, h, argb); + } + static void flushRenderer() { + if (ClickGuiRenderer.renderer == null) return; + if (Renderer2D.isBatching()) { + Renderer2D.flushBatch(); + } else { + ClickGuiRenderer.renderer.begin(); + } + } + static void drawGradientRect(float x, float y, float w, float h, + int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { + if (ClickGuiRenderer.renderer == null) return; + cTopLeft = applyAlpha(cTopLeft); + cTopRight = applyAlpha(cTopRight); + cBottomRight = applyAlpha(cBottomRight); + cBottomLeft = applyAlpha(cBottomLeft); + ClickGuiRenderer.renderer.quadGradient(x, y, w, h, cTopLeft, cTopRight, cBottomRight, cBottomLeft); + } + static void drawCircle(float cx, float cy, float r, int argb) { + if (ClickGuiRenderer.renderer == null) return; + argb = applyAlpha(argb); + if (((argb >>> 24) & 0xFF) <= 0) return; + ClickGuiRenderer.renderer.circle(cx, cy, r, argb); + } + static void drawLine(float x1, float y1, float x2, float y2, int argb) { + if (ClickGuiRenderer.renderer == null) return; + argb = applyAlpha(argb); + if (((argb >>> 24) & 0xFF) <= 0) return; + ClickGuiRenderer.renderer.line(x1, y1, x2, y2, argb); + } + static void drawBlur(float x, float y, float w, float h, float radius, int argb, float alpha) { + alpha *= ClickGuiRenderer.renderAlphaMultiplier; + alpha = AnimationUtility.clamp(alpha * clickGuiBlurDensityScale(), 0.0f, 1.0f); + if (alpha <= 0.01f) return; + float quality = clickGuiBlurQuality(); + float brightness = 1.0f; + Renderer2D.COLOR.blurRect(x, y, w, h, radius, quality, brightness, alpha, 0xFFFFFF); + } + static void drawGlass(float x, float y, float w, float h, float radius, float alpha) { + if (ClickGuiRenderer.renderer == null) return; + alpha *= ClickGuiRenderer.renderAlphaMultiplier; + if (alpha <= 0.01f) return; + + float pad = 5f; + float gx = x - pad; + float gy = y - pad; + float gw = w + pad * 2f; + float gh = h + pad * 2f; + float gr = Math.max(0f, radius + pad); + float blurAlpha = AnimationUtility.clamp(alpha * clickGuiGlassBlurScale(), 0.0f, 1.0f); + float scale = Math.max(0.75f, gr / 10.0f); + + Renderer2D.COLOR.blurRect(gx, gy, gw, gh, gr, clickGuiBlurQuality(), 1.0f, blurAlpha, 0xFFFFFF); + + ClickGuiRenderer.renderer.liquidGlassRect( + gx, gy, gw, gh, gr, + 15.0f * scale, + 0xFFFFFFFF, + alpha, + blurAlpha, + -18.0f, + 1.0f, + 0.78f, + 0.52f, + 0.190f * alpha, + 0.0f + ); + } + static float clickGuiBlurQuality() { + return 27.35f; + } + static float clickGuiBlurDensityScale() { + return 1.16f; + } + static float clickGuiGlassBlurScale() { + return 1.28f; + } + static int getColorClipboard() { + return ClickGuiRenderer.colorClipboard; + } + static void setColorClipboard(int argb) { + ClickGuiRenderer.colorClipboard = argb; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiEditorManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiEditorManager.java new file mode 100644 index 0000000..b453b4c --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiEditorManager.java @@ -0,0 +1,129 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.features.gui.clickgui.editor.ClickGuiTextEditorState; +import dev.loki.lovisual.features.gui.clickgui.picker.ClickGuiPickerState; +import dev.loki.lovisual.features.gui.clickgui.protocol.CombatProtocolHeuristicsEditorState; +import dev.loki.lovisual.features.gui.clickgui.settings.TextEditorOwner; +import dev.loki.lovisual.features.gui.clickgui.settings.TextSetting; +import dev.loki.lovisual.features.module.ModuleManager; +import dev.loki.lovisual.util.text.ClipboardUtil; + +final class ClickGuiEditorManager { + + private ClickGuiEditorManager() { + } + + static void openTextEditor(TextEditorOwner owner, String title, String seedText, float anchorX, float anchorY, float anchorW) { + if (owner == null) return; + clearInlineText(); + if (seedText == null) seedText = ""; + ClickGuiSearch.deactivate(); + ClickGuiRenderer.textEditor = new ClickGuiTextEditorState(owner, title, seedText, anchorX, anchorY, anchorW); + } + + static void closeTextEditor(boolean save) { + if (ClickGuiRenderer.textEditor == null) return; + if (save) ClickGuiRenderer.textEditor.save(); + ClickGuiRenderer.textEditor = null; + } + + static void renderTextEditor(int fbw, int fbh) { + if (ClickGuiRenderer.textEditor == null) return; + ClickGuiRenderer.textEditor.render(fbw, fbh); + } + + static void renderPicker(int fbw, int fbh) { + if (ClickGuiRenderer.picker == null) return; + ClickGuiRenderer.picker.render(fbw, fbh); + } + + static void toggleInlineText(TextSetting owner) { + if (owner == null) return; + if (ClickGuiRenderer.inlineTextOwner == owner) { + clearInlineText(); + return; + } + ClickGuiRenderer.inlineTextOwner = owner; + ClickGuiRenderer.inlineTextBuffer = new StringBuilder(owner.getEditorText()); + ClickGuiSearch.deactivate(); + } + + static boolean isInlineTextActive() { + return ClickGuiRenderer.inlineTextOwner != null; + } + + static boolean isInlineTextOwner(TextSetting owner) { + return ClickGuiRenderer.inlineTextOwner == owner; + } + + static String getInlineText(TextSetting owner) { + if (owner == null) return ""; + if (ClickGuiRenderer.inlineTextOwner == owner && ClickGuiRenderer.inlineTextBuffer != null) { + return ClickGuiRenderer.inlineTextBuffer.toString(); + } + return owner.getEditorText(); + } + + static void updateInlineTextBounds(TextSetting owner, float x, float y, float w, float h) { + if (ClickGuiRenderer.inlineTextOwner != owner) return; + ClickGuiRenderer.inlineTextX = x; + ClickGuiRenderer.inlineTextY = y; + ClickGuiRenderer.inlineTextW = w; + ClickGuiRenderer.inlineTextH = h; + } + + static void finishInlineText(boolean save) { + if (ClickGuiRenderer.inlineTextOwner == null || ClickGuiRenderer.inlineTextBuffer == null) { + clearInlineText(); + return; + } + if (save) { + ClickGuiRenderer.inlineTextOwner.applyEditorText(ClickGuiRenderer.inlineTextBuffer.toString()); + } + clearInlineText(); + } + + static void clearInlineText() { + ClickGuiRenderer.inlineTextOwner = null; + ClickGuiRenderer.inlineTextBuffer = null; + ClickGuiRenderer.inlineTextX = ClickGuiRenderer.inlineTextY = ClickGuiRenderer.inlineTextW = ClickGuiRenderer.inlineTextH = 0f; + } + + static void inlineBackspace() { + if (ClickGuiRenderer.inlineTextBuffer == null) return; + int len = ClickGuiRenderer.inlineTextBuffer.length(); + if (len <= 0) return; + ClickGuiRenderer.inlineTextBuffer.deleteCharAt(len - 1); + } + + static void inlinePaste() { + if (ClickGuiRenderer.inlineTextBuffer == null) return; + String clip = ClipboardUtil.get(); + if (clip == null || clip.isEmpty()) return; + ClickGuiRenderer.inlineTextBuffer.append(normalizeInlineText(clip)); + } + + static String normalizeInlineText(String text) { + if (text == null) return ""; + String normalized = text.replace("\r\n", "\n").replace('\r', '\n'); + return normalized.replace('\n', ' '); + } + + static boolean isTextEditorActive() { + return ClickGuiRenderer.textEditor != null; + } + + static boolean isPickerActive() { + return ClickGuiRenderer.picker != null || ClickGuiRenderer.protocolHeuristicsEditor != null; + } + + static boolean isBlockingModuleKeybinds() { + if (!ModuleManager.isEnabled("clickgui")) return false; + if (ClickGuiRenderer.waitingForKey) return true; + if (ClickGuiRenderer.textEditor != null) return true; + if (ClickGuiRenderer.inlineTextOwner != null) return true; + if (ClickGuiRenderer.protocolHeuristicsEditor != null) return true; + if (ClickGuiRenderer.picker != null && ClickGuiRenderer.picker.isListening()) return true; + return ClickGuiSearch.isActive(); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiEditorScreen.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiEditorScreen.java index 4d571cd..47d3447 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiEditorScreen.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiEditorScreen.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiFonts.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiFonts.java new file mode 100644 index 0000000..04057e1 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiFonts.java @@ -0,0 +1,55 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.FontInfo; +import dev.loki.lovisual.render.engine.text.Fonts; +import dev.loki.lovisual.render.engine.text.TextRenderer; + +final class ClickGuiFonts { + + private ClickGuiFonts() { + } + + static TextRenderer getInterRegular() { + if (ClickGuiRenderer.interRegular == null) { + ClickGuiRenderer.interRegular = Fonts.renderer("Inter", FontInfo.Type.Regular, TextRenderer.get()); + } + return ClickGuiRenderer.interRegular; + } + + static Renderer2D currentRenderer() { + return ClickGuiRenderer.renderer; + } + + static TextRenderer getInterMedium() { + if (ClickGuiRenderer.interMedium == null) { + ClickGuiRenderer.interMedium = Fonts.renderer("InterMedium", FontInfo.Type.Regular, getInterRegular()); + } + return ClickGuiRenderer.interMedium; + } + + static TextRenderer getIosevkaRegular() { + return getSfMedium(); + } + + static TextRenderer getSfMedium() { + if (ClickGuiRenderer.onestMedium == null) { + ClickGuiRenderer.onestMedium = Fonts.renderer("OnestMedium", FontInfo.Type.Regular, TextRenderer.get()); + } + return ClickGuiRenderer.onestMedium; + } + + static TextRenderer getSfProDisplaySemibold() { + if (ClickGuiRenderer.onestBold == null) { + ClickGuiRenderer.onestBold = Fonts.renderer("OnestBold", FontInfo.Type.Regular, getInterMedium()); + } + return ClickGuiRenderer.onestBold; + } + + static TextRenderer getMonsterratRegular() { + if (ClickGuiRenderer.monsterratRegular == null) { + ClickGuiRenderer.monsterratRegular = Fonts.renderer("Monsterrat", FontInfo.Type.Regular, TextRenderer.get()); + } + return ClickGuiRenderer.monsterratRegular; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiInputHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiInputHandler.java new file mode 100644 index 0000000..bca7d4e --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiInputHandler.java @@ -0,0 +1,194 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.features.gui.clickgui.sections.settings.SettingsTabRuntime; +import dev.loki.lovisual.render.engine.math.HudScale; +import dev.loki.lovisual.util.wav.ClickGuiSounds; + +final class ClickGuiInputHandler { + + private ClickGuiInputHandler() { + } + + static void onMouseMove(double x, double y) { + updateMouse(x, y, false); + if (ClickGuiRenderer.picker != null) { + ClickGuiRenderer.picker.handleMouseMove(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY); + } + if (ClickGuiRenderer.protocolHeuristicsEditor != null) { + ClickGuiRenderer.protocolHeuristicsEditor.handleMouseMove(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY); + } + if (ClickGuiRenderer.textEditor != null) { + ClickGuiRenderer.textEditor.handleMouseMove(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY); + } + } + + static void onMouseButton(double x, double y, int button, boolean pressed) { + updateMouse(x, y, false); + handleMouseButton(button, pressed); + } + + static void onMouseScroll(double x, double y, double delta) { + updateMouse(x, y, false); + handleMouseScroll(delta); + } + + static void onMouseMoveScaled(double x, double y) { + updateMouse(x, y, true); + if (ClickGuiRenderer.picker != null) { + ClickGuiRenderer.picker.handleMouseMove(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY); + } + if (ClickGuiRenderer.protocolHeuristicsEditor != null) { + ClickGuiRenderer.protocolHeuristicsEditor.handleMouseMove(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY); + } + if (ClickGuiRenderer.textEditor != null) { + ClickGuiRenderer.textEditor.handleMouseMove(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY); + } + } + + static void onMouseButtonScaled(double x, double y, int button, boolean pressed) { + updateMouse(x, y, true); + handleMouseButton(button, pressed); + } + + static void onMouseScrollScaled(double x, double y, double delta) { + updateMouse(x, y, true); + handleMouseScroll(delta); + } + + static void onEditorMouseMoveScaled(double x, double y) { + updateMouse(x, y, true); + } + + static void onEditorMouseButtonScaled(double x, double y, int button, boolean pressed) { + updateMouse(x, y, true); + if (ClickGuiRenderer.waitingForKey) { + if (pressed) ClickGuiKeyBindManager.addPendingMouseButton(button); + return; + } + if (ClickGuiRenderer.textEditor != null) { + if (pressed) { + ClickGuiRenderer.textEditor.handleMouseDown(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button); + } else { + ClickGuiRenderer.textEditor.handleMouseUp(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button); + } + return; + } + if (ClickGuiTabState.isSettingsTabActive()) { + SettingsTabRuntime.handleEditorMouseButton(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button, pressed); + } + } + + static void onEditorMouseScrollScaled(double x, double y, double delta) { + updateMouse(x, y, true); + if (delta != 0.0) { + ClickGuiSounds.scroll(); + } + if (ClickGuiRenderer.textEditor != null) { + ClickGuiRenderer.textEditor.scroll(delta); + return; + } + if (ClickGuiTabState.isSettingsTabActive()) { + SettingsTabRuntime.handleEditorMouseScroll(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, delta); + } + } + + private static void handleMouseButton(int button, boolean pressed) { + if (!ClickGuiLifecycle.isInputReady()) return; + if (ClickGuiRenderer.waitingForKey) { + if (pressed) ClickGuiKeyBindManager.addPendingMouseButton(button); + return; + } + + if (ClickGuiRenderer.textEditor != null) { + if (pressed) { + ClickGuiRenderer.textEditor.handleMouseDown(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button); + } else { + ClickGuiRenderer.textEditor.handleMouseUp(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button); + } + return; + } + + if (ClickGuiRenderer.protocolHeuristicsEditor != null) { + if (pressed) { + ClickGuiRenderer.protocolHeuristicsEditor.handleMouseDown(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button); + } else { + ClickGuiRenderer.protocolHeuristicsEditor.handleMouseUp(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button); + } + return; + } + + if (pressed && ClickGuiTabBar.handleTabClick(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY)) { + return; + } + + if (ClickGuiRenderer.picker != null) { + if (pressed) { + ClickGuiRenderer.picker.handleMouseDown(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button); + } else { + ClickGuiRenderer.picker.handleMouseUp(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button); + } + return; + } + + if (!pressed) { + ClickGuiTabState.getActiveSection().mouseReleased(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button); + return; + } + + ClickGuiTabState.getActiveSection().mousePressed(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, button); + } + + private static void handleMouseScroll(double delta) { + if (!ClickGuiLifecycle.isInputReady()) return; + if (delta != 0.0) { + ClickGuiSounds.scroll(); + } + + if (ClickGuiRenderer.textEditor != null) { + ClickGuiRenderer.textEditor.scroll(delta); + return; + } + + if (ClickGuiRenderer.protocolHeuristicsEditor != null) { + ClickGuiRenderer.protocolHeuristicsEditor.scroll(delta); + return; + } + + if (ClickGuiRenderer.picker != null) { + ClickGuiRenderer.picker.scroll(delta); + return; + } + + ClickGuiTabState.getActiveSection().mouseScrolled(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY, delta); + } + + private static void updateMouse(double x, double y, boolean fromScaledCoords) { + if (ClickGuiRenderer.MC == null || ClickGuiRenderer.MC.getWindow() == null) { + ClickGuiRenderer.mouseX = (float) x; + ClickGuiRenderer.mouseY = (float) y; + return; + } + if (fromScaledCoords) { + double scaledW = ClickGuiRenderer.MC.getWindow().getGuiScaledWidth(); + double scaledH = ClickGuiRenderer.MC.getWindow().getGuiScaledHeight(); + double fbW = ClickGuiRenderer.MC.getWindow().getWidth(); + double fbH = ClickGuiRenderer.MC.getWindow().getHeight(); + double sx = scaledW > 0 ? fbW / scaledW : ClickGuiRenderer.MC.getWindow().getGuiScale(); + double sy = scaledH > 0 ? fbH / scaledH : ClickGuiRenderer.MC.getWindow().getGuiScale(); + double fbX = x * sx; + double fbY = y * sy; + float uiScale = HudScale.scale((int) fbW, (int) fbH); + ClickGuiRenderer.mouseX = (float) (fbX / uiScale); + ClickGuiRenderer.mouseY = (float) (fbY / uiScale); + return; + } + double scale = ClickGuiRenderer.MC.getWindow().getGuiScale(); + double fbW = ClickGuiRenderer.MC.getWindow().getWidth(); + double fbH = ClickGuiRenderer.MC.getWindow().getHeight(); + double fbX = x * scale; + double fbY = y * scale; + float uiScale = HudScale.scale((int) fbW, (int) fbH); + ClickGuiRenderer.mouseX = (float) (fbX / uiScale); + ClickGuiRenderer.mouseY = (float) (fbY / uiScale); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiKeyBindManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiKeyBindManager.java new file mode 100644 index 0000000..70f7493 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiKeyBindManager.java @@ -0,0 +1,62 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.features.gui.clickgui.settings.FunctionBindSetting; +import dev.loki.lovisual.features.gui.clickgui.settings.KeyBindSetting; +import dev.loki.lovisual.util.input.KeyUtil; +import dev.loki.lovisual.util.wav.ClickGuiSounds; +import org.lwjgl.glfw.GLFW; + +import java.util.Set; + +final class ClickGuiKeyBindManager { + + private ClickGuiKeyBindManager() { + } + + static void beginKeyBind(Object owner) { + ClickGuiEditorManager.clearInlineText(); + ClickGuiRenderer.waitingForKey = true; + ClickGuiRenderer.keyBindOwner = owner; + ClickGuiRenderer.pendingBindKeys.clear(); + ClickGuiSearch.deactivate(); + ClickGuiSounds.bindingStart(); + } + + static void finishKeyBind() { + ClickGuiRenderer.waitingForKey = false; + ClickGuiRenderer.keyBindOwner = null; + ClickGuiRenderer.pendingBindKeys.clear(); + } + + static void addPendingKey(int keyCode, int scancode) { + int code = KeyUtil.fromKeyInput(keyCode, scancode); + if (code == KeyUtil.NONE) return; + ClickGuiRenderer.pendingBindKeys.add(code); + } + + static void addPendingMouseButton(int button) { + if (button < GLFW.GLFW_MOUSE_BUTTON_1 || button > GLFW.GLFW_MOUSE_BUTTON_LAST) return; + ClickGuiRenderer.pendingBindKeys.add(KeyUtil.mouseButtonToCode(button)); + } + + static void submitKeySelection(Set keys) { + if (keys == null || keys.isEmpty()) { + submitKeySelection((String) null); + return; + } + submitKeySelection(KeyUtil.comboToString(keys)); + } + + static void submitKeySelection(String combo) { + if (ClickGuiRenderer.keyBindOwner instanceof KeyBindSetting ks) { + ks.onKeySelected(combo); + } else if (ClickGuiRenderer.keyBindOwner instanceof FunctionBindSetting fs) { + fs.onKeySelected(combo); + } + } + + static String getPendingBindDisplay() { + if (!ClickGuiRenderer.waitingForKey) return null; + return ClickGuiRenderer.pendingBindKeys.isEmpty() ? "..." : KeyUtil.comboToString(ClickGuiRenderer.pendingBindKeys); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiKeyboardHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiKeyboardHandler.java new file mode 100644 index 0000000..3a8e6e9 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiKeyboardHandler.java @@ -0,0 +1,148 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.features.gui.clickgui.sections.settings.SettingsTabRuntime; +import dev.loki.lovisual.features.module.ModuleManager; +import net.minecraft.util.StringUtil; +import org.lwjgl.glfw.GLFW; + +import java.nio.file.Path; +import java.util.List; + +final class ClickGuiKeyboardHandler { + + private ClickGuiKeyboardHandler() { + } + + static boolean onEditorCharTyped(char c) { + return onCharTyped(c); + } + + static boolean onEditorKey(int key, int scancode, int action, int mods) { + return onKey(key, scancode, action, mods); + } + + static void closeGuiEditor() { + SettingsTabRuntime.closeGuiEditor(); + } + + static boolean onCharTyped(char c) { + if (!ModuleManager.isEnabled("clickgui")) return false; + if (ClickGuiRenderer.textEditor != null) { + ClickGuiRenderer.textEditor.insertChar(c); + return true; + } + if (ClickGuiRenderer.picker != null) { + if (ClickGuiRenderer.picker.isListening()) { + ClickGuiRenderer.picker.insertChar(c); + return true; + } + return false; + } + if (ClickGuiRenderer.protocolHeuristicsEditor != null) { + return ClickGuiRenderer.protocolHeuristicsEditor.charTyped(c); + } + if (ClickGuiRenderer.inlineTextOwner != null && ClickGuiRenderer.inlineTextBuffer != null) { + if (StringUtil.isAllowedChatCharacter(c)) { + ClickGuiRenderer.inlineTextBuffer.append(c); + return true; + } + return false; + } + return ClickGuiTabState.getActiveSection().charTyped(c, 0); + } + + static boolean onFilesDrop(List paths) { + if (!ModuleManager.isEnabled("clickgui")) return false; + if (ClickGuiRenderer.textEditor != null || ClickGuiRenderer.picker != null || ClickGuiRenderer.protocolHeuristicsEditor != null) return false; + return ClickGuiTabState.getActiveSection().onFilesDrop(paths); + } + + static boolean onKey(int key, int scancode, int action, int mods) { + if (!ModuleManager.isEnabled("clickgui")) return false; + + if (ClickGuiRenderer.textEditor != null) { + if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT) { + boolean shift = (mods & GLFW.GLFW_MOD_SHIFT) != 0; + boolean ctrl = (mods & GLFW.GLFW_MOD_CONTROL) != 0; + switch (key) { + case GLFW.GLFW_KEY_ESCAPE -> ClickGuiEditorManager.closeTextEditor(false); + case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> ClickGuiRenderer.textEditor.insertNewline(); + case GLFW.GLFW_KEY_BACKSPACE -> ClickGuiRenderer.textEditor.backspace(); + case GLFW.GLFW_KEY_DELETE -> ClickGuiRenderer.textEditor.deleteForward(); + case GLFW.GLFW_KEY_LEFT -> ClickGuiRenderer.textEditor.moveCaret(-1, shift); + case GLFW.GLFW_KEY_RIGHT -> ClickGuiRenderer.textEditor.moveCaret(1, shift); + case GLFW.GLFW_KEY_UP -> ClickGuiRenderer.textEditor.moveCaretVertical(-1, shift); + case GLFW.GLFW_KEY_DOWN -> ClickGuiRenderer.textEditor.moveCaretVertical(1, shift); + case GLFW.GLFW_KEY_HOME -> ClickGuiRenderer.textEditor.moveCaretToStart(shift); + case GLFW.GLFW_KEY_END -> ClickGuiRenderer.textEditor.moveCaretToEnd(shift); + default -> { + if (key == GLFW.GLFW_KEY_V && ctrl) ClickGuiRenderer.textEditor.pasteFromClipboard(); + if (key == GLFW.GLFW_KEY_C && ctrl) ClickGuiRenderer.textEditor.copySelection(); + if (key == GLFW.GLFW_KEY_A && ctrl) ClickGuiRenderer.textEditor.selectAll(); + } + } + } + return true; + } + + if (ClickGuiRenderer.protocolHeuristicsEditor != null) { + return ClickGuiRenderer.protocolHeuristicsEditor.keyPressed(key, scancode, action, mods); + } + + if (ClickGuiRenderer.picker != null) { + if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT) { + boolean ctrl = (mods & GLFW.GLFW_MOD_CONTROL) != 0; + switch (key) { + case GLFW.GLFW_KEY_ESCAPE -> ClickGuiScreenManager.closePicker(); + case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> ClickGuiRenderer.picker.stopListening(); + case GLFW.GLFW_KEY_BACKSPACE -> ClickGuiRenderer.picker.backspace(); + default -> { + if (key == GLFW.GLFW_KEY_F && ctrl) ClickGuiRenderer.picker.toggleListening(); + } + } + } + return true; + } + + if (ClickGuiRenderer.inlineTextOwner != null && ClickGuiRenderer.inlineTextBuffer != null) { + if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT) { + boolean ctrl = (mods & GLFW.GLFW_MOD_CONTROL) != 0; + switch (key) { + case GLFW.GLFW_KEY_ESCAPE -> ClickGuiEditorManager.finishInlineText(false); + case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> ClickGuiEditorManager.finishInlineText(true); + case GLFW.GLFW_KEY_BACKSPACE, GLFW.GLFW_KEY_DELETE -> ClickGuiEditorManager.inlineBackspace(); + default -> { + if (key == GLFW.GLFW_KEY_V && ctrl) ClickGuiEditorManager.inlinePaste(); + } + } + } + return true; + } + + if (ClickGuiRenderer.waitingForKey) { + + if (key == GLFW.GLFW_KEY_ESCAPE) { + ClickGuiKeyBindManager.submitKeySelection((String) null); + ClickGuiKeyBindManager.finishKeyBind(); + return true; + } + + if (action == GLFW.GLFW_PRESS) { + if (key == GLFW.GLFW_KEY_ENTER || key == GLFW.GLFW_KEY_KP_ENTER) { + ClickGuiKeyBindManager.submitKeySelection(ClickGuiRenderer.pendingBindKeys); + ClickGuiKeyBindManager.finishKeyBind(); + return true; + } + + ClickGuiKeyBindManager.addPendingKey(key, scancode); + } + + return true; + } + + if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT) { + return ClickGuiTabState.getActiveSection().keyPressed(key, scancode, mods); + } + return false; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiLifecycle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiLifecycle.java new file mode 100644 index 0000000..1c82e22 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiLifecycle.java @@ -0,0 +1,156 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; +import dev.loki.lovisual.features.module.ModuleManager; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.helpers.SystemCursor; +import dev.loki.lovisual.util.screen.ClientScreen; +import org.lwjgl.glfw.GLFW; + +final class ClickGuiLifecycle { + + private ClickGuiLifecycle() { + } + + static void init() { + if (ClickGuiRenderer.init) return; + ClickGuiRenderer.init = true; + ClickGuiRenderer.activeTabId = ClickGuiRenderer.MODULES_TAB_ID; + for (ClickGuiTabEntry tab : ClickGuiTabState.currentTabs()) { + if (ClickGuiRenderer.MODULES_TAB_ID.equals(tab.id())) { + tab.section().onSelected(); + } else { + tab.section().onDeselected(); + } + } + } + + static void beginOpenAnimation() { + init(); + ClickGuiRenderer.closingForExit = false; + ClickGuiRenderer.finishingClose = false; + ClickGuiRenderer.lastLifecycleAnimNs = System.nanoTime(); + ClickGuiTabState.getActiveSection().onSelected(); + } + + static void beginCloseAnimation() { + if (ClickGuiRenderer.finishingClose) return; + init(); + ClickGuiRenderer.closingForExit = true; + ClickGuiRenderer.lastLifecycleAnimNs = System.nanoTime(); + ClickGuiSearch.deactivate(); + ClickGuiEditorManager.closeTextEditor(false); + ClickGuiEditorManager.clearInlineText(); + ClickGuiScreenManager.clearPicker(); + for (ClickGuiTabEntry tab : ClickGuiTabState.currentTabs()) { + tab.section().onDeselected(); + } + detachScreenForExitOverlay(); + releaseCursorForGameplay(); + } + + private static void detachScreenForExitOverlay() { + if (ClickGuiRenderer.MC == null) return; + if (ClientScreen.current() instanceof ClickGuiScreen cs) { + ClickGuiRenderer.mainScreen = cs; + } + if (ClientScreen.current() instanceof ClickGuiScreen + || ClientScreen.current() instanceof ClickGuiPickerScreen + || ClientScreen.current() instanceof ClickGuiEditorScreen) { + ClientScreen.show(ClickGuiRenderer.MC, null); + } + } + + static boolean isLifecycleActive() { + return ModuleManager.isEnabled("clickgui") || ClickGuiRenderer.closingForExit || ClickGuiRenderer.lifecycleAnim > 0.001f; + } + + static boolean isClosingForExit() { + return ClickGuiRenderer.closingForExit; + } + + static boolean isInputReady() { + return ModuleManager.isEnabled("clickgui") && !ClickGuiRenderer.closingForExit && ClickGuiRenderer.lifecycleAnim >= ClickGuiRenderer.INPUT_READY_PROGRESS; + } + + static void finishCloseImmediately() { + ClickGuiRenderer.closingForExit = false; + ClickGuiRenderer.lifecycleAnim = 0.0f; + onClose(); + ClickGuiScreenManager.clearScreens(); + } + + static void onClose() { + if (!ClickGuiRenderer.cursorShown) return; + long handle = ClickGuiRenderer.MC.getWindow().handle(); + + GLFW.glfwSetInputMode(handle, GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); + SystemCursor.invalidate(); + ClickGuiRenderer.cursorShown = false; + DraggableHudElementRegistry.setForceVisible(false); + ClickGuiSearch.deactivate(); + ClickGuiEditorManager.closeTextEditor(false); + ClickGuiEditorManager.clearInlineText(); + ClickGuiScreenManager.clearPicker(); + + ClickGuiScreenManager.requestConfigSave(); + } + + static void releaseCursorForGameplay() { + if (ClickGuiRenderer.MC == null || ClickGuiRenderer.MC.getWindow() == null) return; + if (ClientScreen.current() == null) { + try { + ClickGuiRenderer.MC.mouseHandler.grabMouse(); + SystemCursor.invalidate(); + } catch (Throwable ignored) { + GLFW.glfwSetInputMode(ClickGuiRenderer.MC.getWindow().handle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); + SystemCursor.invalidate(); + } + } else { + GLFW.glfwSetInputMode(ClickGuiRenderer.MC.getWindow().handle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); + SystemCursor.invalidate(); + } + ClickGuiRenderer.cursorShown = false; + DraggableHudElementRegistry.setForceVisible(false); + } + + static void ensureCursorShown() { + if (ClickGuiRenderer.cursorShown) return; + if (ClickGuiRenderer.MC == null || ClickGuiRenderer.MC.getWindow() == null) return; + GLFW.glfwSetInputMode( + ClickGuiRenderer.MC.getWindow().handle(), + GLFW.GLFW_CURSOR, + GLFW.GLFW_CURSOR_NORMAL + ); + SystemCursor.invalidate(); + ClickGuiRenderer.cursorShown = true; + } + + static void updateLifecycleAnim(long now, boolean opening) { + float dt = (now - ClickGuiRenderer.lastLifecycleAnimNs) / 1_000_000_000f; + ClickGuiRenderer.lastLifecycleAnimNs = now; + if (dt < 0f) dt = 0f; + float target = opening ? 1.0f : 0.0f; + float speed = opening ? ClickGuiRenderer.LIFECYCLE_OPEN_SPEED : ClickGuiRenderer.LIFECYCLE_CLOSE_SPEED; + ClickGuiRenderer.lifecycleAnim = AnimationUtility.approach(ClickGuiRenderer.lifecycleAnim, target, dt, speed); + ClickGuiRenderer.lifecycleAnim = AnimationUtility.snap(ClickGuiRenderer.lifecycleAnim, target, 0.002f); + } + + static boolean sectionsClosed() { + return !ClickGuiTabState.getActiveSection().isVisible(); + } + + static void completeCloseAnimation() { + if (ClickGuiRenderer.finishingClose) return; + ClickGuiRenderer.finishingClose = true; + ClickGuiRenderer.closingForExit = false; + onClose(); + if (ClickGuiRenderer.MC != null && (ClientScreen.current() instanceof ClickGuiScreen + || ClientScreen.current() instanceof ClickGuiPickerScreen + || ClientScreen.current() instanceof ClickGuiEditorScreen)) { + ClientScreen.show(ClickGuiRenderer.MC, null); + } + ClickGuiScreenManager.clearScreens(); + ClickGuiRenderer.finishingClose = false; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiModel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiModel.java new file mode 100644 index 0000000..14a9e05 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiModel.java @@ -0,0 +1,37 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.features.gui.clickgui.sections.ClickGuiSection; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import net.minecraft.world.item.ItemStack; + +record ClickGuiTabEntry(String id, String label, ClickGuiSection section) { +} + +record TextBatchItem(TextRenderer renderer, String text, float x, float y, float size, int argb, + boolean shadow) { +} + +record TextBatchKey(TextRenderer renderer, int sizeBits, boolean shadow) { +} + +record TextMeasureKey(TextRenderer renderer, int sizeBits, String text) { +} + +record TextHeightKey(TextRenderer renderer, int sizeBits) { +} + +record PickerIcon(ItemStack stack, + float x, + float y, + float scale, + boolean hasGlobalClip, + float globalClipX, + float globalClipY, + float globalClipW, + float globalClipH, + boolean hasClip, + float clipX, + float clipY, + float clipW, + float clipH) { +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiPickerIconManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiPickerIconManager.java new file mode 100644 index 0000000..b7526d7 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiPickerIconManager.java @@ -0,0 +1,138 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.mixininterface.IGuiGraphics; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.helpers.ScissorFunction; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.world.item.ItemStack; + +final class ClickGuiPickerIconManager { + + private ClickGuiPickerIconManager() { + } + + static void processPickerIcons(GuiGraphicsExtractor ctx) { + if (ClickGuiRenderer.pickerIcons.isEmpty()) { + ClickGuiRenderer.pickerIconScissorActive = false; + return; + } + if (ctx == null) { + ClickGuiRenderer.pickerIcons.clear(); + ClickGuiRenderer.pickerIconScissorActive = false; + return; + } + if (!(ctx instanceof IGuiGraphics accessor)) { + ClickGuiRenderer.pickerIcons.clear(); + ClickGuiRenderer.pickerIconScissorActive = false; + return; + } + if (ClickGuiRenderer.MC == null) { + ClickGuiRenderer.pickerIcons.clear(); + ClickGuiRenderer.pickerIconScissorActive = false; + return; + } + int seed = 0; + for (PickerIcon icon : ClickGuiRenderer.pickerIcons) { + ItemStack stack = icon.stack(); + if (stack == null || stack.isEmpty()) continue; + boolean clippedGlobal = false; + boolean clippedLocal = false; + if (icon.hasGlobalClip()) { + clippedGlobal = ScissorFunction.pushRaw( + icon.globalClipX(), + icon.globalClipY(), + icon.globalClipW(), + icon.globalClipH() + ); + } + if (icon.hasClip()) { + clippedLocal = ScissorFunction.pushRaw( + icon.clipX(), + icon.clipY(), + icon.clipW(), + icon.clipH() + ); + } + Renderer2D.COLOR.begin(); + // Picker screen uses beginUnscaledLogical(), so queued icon coordinates are already logical. + Renderer2D.COLOR.item( + stack, + icon.x(), + icon.y(), + icon.scale(), + seed++, + Renderer2D.ITEM_OVERLAY_ALL, + null + ); + Renderer2D.COLOR.render(); + if (clippedLocal) ScissorFunction.pop(); + if (clippedGlobal) ScissorFunction.pop(); + } + ClickGuiRenderer.pickerIcons.clear(); + ClickGuiRenderer.pickerIconScissorActive = false; + } + + static void beginPickerIconScissor(float x, float y, float w, float h) { + ClickGuiRenderer.pickerIconScissorActive = true; + ClickGuiRenderer.pickerIconScissorX = x; + ClickGuiRenderer.pickerIconScissorY = y; + ClickGuiRenderer.pickerIconScissorW = w; + ClickGuiRenderer.pickerIconScissorH = h; + } + + static void endPickerIconScissor() { + ClickGuiRenderer.pickerIconScissorActive = false; + } + + static void queuePickerIcon(ItemStack stack, float x, float y, float scale) { + if (stack == null || stack.isEmpty()) return; + ClickGuiRenderer.pickerIcons.add(new PickerIcon( + stack, + x, + y, + scale, + currentPickerIconScissorActive(), + ClickGuiRenderer.pickerIconScissorX, + ClickGuiRenderer.pickerIconScissorY, + ClickGuiRenderer.pickerIconScissorW, + ClickGuiRenderer.pickerIconScissorH, + false, + 0f, + 0f, + 0f, + 0f + )); + } + + static void queuePickerIcon(ItemStack stack, + float x, + float y, + float scale, + float clipX, + float clipY, + float clipW, + float clipH) { + if (stack == null || stack.isEmpty()) return; + boolean hasClip = clipW > 0f && clipH > 0f; + ClickGuiRenderer.pickerIcons.add(new PickerIcon( + stack, + x, + y, + scale, + currentPickerIconScissorActive(), + ClickGuiRenderer.pickerIconScissorX, + ClickGuiRenderer.pickerIconScissorY, + ClickGuiRenderer.pickerIconScissorW, + ClickGuiRenderer.pickerIconScissorH, + hasClip, + clipX, + clipY, + clipW, + clipH + )); + } + + private static boolean currentPickerIconScissorActive() { + return ClickGuiRenderer.pickerIconScissorActive && ClickGuiRenderer.pickerIconScissorW > 0f && ClickGuiRenderer.pickerIconScissorH > 0f; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiPickerScreen.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiPickerScreen.java index 497a77a..cb9c014 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiPickerScreen.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiPickerScreen.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiRenderEngine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiRenderEngine.java new file mode 100644 index 0000000..27fbc4f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiRenderEngine.java @@ -0,0 +1,140 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.features.module.ModuleManager; +import dev.loki.lovisual.render.engine.math.HudScale; +import dev.loki.lovisual.render.engine.profiler.ProfilerPhase; +import dev.loki.lovisual.render.engine.profiler.RenderProfiler2D; +import dev.loki.lovisual.render.engine.profiler.TracyGpuProfiler; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.SystemCursor; +import dev.loki.lovisual.util.screen.ClientScreen; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import org.lwjgl.glfw.GLFW; + +final class ClickGuiRenderEngine { + + private ClickGuiRenderEngine() { + } + + static void renderEngine(Renderer2D rendererIn, TextRenderer fallback, GuiGraphicsExtractor ctx, float tickDelta) { + try (ProfilerPhase.Scope frameScope = ProfilerPhase.scope("2d:clickgui:render"); + RenderProfiler2D.Section ignoredFrame = RenderProfiler2D.section("render")) { + boolean enabled = ModuleManager.isEnabled("clickgui"); + long now = System.nanoTime(); + boolean mainScreenActive = ClientScreen.current() instanceof ClickGuiScreen; + boolean pickerScreenActive = ClientScreen.current() instanceof ClickGuiPickerScreen; + + if (!enabled && !ClickGuiRenderer.closingForExit && ClickGuiRenderer.lifecycleAnim <= 0.001f) { + ClickGuiLifecycle.onClose(); + return; + } + + if (ClientScreen.current() != null && !mainScreenActive && !pickerScreenActive) { + if (ClickGuiRenderer.closingForExit) ClickGuiLifecycle.finishCloseImmediately(); + return; + } + // Screen renders ClickGUI directly; no extra gating needed here. + + ClickGuiLifecycle.init(); + if (enabled && ClickGuiRenderer.closingForExit) { + ClickGuiRenderer.closingForExit = false; + ClickGuiTabState.getActiveSection().onSelected(); + } + ClickGuiLifecycle.updateLifecycleAnim(now, enabled && !ClickGuiRenderer.closingForExit); + ClickGuiRenderer.renderer = rendererIn; + ClickGuiRenderer.pickerIcons.clear(); + + SystemCursor.beginFrame(ctx); + try { + if (enabled && !ClickGuiRenderer.closingForExit && !ClickGuiRenderer.cursorShown) { + GLFW.glfwSetInputMode( + ClickGuiRenderer.MC.getWindow().handle(), + GLFW.GLFW_CURSOR, + GLFW.GLFW_CURSOR_NORMAL + ); + SystemCursor.invalidate(); + ClickGuiRenderer.cursorShown = true; + } + int fbw = ClickGuiRenderer.MC.getWindow().getWidth(); + int fbh = ClickGuiRenderer.MC.getWindow().getHeight(); + int vw = Math.max(1, Math.round(HudScale.virtualWidth(fbw, fbh))); + int vh = Math.max(1, Math.round(HudScale.virtualHeight(fbw, fbh))); + ClickGuiRenderer.fbWidth = vw; + ClickGuiRenderer.fbHeight = vh; + + try (ProfilerPhase.Scope layoutScope = ProfilerPhase.scope("2d:clickgui:layout"); + RenderProfiler2D.Section ignoredLayout = RenderProfiler2D.section("layout"); + TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:layout")) { + ClickGuiTabBar.layout(vw, vh); + ClickGuiTabBar.updateTabAnim(now); + } + + if (pickerScreenActive) { + try (ProfilerPhase.Scope pickerScope = ProfilerPhase.scope("2d:clickgui:modal"); + RenderProfiler2D.Section ignoredPicker = RenderProfiler2D.section("modal"); + TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:modal")) { + if (ClickGuiRenderer.protocolHeuristicsEditor != null) { + ClickGuiRenderer.protocolHeuristicsEditor.render(vw, vh); + } else { + ClickGuiEditorManager.renderPicker(vw, vh); + } + } + try (ProfilerPhase.Scope textEditorScope = ProfilerPhase.scope("2d:clickgui:text_editor"); + RenderProfiler2D.Section ignoredTextEditor = RenderProfiler2D.section("text_editor"); + TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:text_editor")) { + if (!ClickGuiRenderer.closingForExit) { + ClickGuiEditorManager.renderTextEditor(vw, vh); + } + } + return; + } + + try (ProfilerPhase.Scope tabsScope = ProfilerPhase.scope("2d:clickgui:tabs"); + RenderProfiler2D.Section ignoredTabs = RenderProfiler2D.section("tabs"); + TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:tabs")) { + ClickGuiTabBar.drawTabs(); + } + + try (ProfilerPhase.Scope sectionScope = ProfilerPhase.scope("2d:clickgui:section"); + RenderProfiler2D.Section ignoredSection = RenderProfiler2D.section("section"); + TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:section")) { + ClickGuiTabState.getActiveSection().render(ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY); + } + try (ProfilerPhase.Scope textEditorScope = ProfilerPhase.scope("2d:clickgui:text_editor"); + RenderProfiler2D.Section ignoredTextEditor = RenderProfiler2D.section("text_editor"); + TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:text_editor")) { + if (!ClickGuiRenderer.closingForExit) { + ClickGuiEditorManager.renderTextEditor(vw, vh); + } + } + + if (ClickGuiRenderer.closingForExit && ClickGuiRenderer.lifecycleAnim <= 0.001f && ClickGuiLifecycle.sectionsClosed()) { + ClickGuiLifecycle.completeCloseAnimation(); + } + } finally { + SystemCursor.endFrame(); + } + } + } + + static int framebufferWidth() { + return ClickGuiRenderer.fbWidth; + } + + static int framebufferHeight() { + return ClickGuiRenderer.fbHeight; + } + + static float getAnimAlpha() { + return 1f; + } + + static float getMouseX() { + return ClickGuiRenderer.mouseX; + } + + static float getMouseY() { + return ClickGuiRenderer.mouseY; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiRenderer.java index 4ccdac7..75b147b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,83 +7,52 @@ package dev.loki.lovisual.features.gui.clickgui; -import dev.loki.lovisual.addon.ClickGuiSectionManager; -import dev.loki.lovisual.features.gui.clickgui.settings.*; -import dev.loki.lovisual.render.engine.math.HudScale; -import dev.loki.lovisual.render.engine.renderer.RenderWarpStack; -import dev.loki.lovisual.util.screen.ClientScreen; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.util.StringUtil; -import net.minecraft.world.item.ItemStack; -import org.lwjgl.glfw.GLFW; -import dev.loki.lovisual.config.ConfigSerializer; import dev.loki.lovisual.features.gui.clickgui.editor.ClickGuiTextEditorState; import dev.loki.lovisual.features.gui.clickgui.picker.ClickGuiPickerState; import dev.loki.lovisual.features.gui.clickgui.protocol.CombatProtocolHeuristicsEditorState; -import dev.loki.lovisual.features.gui.clickgui.sections.ClickGuiSection; import dev.loki.lovisual.features.gui.clickgui.sections.ModulesSection; import dev.loki.lovisual.features.gui.clickgui.sections.SettingsSection; -import dev.loki.lovisual.features.gui.clickgui.sections.settings.SettingsTabRuntime; -import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; -import dev.loki.lovisual.features.gui.hud.nondraggable.impl.DynamicIsland; -import dev.loki.lovisual.features.module.ModuleManager; -import dev.loki.lovisual.mixininterface.IGuiGraphics; -import dev.loki.lovisual.render.engine.animation.AnimationUtility; -import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; -import dev.loki.lovisual.render.engine.core.RenderPhase; -import dev.loki.lovisual.render.engine.core.RenderPhaseScope; -import dev.loki.lovisual.render.engine.core.ViewportContext; -import dev.loki.lovisual.render.engine.profiler.ProfilerPhase; -import dev.loki.lovisual.render.engine.profiler.RenderProfiler2D; -import dev.loki.lovisual.render.engine.profiler.TracyGpuProfiler; +import dev.loki.lovisual.features.gui.clickgui.settings.*; import dev.loki.lovisual.render.engine.renderer.Renderer2D; -import dev.loki.lovisual.render.engine.text.FontInfo; -import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.render.helpers.ScissorFunction; -import dev.loki.lovisual.render.helpers.SystemCursor; -import dev.loki.lovisual.util.input.KeyUtil; -import dev.loki.lovisual.util.text.ClipboardUtil; -import dev.loki.lovisual.util.wav.ClickGuiSounds; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.world.item.ItemStack; import java.nio.file.Path; import java.util.*; import java.util.concurrent.CompletableFuture; -import static dev.loki.lovisual.features.theme.Theme.theme; - public enum ClickGuiRenderer { ; - private static final Minecraft MC = Minecraft.getInstance(); - private static final ModulesSection MODULES_SECTION = new ModulesSection(); - private static final SettingsSection SETTINGS_SECTION = new SettingsSection(); - private static final String MODULES_TAB_ID = "combatant:modules"; - private static final String SETTINGS_TAB_ID = "combatant:settings"; - private static final float TAB_HEIGHT = 34f; - private static final float TAB_GAP = 0f; - private static final float TAB_PAD_X = 18f; - private static final float TAB_FONT = 17f; - private static final float TAB_MIN_W = 96f; - private static float[] tabX = new float[0]; - private static float[] tabW = new float[0]; - private static final float LIFECYCLE_OPEN_SPEED = 9.5f; - private static final float LIFECYCLE_CLOSE_SPEED = 8.0f; - private static final float INPUT_READY_PROGRESS = 0.72f; - private static final Set pendingBindKeys = new LinkedHashSet<>(); - private static final List pickerIcons = new ArrayList<>(); - private static final java.util.ArrayList TEXT_BATCH = new java.util.ArrayList<>(); - private static final int TEXT_WIDTH_CACHE_LIMIT = 4096; - private static final int TEXT_HEIGHT_CACHE_LIMIT = 256; - private static final Map TEXT_WIDTH_CACHE = new LinkedHashMap<>(512, 0.75f, true) { + static final Minecraft MC = Minecraft.getInstance(); + static final ModulesSection MODULES_SECTION = new ModulesSection(); + static final SettingsSection SETTINGS_SECTION = new SettingsSection(); + static final String MODULES_TAB_ID = "lovisual:modules"; + static final String SETTINGS_TAB_ID = "lovisual:settings"; + static final float TAB_HEIGHT = 34f; + static final float TAB_GAP = 0f; + static final float TAB_PAD_X = 18f; + static final float TAB_FONT = 17f; + static final float TAB_MIN_W = 96f; + static float[] tabX = new float[0]; + static float[] tabW = new float[0]; + static final float LIFECYCLE_OPEN_SPEED = 9.5f; + static final float LIFECYCLE_CLOSE_SPEED = 8.0f; + static final float INPUT_READY_PROGRESS = 0.72f; + static final Set pendingBindKeys = new LinkedHashSet<>(); + static final List pickerIcons = new ArrayList<>(); + static final ArrayList TEXT_BATCH = new ArrayList<>(); + static final int TEXT_WIDTH_CACHE_LIMIT = 4096; + static final int TEXT_HEIGHT_CACHE_LIMIT = 256; + static final Map TEXT_WIDTH_CACHE = new LinkedHashMap<>(512, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > TEXT_WIDTH_CACHE_LIMIT; } }; - private static final Map TEXT_HEIGHT_CACHE = new LinkedHashMap<>(64, 0.75f, true) { + static final Map TEXT_HEIGHT_CACHE = new LinkedHashMap<>(64, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > TEXT_HEIGHT_CACHE_LIMIT; @@ -91,1623 +60,428 @@ public enum ClickGuiRenderer { }; public static boolean waitingForKey = false; public static Object keyBindOwner = null; - private static int colorClipboard = 0xFFFFFFFF; - private static boolean init = false; - private static float mouseX, mouseY; - private static boolean cursorShown = false; - private static int fbWidth, fbHeight; - private static TextRenderer interRegular; - private static TextRenderer interMedium; - private static TextRenderer onestMedium; - private static TextRenderer onestBold; - private static TextRenderer monsterratRegular; - private static String activeTabId = MODULES_TAB_ID; - private static float tabBarX, tabBarY, tabBarW, tabBarH; - private static float tabTargetX, tabTargetW; - private static float tabAnimX, tabAnimW; - private static boolean tabAnimInit = false; - private static long lastTabAnimNs = System.nanoTime(); - private static float lifecycleAnim = 0.0f; - private static boolean closingForExit = false; - private static boolean finishingClose = false; - private static long lastLifecycleAnimNs = System.nanoTime(); - private static float modulesAreaX, modulesAreaY, modulesAreaW, modulesAreaH; - private static CompletableFuture pendingSaveTask; - private static ClickGuiTextEditorState textEditor = null; - private static ClickGuiPickerState picker = null; - private static CombatProtocolHeuristicsEditorState protocolHeuristicsEditor = null; - private static TextSetting inlineTextOwner = null; - private static StringBuilder inlineTextBuffer = null; - private static float inlineTextX, inlineTextY, inlineTextW, inlineTextH; - private static boolean pickerIconScissorActive = false; - private static float pickerIconScissorX, pickerIconScissorY, pickerIconScissorW, pickerIconScissorH; - private static Renderer2D renderer; - private static float renderAlphaMultiplier = 1.0f; - private static ClickGuiScreen mainScreen; - private static ClickGuiPickerScreen pickerScreen; - private static boolean textBatchActive; + static int colorClipboard = 0xFFFFFFFF; + static boolean init = false; + static float mouseX, mouseY; + static boolean cursorShown = false; + static int fbWidth, fbHeight; + static TextRenderer interRegular; + static TextRenderer interMedium; + static TextRenderer onestMedium; + static TextRenderer onestBold; + static TextRenderer monsterratRegular; + static String activeTabId = MODULES_TAB_ID; + static float tabBarX, tabBarY, tabBarW, tabBarH; + static float tabTargetX, tabTargetW; + static float tabAnimX, tabAnimW; + static boolean tabAnimInit = false; + static long lastTabAnimNs = System.nanoTime(); + static float lifecycleAnim = 0.0f; + static boolean closingForExit = false; + static boolean finishingClose = false; + static long lastLifecycleAnimNs = System.nanoTime(); + static float modulesAreaX, modulesAreaY, modulesAreaW, modulesAreaH; + static CompletableFuture pendingSaveTask; + static ClickGuiTextEditorState textEditor = null; + static ClickGuiPickerState picker = null; + static CombatProtocolHeuristicsEditorState protocolHeuristicsEditor = null; + static TextSetting inlineTextOwner = null; + static StringBuilder inlineTextBuffer = null; + static float inlineTextX, inlineTextY, inlineTextW, inlineTextH; + static boolean pickerIconScissorActive = false; + static float pickerIconScissorX, pickerIconScissorY, pickerIconScissorW, pickerIconScissorH; + static Renderer2D renderer; + static float renderAlphaMultiplier = 1.0f; + static ClickGuiScreen mainScreen; + static ClickGuiPickerScreen pickerScreen; + static boolean textBatchActive; // ========================= // API for MIXIN MOUSE // ========================= public static void onMouseMove(double x, double y) { - updateMouse(x, y, false); - if (picker != null) { - picker.handleMouseMove(mouseX, mouseY); - } - if (protocolHeuristicsEditor != null) { - protocolHeuristicsEditor.handleMouseMove(mouseX, mouseY); - } - if (textEditor != null) { - textEditor.handleMouseMove(mouseX, mouseY); - } + ClickGuiInputHandler.onMouseMove(x, y); } public static void onMouseButton(double x, double y, int button, boolean pressed) { - updateMouse(x, y, false); - handleMouseButton(button, pressed); + ClickGuiInputHandler.onMouseButton(x, y, button, pressed); } public static void onMouseScroll(double x, double y, double delta) { - updateMouse(x, y, false); - handleMouseScroll(delta); + ClickGuiInputHandler.onMouseScroll(x, y, delta); } public static void onMouseMoveScaled(double x, double y) { - updateMouse(x, y, true); - if (picker != null) { - picker.handleMouseMove(mouseX, mouseY); - } - if (protocolHeuristicsEditor != null) { - protocolHeuristicsEditor.handleMouseMove(mouseX, mouseY); - } - if (textEditor != null) { - textEditor.handleMouseMove(mouseX, mouseY); - } + ClickGuiInputHandler.onMouseMoveScaled(x, y); } public static void onMouseButtonScaled(double x, double y, int button, boolean pressed) { - updateMouse(x, y, true); - handleMouseButton(button, pressed); + ClickGuiInputHandler.onMouseButtonScaled(x, y, button, pressed); } public static void onMouseScrollScaled(double x, double y, double delta) { - updateMouse(x, y, true); - handleMouseScroll(delta); + ClickGuiInputHandler.onMouseScrollScaled(x, y, delta); } public static void onEditorMouseMoveScaled(double x, double y) { - updateMouse(x, y, true); + ClickGuiInputHandler.onEditorMouseMoveScaled(x, y); } public static void onEditorMouseButtonScaled(double x, double y, int button, boolean pressed) { - updateMouse(x, y, true); - if (waitingForKey) { - if (pressed) addPendingMouseButton(button); - return; - } - if (textEditor != null) { - if (pressed) { - textEditor.handleMouseDown(mouseX, mouseY, button); - } else { - textEditor.handleMouseUp(mouseX, mouseY, button); - } - return; - } - if (isSettingsTabActive()) { - SettingsTabRuntime.handleEditorMouseButton(mouseX, mouseY, button, pressed); - } + ClickGuiInputHandler.onEditorMouseButtonScaled(x, y, button, pressed); } public static void onEditorMouseScrollScaled(double x, double y, double delta) { - updateMouse(x, y, true); - if (delta != 0.0) { - ClickGuiSounds.scroll(); - } - if (textEditor != null) { - textEditor.scroll(delta); - return; - } - if (isSettingsTabActive()) { - SettingsTabRuntime.handleEditorMouseScroll(mouseX, mouseY, delta); - } + ClickGuiInputHandler.onEditorMouseScrollScaled(x, y, delta); } public static boolean onEditorCharTyped(char c) { - return onCharTyped(c); + return ClickGuiKeyboardHandler.onEditorCharTyped(c); } public static boolean onEditorKey(int key, int scancode, int action, int mods) { - return onKey(key, scancode, action, mods); + return ClickGuiKeyboardHandler.onEditorKey(key, scancode, action, mods); } public static void closeGuiEditor() { - SettingsTabRuntime.closeGuiEditor(); + ClickGuiKeyboardHandler.closeGuiEditor(); } - private static void handleMouseButton(int button, boolean pressed) { - if (!isInputReady()) return; - if (waitingForKey) { - if (pressed) addPendingMouseButton(button); - return; - } - - if (textEditor != null) { - if (pressed) { - textEditor.handleMouseDown(mouseX, mouseY, button); - } else { - textEditor.handleMouseUp(mouseX, mouseY, button); - } - return; - } - - if (protocolHeuristicsEditor != null) { - if (pressed) { - protocolHeuristicsEditor.handleMouseDown(mouseX, mouseY, button); - } else { - protocolHeuristicsEditor.handleMouseUp(mouseX, mouseY, button); - } - return; - } - - if (pressed && handleTabClick(mouseX, mouseY)) { - return; - } - - if (picker != null) { - if (pressed) { - picker.handleMouseDown(mouseX, mouseY, button); - } else { - picker.handleMouseUp(mouseX, mouseY, button); - } - return; - } - - if (!pressed) { - getActiveSection().mouseReleased(mouseX, mouseY, button); - return; - } - - getActiveSection().mousePressed(mouseX, mouseY, button); - } - - private static void handleMouseScroll(double delta) { - if (!isInputReady()) return; - if (delta != 0.0) { - ClickGuiSounds.scroll(); - } - - if (textEditor != null) { - textEditor.scroll(delta); - return; - } - - if (protocolHeuristicsEditor != null) { - protocolHeuristicsEditor.scroll(delta); - return; - } - - if (picker != null) { - picker.scroll(delta); - return; - } - - getActiveSection().mouseScrolled(mouseX, mouseY, delta); - } - - private static void updateMouse(double x, double y, boolean fromScaledCoords) { - if (MC == null || MC.getWindow() == null) { - mouseX = (float) x; - mouseY = (float) y; - return; - } - if (fromScaledCoords) { - double scaledW = MC.getWindow().getGuiScaledWidth(); - double scaledH = MC.getWindow().getGuiScaledHeight(); - double fbW = MC.getWindow().getWidth(); - double fbH = MC.getWindow().getHeight(); - double sx = scaledW > 0 ? fbW / scaledW : MC.getWindow().getGuiScale(); - double sy = scaledH > 0 ? fbH / scaledH : MC.getWindow().getGuiScale(); - double fbX = x * sx; - double fbY = y * sy; - float uiScale = HudScale.scale((int) fbW, (int) fbH); - mouseX = (float) (fbX / uiScale); - mouseY = (float) (fbY / uiScale); - return; - } - double scale = MC.getWindow().getGuiScale(); - double fbW = MC.getWindow().getWidth(); - double fbH = MC.getWindow().getHeight(); - double fbX = x * scale; - double fbY = y * scale; - float uiScale = HudScale.scale((int) fbW, (int) fbH); - mouseX = (float) (fbX / uiScale); - mouseY = (float) (fbY / uiScale); - } - - // ========================= - // API for MIXIN KEYBOARD - // ========================= public static boolean onCharTyped(char c) { - if (!ModuleManager.isEnabled("clickgui")) return false; - if (textEditor != null) { - textEditor.insertChar(c); - return true; - } - if (picker != null) { - if (picker.isListening()) { - picker.insertChar(c); - return true; - } - return false; - } - if (protocolHeuristicsEditor != null) { - return protocolHeuristicsEditor.charTyped(c); - } - if (inlineTextOwner != null && inlineTextBuffer != null) { - if (StringUtil.isAllowedChatCharacter(c)) { - inlineTextBuffer.append(c); - return true; - } - return false; - } - return getActiveSection().charTyped(c, 0); + return ClickGuiKeyboardHandler.onCharTyped(c); } public static boolean onFilesDrop(List paths) { - if (!ModuleManager.isEnabled("clickgui")) return false; - if (textEditor != null || picker != null || protocolHeuristicsEditor != null) return false; - return getActiveSection().onFilesDrop(paths); + return ClickGuiKeyboardHandler.onFilesDrop(paths); } public static boolean onKey(int key, int scancode, int action, int mods) { - if (!ModuleManager.isEnabled("clickgui")) return false; - - if (textEditor != null) { - if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT) { - boolean shift = (mods & GLFW.GLFW_MOD_SHIFT) != 0; - boolean ctrl = (mods & GLFW.GLFW_MOD_CONTROL) != 0; - switch (key) { - case GLFW.GLFW_KEY_ESCAPE -> closeTextEditor(false); - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> textEditor.insertNewline(); - case GLFW.GLFW_KEY_BACKSPACE -> textEditor.backspace(); - case GLFW.GLFW_KEY_DELETE -> textEditor.deleteForward(); - case GLFW.GLFW_KEY_LEFT -> textEditor.moveCaret(-1, shift); - case GLFW.GLFW_KEY_RIGHT -> textEditor.moveCaret(1, shift); - case GLFW.GLFW_KEY_UP -> textEditor.moveCaretVertical(-1, shift); - case GLFW.GLFW_KEY_DOWN -> textEditor.moveCaretVertical(1, shift); - case GLFW.GLFW_KEY_HOME -> textEditor.moveCaretToStart(shift); - case GLFW.GLFW_KEY_END -> textEditor.moveCaretToEnd(shift); - default -> { - if (key == GLFW.GLFW_KEY_V && ctrl) textEditor.pasteFromClipboard(); - if (key == GLFW.GLFW_KEY_C && ctrl) textEditor.copySelection(); - if (key == GLFW.GLFW_KEY_A && ctrl) textEditor.selectAll(); - } - } - } - return true; - } - - if (protocolHeuristicsEditor != null) { - return protocolHeuristicsEditor.keyPressed(key, scancode, action, mods); - } - - if (picker != null) { - if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT) { - boolean ctrl = (mods & GLFW.GLFW_MOD_CONTROL) != 0; - switch (key) { - case GLFW.GLFW_KEY_ESCAPE -> closePicker(); - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> picker.stopListening(); - case GLFW.GLFW_KEY_BACKSPACE -> picker.backspace(); - default -> { - if (key == GLFW.GLFW_KEY_F && ctrl) picker.toggleListening(); - } - } - } - return true; - } - - if (inlineTextOwner != null && inlineTextBuffer != null) { - if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT) { - boolean ctrl = (mods & GLFW.GLFW_MOD_CONTROL) != 0; - switch (key) { - case GLFW.GLFW_KEY_ESCAPE -> finishInlineText(false); - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> finishInlineText(true); - case GLFW.GLFW_KEY_BACKSPACE, GLFW.GLFW_KEY_DELETE -> inlineBackspace(); - default -> { - if (key == GLFW.GLFW_KEY_V && ctrl) inlinePaste(); - } - } - } - return true; - } - - if (waitingForKey) { - - if (key == GLFW.GLFW_KEY_ESCAPE) { - submitKeySelection((String) null); - finishKeyBind(); - return true; - } - - if (action == GLFW.GLFW_PRESS) { - if (key == GLFW.GLFW_KEY_ENTER || key == GLFW.GLFW_KEY_KP_ENTER) { - submitKeySelection(pendingBindKeys); - finishKeyBind(); - return true; - } - - addPendingKey(key, scancode); - } - - return true; - } - - if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT) { - return getActiveSection().keyPressed(key, scancode, mods); - } - return false; + return ClickGuiKeyboardHandler.onKey(key, scancode, action, mods); } // ========================= // INIT // ========================= public static void init() { - if (init) return; - init = true; - activeTabId = MODULES_TAB_ID; - for (ClickGuiTabEntry tab : currentTabs()) { - if (MODULES_TAB_ID.equals(tab.id())) { - tab.section().onSelected(); - } else { - tab.section().onDeselected(); - } - } + ClickGuiLifecycle.init(); } public static void beginOpenAnimation() { - init(); - closingForExit = false; - finishingClose = false; - lastLifecycleAnimNs = System.nanoTime(); - getActiveSection().onSelected(); + ClickGuiLifecycle.beginOpenAnimation(); } public static void beginCloseAnimation() { - if (finishingClose) return; - init(); - closingForExit = true; - lastLifecycleAnimNs = System.nanoTime(); - ClickGuiSearch.deactivate(); - closeTextEditor(false); - clearInlineText(); - clearPicker(); - for (ClickGuiTabEntry tab : currentTabs()) { - tab.section().onDeselected(); - } - detachScreenForExitOverlay(); - releaseCursorForGameplay(); + ClickGuiLifecycle.beginCloseAnimation(); } // ========================= // CURSOR OPEN/CLOSE // ========================= - - private static void detachScreenForExitOverlay() { - if (MC == null) return; - if (ClientScreen.current() instanceof ClickGuiScreen cs) { - mainScreen = cs; - } - if (ClientScreen.current() instanceof ClickGuiScreen - || ClientScreen.current() instanceof ClickGuiPickerScreen - || ClientScreen.current() instanceof ClickGuiEditorScreen) { - ClientScreen.show(MC, null); - } - } - public static boolean isLifecycleActive() { - return ModuleManager.isEnabled("clickgui") || closingForExit || lifecycleAnim > 0.001f; + return ClickGuiLifecycle.isLifecycleActive(); } public static boolean isClosingForExit() { - return closingForExit; - } - - private static boolean isInputReady() { - return ModuleManager.isEnabled("clickgui") && !closingForExit && lifecycleAnim >= INPUT_READY_PROGRESS; + return ClickGuiLifecycle.isClosingForExit(); } public static void finishCloseImmediately() { - closingForExit = false; - lifecycleAnim = 0.0f; - onClose(); - clearScreens(); + ClickGuiLifecycle.finishCloseImmediately(); } public static void onClose() { - if (!cursorShown) return; - long handle = MC.getWindow().handle(); - - GLFW.glfwSetInputMode(handle, GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); - SystemCursor.invalidate(); - cursorShown = false; - DraggableHudElementRegistry.setForceVisible(false); - ClickGuiSearch.deactivate(); - closeTextEditor(false); - clearInlineText(); - clearPicker(); - - requestConfigSave(); + ClickGuiLifecycle.onClose(); } public static void releaseCursorForGameplay() { - if (MC == null || MC.getWindow() == null) return; - if (ClientScreen.current() == null) { - try { - MC.mouseHandler.grabMouse(); - SystemCursor.invalidate(); - } catch (Throwable ignored) { - GLFW.glfwSetInputMode(MC.getWindow().handle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); - SystemCursor.invalidate(); - } - } else { - GLFW.glfwSetInputMode(MC.getWindow().handle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); - SystemCursor.invalidate(); - } - cursorShown = false; - DraggableHudElementRegistry.setForceVisible(false); + ClickGuiLifecycle.releaseCursorForGameplay(); } public static void ensureCursorShown() { - if (cursorShown) return; - if (MC == null || MC.getWindow() == null) return; - GLFW.glfwSetInputMode( - MC.getWindow().handle(), - GLFW.GLFW_CURSOR, - GLFW.GLFW_CURSOR_NORMAL - ); - SystemCursor.invalidate(); - cursorShown = true; + ClickGuiLifecycle.ensureCursorShown(); } public static void renderEngine(Renderer2D rendererIn, TextRenderer fallback, GuiGraphicsExtractor ctx, float tickDelta) { - try (ProfilerPhase.Scope frameScope = ProfilerPhase.scope("2d:clickgui:render"); - RenderProfiler2D.Section ignoredFrame = RenderProfiler2D.section("render")) { - boolean enabled = ModuleManager.isEnabled("clickgui"); - long now = System.nanoTime(); - boolean mainScreenActive = ClientScreen.current() instanceof ClickGuiScreen; - boolean pickerScreenActive = ClientScreen.current() instanceof ClickGuiPickerScreen; - - if (!enabled && !closingForExit && lifecycleAnim <= 0.001f) { - ClickGuiRenderer.onClose(); - return; - } - - if (ClientScreen.current() != null && !mainScreenActive && !pickerScreenActive) { - if (closingForExit) finishCloseImmediately(); - return; - } - // Screen renders ClickGUI directly; no extra gating needed here. - - init(); - if (enabled && closingForExit) { - closingForExit = false; - getActiveSection().onSelected(); - } - updateLifecycleAnim(now, enabled && !closingForExit); - renderer = rendererIn; - pickerIcons.clear(); - - SystemCursor.beginFrame(ctx); - try { - if (enabled && !closingForExit && !cursorShown) { - GLFW.glfwSetInputMode( - MC.getWindow().handle(), - GLFW.GLFW_CURSOR, - GLFW.GLFW_CURSOR_NORMAL - ); - SystemCursor.invalidate(); - cursorShown = true; - } - int fbw = MC.getWindow().getWidth(); - int fbh = MC.getWindow().getHeight(); - int vw = Math.max(1, Math.round(HudScale.virtualWidth(fbw, fbh))); - int vh = Math.max(1, Math.round(HudScale.virtualHeight(fbw, fbh))); - fbWidth = vw; - fbHeight = vh; - - try (ProfilerPhase.Scope layoutScope = ProfilerPhase.scope("2d:clickgui:layout"); - RenderProfiler2D.Section ignoredLayout = RenderProfiler2D.section("layout"); - TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:layout")) { - layout(vw, vh); - updateTabAnim(now); - } - - if (pickerScreenActive) { - try (ProfilerPhase.Scope pickerScope = ProfilerPhase.scope("2d:clickgui:modal"); - RenderProfiler2D.Section ignoredPicker = RenderProfiler2D.section("modal"); - TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:modal")) { - if (protocolHeuristicsEditor != null) { - protocolHeuristicsEditor.render(vw, vh); - } else { - renderPicker(vw, vh); - } - } - try (ProfilerPhase.Scope textEditorScope = ProfilerPhase.scope("2d:clickgui:text_editor"); - RenderProfiler2D.Section ignoredTextEditor = RenderProfiler2D.section("text_editor"); - TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:text_editor")) { - if (!closingForExit) { - renderTextEditor(vw, vh); - } - } - return; - } - - try (ProfilerPhase.Scope tabsScope = ProfilerPhase.scope("2d:clickgui:tabs"); - RenderProfiler2D.Section ignoredTabs = RenderProfiler2D.section("tabs"); - TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:tabs")) { - drawTabs(); - } - - try (ProfilerPhase.Scope sectionScope = ProfilerPhase.scope("2d:clickgui:section"); - RenderProfiler2D.Section ignoredSection = RenderProfiler2D.section("section"); - TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:section")) { - getActiveSection().render(mouseX, mouseY); - } - try (ProfilerPhase.Scope textEditorScope = ProfilerPhase.scope("2d:clickgui:text_editor"); - RenderProfiler2D.Section ignoredTextEditor = RenderProfiler2D.section("text_editor"); - TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("2d:clickgui:text_editor")) { - if (!closingForExit) { - renderTextEditor(vw, vh); - } - } - - if (closingForExit && lifecycleAnim <= 0.001f && sectionsClosed()) { - completeCloseAnimation(); - } - } finally { - SystemCursor.endFrame(); - } - } + ClickGuiRenderEngine.renderEngine(rendererIn, fallback, ctx, tickDelta); } public static boolean shouldRenderAsTopLayer() { - return MC != null && (isLifecycleActive() - || ClientScreen.current() instanceof ClickGuiScreen - || ClientScreen.current() instanceof ClickGuiPickerScreen - || ClientScreen.current() instanceof ClickGuiEditorScreen); + return ClickGuiTopLayer.shouldRenderAsTopLayer(); } public static void renderTopLayer(GuiGraphicsExtractor ctx, float tickDelta) { - if (!shouldRenderAsTopLayer()) return; - - CombatantRenderSystem.ensureFrameContext(); - ViewportContext.beginUnscaledLogical(ctx); - try (RenderPhaseScope phaseScope = CombatantRenderSystem.phase(RenderPhase.SCREEN_TOP, "2d:clickgui_top")) { - SystemCursor.beginFrame(ctx); - try { - Renderer2D.COLOR.begin(); - if (ClientScreen.current() instanceof ClickGuiEditorScreen) { - renderEditor(Renderer2D.COLOR, TextRenderer.get(), ctx, tickDelta); - } else { - renderEngine(Renderer2D.COLOR, TextRenderer.get(), ctx, tickDelta); - } - Renderer2D.COLOR.render(); - if (ClientScreen.current() instanceof ClickGuiPickerScreen) { - processPickerIcons(ctx); - } - } finally { - SystemCursor.endFrame(); - } - } - ViewportContext.end(ctx); + ClickGuiTopLayer.renderTopLayer(ctx, tickDelta); } public static void renderEditor(Renderer2D rendererIn, TextRenderer fallback, GuiGraphicsExtractor ctx, float tickDelta) { - if (MC == null || MC.getWindow() == null) return; - init(); - renderer = rendererIn; - int fbw = MC.getWindow().getWidth(); - int fbh = MC.getWindow().getHeight(); - int vw = Math.max(1, Math.round(HudScale.virtualWidth(fbw, fbh))); - int vh = Math.max(1, Math.round(HudScale.virtualHeight(fbw, fbh))); - fbWidth = vw; - fbHeight = vh; - SystemCursor.beginFrame(ctx); - try { - SettingsTabRuntime.renderEditor(rendererIn, fallback, ctx, tickDelta, vw, vh, mouseX, mouseY); - } finally { - SystemCursor.endFrame(); - } + ClickGuiTopLayer.renderEditor(rendererIn, fallback, ctx, tickDelta); } public static void renderModulesPreview(float x, float y, float w, float h) { - if (renderer == null) return; - init(); - float pad = 8f; - float areaX = x + pad; - float areaY = y + pad; - float areaW = Math.max(1f, w - pad * 2f); - float areaH = Math.max(1f, h - pad * 2f); - MODULES_SECTION.layout(areaX, areaY, areaW, areaH); - float mx = -10_000f; - float my = -10_000f; - MODULES_SECTION.render(mx, my); - } - - private static void layout(int fbw, int fbh) { - List tabs = currentTabs(); - ensureActiveTab(tabs); - float contentMarginX = 28f; - float contentTop = 52f; - float contentBottom = 18f; - modulesAreaX = contentMarginX; - modulesAreaY = contentTop; - modulesAreaW = Math.max(1f, fbw - contentMarginX * 2f); - modulesAreaH = Math.max(1f, fbh - contentTop - contentBottom); - for (ClickGuiTabEntry tab : tabs) { - tab.section().layout(modulesAreaX, modulesAreaY, modulesAreaW, modulesAreaH); - } - - tabBarH = TAB_HEIGHT; - tabBarY = 10f; - ensureTabCapacity(tabs.size()); - float totalTabs = 0f; - for (int t = 0; t < tabs.size(); t++) { - float wTab = textWidth(getSfProDisplaySemibold(), tabs.get(t).label(), TAB_FONT) + TAB_PAD_X * 2f; - if (wTab < TAB_MIN_W) wTab = TAB_MIN_W; - tabW[t] = wTab; - totalTabs += wTab; - } - if (!tabs.isEmpty()) { - totalTabs += TAB_GAP * (tabs.size() - 1); - } - tabBarW = totalTabs; - tabBarX = (fbw - totalTabs) * 0.5f; - float cx = tabBarX; - for (int t = 0; t < tabs.size(); t++) { - tabX[t] = cx; - cx += tabW[t] + TAB_GAP; - } - - int activeIdx = 0; - for (int t = 0; t < tabs.size(); t++) { - if (tabs.get(t).id().equals(activeTabId)) { - activeIdx = t; - break; - } - } - tabTargetX = tabX[activeIdx]; - tabTargetW = tabW[activeIdx]; - if (!tabAnimInit) { - tabAnimX = tabTargetX; - tabAnimW = tabTargetW; - tabAnimInit = true; - lastTabAnimNs = System.nanoTime(); - } - } - - private static void updateTabAnim(long now) { - float dt = (now - lastTabAnimNs) / 1_000_000_000f; - lastTabAnimNs = now; - if (dt < 0f) dt = 0f; - float speed = 16f; - float step = Math.min(1f, dt * speed); - tabAnimX += (tabTargetX - tabAnimX) * step; - tabAnimW += (tabTargetW - tabAnimW) * step; - } - - private static void updateLifecycleAnim(long now, boolean opening) { - float dt = (now - lastLifecycleAnimNs) / 1_000_000_000f; - lastLifecycleAnimNs = now; - if (dt < 0f) dt = 0f; - float target = opening ? 1.0f : 0.0f; - float speed = opening ? LIFECYCLE_OPEN_SPEED : LIFECYCLE_CLOSE_SPEED; - lifecycleAnim = AnimationUtility.approach(lifecycleAnim, target, dt, speed); - lifecycleAnim = AnimationUtility.snap(lifecycleAnim, target, 0.002f); - } - - private static boolean sectionsClosed() { - return !getActiveSection().isVisible(); - } - - private static void completeCloseAnimation() { - if (finishingClose) return; - finishingClose = true; - closingForExit = false; - onClose(); - if (MC != null && (ClientScreen.current() instanceof ClickGuiScreen - || ClientScreen.current() instanceof ClickGuiPickerScreen - || ClientScreen.current() instanceof ClickGuiEditorScreen)) { - ClientScreen.show(MC, null); - } - clearScreens(); - finishingClose = false; - } - - private static void drawTabs() { - float eased = easeOutCubic(lifecycleAnim); - if (eased <= 0.001f) return; - List tabs = currentTabs(); - ensureActiveTab(tabs); - if (tabs.isEmpty()) return; - boolean islandShell = DynamicIsland.shouldOwnClickGuiTabShell(); - - TextRenderer tabFont = getSfProDisplaySemibold(); - float y = tabBarY - (1.0f - eased) * 18.0f; - float outerRadius = tabBarH * 0.5f; - float outerPad = 4.0f; - float innerX = tabAnimX + outerPad; - float innerY = y + outerPad; - float innerW = Math.max(1.0f, tabAnimW - outerPad * 2.0f); - float innerH = Math.max(1.0f, tabBarH - outerPad * 2.0f); - float innerRadius = innerH * 0.5f; - - int outerLeft = scaleAlpha(mixColor(theme().surface(), theme().windowBg(), 0.34f), eased); - int outerRight = scaleAlpha(mixColor(theme().surfaceHover(), theme().windowBg(), 0.22f), eased); - int outerStrokeLeft = scaleAlpha(mixColor(theme().strokeSoft(), theme().accentSoft(), 0.18f), 0.72f * eased); - int outerStrokeRight = scaleAlpha(mixColor(theme().strokeSoft(), theme().textPrimary(), 0.08f), 0.58f * eased); - - int activeLeft = scaleAlpha(mixColor(theme().accentSoft(), theme().accent(), 0.18f), eased); - int activeRight = scaleAlpha(mixColor(theme().accent(), theme().textPrimary(), 0.08f), eased); - int activeStrokeLeft = scaleAlpha(mixColor(theme().accentSoft(), theme().textPrimary(), 0.20f), 0.88f * eased); - int activeStrokeRight = scaleAlpha(theme().accent(), 0.92f * eased); - - try (RenderWarpStack.Scope ignored = Renderer2D.pushPerspectiveWarp( - tabBarX, - y, - tabBarW, - tabBarH, - 0.0f, - -5.0f * (1.0f - eased), - 0.0f, - 3.2f, - 0.80f, - 0.965f + 0.035f * eased - )) { - if (!islandShell) { - drawRoundedRectShadow( - tabBarX, - y, - tabBarW, - tabBarH, - outerRadius, - 10.0f, - 1.5f, - scaleAlpha(0xCC000000, 0.34f * eased) - ); - drawRoundedRectGradient(tabBarX, y, tabBarW, tabBarH, outerRadius, outerLeft, outerRight, 0.0f); - drawRoundedRectStrokeGradient(tabBarX, y, tabBarW, tabBarH, outerRadius, 1.0f, outerStrokeLeft, outerStrokeRight, 0.0f); - } - - drawRoundedRectGlow( - innerX, - innerY, - innerW, - innerH, - innerRadius, - 10.0f, - scaleAlpha(theme().accentSoft(), 0.30f * eased) - ); - drawRoundedRectGradient(innerX, innerY, innerW, innerH, innerRadius, activeLeft, activeRight, 0.0f); - drawRoundedRectStrokeGradient(innerX, innerY, innerW, innerH, innerRadius, 1.0f, activeStrokeLeft, activeStrokeRight, 0.0f); - - for (int i = 0; i < tabs.size(); i++) { - float x = tabX[i]; - float w = tabW[i]; - ClickGuiTabEntry tab = tabs.get(i); - boolean active = tab.id().equals(activeTabId); - boolean hovered = !closingForExit && mouseX >= x && mouseX <= x + w && mouseY >= y && mouseY <= y + tabBarH; - if (i > 0) { - float sepH = tabBarH - outerPad * 3.4f; - float sepY = y + (tabBarH - sepH) * 0.5f; - drawRect(x, sepY, 1.0f, sepH, scaleAlpha(theme().strokeSoft(), 0.32f * eased)); - } - int textCol = active ? theme().textPrimary() : theme().textMuted(); - if (!active && hovered) { - textCol = mixColor(textCol, theme().textPrimary(), 0.55f); - } - textCol = scaleAlpha(textCol, eased); - float textH = textHeight(tabFont, TAB_FONT); - float textY = y + (tabBarH - textH) * 0.5f - 0.35f; - float labelW = textWidth(tabFont, tab.label(), TAB_FONT); - float textX = x + (w - labelW) * 0.5f; - drawText(tabFont, tab.label(), textX, textY, TAB_FONT, textCol, false); - } - } - } - - private static boolean handleTabClick(float mx, float my) { - if (!isInputReady()) return false; - if (mx < tabBarX || mx > tabBarX + tabBarW || my < tabBarY || my > tabBarY + tabBarH) return false; - List tabs = currentTabs(); - ensureActiveTab(tabs); - for (int i = 0; i < tabs.size(); i++) { - float x = tabX[i]; - float w = tabW[i]; - if (mx >= x && mx <= x + w && my >= tabBarY && my <= tabBarY + tabBarH) { - ClickGuiTabEntry tab = tabs.get(i); - if (!activeTabId.equals(tab.id())) { - ClickGuiSection previous = getActiveSection(); - activeTabId = tab.id(); - previous.onDeselected(); - ClickGuiSearch.deactivate(); - clearInlineText(); - closeTextEditor(false); - getActiveSection().onSelected(); - } - return true; - } - } - return false; - } - - private static ClickGuiSection getActiveSection() { - List tabs = currentTabs(); - ensureActiveTab(tabs); - for (ClickGuiTabEntry tab : tabs) { - if (tab.id().equals(activeTabId)) { - return tab.section(); - } - } - activeTabId = MODULES_TAB_ID; - return MODULES_SECTION; - } - - private static boolean isSettingsTabActive() { - return SETTINGS_TAB_ID.equals(activeTabId); - } - - private static List currentTabs() { - List addonSections = ClickGuiSectionManager.sections(); - ArrayList out = new ArrayList<>(2 + addonSections.size()); - out.add(new ClickGuiTabEntry(MODULES_TAB_ID, "Modules", MODULES_SECTION)); - out.add(new ClickGuiTabEntry(SETTINGS_TAB_ID, "Settings", SETTINGS_SECTION)); - for (ClickGuiSectionManager.Entry entry : addonSections) { - out.add(new ClickGuiTabEntry(entry.id(), entry.label(), entry.section())); - } - return out; - } - - private static void ensureActiveTab(List tabs) { - for (ClickGuiTabEntry tab : tabs) { - if (tab.id().equals(activeTabId)) { - return; - } - } - activeTabId = MODULES_TAB_ID; + ClickGuiTopLayer.renderModulesPreview(x, y, w, h); } public static ClickGuiIslandState islandState() { - List tabs = currentTabs(); - ensureActiveTab(tabs); - String activeLabel = tabs.isEmpty() ? "" : tabs.get(0).label(); - for (ClickGuiTabEntry tab : tabs) { - if (tab.id().equals(activeTabId)) { - activeLabel = tab.label(); - break; - } - } - return new ClickGuiIslandState( - tabBarX, - tabBarY, - tabBarW, - tabBarH, - tabAnimX, - tabAnimW, - lifecycleAnim, - activeLabel, - tabs.size(), - picker != null || protocolHeuristicsEditor != null - ); - } - - private static void ensureTabCapacity(int size) { - if (tabX.length >= size && tabW.length >= size) return; - tabX = Arrays.copyOf(tabX, size); - tabW = Arrays.copyOf(tabW, size); - } - - private static float easeOutCubic(float t) { - t = Math.max(0.0f, Math.min(1.0f, t)); - float inv = 1.0f - t; - return 1.0f - inv * inv * inv; + return ClickGuiTabState.islandState(); } public static TextRenderer getInterRegular() { - if (interRegular == null) { - interRegular = Fonts.renderer("Inter", FontInfo.Type.Regular, TextRenderer.get()); - } - return interRegular; + return ClickGuiFonts.getInterRegular(); } public static Renderer2D currentRenderer() { - return renderer; + return ClickGuiFonts.currentRenderer(); } public static TextRenderer getInterMedium() { - if (interMedium == null) { - interMedium = Fonts.renderer("InterMedium", FontInfo.Type.Regular, getInterRegular()); - } - return interMedium; + return ClickGuiFonts.getInterMedium(); } public static TextRenderer getIosevkaRegular() { - return getSfMedium(); + return ClickGuiFonts.getIosevkaRegular(); } public static TextRenderer getSfMedium() { - if (onestMedium == null) { - onestMedium = Fonts.renderer("OnestMedium", FontInfo.Type.Regular, TextRenderer.get()); - } - return onestMedium; + return ClickGuiFonts.getSfMedium(); } public static TextRenderer getSfProDisplaySemibold() { - if (onestBold == null) { - onestBold = Fonts.renderer("OnestBold", FontInfo.Type.Regular, getInterMedium()); - } - return onestBold; + return ClickGuiFonts.getSfProDisplaySemibold(); } public static TextRenderer getMonsterratRegular() { - if (monsterratRegular == null) { - monsterratRegular = Fonts.renderer("Monsterrat", FontInfo.Type.Regular, TextRenderer.get()); - } - return monsterratRegular; + return ClickGuiFonts.getMonsterratRegular(); } public static int framebufferWidth() { - return fbWidth; + return ClickGuiRenderEngine.framebufferWidth(); } public static int framebufferHeight() { - return fbHeight; + return ClickGuiRenderEngine.framebufferHeight(); } public static float getAnimAlpha() { - return 1f; + return ClickGuiRenderEngine.getAnimAlpha(); } public static float getMouseX() { - return mouseX; + return ClickGuiRenderEngine.getMouseX(); } public static float getMouseY() { - return mouseY; + return ClickGuiRenderEngine.getMouseY(); } public static int mixColor(int from, int to, float t) { - t = Math.max(0f, Math.min(1f, t)); - int a = (int) (((from >>> 24) & 0xFF) * (1 - t) + ((to >>> 24) & 0xFF) * t); - int r = (int) (((from >>> 16) & 0xFF) * (1 - t) + ((to >>> 16) & 0xFF) * t); - int g = (int) (((from >>> 8) & 0xFF) * (1 - t) + ((to >>> 8) & 0xFF) * t); - int b = (int) (((from) & 0xFF) * (1 - t) + ((to) & 0xFF) * t); - return (a << 24) | (r << 16) | (g << 8) | b; + return ClickGuiDrawHelpers.mixColor(from, to, t); } public static int scaleAlpha(int color, float factor) { - int a = (color >>> 24) & 0xFF; - int na = (int) (a * Math.max(0f, Math.min(1f, factor))); - return (color & 0x00FFFFFF) | (na << 24); + return ClickGuiDrawHelpers.scaleAlpha(color, factor); } public static int withAlpha(int color, int alpha) { - int a = Math.max(0, Math.min(255, alpha)); - return (color & 0x00FFFFFF) | (a << 24); + return ClickGuiDrawHelpers.withAlpha(color, alpha); } public static float setRenderAlphaMultiplier(float alpha) { - float previous = renderAlphaMultiplier; - renderAlphaMultiplier = Math.max(0.0f, Math.min(1.0f, alpha)); - return previous; + return ClickGuiDrawHelpers.setRenderAlphaMultiplier(alpha); } public static float getRenderAlphaMultiplier() { - return renderAlphaMultiplier; + return ClickGuiDrawHelpers.getRenderAlphaMultiplier(); } public static void restoreRenderAlphaMultiplier(float previous) { - renderAlphaMultiplier = Math.max(0.0f, Math.min(1.0f, previous)); - } - - private static int applyAlpha(int argb) { - if (renderAlphaMultiplier >= 0.999f) return argb; - int a = (argb >>> 24) & 0xFF; - int na = Math.round(a * renderAlphaMultiplier); - return (argb & 0x00FFFFFF) | ((na & 0xFF) << 24); + ClickGuiDrawHelpers.restoreRenderAlphaMultiplier(previous); } public static float scaleForSize(float size) { - return size / 18.0f; + return ClickGuiTextBatch.scaleForSize(size); } public static float textWidth(TextRenderer tr, String text, float size) { - if (tr == null || text == null || text.isEmpty()) return 0f; - TextMeasureKey key = new TextMeasureKey(tr, Float.floatToIntBits(size), text); - Float cached = TEXT_WIDTH_CACHE.get(key); - if (cached != null) return cached; - float scale = scaleForSize(size); - tr.begin(scale, true, false); - try { - float width = (float) tr.getWidth(text, false); - TEXT_WIDTH_CACHE.put(key, width); - return width; - } finally { - tr.end(); - } + return ClickGuiTextBatch.textWidth(tr, text, size); } public static float textHeight(TextRenderer tr, float size) { - if (tr == null) return 0f; - TextHeightKey key = new TextHeightKey(tr, Float.floatToIntBits(size)); - Float cached = TEXT_HEIGHT_CACHE.get(key); - if (cached != null) return cached; - float scale = scaleForSize(size); - tr.begin(scale, true, false); - try { - float height = (float) tr.getHeight(false); - TEXT_HEIGHT_CACHE.put(key, height); - return height; - } finally { - tr.end(); - } + return ClickGuiTextBatch.textHeight(tr, size); } public static void beginTextBatch() { - if (textBatchActive) return; - textBatchActive = true; - TEXT_BATCH.clear(); + ClickGuiTextBatch.beginTextBatch(); } public static void endTextBatch() { - if (!textBatchActive) return; - textBatchActive = false; - if (TEXT_BATCH.isEmpty()) return; - - java.util.LinkedHashMap> groups = new java.util.LinkedHashMap<>(); - for (TextBatchItem item : TEXT_BATCH) { - TextBatchKey key = new TextBatchKey(item.renderer, Float.floatToIntBits(item.size), item.shadow); - java.util.ArrayList list = groups.get(key); - if (list == null) { - list = new java.util.ArrayList<>(); - groups.put(key, list); - } - list.add(item); - } - - for (var entry : groups.entrySet()) { - TextBatchKey key = entry.getKey(); - TextRenderer tr = key.renderer; - if (tr == null) continue; - float size = Float.intBitsToFloat(key.sizeBits); - float scale = scaleForSize(size); - tr.begin(scale, false, false); - for (TextBatchItem item : entry.getValue()) { - tr.render(item.text, item.x, item.y, new RenderColor(item.argb), item.shadow); - } - tr.end(); - } - - TEXT_BATCH.clear(); + ClickGuiTextBatch.endTextBatch(); } public static void drawText(TextRenderer tr, String text, float x, float y, float size, int argb, boolean shadow) { - if (tr == null || text == null || text.isEmpty()) return; - argb = applyAlpha(argb); - if (((argb >>> 24) & 0xFF) <= 0) return; - if (textBatchActive) { - TEXT_BATCH.add(new TextBatchItem(tr, text, x, y, size, argb, shadow)); - return; - } - float scale = scaleForSize(size); - tr.begin(scale, false, false); - tr.render(text, x, y, new RenderColor(argb), shadow); - tr.end(); + ClickGuiTextBatch.drawText(tr, text, x, y, size, argb, shadow); } public static String fitText(TextRenderer tr, String text, float size, float maxWidth) { - if (text == null) return ""; - if (maxWidth <= 0f) return text; - String trimmed = text; - float w = textWidth(tr, trimmed, size); - if (w <= maxWidth) return trimmed; - while (trimmed.length() > 1 && textWidth(tr, trimmed + "...", size) > maxWidth) { - trimmed = trimmed.substring(0, trimmed.length() - 1); - } - return trimmed + "..."; + return ClickGuiTextBatch.fitText(tr, text, size, maxWidth); } public static List wrapText(TextRenderer tr, String text, float size, float maxWidth, int maxLines) { - ArrayList lines = new ArrayList<>(); - if (text == null || text.isBlank()) { - lines.add(""); - return lines; - } - if (maxLines <= 1 || maxWidth <= 0f) { - lines.add(fitText(tr, text, size, maxWidth)); - return lines; - } - - String remaining = normalizeSpaces(text); - while (!remaining.isEmpty() && lines.size() < maxLines) { - if (lines.size() == maxLines - 1) { - lines.add(fitText(tr, remaining, size, maxWidth)); - break; - } - if (textWidth(tr, remaining, size) <= maxWidth) { - lines.add(remaining); - break; - } - - int split = bestWrapIndex(tr, remaining, size, maxWidth); - String line = remaining.substring(0, split).trim(); - if (line.isEmpty()) { - lines.add(fitText(tr, remaining, size, maxWidth)); - break; - } - lines.add(line); - remaining = remaining.substring(split).trim(); - } - - if (lines.isEmpty()) { - lines.add(fitText(tr, text, size, maxWidth)); - } - return lines; - } - - private static int bestWrapIndex(TextRenderer tr, String text, float size, float maxWidth) { - int bestSpace = -1; - for (int i = 0; i < text.length(); i++) { - if (!Character.isWhitespace(text.charAt(i))) continue; - String candidate = text.substring(0, i).trim(); - if (!candidate.isEmpty() && textWidth(tr, candidate, size) <= maxWidth) { - bestSpace = i; - continue; - } - if (bestSpace >= 0) break; - } - if (bestSpace >= 0) return bestSpace; - - String fitted = fitText(tr, text, size, maxWidth); - if (fitted.endsWith("...")) { - fitted = fitted.substring(0, Math.max(1, fitted.length() - 3)); - } - return Math.max(1, Math.min(text.length(), fitted.length())); - } - - private static String normalizeSpaces(String text) { - if (text == null) return ""; - String trimmed = text.trim(); - if (trimmed.isEmpty()) return ""; - - StringBuilder sb = new StringBuilder(trimmed.length()); - boolean lastSpace = false; - for (int i = 0; i < trimmed.length(); i++) { - char c = trimmed.charAt(i); - if (Character.isWhitespace(c)) { - if (!lastSpace) { - sb.append(' '); - lastSpace = true; - } - } else { - sb.append(c); - lastSpace = false; - } - } - return sb.toString(); - } - - private static String normalizeInlineText(String text) { - if (text == null) return ""; - String normalized = text.replace("\r\n", "\n").replace('\r', '\n'); - return normalized.replace('\n', ' '); + return ClickGuiTextBatch.wrapText(tr, text, size, maxWidth, maxLines); } public static void drawRoundedRect(float x, float y, float w, float h, float radius, int argb) { - if (renderer == null) return; - argb = applyAlpha(argb); - if (((argb >>> 24) & 0xFF) <= 0) return; - renderer.roundedRect(x, y, w, h, radius, 1.1f, argb); + ClickGuiDrawHelpers.drawRoundedRect(x, y, w, h, radius, argb); } public static void drawRoundedRectStroke(float x, float y, float w, float h, float radius, float thickness, int argb) { - if (renderer == null) return; - argb = applyAlpha(argb); - if (((argb >>> 24) & 0xFF) <= 0) return; - renderer.roundedRectStroke(x, y, w, h, radius, 1.1f, thickness, argb); + ClickGuiDrawHelpers.drawRoundedRectStroke(x, y, w, h, radius, thickness, argb); } public static void drawRoundedRectGlow(float x, float y, float w, float h, float radius, float glow, int argb) { - if (renderer == null) return; - argb = applyAlpha(argb); - if (((argb >>> 24) & 0xFF) <= 0) return; - renderer.roundedRectGlow(x, y, w, h, radius, 1.1f, glow, argb); + ClickGuiDrawHelpers.drawRoundedRectGlow(x, y, w, h, radius, glow, argb); } public static void drawRoundedRectShadow(float x, float y, float w, float h, float radius, float softness, float spread, int argb) { - if (renderer == null) return; - argb = applyAlpha(argb); - if (((argb >>> 24) & 0xFF) <= 0) return; - renderer.roundedRectShadow(x, y, w, h, radius, softness, spread, argb); + ClickGuiDrawHelpers.drawRoundedRectShadow(x, y, w, h, radius, softness, spread, argb); } public static void drawRoundedRectGradient(float x, float y, float w, float h, float radius, int startArgb, int endArgb, float angleDeg) { - if (renderer == null) return; - startArgb = applyAlpha(startArgb); - endArgb = applyAlpha(endArgb); - if (((startArgb >>> 24) & 0xFF) <= 0 && ((endArgb >>> 24) & 0xFF) <= 0) return; - renderer.roundedRectGradient(x, y, w, h, radius, 1.1f, startArgb, endArgb, angleDeg); + ClickGuiDrawHelpers.drawRoundedRectGradient(x, y, w, h, radius, startArgb, endArgb, angleDeg); } public static void drawRoundedRectStrokeGradient(float x, float y, float w, float h, float radius, float thickness, int startArgb, int endArgb, float angleDeg) { - if (renderer == null) return; - startArgb = applyAlpha(startArgb); - endArgb = applyAlpha(endArgb); - if (((startArgb >>> 24) & 0xFF) <= 0 && ((endArgb >>> 24) & 0xFF) <= 0) return; - renderer.roundedRectStrokeGradient(x, y, w, h, radius, 1.1f, thickness, startArgb, endArgb, angleDeg); + ClickGuiDrawHelpers.drawRoundedRectStrokeGradient(x, y, w, h, radius, thickness, startArgb, endArgb, angleDeg); } public static void drawRoundedRectCorners(float x, float y, float w, float h, float radiusTL, float radiusTR, float radiusBR, float radiusBL, int argb) { - if (renderer == null) return; - argb = applyAlpha(argb); - if (((argb >>> 24) & 0xFF) <= 0) return; - renderer.roundedRectCorners(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, 1.1f, argb); + ClickGuiDrawHelpers.drawRoundedRectCorners(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, argb); } public static void drawRect(float x, float y, float w, float h, int argb) { - if (renderer == null) return; - argb = applyAlpha(argb); - if (((argb >>> 24) & 0xFF) <= 0) return; - renderer.quad(x, y, w, h, argb); + ClickGuiDrawHelpers.drawRect(x, y, w, h, argb); } public static void flushRenderer() { - if (renderer == null) return; - if (Renderer2D.isBatching()) { - Renderer2D.flushBatch(); - } else { - renderer.begin(); - } + ClickGuiDrawHelpers.flushRenderer(); } public static void drawGradientRect(float x, float y, float w, float h, int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { - if (renderer == null) return; - cTopLeft = applyAlpha(cTopLeft); - cTopRight = applyAlpha(cTopRight); - cBottomRight = applyAlpha(cBottomRight); - cBottomLeft = applyAlpha(cBottomLeft); - renderer.quadGradient(x, y, w, h, cTopLeft, cTopRight, cBottomRight, cBottomLeft); + ClickGuiDrawHelpers.drawGradientRect(x, y, w, h, cTopLeft, cTopRight, cBottomRight, cBottomLeft); } public static void drawCircle(float cx, float cy, float r, int argb) { - if (renderer == null) return; - argb = applyAlpha(argb); - if (((argb >>> 24) & 0xFF) <= 0) return; - renderer.circle(cx, cy, r, argb); + ClickGuiDrawHelpers.drawCircle(cx, cy, r, argb); } public static void drawLine(float x1, float y1, float x2, float y2, int argb) { - if (renderer == null) return; - argb = applyAlpha(argb); - if (((argb >>> 24) & 0xFF) <= 0) return; - renderer.line(x1, y1, x2, y2, argb); + ClickGuiDrawHelpers.drawLine(x1, y1, x2, y2, argb); } public static void drawBlur(float x, float y, float w, float h, float radius, int argb, float alpha) { - alpha *= renderAlphaMultiplier; - alpha = AnimationUtility.clamp(alpha * clickGuiBlurDensityScale(), 0.0f, 1.0f); - if (alpha <= 0.01f) return; - float quality = clickGuiBlurQuality(); - float brightness = 1.0f; - Renderer2D.COLOR.blurRect(x, y, w, h, radius, quality, brightness, alpha, 0xFFFFFF); + ClickGuiDrawHelpers.drawBlur(x, y, w, h, radius, argb, alpha); } public static void drawGlass(float x, float y, float w, float h, float radius, float alpha) { - if (renderer == null) return; - alpha *= renderAlphaMultiplier; - if (alpha <= 0.01f) return; - - float pad = 5f; - float gx = x - pad; - float gy = y - pad; - float gw = w + pad * 2f; - float gh = h + pad * 2f; - float gr = Math.max(0f, radius + pad); - float blurAlpha = AnimationUtility.clamp(alpha * clickGuiGlassBlurScale(), 0.0f, 1.0f); - float scale = Math.max(0.75f, gr / 10.0f); - - Renderer2D.COLOR.blurRect(gx, gy, gw, gh, gr, clickGuiBlurQuality(), 1.0f, blurAlpha, 0xFFFFFF); - - renderer.liquidGlassRect( - gx, gy, gw, gh, gr, - 15.0f * scale, - 0xFFFFFFFF, - alpha, - blurAlpha, - -18.0f, - 1.0f, - 0.78f, - 0.52f, - 0.190f * alpha, - 0.0f - ); + ClickGuiDrawHelpers.drawGlass(x, y, w, h, radius, alpha); } public static float clickGuiBlurQuality() { - return 27.35f; + return ClickGuiDrawHelpers.clickGuiBlurQuality(); } public static float clickGuiBlurDensityScale() { - return 1.16f; + return ClickGuiDrawHelpers.clickGuiBlurDensityScale(); } public static float clickGuiGlassBlurScale() { - return 1.28f; + return ClickGuiDrawHelpers.clickGuiGlassBlurScale(); } public static int getColorClipboard() { - return colorClipboard; + return ClickGuiDrawHelpers.getColorClipboard(); } public static void setColorClipboard(int argb) { - colorClipboard = argb; + ClickGuiDrawHelpers.setColorClipboard(argb); } public static void beginKeyBind(Object owner) { - clearInlineText(); - waitingForKey = true; - keyBindOwner = owner; - pendingBindKeys.clear(); - ClickGuiSearch.deactivate(); - ClickGuiSounds.bindingStart(); + ClickGuiKeyBindManager.beginKeyBind(owner); } public static void finishKeyBind() { - waitingForKey = false; - keyBindOwner = null; - pendingBindKeys.clear(); - } - - private static void addPendingKey(int keyCode, int scancode) { - int code = KeyUtil.fromKeyInput(keyCode, scancode); - if (code == KeyUtil.NONE) return; - pendingBindKeys.add(code); - } - - private static void addPendingMouseButton(int button) { - if (button < GLFW.GLFW_MOUSE_BUTTON_1 || button > GLFW.GLFW_MOUSE_BUTTON_LAST) return; - pendingBindKeys.add(KeyUtil.mouseButtonToCode(button)); - } - - private static void submitKeySelection(Set keys) { - if (keys == null || keys.isEmpty()) { - submitKeySelection((String) null); - return; - } - submitKeySelection(KeyUtil.comboToString(keys)); - } - - private static void submitKeySelection(String combo) { - if (keyBindOwner instanceof KeyBindSetting ks) { - ks.onKeySelected(combo); - } else if (keyBindOwner instanceof FunctionBindSetting fs) { - fs.onKeySelected(combo); - } + ClickGuiKeyBindManager.finishKeyBind(); } public static String getPendingBindDisplay() { - if (!waitingForKey) return null; - return pendingBindKeys.isEmpty() ? "..." : KeyUtil.comboToString(pendingBindKeys); + return ClickGuiKeyBindManager.getPendingBindDisplay(); } public static void openTextEditor(TextEditorOwner owner, String title, String seedText, float anchorX, float anchorY, float anchorW) { - if (owner == null) return; - clearInlineText(); - if (seedText == null) seedText = ""; - ClickGuiSearch.deactivate(); - textEditor = new ClickGuiTextEditorState(owner, title, seedText, anchorX, anchorY, anchorW); + ClickGuiEditorManager.openTextEditor(owner, title, seedText, anchorX, anchorY, anchorW); } public static void closeTextEditor(boolean save) { - if (textEditor == null) return; - if (save) textEditor.save(); - textEditor = null; + ClickGuiEditorManager.closeTextEditor(save); } public static void renderTextEditor(int fbw, int fbh) { - if (textEditor == null) return; - textEditor.render(fbw, fbh); - } - - private static void renderPicker(int fbw, int fbh) { - if (picker == null) return; - picker.render(fbw, fbh); + ClickGuiEditorManager.renderTextEditor(fbw, fbh); } public static void toggleInlineText(TextSetting owner) { - if (owner == null) return; - if (inlineTextOwner == owner) { - clearInlineText(); - return; - } - inlineTextOwner = owner; - inlineTextBuffer = new StringBuilder(owner.getEditorText()); - ClickGuiSearch.deactivate(); + ClickGuiEditorManager.toggleInlineText(owner); } public static boolean isInlineTextActive() { - return inlineTextOwner != null; + return ClickGuiEditorManager.isInlineTextActive(); } public static boolean isInlineTextOwner(TextSetting owner) { - return inlineTextOwner == owner; + return ClickGuiEditorManager.isInlineTextOwner(owner); } public static String getInlineText(TextSetting owner) { - if (owner == null) return ""; - if (inlineTextOwner == owner && inlineTextBuffer != null) { - return inlineTextBuffer.toString(); - } - return owner.getEditorText(); + return ClickGuiEditorManager.getInlineText(owner); } public static void updateInlineTextBounds(TextSetting owner, float x, float y, float w, float h) { - if (inlineTextOwner != owner) return; - inlineTextX = x; - inlineTextY = y; - inlineTextW = w; - inlineTextH = h; - } - - private static void finishInlineText(boolean save) { - if (inlineTextOwner == null || inlineTextBuffer == null) { - clearInlineText(); - return; - } - if (save) { - inlineTextOwner.applyEditorText(inlineTextBuffer.toString()); - } - clearInlineText(); - } - - private static void clearInlineText() { - inlineTextOwner = null; - inlineTextBuffer = null; - inlineTextX = inlineTextY = inlineTextW = inlineTextH = 0f; - } - - private static void inlineBackspace() { - if (inlineTextBuffer == null) return; - int len = inlineTextBuffer.length(); - if (len <= 0) return; - inlineTextBuffer.deleteCharAt(len - 1); - } - - private static void inlinePaste() { - if (inlineTextBuffer == null) return; - String clip = ClipboardUtil.get(); - if (clip == null || clip.isEmpty()) return; - inlineTextBuffer.append(normalizeInlineText(clip)); + ClickGuiEditorManager.updateInlineTextBounds(owner, x, y, w, h); } public static boolean isTextEditorActive() { - return textEditor != null; + return ClickGuiEditorManager.isTextEditorActive(); } public static boolean isPickerActive() { - return picker != null || protocolHeuristicsEditor != null; + return ClickGuiEditorManager.isPickerActive(); } public static boolean isBlockingModuleKeybinds() { - if (!ModuleManager.isEnabled("clickgui")) return false; - if (waitingForKey) return true; - if (textEditor != null) return true; - if (inlineTextOwner != null) return true; - if (protocolHeuristicsEditor != null) return true; - if (picker != null && picker.isListening()) return true; - return ClickGuiSearch.isActive(); + return ClickGuiEditorManager.isBlockingModuleKeybinds(); } public static void processPickerIcons(GuiGraphicsExtractor ctx) { - if (pickerIcons.isEmpty()) { - pickerIconScissorActive = false; - return; - } - if (ctx == null) { - pickerIcons.clear(); - pickerIconScissorActive = false; - return; - } - if (!(ctx instanceof IGuiGraphics accessor)) { - pickerIcons.clear(); - pickerIconScissorActive = false; - return; - } - Minecraft mc = MC; - if (mc == null) { - pickerIcons.clear(); - pickerIconScissorActive = false; - return; - } - int seed = 0; - for (PickerIcon icon : pickerIcons) { - ItemStack stack = icon.stack(); - if (stack == null || stack.isEmpty()) continue; - boolean clippedGlobal = false; - boolean clippedLocal = false; - if (icon.hasGlobalClip()) { - clippedGlobal = ScissorFunction.pushRaw( - icon.globalClipX(), - icon.globalClipY(), - icon.globalClipW(), - icon.globalClipH() - ); - } - if (icon.hasClip()) { - clippedLocal = ScissorFunction.pushRaw( - icon.clipX(), - icon.clipY(), - icon.clipW(), - icon.clipH() - ); - } - Renderer2D.COLOR.begin(); - // Picker screen uses beginUnscaledLogical(), so queued icon coordinates are already logical. - Renderer2D.COLOR.item( - stack, - icon.x(), - icon.y(), - icon.scale(), - seed++, - Renderer2D.ITEM_OVERLAY_ALL, - null - ); - Renderer2D.COLOR.render(); - if (clippedLocal) ScissorFunction.pop(); - if (clippedGlobal) ScissorFunction.pop(); - } - pickerIcons.clear(); - pickerIconScissorActive = false; + ClickGuiPickerIconManager.processPickerIcons(ctx); } public static void beginPickerIconScissor(float x, float y, float w, float h) { - pickerIconScissorActive = true; - pickerIconScissorX = x; - pickerIconScissorY = y; - pickerIconScissorW = w; - pickerIconScissorH = h; + ClickGuiPickerIconManager.beginPickerIconScissor(x, y, w, h); } public static void endPickerIconScissor() { - pickerIconScissorActive = false; + ClickGuiPickerIconManager.endPickerIconScissor(); } public static void queuePickerIcon(ItemStack stack, float x, float y, float scale) { - if (stack == null || stack.isEmpty()) return; - pickerIcons.add(new PickerIcon( - stack, - x, - y, - scale, - currentPickerIconScissorActive(), - pickerIconScissorX, - pickerIconScissorY, - pickerIconScissorW, - pickerIconScissorH, - false, - 0f, - 0f, - 0f, - 0f - )); + ClickGuiPickerIconManager.queuePickerIcon(stack, x, y, scale); } public static void queuePickerIcon(ItemStack stack, @@ -1718,142 +492,39 @@ public enum ClickGuiRenderer { float clipY, float clipW, float clipH) { - if (stack == null || stack.isEmpty()) return; - boolean hasClip = clipW > 0f && clipH > 0f; - pickerIcons.add(new PickerIcon( - stack, - x, - y, - scale, - currentPickerIconScissorActive(), - pickerIconScissorX, - pickerIconScissorY, - pickerIconScissorW, - pickerIconScissorH, - hasClip, - clipX, - clipY, - clipW, - clipH - )); - } - - private static boolean currentPickerIconScissorActive() { - return pickerIconScissorActive && pickerIconScissorW > 0f && pickerIconScissorH > 0f; + ClickGuiPickerIconManager.queuePickerIcon(stack, x, y, scale, clipX, clipY, clipW, clipH); } public static void openClickGuiScreen() { - if (MC == null) return; - if (ClientScreen.current() != null) return; - if (mainScreen == null) { - mainScreen = new ClickGuiScreen(); - } - ClickGuiSounds.guiOpen(); - ClientScreen.show(MC, mainScreen); + ClickGuiScreenManager.openClickGuiScreen(); } public static void captureMainScreen() { - if (MC != null && ClientScreen.current() instanceof ClickGuiScreen cs) { - mainScreen = cs; - } + ClickGuiScreenManager.captureMainScreen(); } public static ClickGuiScreen ensureMainScreen() { - if (mainScreen == null) { - mainScreen = new ClickGuiScreen(); - } - return mainScreen; - } - - private static void openPickerScreen() { - if (MC == null) return; - if (ClientScreen.current() instanceof ClickGuiScreen cs) { - mainScreen = cs; - } - if (pickerScreen == null) { - pickerScreen = new ClickGuiPickerScreen(); - } - ClientScreen.show(MC, pickerScreen); + return ClickGuiScreenManager.ensureMainScreen(); } public static void clearScreens() { - mainScreen = null; - pickerScreen = null; - SettingsTabRuntime.clearScreens(); - } - - public static void shutdownForRuntime() { - finishCloseImmediately(); - clearInlineText(); - clearPicker(); - textEditor = null; - pickerIcons.clear(); - pendingBindKeys.clear(); - waitingForKey = false; - keyBindOwner = null; - renderer = null; - init = false; + ClickGuiScreenManager.clearScreens(); } public static void openPicker(TextListSetting owner, String title, TextListSetting.PickerMode mode) { - if (owner == null) return; - clearInlineText(); - ClickGuiSearch.deactivate(); - protocolHeuristicsEditor = null; - picker = new ClickGuiPickerState(owner, title, mode); - openPickerScreen(); + ClickGuiScreenManager.openPicker(owner, title, mode); } public static void openProtocolHeuristicsEditor(ProtocolHeuristicsSetting owner, String title) { - if (owner == null) return; - clearInlineText(); - ClickGuiSearch.deactivate(); - picker = null; - protocolHeuristicsEditor = new CombatProtocolHeuristicsEditorState(owner, title); - openPickerScreen(); + ClickGuiScreenManager.openProtocolHeuristicsEditor(owner, title); } public static void closeProtocolHeuristicsEditor() { - closePicker(); + ClickGuiScreenManager.closeProtocolHeuristicsEditor(); } public static void closePickerScreen() { - closePicker(); - } - - private static void closePicker() { - picker = null; - protocolHeuristicsEditor = null; - textEditor = null; - if (MC != null && ClientScreen.current() instanceof ClickGuiPickerScreen) { - if (mainScreen == null) { - mainScreen = new ClickGuiScreen(); - } - ClientScreen.show(MC, mainScreen); - } - } - - private static void clearPicker() { - picker = null; - protocolHeuristicsEditor = null; - } - - private static synchronized void requestConfigSave() { - Runnable task = () -> { - try { - ConfigSerializer.saveAll(); - } catch (Throwable ignored) { - } - }; - - if (pendingSaveTask == null || pendingSaveTask.isDone()) { - pendingSaveTask = CompletableFuture.runAsync(task); - } else { - pendingSaveTask = pendingSaveTask.thenRunAsync(task); - } - } - - private record ClickGuiTabEntry(String id, String label, ClickGuiSection section) { + ClickGuiScreenManager.closePickerScreen(); } public record ClickGuiIslandState(float tabBarX, @@ -1868,33 +539,4 @@ public enum ClickGuiRenderer { boolean pickerActive) { } - private record TextBatchItem(TextRenderer renderer, String text, float x, float y, float size, int argb, - boolean shadow) { - } - - private record TextBatchKey(TextRenderer renderer, int sizeBits, boolean shadow) { - } - - private record TextMeasureKey(TextRenderer renderer, int sizeBits, String text) { - } - - private record TextHeightKey(TextRenderer renderer, int sizeBits) { - } - - private record PickerIcon(ItemStack stack, - float x, - float y, - float scale, - boolean hasGlobalClip, - float globalClipX, - float globalClipY, - float globalClipW, - float globalClipH, - boolean hasClip, - float clipX, - float clipY, - float clipW, - float clipH) { - } - } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiScreen.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiScreen.java index e8643c6..fe5be5c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiScreen.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiScreen.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiScreenManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiScreenManager.java new file mode 100644 index 0000000..7594cdc --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiScreenManager.java @@ -0,0 +1,116 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.config.ConfigSerializer; +import dev.loki.lovisual.features.gui.clickgui.picker.ClickGuiPickerState; +import dev.loki.lovisual.features.gui.clickgui.protocol.CombatProtocolHeuristicsEditorState; +import dev.loki.lovisual.features.gui.clickgui.sections.settings.SettingsTabRuntime; +import dev.loki.lovisual.features.gui.clickgui.settings.ProtocolHeuristicsSetting; +import dev.loki.lovisual.features.gui.clickgui.settings.TextListSetting; +import dev.loki.lovisual.util.screen.ClientScreen; +import dev.loki.lovisual.util.wav.ClickGuiSounds; + +import java.util.concurrent.CompletableFuture; + +final class ClickGuiScreenManager { + + private ClickGuiScreenManager() { + } + + static void openClickGuiScreen() { + if (ClickGuiRenderer.MC == null) return; + if (ClientScreen.current() != null) return; + if (ClickGuiRenderer.mainScreen == null) { + ClickGuiRenderer.mainScreen = new ClickGuiScreen(); + } + ClickGuiSounds.guiOpen(); + ClientScreen.show(ClickGuiRenderer.MC, ClickGuiRenderer.mainScreen); + } + + static void captureMainScreen() { + if (ClickGuiRenderer.MC != null && ClientScreen.current() instanceof ClickGuiScreen cs) { + ClickGuiRenderer.mainScreen = cs; + } + } + + static ClickGuiScreen ensureMainScreen() { + if (ClickGuiRenderer.mainScreen == null) { + ClickGuiRenderer.mainScreen = new ClickGuiScreen(); + } + return ClickGuiRenderer.mainScreen; + } + + private static void openPickerScreen() { + if (ClickGuiRenderer.MC == null) return; + if (ClientScreen.current() instanceof ClickGuiScreen cs) { + ClickGuiRenderer.mainScreen = cs; + } + if (ClickGuiRenderer.pickerScreen == null) { + ClickGuiRenderer.pickerScreen = new ClickGuiPickerScreen(); + } + ClientScreen.show(ClickGuiRenderer.MC, ClickGuiRenderer.pickerScreen); + } + + static void clearScreens() { + ClickGuiRenderer.mainScreen = null; + ClickGuiRenderer.pickerScreen = null; + SettingsTabRuntime.clearScreens(); + } + + static void openPicker(TextListSetting owner, String title, TextListSetting.PickerMode mode) { + if (owner == null) return; + ClickGuiEditorManager.clearInlineText(); + ClickGuiSearch.deactivate(); + ClickGuiRenderer.protocolHeuristicsEditor = null; + ClickGuiRenderer.picker = new ClickGuiPickerState(owner, title, mode); + openPickerScreen(); + } + + static void openProtocolHeuristicsEditor(ProtocolHeuristicsSetting owner, String title) { + if (owner == null) return; + ClickGuiEditorManager.clearInlineText(); + ClickGuiSearch.deactivate(); + ClickGuiRenderer.picker = null; + ClickGuiRenderer.protocolHeuristicsEditor = new CombatProtocolHeuristicsEditorState(owner, title); + openPickerScreen(); + } + + static void closeProtocolHeuristicsEditor() { + closePicker(); + } + + static void closePickerScreen() { + closePicker(); + } + + static void closePicker() { + ClickGuiRenderer.picker = null; + ClickGuiRenderer.protocolHeuristicsEditor = null; + ClickGuiRenderer.textEditor = null; + if (ClickGuiRenderer.MC != null && ClientScreen.current() instanceof ClickGuiPickerScreen) { + if (ClickGuiRenderer.mainScreen == null) { + ClickGuiRenderer.mainScreen = new ClickGuiScreen(); + } + ClientScreen.show(ClickGuiRenderer.MC, ClickGuiRenderer.mainScreen); + } + } + + static void clearPicker() { + ClickGuiRenderer.picker = null; + ClickGuiRenderer.protocolHeuristicsEditor = null; + } + + static synchronized void requestConfigSave() { + Runnable task = () -> { + try { + ConfigSerializer.saveAll(); + } catch (Throwable ignored) { + } + }; + + if (ClickGuiRenderer.pendingSaveTask == null || ClickGuiRenderer.pendingSaveTask.isDone()) { + ClickGuiRenderer.pendingSaveTask = CompletableFuture.runAsync(task); + } else { + ClickGuiRenderer.pendingSaveTask = ClickGuiRenderer.pendingSaveTask.thenRunAsync(task); + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiSearch.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiSearch.java index 1c32484..cc5ec2a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiSearch.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiSearch.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTabBar.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTabBar.java new file mode 100644 index 0000000..db23e64 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTabBar.java @@ -0,0 +1,195 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.features.gui.hud.nondraggable.impl.DynamicIsland; +import dev.loki.lovisual.render.engine.renderer.RenderWarpStack; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; + +import java.util.List; + +import static dev.loki.lovisual.features.theme.Theme.theme; + +final class ClickGuiTabBar { + + private ClickGuiTabBar() { + } + + static void layout(int fbw, int fbh) { + List tabs = ClickGuiTabState.currentTabs(); + ClickGuiTabState.ensureActiveTab(tabs); + float contentMarginX = 28f; + float contentTop = 52f; + float contentBottom = 18f; + ClickGuiRenderer.modulesAreaX = contentMarginX; + ClickGuiRenderer.modulesAreaY = contentTop; + ClickGuiRenderer.modulesAreaW = Math.max(1f, fbw - contentMarginX * 2f); + ClickGuiRenderer.modulesAreaH = Math.max(1f, fbh - contentTop - contentBottom); + for (ClickGuiTabEntry tab : tabs) { + tab.section().layout(ClickGuiRenderer.modulesAreaX, ClickGuiRenderer.modulesAreaY, ClickGuiRenderer.modulesAreaW, ClickGuiRenderer.modulesAreaH); + } + + ClickGuiRenderer.tabBarH = ClickGuiRenderer.TAB_HEIGHT; + ClickGuiRenderer.tabBarY = 10f; + ClickGuiTabState.ensureTabCapacity(tabs.size()); + float totalTabs = 0f; + for (int t = 0; t < tabs.size(); t++) { + float wTab = ClickGuiTextBatch.textWidth(ClickGuiFonts.getSfProDisplaySemibold(), tabs.get(t).label(), ClickGuiRenderer.TAB_FONT) + ClickGuiRenderer.TAB_PAD_X * 2f; + if (wTab < ClickGuiRenderer.TAB_MIN_W) wTab = ClickGuiRenderer.TAB_MIN_W; + ClickGuiRenderer.tabW[t] = wTab; + totalTabs += wTab; + } + if (!tabs.isEmpty()) { + totalTabs += ClickGuiRenderer.TAB_GAP * (tabs.size() - 1); + } + ClickGuiRenderer.tabBarW = totalTabs; + ClickGuiRenderer.tabBarX = (fbw - totalTabs) * 0.5f; + float cx = ClickGuiRenderer.tabBarX; + for (int t = 0; t < tabs.size(); t++) { + ClickGuiRenderer.tabX[t] = cx; + cx += ClickGuiRenderer.tabW[t] + ClickGuiRenderer.TAB_GAP; + } + + int activeIdx = 0; + for (int t = 0; t < tabs.size(); t++) { + if (tabs.get(t).id().equals(ClickGuiRenderer.activeTabId)) { + activeIdx = t; + break; + } + } + ClickGuiRenderer.tabTargetX = ClickGuiRenderer.tabX[activeIdx]; + ClickGuiRenderer.tabTargetW = ClickGuiRenderer.tabW[activeIdx]; + if (!ClickGuiRenderer.tabAnimInit) { + ClickGuiRenderer.tabAnimX = ClickGuiRenderer.tabTargetX; + ClickGuiRenderer.tabAnimW = ClickGuiRenderer.tabTargetW; + ClickGuiRenderer.tabAnimInit = true; + ClickGuiRenderer.lastTabAnimNs = System.nanoTime(); + } + } + + static void updateTabAnim(long now) { + float dt = (now - ClickGuiRenderer.lastTabAnimNs) / 1_000_000_000f; + ClickGuiRenderer.lastTabAnimNs = now; + if (dt < 0f) dt = 0f; + float speed = 16f; + float step = Math.min(1f, dt * speed); + ClickGuiRenderer.tabAnimX += (ClickGuiRenderer.tabTargetX - ClickGuiRenderer.tabAnimX) * step; + ClickGuiRenderer.tabAnimW += (ClickGuiRenderer.tabTargetW - ClickGuiRenderer.tabAnimW) * step; + } + + static void drawTabs() { + float eased = ClickGuiTabState.easeOutCubic(ClickGuiRenderer.lifecycleAnim); + if (eased <= 0.001f) return; + List tabs = ClickGuiTabState.currentTabs(); + ClickGuiTabState.ensureActiveTab(tabs); + if (tabs.isEmpty()) return; + boolean islandShell = DynamicIsland.shouldOwnClickGuiTabShell(); + + TextRenderer tabFont = ClickGuiFonts.getSfProDisplaySemibold(); + float y = ClickGuiRenderer.tabBarY - (1.0f - eased) * 18.0f; + float outerRadius = ClickGuiRenderer.tabBarH * 0.5f; + float outerPad = 4.0f; + float innerX = ClickGuiRenderer.tabAnimX + outerPad; + float innerY = y + outerPad; + float innerW = Math.max(1.0f, ClickGuiRenderer.tabAnimW - outerPad * 2.0f); + float innerH = Math.max(1.0f, ClickGuiRenderer.tabBarH - outerPad * 2.0f); + float innerRadius = innerH * 0.5f; + + int outerLeft = ClickGuiDrawHelpers.scaleAlpha(ClickGuiDrawHelpers.mixColor(theme().surface(), theme().windowBg(), 0.34f), eased); + int outerRight = ClickGuiDrawHelpers.scaleAlpha(ClickGuiDrawHelpers.mixColor(theme().surfaceHover(), theme().windowBg(), 0.22f), eased); + int outerStrokeLeft = ClickGuiDrawHelpers.scaleAlpha(ClickGuiDrawHelpers.mixColor(theme().strokeSoft(), theme().accentSoft(), 0.18f), 0.72f * eased); + int outerStrokeRight = ClickGuiDrawHelpers.scaleAlpha(ClickGuiDrawHelpers.mixColor(theme().strokeSoft(), theme().textPrimary(), 0.08f), 0.58f * eased); + + int activeLeft = ClickGuiDrawHelpers.scaleAlpha(ClickGuiDrawHelpers.mixColor(theme().accentSoft(), theme().accent(), 0.18f), eased); + int activeRight = ClickGuiDrawHelpers.scaleAlpha(ClickGuiDrawHelpers.mixColor(theme().accent(), theme().textPrimary(), 0.08f), eased); + int activeStrokeLeft = ClickGuiDrawHelpers.scaleAlpha(ClickGuiDrawHelpers.mixColor(theme().accentSoft(), theme().textPrimary(), 0.20f), 0.88f * eased); + int activeStrokeRight = ClickGuiDrawHelpers.scaleAlpha(theme().accent(), 0.92f * eased); + + try (RenderWarpStack.Scope ignored = Renderer2D.pushPerspectiveWarp( + ClickGuiRenderer.tabBarX, + y, + ClickGuiRenderer.tabBarW, + ClickGuiRenderer.tabBarH, + 0.0f, + -5.0f * (1.0f - eased), + 0.0f, + 3.2f, + 0.80f, + 0.965f + 0.035f * eased + )) { + if (!islandShell) { + ClickGuiDrawHelpers.drawRoundedRectShadow( + ClickGuiRenderer.tabBarX, + y, + ClickGuiRenderer.tabBarW, + ClickGuiRenderer.tabBarH, + outerRadius, + 10.0f, + 1.5f, + ClickGuiDrawHelpers.scaleAlpha(0xCC000000, 0.34f * eased) + ); + ClickGuiDrawHelpers.drawRoundedRectGradient(ClickGuiRenderer.tabBarX, y, ClickGuiRenderer.tabBarW, ClickGuiRenderer.tabBarH, outerRadius, outerLeft, outerRight, 0.0f); + ClickGuiDrawHelpers.drawRoundedRectStrokeGradient(ClickGuiRenderer.tabBarX, y, ClickGuiRenderer.tabBarW, ClickGuiRenderer.tabBarH, outerRadius, 1.0f, outerStrokeLeft, outerStrokeRight, 0.0f); + } + + ClickGuiDrawHelpers.drawRoundedRectGlow( + innerX, + innerY, + innerW, + innerH, + innerRadius, + 10.0f, + ClickGuiDrawHelpers.scaleAlpha(theme().accentSoft(), 0.30f * eased) + ); + ClickGuiDrawHelpers.drawRoundedRectGradient(innerX, innerY, innerW, innerH, innerRadius, activeLeft, activeRight, 0.0f); + ClickGuiDrawHelpers.drawRoundedRectStrokeGradient(innerX, innerY, innerW, innerH, innerRadius, 1.0f, activeStrokeLeft, activeStrokeRight, 0.0f); + + for (int i = 0; i < tabs.size(); i++) { + float x = ClickGuiRenderer.tabX[i]; + float w = ClickGuiRenderer.tabW[i]; + ClickGuiTabEntry tab = tabs.get(i); + boolean active = tab.id().equals(ClickGuiRenderer.activeTabId); + boolean hovered = !ClickGuiRenderer.closingForExit && ClickGuiRenderer.mouseX >= x && ClickGuiRenderer.mouseX <= x + w && ClickGuiRenderer.mouseY >= y && ClickGuiRenderer.mouseY <= y + ClickGuiRenderer.tabBarH; + if (i > 0) { + float sepH = ClickGuiRenderer.tabBarH - outerPad * 3.4f; + float sepY = y + (ClickGuiRenderer.tabBarH - sepH) * 0.5f; + ClickGuiDrawHelpers.drawRect(x, sepY, 1.0f, sepH, ClickGuiDrawHelpers.scaleAlpha(theme().strokeSoft(), 0.32f * eased)); + } + int textCol = active ? theme().textPrimary() : theme().textMuted(); + if (!active && hovered) { + textCol = ClickGuiDrawHelpers.mixColor(textCol, theme().textPrimary(), 0.55f); + } + textCol = ClickGuiDrawHelpers.scaleAlpha(textCol, eased); + float textH = ClickGuiTextBatch.textHeight(tabFont, ClickGuiRenderer.TAB_FONT); + float textY = y + (ClickGuiRenderer.tabBarH - textH) * 0.5f - 0.35f; + float labelW = ClickGuiTextBatch.textWidth(tabFont, tab.label(), ClickGuiRenderer.TAB_FONT); + float textX = x + (w - labelW) * 0.5f; + ClickGuiTextBatch.drawText(tabFont, tab.label(), textX, textY, ClickGuiRenderer.TAB_FONT, textCol, false); + } + } + } + + static boolean handleTabClick(float mx, float my) { + if (!ClickGuiLifecycle.isInputReady()) return false; + if (mx < ClickGuiRenderer.tabBarX || mx > ClickGuiRenderer.tabBarX + ClickGuiRenderer.tabBarW || my < ClickGuiRenderer.tabBarY || my > ClickGuiRenderer.tabBarY + ClickGuiRenderer.tabBarH) return false; + List tabs = ClickGuiTabState.currentTabs(); + ClickGuiTabState.ensureActiveTab(tabs); + for (int i = 0; i < tabs.size(); i++) { + float x = ClickGuiRenderer.tabX[i]; + float w = ClickGuiRenderer.tabW[i]; + if (mx >= x && mx <= x + w && my >= ClickGuiRenderer.tabBarY && my <= ClickGuiRenderer.tabBarY + ClickGuiRenderer.tabBarH) { + ClickGuiTabEntry tab = tabs.get(i); + if (!ClickGuiRenderer.activeTabId.equals(tab.id())) { + dev.loki.lovisual.features.gui.clickgui.sections.ClickGuiSection previous = ClickGuiTabState.getActiveSection(); + ClickGuiRenderer.activeTabId = tab.id(); + previous.onDeselected(); + ClickGuiSearch.deactivate(); + ClickGuiEditorManager.clearInlineText(); + ClickGuiEditorManager.closeTextEditor(false); + ClickGuiTabState.getActiveSection().onSelected(); + } + return true; + } + } + return false; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTabState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTabState.java new file mode 100644 index 0000000..d6ebcf4 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTabState.java @@ -0,0 +1,86 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.addon.ClickGuiSectionManager; +import dev.loki.lovisual.features.gui.clickgui.sections.ClickGuiSection; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +final class ClickGuiTabState { + + private ClickGuiTabState() { + } + + static ClickGuiSection getActiveSection() { + List tabs = currentTabs(); + ensureActiveTab(tabs); + for (ClickGuiTabEntry tab : tabs) { + if (tab.id().equals(ClickGuiRenderer.activeTabId)) { + return tab.section(); + } + } + ClickGuiRenderer.activeTabId = ClickGuiRenderer.MODULES_TAB_ID; + return ClickGuiRenderer.MODULES_SECTION; + } + + static boolean isSettingsTabActive() { + return ClickGuiRenderer.SETTINGS_TAB_ID.equals(ClickGuiRenderer.activeTabId); + } + + static List currentTabs() { + List addonSections = ClickGuiSectionManager.sections(); + ArrayList out = new ArrayList<>(2 + addonSections.size()); + out.add(new ClickGuiTabEntry(ClickGuiRenderer.MODULES_TAB_ID, "Modules", ClickGuiRenderer.MODULES_SECTION)); + out.add(new ClickGuiTabEntry(ClickGuiRenderer.SETTINGS_TAB_ID, "Settings", ClickGuiRenderer.SETTINGS_SECTION)); + for (ClickGuiSectionManager.Entry entry : addonSections) { + out.add(new ClickGuiTabEntry(entry.id(), entry.label(), entry.section())); + } + return out; + } + + static void ensureActiveTab(List tabs) { + for (ClickGuiTabEntry tab : tabs) { + if (tab.id().equals(ClickGuiRenderer.activeTabId)) { + return; + } + } + ClickGuiRenderer.activeTabId = ClickGuiRenderer.MODULES_TAB_ID; + } + + static void ensureTabCapacity(int size) { + if (ClickGuiRenderer.tabX.length >= size && ClickGuiRenderer.tabW.length >= size) return; + ClickGuiRenderer.tabX = Arrays.copyOf(ClickGuiRenderer.tabX, size); + ClickGuiRenderer.tabW = Arrays.copyOf(ClickGuiRenderer.tabW, size); + } + + static float easeOutCubic(float t) { + t = Math.max(0.0f, Math.min(1.0f, t)); + float inv = 1.0f - t; + return 1.0f - inv * inv * inv; + } + + static ClickGuiRenderer.ClickGuiIslandState islandState() { + List tabs = currentTabs(); + ensureActiveTab(tabs); + String activeLabel = tabs.isEmpty() ? "" : tabs.get(0).label(); + for (ClickGuiTabEntry tab : tabs) { + if (tab.id().equals(ClickGuiRenderer.activeTabId)) { + activeLabel = tab.label(); + break; + } + } + return new ClickGuiRenderer.ClickGuiIslandState( + ClickGuiRenderer.tabBarX, + ClickGuiRenderer.tabBarY, + ClickGuiRenderer.tabBarW, + ClickGuiRenderer.tabBarH, + ClickGuiRenderer.tabAnimX, + ClickGuiRenderer.tabAnimW, + ClickGuiRenderer.lifecycleAnim, + activeLabel, + tabs.size(), + ClickGuiRenderer.picker != null || ClickGuiRenderer.protocolHeuristicsEditor != null + ); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTextBatch.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTextBatch.java new file mode 100644 index 0000000..96cde69 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTextBatch.java @@ -0,0 +1,194 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.text.TextRenderer; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +final class ClickGuiTextBatch { + + private ClickGuiTextBatch() { + } + + static float scaleForSize(float size) { + return size / 18.0f; + } + + static float textWidth(TextRenderer tr, String text, float size) { + if (tr == null || text == null || text.isEmpty()) return 0f; + TextMeasureKey key = new TextMeasureKey(tr, Float.floatToIntBits(size), text); + Float cached = ClickGuiRenderer.TEXT_WIDTH_CACHE.get(key); + if (cached != null) return cached; + float scale = scaleForSize(size); + tr.begin(scale, true, false); + try { + float width = (float) tr.getWidth(text, false); + ClickGuiRenderer.TEXT_WIDTH_CACHE.put(key, width); + return width; + } finally { + tr.end(); + } + } + + static float textHeight(TextRenderer tr, float size) { + if (tr == null) return 0f; + TextHeightKey key = new TextHeightKey(tr, Float.floatToIntBits(size)); + Float cached = ClickGuiRenderer.TEXT_HEIGHT_CACHE.get(key); + if (cached != null) return cached; + float scale = scaleForSize(size); + tr.begin(scale, true, false); + try { + float height = (float) tr.getHeight(false); + ClickGuiRenderer.TEXT_HEIGHT_CACHE.put(key, height); + return height; + } finally { + tr.end(); + } + } + + static void beginTextBatch() { + if (ClickGuiRenderer.textBatchActive) return; + ClickGuiRenderer.textBatchActive = true; + ClickGuiRenderer.TEXT_BATCH.clear(); + } + + static void endTextBatch() { + if (!ClickGuiRenderer.textBatchActive) return; + ClickGuiRenderer.textBatchActive = false; + if (ClickGuiRenderer.TEXT_BATCH.isEmpty()) return; + + LinkedHashMap> groups = new LinkedHashMap<>(); + for (TextBatchItem item : ClickGuiRenderer.TEXT_BATCH) { + TextBatchKey key = new TextBatchKey(item.renderer(), Float.floatToIntBits(item.size()), item.shadow()); + ArrayList list = groups.get(key); + if (list == null) { + list = new ArrayList<>(); + groups.put(key, list); + } + list.add(item); + } + + for (var entry : groups.entrySet()) { + TextBatchKey key = entry.getKey(); + TextRenderer tr = key.renderer(); + if (tr == null) continue; + float size = Float.intBitsToFloat(key.sizeBits()); + float scale = scaleForSize(size); + tr.begin(scale, false, false); + for (TextBatchItem item : entry.getValue()) { + tr.render(item.text(), item.x(), item.y(), new RenderColor(item.argb()), item.shadow()); + } + tr.end(); + } + + ClickGuiRenderer.TEXT_BATCH.clear(); + } + + static void drawText(TextRenderer tr, String text, float x, float y, float size, int argb, boolean shadow) { + if (tr == null || text == null || text.isEmpty()) return; + argb = ClickGuiDrawHelpers.applyAlpha(argb); + if (((argb >>> 24) & 0xFF) <= 0) return; + if (ClickGuiRenderer.textBatchActive) { + ClickGuiRenderer.TEXT_BATCH.add(new TextBatchItem(tr, text, x, y, size, argb, shadow)); + return; + } + float scale = scaleForSize(size); + tr.begin(scale, false, false); + tr.render(text, x, y, new RenderColor(argb), shadow); + tr.end(); + } + + static String fitText(TextRenderer tr, String text, float size, float maxWidth) { + if (text == null) return ""; + if (maxWidth <= 0f) return text; + String trimmed = text; + float w = textWidth(tr, trimmed, size); + if (w <= maxWidth) return trimmed; + while (trimmed.length() > 1 && textWidth(tr, trimmed + "...", size) > maxWidth) { + trimmed = trimmed.substring(0, trimmed.length() - 1); + } + return trimmed + "..."; + } + + static List wrapText(TextRenderer tr, String text, float size, float maxWidth, int maxLines) { + ArrayList lines = new ArrayList<>(); + if (text == null || text.isBlank()) { + lines.add(""); + return lines; + } + if (maxLines <= 1 || maxWidth <= 0f) { + lines.add(fitText(tr, text, size, maxWidth)); + return lines; + } + + String remaining = normalizeSpaces(text); + while (!remaining.isEmpty() && lines.size() < maxLines) { + if (lines.size() == maxLines - 1) { + lines.add(fitText(tr, remaining, size, maxWidth)); + break; + } + if (textWidth(tr, remaining, size) <= maxWidth) { + lines.add(remaining); + break; + } + + int split = bestWrapIndex(tr, remaining, size, maxWidth); + String line = remaining.substring(0, split).trim(); + if (line.isEmpty()) { + lines.add(fitText(tr, remaining, size, maxWidth)); + break; + } + lines.add(line); + remaining = remaining.substring(split).trim(); + } + + if (lines.isEmpty()) { + lines.add(fitText(tr, text, size, maxWidth)); + } + return lines; + } + + private static int bestWrapIndex(TextRenderer tr, String text, float size, float maxWidth) { + int bestSpace = -1; + for (int i = 0; i < text.length(); i++) { + if (!Character.isWhitespace(text.charAt(i))) continue; + String candidate = text.substring(0, i).trim(); + if (!candidate.isEmpty() && textWidth(tr, candidate, size) <= maxWidth) { + bestSpace = i; + continue; + } + if (bestSpace >= 0) break; + } + if (bestSpace >= 0) return bestSpace; + + String fitted = fitText(tr, text, size, maxWidth); + if (fitted.endsWith("...")) { + fitted = fitted.substring(0, Math.max(1, fitted.length() - 3)); + } + return Math.max(1, Math.min(text.length(), fitted.length())); + } + + private static String normalizeSpaces(String text) { + if (text == null) return ""; + String trimmed = text.trim(); + if (trimmed.isEmpty()) return ""; + + StringBuilder sb = new StringBuilder(trimmed.length()); + boolean lastSpace = false; + for (int i = 0; i < trimmed.length(); i++) { + char c = trimmed.charAt(i); + if (Character.isWhitespace(c)) { + if (!lastSpace) { + sb.append(' '); + lastSpace = true; + } + } else { + sb.append(c); + lastSpace = false; + } + } + return sb.toString(); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTopLayer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTopLayer.java new file mode 100644 index 0000000..e1a16c8 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/ClickGuiTopLayer.java @@ -0,0 +1,83 @@ +package dev.loki.lovisual.features.gui.clickgui; + +import dev.loki.lovisual.features.gui.clickgui.sections.settings.SettingsTabRuntime; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; +import dev.loki.lovisual.render.engine.core.RenderPhase; +import dev.loki.lovisual.render.engine.core.RenderPhaseScope; +import dev.loki.lovisual.render.engine.core.ViewportContext; +import dev.loki.lovisual.render.engine.math.HudScale; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.SystemCursor; +import dev.loki.lovisual.util.screen.ClientScreen; +import net.minecraft.client.gui.GuiGraphicsExtractor; + +final class ClickGuiTopLayer { + + private ClickGuiTopLayer() { + } + + static boolean shouldRenderAsTopLayer() { + return ClickGuiRenderer.MC != null && (ClickGuiLifecycle.isLifecycleActive() + || ClientScreen.current() instanceof ClickGuiScreen + || ClientScreen.current() instanceof ClickGuiPickerScreen + || ClientScreen.current() instanceof ClickGuiEditorScreen); + } + + static void renderTopLayer(GuiGraphicsExtractor ctx, float tickDelta) { + if (!shouldRenderAsTopLayer()) return; + + LoVisualRenderSystem.ensureFrameContext(); + ViewportContext.beginUnscaledLogical(ctx); + try (RenderPhaseScope phaseScope = LoVisualRenderSystem.phase(RenderPhase.SCREEN_TOP, "2d:clickgui_top")) { + SystemCursor.beginFrame(ctx); + try { + Renderer2D.COLOR.begin(); + if (ClientScreen.current() instanceof ClickGuiEditorScreen) { + renderEditor(Renderer2D.COLOR, TextRenderer.get(), ctx, tickDelta); + } else { + ClickGuiRenderEngine.renderEngine(Renderer2D.COLOR, TextRenderer.get(), ctx, tickDelta); + } + Renderer2D.COLOR.render(); + if (ClientScreen.current() instanceof ClickGuiPickerScreen) { + ClickGuiPickerIconManager.processPickerIcons(ctx); + } + } finally { + SystemCursor.endFrame(); + } + } + ViewportContext.end(ctx); + } + + static void renderEditor(Renderer2D rendererIn, TextRenderer fallback, GuiGraphicsExtractor ctx, float tickDelta) { + if (ClickGuiRenderer.MC == null || ClickGuiRenderer.MC.getWindow() == null) return; + ClickGuiLifecycle.init(); + ClickGuiRenderer.renderer = rendererIn; + int fbw = ClickGuiRenderer.MC.getWindow().getWidth(); + int fbh = ClickGuiRenderer.MC.getWindow().getHeight(); + int vw = Math.max(1, Math.round(HudScale.virtualWidth(fbw, fbh))); + int vh = Math.max(1, Math.round(HudScale.virtualHeight(fbw, fbh))); + ClickGuiRenderer.fbWidth = vw; + ClickGuiRenderer.fbHeight = vh; + SystemCursor.beginFrame(ctx); + try { + SettingsTabRuntime.renderEditor(rendererIn, fallback, ctx, tickDelta, vw, vh, ClickGuiRenderer.mouseX, ClickGuiRenderer.mouseY); + } finally { + SystemCursor.endFrame(); + } + } + + static void renderModulesPreview(float x, float y, float w, float h) { + if (ClickGuiRenderer.renderer == null) return; + ClickGuiLifecycle.init(); + float pad = 8f; + float areaX = x + pad; + float areaY = y + pad; + float areaW = Math.max(1f, w - pad * 2f); + float areaH = Math.max(1f, h - pad * 2f); + ClickGuiRenderer.MODULES_SECTION.layout(areaX, areaY, areaW, areaH); + float mx = -10_000f; + float my = -10_000f; + ClickGuiRenderer.MODULES_SECTION.render(mx, my); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/editor/ClickGuiTextEditorState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/editor/ClickGuiTextEditorState.java index 462d6e2..708930e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/editor/ClickGuiTextEditorState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/editor/ClickGuiTextEditorState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuCategory.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuCategory.java index 8375f0c..1e56dc6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuCategory.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuCategory.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuPanel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuPanel.java index 688b594..b109fc9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuPanel.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuPanel.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuResolver.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuResolver.java index 42d68eb..600500c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuResolver.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuResolver.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuScreen.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuScreen.java index 2d810c5..ab5633d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuScreen.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuScreen.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuStyle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuStyle.java index 59634c5..4bb5b10 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuStyle.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/modules/ModulesMenuStyle.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/MenuScreen.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/MenuScreen.java index 02c1e40..38a3749 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/MenuScreen.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/MenuScreen.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/MenuSettingsResolver.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/MenuSettingsResolver.java index ed6bd45..a21d05e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/MenuSettingsResolver.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/MenuSettingsResolver.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/SettingsGuiPalette.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/SettingsGuiPalette.java index e313b16..4c5a53e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/SettingsGuiPalette.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/SettingsGuiPalette.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/category/CategoryComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/category/CategoryComponent.java index 7d3d023..f4f45e1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/category/CategoryComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/category/CategoryComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigDiffPanelComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigDiffPanelComponent.java new file mode 100644 index 0000000..8179793 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigDiffPanelComponent.java @@ -0,0 +1,400 @@ +/* + * 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.features.gui.clickgui.layout.screen.settings.implement.config; + +import dev.loki.lovisual.config.profile.ConfigProfileDiff; +import dev.loki.lovisual.config.profile.ConfigProfileMeta; +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.SettingsGuiPalette; +import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.render.LayoutRender2D; +import dev.loki.lovisual.features.gui.clickgui.util.ClickGuiI18n; +import dev.loki.lovisual.features.gui.clickgui.util.ClickGuiMath; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.svg.SvgRenderOptions; +import dev.loki.lovisual.render.helpers.ScissorFunction; +import dev.loki.lovisual.render.helpers.SystemCursor; + +public final class ConfigDiffPanelComponent { + private float scroll; + private float smoothedScroll; + private float openAnim; + private boolean openTarget; + private float saveHoverAnim; + private float closeHoverAnim; + private boolean scrollbarVisible; + private boolean draggingScrollbar; + private float scrollbarX; + private float scrollbarY; + private float scrollbarW; + private float scrollbarH; + private float scrollbarThumbY; + private float scrollbarThumbH; + private float scrollbarMaxScroll; + private float scrollbarDragOffset; + private float panelX; + private float panelY; + private float panelW; + private float panelH; + private float saveX; + private float saveY; + private float saveW; + private float saveH; + private float closeX; + private float closeY; + private float closeW; + private float closeH; + + private static String stringify(Object value) { + if (value == null) return "null"; + String text = String.valueOf(value); + if (text.length() > 34) text = text.substring(0, 31) + "..."; + return text; + } + + public void resetScroll() { + scroll = 0f; + smoothedScroll = 0f; + draggingScrollbar = false; + } + + public void open() { + openTarget = true; + } + + public void close() { + openTarget = false; + draggingScrollbar = false; + } + + public boolean isActive() { + return openTarget || openAnim > 0.001f; + } + + public boolean isOpen() { + return openTarget; + } + + public void render(float x, + float y, + float w, + float h, + ConfigProfileMeta selected, + ConfigProfileDiff diff, + String error, + float scale, + SettingsGuiPalette palette) { + float dt = AnimationUtility.deltaTime(); + float target = openTarget ? 1f : 0f; + openAnim = AnimationUtility.approach(openAnim, target, dt, openTarget ? 12f : 13f); + openAnim = AnimationUtility.snap(openAnim, target, 0.01f); + if (!openTarget && openAnim <= 0.001f) { + openAnim = 0f; + return; + } + + float reveal = AnimationUtility.easeOutBack(openAnim, 0.85f); + x += (1f - reveal) * 10f * scale; + panelX = x; + panelY = y; + panelW = w; + panelH = h; + + int shadow = LayoutRender2D.alpha(palette.panelShadow(), openAnim); + int blurTint = LayoutRender2D.alpha(palette.panelBlurTint(), openAnim); + int bgLeft = LayoutRender2D.alpha(palette.panelBgLeft(), openAnim); + int bgRight = LayoutRender2D.alpha(palette.panelBgRight(), openAnim); + int stroke = LayoutRender2D.alpha(palette.panelStroke(), openAnim); + int divider = LayoutRender2D.alpha(palette.panelDivider(), openAnim); + int text = LayoutRender2D.alpha(palette.panelText(), openAnim); + + LayoutRender2D.roundedSoftShadow(x, y, w, h, 8f * scale, 8f * scale, 0.018f, shadow); + ClickGuiRenderer.drawBlur(x, y, w, h, 8f * scale, blurTint, (200f / 255f) * openAnim); + LayoutRender2D.roundedQuad( + x, y, w, h, 8f * scale, + bgLeft, + bgRight, + bgRight, + bgLeft + ); + LayoutRender2D.roundedStroke(x, y, w, h, 8f * scale, 0.1f * scale, stroke); + LayoutRender2D.rect(x, y + 22f * scale, w, 0.5f * scale, divider); + + ClickGuiRenderer.drawText( + ClickGuiRenderer.getInterRegular(), + ClickGuiI18n.tr("clickgui.settings.config.diff.title", "Diff Settings"), + x + 10f * scale, + y + 9f * scale, + 7.5f * scale, + text, + false + ); + renderHeaderActions(x, y, w, mx(), my(), scale, palette); + + float bodyX = x + 8f * scale; + float bodyY = y + 27f * scale; + float bodyW = w - 16f * scale; + float bodyH = h - 31f * scale; + float contentH = contentHeight(selected, diff, error, scale); + float maxScroll = Math.max(0f, contentH - bodyH); + updateScrollbarMetrics(bodyX, bodyY, bodyW, bodyH, maxScroll, scale); + if (draggingScrollbar) scrollToMouse(ClickGuiRenderer.getMouseY()); + + scroll = ClickGuiMath.clamp(scroll, -maxScroll, 0f); + smoothedScroll = AnimationUtility.approach(smoothedScroll, scroll, draggingScrollbar ? 0.55f : 0.2f); + smoothedScroll = AnimationUtility.snap(smoothedScroll, scroll, draggingScrollbar ? 0.01f : 0.05f); + boolean clipped = ScissorFunction.pushRaw(bodyX, bodyY, bodyW, bodyH); + renderBody(bodyX, bodyY + smoothedScroll, bodyW - (scrollbarVisible ? 7f * scale : 0f), bodyY, bodyH, selected, diff, error, scale, palette); + if (clipped) ScissorFunction.pop(); + + renderScrollbar(scale, palette); + } + + public HeaderAction headerAction(float mx, float my, int button) { + if (!openTarget || openAnim <= 0.01f) return HeaderAction.NONE; + if (button != 0) return HeaderAction.NONE; + if (ClickGuiMath.insideRect(mx, my, closeX, closeY, closeW, closeH)) return HeaderAction.CLOSE; + if (ClickGuiMath.insideRect(mx, my, saveX, saveY, saveW, saveH)) return HeaderAction.SAVE; + return HeaderAction.NONE; + } + + public boolean mousePressedScrollbar(float mx, float my, int button) { + if (!openTarget || openAnim <= 0.01f) return false; + if (button != 0) return false; + if (!isScrollbarHovered(mx, my)) return false; + draggingScrollbar = true; + scrollbarDragOffset = ClickGuiMath.insideRect(mx, my, scrollbarX, scrollbarThumbY, scrollbarW, scrollbarThumbH) + ? my - scrollbarThumbY + : scrollbarThumbH * 0.5f; + scrollToMouse(my); + return true; + } + + public void mouseReleased(int button) { + if (button == 0) draggingScrollbar = false; + } + + public boolean scroll(float mx, float my, double amount) { + if (!openTarget || openAnim <= 0.01f) return false; + if (!ClickGuiMath.insideRect(mx, my, panelX, panelY, panelW, panelH)) return false; + if (!scrollbarVisible && scrollbarMaxScroll <= 0.5f) return true; + scroll += (float) (amount * 20f); + return true; + } + + private void renderHeaderActions(float x, + float y, + float w, + float mx, + float my, + float scale, + SettingsGuiPalette palette) { + float btn = 16f * scale; + closeX = x + w - btn - 4f * scale; + closeY = y + 3f * scale; + closeW = btn; + closeH = btn; + saveX = closeX - btn - scale; + saveY = closeY; + saveW = btn; + saveH = btn; + + boolean saveHover = ClickGuiMath.insideRect(mx, my, saveX, saveY, saveW, saveH); + boolean closeHover = ClickGuiMath.insideRect(mx, my, closeX, closeY, closeW, closeH); + saveHoverAnim = AnimationUtility.approach(saveHoverAnim, saveHover ? 1f : 0f, AnimationUtility.deltaTime(), 10f); + closeHoverAnim = AnimationUtility.approach(closeHoverAnim, closeHover ? 1f : 0f, AnimationUtility.deltaTime(), 10f); + + drawHeaderIcon(saveX, saveY, btn, "save", saveHoverAnim, scale, palette); + LayoutRender2D.rect(closeX - scale, y + 6f * scale, 0.5f * scale, 10f * scale, LayoutRender2D.alpha(palette.panelDivider(), openAnim)); + drawHeaderIcon(closeX, closeY, btn, "x", closeHoverAnim, scale, palette); + if (saveHover || closeHover) SystemCursor.set(SystemCursor.CursorType.MOVE); + } + + private void drawHeaderIcon(float x, + float y, + float size, + String icon, + float hover, + float scale, + SettingsGuiPalette palette) { + boolean save = "save".equals(icon); + int bgA = LayoutRender2D.alpha(SettingsGuiPalette.mix(palette.moduleCardTop(), save ? palette.menuCategorySelectedLeft() : palette.menuCategoryHoverLeft(), 0.14f + hover * 0.22f), openAnim); + int bgB = LayoutRender2D.alpha(SettingsGuiPalette.mix(palette.moduleCardTopStrong(), save ? palette.menuCategorySelectedRight() : palette.menuCategoryHoverRight(), 0.12f + hover * 0.18f), openAnim); + int bgC = LayoutRender2D.alpha(SettingsGuiPalette.mix(SettingsGuiPalette.darken(palette.moduleCardTopStrong(), 0.12f), save ? palette.menuCategorySelectedRight() : palette.menuCategoryHoverRight(), 0.08f + hover * 0.15f), openAnim); + LayoutRender2D.roundedSoftShadow( + x, + y + 0.4f * scale, + size, + size, + 3.5f * scale, + 4f * scale, + 0.015f + hover * 0.02f, + LayoutRender2D.alpha(palette.menuShadow(), openAnim * (0.50f + hover * 0.45f)) + ); + LayoutRender2D.roundedQuad(x, y, size, size, 3.5f * scale, bgA, bgB, bgC, bgA); + LayoutRender2D.roundedStrokeQuad( + x, + y, + size, + size, + 3.5f * scale, + (0.35f + hover * 0.18f) * scale, + LayoutRender2D.alpha(palette.moduleDividerStart(), openAnim * (0.54f + hover * 0.24f)), + LayoutRender2D.alpha(palette.moduleDividerEnd(), openAnim * (0.62f + hover * 0.24f)), + LayoutRender2D.alpha(palette.moduleDividerEnd(), openAnim * (0.48f + hover * 0.20f)), + LayoutRender2D.alpha(palette.moduleDividerStart(), openAnim * (0.54f + hover * 0.24f)) + ); + + int color = LayoutRender2D.alpha(SettingsGuiPalette.mix(palette.panelText(), palette.menuCategoryText(), 0.16f + hover * 0.38f), openAnim); + Renderer2D.COLOR.svg( + icon, + x + 4.6f * scale, + y + 4.6f * scale, + size - 9.2f * scale, + size - 9.2f * scale, + SvgRenderOptions.overrideColor(color) + ); + } + + private float mx() { + return ClickGuiRenderer.getMouseX(); + } + + private float my() { + return ClickGuiRenderer.getMouseY(); + } + + private void renderBody(float x, + float y, + float w, + float clipY, + float clipH, + ConfigProfileMeta selected, + ConfigProfileDiff diff, + String error, + float scale, + SettingsGuiPalette palette) { + if (error != null && !error.isBlank()) { + drawLine(ClickGuiI18n.tr("clickgui.settings.config.diff.error", "Diff error: %s", error), x, y, 7.2f * scale, palette.panelMuted()); + return; + } + if (selected == null) { + drawLine(ClickGuiI18n.tr("clickgui.settings.config.diff.select_config", "Select a config and press diff."), x, y, 7.2f * scale, palette.panelMuted()); + return; + } + if (diff == null) { + drawLine(selected.name(), x, y, 7.2f * scale, palette.panelText()); + drawLine(ClickGuiI18n.tr("clickgui.settings.config.diff.not_loaded", "Diff is not loaded."), x, y + 10f * scale, 7.2f * scale, palette.panelMuted()); + return; + } + if (diff.isEmpty()) { + drawLine(selected.name(), x, y, 7.2f * scale, palette.panelText()); + drawLine(ClickGuiI18n.tr("clickgui.settings.config.diff.no_differences", "No differences."), x, y + 11f * scale, 7.2f * scale, palette.panelMuted()); + return; + } + + float cy = y; + drawVisibleLine(ClickGuiRenderer.fitText(ClickGuiRenderer.getInterMedium(), selected.name(), 7.4f * scale, w), x, cy, 7.4f * scale, palette.panelText(), clipY, clipH, scale); + cy += 11f * scale; + drawVisibleLine(ClickGuiI18n.tr("clickgui.settings.config.diff.changed", "Changes: %s", diff.valueChangeCount()), x, cy, 7f * scale, palette.panelMuted(), clipY, clipH, scale); + cy += 13f * scale; + + for (ConfigProfileDiff.Entry entry : diff.entries()) { + String owner = ClickGuiRenderer.fitText(ClickGuiRenderer.getInterMedium(), entry.displayName(), 7.4f * scale, w); + drawVisibleLine(owner, x, cy, 7.4f * scale, palette.panelText(), clipY, clipH, scale); + cy += 9.5f * scale; + + for (ConfigProfileDiff.Value value : entry.values()) { + String text = value.key() + ": " + stringify(value.currentValue()) + " -> " + stringify(value.selectedValue()); + text = ClickGuiRenderer.fitText(ClickGuiRenderer.getInterRegular(), text, 6.7f * scale, w - 5f * scale); + drawVisibleLine(text, x + 5f * scale, cy, 6.7f * scale, palette.panelMuted(), clipY, clipH, scale); + cy += 8.5f * scale; + } + cy += 4f * scale; + } + } + + private float contentHeight(ConfigProfileMeta selected, ConfigProfileDiff diff, String error, float scale) { + if (error != null && !error.isBlank()) return 11f * scale; + if (selected == null) return 11f * scale; + if (diff == null || diff.isEmpty()) return 23f * scale; + + float h = 24f * scale; + for (ConfigProfileDiff.Entry entry : diff.entries()) { + h += 9.5f * scale; + h += entry.values().size() * 8.5f * scale; + h += 4f * scale; + } + return h; + } + + private void renderScrollbar(float scale, SettingsGuiPalette palette) { + if (!scrollbarVisible) return; + float mx = ClickGuiRenderer.getMouseX(); + float my = ClickGuiRenderer.getMouseY(); + if (isScrollbarHovered(mx, my) || draggingScrollbar) SystemCursor.set(SystemCursor.CursorType.SCROLL); + + LayoutRender2D.roundedQuad(scrollbarX, scrollbarY, scrollbarW, scrollbarH, 2f * scale, + LayoutRender2D.alpha(palette.moduleScrollTrackA(), openAnim), + LayoutRender2D.alpha(palette.moduleScrollTrackB(), openAnim), + LayoutRender2D.alpha(palette.moduleScrollTrackB(), openAnim), + LayoutRender2D.alpha(palette.moduleScrollTrackA(), openAnim)); + LayoutRender2D.roundedQuad(scrollbarX, scrollbarThumbY, scrollbarW, scrollbarThumbH, 2f * scale, + LayoutRender2D.alpha(palette.moduleScrollHandleA(), openAnim), + LayoutRender2D.alpha(palette.moduleScrollHandleB(), openAnim), + LayoutRender2D.alpha(palette.moduleScrollHandleB(), openAnim), + LayoutRender2D.alpha(palette.moduleScrollHandleA(), openAnim)); + } + + private void updateScrollbarMetrics(float x, float y, float w, float h, float maxScroll, float scale) { + scrollbarVisible = maxScroll > 0.5f; + scrollbarMaxScroll = Math.max(0f, maxScroll); + if (!scrollbarVisible) { + draggingScrollbar = false; + scrollbarX = scrollbarY = scrollbarW = scrollbarH = scrollbarThumbY = scrollbarThumbH = 0f; + return; + } + scrollbarW = 3f * scale; + scrollbarX = x + w - scrollbarW - 1.5f * scale; + scrollbarY = y + 2f * scale; + scrollbarH = Math.max(1f, h - 4f * scale); + scrollbarThumbH = Math.max(16f * scale, scrollbarH * (scrollbarH / (scrollbarMaxScroll + scrollbarH))); + float scrollRatio = scrollbarMaxScroll <= 0f ? 0f : (-smoothedScroll / scrollbarMaxScroll); + scrollbarThumbY = scrollbarY + (scrollbarH - scrollbarThumbH) * AnimationUtility.clamp(scrollRatio, 0f, 1f); + } + + private boolean isScrollbarHovered(float mx, float my) { + if (!scrollbarVisible) return false; + float pad = 4f; + return ClickGuiMath.insideRect(mx, my, scrollbarX - pad, scrollbarY - pad, scrollbarW + pad * 2f, scrollbarH + pad * 2f); + } + + private void scrollToMouse(float my) { + if (!scrollbarVisible || scrollbarMaxScroll <= 0f) return; + float span = scrollbarH - scrollbarThumbH; + if (span <= 0.5f) return; + float thumbTop = AnimationUtility.clamp(my - scrollbarDragOffset, scrollbarY, scrollbarY + span); + float ratio = (thumbTop - scrollbarY) / span; + scroll = -scrollbarMaxScroll * AnimationUtility.clamp(ratio, 0f, 1f); + } + + private void drawVisibleLine(String text, float x, float y, float size, int color, float clipY, float clipH, float scale) { + if (y + 9f * scale < clipY || y > clipY + clipH) return; + drawLine(text, x, y, size, color); + } + + private void drawLine(String text, float x, float y, float size, int color) { + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterRegular(), text, x, y, size, LayoutRender2D.alpha(color, openAnim), false); + } + + public enum HeaderAction { + NONE, + SAVE, + CLOSE + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigProfileCardComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigProfileCardComponent.java new file mode 100644 index 0000000..d2c3107 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigProfileCardComponent.java @@ -0,0 +1,156 @@ +/* + * 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.features.gui.clickgui.layout.screen.settings.implement.config; + +import dev.loki.lovisual.config.profile.ConfigProfileDateFormatter; +import dev.loki.lovisual.config.profile.ConfigProfileMeta; +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.SettingsGuiPalette; +import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.render.LayoutRender2D; +import dev.loki.lovisual.features.gui.clickgui.util.ClickGuiI18n; +import dev.loki.lovisual.features.gui.clickgui.util.ClickGuiMath; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.svg.SvgRenderOptions; + +public final class ConfigProfileCardComponent { + public CardHit render(ConfigProfileMeta meta, + float x, + float y, + float w, + float h, + float mx, + float my, + boolean selected, + float scale, + SettingsGuiPalette palette) { + boolean hover = ClickGuiMath.insideRect(mx, my, x, y, w, h); + int top = selected ? SettingsGuiPalette.mix(palette.moduleCardTop(), palette.menuCategorySelectedLeft(), 0.16f) : palette.moduleCardTop(); + int topStrong = selected ? SettingsGuiPalette.mix(palette.moduleCardTopStrong(), palette.menuCategorySelectedRight(), 0.16f) : palette.moduleCardTopStrong(); + int bottom = hover ? SettingsGuiPalette.mix(palette.moduleCardBottom(), palette.menuCategoryHoverLeft(), 0.18f) : palette.moduleCardBottom(); + int bottomStrong = hover ? SettingsGuiPalette.mix(palette.moduleCardBottomStrong(), palette.menuCategoryHoverRight(), 0.14f) : palette.moduleCardBottomStrong(); + + ClickGuiRenderer.drawBlur(x, y, w, h, 5f * scale, 0xFF000000, 200f / 255f); + LayoutRender2D.roundedQuad(x, y, w, h, 5f * scale, top, topStrong, bottom, bottomStrong); + + float iconBox = 15f * scale; + float iconBoxX = x + 6f * scale; + float iconBoxY = y + 4.2f * scale; + Renderer2D.COLOR.roundedRectCorners( + iconBoxX, + iconBoxY, + iconBox, + iconBox, + 4f * scale, + 4f * scale, + 4f * scale, + 4f * scale, + 1.1f, + LayoutRender2D.alpha(palette.menuCategorySelectedRight(), selected ? 0.88f : 0.62f) + ); + Renderer2D.COLOR.svg( + "folder-cog", + iconBoxX + 3.2f * scale, + iconBoxY + 3.2f * scale, + 8.6f * scale, + 8.6f * scale, + SvgRenderOptions.overrideColor(palette.menuCategoryText()) + ); + + float textX = x + 25f * scale; + float titleSize = 8.8f * scale; + float titleX = textX; + float titleY = y + 3.8f * scale; + float titleW = w - 72f * scale; + float titleH = 10f * scale; + String title = ClickGuiRenderer.fitText(ClickGuiRenderer.getInterMedium(), meta.name(), titleSize, titleW); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterMedium(), title, titleX, titleY, titleSize, palette.moduleTitleText(), false); + + float authorSize = 6.8f * scale; + String author = ClickGuiRenderer.fitText(ClickGuiRenderer.getInterRegular(), meta.author(), authorSize, w - 72f * scale); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterRegular(), author, textX, y + 14.4f * scale, authorSize, palette.moduleDescriptionText(), false); + + LayoutRender2D.rectQuad( + x, + y + 23f * scale, + w, + 0.5f * scale, + palette.moduleDividerStart(), + palette.moduleDividerEnd(), + palette.moduleDividerEnd(), + palette.moduleDividerStart() + ); + + float rowSize = 7.2f * scale; + float labelX = x + 7f * scale; + float valueX = x + 50f * scale; + float row1Y = y + 28f * scale; + float row2Y = y + 38f * scale; + int labelColor = palette.moduleDescriptionIcon(); + int valueColor = palette.moduleDescriptionText(); + + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterRegular(), ClickGuiI18n.tr("clickgui.settings.config.card.created", "Created:"), labelX, row1Y, rowSize, labelColor, false); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterRegular(), + ClickGuiRenderer.fitText(ClickGuiRenderer.getInterRegular(), ConfigProfileDateFormatter.created(meta), rowSize, w - 110f * scale), + valueX, + row1Y, + rowSize, + valueColor, + false + ); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterRegular(), ClickGuiI18n.tr("clickgui.settings.config.card.updated", "Updated:"), labelX, row2Y, rowSize, labelColor, false); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterRegular(), + ClickGuiRenderer.fitText(ClickGuiRenderer.getInterRegular(), ConfigProfileDateFormatter.updated(meta), rowSize, w - 110f * scale), + valueX, + row2Y, + rowSize, + valueColor, + false + ); + + float btn = 16f * scale; + float gap = 4f * scale; + float by = y + h - 20f * scale; + float trashX = x + w - 7f * scale - btn; + float downloadX = trashX - gap - btn; + float diffX = downloadX - gap - btn; + + drawAction(diffX, by, btn, "diff", mx, my, scale, palette); + drawAction(downloadX, by, btn, "download", mx, my, scale, palette); + drawAction(trashX, by, btn, "trash-2", mx, my, scale, palette); + + return new CardHit(x, y, w, h, + new ActionHit(titleX, titleY - scale, titleW, titleH, CardActionType.RENAME), + new ActionHit(diffX, by, btn, btn, CardActionType.DIFF), + new ActionHit(downloadX, by, btn, btn, CardActionType.APPLY), + new ActionHit(trashX, by, btn, btn, CardActionType.DELETE)); + } + + private void drawAction(float x, float y, float size, String icon, float mx, float my, float scale, SettingsGuiPalette palette) { + boolean hover = ClickGuiMath.insideRect(mx, my, x, y, size, size); + int bgA = hover ? SettingsGuiPalette.mix(palette.moduleCardTop(), palette.menuCategoryHoverLeft(), 0.36f) : LayoutRender2D.alpha(palette.moduleCardTop(), 0.88f); + int bgB = hover ? SettingsGuiPalette.mix(palette.moduleCardTopStrong(), palette.menuCategoryHoverRight(), 0.28f) : LayoutRender2D.alpha(palette.moduleCardTopStrong(), 0.88f); + LayoutRender2D.roundedQuad(x, y, size, size, 4f * scale, bgA, bgB, bgB, bgA); + Renderer2D.COLOR.svg( + icon, + x + 4f * scale, + y + 4f * scale, + size - 8f * scale, + size - 8f * scale, + SvgRenderOptions.overrideColor(palette.menuCategoryText()) + ); + } + + public enum CardActionType {SELECT, RENAME, DIFF, APPLY, DELETE} + + public record CardHit(float x, float y, float w, float h, ActionHit title, ActionHit diff, ActionHit apply, + ActionHit delete) { + } + + public record ActionHit(float x, float y, float w, float h, CardActionType type) { + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigProfilesComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigProfilesComponent.java new file mode 100644 index 0000000..95157ac --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/config/ConfigProfilesComponent.java @@ -0,0 +1,791 @@ +/* + * 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.features.gui.clickgui.layout.screen.settings.implement.config; + +import dev.loki.lovisual.config.profile.*; +import org.lwjgl.glfw.GLFW; +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.features.gui.clickgui.ClickGuiSearch; +import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.SettingsGuiPalette; +import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.implement.config.ConfigProfileCardComponent.CardHit; +import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.render.LayoutRender2D; +import dev.loki.lovisual.features.gui.clickgui.util.ClickGuiI18n; +import dev.loki.lovisual.features.gui.clickgui.util.ClickGuiMath; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.svg.SvgRenderOptions; +import dev.loki.lovisual.render.helpers.ScissorFunction; +import dev.loki.lovisual.render.helpers.SystemCursor; +import dev.loki.lovisual.util.logging.DebugLog; + +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public final class ConfigProfilesComponent { + private static final DateTimeFormatter GENERATED_NAME_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss"); + private static final long STATUS_DURATION_MS = 2400L; + + private final ConfigProfileCardComponent cardComponent = new ConfigProfileCardComponent(); + private final ConfigDiffPanelComponent diffPanelComponent = new ConfigDiffPanelComponent(); + private final List hits = new ArrayList<>(); + + private ConfigProfileType type = ConfigProfileType.MODULES; + private ConfigProfileMeta selected; + private ConfigProfileDiff selectedDiff; + private String diffError; + private String statusMessage; + private long statusUntilMs; + private ConfigProfileType editingType; + private String editingId; + private String editingText = ""; + private Rect editingTitleRect = Rect.ZERO; + + private float scroll; + private float smoothedScroll; + private boolean scrollbarVisible; + private boolean draggingScrollbar; + private float scrollbarX; + private float scrollbarY; + private float scrollbarW; + private float scrollbarH; + private float scrollbarThumbY; + private float scrollbarThumbH; + private float scrollbarMaxScroll; + private float scrollbarDragOffset; + + private Rect modulesPill = Rect.ZERO; + private Rect hudPill = Rect.ZERO; + private Rect themesPill = Rect.ZERO; + private Rect saveButton = Rect.ZERO; + private float modeAnim; + private float modulesHoverAnim; + private float hudHoverAnim; + private float themesHoverAnim; + private float saveHoverAnim; + private float savePulseAnim; + + private static boolean inside(ConfigProfileCardComponent.ActionHit hit, float mx, float my) { + return hit != null && ClickGuiMath.insideRect(mx, my, hit.x(), hit.y(), hit.w(), hit.h()); + } + + public void resetScroll() { + scroll = 0f; + smoothedScroll = 0f; + draggingScrollbar = false; + diffPanelComponent.resetScroll(); + } + + public void render(float menuX, float menuY, float menuW, float menuH, float mx, float my, float scale) { + hits.clear(); + SettingsGuiPalette palette = SettingsGuiPalette.current(); + + float areaX = menuX + 31f * scale; + float areaY = menuY + 33f * scale; + float areaW = menuW - 42f * scale; + float areaH = menuH - 39f * scale; + + renderToolbar(areaX, areaY, areaW, mx, my, scale, palette); + + float listX = areaX; + float listY = areaY + 24f * scale; + float listW = areaW; + float listH = areaH - 24f * scale; + + List entries = filteredProfiles(ConfigProfileService.INSTANCE.list(type)); + renderCards(listX, listY, listW, listH, entries, mx, my, scale, palette); + + if (selectedDiff != null || diffError != null || diffPanelComponent.isActive()) { + diffPanelComponent.render( + menuX + menuW + 24f * scale, + menuY + 4f * scale, + 160f * scale, + Math.min(200f * scale, menuH - 8f * scale), + selected, + selectedDiff, + diffError, + scale, + palette + ); + if (!diffPanelComponent.isOpen() && !diffPanelComponent.isActive()) { + selectedDiff = null; + diffError = null; + } + } + + renderStatus(areaX, areaY, areaW, scale, palette); + } + + public boolean mousePressedScrollbar(float mx, float my, int button) { + if (button != 0) return false; + if (diffPanelComponent.mousePressedScrollbar(mx, my, button)) return true; + if (!isScrollbarHovered(mx, my)) return false; + draggingScrollbar = true; + scrollbarDragOffset = ClickGuiMath.insideRect(mx, my, scrollbarX, scrollbarThumbY, scrollbarW, scrollbarThumbH) + ? my - scrollbarThumbY + : scrollbarThumbH * 0.5f; + scrollToMouse(my); + return true; + } + + public void mouseReleased(int button) { + diffPanelComponent.mouseReleased(button); + if (button == 0) draggingScrollbar = false; + } + + public void scroll(float mx, float my, float menuX, float menuY, float menuW, float menuH, double amount, float scale) { + if (diffPanelComponent.scroll(mx, my, amount)) return; + + float x = menuX + 31f * scale; + float y = menuY + 55f * scale; + float w = menuW - 42f * scale; + float h = menuH - 61f * scale; + if (!ClickGuiMath.insideRect(mx, my, x, y, w, h)) return; + scroll += (float) (amount * 22f); + } + + public boolean click(float mx, float my, int button) { + if (button != 0) return false; + + if (selectedDiff != null || diffError != null) { + ConfigDiffPanelComponent.HeaderAction diffAction = diffPanelComponent.headerAction(mx, my, button); + if (diffAction == ConfigDiffPanelComponent.HeaderAction.CLOSE) { + diffPanelComponent.close(); + return true; + } + if (diffAction == ConfigDiffPanelComponent.HeaderAction.SAVE) { + overwriteSelected(); + return true; + } + } + + if (modulesPill.contains(mx, my)) { + switchType(ConfigProfileType.MODULES); + return true; + } + if (hudPill.contains(mx, my)) { + switchType(ConfigProfileType.HUD); + return true; + } + if (themesPill.contains(mx, my)) { + switchType(ConfigProfileType.THEMES); + return true; + } + if (saveButton.contains(mx, my)) { + savePulseAnim = 1f; + saveCurrent(); + return true; + } + if (isScrollbarHovered(mx, my)) return true; + + for (CardEntryHit entryHit : hits) { + CardHit hit = entryHit.hit(); + if (inside(hit.title(), mx, my)) { + select(entryHit.meta()); + beginRename(entryHit.meta(), hit.title()); + return true; + } + if (inside(hit.diff(), mx, my)) { + select(entryHit.meta()); + diffPanelComponent.resetScroll(); + loadDiff(entryHit.meta()); + return true; + } + if (inside(hit.apply(), mx, my)) { + select(entryHit.meta()); + apply(entryHit.meta()); + return true; + } + if (inside(hit.delete(), mx, my)) { + delete(entryHit.meta()); + return true; + } + if (ClickGuiMath.insideRect(mx, my, hit.x(), hit.y(), hit.w(), hit.h())) { + select(entryHit.meta()); + return true; + } + } + return false; + } + + private void renderToolbar(float x, float y, float w, float mx, float my, float scale, SettingsGuiPalette palette) { + float pillW = 132f * scale; + float pillH = 15f * scale; + float targetMode = switch (type) { + case MODULES -> 0f; + case HUD -> 1f; + case THEMES -> 2f; + }; + float dt = AnimationUtility.deltaTime(); + modeAnim = AnimationUtility.approach(modeAnim, targetMode, dt, 12f); + modeAnim = AnimationUtility.snap(modeAnim, targetMode, 0.01f); + + modulesPill = new Rect(x, y, pillW / 3f, pillH); + hudPill = new Rect(x + pillW / 3f, y, pillW / 3f, pillH); + themesPill = new Rect(x + pillW * 2f / 3f, y, pillW / 3f, pillH); + + modulesHoverAnim = updateHover(modulesHoverAnim, modulesPill.contains(mx, my), dt); + hudHoverAnim = updateHover(hudHoverAnim, hudPill.contains(mx, my), dt); + themesHoverAnim = updateHover(themesHoverAnim, themesPill.contains(mx, my), dt); + + int baseLeft = SettingsGuiPalette.mix(palette.panelPillBase(), palette.panelBgLeft(), 0.34f); + int baseRight = SettingsGuiPalette.mix(palette.panelPillBase(), palette.panelBgRight(), 0.44f); + float anyHover = Math.max(modulesHoverAnim, Math.max(hudHoverAnim, themesHoverAnim)); + baseLeft = SettingsGuiPalette.mix(baseLeft, palette.menuCategoryHoverLeft(), 0.12f * anyHover); + baseRight = SettingsGuiPalette.mix(baseRight, palette.menuCategoryHoverRight(), 0.12f * anyHover); + + ClickGuiRenderer.drawBlur(x, y, pillW, pillH, 4f * scale, palette.panelBlurTint(), 145f / 255f); + LayoutRender2D.roundedQuad( + x, + y, + pillW, + pillH, + 3.5f * scale, + baseLeft, + baseRight, + baseRight, + baseLeft + ); + LayoutRender2D.roundedStrokeQuad( + x, + y, + pillW, + pillH, + 3.5f * scale, + 0.5f * scale, + SettingsGuiPalette.mix(palette.panelStroke(), palette.moduleDividerStart(), 0.18f), + SettingsGuiPalette.mix(palette.panelStroke(), palette.moduleDividerEnd(), 0.18f), + SettingsGuiPalette.mix(palette.panelStroke(), palette.moduleDividerEnd(), 0.18f), + SettingsGuiPalette.mix(palette.panelStroke(), palette.moduleDividerStart(), 0.18f) + ); + + float pad = 1.2f * scale; + float segment = (pillW - pad * 2f) / 3f; + float activeX = x + pad + segment * modeAnim; + float activeHover = switch (type) { + case MODULES -> modulesHoverAnim; + case HUD -> hudHoverAnim; + case THEMES -> themesHoverAnim; + }; + int activeA = SettingsGuiPalette.mix(palette.panelPillActive(), palette.menuCategorySelectedLeft(), 0.22f + activeHover * 0.08f); + int activeB = SettingsGuiPalette.mix(palette.panelPillActive(), palette.menuCategorySelectedRight(), 0.22f + activeHover * 0.12f); + int activeC = SettingsGuiPalette.mix(SettingsGuiPalette.darken(palette.panelPillActive(), 0.16f), palette.menuCategorySelectedRight(), 0.18f + activeHover * 0.10f); + LayoutRender2D.roundedQuad( + activeX, + y + pad, + segment, + pillH - pad * 2f, + 3f * scale, + activeA, + activeB, + activeC, + activeA + ); + LayoutRender2D.roundedStrokeQuad( + activeX, + y + pad, + segment, + pillH - pad * 2f, + 3f * scale, + 0.35f * scale, + SettingsGuiPalette.withAlpha(palette.moduleDividerStart(), 150), + SettingsGuiPalette.withAlpha(palette.moduleDividerEnd(), 178), + SettingsGuiPalette.withAlpha(palette.moduleDividerEnd(), 142), + SettingsGuiPalette.withAlpha(palette.moduleDividerStart(), 150) + ); + + drawToolbarSeparator(x + pad + segment, y, pillH, scale, palette); + drawToolbarSeparator(x + pad + segment * 2f, y, pillH, scale, palette); + + drawSegment(modulesPill, ClickGuiI18n.tr("clickgui.settings.config.type.modules", "Modules"), type == ConfigProfileType.MODULES, modulesHoverAnim, scale, palette); + drawSegment(hudPill, ClickGuiI18n.tr("clickgui.settings.config.type.hud", "Hud"), type == ConfigProfileType.HUD, hudHoverAnim, scale, palette); + drawSegment(themesPill, ClickGuiI18n.tr("clickgui.settings.config.type.themes", "Themes"), type == ConfigProfileType.THEMES, themesHoverAnim, scale, palette); + + float saveW = 68f * scale; + float saveH = pillH; + saveButton = new Rect(x + pillW + 7f * scale, y, saveW, saveH); + boolean saveHover = saveButton.contains(mx, my); + saveHoverAnim = updateHover(saveHoverAnim, saveHover, dt); + savePulseAnim = AnimationUtility.snap(AnimationUtility.approach(savePulseAnim, 0f, dt, 7f), 0f, 0.01f); + renderSaveButton(saveButton, saveHoverAnim, savePulseAnim, scale, palette); + if (saveHover) SystemCursor.set(SystemCursor.CursorType.MOVE); + } + + private float updateHover(float current, boolean hovered, float dt) { + return AnimationUtility.snap( + AnimationUtility.approach(current, hovered ? 1f : 0f, dt, 12f), + hovered ? 1f : 0f, + 0.01f + ); + } + + private void drawToolbarSeparator(float x, float y, float h, float scale, SettingsGuiPalette palette) { + float backingW = Math.max(1.25f * scale, 1.05f); + float backingH = h - 4.4f * scale; + float backingY = y + (h - backingH) * 0.5f; + int backingTop = SettingsGuiPalette.withAlpha(palette.panelBgLeft(), 98); + int backingBottom = SettingsGuiPalette.withAlpha(palette.panelBgRight(), 78); + LayoutRender2D.roundedQuad( + x - backingW * 0.5f, + backingY, + backingW, + backingH, + backingW * 0.5f, + backingTop, + backingTop, + backingBottom, + backingBottom + ); + + float lineW = Math.max(0.5f * scale, 0.75f); + float lineH = h - 6.0f * scale; + float lineY = y + (h - lineH) * 0.5f; + int top = SettingsGuiPalette.withAlpha(SettingsGuiPalette.mix(palette.moduleDividerStart(), palette.menuCategorySelectedLeft(), 0.34f), 146); + int mid = SettingsGuiPalette.withAlpha(SettingsGuiPalette.mix(palette.moduleDividerEnd(), palette.menuCategorySelectedRight(), 0.40f), 210); + int bottom = SettingsGuiPalette.withAlpha(SettingsGuiPalette.mix(palette.moduleDividerEnd(), palette.panelText(), 0.24f), 136); + LayoutRender2D.roundedQuad( + x - lineW * 0.5f, + lineY, + lineW, + lineH, + lineW * 0.5f, + top, + mid, + bottom, + top + ); + + } + + private void renderSaveButton(Rect rect, float hover, float pulse, float scale, SettingsGuiPalette palette) { + float lift = (hover * 0.65f + pulse * 0.85f) * scale; + float x = rect.x(); + float y = rect.y() - lift * 0.15f; + float w = rect.w(); + float h = rect.h(); + int bgA = SettingsGuiPalette.mix(palette.panelPillBase(), palette.menuCategoryHoverLeft(), 0.18f + hover * 0.22f + pulse * 0.24f); + int bgB = SettingsGuiPalette.mix(palette.panelPillBase(), palette.menuCategoryHoverRight(), 0.16f + hover * 0.24f + pulse * 0.26f); + int bgC = SettingsGuiPalette.mix(SettingsGuiPalette.darken(palette.panelPillBase(), 0.18f), palette.menuCategorySelectedRight(), 0.12f + hover * 0.18f + pulse * 0.24f); + LayoutRender2D.roundedSoftShadow( + x, + y + 0.4f * scale, + w, + h, + 3.6f * scale, + 5f * scale, + 0.02f + hover * 0.03f, + SettingsGuiPalette.withAlpha(palette.menuShadow(), Math.round(65f + hover * 50f + pulse * 58f)) + ); + LayoutRender2D.roundedQuad(x, y, w, h, 3.6f * scale, bgA, bgB, bgC, bgA); + LayoutRender2D.roundedStrokeQuad( + x, + y, + w, + h, + 3.6f * scale, + (0.45f + hover * 0.22f + pulse * 0.22f) * scale, + SettingsGuiPalette.withAlpha(palette.moduleDividerStart(), Math.round(138f + hover * 45f + pulse * 50f)), + SettingsGuiPalette.withAlpha(palette.moduleDividerEnd(), Math.round(158f + hover * 55f + pulse * 55f)), + SettingsGuiPalette.withAlpha(palette.moduleDividerEnd(), Math.round(120f + hover * 45f + pulse * 50f)), + SettingsGuiPalette.withAlpha(palette.moduleDividerStart(), Math.round(138f + hover * 45f + pulse * 50f)) + ); + + int iconColor = SettingsGuiPalette.mix(palette.panelText(), palette.menuCategoryText(), 0.22f + hover * 0.34f + pulse * 0.34f); + Renderer2D.COLOR.svg("save", x + 6.2f * scale, y + 4f * scale, 7f * scale, 7f * scale, SvgRenderOptions.overrideColor(iconColor)); + String label = ClickGuiI18n.tr("clickgui.settings.config.save", "Save"); + float textSize = 6.7f * scale; + int textColor = SettingsGuiPalette.mix(palette.panelText(), palette.menuCategoryText(), hover * 0.24f + pulse * 0.24f); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterMedium(), label, x + 17.4f * scale, y + 4.2f * scale, textSize, textColor, false); + } + + private void drawSegment(Rect rect, String label, boolean active, float hover, float scale, SettingsGuiPalette palette) { + float size = 7.5f * scale; + float tw = ClickGuiRenderer.textWidth(ClickGuiRenderer.getInterMedium(), label, size); + float th = ClickGuiRenderer.textHeight(ClickGuiRenderer.getInterMedium(), size); + int color = active + ? palette.panelText() + : SettingsGuiPalette.mix(palette.panelMuted(), palette.panelText(), 0.20f * hover); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterMedium(), label, rect.x() + (rect.w() - tw) * 0.5f, rect.y() + (rect.h() - th) * 0.5f, size, color, false); + } + + private void renderCards(float x, + float y, + float w, + float h, + List entries, + float mx, + float my, + float scale, + SettingsGuiPalette palette) { + float gap = 6f * scale; + int columns = w > 230f * scale ? 2 : 1; + float cardW = (w - gap * (columns - 1)) / columns; + float cardH = 58f * scale; + float stepY = cardH + gap; + int rows = (entries.size() + columns - 1) / columns; + float contentH = rows <= 0 ? 0f : rows * stepY - gap; + float maxScroll = Math.max(0f, contentH - h); + updateScrollbarMetrics(x, y, w, h, maxScroll, scale); + if (draggingScrollbar) scrollToMouse(ClickGuiRenderer.getMouseY()); + + scroll = ClickGuiMath.clamp(scroll, -maxScroll, 0f); + smoothedScroll = AnimationUtility.approach(smoothedScroll, scroll, draggingScrollbar ? 0.55f : 0.2f); + smoothedScroll = AnimationUtility.snap(smoothedScroll, scroll, draggingScrollbar ? 0.01f : 0.05f); + + if (entries.isEmpty()) { + String empty = ClickGuiSearch.isActive() && !ClickGuiSearch.getText().isBlank() + ? ClickGuiI18n.tr("clickgui.settings.config.empty.no_matches", "No matching configs.") + : ClickGuiI18n.tr("clickgui.settings.config.empty.none_saved", "No saved configs."); + float emptySize = 8.0f * scale; + float emptyW = ClickGuiRenderer.textWidth(ClickGuiRenderer.getInterRegular(), empty, emptySize); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterRegular(), empty, x + (w - emptyW) * 0.5f, y + h * 0.42f, emptySize, palette.panelMuted(), false); + if (!ClickGuiSearch.isActive() || ClickGuiSearch.getText().isBlank()) { + String hint = ClickGuiI18n.tr("clickgui.settings.config.empty.drop_hint", "Drop .cbcfg files here, or put them anywhere under config/lovisual/profiles/."); + float hintSize = 6.9f * scale; + String fitted = ClickGuiRenderer.fitText(ClickGuiRenderer.getInterRegular(), hint, hintSize, w - 18f * scale); + float hintW = ClickGuiRenderer.textWidth(ClickGuiRenderer.getInterRegular(), fitted, hintSize); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterRegular(), fitted, x + (w - hintW) * 0.5f, y + h * 0.42f + 13f * scale, hintSize, palette.panelMuted(), false); + } + return; + } + boolean clipped = ScissorFunction.pushRaw(x, y, w, h); + for (int i = 0; i < entries.size(); i++) { + int col = i % columns; + int row = i / columns; + float cx = x + col * (cardW + gap); + float cy = y + row * stepY + smoothedScroll; + if (cy + cardH < y || cy > y + h) continue; + ConfigProfileMeta meta = entries.get(i); + boolean selectedState = selected != null && selected.getId().equals(meta.getId()) && selected.type() == meta.type(); + CardHit hit = cardComponent.render(meta, cx, cy, cardW, cardH, mx, my, selectedState, scale, palette); + if (isEditing(meta)) { + editingTitleRect = new Rect(hit.title().x(), hit.title().y(), hit.title().w(), hit.title().h()); + renderRenameInput(editingTitleRect, scale, palette); + } + if (inside(hit.title(), mx, my)) SystemCursor.set(SystemCursor.CursorType.MOVE); + hits.add(new CardEntryHit(meta, hit)); + } + if (clipped) ScissorFunction.pop(); + + renderScrollbar(x, y, w, h, maxScroll, scale, palette); + } + + private void renderScrollbar(float x, float y, float w, float h, float maxScroll, float scale, SettingsGuiPalette palette) { + updateScrollbarMetrics(x, y, w, h, maxScroll, scale); + if (!scrollbarVisible) return; + float mx = ClickGuiRenderer.getMouseX(); + float my = ClickGuiRenderer.getMouseY(); + if (isScrollbarHovered(mx, my) || draggingScrollbar) SystemCursor.set(SystemCursor.CursorType.SCROLL); + + LayoutRender2D.roundedQuad(scrollbarX, scrollbarY, scrollbarW, scrollbarH, 2f * scale, + palette.moduleScrollTrackA(), palette.moduleScrollTrackB(), palette.moduleScrollTrackB(), palette.moduleScrollTrackA()); + LayoutRender2D.roundedQuad(scrollbarX, scrollbarThumbY, scrollbarW, scrollbarThumbH, 2f * scale, + palette.moduleScrollHandleA(), palette.moduleScrollHandleB(), palette.moduleScrollHandleB(), palette.moduleScrollHandleA()); + } + + private void updateScrollbarMetrics(float x, float y, float w, float h, float maxScroll, float scale) { + scrollbarVisible = maxScroll > 0.5f; + scrollbarMaxScroll = Math.max(0f, maxScroll); + if (!scrollbarVisible) { + draggingScrollbar = false; + scrollbarX = scrollbarY = scrollbarW = scrollbarH = scrollbarThumbY = scrollbarThumbH = 0f; + return; + } + scrollbarW = 3f * scale; + scrollbarX = x + w - scrollbarW - 2f * scale; + scrollbarY = y + 3f * scale; + scrollbarH = Math.max(1f, h - 6f * scale); + scrollbarThumbH = Math.max(18f * scale, scrollbarH * (scrollbarH / (scrollbarMaxScroll + scrollbarH))); + float scrollRatio = scrollbarMaxScroll <= 0f ? 0f : (-smoothedScroll / scrollbarMaxScroll); + scrollbarThumbY = scrollbarY + (scrollbarH - scrollbarThumbH) * AnimationUtility.clamp(scrollRatio, 0f, 1f); + } + + private boolean isScrollbarHovered(float mx, float my) { + if (!scrollbarVisible) return false; + float pad = 4f; + return ClickGuiMath.insideRect(mx, my, scrollbarX - pad, scrollbarY - pad, scrollbarW + pad * 2f, scrollbarH + pad * 2f); + } + + private void scrollToMouse(float my) { + if (!scrollbarVisible || scrollbarMaxScroll <= 0f) return; + float span = scrollbarH - scrollbarThumbH; + if (span <= 0.5f) return; + float thumbTop = AnimationUtility.clamp(my - scrollbarDragOffset, scrollbarY, scrollbarY + span); + float ratio = (thumbTop - scrollbarY) / span; + scroll = -scrollbarMaxScroll * AnimationUtility.clamp(ratio, 0f, 1f); + } + + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (!isRenaming()) return false; + if (keyCode == GLFW.GLFW_KEY_ESCAPE) { + cancelRename(); + return true; + } + if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) { + commitRename(); + return true; + } + if (keyCode == GLFW.GLFW_KEY_BACKSPACE) { + if (!editingText.isEmpty()) editingText = editingText.substring(0, editingText.length() - 1); + return true; + } + return true; + } + + public boolean charTyped(char chr, int modifiers) { + if (!isRenaming()) return false; + if (chr >= 32 && chr != 127 && editingText.length() < 48) { + editingText += chr; + } + return true; + } + + public boolean importDroppedFiles(List paths) { + if (paths == null || paths.isEmpty()) return false; + int imported = 0; + int failed = 0; + ConfigProfileMeta last = null; + for (Path path : paths) { + try { + ConfigProfileStorage.ImportResult result = ConfigProfileService.INSTANCE.importProfileFile(path, false); + imported++; + last = result.meta(); + } catch (Exception e) { + failed++; + DebugLog.error("Failed to import dropped config profile %s", e, path == null ? "" : path.toAbsolutePath()); + } + } + if (last != null) { + switchType(last.type()); + selected = last; + } + if (imported > 0 && failed > 0) { + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.imported_partial", "Imported: %s, failed: %s", imported, failed)); + } else if (imported > 0) { + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.imported", "Imported: %s", imported)); + } else { + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.import_failed", "Import failed")); + } + return true; + } + + private void beginRename(ConfigProfileMeta meta, ConfigProfileCardComponent.ActionHit titleHit) { + if (meta == null) return; + editingType = meta.type(); + editingId = meta.getId(); + editingText = meta.name(); + editingTitleRect = new Rect(titleHit.x(), titleHit.y(), titleHit.w(), titleHit.h()); + clearStatus(); + } + + private void cancelRename() { + editingType = null; + editingId = null; + editingText = ""; + editingTitleRect = Rect.ZERO; + } + + private boolean isRenaming() { + return editingType != null && editingId != null; + } + + private boolean isEditing(ConfigProfileMeta meta) { + return meta != null && editingType == meta.type() && editingId != null && editingId.equals(meta.getId()); + } + + private void commitRename() { + if (!isRenaming()) return; + String next = editingText == null ? "" : editingText.trim(); + if (next.isBlank()) { + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.empty_name", "Name cannot be empty")); + return; + } + try { + ConfigProfileMeta oldSelected = selected; + ConfigProfileMeta renamed = ConfigProfileService.INSTANCE.rename(editingType, editingId, next).meta(); + if (oldSelected != null && oldSelected.type() == editingType && oldSelected.getId().equals(editingId)) { + selected = renamed; + } + cancelRename(); + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.renamed", "Renamed: %s", renamed.name())); + } catch (Exception e) { + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.rename_failed", "Rename failed")); + DebugLog.error("Failed to rename config profile", e); + } + } + + private void renderRenameInput(Rect rect, float scale, SettingsGuiPalette palette) { + float padX = 2f * scale; + float y = rect.y() - scale; + float h = rect.h() + 2f * scale; + LayoutRender2D.roundedQuad( + rect.x() - padX, + y, + rect.w() + padX * 2f, + h, + 3f * scale, + SettingsGuiPalette.mix(palette.moduleCardTop(), palette.menuCategorySelectedLeft(), 0.28f), + SettingsGuiPalette.mix(palette.moduleCardTopStrong(), palette.menuCategorySelectedRight(), 0.22f), + SettingsGuiPalette.mix(palette.moduleCardTopStrong(), palette.menuCategorySelectedRight(), 0.22f), + SettingsGuiPalette.mix(palette.moduleCardTop(), palette.menuCategorySelectedLeft(), 0.28f) + ); + String text = ClickGuiRenderer.fitText(ClickGuiRenderer.getInterMedium(), editingText, 8.8f * scale, rect.w() - 5f * scale); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterMedium(), text, rect.x(), rect.y(), 8.8f * scale, palette.moduleTitleText(), false); + if ((System.currentTimeMillis() / 500L) % 2L == 0L) { + float tw = ClickGuiRenderer.textWidth(ClickGuiRenderer.getInterMedium(), text, 8.8f * scale); + LayoutRender2D.rect(rect.x() + Math.min(tw + 1.5f * scale, rect.w() - 2f * scale), rect.y() + 1.2f * scale, 0.6f * scale, 8f * scale, palette.moduleTitleText()); + } + } + + private void renderStatus(float x, float y, float w, float scale, SettingsGuiPalette palette) { + if (statusMessage == null || statusMessage.isBlank()) return; + if (System.currentTimeMillis() > statusUntilMs) { + clearStatus(); + return; + } + float size = 6.8f * scale; + String text = ClickGuiRenderer.fitText(ClickGuiRenderer.getInterRegular(), statusMessage, size, w - 176f * scale); + float tw = ClickGuiRenderer.textWidth(ClickGuiRenderer.getInterRegular(), text, size); + ClickGuiRenderer.drawText(ClickGuiRenderer.getInterRegular(), text, x + w - tw, y + 7.2f * scale, size, palette.panelMuted(), false); + } + + private void setStatus(String message) { + statusMessage = message; + statusUntilMs = System.currentTimeMillis() + STATUS_DURATION_MS; + } + + private void clearStatus() { + statusMessage = null; + statusUntilMs = 0L; + } + + private List filteredProfiles(List src) { + if (!ClickGuiSearch.isActive() || ClickGuiSearch.getText().isBlank()) return src; + List out = new ArrayList<>(); + String q = ClickGuiSearch.getText().toLowerCase(Locale.ROOT); + for (ConfigProfileMeta meta : src) { + if (meta.name().toLowerCase(Locale.ROOT).contains(q) || meta.author().toLowerCase(Locale.ROOT).contains(q)) + out.add(meta); + } + return out; + } + + private void switchType(ConfigProfileType next) { + if (type == next) return; + type = next; + selected = null; + selectedDiff = null; + diffError = null; + diffPanelComponent.close(); + clearStatus(); + cancelRename(); + resetScroll(); + } + + private void select(ConfigProfileMeta meta) { + boolean same = selected != null && meta != null && selected.type() == meta.type() && selected.getId().equals(meta.getId()); + selected = meta; + if (!same) { + selectedDiff = null; + diffError = null; + diffPanelComponent.close(); + diffPanelComponent.resetScroll(); + } + } + + private void saveCurrent() { + String name = type.folderName() + " " + GENERATED_NAME_TIME.format(LocalDateTime.now()); + try { + diffPanelComponent.close(); + selected = ConfigProfileService.INSTANCE.saveCurrent(type, name).meta(); + selectedDiff = null; + diffError = null; + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.saved", "Saved: %s", selected.name())); + } catch (Exception e) { + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.save_failed", "Save failed")); + DebugLog.error("Failed to save config profile", e); + } + } + + private void overwriteSelected() { + if (selected == null) return; + try { + diffPanelComponent.close(); + selected = ConfigProfileService.INSTANCE.overwriteCurrent(selected).meta(); + selectedDiff = null; + diffError = null; + diffPanelComponent.resetScroll(); + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.overwritten", "Overwritten: %s", selected.name())); + } catch (Exception e) { + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.overwrite_failed", "Overwrite failed")); + DebugLog.error("Failed to overwrite config profile", e); + } + } + + private void loadDiff(ConfigProfileMeta meta) { + try { + selectedDiff = ConfigProfileService.INSTANCE.diffWithCurrent(meta.type(), meta.getId()); + diffError = null; + diffPanelComponent.open(); + diffPanelComponent.resetScroll(); + setStatus(selectedDiff.isEmpty() + ? ClickGuiI18n.tr("clickgui.settings.config.status.no_differences", "No differences") + : ClickGuiI18n.tr("clickgui.settings.config.status.diff_count", "Diff: %s changes", selectedDiff.valueChangeCount())); + } catch (Exception e) { + selectedDiff = null; + diffError = e.getMessage(); + diffPanelComponent.open(); + diffPanelComponent.resetScroll(); + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.diff_failed", "Diff failed")); + DebugLog.error("Failed to diff config profile", e); + } + } + + private void apply(ConfigProfileMeta meta) { + try { + diffPanelComponent.close(); + ConfigProfileApplier.ApplyResult result = ConfigProfileService.INSTANCE.apply(meta.type(), meta.getId()); + selectedDiff = null; + diffError = null; + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.applied", "Applied: %s, missing: %s/%s", result.appliedOwners(), result.missingOwners(), result.missingValues())); + } catch (Exception e) { + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.apply_failed", "Apply failed")); + DebugLog.error("Failed to apply config profile", e); + } + } + + private void delete(ConfigProfileMeta meta) { + try { + ConfigProfileService.INSTANCE.delete(meta.type(), meta.getId()); + if (selected != null && selected.getId().equals(meta.getId()) && selected.type() == meta.type()) { + selected = null; + selectedDiff = null; + diffError = null; + diffPanelComponent.close(); + } + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.deleted", "Deleted: %s", meta.name())); + } catch (Exception e) { + setStatus(ClickGuiI18n.tr("clickgui.settings.config.status.delete_failed", "Delete failed")); + DebugLog.error("Failed to delete config profile", e); + } + } + + private record CardEntryHit(ConfigProfileMeta meta, CardHit hit) { + } + + private record Rect(float x, float y, float w, float h) { + static final Rect ZERO = new Rect(0f, 0f, 0f, 0f); + + boolean contains(float mx, float my) { + return ClickGuiMath.insideRect(mx, my, x, y, w, h); + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/main/MainSettingsComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/main/MainSettingsComponent.java index a00ca5e..6d60c54 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/main/MainSettingsComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/main/MainSettingsComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/ModuleComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/ModuleComponent.java index c90d1b1..08e4b9c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/ModuleComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/ModuleComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/ModuleSettingsWindow.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/ModuleSettingsWindow.java index 3f60088..18a11d8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/ModuleSettingsWindow.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/ModuleSettingsWindow.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/SettingsPanelComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/SettingsPanelComponent.java index def65e7..eec5f7b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/SettingsPanelComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/module/SettingsPanelComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/BackgroundComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/BackgroundComponent.java index 7ba2787..73e3a8c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/BackgroundComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/BackgroundComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * Portions derived from ThunderHack Recode, copyright (c) 2023-2024 Pan4ur & 06ED. * Upstream: https://github.com/Pan4ur/ThunderHack-Recode diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/CategoryContainerComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/CategoryContainerComponent.java index 497a00a..6c377db 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/CategoryContainerComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/CategoryContainerComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/SearchComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/SearchComponent.java index 35f3ab1..0278af2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/SearchComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/SearchComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/StatusRender.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/StatusRender.java index 1dee416..d19b23d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/StatusRender.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/other/StatusRender.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/OnlineRelationPlayerPickerComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/OnlineRelationPlayerPickerComponent.java index bd7c693..6dc164c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/OnlineRelationPlayerPickerComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/OnlineRelationPlayerPickerComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/RelationPlayerCardComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/RelationPlayerCardComponent.java index b00bc57..92adf0a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/RelationPlayerCardComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/RelationPlayerCardComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/RelationsComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/RelationsComponent.java index 135f982..ac90b80 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/RelationsComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/relations/RelationsComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/theme/ThemeComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/theme/ThemeComponent.java index fbf4489..010192a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/theme/ThemeComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/theme/ThemeComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/theme/ThemeEditorPreviewComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/theme/ThemeEditorPreviewComponent.java index 405a03d..b1d7b3e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/theme/ThemeEditorPreviewComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/implement/theme/ThemeEditorPreviewComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -27,7 +27,7 @@ import java.util.LinkedHashMap; import java.util.Map; public final class ThemeEditorPreviewComponent { - private static final String PREVIEW_LAYOUT_ID = "combatant:api/clickgui/theme_preview"; + private static final String PREVIEW_LAYOUT_ID = "lovisual:api/clickgui/theme_preview"; private static final float DESIGN_W = 320f; private static final float DESIGN_H = 190f; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/render/LayoutRender2D.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/render/LayoutRender2D.java index d4a3261..c174b2f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/render/LayoutRender2D.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/layout/screen/settings/render/LayoutRender2D.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/ClickGuiPickerState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/ClickGuiPickerState.java index ca8579a..2839ad9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/ClickGuiPickerState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/ClickGuiPickerState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerCatalog.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerCatalog.java index 3c554d1..547c577 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerCatalog.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerCatalog.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerCatalogFactory.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerCatalogFactory.java index 524f4fa..f31b1c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerCatalogFactory.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerCatalogFactory.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerEntryData.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerEntryData.java index e458cc6..b10c2ad 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerEntryData.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/picker/PickerEntryData.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/protocol/CombatProtocolHeuristicsEditorState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/protocol/CombatProtocolHeuristicsEditorState.java index 56c7ecb..4fbb906 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/protocol/CombatProtocolHeuristicsEditorState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/protocol/CombatProtocolHeuristicsEditorState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/ClickGuiSection.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/ClickGuiSection.java index 5949af5..ecef493 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/ClickGuiSection.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/ClickGuiSection.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/ModulesSection.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/ModulesSection.java index f634b2f..0e5d075 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/ModulesSection.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/ModulesSection.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/SettingsSection.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/SettingsSection.java index 29f09ca..66a9fe3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/SettingsSection.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/SettingsSection.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/settings/SettingsTabRuntime.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/settings/SettingsTabRuntime.java index 235aae9..25fd830 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/settings/SettingsTabRuntime.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/sections/settings/SettingsTabRuntime.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BindRendererUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BindRendererUtil.java new file mode 100644 index 0000000..094f965 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BindRendererUtil.java @@ -0,0 +1,192 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ScissorFunction; + +final class BindRendererUtil { + private BindRendererUtil() { + } + + static float bindHeight(float lastW, String label, String display, String modeText) { + float w = lastW > 0f ? lastW : SettingSkinUtil.m(160f, 115f); + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float size = SettingSkinUtil.m(17f, 7.0f); + float small = SettingSkinUtil.m(11.5f, 5.7f); + float pad = SettingSkinUtil.m(6f, 5f); + float gap = SettingSkinUtil.m(4f, 4f); + float chipPad = SettingSkinUtil.m(7f, 5f); + float minLabelW = SettingSkinUtil.m(72f, 38f); + float modeW = modeText == null ? 0f : Math.max(SettingSkinUtil.m(36f, 25f), UnifiedSettingsSkin.textWidth(font, modeText, small) + SettingSkinUtil.m(10f, 8f)); + float modeBlockW = modeW > 0f ? modeW + gap : 0f; + String displayText = display == null || display.isBlank() ? "NONE" : display; + float wantedChipW = UnifiedSettingsSkin.textWidth(font, displayText, size) + chipPad * 2f; + float sameLineMaxChipW = Math.max(SettingSkinUtil.m(48f, 30f), w - pad * 3f - modeBlockW - minLabelW); + boolean nextLine = sameLineMaxChipW < SettingSkinUtil.m(48f, 30f); + if (!nextLine) { + float chipW = Math.max(SettingSkinUtil.m(48f, 30f), Math.min(wantedChipW, sameLineMaxChipW)); + float labelMax = w - pad * 3f - modeBlockW - chipW; + nextLine = labelMax < minLabelW; + } + return nextLine ? SettingSkinUtil.m(48f, 31f) : SettingSkinUtil.m(38f, 22f); + } + + static float bindHoverAnim(Object uiObj, boolean hover) { + float dt = AnimationUtility.deltaTime(); + if (uiObj instanceof KeyBindSetting.UiState ui) { + ui.hoverAnim = AnimationUtility.approach(ui.hoverAnim, hover ? 1f : 0f, dt, 12f); + return ui.hoverAnim; + } + if (uiObj instanceof FunctionBindSetting.UiState ui) { + ui.hoverAnim = AnimationUtility.approach(ui.hoverAnim, hover ? 1f : 0f, dt, 12f); + return ui.hoverAnim; + } + return hover ? 1f : 0f; + } + + static float bindWaitAnim(Object uiObj, boolean waiting) { + float dt = AnimationUtility.deltaTime(); + if (uiObj instanceof KeyBindSetting.UiState ui) { + ui.waitAnim = AnimationUtility.approach(ui.waitAnim, waiting ? 1f : 0f, dt, 14f); + return ui.waitAnim; + } + if (uiObj instanceof FunctionBindSetting.UiState ui) { + ui.waitAnim = AnimationUtility.approach(ui.waitAnim, waiting ? 1f : 0f, dt, 14f); + return ui.waitAnim; + } + return waiting ? 1f : 0f; + } + + static void renderSmallModeChip(float x, float y, float w, float h, String text, float size, float hoverAnim, float waitAnim) { + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float inset = SettingSkinUtil.m(0.8f, 0.45f); + float dx = x + inset; + float dy = y + inset; + float dw = Math.max(1f, w - inset * 2f); + float dh = Math.max(1f, h - inset * 2f); + float radius = Math.max(0f, SettingSkinUtil.m(6f, 4f) - inset); + int bg = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, 0.45f + hoverAnim * 0.25f + waitAnim * 0.20f); + ClickGuiRenderer.drawRoundedRect(dx, dy, dw, dh, radius, bg); + ClickGuiRenderer.drawRoundedRectStroke(dx, dy, dw, dh, radius, SettingSkinUtil.m(0.55f, 0.35f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(34f + hoverAnim * 24f + waitAnim * 30f))); + String fitted = UnifiedSettingsSkin.fit(font, text, size, Math.max(1f, w - SettingSkinUtil.m(6f, 6f))); + float tw = UnifiedSettingsSkin.textWidth(font, fitted, size); + int color = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, waitAnim * 0.35f + hoverAnim * 0.15f); + ClickGuiRenderer.drawText(font, fitted, x + (w - tw) * 0.5f, y + (h - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f, size, color, false); + } + + static void renderBindBase(String label, String display, String modeText, boolean waiting, float x, float y, float w, float mx, float my, Object uiObj) { + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float size = SettingSkinUtil.m(17f, 7.0f); + float small = SettingSkinUtil.m(11.5f, 5.7f); + String displayText = display == null || display.isBlank() ? "NONE" : display; + boolean none = displayText.equalsIgnoreCase("NONE"); + float pad = SettingSkinUtil.m(6f, 5f); + float gap = SettingSkinUtil.m(4f, 4f); + float chipPad = SettingSkinUtil.m(7f, 5f); + float chipH = SettingSkinUtil.m(22f, 13.5f); + float minLabelW = SettingSkinUtil.m(72f, 38f); + float modeW = modeText == null ? 0f : Math.max(SettingSkinUtil.m(36f, 25f), UnifiedSettingsSkin.textWidth(font, modeText, small) + SettingSkinUtil.m(10f, 8f)); + float modeBlockW = modeW > 0f ? modeW + gap : 0f; + float rawTextW = UnifiedSettingsSkin.textWidth(font, displayText, size); + float wantedChipW = rawTextW + chipPad * 2f; + + float sameLineMaxChipW = Math.max(SettingSkinUtil.m(48f, 30f), w - pad * 3f - modeBlockW - minLabelW); + boolean nextLine = sameLineMaxChipW < SettingSkinUtil.m(48f, 30f); + float maxChipW = nextLine + ? Math.max(SettingSkinUtil.m(48f, 30f), w - pad * 2f - modeBlockW) + : sameLineMaxChipW; + float chipW = Math.max(SettingSkinUtil.m(48f, 30f), Math.min(wantedChipW, maxChipW)); + float labelMax = nextLine ? w - pad * 2f : Math.max(1f, w - pad * 3f - modeBlockW - chipW); + if (!nextLine && labelMax < minLabelW) { + nextLine = true; + maxChipW = Math.max(SettingSkinUtil.m(48f, 30f), w - pad * 2f - modeBlockW); + chipW = Math.max(SettingSkinUtil.m(48f, 30f), Math.min(wantedChipW, maxChipW)); + labelMax = w - pad * 2f; + } + + float rowH = nextLine ? SettingSkinUtil.m(48f, 31f) : SettingSkinUtil.m(38f, 22f); + float cardX = x + SettingSkinUtil.m(2f, 2f); + float cardY = y + SettingSkinUtil.m(3f, 2f); + float cardW = Math.max(1f, w - SettingSkinUtil.m(4f, 4f)); + float cardH = Math.max(SettingSkinUtil.m(30f, 18f), rowH - SettingSkinUtil.m(6f, 4f)); + float cardRadius = SettingSkinUtil.m(8f, 5f); + boolean hover = UnifiedSettingsSkin.inside(mx, my, cardX, cardY, cardW, cardH); + float hoverAnim = bindHoverAnim(uiObj, hover); + float waitAnim = bindWaitAnim(uiObj, waiting); + + UnifiedSettingsSkin.drawCard(cardX, cardY, cardW, cardH, cardRadius, 0.38f + hoverAnim * 0.24f + waitAnim * 0.10f); + if (hoverAnim > 0.001f || waitAnim > 0.001f) { + int strokeA = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(hoverAnim * 72f)); + int strokeB = UnifiedSettingsSkin.accentGradientStart(waitAnim * 0.70f); + ClickGuiRenderer.drawRoundedRectStroke(cardX, cardY, cardW, cardH, cardRadius, SettingSkinUtil.m(0.65f, 0.42f), UnifiedSettingsSkin.mix(strokeA, strokeB, Math.max(waitAnim, hoverAnim * 0.28f))); + } + + float labelY = y + (nextLine ? SettingSkinUtil.m(7f, 4f) : (rowH - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f); + float chipY = nextLine ? y + SettingSkinUtil.m(27f, 16f) : y + (rowH - chipH) * 0.5f; + float chipX; + float modeX = 0f; + float modeY = chipY; + if (nextLine) { + chipX = cardX + pad; + if (modeW > 0f) modeX = x + w - pad - modeW; + } else { + chipX = x + w - pad - chipW; + if (modeW > 0f) modeX = chipX - gap - modeW; + } + + int labelColor = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.72f + hoverAnim * 0.18f + waitAnim * 0.10f); + ClickGuiRenderer.drawText(font, UnifiedSettingsSkin.fit(font, label, size, Math.max(1f, labelMax)), cardX + pad, labelY, size, labelColor, false); + if (modeW > 0f) renderSmallModeChip(modeX, modeY, modeW, chipH, modeText, small, hoverAnim, waitAnim); + + float chipInset = SettingSkinUtil.m(0.8f, 0.45f); + float chipDrawX = chipX + chipInset; + float chipDrawY = chipY + chipInset; + float chipDrawW = Math.max(1f, chipW - chipInset * 2f); + float chipDrawH = Math.max(1f, chipH - chipInset * 2f); + float chipRadius = Math.max(0f, SettingSkinUtil.m(6f, 4f) - chipInset); + if (waiting) { + UnifiedSettingsSkin.drawAccent(chipDrawX, chipDrawY, chipDrawW, chipDrawH, chipRadius, 0.62f + hoverAnim * 0.18f); + ClickGuiRenderer.drawRoundedRectStrokeGradient(chipDrawX, chipDrawY, chipDrawW, chipDrawH, chipRadius, SettingSkinUtil.m(0.75f, 0.45f), UnifiedSettingsSkin.accentGradientStart(0.92f), UnifiedSettingsSkin.accentGradientEnd(0.92f), UnifiedSettingsSkin.ACCENT_GRADIENT_ANGLE); + } else { + UnifiedSettingsSkin.drawSurface(chipDrawX, chipDrawY, chipDrawW, chipDrawH, chipRadius, none ? 0.30f + hoverAnim * 0.12f : 0.46f + hoverAnim * 0.16f); + int chipStroke = none + ? UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(34f + hoverAnim * 36f)) + : UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, Math.round(48f + hoverAnim * 54f)); + ClickGuiRenderer.drawRoundedRectStroke(chipDrawX, chipDrawY, chipDrawW, chipDrawH, chipRadius, SettingSkinUtil.m(0.65f, 0.42f), chipStroke); + } + + float contentX = chipX + chipPad; + float contentW = Math.max(1f, chipW - chipPad * 2f); + float textX = contentX; + if (rawTextW <= contentW) { + textX = chipX + (chipW - rawTextW) * 0.5f; + } + float textY = chipY + (chipH - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f; + boolean textClip = ScissorFunction.pushRaw(contentX, chipY, contentW, chipH); + int valueColor = waiting + ? 0xFFFFFFFF + : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, none ? 0.20f + hoverAnim * 0.12f : 0.82f + hoverAnim * 0.12f); + if (rawTextW > contentW + 0.5f) { + SettingSkinUtil.drawBindMarquee(font, displayText, contentX, textY, rawTextW, contentW, size, valueColor); + } else { + ClickGuiRenderer.drawText(font, displayText, textX, textY, size, valueColor, false); + } + if (textClip) ScissorFunction.pop(); + + if (uiObj instanceof KeyBindSetting.UiState ui) { + ui.lastX = x; ui.lastY = y; ui.lastW = w; ui.lastH = rowH; + ui.lastBx = chipX; ui.lastBy = chipY; ui.lastBw = chipW; ui.lastBh = chipH; + } else if (uiObj instanceof FunctionBindSetting.UiState ui) { + ui.lastX = x; ui.lastY = y; ui.lastW = w; ui.lastH = rowH; + ui.lastBx = chipX; ui.lastBy = chipY; ui.lastBw = chipW; ui.lastBh = chipH; + } + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BooleanSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BooleanSetting.java index 1402644..4181020 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BooleanSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BooleanSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BooleanSettingRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BooleanSettingRenderer.java new file mode 100644 index 0000000..6e3d83e --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/BooleanSettingRenderer.java @@ -0,0 +1,128 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.wav.ClickGuiSounds; + +final class BooleanSettingRenderer { + private BooleanSettingRenderer() { + } + + record LayoutBoolean(String[] lines, float lineH, float labelY, float controlY, float rowH) { + } + + static void render(BooleanSetting setting, float x, float y, float w, float mx, float my) { + UnifiedSettingsSkin.syncTheme(); + BooleanSetting.UiState ui = setting.ui(); + LayoutBoolean layout = booleanLayout(setting, w); + ui.lastX = x; + ui.lastY = y; + ui.lastW = w; + ui.lastH = layout.rowH; + + boolean enabled = setting.get(); + float dt = AnimationUtility.deltaTime(); + ui.anim = AnimationUtility.approach(ui.anim, enabled ? 1f : 0f, dt, 13f); + boolean hover = UnifiedSettingsSkin.inside(mx, my, x, y, w, layout.rowH); + ui.hoverAnim = AnimationUtility.approach(ui.hoverAnim, hover ? 1f : 0f, dt, 12f); + + TextRenderer font = SettingSkinUtil.modules() ? UnifiedSettingsSkin.fontRegular() : ClickGuiRenderer.getIosevkaRegular(); + float labelSize = SettingSkinUtil.m(18f, 6.8f); + + float cardX = x + SettingSkinUtil.m(2f, 2f); + float cardY = y + SettingSkinUtil.m(3f, 2f); + float cardW = Math.max(1f, w - SettingSkinUtil.m(4f, 4f)); + float cardH = Math.max(SettingSkinUtil.m(28f, 17f), layout.rowH - SettingSkinUtil.m(6f, 4f)); + float radius = SettingSkinUtil.m(8f, 5f); + UnifiedSettingsSkin.drawCard(cardX, cardY, cardW, cardH, radius, 0.42f + ui.hoverAnim * 0.24f); + float cardStrokeAnim = Math.max(ui.hoverAnim, ui.anim); + if (cardStrokeAnim > 0.001f) { + int strokeA = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(ui.hoverAnim * 82f)); + int strokeB = UnifiedSettingsSkin.accentGradientStart(ui.anim * 0.50f); + ClickGuiRenderer.drawRoundedRectStroke(cardX, cardY, cardW, cardH, radius, SettingSkinUtil.m(0.65f, 0.42f), UnifiedSettingsSkin.mix(strokeA, strokeB, Math.max(ui.anim, ui.hoverAnim * 0.28f))); + } + + float sw = SettingSkinUtil.m(39f, 16f); + float sh = SettingSkinUtil.m(18f, 8f); + float sx = cardX + SettingSkinUtil.m(8f, 5f); + float sy = cardY + (cardH - sh) * 0.5f; + ui.lastControlX = sx; + ui.lastControlY = sy; + ui.lastControlW = sw; + ui.lastControlH = sh; + + int bgOffA = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE, UnifiedSettingsSkin.SURFACE_HOVER, 0.45f + ui.hoverAnim * 0.20f); + int bgOffB = UnifiedSettingsSkin.mix(bgOffA, 0xFF000000, 0.30f); + int bgOnA = UnifiedSettingsSkin.accentGradientStart(1f); + int bgOnB = UnifiedSettingsSkin.accentGradientEnd(1f); + int bgA = UnifiedSettingsSkin.mix(bgOffA, bgOnA, ui.anim); + int bgB = UnifiedSettingsSkin.mix(bgOffB, bgOnB, ui.anim); + ClickGuiRenderer.drawRoundedRectGradient(sx, sy, sw, sh, sh * 0.5f, bgA, bgB, UnifiedSettingsSkin.ACCENT_GRADIENT_ANGLE); + ClickGuiRenderer.drawRoundedRectStroke(sx, sy, sw, sh, sh * 0.5f, SettingSkinUtil.m(0.65f, 0.42f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 50 + Math.round(ui.hoverAnim * 44f))); + + float knob = sh - SettingSkinUtil.m(4f, 2.4f); + float kx = sx + SettingSkinUtil.m(2f, 1.2f) + (sw - knob - SettingSkinUtil.m(4f, 2.4f)) * AnimationUtility.easeInOutCubic(ui.anim); + float ky = sy + (sh - knob) * 0.5f; + int knobCol = UnifiedSettingsSkin.mix(0xFFECEEF2, 0xFFFFFFFF, ui.anim * 0.55f + ui.hoverAnim * 0.18f); + ClickGuiRenderer.drawRoundedRect(kx, ky, knob, knob, knob * 0.5f, knobCol); + + float labelX = sx + sw + SettingSkinUtil.m(9f, 6f); + int labelColor = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.72f + ui.hoverAnim * 0.16f + ui.anim * 0.12f); + + ClickGuiRenderer.beginTextBatch(); + for (int i = 0; i < layout.lines.length; i++) { + ClickGuiRenderer.drawText(font, layout.lines[i], labelX, y + layout.labelY + i * (layout.lineH + SettingSkinUtil.m(2f, 0.7f)), labelSize, labelColor, false); + } + ClickGuiRenderer.endTextBatch(); + } + + static void mouseClicked(BooleanSetting setting, double mx, double my, int button) { + if (button != 0) return; + BooleanSetting.UiState ui = setting.ui(); + if (!UnifiedSettingsSkin.inside(mx, my, ui.lastX, ui.lastY, ui.lastW, ui.lastH)) return; + setting.set(!setting.get()); + ClickGuiSounds.changeMode(); + if (setting.getParent() != null) setting.getParent().saveConfig(); + } + + static float getHeight(BooleanSetting setting) { + return booleanLayout(setting, setting.ui().lastW > 0f ? setting.ui().lastW : SettingSkinUtil.m(170f, 115f)).rowH; + } + + private static LayoutBoolean booleanLayout(BooleanSetting setting, float width) { + BooleanSetting.UiState ui = setting.ui(); + TextRenderer font = SettingSkinUtil.modules() ? UnifiedSettingsSkin.fontRegular() : ClickGuiRenderer.getIosevkaRegular(); + float labelSize = SettingSkinUtil.m(18f, 6.8f); + float switchW = SettingSkinUtil.m(39f, 16f); + String labelText = setting.getDisplayName(); + boolean needsLayout = !Float.isFinite(ui.layoutW) + || Math.abs(ui.layoutW - width) > 0.5f + || !labelText.equals(ui.layoutLabel); + if (needsLayout) { + float lineH = UnifiedSettingsSkin.textHeight(font, labelSize); + float labelMaxW = Math.max(SettingSkinUtil.m(72f, 36f), width - switchW - SettingSkinUtil.m(31f, 18f)); + var linesList = ClickGuiRenderer.wrapText(font, labelText, labelSize, labelMaxW, 2); + String[] lines = linesList.toArray(new String[0]); + float gap = SettingSkinUtil.m(2f, 0.7f); + float textBlockH = lines.length * lineH + Math.max(0, lines.length - 1) * gap; + float contentH = Math.max(textBlockH, SettingSkinUtil.m(18f, 8f)); + float minRow = SettingSkinUtil.m(44f, 24f); + ui.layoutW = width; + ui.layoutLabel = labelText; + ui.layoutLines = lines; + ui.layoutLineH = lineH; + ui.layoutRowH = Math.max(minRow, contentH + SettingSkinUtil.m(14f, 8f)); + ui.layoutLabelY = (ui.layoutRowH - textBlockH) * 0.5f; + ui.layoutControlY = (ui.layoutRowH - SettingSkinUtil.m(18f, 8f)) * 0.5f; + } + return new LayoutBoolean(ui.layoutLines, ui.layoutLineH, ui.layoutLabelY, ui.layoutControlY, ui.layoutRowH); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorPresetStore.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorPresetStore.java index 1a6e092..d689430 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorPresetStore.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorPresetStore.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSetting.java index 78b8c39..db85845 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingDrag.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingDrag.java new file mode 100644 index 0000000..6b21567 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingDrag.java @@ -0,0 +1,99 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.config.values.ColorValue; + +import java.awt.Color; + +final class ColorSettingDrag { + private ColorSettingDrag() { + } + + static boolean colorDragActive(ColorSetting.UiState ui) { + return ui.sbFocused || ui.hFocused || ui.aFocused || ui.rFocused || ui.gFocused || ui.bFocused || ui.aRgbFocused; + } + + static void clearColorFocus(ColorSetting.UiState ui) { + ui.sbFocused = false; + ui.hFocused = false; + ui.aFocused = false; + ui.rFocused = false; + ui.gFocused = false; + ui.bFocused = false; + ui.aRgbFocused = false; + } + + static void updateColorDrag(ColorSetting.UiState ui, ColorValue value, float mx, float my, boolean hasAlpha) { + if (value.isRainbow()) return; + if (ui.sbFocused) { + ui.saturation = UnifiedSettingsSkin.clamp01((mx - ui.squareX) / Math.max(1f, ui.squareW)); + ui.brightness = UnifiedSettingsSkin.clamp01(1f - ((my - ui.squareY) / Math.max(1f, ui.squareH))); + setColorFromHsb(ui, value); + } + if (ui.hFocused) { + ui.hue = UnifiedSettingsSkin.clamp01((my - ui.hueY) / Math.max(1f, ui.hueH)); + setColorFromHsb(ui, value); + } + if (hasAlpha && ui.aFocused) { + ui.alpha = Math.round(UnifiedSettingsSkin.clamp01(1f - ((my - ui.alphaY) / Math.max(1f, ui.alphaH))) * 255f); + setColorFromHsb(ui, value); + } + if (ui.rFocused) { + ui.red = Math.round(UnifiedSettingsSkin.clamp01((mx - ui.rX) / Math.max(1f, ui.rW)) * 255f); + setColorFromRgb(ui, value); + } + if (ui.gFocused) { + ui.green = Math.round(UnifiedSettingsSkin.clamp01((mx - ui.gX) / Math.max(1f, ui.gW)) * 255f); + setColorFromRgb(ui, value); + } + if (ui.bFocused) { + ui.blue = Math.round(UnifiedSettingsSkin.clamp01((mx - ui.bX) / Math.max(1f, ui.bW)) * 255f); + setColorFromRgb(ui, value); + } + if (hasAlpha && ui.aRgbFocused) { + ui.alpha = Math.round(UnifiedSettingsSkin.clamp01((mx - ui.aX) / Math.max(1f, ui.aW)) * 255f); + setColorFromRgb(ui, value); + } + } + + static void syncColorFromValue(ColorSetting.UiState ui, ColorValue value) { + int argb = value.getArgb(); + ui.lastArgb = argb; + ui.red = (argb >>> 16) & 0xFF; + ui.green = (argb >>> 8) & 0xFF; + ui.blue = argb & 0xFF; + ui.alpha = (argb >>> 24) & 0xFF; + float[] hsb = Color.RGBtoHSB(ui.red, ui.green, ui.blue, null); + if (hsb[1] > 0.0001f && hsb[2] > 0.0001f) ui.hue = hsb[0]; + ui.saturation = hsb[1]; + ui.brightness = hsb[2]; + } + + static void setColorFromHsb(ColorSetting.UiState ui, ColorValue value) { + int rgb = Color.HSBtoRGB(ui.hue, ui.saturation, ui.brightness) & 0x00FFFFFF; + ui.red = (rgb >>> 16) & 0xFF; + ui.green = (rgb >>> 8) & 0xFF; + ui.blue = rgb & 0xFF; + applyColor(value, ((value.supportsAlpha() ? ui.alpha : 255) << 24) | rgb); + } + + static void setColorFromRgb(ColorSetting.UiState ui, ColorValue value) { + float[] hsb = Color.RGBtoHSB(ui.red, ui.green, ui.blue, null); + if (hsb[1] > 0.0001f && hsb[2] > 0.0001f) ui.hue = hsb[0]; + ui.saturation = hsb[1]; + ui.brightness = hsb[2]; + applyColor(value, ((value.supportsAlpha() ? ui.alpha : 255) << 24) | (ui.red << 16) | (ui.green << 8) | ui.blue); + } + + static void applyColor(ColorValue value, int argb) { + if (value.supportsAlpha()) + value.set(String.format("#%02X%02X%02X%02X", (argb >>> 24) & 0xFF, (argb >>> 16) & 0xFF, (argb >>> 8) & 0xFF, argb & 0xFF)); + else value.set(String.format("#%02X%02X%02X", (argb >>> 16) & 0xFF, (argb >>> 8) & 0xFF, argb & 0xFF)); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingHexInput.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingHexInput.java new file mode 100644 index 0000000..807fbdd --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingHexInput.java @@ -0,0 +1,177 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.config.values.ColorValue; +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.svg.SvgRenderOptions; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ScissorFunction; +import dev.loki.lovisual.util.text.ClipboardUtil; +import org.lwjgl.glfw.GLFW; + +final class ColorSettingHexInput { + private ColorSettingHexInput() { + } + + static void beginHexEdit(ColorSetting.UiState ui, ColorValue value) { + ui.hexFocused = true; + ui.hexBuffer = ColorSettingHexState.displayHex(value, value.supportsAlpha()); + ui.hexCursor = ui.hexBuffer.length(); + ui.hexSelection.clear(); + ui.hexErrorAnim = 0f; + } + + static void cancelHexEdit(ColorSetting.UiState ui, ColorValue value) { + ui.hexFocused = false; + ui.hexBuffer = ColorSettingHexState.displayHex(value, value.supportsAlpha()); + ui.hexCursor = ui.hexBuffer.length(); + ui.hexSelection.clear(); + ui.hexErrorAnim = 0f; + } + + static boolean commitHexEdit(ColorSetting setting, ColorValue value, ColorSetting.UiState ui, boolean save) { + Integer parsed = ColorSettingHexState.parseHexInput(ui.hexBuffer, value.supportsAlpha()); + if (parsed == null) { + ui.hexErrorAnim = 1f; + return false; + } + ColorSettingDrag.applyColor(value, parsed); + ColorSettingDrag.syncColorFromValue(ui, value); + ui.hexFocused = false; + ui.hexSelection.clear(); + if (save && setting.getParent() != null) setting.getParent().saveConfig(); + return true; + } + + static boolean keyPressed(ColorSetting setting, int keyCode, int scanCode, int modifiers) { + ColorSetting.UiState ui = setting.ui(); + if (!ui.hexFocused) return false; + ColorValue value = setting.value(); + boolean ctrl = (modifiers & GLFW.GLFW_MOD_CONTROL) != 0; + if (ctrl && keyCode == GLFW.GLFW_KEY_A) { + ColorSettingHexState.selectAllHex(ui); + return true; + } + if (ctrl && keyCode == GLFW.GLFW_KEY_C) { + ClipboardUtil.copy("#" + ColorSettingHexState.selectedOrAllHex(ui)); + return true; + } + if (ctrl && keyCode == GLFW.GLFW_KEY_V) { + ColorSettingHexState.insertHexText(ui, ClipboardUtil.get()); + return true; + } + if (ctrl && keyCode == GLFW.GLFW_KEY_X) { + ClipboardUtil.copy("#" + ColorSettingHexState.selectedOrAllHex(ui)); + ColorSettingHexState.deleteHexSelection(ui); + return true; + } + switch (keyCode) { + case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> { + commitHexEdit(setting, value, ui, true); + return true; + } + case GLFW.GLFW_KEY_ESCAPE -> { + cancelHexEdit(ui, value); + return true; + } + case GLFW.GLFW_KEY_BACKSPACE -> { + if (!ColorSettingHexState.deleteHexSelection(ui) && ui.hexCursor > 0) { + ui.hexBuffer = ui.hexBuffer.substring(0, ui.hexCursor - 1) + ui.hexBuffer.substring(ui.hexCursor); + ui.hexCursor--; + } + return true; + } + case GLFW.GLFW_KEY_DELETE -> { + if (!ColorSettingHexState.deleteHexSelection(ui) && ui.hexCursor < ui.hexBuffer.length()) + ui.hexBuffer = ui.hexBuffer.substring(0, ui.hexCursor) + ui.hexBuffer.substring(ui.hexCursor + 1); + return true; + } + case GLFW.GLFW_KEY_LEFT -> { + ColorSettingHexState.moveHexCursor(ui, -1, (modifiers & GLFW.GLFW_MOD_SHIFT) != 0); + return true; + } + case GLFW.GLFW_KEY_RIGHT -> { + ColorSettingHexState.moveHexCursor(ui, 1, (modifiers & GLFW.GLFW_MOD_SHIFT) != 0); + return true; + } + case GLFW.GLFW_KEY_HOME -> { + ColorSettingHexState.setHexCursor(ui, 0, (modifiers & GLFW.GLFW_MOD_SHIFT) != 0); + return true; + } + case GLFW.GLFW_KEY_END -> { + ColorSettingHexState.setHexCursor(ui, ui.hexBuffer.length(), (modifiers & GLFW.GLFW_MOD_SHIFT) != 0); + return true; + } + } + return true; + } + + static boolean charTyped(ColorSetting setting, char chr, int modifiers) { + ColorSetting.UiState ui = setting.ui(); + if (!ui.hexFocused) return false; + if (ColorSettingHexState.isHexChar(chr)) { + ColorSettingHexState.insertHexText(ui, String.valueOf(chr)); + } else if (chr == '#') { + // accepted as no-op so pasted/manual values with # don't flash error + } else { + ui.hexErrorAnim = 1f; + } + return true; + } + + static void renderHexInput(ColorSetting.UiState ui, ColorValue value, float mx, float my, float slide) { + float y = ui.hexY + slide; + boolean hover = UnifiedSettingsSkin.inside(mx, my, ui.hexX, y, ui.hexW, ui.hexH); + float dt = AnimationUtility.deltaTime(); + ui.hexAnim = AnimationUtility.approach(ui.hexAnim, ui.hexFocused ? 1f : hover ? 0.55f : 0f, dt, 13f); + ui.hexErrorAnim = AnimationUtility.approach(ui.hexErrorAnim, 0f, dt, 7.5f); + if (ui.hexFocused) ui.hexCursorBlink += dt * 2.2f; + else ui.hexCursorBlink = 0f; + int bg = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, ui.hexAnim), 58 + Math.round(35f * ui.hexAnim)); + int stroke = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 70), 0xFFFF5F66, ui.hexErrorAnim); + ClickGuiRenderer.drawRoundedRect(ui.hexX, y, ui.hexW, ui.hexH, SettingSkinUtil.m(5f, 3f), bg); + ClickGuiRenderer.drawRoundedRectStroke(ui.hexX, y, ui.hexW, ui.hexH, SettingSkinUtil.m(5f, 3f), SettingSkinUtil.m(0.7f, 0.45f), stroke); + int icon = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_MUTED, 185); + Renderer2D.COLOR.svg("brush", ui.hexX + SettingSkinUtil.m(5f, 3f), y + (ui.hexH - SettingSkinUtil.m(9f, 6f)) * 0.5f, SettingSkinUtil.m(9f, 6f), SettingSkinUtil.m(9f, 6f), + SvgRenderOptions.overrideColor(icon)); + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float size = SettingSkinUtil.m(11.5f, 5.4f); + String text = ui.hexFocused ? ui.hexBuffer : ColorSettingHexState.displayHex(value, value.supportsAlpha()); + String label = "HEX"; + float tx = ui.hexX + SettingSkinUtil.m(18f, 12f); + ClickGuiRenderer.drawText(font, label, tx, y + (ui.hexH - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f, size, UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_MUTED, 175), false); + float labelW = UnifiedSettingsSkin.textWidth(font, label, size) + SettingSkinUtil.m(5f, 4f); + int textColor = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_PRIMARY, 0xFFFF7777, ui.hexErrorAnim); + float textX = tx + labelW; + float textY = y + (ui.hexH - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f; + float textClipW = Math.max(1f, ui.hexW - (textX - ui.hexX) - SettingSkinUtil.m(25f, 17f)); + boolean hexClip = ScissorFunction.pushRaw(textX, y, textClipW, ui.hexH); + String prefix = "#"; + String draw = prefix + text; + if (ui.hexFocused) { + SettingTextInputUtil.renderInlineSelection(font, text, ColorSettingHexState.hexSelStart(ui), ColorSettingHexState.hexSelEnd(ui), textX + UnifiedSettingsSkin.textWidth(font, prefix, size), textY, size, ui.hexH, y); + ClickGuiRenderer.drawText(font, draw, textX, textY, size, textColor, false); + if (((int) (ui.hexCursorBlink * 2f) & 1) == 0) { + int cursor = Math.max(0, Math.min(ui.hexCursor, ui.hexBuffer.length())); + float cx = textX + UnifiedSettingsSkin.textWidth(font, prefix + ui.hexBuffer.substring(0, cursor), size) + SettingSkinUtil.m(0.5f, 0.3f); + ClickGuiRenderer.drawRect(cx, y + SettingSkinUtil.m(3f, 2f), SettingSkinUtil.m(0.65f, 0.4f), ui.hexH - SettingSkinUtil.m(6f, 4f), UnifiedSettingsSkin.withAlpha(textColor, 190)); + } + } else { + String display = "#" + UnifiedSettingsSkin.fit(font, text, size, textClipW); + ClickGuiRenderer.drawText(font, display, textX, textY, size, textColor, false); + } + if (hexClip) ScissorFunction.pop(); + float preview = ui.hexH - SettingSkinUtil.m(5f, 3f); + float px = ui.hexX + ui.hexW - preview - SettingSkinUtil.m(3f, 2f); + SettingSkinUtil.renderChecker(px, y + (ui.hexH - preview) * 0.5f, preview, preview, SettingSkinUtil.m(3f, 2f), SettingSkinUtil.m(3f, 2f)); + ClickGuiRenderer.drawRoundedRect(px, y + (ui.hexH - preview) * 0.5f, preview, preview, SettingSkinUtil.m(3f, 2f), value.getArgb()); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingHexState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingHexState.java new file mode 100644 index 0000000..bebcb66 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingHexState.java @@ -0,0 +1,147 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.config.values.ColorValue; +import dev.loki.lovisual.render.engine.text.TextRenderer; + +final class ColorSettingHexState { + private ColorSettingHexState() { + } + + static String displayHex(ColorValue value, boolean hasAlpha) { + int argb = value.isRainbow() ? parseFallbackHex(value.rainbowFallbackHex(), value.getArgb()) : value.getArgb(); + if (hasAlpha) + return String.format("%02X%02X%02X%02X", (argb >>> 24) & 0xFF, (argb >>> 16) & 0xFF, (argb >>> 8) & 0xFF, argb & 0xFF); + return String.format("%02X%02X%02X", (argb >>> 16) & 0xFF, (argb >>> 8) & 0xFF, argb & 0xFF); + } + + private static int parseFallbackHex(String hex, int fallback) { + Integer parsed = parseHexInput(hex, true); + return parsed == null ? fallback : parsed; + } + + static Integer parseHexInput(String raw, boolean hasAlpha) { + if (raw == null) return null; + StringBuilder clean = new StringBuilder(); + String t = raw.trim(); + if (t.startsWith("#")) t = t.substring(1); + if (t.startsWith("0x") || t.startsWith("0X")) t = t.substring(2); + for (int i = 0; i < t.length(); i++) { + char c = t.charAt(i); + if (isHexChar(c)) clean.append(Character.toUpperCase(c)); + } + String s = clean.toString(); + try { + if (s.length() == 3) { + int r = Integer.parseInt(s.substring(0, 1) + s.substring(0, 1), 16); + int g = Integer.parseInt(s.substring(1, 2) + s.substring(1, 2), 16); + int b = Integer.parseInt(s.substring(2, 3) + s.substring(2, 3), 16); + return 0xFF000000 | (r << 16) | (g << 8) | b; + } + if (s.length() == 6) { + return (int) (0xFF000000L | Long.parseUnsignedLong(s, 16)); + } + if (hasAlpha && s.length() == 8) { + return (int) Long.parseUnsignedLong(s, 16); + } + if (!hasAlpha && s.length() == 8) { + return (int) (0xFF000000L | (Long.parseUnsignedLong(s.substring(2), 16) & 0xFFFFFFL)); + } + } catch (Throwable ignored) { + } + return null; + } + + static boolean isHexChar(char c) { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); + } + + static void insertHexText(ColorSetting.UiState ui, String text) { + if (text == null || text.isEmpty()) return; + deleteHexSelection(ui); + StringBuilder insert = new StringBuilder(); + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (isHexChar(c)) insert.append(Character.toUpperCase(c)); + } + if (insert.length() == 0) { + ui.hexErrorAnim = 1f; + return; + } + int maxLen = 8; + int allowed = Math.max(0, maxLen - ui.hexBuffer.length()); + if (insert.length() > allowed) { + insert.setLength(allowed); + ui.hexErrorAnim = 1f; + } + if (insert.length() == 0) return; + ui.hexBuffer = ui.hexBuffer.substring(0, ui.hexCursor) + insert + ui.hexBuffer.substring(ui.hexCursor); + ui.hexCursor += insert.length(); + } + + static void selectAllHex(ColorSetting.UiState ui) { + ui.hexSelection.begin(0, 0); + ui.hexSelection.updateCaret(0, ui.hexBuffer == null ? 0 : ui.hexBuffer.length()); + ui.hexCursor = ui.hexBuffer == null ? 0 : ui.hexBuffer.length(); + } + + static String selectedOrAllHex(ColorSetting.UiState ui) { + if (hasHexSelection(ui)) return ui.hexBuffer.substring(hexSelStart(ui), hexSelEnd(ui)); + return ui.hexBuffer == null ? "" : ui.hexBuffer; + } + + static boolean hasHexSelection(ColorSetting.UiState ui) { + return ui.hexSelection.hasRange(); + } + + static int hexSelStart(ColorSetting.UiState ui) { + return hasHexSelection(ui) ? Math.max(0, Math.min(ui.hexSelection.start(), ui.hexBuffer.length())) : -1; + } + + static int hexSelEnd(ColorSetting.UiState ui) { + return hasHexSelection(ui) ? Math.max(0, Math.min(ui.hexSelection.end(), ui.hexBuffer.length())) : -1; + } + + static boolean deleteHexSelection(ColorSetting.UiState ui) { + if (!hasHexSelection(ui)) return false; + int start = hexSelStart(ui); + int end = hexSelEnd(ui); + ui.hexBuffer = ui.hexBuffer.substring(0, start) + ui.hexBuffer.substring(end); + ui.hexCursor = start; + ui.hexSelection.clear(); + return true; + } + + static void moveHexCursor(ColorSetting.UiState ui, int dir, boolean shift) { + setHexCursor(ui, Math.max(0, Math.min(ui.hexBuffer.length(), ui.hexCursor + dir)), shift); + } + + static void setHexCursor(ColorSetting.UiState ui, int pos, boolean shift) { + int next = Math.max(0, Math.min(ui.hexBuffer == null ? 0 : ui.hexBuffer.length(), pos)); + if (shift) { + if (!ui.hexSelection.hasRange()) ui.hexSelection.begin(0, ui.hexCursor); + ui.hexSelection.updateCaret(0, next); + } else { + ui.hexSelection.clear(); + } + ui.hexCursor = next; + ui.hexCursorBlink = 0f; + } + + static void setHexCursorFromMouse(ColorSetting.UiState ui, float mx, boolean shift) { + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float size = SettingSkinUtil.m(11.5f, 5.4f); + String label = "HEX"; + float tx = ui.hexX + SettingSkinUtil.m(18f, 12f); + float labelW = UnifiedSettingsSkin.textWidth(font, label, size) + SettingSkinUtil.m(5f, 4f); + float textX = tx + labelW + UnifiedSettingsSkin.textWidth(font, "#", size); + int cursor = SettingTextInputUtil.caretFromText(font, ui.hexBuffer == null ? "" : ui.hexBuffer, size, textX, mx); + setHexCursor(ui, cursor, shift); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingLayout.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingLayout.java new file mode 100644 index 0000000..b010545 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingLayout.java @@ -0,0 +1,152 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.render.engine.animation.AnimationUtility; + +final class ColorSettingLayout { + private ColorSettingLayout() { + } + + static float colorHeaderH() { + return SettingSkinUtil.m(48f, 18f); + } + + static float colorExpandedHeight(ColorSetting.UiState ui, boolean hasAlpha) { + int bars = hasAlpha ? 4 : 3; + float rgbBlock = (SettingSkinUtil.m(8f, 7f) + bars * SettingSkinUtil.m(9f, 7f) + (bars - 1) * SettingSkinUtil.m(5f, 5f)) * colorRgbReveal(ui); + float presets = SettingSkinUtil.m(20f, 12f); + float presetsExpanded = (SettingSkinUtil.m(5f, 3f) + SettingSkinUtil.m(44f, 31f)) * colorPresetReveal(ui); + float hex = SettingSkinUtil.m(18f, 12f); + float actions = SettingSkinUtil.m(17f, 10.5f); + return Math.max(0f, colorHeaderH() + SettingSkinUtil.m(6f, 5f) + SettingSkinUtil.m(82f, 60f) + rgbBlock + SettingSkinUtil.m(6f, 4f) + presets + presetsExpanded + SettingSkinUtil.m(5f, 3f) + hex + SettingSkinUtil.m(5f, 3f) + actions + SettingSkinUtil.m(14f, 8f) - colorHeaderH()); + } + + static float colorRgbReveal(ColorSetting.UiState ui) { + return AnimationUtility.easeInOutCubic(UnifiedSettingsSkin.clamp01(ui.rgbExpandAnim)); + } + + static float colorPresetReveal(ColorSetting.UiState ui) { + return AnimationUtility.easeInOutCubic(UnifiedSettingsSkin.clamp01(ui.presetsExpandAnim)); + } + + static float colorLayoutAnim(ColorSetting.UiState ui) { + float t = UnifiedSettingsSkin.clamp01(ui.expandAnim); + return ui.editing ? AnimationUtility.clamp(AnimationUtility.easeOutBack(t, 0.42f), 0f, 1.02f) : 1f - AnimationUtility.easeInCubic(1f - t); + } + + static float colorReveal(ColorSetting.UiState ui) { + float t = UnifiedSettingsSkin.clamp01(ui.expandAnim); + if (ui.editing) return AnimationUtility.easeInOutCubic(UnifiedSettingsSkin.clamp01((t - 0.08f) / 0.92f)); + return 1f - AnimationUtility.easeInCubic(1f - t); + } + + static void layoutColor(ColorSetting.UiState ui, float x, float y, float w, boolean hasAlpha) { + int verticalBars = hasAlpha ? 2 : 1; + float sidePad = SettingSkinUtil.m(5f, 5f); + float rightInset = SettingSkinUtil.m(5f, 4f); + float barW = SettingSkinUtil.m(6f, 4f); + float barGap = SettingSkinUtil.m(7f, 5f); + ui.squareX = x + sidePad; + ui.squareY = y + colorHeaderH() + SettingSkinUtil.m(6f, 5f); + ui.squareH = SettingSkinUtil.m(82f, 60f); + ui.squareW = Math.max(SettingSkinUtil.m(74f, 44f), w - sidePad * 2f - rightInset - verticalBars * barW - verticalBars * barGap); + ui.hueX = ui.squareX + ui.squareW + barGap; + ui.hueY = ui.squareY; + ui.hueW = barW; + ui.hueH = ui.squareH; + if (hasAlpha) { + ui.alphaX = ui.hueX + barW + barGap; + ui.alphaY = ui.squareY; + ui.alphaW = barW; + ui.alphaH = ui.squareH; + } else { + ui.alphaX = ui.hueX; + ui.alphaY = ui.hueY; + ui.alphaW = 0f; + ui.alphaH = 0f; + } + float rgbReveal = colorRgbReveal(ui); + int rgbBars = hasAlpha ? 4 : 3; + float rgbGapY = SettingSkinUtil.m(5f, 5f); + float rgbH = SettingSkinUtil.m(9f, 7f); + float valueColumn = SettingSkinUtil.m(25f, 18f); + float rgbBlockFull = SettingSkinUtil.m(8f, 7f) + rgbBars * rgbH + Math.max(0, rgbBars - 1) * rgbGapY; + float rgbBlockH = rgbBlockFull * rgbReveal; + ui.rX = ui.squareX; + ui.rY = ui.squareY + ui.squareH + SettingSkinUtil.m(8f, 7f); + ui.rW = Math.max(1f, ui.squareW - valueColumn); + ui.rH = rgbH; + ui.gX = ui.rX; + ui.gY = ui.rY + rgbH + rgbGapY; + ui.gW = ui.rW; + ui.gH = ui.rH; + ui.bX = ui.rX; + ui.bY = ui.gY + rgbH + rgbGapY; + ui.bW = ui.rW; + ui.bH = ui.rH; + if (hasAlpha) { + ui.aX = ui.rX; + ui.aY = ui.bY + rgbH + rgbGapY; + ui.aW = ui.rW; + ui.aH = ui.rH; + } else { + ui.aX = ui.rX; + ui.aY = ui.bY; + ui.aW = 0f; + ui.aH = 0f; + } + ui.rgbBottom = ui.squareY + ui.squareH + rgbBlockH; + + float actionX = ui.squareX; + float actionW = Math.max(1f, x + w - SettingSkinUtil.m(10f, 10f) - actionX); + float gap = SettingSkinUtil.m(4f, 4f); + ui.presetX = actionX; + ui.presetY = ui.rgbBottom + SettingSkinUtil.m(6f, 4f); + ui.presetW = actionW; + ui.presetH = SettingSkinUtil.m(20f, 12f); + + float presetButtonW = SettingSkinUtil.m(20f, 14f); + ui.presetToggleW = presetButtonW; + ui.savePresetW = presetButtonW; + ui.deletePresetW = presetButtonW; + ui.presetToggleX = actionX + actionW - presetButtonW * 3f; + ui.savePresetX = ui.presetToggleX + presetButtonW; + ui.deletePresetX = ui.savePresetX + presetButtonW; + ui.savePresetY = ui.presetY; + ui.deletePresetY = ui.presetY; + ui.presetToggleY = ui.presetY; + ui.savePresetH = ui.presetH; + ui.deletePresetH = ui.presetH; + ui.presetToggleH = ui.presetH; + + float listReveal = colorPresetReveal(ui); + float listGap = SettingSkinUtil.m(5f, 3f); + float listFullH = SettingSkinUtil.m(44f, 31f); + ui.presetListX = actionX; + ui.presetListY = ui.presetY + ui.presetH + listGap; + ui.presetListW = actionW; + ui.presetListH = listFullH * listReveal; + + ui.hexX = actionX; + ui.hexY = ui.presetY + ui.presetH + (listGap + listFullH) * listReveal + SettingSkinUtil.m(5f, 3f); + ui.hexW = actionW; + ui.hexH = SettingSkinUtil.m(18f, 12f); + float actionY = ui.hexY + ui.hexH + SettingSkinUtil.m(5f, 3f); + float bw = Math.max(1f, (actionW - gap) / 2f); + float bh = SettingSkinUtil.m(17f, 10.5f); + ui.sliderX = actionX; + ui.sliderY = actionY; + ui.sliderW = bw; + ui.sliderH = bh; + ui.rnbX = ui.sliderX + bw + gap; + ui.rnbY = actionY; + ui.rnbW = bw; + ui.rnbH = bh; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingMath.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingMath.java new file mode 100644 index 0000000..b6875f3 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingMath.java @@ -0,0 +1,23 @@ +/* + * 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.features.gui.clickgui.settings; + +import java.awt.Color; + +final class ColorSettingMath { + private ColorSettingMath() { + } + + static int hsbToArgb(float h, float s, float b, int a) { + return (Math.max(0, Math.min(255, a)) << 24) | (Color.HSBtoRGB(h, s, b) & 0x00FFFFFF); + } + + static int withAlpha(int argb, int a) { + return (argb & 0x00FFFFFF) | ((Math.max(0, Math.min(255, a)) & 0xFF) << 24); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingNoAlpha.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingNoAlpha.java index b43a3df..b3c5d66 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingNoAlpha.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingNoAlpha.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingPresetHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingPresetHandler.java new file mode 100644 index 0000000..cb14361 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingPresetHandler.java @@ -0,0 +1,95 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.config.values.ColorValue; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; + +final class ColorSettingPresetHandler { + private ColorSettingPresetHandler() { + } + + static boolean handleColorPresetClick(ColorSetting setting, ColorValue value, ColorSetting.UiState ui, double mx, double my, int button) { + if (button != 0 && button != 1) return false; + float slide = (1f - ColorSettingLayout.colorReveal(ui)) * SettingSkinUtil.m(8f, 8f); + float rowY = ui.presetY + slide; + float swatch = SettingSkinUtil.m(12f, 8f); + float gap = SettingSkinUtil.m(4f, 3f); + float sx = ui.presetX + swatch + gap; + float available = Math.max(1f, ui.presetToggleX - gap - sx); + java.util.List presets = ColorPresetStore.presets(); + int max = Math.max(1, (int) Math.floor(available / (swatch + gap))); + for (int i = 0; i < Math.min(max, presets.size()); i++) { + float px = sx + i * (swatch + gap); + if (!UnifiedSettingsSkin.inside(mx, my, px, rowY + (ui.presetH - swatch) * 0.5f, swatch, swatch)) continue; + int color = presets.get(i); + if (button == 1) ColorPresetStore.removeExact(color); + else ColorSettingDrag.applyColor(value, color); + ColorSettingDrag.syncColorFromValue(ui, value); + if (setting.getParent() != null) setting.getParent().saveConfig(); + return true; + } + if (button == 0 && UnifiedSettingsSkin.inside(mx, my, ui.presetToggleX, rowY, ui.presetToggleW, ui.presetToggleH)) { + ui.presetsExpanded = !ui.presetsExpanded; + return true; + } + if (button == 0 && UnifiedSettingsSkin.inside(mx, my, ui.savePresetX, rowY, ui.savePresetW, ui.savePresetH)) { + ColorPresetStore.add(value.getArgb()); + return true; + } + if (button == 0 && UnifiedSettingsSkin.inside(mx, my, ui.deletePresetX, rowY, ui.deletePresetW, ui.deletePresetH)) { + ColorPresetStore.removeClosest(value.getArgb()); + return true; + } + + if (ui.presetsExpanded && ui.presetsExpandAnim > 0.05f) { + float listY = ui.presetListY + slide; + if (button == 0 && ui.presetsMaxScroll > 0.5f && UnifiedSettingsSkin.inside(mx, my, ui.presetScrollbarX - SettingSkinUtil.m(3f, 2f), ui.presetScrollbarY, ui.presetScrollbarW + SettingSkinUtil.m(6f, 4f), ui.presetScrollbarH)) { + ui.presetsScrollbarDragging = true; + ui.presetsScrollbarDragOffset = (float) my - ui.presetScrollbarHandleY; + updatePresetScrollbarDrag(ui, (float) my); + return true; + } + if (UnifiedSettingsSkin.inside(mx, my, ui.presetListX, listY, ui.presetListW, Math.max(1f, ui.presetListH))) { + float pad = SettingSkinUtil.m(5f, 4f); + float innerX = ui.presetListX + pad; + float innerY = listY + pad; + int cols = Math.max(1, (int) Math.floor((ui.presetListW - pad * 2f - SettingSkinUtil.m(7f, 5f)) / (swatch + gap))); + float rowH = swatch + gap; + float localX = (float) mx - innerX; + float localY = (float) my - innerY + ui.presetsScroll; + int col = (int) Math.floor(localX / (swatch + gap)); + int row = (int) Math.floor(localY / rowH); + if (col >= 0 && col < cols && row >= 0) { + float cellX = col * (swatch + gap); + float cellY = row * rowH; + if (localX >= cellX && localX <= cellX + swatch && localY >= cellY && localY <= cellY + swatch) { + int index = row * cols + col; + if (index >= 0 && index < presets.size()) { + int color = presets.get(index); + if (button == 1) ColorPresetStore.removeExact(color); + else ColorSettingDrag.applyColor(value, color); + ColorSettingDrag.syncColorFromValue(ui, value); + if (setting.getParent() != null) setting.getParent().saveConfig(); + return true; + } + } + } + } + } + return false; + } + + static void updatePresetScrollbarDrag(ColorSetting.UiState ui, float my) { + if (ui.presetsMaxScroll <= 0.5f) return; + float track = Math.max(1f, ui.presetScrollbarH - ui.presetScrollbarHandleH); + float handleY = AnimationUtility.clamp(my - ui.presetsScrollbarDragOffset, ui.presetScrollbarY, ui.presetScrollbarY + track); + float t = (handleY - ui.presetScrollbarY) / track; + ui.presetsScroll = AnimationUtility.clamp(t * ui.presetsMaxScroll, 0f, ui.presetsMaxScroll); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingPresetRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingPresetRenderer.java new file mode 100644 index 0000000..5b183b4 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingPresetRenderer.java @@ -0,0 +1,169 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.config.values.ColorValue; +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.svg.SvgRenderOptions; +import dev.loki.lovisual.render.helpers.ScissorFunction; + +final class ColorSettingPresetRenderer { + private ColorSettingPresetRenderer() { + } + + static void renderColorPresets(ColorSetting.UiState ui, ColorValue value, float mx, float my, float slide) { + float y = ui.presetY + slide; + float swatch = SettingSkinUtil.m(12f, 8f); + float gap = SettingSkinUtil.m(4f, 3f); + int labelColor = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_MUTED, 190); + Renderer2D.COLOR.svg("palette", ui.presetX, y + (ui.presetH - swatch) * 0.5f, swatch, swatch, + SvgRenderOptions.overrideColor(labelColor)); + float sx = ui.presetX + swatch + gap; + float available = Math.max(1f, ui.presetToggleX - gap - sx); + java.util.List presets = ColorPresetStore.presets(); + int max = Math.max(1, (int) Math.floor(available / (swatch + gap))); + for (int i = 0; i < Math.min(max, presets.size()); i++) { + float px = sx + i * (swatch + gap); + int color = presets.get(i); + boolean hover = UnifiedSettingsSkin.inside(mx, my, px, y + (ui.presetH - swatch) * 0.5f, swatch, swatch); + renderPresetSwatch(px, y + (ui.presetH - swatch) * 0.5f, swatch, presetDisplayColor(value, color), hover, value.supportsAlpha()); + } + + float dt = AnimationUtility.deltaTime(); + ui.presetsToggleHoverAnim = AnimationUtility.approach(ui.presetsToggleHoverAnim, UnifiedSettingsSkin.inside(mx, my, ui.presetToggleX, y, ui.presetToggleW, ui.presetToggleH) ? 1f : 0f, dt, 14f); + ui.savePresetHoverAnim = AnimationUtility.approach(ui.savePresetHoverAnim, UnifiedSettingsSkin.inside(mx, my, ui.savePresetX, y, ui.savePresetW, ui.savePresetH) ? 1f : 0f, dt, 14f); + ui.deletePresetHoverAnim = AnimationUtility.approach(ui.deletePresetHoverAnim, UnifiedSettingsSkin.inside(mx, my, ui.deletePresetX, y, ui.deletePresetW, ui.deletePresetH) ? 1f : 0f, dt, 14f); + renderColorPresetActionGroup(ui, y); + + float reveal = ColorSettingLayout.colorPresetReveal(ui); + if (reveal <= 0.035f) { + ui.presetsMaxScroll = 0f; + ui.presetsContentH = 0f; + ui.presetsViewportH = 0f; + ui.presetListH = 0f; + ui.presetScrollbarX = ui.presetScrollbarY = ui.presetScrollbarW = ui.presetScrollbarH = 0f; + return; + } + + float listY = ui.presetListY + slide; + float listH = ui.presetListH; + if (listH <= SettingSkinUtil.m(2f, 1.2f)) { + ui.presetsMaxScroll = 0f; + return; + } + float pad = SettingSkinUtil.m(5f, 4f); + UnifiedSettingsSkin.drawSurface(ui.presetListX, listY, ui.presetListW, listH, SettingSkinUtil.m(6f, 4f), 0.68f * reveal); + if (UnifiedSettingsSkin.STROKE_GRADIENT_ENABLED) { + UnifiedSettingsSkin.drawStroke(ui.presetListX, listY, ui.presetListW, listH, SettingSkinUtil.m(6f, 4f), SettingSkinUtil.m(0.65f, 0.42f), 0.32f * reveal); + } else { + ClickGuiRenderer.drawRoundedRectStroke(ui.presetListX, listY, ui.presetListW, listH, SettingSkinUtil.m(6f, 4f), SettingSkinUtil.m(0.65f, 0.42f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(58f * reveal))); + } + + int cols = Math.max(1, (int) Math.floor((ui.presetListW - pad * 2f - SettingSkinUtil.m(7f, 5f)) / (swatch + gap))); + int rows = (int) Math.ceil(presets.size() / (double) cols); + float rowH = swatch + gap; + ui.presetsContentH = Math.max(0f, rows * rowH - gap); + ui.presetsViewportH = Math.max(1f, listH - pad * 2f); + ui.presetsMaxScroll = Math.max(0f, ui.presetsContentH - ui.presetsViewportH); + ui.presetsScroll = AnimationUtility.clamp(ui.presetsScroll, 0f, ui.presetsMaxScroll); + + boolean clip = ScissorFunction.pushRaw(ui.presetListX + pad, listY + pad, Math.max(1f, ui.presetListW - pad * 2f - (ui.presetsMaxScroll > 0.5f ? SettingSkinUtil.m(5f, 4f) : 0f)), ui.presetsViewportH); + for (int i = 0; i < presets.size(); i++) { + int col = i % cols; + int row = i / cols; + float px = ui.presetListX + pad + col * (swatch + gap); + float py = listY + pad + row * rowH - ui.presetsScroll; + if (py + swatch < listY + pad - 1f || py > listY + pad + ui.presetsViewportH + 1f) continue; + boolean hover = UnifiedSettingsSkin.inside(mx, my, px, py, swatch, swatch); + renderPresetSwatch(px, py, swatch, presetDisplayColor(value, presets.get(i)), hover, value.supportsAlpha()); + } + if (clip) ScissorFunction.pop(); + + if (ui.presetsMaxScroll > 0.5f) { + ui.presetScrollbarW = SettingSkinUtil.m(2.5f, 1.7f); + ui.presetScrollbarX = ui.presetListX + ui.presetListW - pad - ui.presetScrollbarW; + ui.presetScrollbarY = listY + pad; + ui.presetScrollbarH = ui.presetsViewportH; + ui.presetScrollbarHandleH = Math.max(SettingSkinUtil.m(12f, 8f), ui.presetScrollbarH * (ui.presetScrollbarH / (ui.presetScrollbarH + ui.presetsMaxScroll))); + ui.presetScrollbarHandleY = ui.presetScrollbarY + (ui.presetScrollbarH - ui.presetScrollbarHandleH) * (ui.presetsScroll / Math.max(1f, ui.presetsMaxScroll)); + boolean barHover = UnifiedSettingsSkin.inside(mx, my, ui.presetScrollbarX - SettingSkinUtil.m(3f, 2f), ui.presetScrollbarY, ui.presetScrollbarW + SettingSkinUtil.m(6f, 4f), ui.presetScrollbarH) || ui.presetsScrollbarDragging; + ui.presetsScrollbarHoverAnim = AnimationUtility.approach(ui.presetsScrollbarHoverAnim, barHover ? 1f : 0f, dt, 14f); + ClickGuiRenderer.drawRoundedRect(ui.presetScrollbarX, ui.presetScrollbarY, ui.presetScrollbarW, ui.presetScrollbarH, ui.presetScrollbarW * 0.5f, UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 42)); + ClickGuiRenderer.drawRoundedRect(ui.presetScrollbarX, ui.presetScrollbarHandleY, ui.presetScrollbarW, ui.presetScrollbarHandleH, ui.presetScrollbarW * 0.5f, UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_MUTED, 95 + Math.round(65f * ui.presetsScrollbarHoverAnim))); + if (ui.presetsScrollbarDragging) { + ColorSettingPresetHandler.updatePresetScrollbarDrag(ui, my); + } + } else { + ui.presetScrollbarX = ui.presetScrollbarY = ui.presetScrollbarW = ui.presetScrollbarH = 0f; + } + } + + private static void renderPresetSwatch(float x, float y, float size, int color, boolean hover, boolean alphaContext) { + int stroke = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, hover ? 130 : 78); + if (alphaContext || ((color >>> 24) & 0xFF) < 255) { + SettingSkinUtil.renderChecker(x, y, size, size, SettingSkinUtil.m(3f, 2f), SettingSkinUtil.m(3f, 2f)); + } + ClickGuiRenderer.drawRoundedRect(x, y, size, size, SettingSkinUtil.m(3f, 2f), color); + ClickGuiRenderer.drawRoundedRectStroke(x, y, size, size, SettingSkinUtil.m(3f, 2f), SettingSkinUtil.m(0.7f, 0.45f), stroke); + } + + private static int presetDisplayColor(ColorValue value, int argb) { + return value.supportsAlpha() ? argb : (0xFF000000 | (argb & 0x00FFFFFF)); + } + + private static void renderColorPresetActionGroup(ColorSetting.UiState ui, float y) { + float x = ui.presetToggleX; + float w = ui.presetToggleW + ui.savePresetW + ui.deletePresetW; + float h = ui.presetToggleH; + float hover = Math.max(ui.presetsToggleHoverAnim, Math.max(ui.savePresetHoverAnim, ui.deletePresetHoverAnim)); + float active = ui.presetsExpanded ? 1f : 0f; + if (ui.presetsExpanded) { + UnifiedSettingsSkin.drawAccent(x, y, w, h, SettingSkinUtil.m(5f, 4f), 0.32f + hover * 0.16f); + } else { + UnifiedSettingsSkin.drawSurface(x, y, w, h, SettingSkinUtil.m(5f, 4f), 0.58f + hover * 0.24f); + } + int stroke = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 62), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 150), active); + stroke = UnifiedSettingsSkin.mix(stroke, UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_MUTED, 120), hover * 0.35f); + if (UnifiedSettingsSkin.STROKE_GRADIENT_ENABLED || ui.presetsExpanded) { + ClickGuiRenderer.drawRoundedRectStrokeGradient(x, y, w, h, SettingSkinUtil.m(5f, 4f), SettingSkinUtil.m(0.7f, 0.45f), UnifiedSettingsSkin.accentGradientStart(0.58f + active * 0.20f), UnifiedSettingsSkin.accentGradientEnd(0.58f + active * 0.20f), UnifiedSettingsSkin.ACCENT_GRADIENT_ANGLE); + } else { + ClickGuiRenderer.drawRoundedRectStroke(x, y, w, h, SettingSkinUtil.m(5f, 4f), SettingSkinUtil.m(0.7f, 0.45f), stroke); + } + + float sepW = SettingSkinUtil.m(0.7f, 0.45f); + int sep = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 55 + Math.round(35f * hover)); + ClickGuiRenderer.drawRect(ui.savePresetX, y + SettingSkinUtil.m(3f, 2f), sepW, h - SettingSkinUtil.m(6f, 4f), sep); + ClickGuiRenderer.drawRect(ui.deletePresetX, y + SettingSkinUtil.m(3f, 2f), sepW, h - SettingSkinUtil.m(6f, 4f), sep); + + renderPresetActionIcon("folder-closed", ui.presetToggleX, y, ui.presetToggleW, h, ui.presetsToggleHoverAnim, ui.presetsExpanded); + renderPresetActionIcon("heart-plus", ui.savePresetX, y, ui.savePresetW, h, ui.savePresetHoverAnim, false); + renderPresetActionIcon("minus", ui.deletePresetX, y, ui.deletePresetW, h, ui.deletePresetHoverAnim, false); + } + + private static void renderPresetActionIcon(String icon, float x, float y, float w, float h, float hoverAnim, boolean active) { + float size = Math.min(SettingSkinUtil.m(11f, 7f), Math.max(SettingSkinUtil.m(8f, 5f), Math.min(w, h) - SettingSkinUtil.m(5f, 3f))); + int color = active + ? UnifiedSettingsSkin.ACCENT + : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.55f + hoverAnim * 0.35f); + Renderer2D.COLOR.svg(icon, x + (w - size) * 0.5f, y + (h - size) * 0.5f, size, size, + SvgRenderOptions.overrideColor(color)); + } + + static void renderColorActions(ColorSetting.UiState ui, ColorValue value, float mx, float my, float slide) { + float dt = AnimationUtility.deltaTime(); + boolean rgbHover = UnifiedSettingsSkin.inside(mx, my, ui.sliderX, ui.sliderY + slide, ui.sliderW, ui.sliderH); + boolean rnbHover = UnifiedSettingsSkin.inside(mx, my, ui.rnbX, ui.rnbY + slide, ui.rnbW, ui.rnbH); + ui.sliderHoverAnim = AnimationUtility.approach(ui.sliderHoverAnim, rgbHover ? 1f : 0f, dt, 14f); + ui.rnbHoverAnim = AnimationUtility.approach(ui.rnbHoverAnim, rnbHover ? 1f : 0f, dt, 14f); + ui.rnbOffAnim = AnimationUtility.approach(ui.rnbOffAnim, value.isRainbow() ? 0f : 1f, dt, 8f); + SettingSkinUtil.renderChipButton(ui.sliderX, ui.sliderY + slide, ui.sliderW, ui.sliderH, "RGB", ui.sliderHoverAnim, ui.showRgbBars); + SettingSkinUtil.renderRainbowChipButton(ui.rnbX, ui.rnbY + slide, ui.rnbW, ui.rnbH, ui.rnbHoverAnim, value.isRainbow()); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingRenderer.java new file mode 100644 index 0000000..bc4a8f6 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingRenderer.java @@ -0,0 +1,190 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.config.values.ColorValue; +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ScissorFunction; + +final class ColorSettingRenderer { + private ColorSettingRenderer() { + } + + static void render(ColorSetting setting, float x, float y, float w, float mx, float my) { + UnifiedSettingsSkin.syncTheme(); + ColorSetting.UiState ui = setting.ui(); + ColorValue value = setting.value(); + boolean hasAlpha = value.supportsAlpha(); + ui.lastX = x; + ui.lastY = y; + ui.lastW = w; + if (!ui.hexFocused && !ColorSettingDrag.colorDragActive(ui)) ColorSettingDrag.syncColorFromValue(ui, value); + ui.rainbow = value.isRainbow(); + if (ui.rainbow) ColorSettingDrag.clearColorFocus(ui); + + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float labelSize = SettingSkinUtil.m(18f, 7f); + float previewW = SettingSkinUtil.m(34f, 20f); + float previewH = SettingSkinUtil.m(16f, 10f); + float previewX = x + w - previewW - SettingSkinUtil.m(5f, 5f); + float previewY = y + (ColorSettingLayout.colorHeaderH() - previewH) * 0.5f; + String label = UnifiedSettingsSkin.fit(font, setting.getDisplayName(), labelSize, Math.max(1f, previewX - x - SettingSkinUtil.m(12f, 12f))); + ClickGuiRenderer.drawText(font, label, x + SettingSkinUtil.m(7f, 7f), y + (ColorSettingLayout.colorHeaderH() - UnifiedSettingsSkin.textHeight(font, labelSize)) * 0.5f, labelSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); + renderColorPreview(previewX, previewY, previewW, previewH, value.getArgb(), SettingSkinUtil.m(3f, 3f)); + ui.previewGlowAnim = AnimationUtility.approach(ui.previewGlowAnim, ui.editing ? 1f : UnifiedSettingsSkin.inside(mx, my, previewX, previewY, previewW, previewH) ? 0.55f : 0f, 0.20f); + + if (ui.expandAnim <= 0.001f) return; + ColorSettingLayout.layoutColor(ui, x, y, w, hasAlpha); + ColorSettingDrag.updateColorDrag(ui, value, mx, my, hasAlpha); + float reveal = ColorSettingLayout.colorReveal(ui); + float slide = ui.editing ? (1f - reveal) * SettingSkinUtil.m(8f, 8f) : (1f - reveal) * SettingSkinUtil.m(6f, 6f); + float clipY = y + ColorSettingLayout.colorHeaderH(); + float clipH = (ColorSettingLayout.colorExpandedHeight(ui, hasAlpha) + SettingSkinUtil.m(5f, 5f)) * reveal; + boolean clipped = clipH > 0.5f && ScissorFunction.pushRaw(x, clipY, w, clipH); + + float cx = ui.squareX; + float cy = ui.squareY + slide; + float containerX = cx - SettingSkinUtil.m(5f, 5f); + float containerY = cy - SettingSkinUtil.m(5f, 5f); + float containerW = x + w - SettingSkinUtil.m(5f, 5f) - containerX; + float containerH = ColorSettingLayout.colorExpandedHeight(ui, hasAlpha); + UnifiedSettingsSkin.drawSurface(containerX, containerY, containerW, containerH, SettingSkinUtil.m(6f, 6f), 0.90f); + + ColorSettingSquareRenderer.renderColorSquare(ui, cy); + ColorSettingSquareRenderer.renderHueBar(ui, slide); + if (hasAlpha) { + SettingSkinUtil.renderChecker(ui.alphaX, ui.alphaY + slide, ui.alphaW, ui.alphaH, SettingSkinUtil.m(3f, 3f), SettingSkinUtil.m(3f, 3f)); + ColorSettingSquareRenderer.renderAlphaBar(ui, slide); + } + if (ui.rgbExpandAnim > 0.001f) ColorSettingSquareRenderer.renderRgbBars(ui, hasAlpha, slide); + ColorSettingSquareRenderer.renderColorMarkers(ui, hasAlpha, slide); + ColorSettingPresetRenderer.renderColorPresets(ui, value, mx, my, slide); + ColorSettingHexInput.renderHexInput(ui, value, mx, my, slide); + ColorSettingPresetRenderer.renderColorActions(ui, value, mx, my, slide); + if (clipped) ScissorFunction.pop(); + } + + static void mouseClicked(ColorSetting setting, double mx, double my, int button) { + if (button != 0 && button != 1 && button != 2) return; + ColorSetting.UiState ui = setting.ui(); + ColorValue value = setting.value(); + boolean hasAlpha = value.supportsAlpha(); + float pw = SettingSkinUtil.m(34f, 20f); + float ph = SettingSkinUtil.m(16f, 10f); + float px = ui.lastX + ui.lastW - pw - SettingSkinUtil.m(5f, 5f); + float py = ui.lastY + (ColorSettingLayout.colorHeaderH() - ph) * 0.5f; + boolean headerHit = UnifiedSettingsSkin.inside(mx, my, ui.lastX, ui.lastY, ui.lastW, ColorSettingLayout.colorHeaderH()); + if (button == 0 && headerHit) { + ui.editing = !ui.editing; + ColorSettingDrag.clearColorFocus(ui); + return; + } + if (!ui.editing) return; + ColorSettingLayout.layoutColor(ui, ui.lastX, ui.lastY, ui.lastW, hasAlpha); + if (ColorSettingPresetHandler.handleColorPresetClick(setting, value, ui, mx, my, button)) return; + if (button != 0) return; + if (UnifiedSettingsSkin.inside(mx, my, ui.hexX, ui.hexY, ui.hexW, ui.hexH)) { + ColorSettingHexInput.beginHexEdit(ui, value); + ColorSettingHexState.setHexCursorFromMouse(ui, (float) mx, false); + return; + } + if (ui.hexFocused) { + if (!ColorSettingHexInput.commitHexEdit(setting, value, ui, true)) return; + } + if (UnifiedSettingsSkin.inside(mx, my, ui.sliderX, ui.sliderY, ui.sliderW, ui.sliderH)) { + ui.showRgbBars = !ui.showRgbBars; + ColorSettingDrag.clearColorFocus(ui); + return; + } + if (UnifiedSettingsSkin.inside(mx, my, ui.rnbX, ui.rnbY, ui.rnbW, ui.rnbH)) { + value.set(value.isRainbow() ? value.rainbowFallbackHex() : value.toRainbowValue()); + ColorSettingDrag.syncColorFromValue(ui, value); + ColorSettingDrag.clearColorFocus(ui); + if (setting.getParent() != null) setting.getParent().saveConfig(); + return; + } + if (value.isRainbow()) return; + ColorSettingDrag.clearColorFocus(ui); + if (UnifiedSettingsSkin.inside(mx, my, ui.squareX, ui.squareY, ui.squareW, ui.squareH)) { + ui.sbFocused = true; + return; + } + if (UnifiedSettingsSkin.inside(mx, my, ui.hueX - SettingSkinUtil.m(2f, 2f), ui.hueY, ui.hueW + SettingSkinUtil.m(4f, 4f), ui.hueH)) { + ui.hFocused = true; + return; + } + if (hasAlpha && UnifiedSettingsSkin.inside(mx, my, ui.alphaX - SettingSkinUtil.m(2f, 2f), ui.alphaY, ui.alphaW + SettingSkinUtil.m(4f, 4f), ui.alphaH)) { + ui.aFocused = true; + return; + } + if (ui.showRgbBars && ui.rgbExpandAnim > 0.20f) { + if (UnifiedSettingsSkin.inside(mx, my, ui.rX, ui.rY, ui.rW, ui.rH)) { + ui.rFocused = true; + return; + } + if (UnifiedSettingsSkin.inside(mx, my, ui.gX, ui.gY, ui.gW, ui.gH)) { + ui.gFocused = true; + return; + } + if (UnifiedSettingsSkin.inside(mx, my, ui.bX, ui.bY, ui.bW, ui.bH)) { + ui.bFocused = true; + return; + } + if (hasAlpha && UnifiedSettingsSkin.inside(mx, my, ui.aX, ui.aY, ui.aW, ui.aH)) ui.aRgbFocused = true; + } + } + + static void mouseReleased(ColorSetting setting, double mx, double my, int button) { + if (button != 0) return; + ColorSetting.UiState ui = setting.ui(); + boolean changed = ui.sbFocused || ui.hFocused || ui.aFocused || ui.rFocused || ui.gFocused || ui.bFocused || ui.aRgbFocused; + ui.presetsScrollbarDragging = false; + ColorSettingDrag.clearColorFocus(ui); + if (changed && setting.getParent() != null) setting.getParent().saveConfig(); + } + + static void mouseClickedOutside(ColorSetting setting, double mx, double my, int button) { + if (button != 0) return; + ColorSetting.UiState ui = setting.ui(); + if (ui.hexFocused) { + ColorSettingHexInput.commitHexEdit(setting, setting.value(), ui, true); + } + ui.presetsScrollbarDragging = false; + ColorSettingDrag.clearColorFocus(ui); + } + + static boolean mouseScrolled(ColorSetting setting, double mx, double my, double amount) { + ColorSetting.UiState ui = setting.ui(); + if (!ui.editing || !ui.presetsExpanded || ui.presetsMaxScroll <= 0.5f) return false; + float slide = (1f - ColorSettingLayout.colorReveal(ui)) * SettingSkinUtil.m(8f, 8f); + float listY = ui.presetListY + slide; + if (!UnifiedSettingsSkin.inside(mx, my, ui.presetListX, listY, ui.presetListW, Math.max(1f, ui.presetListH))) + return false; + ui.presetsScroll = AnimationUtility.clamp(ui.presetsScroll - (float) amount * SettingSkinUtil.m(16f, 12f), 0f, ui.presetsMaxScroll); + return true; + } + + static float getHeight(ColorSetting setting) { + ColorSetting.UiState ui = setting.ui(); + boolean hasAlpha = setting.value().supportsAlpha(); + float dt = AnimationUtility.deltaTime(); + ui.expandAnim = AnimationUtility.approach(ui.expandAnim, ui.editing ? 1f : 0f, dt, ui.editing ? 5.2f : 4.0f); + ui.expandAnim = AnimationUtility.snap(ui.expandAnim, ui.editing ? 1f : 0f, 0.001f); + ui.rgbExpandAnim = AnimationUtility.approach(ui.rgbExpandAnim, ui.showRgbBars ? 1f : 0f, dt, ui.showRgbBars ? 10f : 9f); + ui.rgbExpandAnim = AnimationUtility.snap(ui.rgbExpandAnim, ui.showRgbBars ? 1f : 0f, 0.002f); + ui.presetsExpandAnim = AnimationUtility.approach(ui.presetsExpandAnim, ui.presetsExpanded ? 1f : 0f, dt, ui.presetsExpanded ? 9.5f : 8.5f); + ui.presetsExpandAnim = AnimationUtility.snap(ui.presetsExpandAnim, ui.presetsExpanded ? 1f : 0f, 0.002f); + return ColorSettingLayout.colorHeaderH() + ColorSettingLayout.colorExpandedHeight(ui, hasAlpha) * ColorSettingLayout.colorLayoutAnim(ui); + } + + private static void renderColorPreview(float x, float y, float w, float h, int color, float radius) { + ClickGuiRenderer.drawRoundedRect(x, y, w, h, radius, color); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingSquareRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingSquareRenderer.java new file mode 100644 index 0000000..4ceabd4 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ColorSettingSquareRenderer.java @@ -0,0 +1,86 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ScissorFunction; + +final class ColorSettingSquareRenderer { + private ColorSettingSquareRenderer() { + } + + static void renderColorSquare(ColorSetting.UiState ui, float y) { + int left = ColorSettingMath.hsbToArgb(ui.hue, 0f, 1f, 255); + int right = ColorSettingMath.hsbToArgb(ui.hue, 1f, 1f, 255); + ClickGuiRenderer.drawRoundedRect(ui.squareX, y, ui.squareW, ui.squareH, SettingSkinUtil.m(6f, 6f), right); + ClickGuiRenderer.drawGradientRect(ui.squareX, y, ui.squareW, ui.squareH, left, right, right, left); + ClickGuiRenderer.drawGradientRect(ui.squareX, y, ui.squareW, ui.squareH, 0x00FFFFFF, 0x00FFFFFF, 0xFF000000, 0xFF000000); + } + + static void renderHueBar(ColorSetting.UiState ui, float slide) { + int steps = Math.max(1, Math.round(ui.hueH)); + for (int i = 0; i < steps; i++) { + float h = i / Math.max(1f, ui.hueH - 1f); + ClickGuiRenderer.drawCircle(ui.hueX + ui.hueW * 0.5f, ui.hueY + slide + i, ui.hueW * 0.5f, ColorSettingMath.hsbToArgb(h, 1f, 1f, 255)); + } + } + + static void renderAlphaBar(ColorSetting.UiState ui, float slide) { + int rgb = ColorSettingMath.hsbToArgb(ui.hue, ui.saturation, ui.brightness, 255); + ClickGuiRenderer.drawGradientRect(ui.alphaX, ui.alphaY + slide, ui.alphaW, ui.alphaH, ColorSettingMath.withAlpha(rgb, 255), ColorSettingMath.withAlpha(rgb, 255), ColorSettingMath.withAlpha(rgb, 0), ColorSettingMath.withAlpha(rgb, 0)); + } + + static void renderRgbBars(ColorSetting.UiState ui, boolean hasAlpha, float slide) { + float reveal = ColorSettingLayout.colorRgbReveal(ui); + if (reveal <= 0.001f) return; + int alpha = hasAlpha ? ui.alpha : 255; + float top = ui.rY + slide - SettingSkinUtil.m(2f, 2f); + float bottom = (hasAlpha ? ui.aY + ui.aH : ui.bY + ui.bH) + slide + SettingSkinUtil.m(2f, 2f); + boolean clip = ScissorFunction.pushRaw(ui.rX - SettingSkinUtil.m(10f, 8f), top, ui.rW + SettingSkinUtil.m(40f, 28f), Math.max(1f, (bottom - top) * reveal)); + renderRgbBar("R", ui.rX, ui.rY + slide, ui.rW, ui.rH, (alpha << 24) | (ui.green << 8) | ui.blue, (alpha << 24) | (255 << 16) | (ui.green << 8) | ui.blue, ui.red / 255f, ui.red); + renderRgbBar("G", ui.gX, ui.gY + slide, ui.gW, ui.gH, (alpha << 24) | (ui.red << 16) | ui.blue, (alpha << 24) | (ui.red << 16) | (255 << 8) | ui.blue, ui.green / 255f, ui.green); + renderRgbBar("B", ui.bX, ui.bY + slide, ui.bW, ui.bH, (alpha << 24) | (ui.red << 16) | (ui.green << 8), (alpha << 24) | (ui.red << 16) | (ui.green << 8) | 255, ui.blue / 255f, ui.blue); + if (hasAlpha) { + SettingSkinUtil.renderChecker(ui.aX + SettingSkinUtil.m(8f, 8f), ui.aY + slide, Math.max(1f, ui.aW - SettingSkinUtil.m(16f, 8f)), ui.aH, SettingSkinUtil.m(3f, 3f), SettingSkinUtil.m(2.5f, 2.5f)); + renderRgbBar("A", ui.aX, ui.aY + slide, ui.aW, ui.aH, (ui.red << 16) | (ui.green << 8) | ui.blue, (255 << 24) | (ui.red << 16) | (ui.green << 8) | ui.blue, ui.alpha / 255f, ui.alpha); + } + if (clip) ScissorFunction.pop(); + } + + private static void renderRgbBar(String label, float x, float y, float w, float h, int c0, int c1, float progress, int value) { + TextRenderer font = UnifiedSettingsSkin.fontLight(); + float size = SettingSkinUtil.m(11f, 5.5f); + ClickGuiRenderer.drawText(font, label, x, y - SettingSkinUtil.m(0.3f, 0.3f), size, UnifiedSettingsSkin.TEXT_MUTED, false); + float bx = x + SettingSkinUtil.m(8f, 8f); + float bw = Math.max(1f, w - SettingSkinUtil.m(16f, 8f)); + ClickGuiRenderer.drawGradientRect(bx, y, bw, h, c0, c1, c1, c0); + float px = bx + UnifiedSettingsSkin.clamp01(progress) * bw; + ClickGuiRenderer.drawRoundedRect(px - SettingSkinUtil.m(1f, 1f), y - SettingSkinUtil.m(1f, 1f), SettingSkinUtil.m(2f, 2f), h + SettingSkinUtil.m(2f, 2f), SettingSkinUtil.m(1f, 1f), UnifiedSettingsSkin.TEXT_PRIMARY); + String valueText = Integer.toString(Math.max(0, Math.min(255, value))); + float valueSize = SettingSkinUtil.m(10.5f, 5.2f); + float valueX = x + w + SettingSkinUtil.m(3f, 3f); + float valueY = y + (h - UnifiedSettingsSkin.textHeight(font, valueSize)) * 0.5f - SettingSkinUtil.m(0.2f, 0.15f); + ClickGuiRenderer.drawText(font, valueText, valueX, valueY, valueSize, UnifiedSettingsSkin.TEXT_MUTED, false); + } + + static void renderColorMarkers(ColorSetting.UiState ui, boolean hasAlpha, float slide) { + float sbX = ui.squareX + ui.saturation * ui.squareW; + float sbY = ui.squareY + slide + (1f - ui.brightness) * ui.squareH; + ClickGuiRenderer.drawCircle(sbX, sbY, SettingSkinUtil.m(4f, 4f), 0xFF000000); + ClickGuiRenderer.drawCircle(sbX, sbY, SettingSkinUtil.m(3f, 3f), 0xFFFFFFFF); + float hueY = ui.hueY + slide + ui.hue * Math.max(1f, ui.hueH - 1f); + ClickGuiRenderer.drawCircle(ui.hueX + ui.hueW * 0.5f, hueY, SettingSkinUtil.m(4f, 4f), 0xFF000000); + ClickGuiRenderer.drawCircle(ui.hueX + ui.hueW * 0.5f, hueY, SettingSkinUtil.m(3f, 3f), 0xFFFFFFFF); + if (hasAlpha) { + float alphaY = ui.alphaY + slide + (1f - ui.alpha / 255f) * Math.max(1f, ui.alphaH - 1f); + ClickGuiRenderer.drawCircle(ui.alphaX + ui.alphaW * 0.5f, alphaY, SettingSkinUtil.m(4f, 4f), 0xFF000000); + ClickGuiRenderer.drawCircle(ui.alphaX + ui.alphaW * 0.5f, alphaY, SettingSkinUtil.m(3f, 3f), 0xFFFFFFFF); + } + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ConfigColorSettingNoAlpha.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ConfigColorSettingNoAlpha.java index 49e31ac..7cc4ebd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ConfigColorSettingNoAlpha.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ConfigColorSettingNoAlpha.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/CooldownRulesSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/CooldownRulesSetting.java index 3e7025a..dcf57f0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/CooldownRulesSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/CooldownRulesSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/FunctionBindSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/FunctionBindSetting.java index 0b815c3..1cd7b23 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/FunctionBindSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/FunctionBindSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/FunctionBindSettingRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/FunctionBindSettingRenderer.java new file mode 100644 index 0000000..2b61be2 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/FunctionBindSettingRenderer.java @@ -0,0 +1,38 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.config.values.BindMode; +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; + +final class FunctionBindSettingRenderer { + private FunctionBindSettingRenderer() { + } + + static void render(FunctionBindSetting setting, float x, float y, float w, float mx, float my) { + UnifiedSettingsSkin.syncTheme(); + FunctionBindSetting.UiState ui = setting.ui(); + String pending = ClickGuiRenderer.getPendingBindDisplay(); + String display = ui.waiting ? (pending == null ? "..." : pending) : setting.get(); + String modeText = setting.mode() == BindMode.HOLD ? "Hold" : "Press"; + BindRendererUtil.renderBindBase(setting.getDisplayName(), display, modeText, ui.waiting, x, y, w, mx, my, ui); + } + + static void mouseClicked(FunctionBindSetting setting, double mx, double my, int button) { + if (button != 0) return; + FunctionBindSetting.UiState ui = setting.ui(); + if (!UnifiedSettingsSkin.inside(mx, my, ui.lastBx, ui.lastBy, ui.lastBw, ui.lastBh)) return; + ui.waiting = true; + ClickGuiRenderer.beginKeyBind(setting); + } + + static float getHeight(FunctionBindSetting setting) { + String modeText = setting.mode() == BindMode.HOLD ? "Hold" : "Press"; + return BindRendererUtil.bindHeight(setting.ui().lastW, setting.getDisplayName(), setting.get(), modeText); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/GroupSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/GroupSetting.java index aad12f5..5c2b14b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/GroupSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/GroupSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/GroupSettingRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/GroupSettingRenderer.java new file mode 100644 index 0000000..0481289 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/GroupSettingRenderer.java @@ -0,0 +1,120 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.wav.ClickGuiSounds; + +import java.util.HashSet; +import java.util.Set; + +final class GroupSettingRenderer { + private GroupSettingRenderer() { + } + + static void render(GroupSetting setting, float x, float y, float w, float mx, float my) { + UnifiedSettingsSkin.syncTheme(); + GroupSetting.UiState ui = setting.ui(); + ui.baseX = x; + ui.baseY = y; + ui.baseW = w; + layoutGroup(setting); + + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float size = SettingSkinUtil.m(17f, 6.5f); + ClickGuiRenderer.drawText(font, setting.getDisplayName(), x + SettingSkinUtil.m(5f, 5f), y + SettingSkinUtil.m(4f, 1.7f), size, UnifiedSettingsSkin.TEXT_PRIMARY, false); + SettingSkinUtil.renderOptionContainer(x + SettingSkinUtil.m(6f, 6f), y + SettingSkinUtil.m(24f, 9.7f), Math.max(1f, containerWidth(ui.optionLayouts)), optionContainerHeightGroup(ui), false); + + for (GroupSetting.OptionLayout opt : ui.optionLayouts) { + float ox = x + opt.x(); + float oy = y + opt.y(); + boolean active = setting.value().get(opt.getId()); + boolean hover = UnifiedSettingsSkin.inside(mx, my, ox - SettingSkinUtil.m(2f, 2f), oy - SettingSkinUtil.m(1f, 1f), opt.w() + SettingSkinUtil.m(4f, 4f), SettingSkinUtil.m(16f, 8f)); + float hoverAnim = AnimationUtility.approach(ui.hoverAnims.getOrDefault(opt.getId(), 0f), hover ? 1f : 0f, 0.20f); + float activeAnim = AnimationUtility.approach(ui.selectAnims.getOrDefault(opt.getId(), active ? 1f : 0f), active ? 1f : 0f, 0.22f); + ui.hoverAnims.put(opt.getId(), hoverAnim); + ui.selectAnims.put(opt.getId(), activeAnim); + int color = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.72f + hoverAnim * 0.28f); + color = UnifiedSettingsSkin.mix(color, UnifiedSettingsSkin.ACCENT, activeAnim); + ClickGuiRenderer.drawText(font, opt.label(), ox, oy, size, color, false); + } + } + + static void mouseClicked(GroupSetting setting, double mx, double my, int button) { + if (button != 0) return; + GroupSetting.UiState ui = setting.ui(); + for (GroupSetting.OptionLayout opt : ui.optionLayouts) { + float ox = ui.baseX + opt.x(); + float oy = ui.baseY + opt.y(); + if (!UnifiedSettingsSkin.inside(mx, my, ox - SettingSkinUtil.m(2f, 2f), oy - SettingSkinUtil.m(1f, 1f), opt.w() + SettingSkinUtil.m(4f, 4f), SettingSkinUtil.m(16f, 8f))) + continue; + setting.value().set(opt.getId(), !setting.value().get(opt.getId())); + ClickGuiSounds.changeMode(); + if (setting.getParent() != null) setting.getParent().saveConfig(); + return; + } + } + + static float getHeight(GroupSetting setting) { + layoutGroup(setting); + return setting.ui().cachedHeight; + } + + private static void layoutGroup(GroupSetting setting) { + GroupSetting.UiState ui = setting.ui(); + float width = ui.baseW > 0f ? ui.baseW : SettingSkinUtil.m(160f, 115f); + int count = visibleGroupCount(setting); + if (Float.isFinite(ui.lastLayoutW) && Math.abs(ui.lastLayoutW - width) <= 0.5f && ui.layoutOptionCount == count) + return; + ui.optionLayouts.clear(); + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float size = SettingSkinUtil.m(17f, 6.5f); + float maxW = Math.max(1f, width - SettingSkinUtil.m(10f, 10f)); + float offsetX = 0f, offsetY = 0f, maxRowW = 0f; + Set alive = new HashSet<>(); + for (String id : setting.value().getAll().keySet()) { + if (!setting.isOptionVisible(id)) continue; + String label = setting.getOptionDisplayName(id); + float tw = UnifiedSettingsSkin.textWidth(font, label, size) + SettingSkinUtil.m(4f, 4f); + if (offsetX + tw >= maxW && offsetX > 0f) { + maxRowW = Math.max(maxRowW, offsetX); + offsetX = 0f; + offsetY += SettingSkinUtil.m(16f, 8f); + } + ui.optionLayouts.add(new GroupSetting.OptionLayout(id, label, SettingSkinUtil.m(8f, 8f) + offsetX, SettingSkinUtil.m(27f, 10.7f) + offsetY, tw)); + offsetX += tw; + alive.add(id); + } + maxRowW = Math.max(maxRowW, offsetX); + ui.cachedHeight = SettingSkinUtil.m(45f, 22f) + offsetY; + ui.lastLayoutW = width; + ui.layoutOptionCount = count; + ui.hoverAnims.keySet().removeIf(key -> !alive.contains(key)); + ui.selectAnims.keySet().removeIf(key -> !alive.contains(key)); + } + + private static int visibleGroupCount(GroupSetting setting) { + int count = 0; + for (String id : setting.value().getAll().keySet()) if (setting.isOptionVisible(id)) count++; + return count; + } + + private static float containerWidth(java.util.List layouts) { + float max = 0f; + for (GroupSetting.OptionLayout opt : layouts) max = Math.max(max, opt.x() - SettingSkinUtil.m(6f, 6f) + opt.w()); + return max + SettingSkinUtil.m(0.5f, 0.5f); + } + + private static float optionContainerHeightGroup(GroupSetting.UiState ui) { + float max = SettingSkinUtil.m(10f, 10f); + for (GroupSetting.OptionLayout opt : ui.optionLayouts) max = Math.max(max, opt.y() - SettingSkinUtil.m(19f, 9.7f) + SettingSkinUtil.m(16f, 8f)); + return max; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nDuplicateScanner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nDuplicateScanner.java index daaf789..856734b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nDuplicateScanner.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nDuplicateScanner.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -33,7 +33,7 @@ public enum I18nDuplicateScanner { Map> resources = manager.listResourceStacks( "lang", - id -> "combatant".equals(id.getNamespace()) && id.getPath().endsWith(".json") + id -> "lovisual".equals(id.getNamespace()) && id.getPath().endsWith(".json") ); if (resources.isEmpty()) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nPreflightContributors.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nPreflightContributors.java index 779d858..2d607df 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nPreflightContributors.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nPreflightContributors.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nPreflightManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nPreflightManager.java index 127a29f..00f23ea 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nPreflightManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/I18nPreflightManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/KeyBindSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/KeyBindSetting.java index 6110664..037908e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/KeyBindSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/KeyBindSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/KeyBindSettingRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/KeyBindSettingRenderer.java new file mode 100644 index 0000000..eeed3ef --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/KeyBindSettingRenderer.java @@ -0,0 +1,35 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; + +final class KeyBindSettingRenderer { + private KeyBindSettingRenderer() { + } + + static void render(KeyBindSetting setting, float x, float y, float w, float mx, float my) { + UnifiedSettingsSkin.syncTheme(); + KeyBindSetting.UiState ui = setting.ui(); + String pending = ClickGuiRenderer.getPendingBindDisplay(); + String display = ui.waiting ? (pending == null ? "..." : pending) : setting.getValue().get(); + BindRendererUtil.renderBindBase(setting.getDisplayName(), display, null, ui.waiting, x, y, w, mx, my, ui); + } + + static void mouseClicked(KeyBindSetting setting, double mx, double my, int button) { + if (button != 0) return; + KeyBindSetting.UiState ui = setting.ui(); + if (!UnifiedSettingsSkin.inside(mx, my, ui.lastBx, ui.lastBy, ui.lastBw, ui.lastBh)) return; + ui.waiting = true; + ClickGuiRenderer.beginKeyBind(setting); + } + + static float getHeight(KeyBindSetting setting) { + return BindRendererUtil.bindHeight(setting.ui().lastW, setting.getDisplayName(), setting.getValue().get(), null); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModeSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModeSetting.java index d7fd761..4c9c473 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModeSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModeSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModeSettingRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModeSettingRenderer.java new file mode 100644 index 0000000..a21c5ae --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModeSettingRenderer.java @@ -0,0 +1,100 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.wav.ClickGuiSounds; + +final class ModeSettingRenderer { + private ModeSettingRenderer() { + } + + static void render(ModeSetting setting, float x, float y, float w, float mx, float my) { + UnifiedSettingsSkin.syncTheme(); + ModeSetting.UiState ui = setting.ui(); + ui.baseX = x; + ui.baseY = y; + ui.baseW = w; + layoutMode(setting); + + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float size = SettingSkinUtil.m(17f, 6.5f); + ClickGuiRenderer.drawText(font, setting.getDisplayName(), x + SettingSkinUtil.m(5f, 5f), y + SettingSkinUtil.m(4f, 1.3f), size, UnifiedSettingsSkin.TEXT_PRIMARY, false); + SettingSkinUtil.renderOptionContainer(x + SettingSkinUtil.m(5f, 5f), y + SettingSkinUtil.m(24f, 9.7f), ui.selectW, optionContainerHeightMode(ui), false); + + for (ModeSetting.OptionLayout opt : ui.optionLayouts) { + float ox = x + opt.x(); + float oy = y + opt.y(); + boolean active = opt.getId().equals(setting.selectedId()); + boolean hover = UnifiedSettingsSkin.inside(mx, my, ox - SettingSkinUtil.m(2f, 2f), oy - SettingSkinUtil.m(1f, 1f), opt.w() + SettingSkinUtil.m(4f, 4f), SettingSkinUtil.m(16f, 8f)); + float hoverAnim = AnimationUtility.approach(ui.hoverAnims.getOrDefault(opt.getId(), 0f), hover ? 1f : 0f, 0.20f); + ui.hoverAnims.put(opt.getId(), hoverAnim); + int color = active ? UnifiedSettingsSkin.ACCENT : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, hoverAnim * 0.50f); + ClickGuiRenderer.drawText(font, opt.label(), ox, oy, size, color, false); + } + } + + static void mouseClicked(ModeSetting setting, double mx, double my, int button) { + if (button != 0) return; + ModeSetting.UiState ui = setting.ui(); + for (ModeSetting.OptionLayout opt : ui.optionLayouts) { + float ox = ui.baseX + opt.x(); + float oy = ui.baseY + opt.y(); + if (!UnifiedSettingsSkin.inside(mx, my, ox - SettingSkinUtil.m(2f, 2f), oy - SettingSkinUtil.m(1f, 1f), opt.w() + SettingSkinUtil.m(4f, 4f), SettingSkinUtil.m(16f, 8f))) + continue; + String before = setting.selectedId(); + setting.selectId(opt.getId()); + if (!opt.getId().equals(before)) ClickGuiSounds.changeMode(); + if (setting.onChange() != null) setting.onChange().run(); + if (setting.getParent() != null) setting.getParent().saveConfig(); + return; + } + } + + static float getHeight(ModeSetting setting) { + layoutMode(setting); + return setting.ui().cachedHeight; + } + + private static void layoutMode(ModeSetting setting) { + ModeSetting.UiState ui = setting.ui(); + float width = ui.baseW > 0f ? ui.baseW : SettingSkinUtil.m(160f, 115f); + int count = setting.optionIds().size(); + if (Float.isFinite(ui.lastLayoutW) && Math.abs(ui.lastLayoutW - width) <= 0.5f && ui.layoutOptionCount == count) + return; + ui.optionLayouts.clear(); + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float size = SettingSkinUtil.m(17f, 6.5f); + float maxW = Math.max(1f, width - SettingSkinUtil.m(10f, 10f)); + float offsetX = 0f, offsetY = 0f, maxRowW = 0f; + for (String id : setting.optionIds()) { + String label = setting.getOptionDisplayName(id); + float tw = UnifiedSettingsSkin.textWidth(font, label, size) + SettingSkinUtil.m(2f, 2f); + if (offsetX + tw >= maxW && offsetX > 0f) { + maxRowW = Math.max(maxRowW, offsetX); + offsetX = 0f; + offsetY += SettingSkinUtil.m(16f, 8f); + } + ui.optionLayouts.add(new ModeSetting.OptionLayout(id, label, SettingSkinUtil.m(7f, 6f) + offsetX, SettingSkinUtil.m(27f, 10.7f) + offsetY, tw)); + offsetX += tw; + } + maxRowW = Math.max(maxRowW, offsetX); + ui.selectW = Math.max(0f, maxRowW + SettingSkinUtil.m(2f, 2f)); + ui.cachedHeight = SettingSkinUtil.m(45f, 22f) + offsetY; + ui.lastLayoutW = width; + ui.layoutOptionCount = count; + } + + private static float optionContainerHeightMode(ModeSetting.UiState ui) { + float max = SettingSkinUtil.m(10f, 10f); + for (ModeSetting.OptionLayout opt : ui.optionLayouts) max = Math.max(max, opt.y() - SettingSkinUtil.m(19f, 9.7f) + SettingSkinUtil.m(16f, 8f)); + return max; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModulesSettingsSkin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModulesSettingsSkin.java index f7a9920..02b657c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModulesSettingsSkin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ModulesSettingsSkin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/PickerDetailOwner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/PickerDetailOwner.java index 64806ba..9c52f08 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/PickerDetailOwner.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/PickerDetailOwner.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ProtocolHeuristicsSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ProtocolHeuristicsSetting.java index 7bffac7..c4c02f4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ProtocolHeuristicsSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/ProtocolHeuristicsSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/Setting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/Setting.java index 747cc0c..d6d29be 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/Setting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/Setting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingFactory.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingFactory.java index 7cd9e97..bb6d8cf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingFactory.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingFactory.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRenderContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRenderContext.java index 3adda5d..36c81fe 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRenderContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRenderContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRenderSurface.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRenderSurface.java index bf57f49..e1f0049 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRenderSurface.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRenderSurface.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRendererBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRendererBridge.java index 58bd64c..3e92a60 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRendererBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingRendererBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingSkinUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingSkinUtil.java new file mode 100644 index 0000000..14fb5a9 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingSkinUtil.java @@ -0,0 +1,142 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ScissorFunction; + +final class SettingSkinUtil { + private SettingSkinUtil() { + } + + static float m(float settings, float modules) { + return UnifiedSettingsSkin.metric(settings, modules); + } + + static float s() { + return UnifiedSettingsSkin.scale(); + } + + static boolean modules() { + return UnifiedSettingsSkin.modules(); + } + + static void renderOptionContainer(float x, float y, float w, float h, boolean active) { + float alpha = active ? 0.22f : 0.12f; + if (active) { + UnifiedSettingsSkin.drawAccent(x, y, Math.max(1f, w), Math.max(m(14f, 10f), h), m(3f, 3f), alpha); + } else { + UnifiedSettingsSkin.drawSurface(x, y, Math.max(1f, w), Math.max(m(14f, 10f), h), m(3f, 3f), 0.34f); + } + } + + static void renderChipButton(float x, float y, float w, float h, String label, float hoverAnim, boolean active) { + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + int bg = active ? UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 70) : UnifiedSettingsSkin.SURFACE_SOFT; + bg = UnifiedSettingsSkin.mix(bg, UnifiedSettingsSkin.SURFACE_HOVER, hoverAnim * 0.72f); + ClickGuiRenderer.drawRoundedRect(x, y, w, h, m(4f, 4f), bg); + int stroke = active + ? UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 135 + Math.round(hoverAnim * 55f)) + : UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 58 + Math.round(hoverAnim * 65f)); + ClickGuiRenderer.drawRoundedRectStroke(x, y, w, h, m(4f, 4f), m(0.7f, 0.45f), stroke); + float size = Math.min(m(13f, 6f), Math.max(m(10f, 4.8f), (w - m(4f, 4f)) / Math.max(1f, label.length()) * 1.45f)); + float tw = UnifiedSettingsSkin.textWidth(font, label, size); + float ty = y + (h - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f - m(0.2f, 0.2f); + int color = active ? UnifiedSettingsSkin.ACCENT : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.68f + hoverAnim * 0.32f); + ClickGuiRenderer.drawText(font, label, x + Math.max(m(2f, 2f), (w - tw) * 0.5f), ty, size, color, false); + } + + static void renderRainbowChipButton(float x, float y, float w, float h, float hoverAnim, boolean active) { + float t = (System.nanoTime() % 3_000_000_000L) / 3_000_000_000f; + int c0 = ColorSettingMath.hsbToArgb((t + 0.00f) % 1f, 0.80f, 1.0f, active ? 205 : 92 + Math.round(hoverAnim * 34f)); + int c1 = ColorSettingMath.hsbToArgb((t + 0.18f) % 1f, 0.80f, 1.0f, active ? 215 : 96 + Math.round(hoverAnim * 38f)); + int c2 = ColorSettingMath.hsbToArgb((t + 0.36f) % 1f, 0.80f, 1.0f, active ? 215 : 96 + Math.round(hoverAnim * 38f)); + int c3 = ColorSettingMath.hsbToArgb((t + 0.54f) % 1f, 0.80f, 1.0f, active ? 205 : 92 + Math.round(hoverAnim * 34f)); + if (active) { + ClickGuiRenderer.drawRoundedRectGradient(x, y, w, h, m(4f, 4f), c0, c2, 25f + t * 360f); + ClickGuiRenderer.drawRoundedRect(x, y, w, h, m(4f, 4f), UnifiedSettingsSkin.withAlpha(0xFF000000, 18 - Math.round(hoverAnim * 6f))); + ClickGuiRenderer.drawRoundedRectStrokeGradient(x, y, w, h, m(4f, 4f), m(0.8f, 0.45f), c0, c2, 25f + t * 360f); + } else { + int bg = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, hoverAnim * 0.75f); + ClickGuiRenderer.drawRoundedRect(x, y, w, h, m(4f, 4f), UnifiedSettingsSkin.withAlpha(bg, 70 + Math.round(hoverAnim * 42f))); + if (hoverAnim > 0.02f) { + ClickGuiRenderer.drawRoundedRectGradient(x, y, w, h, m(4f, 4f), UnifiedSettingsSkin.withAlpha(c0, Math.round(52f * hoverAnim)), UnifiedSettingsSkin.withAlpha(c2, Math.round(52f * hoverAnim)), 25f + t * 360f); + ClickGuiRenderer.drawRoundedRectStrokeGradient(x, y, w, h, m(4f, 4f), m(0.7f, 0.45f), UnifiedSettingsSkin.withAlpha(c0, 80 + Math.round(96f * hoverAnim)), UnifiedSettingsSkin.withAlpha(c2, 80 + Math.round(96f * hoverAnim)), 25f + t * 360f); + } else { + ClickGuiRenderer.drawRoundedRectStroke(x, y, w, h, m(4f, 4f), m(0.7f, 0.45f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 72)); + } + } + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + String label = "RNB"; + float size = Math.min(m(13f, 6f), Math.max(m(10f, 4.8f), (w - m(4f, 4f)) / Math.max(1f, label.length()) * 1.45f)); + float tw = UnifiedSettingsSkin.textWidth(font, label, size); + float ty = y + (h - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f - m(0.2f, 0.2f); + int labelColor = active ? 0xFFFFFFFF : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, 0xFFFFFFFF, hoverAnim * 0.62f); + ClickGuiRenderer.drawText(font, label, x + Math.max(m(2f, 2f), (w - tw) * 0.5f), ty, size, labelColor, false); + } + + static void renderChecker(float x, float y, float w, float h, float cell, float radius) { + int light = 0xFFE7E7E7; + int dark = 0xFF777777; + ClickGuiRenderer.drawRoundedRect(x, y, w, h, radius, light); + float safeCell = Math.max(1f, cell); + int cols = Math.max(1, (int) Math.ceil(w / safeCell)); + int rows = Math.max(1, (int) Math.ceil(h / safeCell)); + boolean clipped = ScissorFunction.pushRaw(x, y, w, h); + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + if (((row + col) & 1) == 0) continue; + ClickGuiRenderer.drawRect(x + col * safeCell, y + row * safeCell, safeCell, safeCell, dark); + } + } + if (clipped) ScissorFunction.pop(); + } + + static void drawBindMarquee( + TextRenderer font, + String text, + float x, + float y, + float fullWidth, + float viewWidth, + float fontSize, + int color + ) { + final float speed = 22.0f; + final float gap = 14.0f; + final float pauseSec = 0.8f; + + if (text == null || text.isEmpty()) return; + if (speed <= 0.0f) { + ClickGuiRenderer.drawText(font, text, x, y, fontSize, color, false); + return; + } + + float cycleDistance = fullWidth + gap; + float cycleTime = pauseSec + cycleDistance / speed; + if (cycleTime <= 0.0f) { + ClickGuiRenderer.drawText(font, text, x, y, fontSize, color, false); + return; + } + + float now = net.minecraft.util.Util.getMillis() / 1000.0f; + float t = now % cycleTime; + + float offset = 0.0f; + if (t > pauseSec) { + offset = -(t - pauseSec) * speed; + } + + ClickGuiRenderer.drawText(font, text, x + offset, y, fontSize, color, false); + + if (cycleDistance > viewWidth * 0.5f) { + ClickGuiRenderer.drawText(font, text, x + offset + cycleDistance, y, fontSize, color, false); + } + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingTextInputUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingTextInputUtil.java new file mode 100644 index 0000000..e66ffe5 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SettingTextInputUtil.java @@ -0,0 +1,45 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.text.TextRenderer; + +final class SettingTextInputUtil { + private SettingTextInputUtil() { + } + + static int caretFromText(TextRenderer font, String text, float size, float textX, float mx) { + if (text == null || text.isEmpty()) return 0; + float rel = mx - textX; + if (rel <= 0f) return 0; + for (int i = 1; i <= text.length(); i++) { + float prev = UnifiedSettingsSkin.textWidth(font, text.substring(0, i - 1), size); + float cur = UnifiedSettingsSkin.textWidth(font, text.substring(0, i), size); + if (rel < (prev + cur) * 0.5f) return i - 1; + } + return text.length(); + } + + static void renderInlineSelection(TextRenderer font, String text, int start, int end, float textX, float textY, float size, float fieldH, float fieldY) { + if (text == null || start < 0 || end < 0 || start == end) return; + int a = Math.max(0, Math.min(start, text.length())); + int b = Math.max(0, Math.min(end, text.length())); + if (a == b) return; + if (a > b) { + int t = a; + a = b; + b = t; + } + float x0 = textX + UnifiedSettingsSkin.textWidth(font, text.substring(0, a), size); + float x1 = textX + UnifiedSettingsSkin.textWidth(font, text.substring(0, b), size); + float h = Math.max(SettingSkinUtil.m(8f, 5f), UnifiedSettingsSkin.textHeight(font, size) + SettingSkinUtil.m(3f, 2f)); + float y = fieldY > 0f ? fieldY + (fieldH - h) * 0.5f : textY - SettingSkinUtil.m(1.5f, 0.7f); + ClickGuiRenderer.drawRoundedRect(x0, y, Math.max(SettingSkinUtil.m(1f, 0.7f), x1 - x0), h, SettingSkinUtil.m(2f, 1.5f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 92)); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderSetting.java index d909945..1847072 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderSettingRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderSettingRenderer.java new file mode 100644 index 0000000..229f237 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderSettingRenderer.java @@ -0,0 +1,191 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.config.values.NumberValue; +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ScissorFunction; +import dev.loki.lovisual.render.helpers.SystemCursor; + +final class SliderSettingRenderer { + private SliderSettingRenderer() { + } + + static void render(SliderSetting setting, float x, float y, float w, float mx, float my) { + UnifiedSettingsSkin.syncTheme(); + SliderSetting.UiState ui = setting.ui(); + NumberValue value = setting.value(); + double min = value.getMin().doubleValue(); + double max = value.getMax().doubleValue(); + double val = value.get().doubleValue(); + + ui.lastX = x; + ui.lastY = y; + ui.lastW = w; + + float dt = AnimationUtility.deltaTime(); + if (ui.dragging && !ui.editing) { + SliderTextInputHandler.setSliderValueFromMouse(setting, mx, x + SettingSkinUtil.m(6f, 5f), Math.max(1f, w - SettingSkinUtil.m(6f, 5f) * 2f), min, max); + val = value.get().doubleValue(); + } + + float trackPad = SettingSkinUtil.m(6f, 5f); + float trackX = x + trackPad; + float trackW = Math.max(1f, w - trackPad * 2f); + float trackY = y + SettingSkinUtil.m(38f, 15f); + float trackH = SettingSkinUtil.m(2.4f, 1.2f); + + float target = max == min ? 0f : (float) ((val - min) / (max - min)); + target = UnifiedSettingsSkin.clamp01(target); + ui.anim = AnimationUtility.approach(ui.anim, target, 0.40f); + boolean trackHover = UnifiedSettingsSkin.inside(mx, my, trackX, trackY - SettingSkinUtil.m(6f, 2f), trackW, trackH + SettingSkinUtil.m(12f, 4f)); + if ((trackHover && !ui.editing) || ui.dragging) { + SystemCursor.set(SystemCursor.CursorType.RESIZE_HORIZONTAL); + } + ui.hoverAnim = AnimationUtility.approach(ui.hoverAnim, trackHover ? 1f : 0f, dt, 12f); + ui.editAnim = AnimationUtility.approach(ui.editAnim, ui.editing ? 1f : 0f, dt, 14f); + ui.errorAnim = AnimationUtility.approach(ui.errorAnim, 0f, dt, 7.5f); + if (ui.editing) ui.cursorBlink += dt * 2.3f; + else ui.cursorBlink = 0f; + + TextRenderer font = SettingSkinUtil.modules() ? UnifiedSettingsSkin.fontRegular() : ClickGuiRenderer.getIosevkaRegular(); + float labelSize = SettingSkinUtil.m(17f, 6.8f); + float valueSize = SettingSkinUtil.m(17f, 6.8f); + float textY = y + SettingSkinUtil.m(6f, 1.9f); + String display = ui.editing ? ui.editBuffer : value.toDisplay(); + if (display == null) display = ""; + float valuePad = SettingSkinUtil.m(6f, 4f); + float rawValueW = UnifiedSettingsSkin.textWidth(font, display.isEmpty() ? "0" : display, valueSize) + valuePad * 2f; + float valueW = Math.max(SettingSkinUtil.m(34f, 20f), rawValueW); + valueW = Math.min(valueW, Math.max(SettingSkinUtil.m(46f, 28f), w * 0.48f)); + ui.valueX = x + w - valueW - trackPad; + ui.valueY = textY - SettingSkinUtil.m(4f, 1.5f); + ui.valueW = valueW; + ui.valueH = UnifiedSettingsSkin.textHeight(font, valueSize) + SettingSkinUtil.m(8f, 4f); + boolean valueHover = UnifiedSettingsSkin.inside(mx, my, ui.valueX, ui.valueY, ui.valueW, ui.valueH); + ui.valueHoverAnim = AnimationUtility.approach(ui.valueHoverAnim, valueHover ? 1f : 0f, dt, 12f); + ui.inputHoverAnim = AnimationUtility.approach(ui.inputHoverAnim, valueHover ? 1f : 0f, dt, 15f); + ui.inputFocusGlowAnim = AnimationUtility.approach(ui.inputFocusGlowAnim, ui.editing ? 1f : 0f, dt, 12f); + ui.inputPressAnim = AnimationUtility.approach(ui.inputPressAnim, ui.editing ? 1f : 0f, dt, 10f); + + int textCol = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_PRIMARY, 0xFFFF7777, ui.errorAnim * 0.85f); + float fieldAnim = Math.max(ui.inputHoverAnim * 0.62f, ui.inputFocusGlowAnim); + int fieldBg = UnifiedSettingsSkin.withAlpha( + UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, fieldAnim * 0.72f), + Math.round(fieldAnim * 104f) + ); + int fieldStrokeBase = UnifiedSettingsSkin.mix( + UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(fieldAnim * 70f)), + UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, Math.round(ui.inputFocusGlowAnim * 160f)), + ui.inputFocusGlowAnim + ); + int fieldStroke = UnifiedSettingsSkin.mix(fieldStrokeBase, 0xFFFF5F66, ui.errorAnim); + + ClickGuiRenderer.beginTextBatch(); + String label = setting.getDisplayName(); + float labelMax = Math.max(1f, ui.valueX - trackX - SettingSkinUtil.m(7f, 5f)); + ClickGuiRenderer.drawText(font, UnifiedSettingsSkin.fit(font, label, labelSize, labelMax), trackX, textY, labelSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); + ClickGuiRenderer.endTextBatch(); + + if (fieldAnim > 0.001f || ui.errorAnim > 0.001f) { + float lift = ui.inputFocusGlowAnim * SettingSkinUtil.m(1.0f, 0.45f); + if (UnifiedSettingsSkin.SURFACE_GRADIENT_ENABLED) { + UnifiedSettingsSkin.drawSurface(ui.valueX, ui.valueY - lift, ui.valueW, ui.valueH + lift * 2f, SettingSkinUtil.m(6f, 3.5f), fieldAnim); + } else { + ClickGuiRenderer.drawRoundedRect(ui.valueX, ui.valueY - lift, ui.valueW, ui.valueH + lift * 2f, SettingSkinUtil.m(6f, 3.5f), fieldBg); + } + if (ui.inputFocusGlowAnim > 0.02f) { + ClickGuiRenderer.drawRoundedRectStrokeGradient(ui.valueX, ui.valueY - lift, ui.valueW, ui.valueH + lift * 2f, SettingSkinUtil.m(6f, 3.5f), SettingSkinUtil.m(0.8f, 0.45f), UnifiedSettingsSkin.accentGradientStart(0.72f), UnifiedSettingsSkin.accentGradientEnd(0.72f), UnifiedSettingsSkin.ACCENT_GRADIENT_ANGLE); + } else { + ClickGuiRenderer.drawRoundedRectStroke(ui.valueX, ui.valueY - lift, ui.valueW, ui.valueH + lift * 2f, SettingSkinUtil.m(6f, 3.5f), SettingSkinUtil.m(0.7f, 0.45f), fieldStroke); + } + if (ui.errorAnim > 0.01f) { + ClickGuiRenderer.drawRoundedRectStroke(ui.valueX, ui.valueY - lift, ui.valueW, ui.valueH + lift * 2f, SettingSkinUtil.m(6f, 3.5f), SettingSkinUtil.m(1.0f, 0.55f), UnifiedSettingsSkin.withAlpha(0xFFFF5F66, Math.round(170f * ui.errorAnim))); + } + } + + float textBaseY = y + SettingSkinUtil.m(6f, 1.9f); + ui.valueTextSize = valueSize; + ui.valueTextPad = valuePad; + ui.valueTextY = textBaseY; + String drawValue = ui.editing ? display : UnifiedSettingsSkin.fit(font, display, valueSize, ui.valueW - valuePad * 2f); + float drawW = UnifiedSettingsSkin.textWidth(font, drawValue, valueSize); + float drawX = ui.editing ? ui.valueX + valuePad : ui.valueX + ui.valueW - drawW - valuePad; + ui.valueTextX = drawX; + boolean textClip = ScissorFunction.pushRaw(ui.valueX + valuePad * 0.65f, ui.valueY, Math.max(1f, ui.valueW - valuePad * 1.3f), ui.valueH); + if (ui.editing) { + SettingTextInputUtil.renderInlineSelection(font, ui.editBuffer, SliderTextInputState.sliderSelStart(ui), SliderTextInputState.sliderSelEnd(ui), drawX, textBaseY, valueSize, ui.valueH, 0f); + } + ClickGuiRenderer.drawText(font, drawValue, drawX, textBaseY, valueSize, textCol, false); + if (ui.editing && ((int) (ui.cursorBlink * 2f) & 1) == 0) { + int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); + float cx = drawX + UnifiedSettingsSkin.textWidth(font, ui.editBuffer.substring(0, cursor), valueSize) + SettingSkinUtil.m(0.5f, 0.3f); + ClickGuiRenderer.drawRect(cx, ui.valueY + SettingSkinUtil.m(3f, 1.5f), SettingSkinUtil.m(0.75f, 0.45f), ui.valueH - SettingSkinUtil.m(6f, 3f), UnifiedSettingsSkin.withAlpha(textCol, 205)); + } + if (textClip) ScissorFunction.pop(); + + int baseTrack = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE, UnifiedSettingsSkin.SURFACE_HOVER, 0.55f + ui.hoverAnim * 0.15f); + ClickGuiRenderer.drawRoundedRect(trackX, trackY, trackW, trackH, 0.6f * SettingSkinUtil.s(), baseTrack); + float fillW = trackW * ui.anim; + if (fillW > 0.5f) { + ClickGuiRenderer.drawGradientRect(trackX, trackY, fillW, trackH, UnifiedSettingsSkin.accentGradientStart(1f), UnifiedSettingsSkin.accentGradientEnd(1f), UnifiedSettingsSkin.accentGradientEnd(1f), UnifiedSettingsSkin.accentGradientStart(1f)); + } + + float knobW = SettingSkinUtil.m(2.4f, 1.2f); + float knobH = SettingSkinUtil.m(7.2f, 4.2f); + float knobX = trackX + fillW - knobW * 0.5f; + float knobY = trackY - (knobH - trackH) * 0.5f; + int knobCol = UnifiedSettingsSkin.mix(0xFFE1E1E1, UnifiedSettingsSkin.accentGradientStart(1f), 0.25f + ui.hoverAnim * 0.20f); + ClickGuiRenderer.drawRoundedRect(knobX, knobY, knobW, knobH, knobW * 0.5f, knobCol); + } + + static void mouseClicked(SliderSetting setting, double mx, double my, int button) { + if (button != 0) return; + float trackPad = SettingSkinUtil.m(6f, 5f); + SliderSetting.UiState ui = setting.ui(); + if (ui.editing) { + if (UnifiedSettingsSkin.inside(mx, my, ui.valueX, ui.valueY, ui.valueW, ui.valueH)) { + SliderTextInputHandler.setSliderEditCursorFromMouse(setting, (float) mx, false); + } else { + SliderTextInputHandler.commitSliderEdit(setting, true); + } + return; + } + if (UnifiedSettingsSkin.inside(mx, my, ui.valueX, ui.valueY, ui.valueW, ui.valueH)) { + SliderTextInputHandler.beginSliderEdit(setting); + SliderTextInputHandler.setSliderEditCursorFromMouse(setting, (float) mx, false); + return; + } + float trackX = ui.lastX + trackPad; + float trackW = Math.max(1f, ui.lastW - trackPad * 2f); + float trackY = ui.lastY + SettingSkinUtil.m(38f, 15f); + float trackH = SettingSkinUtil.m(2.4f, 1.2f); + if (!UnifiedSettingsSkin.inside(mx, my, trackX, trackY - SettingSkinUtil.m(6f, 2f), trackW, trackH + SettingSkinUtil.m(12f, 4f))) return; + ui.dragging = true; + SliderTextInputHandler.setSliderValueFromMouse(setting, (float) mx, trackX, trackW, setting.value().getMin().doubleValue(), setting.value().getMax().doubleValue()); + } + + static void mouseReleased(SliderSetting setting, double mx, double my, int button) { + if (button != 0 || !setting.ui().dragging) return; + setting.ui().dragging = false; + if (setting.getParent() != null) setting.getParent().saveConfig(); + } + + static void mouseClickedOutside(SliderSetting setting, double mx, double my, int button) { + if (button != 0) return; + SliderSetting.UiState ui = setting.ui(); + if (!ui.editing) return; + SliderTextInputHandler.commitSliderEdit(setting, true); + } + + static float getHeight(SliderSetting setting) { + return SettingSkinUtil.m(58f, 24f); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderTextInputHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderTextInputHandler.java new file mode 100644 index 0000000..3dab9e8 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderTextInputHandler.java @@ -0,0 +1,185 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.config.values.NumberValue; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.text.ClipboardUtil; +import dev.loki.lovisual.util.wav.ClickGuiSounds; +import org.lwjgl.glfw.GLFW; + +final class SliderTextInputHandler { + private SliderTextInputHandler() { + } + + static void beginSliderEdit(SliderSetting setting) { + SliderSetting.UiState ui = setting.ui(); + ui.editing = true; + ui.dragging = false; + ui.editBuffer = String.valueOf(setting.value().get()).replace(',', '.'); + ui.editCursor = ui.editBuffer.length(); + ui.editSelection.clear(); + ui.errorAnim = 0f; + ui.cursorBlink = 0f; + } + + static void cancelSliderEdit(SliderSetting setting) { + SliderSetting.UiState ui = setting.ui(); + ui.editing = false; + ui.editBuffer = ""; + ui.editCursor = 0; + ui.editSelection.clear(); + ui.errorAnim = 0f; + } + + static void commitSliderEdit(SliderSetting setting, boolean save) { + SliderSetting.UiState ui = setting.ui(); + String raw = ui.editBuffer == null ? "" : ui.editBuffer.trim().replace(',', '.'); + if (!SliderTextInputState.sliderTextCanCommit(setting, raw)) { + SliderTextInputState.pulseSliderError(ui); + return; + } + try { + double parsed = Double.parseDouble(raw); + double min = setting.value().getMin().doubleValue(); + double max = setting.value().getMax().doubleValue(); + parsed = Math.max(min, Math.min(max, parsed)); + if (SliderTextInputState.sliderInteger(setting)) parsed = Math.round(parsed); + else parsed = Math.round(parsed * 1000d) / 1000d; + N next = setting.value().castToType(parsed); + setting.value().set(next); + ui.editing = false; + ui.editBuffer = ""; + ui.editCursor = 0; + ui.editSelection.clear(); + if (save && setting.getParent() != null) setting.getParent().saveConfig(); + } catch (Throwable ignored) { + SliderTextInputState.pulseSliderError(ui); + } + } + + static void setSliderEditCursorFromMouse(SliderSetting setting, float mx, boolean shift) { + SliderSetting.UiState ui = setting.ui(); + TextRenderer font = SettingSkinUtil.modules() ? UnifiedSettingsSkin.fontRegular() : ClickGuiRenderer.getIosevkaRegular(); + int cursor = SettingTextInputUtil.caretFromText(font, ui.editBuffer == null ? "" : ui.editBuffer, ui.valueTextSize <= 0f ? SettingSkinUtil.m(17f, 6.8f) : ui.valueTextSize, ui.valueTextX, mx); + SliderTextInputState.setSliderCursor(ui, cursor, shift); + } + + static void insertSliderText(SliderSetting setting, String text) { + String sanitized = SliderTextInputState.sanitizeSliderText(text, SliderTextInputState.sliderInteger(setting)); + if (sanitized.isEmpty()) { + SliderTextInputState.pulseSliderError(setting.ui()); + return; + } + SliderSetting.UiState ui = setting.ui(); + if (SliderTextInputState.hasSliderSelection(ui)) SliderTextInputState.deleteSliderSelection(ui); + for (int i = 0; i < sanitized.length(); i++) { + char c = sanitized.charAt(i); + if (c == '.' && (SliderTextInputState.sliderInteger(setting) || SliderTextInputState.sliderTextHasDecimal(ui.editBuffer))) { + SliderTextInputState.pulseSliderError(ui); + continue; + } + if (c == '-' && (setting.value().getMin().doubleValue() >= 0.0 || ui.editCursor != 0 || ui.editBuffer.indexOf('-') >= 0)) { + SliderTextInputState.pulseSliderError(ui); + continue; + } + SliderTextInputState.insertSliderTextRaw(ui, String.valueOf(c)); + } + SliderTextInputState.validateSliderLive(setting, ui); + } + + static void setSliderValueFromMouse(SliderSetting setting, float mx, float trackX, float trackW, double min, double max) { + float percent = UnifiedSettingsSkin.clamp01((mx - trackX) / Math.max(1f, trackW)); + double nextRaw = min + (max - min) * percent; + NumberValue value = setting.value(); + if (value.get() instanceof Integer || value.get() instanceof Long) + nextRaw = Math.round(nextRaw); + else nextRaw = Math.round(nextRaw * 100d) / 100d; + N current = value.get(); + N next = value.castToType(nextRaw); + if (Double.compare(current.doubleValue(), next.doubleValue()) != 0) { + value.set(next); + ClickGuiSounds.sliderMove(); + } + } + + static boolean keyPressed(SliderSetting setting, int keyCode, int scanCode, int modifiers) { + SliderSetting.UiState ui = setting.ui(); + if (!ui.editing) return false; + boolean ctrl = (modifiers & GLFW.GLFW_MOD_CONTROL) != 0; + boolean shift = (modifiers & GLFW.GLFW_MOD_SHIFT) != 0; + if (ctrl && keyCode == GLFW.GLFW_KEY_A) { SliderTextInputState.selectAllSliderText(ui); return true; } + if (ctrl && keyCode == GLFW.GLFW_KEY_C) { ClipboardUtil.copy(SliderTextInputState.selectedOrAllSliderText(ui)); return true; } + if (ctrl && keyCode == GLFW.GLFW_KEY_V) { insertSliderText(setting, ClipboardUtil.get()); return true; } + if (ctrl && keyCode == GLFW.GLFW_KEY_X) { + ClipboardUtil.copy(SliderTextInputState.selectedOrAllSliderText(ui)); + SliderTextInputState.deleteSliderSelection(ui); + return true; + } + switch (keyCode) { + case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> { commitSliderEdit(setting, true); return true; } + case GLFW.GLFW_KEY_ESCAPE -> { cancelSliderEdit(setting); return true; } + case GLFW.GLFW_KEY_BACKSPACE -> { + if (!SliderTextInputState.deleteSliderSelection(ui) && ui.editCursor > 0) { + ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor - 1) + ui.editBuffer.substring(ui.editCursor); + ui.editCursor--; + } + SliderTextInputState.validateSliderLive(setting, ui); + return true; + } + case GLFW.GLFW_KEY_DELETE -> { + if (!SliderTextInputState.deleteSliderSelection(ui) && ui.editCursor < ui.editBuffer.length()) { + ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor) + ui.editBuffer.substring(ui.editCursor + 1); + } + SliderTextInputState.validateSliderLive(setting, ui); + return true; + } + case GLFW.GLFW_KEY_LEFT -> { SliderTextInputState.moveSliderCursor(ui, -1, shift); return true; } + case GLFW.GLFW_KEY_RIGHT -> { SliderTextInputState.moveSliderCursor(ui, 1, shift); return true; } + case GLFW.GLFW_KEY_HOME -> { SliderTextInputState.setSliderCursor(ui, 0, shift); return true; } + case GLFW.GLFW_KEY_END -> { SliderTextInputState.setSliderCursor(ui, ui.editBuffer.length(), shift); return true; } + } + return true; + } + + static boolean charTyped(SliderSetting setting, char chr, int modifiers) { + SliderSetting.UiState ui = setting.ui(); + if (!ui.editing) return false; + if (chr == ',' || chr == '.') { + if (SliderTextInputState.sliderInteger(setting) || SliderTextInputState.sliderTextHasDecimal(ui.editBuffer)) { + SliderTextInputState.pulseSliderError(ui); + return true; + } + SliderTextInputState.insertSliderTextRaw(ui, "."); + SliderTextInputState.validateSliderLive(setting, ui); + return true; + } + if (chr == '-') { + if (setting.value().getMin().doubleValue() >= 0.0) { + SliderTextInputState.pulseSliderError(ui); + return true; + } + if (SliderTextInputState.hasSliderSelection(ui)) SliderTextInputState.deleteSliderSelection(ui); + if (ui.editCursor != 0 || ui.editBuffer.indexOf('-') >= 0) { + SliderTextInputState.pulseSliderError(ui); + return true; + } + SliderTextInputState.insertSliderTextRaw(ui, "-"); + SliderTextInputState.validateSliderLive(setting, ui); + return true; + } + if (chr >= '0' && chr <= '9') { + SliderTextInputState.insertSliderTextRaw(ui, String.valueOf(chr)); + SliderTextInputState.validateSliderLive(setting, ui); + return true; + } + SliderTextInputState.pulseSliderError(ui); + return true; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderTextInputState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderTextInputState.java new file mode 100644 index 0000000..08fdea4 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/SliderTextInputState.java @@ -0,0 +1,125 @@ +/* + * 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.features.gui.clickgui.settings; + +final class SliderTextInputState { + private SliderTextInputState() { + } + + static String sanitizeSliderText(String text, boolean integer) { + if (text == null) return ""; + StringBuilder out = new StringBuilder(); + boolean dot = false; + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (c >= '0' && c <= '9') { + out.append(c); + } else if (c == '-' && out.length() == 0) { + out.append('-'); + } else if (!integer && (c == '.' || c == ',') && !dot) { + out.append('.'); + dot = true; + } + } + return out.toString(); + } + + static void selectAllSliderText(SliderSetting.UiState ui) { + ui.editSelection.begin(0, 0); + ui.editSelection.updateCaret(0, ui.editBuffer == null ? 0 : ui.editBuffer.length()); + ui.editCursor = ui.editBuffer == null ? 0 : ui.editBuffer.length(); + } + + static boolean hasSliderSelection(SliderSetting.UiState ui) { + return ui.editSelection.hasRange(); + } + + static int sliderSelStart(SliderSetting.UiState ui) { + return hasSliderSelection(ui) ? Math.max(0, Math.min(ui.editSelection.start(), ui.editBuffer.length())) : -1; + } + + static int sliderSelEnd(SliderSetting.UiState ui) { + return hasSliderSelection(ui) ? Math.max(0, Math.min(ui.editSelection.end(), ui.editBuffer.length())) : -1; + } + + static String selectedOrAllSliderText(SliderSetting.UiState ui) { + if (hasSliderSelection(ui)) return ui.editBuffer.substring(sliderSelStart(ui), sliderSelEnd(ui)); + return ui.editBuffer == null ? "" : ui.editBuffer; + } + + static boolean deleteSliderSelection(SliderSetting.UiState ui) { + if (!hasSliderSelection(ui)) return false; + int start = sliderSelStart(ui); + int end = sliderSelEnd(ui); + ui.editBuffer = ui.editBuffer.substring(0, start) + ui.editBuffer.substring(end); + ui.editCursor = start; + ui.editSelection.clear(); + return true; + } + + static void insertSliderTextRaw(SliderSetting.UiState ui, String text) { + if (text == null || text.isEmpty()) return; + deleteSliderSelection(ui); + int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); + ui.editBuffer = ui.editBuffer.substring(0, cursor) + text + ui.editBuffer.substring(cursor); + ui.editCursor = cursor + text.length(); + ui.editSelection.clear(); + } + + static void moveSliderCursor(SliderSetting.UiState ui, int dir, boolean shift) { + setSliderCursor(ui, Math.max(0, Math.min(ui.editBuffer.length(), ui.editCursor + dir)), shift); + } + + static void setSliderCursor(SliderSetting.UiState ui, int pos, boolean shift) { + int next = Math.max(0, Math.min(ui.editBuffer == null ? 0 : ui.editBuffer.length(), pos)); + updateSelection(ui, next, shift); + ui.editCursor = next; + ui.cursorBlink = 0f; + } + + private static void updateSelection(SliderSetting.UiState ui, int next, boolean shift) { + if (shift) { + if (!ui.editSelection.hasRange()) ui.editSelection.begin(0, ui.editCursor); + ui.editSelection.updateCaret(0, next); + } else { + ui.editSelection.clear(); + } + } + + static void pulseSliderError(SliderSetting.UiState ui) { + ui.errorAnim = 1f; + } + + static boolean sliderInteger(SliderSetting setting) { + Object current = setting.value().get(); + return current instanceof Integer || current instanceof Long; + } + + static boolean sliderTextCanCommit(SliderSetting setting, String raw) { + if (raw == null) return false; + String text = raw.trim().replace(',', '.'); + if (text.isEmpty() || text.equals("-") || text.equals(".") || text.equals("-.")) return false; + if (sliderInteger(setting) && text.indexOf('.') >= 0) return false; + try { + double parsed = Double.parseDouble(text); + return Double.isFinite(parsed); + } catch (Throwable ignored) { + return false; + } + } + + static boolean sliderTextHasDecimal(String text) { + return text != null && (text.indexOf('.') >= 0 || text.indexOf(',') >= 0); + } + + static void validateSliderLive(SliderSetting setting, SliderSetting.UiState ui) { + if (ui.editBuffer == null || ui.editBuffer.isEmpty() || ui.editBuffer.equals("-") || ui.editBuffer.equals(".")) + return; + if (!sliderTextCanCommit(setting, ui.editBuffer)) pulseSliderError(ui); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextEditorOwner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextEditorOwner.java index f0f9451..6df89bc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextEditorOwner.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextEditorOwner.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListSetting.java index f89bf70..4469179 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListSettingRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListSettingRenderer.java new file mode 100644 index 0000000..13a1439 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListSettingRenderer.java @@ -0,0 +1,181 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ScissorFunction; + +import java.util.List; +import java.util.Set; + +final class TextListSettingRenderer { + private TextListSettingRenderer() { + } + + static void render(TextListSetting setting, float x, float y, float w, float mx, float my) { + UnifiedSettingsSkin.syncTheme(); + TextListSetting.UiState ui = setting.ui(); + ui.lastX = x; + ui.lastY = y; + ui.lastW = w; + + if (isInlineTextList(setting)) { + renderInlineTextList(setting, x, y, w, mx, my); + return; + } + + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float labelSize = SettingSkinUtil.m(15.5f, 6.4f); + float small = SettingSkinUtil.m(11.5f, 5.7f); + float bh = SettingSkinUtil.m(18f, 13f); + float editW = Math.max(SettingSkinUtil.m(36f, 28f), UnifiedSettingsSkin.textWidth(font, "Edit", small) + SettingSkinUtil.m(12f, 12f)); + float labelX = x + SettingSkinUtil.m(5f, 5f); + float labelMax = Math.max(SettingSkinUtil.m(50f, 34f), w - editW - SettingSkinUtil.m(22f, 16f)); + List labelLines = ClickGuiRenderer.wrapText(font, setting.getDisplayName(), labelSize, labelMax, 2); + if (labelLines.isEmpty()) labelLines = java.util.List.of(setting.getDisplayName()); + float lineH = UnifiedSettingsSkin.textHeight(font, labelSize); + float lineGap = SettingSkinUtil.m(2f, 0.7f); + float textBlockH = labelLines.size() * lineH + Math.max(0, labelLines.size() - 1) * lineGap; + float rowH = Math.max(SettingSkinUtil.m(44f, 24f), textBlockH + SettingSkinUtil.m(14f, 8f)); + float bx = x + w - SettingSkinUtil.m(9f, 9f) - editW; + float by = y + (rowH - bh) * 0.5f; + ui.lastButtonX = bx; + ui.lastButtonY = by; + ui.lastButtonW = editW; + ui.lastButtonH = bh; + boolean hover = UnifiedSettingsSkin.inside(mx, my, bx, by, editW, bh); + ui.moduleHoverAnim = AnimationUtility.approach(ui.moduleHoverAnim, hover ? 1f : 0f, AnimationUtility.deltaTime(), 13f); + float labelY = y + (rowH - textBlockH) * 0.5f; + for (int i = 0; i < labelLines.size(); i++) { + ClickGuiRenderer.drawText(font, labelLines.get(i), labelX, labelY + i * (lineH + lineGap), labelSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); + } + SettingSkinUtil.renderChipButton(bx, by, editW, bh, "Edit", ui.moduleHoverAnim, false); + } + + private static void renderInlineTextList(TextListSetting setting, float x, float y, float w, float mx, float my) { + TextListSetting.UiState ui = setting.ui(); + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float labelSize = SettingSkinUtil.m(15.5f, 6.3f); + float fieldSize = SettingSkinUtil.m(14f, 6.1f); + String label = setting.getDisplayName(); + float labelY = y + SettingSkinUtil.m(5f, 2.5f); + float fieldY = y + SettingSkinUtil.m(23f, 11.5f); + float fieldH = SettingSkinUtil.m(20f, 13f); + float fieldX = x + SettingSkinUtil.m(5f, 5f); + float fieldW = Math.max(1f, w - SettingSkinUtil.m(10f, 10f)); + ui.fieldX = fieldX; + ui.fieldY = fieldY; + ui.fieldW = fieldW; + ui.fieldH = fieldH; + boolean hover = UnifiedSettingsSkin.inside(mx, my, fieldX, fieldY, fieldW, fieldH); + float dt = AnimationUtility.deltaTime(); + ui.fieldHoverAnim = AnimationUtility.approach(ui.fieldHoverAnim, hover ? 1f : 0f, dt, 13f); + ui.fieldFocusAnim = AnimationUtility.approach(ui.fieldFocusAnim, ui.editing ? 1f : 0f, dt, 12f); + ui.fieldErrorAnim = AnimationUtility.approach(ui.fieldErrorAnim, 0f, dt, 7f); + if (ui.editing) ui.cursorBlink += dt * 2.2f; + else ui.cursorBlink = 0f; + + ClickGuiRenderer.drawText(font, UnifiedSettingsSkin.fit(font, label, labelSize, fieldW), fieldX, labelY, labelSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); + float fieldAnim = Math.max(ui.fieldHoverAnim * 0.65f, ui.fieldFocusAnim); + int bg = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, fieldAnim), 56 + Math.round(fieldAnim * 42f)); + int stroke = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 58), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 155), ui.fieldFocusAnim); + stroke = UnifiedSettingsSkin.mix(stroke, 0xFFFF5F66, ui.fieldErrorAnim); + if (UnifiedSettingsSkin.SURFACE_GRADIENT_ENABLED) { + UnifiedSettingsSkin.drawSurface(fieldX, fieldY, fieldW, fieldH, SettingSkinUtil.m(5f, 3.5f), 0.55f + fieldAnim * 0.32f); + } else { + ClickGuiRenderer.drawRoundedRect(fieldX, fieldY, fieldW, fieldH, SettingSkinUtil.m(5f, 3.5f), bg); + } + ClickGuiRenderer.drawRoundedRectStroke(fieldX, fieldY, fieldW, fieldH, SettingSkinUtil.m(5f, 3.5f), SettingSkinUtil.m(0.7f, 0.45f), stroke); + + String current = firstTextListEntry(setting); + String text = ui.editing ? ui.editBuffer : current; + if (text == null) text = ""; + String placeholder = "value..."; + float pad = SettingSkinUtil.m(6f, 4f); + float textX = fieldX + pad; + float textY = fieldY + (fieldH - UnifiedSettingsSkin.textHeight(font, fieldSize)) * 0.5f - SettingSkinUtil.m(0.2f, 0.15f); + boolean clip = ScissorFunction.pushRaw(textX, fieldY, Math.max(1f, fieldW - pad * 2f), fieldH); + if (ui.editing) { + SettingTextInputUtil.renderInlineSelection(font, ui.editBuffer, TextListTextEditHandler.textListSelStart(ui), TextListTextEditHandler.textListSelEnd(ui), textX, textY, fieldSize, fieldH, fieldY); + ClickGuiRenderer.drawText(font, ui.editBuffer, textX, textY, fieldSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); + if (((int) (ui.cursorBlink * 2f) & 1) == 0) { + int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); + float cx = textX + UnifiedSettingsSkin.textWidth(font, ui.editBuffer.substring(0, cursor), fieldSize) + SettingSkinUtil.m(0.5f, 0.3f); + ClickGuiRenderer.drawRect(cx, fieldY + SettingSkinUtil.m(3f, 2f), SettingSkinUtil.m(0.65f, 0.4f), fieldH - SettingSkinUtil.m(6f, 4f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_PRIMARY, 205)); + } + } else { + boolean empty = text.isBlank(); + String draw = empty ? placeholder : UnifiedSettingsSkin.fit(font, text, fieldSize, fieldW - pad * 2f); + ClickGuiRenderer.drawText(font, draw, textX, textY, fieldSize, empty ? UnifiedSettingsSkin.TEXT_FAINT : UnifiedSettingsSkin.TEXT_PRIMARY, false); + } + if (clip) ScissorFunction.pop(); + } + + static void mouseClicked(TextListSetting setting, double mx, double my, int button) { + if (button != 0) return; + TextListSetting.UiState ui = setting.ui(); + if (isInlineTextList(setting)) { + if (UnifiedSettingsSkin.inside(mx, my, ui.fieldX, ui.fieldY, ui.fieldW, ui.fieldH)) { + TextListTextEditHandler.beginTextListEdit(setting); + TextListTextEditHandler.setTextListCursorFromMouse(setting, (float) mx, false); + } else if (ui.editing) { + TextListTextEditHandler.commitTextListEdit(setting, true); + } + return; + } + if (!UnifiedSettingsSkin.inside(mx, my, ui.lastButtonX, ui.lastButtonY, ui.lastButtonW, ui.lastButtonH)) return; + if (setting.getPickerMode() == TextListSetting.PickerMode.TEXT) { + ClickGuiRenderer.openTextEditor(setting, setting.getDisplayName(), setting.getEditorText(), ui.lastButtonX, ui.lastButtonY, ui.lastButtonW); + } else { + ClickGuiRenderer.openPicker(setting, setting.getDisplayName(), setting.getPickerMode()); + } + } + + static void mouseClickedOutside(TextListSetting setting, double mx, double my, int button) { + if (button != 0 || !isInlineTextList(setting)) return; + if (setting.ui().editing) TextListTextEditHandler.commitTextListEdit(setting, true); + } + + static float getHeight(TextListSetting setting) { + return isInlineTextList(setting) ? inlineTextListHeight() : textListButtonHeight(setting); + } + + static boolean isInlineTextList(TextListSetting setting) { + return setting.getPickerMode() == TextListSetting.PickerMode.TEXT && setting.isSingleLine(); + } + + private static float inlineTextListHeight() { + return SettingSkinUtil.m(50f, 28f); + } + + private static String firstTextListEntry(TextListSetting setting) { + Set set = setting.getValueSet(); + if (set == null || set.isEmpty()) return ""; + return set.iterator().next(); + } + + private static float textListButtonHeight(TextListSetting setting) { + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float width = setting.ui().lastW > 0f ? setting.ui().lastW : SettingSkinUtil.m(170f, 115f); + float labelSize = SettingSkinUtil.m(15.5f, 6.4f); + float small = SettingSkinUtil.m(11.5f, 5.7f); + float editW = Math.max(SettingSkinUtil.m(36f, 28f), UnifiedSettingsSkin.textWidth(font, "Edit", small) + SettingSkinUtil.m(12f, 12f)); + float labelMax = Math.max(SettingSkinUtil.m(50f, 34f), width - editW - SettingSkinUtil.m(22f, 16f)); + List labelLines = ClickGuiRenderer.wrapText(font, setting.getDisplayName(), labelSize, labelMax, 2); + int lines = Math.max(1, labelLines.size()); + float lineH = UnifiedSettingsSkin.textHeight(font, labelSize); + float textBlockH = lines * lineH + Math.max(0, lines - 1) * SettingSkinUtil.m(2f, 0.7f); + return Math.max(SettingSkinUtil.m(44f, 24f), textBlockH + SettingSkinUtil.m(14f, 8f)); + } + + static String firstEntry(TextListSetting setting) { + return firstTextListEntry(setting); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListTextEditHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListTextEditHandler.java new file mode 100644 index 0000000..6d08e41 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextListTextEditHandler.java @@ -0,0 +1,161 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.text.ClipboardUtil; +import org.lwjgl.glfw.GLFW; + +import java.util.LinkedHashSet; + +final class TextListTextEditHandler { + private TextListTextEditHandler() { + } + + static void beginTextListEdit(TextListSetting setting) { + TextListSetting.UiState ui = setting.ui(); + if (!ui.editing) { + ui.editBuffer = TextListSettingRenderer.firstEntry(setting); + ui.editCursor = ui.editBuffer.length(); + ui.editSelection.clear(); + ui.fieldErrorAnim = 0f; + } + ui.editing = true; + ui.cursorBlink = 0f; + } + + static void cancelTextListEdit(TextListSetting setting) { + TextListSetting.UiState ui = setting.ui(); + ui.editing = false; + ui.editBuffer = TextListSettingRenderer.firstEntry(setting); + ui.editCursor = ui.editBuffer.length(); + ui.editSelection.clear(); + ui.fieldErrorAnim = 0f; + } + + static void commitTextListEdit(TextListSetting setting, boolean save) { + TextListSetting.UiState ui = setting.ui(); + String raw = ui.editBuffer == null ? "" : ui.editBuffer.trim(); + LinkedHashSet next = new LinkedHashSet<>(); + if (!raw.isEmpty()) next.add(setting.normalizeEntry(raw)); + setting.value().set(next); + ui.editing = false; + ui.editSelection.clear(); + if (save && setting.getParent() != null) setting.getParent().saveConfig(); + } + + static void setTextListCursorFromMouse(TextListSetting setting, float mx, boolean shift) { + TextListSetting.UiState ui = setting.ui(); + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float size = SettingSkinUtil.m(14f, 6.1f); + int cursor = SettingTextInputUtil.caretFromText(font, ui.editBuffer == null ? "" : ui.editBuffer, size, ui.fieldX + SettingSkinUtil.m(6f, 4f), mx); + setTextListCursor(ui, cursor, shift); + } + + static void setTextListCursor(TextListSetting.UiState ui, int pos, boolean shift) { + int next = Math.max(0, Math.min(ui.editBuffer == null ? 0 : ui.editBuffer.length(), pos)); + if (shift) { + if (!ui.editSelection.hasRange()) ui.editSelection.begin(0, ui.editCursor); + ui.editSelection.updateCaret(0, next); + } else { + ui.editSelection.clear(); + } + ui.editCursor = next; + ui.cursorBlink = 0f; + } + + static void insertTextListText(TextListSetting setting, String text) { + TextListSetting.UiState ui = setting.ui(); + if (text == null || text.isEmpty()) return; + deleteTextListSelection(ui); + String clean = text.replace("\r", "").replace("\n", " "); + int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); + ui.editBuffer = ui.editBuffer.substring(0, cursor) + clean + ui.editBuffer.substring(cursor); + ui.editCursor = cursor + clean.length(); + ui.editSelection.clear(); + } + + static void selectAllTextList(TextListSetting.UiState ui) { + ui.editSelection.begin(0, 0); + ui.editSelection.updateCaret(0, ui.editBuffer == null ? 0 : ui.editBuffer.length()); + ui.editCursor = ui.editBuffer == null ? 0 : ui.editBuffer.length(); + } + + static String selectedOrAllTextList(TextListSetting.UiState ui) { + if (hasTextListSelection(ui)) return ui.editBuffer.substring(textListSelStart(ui), textListSelEnd(ui)); + return ui.editBuffer == null ? "" : ui.editBuffer; + } + + static boolean hasTextListSelection(TextListSetting.UiState ui) { + return ui.editSelection.hasRange(); + } + + static int textListSelStart(TextListSetting.UiState ui) { + return hasTextListSelection(ui) ? Math.max(0, Math.min(ui.editSelection.start(), ui.editBuffer.length())) : -1; + } + + static int textListSelEnd(TextListSetting.UiState ui) { + return hasTextListSelection(ui) ? Math.max(0, Math.min(ui.editSelection.end(), ui.editBuffer.length())) : -1; + } + + static boolean deleteTextListSelection(TextListSetting.UiState ui) { + if (!hasTextListSelection(ui)) return false; + int start = textListSelStart(ui); + int end = textListSelEnd(ui); + ui.editBuffer = ui.editBuffer.substring(0, start) + ui.editBuffer.substring(end); + ui.editCursor = start; + ui.editSelection.clear(); + return true; + } + + static boolean keyPressed(TextListSetting setting, int keyCode, int scanCode, int modifiers) { + if (!TextListSettingRenderer.isInlineTextList(setting)) return false; + TextListSetting.UiState ui = setting.ui(); + if (!ui.editing) return false; + boolean ctrl = (modifiers & GLFW.GLFW_MOD_CONTROL) != 0; + boolean shift = (modifiers & GLFW.GLFW_MOD_SHIFT) != 0; + if (ctrl && keyCode == GLFW.GLFW_KEY_A) { selectAllTextList(ui); return true; } + if (ctrl && keyCode == GLFW.GLFW_KEY_C) { ClipboardUtil.copy(selectedOrAllTextList(ui)); return true; } + if (ctrl && keyCode == GLFW.GLFW_KEY_V) { insertTextListText(setting, ClipboardUtil.get()); return true; } + if (ctrl && keyCode == GLFW.GLFW_KEY_X) { + ClipboardUtil.copy(selectedOrAllTextList(ui)); + deleteTextListSelection(ui); + return true; + } + switch (keyCode) { + case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> { commitTextListEdit(setting, true); return true; } + case GLFW.GLFW_KEY_ESCAPE -> { cancelTextListEdit(setting); return true; } + case GLFW.GLFW_KEY_BACKSPACE -> { + if (!deleteTextListSelection(ui) && ui.editCursor > 0) { + ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor - 1) + ui.editBuffer.substring(ui.editCursor); + ui.editCursor--; + } + return true; + } + case GLFW.GLFW_KEY_DELETE -> { + if (!deleteTextListSelection(ui) && ui.editCursor < ui.editBuffer.length()) + ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor) + ui.editBuffer.substring(ui.editCursor + 1); + return true; + } + case GLFW.GLFW_KEY_LEFT -> { setTextListCursor(ui, ui.editCursor - 1, shift); return true; } + case GLFW.GLFW_KEY_RIGHT -> { setTextListCursor(ui, ui.editCursor + 1, shift); return true; } + case GLFW.GLFW_KEY_HOME -> { setTextListCursor(ui, 0, shift); return true; } + case GLFW.GLFW_KEY_END -> { setTextListCursor(ui, ui.editBuffer.length(), shift); return true; } + } + return true; + } + + static boolean charTyped(TextListSetting setting, char chr, int modifiers) { + if (!TextListSettingRenderer.isInlineTextList(setting)) return false; + TextListSetting.UiState ui = setting.ui(); + if (!ui.editing) return false; + if (chr == '\n' || chr == '\r') return true; + insertTextListText(setting, String.valueOf(chr)); + return true; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSetting.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSetting.java index e6f9d51..72810de 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSetting.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSetting.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSettingRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSettingRenderer.java new file mode 100644 index 0000000..5dff8e5 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSettingRenderer.java @@ -0,0 +1,103 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ScissorFunction; + +final class TextSettingRenderer { + private TextSettingRenderer() { + } + + static void render(TextSetting setting, float x, float y, float w, float mx, float my) { + UnifiedSettingsSkin.syncTheme(); + TextSetting.UiState ui = setting.ui(); + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + float labelSize = SettingSkinUtil.m(15.5f, 6.3f); + float fieldSize = SettingSkinUtil.m(14f, 6.1f); + float fx = x + SettingSkinUtil.m(5f, 5f); + float fy = y + SettingSkinUtil.m(23f, 11.5f); + float fw = Math.max(1f, w - SettingSkinUtil.m(10f, 10f)); + float fh = SettingSkinUtil.m(20f, 13f); + String value = setting.getEditorText(); + ui.fieldX = fx; + ui.fieldY = fy; + ui.fieldW = fw; + ui.fieldH = fh; + + boolean hover = UnifiedSettingsSkin.inside(mx, my, fx, fy, fw, fh); + float dt = AnimationUtility.deltaTime(); + ui.hoverAnim = AnimationUtility.approach(ui.hoverAnim, hover ? 1f : 0f, dt, 13f); + ui.focusAnim = AnimationUtility.approach(ui.focusAnim, ui.editing ? 1f : 0f, dt, 12f); + ui.errorAnim = AnimationUtility.approach(ui.errorAnim, 0f, dt, 7f); + if (ui.editing) ui.cursorBlink += dt * 2.2f; + else ui.cursorBlink = 0f; + + ClickGuiRenderer.drawText(font, UnifiedSettingsSkin.fit(font, setting.getDisplayName(), labelSize, fw), fx, y + SettingSkinUtil.m(5f, 2.5f), labelSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); + float fieldAnim = Math.max(ui.hoverAnim * 0.65f, ui.focusAnim); + int bg = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, fieldAnim), 56 + Math.round(fieldAnim * 42f)); + int stroke = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 58), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 155), ui.focusAnim); + stroke = UnifiedSettingsSkin.mix(stroke, 0xFFFF5F66, ui.errorAnim); + if (UnifiedSettingsSkin.SURFACE_GRADIENT_ENABLED) { + UnifiedSettingsSkin.drawSurface(fx, fy, fw, fh, SettingSkinUtil.m(5f, 3.5f), 0.55f + fieldAnim * 0.32f); + } else { + ClickGuiRenderer.drawRoundedRect(fx, fy, fw, fh, SettingSkinUtil.m(5f, 3.5f), bg); + } + ClickGuiRenderer.drawRoundedRectStroke(fx, fy, fw, fh, SettingSkinUtil.m(5f, 3.5f), SettingSkinUtil.m(0.7f, 0.45f), stroke); + + String text = ui.editing ? ui.editBuffer : (value == null ? "" : value); + String placeholder = "text..."; + float pad = SettingSkinUtil.m(6f, 4f); + float textX = fx + pad; + float textY = fy + (fh - UnifiedSettingsSkin.textHeight(font, fieldSize)) * 0.5f - SettingSkinUtil.m(0.2f, 0.15f); + float clipW = Math.max(1f, fw - pad * 2f); + if (ui.editing) TextSettingTextInputHandler.ensureTextCursorVisible(ui, font, ui.editBuffer, fieldSize, clipW); + else ui.textScroll = 0f; + float drawX = textX - ui.textScroll; + ui.textX = drawX; + ui.textY = textY; + ui.textSize = fieldSize; + boolean clip = ScissorFunction.pushRaw(textX, fy, clipW, fh); + if (ui.editing) { + SettingTextInputUtil.renderInlineSelection(font, ui.editBuffer, TextSettingTextInputHandler.textSelStart(ui), TextSettingTextInputHandler.textSelEnd(ui), drawX, textY, fieldSize, fh, fy); + ClickGuiRenderer.drawText(font, ui.editBuffer, drawX, textY, fieldSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); + if (((int) (ui.cursorBlink * 2f) & 1) == 0) { + int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); + float cx = drawX + UnifiedSettingsSkin.textWidth(font, ui.editBuffer.substring(0, cursor), fieldSize) + SettingSkinUtil.m(0.5f, 0.3f); + ClickGuiRenderer.drawRect(cx, fy + SettingSkinUtil.m(3f, 2f), SettingSkinUtil.m(0.65f, 0.4f), fh - SettingSkinUtil.m(6f, 4f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_PRIMARY, 205)); + } + } else { + boolean empty = text.isBlank(); + String draw = empty ? placeholder : UnifiedSettingsSkin.fit(font, text, fieldSize, fw - pad * 2f); + ClickGuiRenderer.drawText(font, draw, textX, textY, fieldSize, empty ? UnifiedSettingsSkin.TEXT_FAINT : UnifiedSettingsSkin.TEXT_PRIMARY, false); + } + if (clip) ScissorFunction.pop(); + } + + static void mouseClicked(TextSetting setting, double mx, double my, int button) { + if (button != 0) return; + TextSetting.UiState ui = setting.ui(); + if (UnifiedSettingsSkin.inside(mx, my, ui.fieldX, ui.fieldY, ui.fieldW, ui.fieldH)) { + TextSettingTextInputHandler.beginTextEdit(setting); + TextSettingTextInputHandler.setTextCursorFromMouse(setting, (float) mx, false); + } else if (ui.editing) { + TextSettingTextInputHandler.commitTextEdit(setting, true); + } + } + + static void mouseClickedOutside(TextSetting setting, double mx, double my, int button) { + if (button != 0) return; + if (setting.ui().editing) TextSettingTextInputHandler.commitTextEdit(setting, true); + } + + static float getHeight(TextSetting setting) { + return SettingSkinUtil.m(50f, 28f); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSettingTextInputHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSettingTextInputHandler.java new file mode 100644 index 0000000..05278bf --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/TextSettingTextInputHandler.java @@ -0,0 +1,171 @@ +/* + * 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.features.gui.clickgui.settings; + +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.text.ClipboardUtil; +import org.lwjgl.glfw.GLFW; + +final class TextSettingTextInputHandler { + private TextSettingTextInputHandler() { + } + + static void beginTextEdit(TextSetting setting) { + TextSetting.UiState ui = setting.ui(); + if (!ui.editing) { + ui.editBuffer = setting.getEditorText(); + ui.editCursor = ui.editBuffer.length(); + ui.editSelection.clear(); + ui.errorAnim = 0f; + } + ui.editing = true; + ui.cursorBlink = 0f; + } + + static void cancelTextEdit(TextSetting setting) { + TextSetting.UiState ui = setting.ui(); + ui.editing = false; + ui.editBuffer = setting.getEditorText(); + ui.editCursor = ui.editBuffer.length(); + ui.textScroll = 0f; + ui.editSelection.clear(); + ui.errorAnim = 0f; + } + + static void commitTextEdit(TextSetting setting, boolean save) { + TextSetting.UiState ui = setting.ui(); + setting.applyEditorText(ui.editBuffer == null ? "" : ui.editBuffer); + ui.editing = false; + ui.textScroll = 0f; + ui.editSelection.clear(); + if (!save && setting.getParent() != null) setting.getParent().saveConfig(); + } + + static void setTextCursorFromMouse(TextSetting setting, float mx, boolean shift) { + TextSetting.UiState ui = setting.ui(); + TextRenderer font = UnifiedSettingsSkin.fontMedium(); + int cursor = SettingTextInputUtil.caretFromText(font, ui.editBuffer == null ? "" : ui.editBuffer, ui.textSize <= 0f ? SettingSkinUtil.m(14f, 6.1f) : ui.textSize, ui.textX, mx); + setTextCursor(ui, cursor, shift); + } + + static void setTextCursor(TextSetting.UiState ui, int pos, boolean shift) { + int next = Math.max(0, Math.min(ui.editBuffer == null ? 0 : ui.editBuffer.length(), pos)); + if (shift) { + if (!ui.editSelection.hasRange()) ui.editSelection.begin(0, ui.editCursor); + ui.editSelection.updateCaret(0, next); + } else { + ui.editSelection.clear(); + } + ui.editCursor = next; + ui.cursorBlink = 0f; + } + + static void insertTextText(TextSetting setting, String text) { + TextSetting.UiState ui = setting.ui(); + if (text == null || text.isEmpty()) return; + deleteTextSelection(ui); + String clean = text.replace("\r", "").replace("\n", " "); + int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); + ui.editBuffer = ui.editBuffer.substring(0, cursor) + clean + ui.editBuffer.substring(cursor); + ui.editCursor = cursor + clean.length(); + ui.editSelection.clear(); + } + + static void ensureTextCursorVisible(TextSetting.UiState ui, TextRenderer font, String text, float size, float visibleW) { + String safe = text == null ? "" : text; + int cursor = Math.max(0, Math.min(ui.editCursor, safe.length())); + float textW = UnifiedSettingsSkin.textWidth(font, safe, size); + float maxScroll = Math.max(0f, textW - visibleW); + float caretX = UnifiedSettingsSkin.textWidth(font, safe.substring(0, cursor), size); + float margin = Math.min(SettingSkinUtil.m(8f, 4f), visibleW * 0.35f); + + if (caretX - ui.textScroll > visibleW - margin) { + ui.textScroll = caretX - visibleW + margin; + } else if (caretX - ui.textScroll < margin) { + ui.textScroll = caretX - margin; + } + ui.textScroll = Math.max(0f, Math.min(maxScroll, ui.textScroll)); + } + + static void selectAllText(TextSetting.UiState ui) { + ui.editSelection.begin(0, 0); + ui.editSelection.updateCaret(0, ui.editBuffer == null ? 0 : ui.editBuffer.length()); + ui.editCursor = ui.editBuffer == null ? 0 : ui.editBuffer.length(); + } + + static String selectedOrAllText(TextSetting.UiState ui) { + if (hasTextSelection(ui)) return ui.editBuffer.substring(textSelStart(ui), textSelEnd(ui)); + return ui.editBuffer == null ? "" : ui.editBuffer; + } + + static boolean hasTextSelection(TextSetting.UiState ui) { + return ui.editSelection.hasRange(); + } + + static int textSelStart(TextSetting.UiState ui) { + return hasTextSelection(ui) ? Math.max(0, Math.min(ui.editSelection.start(), ui.editBuffer.length())) : -1; + } + + static int textSelEnd(TextSetting.UiState ui) { + return hasTextSelection(ui) ? Math.max(0, Math.min(ui.editSelection.end(), ui.editBuffer.length())) : -1; + } + + static boolean deleteTextSelection(TextSetting.UiState ui) { + if (!hasTextSelection(ui)) return false; + int start = textSelStart(ui); + int end = textSelEnd(ui); + ui.editBuffer = ui.editBuffer.substring(0, start) + ui.editBuffer.substring(end); + ui.editCursor = start; + ui.editSelection.clear(); + return true; + } + + static boolean keyPressed(TextSetting setting, int keyCode, int scanCode, int modifiers) { + TextSetting.UiState ui = setting.ui(); + if (!ui.editing) return false; + boolean ctrl = (modifiers & GLFW.GLFW_MOD_CONTROL) != 0; + boolean shift = (modifiers & GLFW.GLFW_MOD_SHIFT) != 0; + if (ctrl && keyCode == GLFW.GLFW_KEY_A) { selectAllText(ui); return true; } + if (ctrl && keyCode == GLFW.GLFW_KEY_C) { ClipboardUtil.copy(selectedOrAllText(ui)); return true; } + if (ctrl && keyCode == GLFW.GLFW_KEY_V) { insertTextText(setting, ClipboardUtil.get()); return true; } + if (ctrl && keyCode == GLFW.GLFW_KEY_X) { + ClipboardUtil.copy(selectedOrAllText(ui)); + deleteTextSelection(ui); + return true; + } + switch (keyCode) { + case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> { commitTextEdit(setting, true); return true; } + case GLFW.GLFW_KEY_ESCAPE -> { cancelTextEdit(setting); return true; } + case GLFW.GLFW_KEY_BACKSPACE -> { + if (!deleteTextSelection(ui) && ui.editCursor > 0) { + ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor - 1) + ui.editBuffer.substring(ui.editCursor); + ui.editCursor--; + } + return true; + } + case GLFW.GLFW_KEY_DELETE -> { + if (!deleteTextSelection(ui) && ui.editCursor < ui.editBuffer.length()) + ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor) + ui.editBuffer.substring(ui.editCursor + 1); + return true; + } + case GLFW.GLFW_KEY_LEFT -> { setTextCursor(ui, ui.editCursor - 1, shift); return true; } + case GLFW.GLFW_KEY_RIGHT -> { setTextCursor(ui, ui.editCursor + 1, shift); return true; } + case GLFW.GLFW_KEY_HOME -> { setTextCursor(ui, 0, shift); return true; } + case GLFW.GLFW_KEY_END -> { setTextCursor(ui, ui.editBuffer.length(), shift); return true; } + } + return true; + } + + static boolean charTyped(TextSetting setting, char chr, int modifiers) { + TextSetting.UiState ui = setting.ui(); + if (!ui.editing) return false; + if (chr == '\n' || chr == '\r') return true; + insertTextText(setting, String.valueOf(chr)); + return true; + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/UnifiedSettingRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/UnifiedSettingRenderer.java index bed4d68..4f3172c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/UnifiedSettingRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/UnifiedSettingRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,2792 +7,202 @@ package dev.loki.lovisual.features.gui.clickgui.settings; -import dev.loki.lovisual.render.engine.renderer.Renderer2D; -import dev.loki.lovisual.render.engine.svg.SvgRenderOptions; -import org.lwjgl.glfw.GLFW; -import dev.loki.lovisual.config.values.BindMode; -import dev.loki.lovisual.config.values.ColorValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; -import dev.loki.lovisual.render.engine.animation.AnimationUtility; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.render.helpers.ScissorFunction; -import dev.loki.lovisual.render.helpers.SystemCursor; -import dev.loki.lovisual.util.text.ClipboardUtil; -import dev.loki.lovisual.util.wav.ClickGuiSounds; - -import java.awt.*; -import java.util.HashSet; -import java.util.Set; - enum UnifiedSettingRenderer { ; - private static final float BIND_MARQUEE_SPEED = 22f; - private static final float BIND_MARQUEE_GAP = 14f; - private static final float BIND_MARQUEE_PAUSE_SEC = 0.8f; - - private static float m(float settings, float modules) { - return UnifiedSettingsSkin.metric(settings, modules); - } - - private static float s() { - return UnifiedSettingsSkin.scale(); - } - - private static boolean modules() { - return UnifiedSettingsSkin.modules(); - } // ------------------------------------------------------------ // Boolean // ------------------------------------------------------------ static void render(BooleanSetting setting, float x, float y, float w, float mx, float my) { - UnifiedSettingsSkin.syncTheme(); - BooleanSetting.UiState ui = setting.ui(); - LayoutBoolean layout = booleanLayout(setting, w); - ui.lastX = x; - ui.lastY = y; - ui.lastW = w; - ui.lastH = layout.rowH; - - boolean enabled = setting.get(); - float dt = AnimationUtility.deltaTime(); - ui.anim = AnimationUtility.approach(ui.anim, enabled ? 1f : 0f, dt, 13f); - boolean hover = UnifiedSettingsSkin.inside(mx, my, x, y, w, layout.rowH); - ui.hoverAnim = AnimationUtility.approach(ui.hoverAnim, hover ? 1f : 0f, dt, 12f); - - TextRenderer font = modules() ? UnifiedSettingsSkin.fontRegular() : ClickGuiRenderer.getIosevkaRegular(); - float labelSize = m(18f, 6.8f); - - float cardX = x + m(2f, 2f); - float cardY = y + m(3f, 2f); - float cardW = Math.max(1f, w - m(4f, 4f)); - float cardH = Math.max(m(28f, 17f), layout.rowH - m(6f, 4f)); - float radius = m(8f, 5f); - UnifiedSettingsSkin.drawCard(cardX, cardY, cardW, cardH, radius, 0.42f + ui.hoverAnim * 0.24f); - float cardStrokeAnim = Math.max(ui.hoverAnim, ui.anim); - if (cardStrokeAnim > 0.001f) { - int strokeA = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(ui.hoverAnim * 82f)); - int strokeB = UnifiedSettingsSkin.accentGradientStart(ui.anim * 0.50f); - ClickGuiRenderer.drawRoundedRectStroke(cardX, cardY, cardW, cardH, radius, m(0.65f, 0.42f), UnifiedSettingsSkin.mix(strokeA, strokeB, Math.max(ui.anim, ui.hoverAnim * 0.28f))); - } - - float sw = m(39f, 16f); - float sh = m(18f, 8f); - float sx = cardX + m(8f, 5f); - float sy = cardY + (cardH - sh) * 0.5f; - ui.lastControlX = sx; - ui.lastControlY = sy; - ui.lastControlW = sw; - ui.lastControlH = sh; - - int bgOffA = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE, UnifiedSettingsSkin.SURFACE_HOVER, 0.45f + ui.hoverAnim * 0.20f); - int bgOffB = UnifiedSettingsSkin.mix(bgOffA, 0xFF000000, 0.30f); - int bgOnA = UnifiedSettingsSkin.accentGradientStart(1f); - int bgOnB = UnifiedSettingsSkin.accentGradientEnd(1f); - int bgA = UnifiedSettingsSkin.mix(bgOffA, bgOnA, ui.anim); - int bgB = UnifiedSettingsSkin.mix(bgOffB, bgOnB, ui.anim); - ClickGuiRenderer.drawRoundedRectGradient(sx, sy, sw, sh, sh * 0.5f, bgA, bgB, UnifiedSettingsSkin.ACCENT_GRADIENT_ANGLE); - ClickGuiRenderer.drawRoundedRectStroke(sx, sy, sw, sh, sh * 0.5f, m(0.65f, 0.42f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 50 + Math.round(ui.hoverAnim * 44f))); - - float knob = sh - m(4f, 2.4f); - float kx = sx + m(2f, 1.2f) + (sw - knob - m(4f, 2.4f)) * AnimationUtility.easeInOutCubic(ui.anim); - float ky = sy + (sh - knob) * 0.5f; - int knobCol = UnifiedSettingsSkin.mix(0xFFECEEF2, 0xFFFFFFFF, ui.anim * 0.55f + ui.hoverAnim * 0.18f); - ClickGuiRenderer.drawRoundedRect(kx, ky, knob, knob, knob * 0.5f, knobCol); - - float labelX = sx + sw + m(9f, 6f); - int labelColor = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.72f + ui.hoverAnim * 0.16f + ui.anim * 0.12f); - - ClickGuiRenderer.beginTextBatch(); - for (int i = 0; i < layout.lines.length; i++) { - ClickGuiRenderer.drawText(font, layout.lines[i], labelX, y + layout.labelY + i * (layout.lineH + m(2f, 0.7f)), labelSize, labelColor, false); - } - ClickGuiRenderer.endTextBatch(); + BooleanSettingRenderer.render(setting, x, y, w, mx, my); } static void mouseClicked(BooleanSetting setting, double mx, double my, int button) { - if (button != 0) return; - BooleanSetting.UiState ui = setting.ui(); - if (!UnifiedSettingsSkin.inside(mx, my, ui.lastX, ui.lastY, ui.lastW, ui.lastH)) return; - setting.set(!setting.get()); - ClickGuiSounds.changeMode(); - if (setting.getParent() != null) setting.getParent().saveConfig(); + BooleanSettingRenderer.mouseClicked(setting, mx, my, button); } static float getHeight(BooleanSetting setting) { - return booleanLayout(setting, setting.ui().lastW > 0f ? setting.ui().lastW : m(170f, 115f)).rowH; - } - - private static LayoutBoolean booleanLayout(BooleanSetting setting, float width) { - BooleanSetting.UiState ui = setting.ui(); - TextRenderer font = modules() ? UnifiedSettingsSkin.fontRegular() : ClickGuiRenderer.getIosevkaRegular(); - float labelSize = m(18f, 6.8f); - float switchW = m(39f, 16f); - String labelText = setting.getDisplayName(); - boolean needsLayout = !Float.isFinite(ui.layoutW) - || Math.abs(ui.layoutW - width) > 0.5f - || !labelText.equals(ui.layoutLabel); - if (needsLayout) { - float lineH = UnifiedSettingsSkin.textHeight(font, labelSize); - float labelMaxW = Math.max(m(72f, 36f), width - switchW - m(31f, 18f)); - var linesList = ClickGuiRenderer.wrapText(font, labelText, labelSize, labelMaxW, 2); - String[] lines = linesList.toArray(new String[0]); - float gap = m(2f, 0.7f); - float textBlockH = lines.length * lineH + Math.max(0, lines.length - 1) * gap; - float contentH = Math.max(textBlockH, m(18f, 8f)); - float minRow = m(44f, 24f); - ui.layoutW = width; - ui.layoutLabel = labelText; - ui.layoutLines = lines; - ui.layoutLineH = lineH; - ui.layoutRowH = Math.max(minRow, contentH + m(14f, 8f)); - ui.layoutLabelY = (ui.layoutRowH - textBlockH) * 0.5f; - ui.layoutControlY = (ui.layoutRowH - m(18f, 8f)) * 0.5f; - } - return new LayoutBoolean(ui.layoutLines, ui.layoutLineH, ui.layoutLabelY, ui.layoutControlY, ui.layoutRowH); - } - - static void render(SliderSetting setting, float x, float y, float w, float mx, float my) { - UnifiedSettingsSkin.syncTheme(); - SliderSetting.UiState ui = setting.ui(); - NumberValue value = setting.value(); - double min = value.getMin().doubleValue(); - double max = value.getMax().doubleValue(); - double val = value.get().doubleValue(); - - ui.lastX = x; - ui.lastY = y; - ui.lastW = w; - - float dt = AnimationUtility.deltaTime(); - if (ui.dragging && !ui.editing) { - setSliderValueFromMouse(setting, mx, x + m(6f, 5f), Math.max(1f, w - m(6f, 5f) * 2f), min, max); - val = value.get().doubleValue(); - } - - float trackPad = m(6f, 5f); - float trackX = x + trackPad; - float trackW = Math.max(1f, w - trackPad * 2f); - float trackY = y + m(38f, 15f); - float trackH = m(2.4f, 1.2f); - - float target = max == min ? 0f : (float) ((val - min) / (max - min)); - target = UnifiedSettingsSkin.clamp01(target); - ui.anim = AnimationUtility.approach(ui.anim, target, 0.40f); - boolean trackHover = UnifiedSettingsSkin.inside(mx, my, trackX, trackY - m(6f, 2f), trackW, trackH + m(12f, 4f)); - if ((trackHover && !ui.editing) || ui.dragging) { - SystemCursor.set(SystemCursor.CursorType.RESIZE_HORIZONTAL); - } - ui.hoverAnim = AnimationUtility.approach(ui.hoverAnim, trackHover ? 1f : 0f, dt, 12f); - ui.editAnim = AnimationUtility.approach(ui.editAnim, ui.editing ? 1f : 0f, dt, 14f); - ui.errorAnim = AnimationUtility.approach(ui.errorAnim, 0f, dt, 7.5f); - if (ui.editing) ui.cursorBlink += dt * 2.3f; - else ui.cursorBlink = 0f; - - TextRenderer font = modules() ? UnifiedSettingsSkin.fontRegular() : ClickGuiRenderer.getIosevkaRegular(); - float labelSize = m(17f, 6.8f); - float valueSize = m(17f, 6.8f); - float textY = y + m(6f, 1.9f); - String display = ui.editing ? ui.editBuffer : value.toDisplay(); - if (display == null) display = ""; - float valuePad = m(6f, 4f); - float rawValueW = UnifiedSettingsSkin.textWidth(font, display.isEmpty() ? "0" : display, valueSize) + valuePad * 2f; - float valueW = Math.max(m(34f, 20f), rawValueW); - valueW = Math.min(valueW, Math.max(m(46f, 28f), w * 0.48f)); - ui.valueX = x + w - valueW - trackPad; - ui.valueY = textY - m(4f, 1.5f); - ui.valueW = valueW; - ui.valueH = UnifiedSettingsSkin.textHeight(font, valueSize) + m(8f, 4f); - boolean valueHover = UnifiedSettingsSkin.inside(mx, my, ui.valueX, ui.valueY, ui.valueW, ui.valueH); - ui.valueHoverAnim = AnimationUtility.approach(ui.valueHoverAnim, valueHover ? 1f : 0f, dt, 12f); - ui.inputHoverAnim = AnimationUtility.approach(ui.inputHoverAnim, valueHover ? 1f : 0f, dt, 15f); - ui.inputFocusGlowAnim = AnimationUtility.approach(ui.inputFocusGlowAnim, ui.editing ? 1f : 0f, dt, 12f); - ui.inputPressAnim = AnimationUtility.approach(ui.inputPressAnim, ui.editing ? 1f : 0f, dt, 10f); - - int textCol = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_PRIMARY, 0xFFFF7777, ui.errorAnim * 0.85f); - float fieldAnim = Math.max(ui.inputHoverAnim * 0.62f, ui.inputFocusGlowAnim); - int fieldBg = UnifiedSettingsSkin.withAlpha( - UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, fieldAnim * 0.72f), - Math.round(fieldAnim * 104f) - ); - int fieldStrokeBase = UnifiedSettingsSkin.mix( - UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(fieldAnim * 70f)), - UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, Math.round(ui.inputFocusGlowAnim * 160f)), - ui.inputFocusGlowAnim - ); - int fieldStroke = UnifiedSettingsSkin.mix(fieldStrokeBase, 0xFFFF5F66, ui.errorAnim); - - ClickGuiRenderer.beginTextBatch(); - String label = setting.getDisplayName(); - float labelMax = Math.max(1f, ui.valueX - trackX - m(7f, 5f)); - ClickGuiRenderer.drawText(font, UnifiedSettingsSkin.fit(font, label, labelSize, labelMax), trackX, textY, labelSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); - ClickGuiRenderer.endTextBatch(); - - if (fieldAnim > 0.001f || ui.errorAnim > 0.001f) { - float lift = ui.inputFocusGlowAnim * m(1.0f, 0.45f); - if (UnifiedSettingsSkin.SURFACE_GRADIENT_ENABLED) { - UnifiedSettingsSkin.drawSurface(ui.valueX, ui.valueY - lift, ui.valueW, ui.valueH + lift * 2f, m(6f, 3.5f), fieldAnim); - } else { - ClickGuiRenderer.drawRoundedRect(ui.valueX, ui.valueY - lift, ui.valueW, ui.valueH + lift * 2f, m(6f, 3.5f), fieldBg); - } - if (ui.inputFocusGlowAnim > 0.02f) { - ClickGuiRenderer.drawRoundedRectStrokeGradient(ui.valueX, ui.valueY - lift, ui.valueW, ui.valueH + lift * 2f, m(6f, 3.5f), m(0.8f, 0.45f), UnifiedSettingsSkin.accentGradientStart(0.72f), UnifiedSettingsSkin.accentGradientEnd(0.72f), UnifiedSettingsSkin.ACCENT_GRADIENT_ANGLE); - } else { - ClickGuiRenderer.drawRoundedRectStroke(ui.valueX, ui.valueY - lift, ui.valueW, ui.valueH + lift * 2f, m(6f, 3.5f), m(0.7f, 0.45f), fieldStroke); - } - if (ui.errorAnim > 0.01f) { - ClickGuiRenderer.drawRoundedRectStroke(ui.valueX, ui.valueY - lift, ui.valueW, ui.valueH + lift * 2f, m(6f, 3.5f), m(1.0f, 0.55f), UnifiedSettingsSkin.withAlpha(0xFFFF5F66, Math.round(170f * ui.errorAnim))); - } - } - - float textBaseY = y + m(6f, 1.9f); - ui.valueTextSize = valueSize; - ui.valueTextPad = valuePad; - ui.valueTextY = textBaseY; - String drawValue = ui.editing ? display : UnifiedSettingsSkin.fit(font, display, valueSize, ui.valueW - valuePad * 2f); - float drawW = UnifiedSettingsSkin.textWidth(font, drawValue, valueSize); - float drawX = ui.editing ? ui.valueX + valuePad : ui.valueX + ui.valueW - drawW - valuePad; - ui.valueTextX = drawX; - boolean textClip = ScissorFunction.pushRaw(ui.valueX + valuePad * 0.65f, ui.valueY, Math.max(1f, ui.valueW - valuePad * 1.3f), ui.valueH); - if (ui.editing) { - renderInlineSelection(font, ui.editBuffer, sliderSelStart(ui), sliderSelEnd(ui), drawX, textBaseY, valueSize, ui.valueH, 0f); - } - ClickGuiRenderer.drawText(font, drawValue, drawX, textBaseY, valueSize, textCol, false); - if (ui.editing && ((int) (ui.cursorBlink * 2f) & 1) == 0) { - int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); - float cx = drawX + UnifiedSettingsSkin.textWidth(font, ui.editBuffer.substring(0, cursor), valueSize) + m(0.5f, 0.3f); - ClickGuiRenderer.drawRect(cx, ui.valueY + m(3f, 1.5f), m(0.75f, 0.45f), ui.valueH - m(6f, 3f), UnifiedSettingsSkin.withAlpha(textCol, 205)); - } - if (textClip) ScissorFunction.pop(); - - int baseTrack = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE, UnifiedSettingsSkin.SURFACE_HOVER, 0.55f + ui.hoverAnim * 0.15f); - ClickGuiRenderer.drawRoundedRect(trackX, trackY, trackW, trackH, 0.6f * s(), baseTrack); - float fillW = trackW * ui.anim; - if (fillW > 0.5f) { - ClickGuiRenderer.drawGradientRect(trackX, trackY, fillW, trackH, UnifiedSettingsSkin.accentGradientStart(1f), UnifiedSettingsSkin.accentGradientEnd(1f), UnifiedSettingsSkin.accentGradientEnd(1f), UnifiedSettingsSkin.accentGradientStart(1f)); - } - - float knobW = m(2.4f, 1.2f); - float knobH = m(7.2f, 4.2f); - float knobX = trackX + fillW - knobW * 0.5f; - float knobY = trackY - (knobH - trackH) * 0.5f; - int knobCol = UnifiedSettingsSkin.mix(0xFFE1E1E1, UnifiedSettingsSkin.accentGradientStart(1f), 0.25f + ui.hoverAnim * 0.20f); - ClickGuiRenderer.drawRoundedRect(knobX, knobY, knobW, knobH, knobW * 0.5f, knobCol); + return BooleanSettingRenderer.getHeight(setting); } // ------------------------------------------------------------ // Slider // ------------------------------------------------------------ + static void render(SliderSetting setting, float x, float y, float w, float mx, float my) { + SliderSettingRenderer.render(setting, x, y, w, mx, my); + } + static void mouseClicked(SliderSetting setting, double mx, double my, int button) { - if (button != 0) return; - float trackPad = m(6f, 5f); - SliderSetting.UiState ui = setting.ui(); - if (ui.editing) { - if (UnifiedSettingsSkin.inside(mx, my, ui.valueX, ui.valueY, ui.valueW, ui.valueH)) { - setSliderEditCursorFromMouse(setting, (float) mx, false); - } else { - commitSliderEdit(setting, true); - } - return; - } - if (UnifiedSettingsSkin.inside(mx, my, ui.valueX, ui.valueY, ui.valueW, ui.valueH)) { - beginSliderEdit(setting); - setSliderEditCursorFromMouse(setting, (float) mx, false); - return; - } - float trackX = ui.lastX + trackPad; - float trackW = Math.max(1f, ui.lastW - trackPad * 2f); - float trackY = ui.lastY + m(38f, 15f); - float trackH = m(2.4f, 1.2f); - if (!UnifiedSettingsSkin.inside(mx, my, trackX, trackY - m(6f, 2f), trackW, trackH + m(12f, 4f))) return; - ui.dragging = true; - setSliderValueFromMouse(setting, (float) mx, trackX, trackW, setting.value().getMin().doubleValue(), setting.value().getMax().doubleValue()); + SliderSettingRenderer.mouseClicked(setting, mx, my, button); } static void mouseReleased(SliderSetting setting, double mx, double my, int button) { - if (button != 0 || !setting.ui().dragging) return; - setting.ui().dragging = false; - if (setting.getParent() != null) setting.getParent().saveConfig(); + SliderSettingRenderer.mouseReleased(setting, mx, my, button); } static void mouseClickedOutside(SliderSetting setting, double mx, double my, int button) { - if (button != 0) return; - SliderSetting.UiState ui = setting.ui(); - if (!ui.editing) return; - commitSliderEdit(setting, true); + SliderSettingRenderer.mouseClickedOutside(setting, mx, my, button); } static boolean keyPressed(SliderSetting setting, int keyCode, int scanCode, int modifiers) { - SliderSetting.UiState ui = setting.ui(); - if (!ui.editing) return false; - boolean ctrl = (modifiers & GLFW.GLFW_MOD_CONTROL) != 0; - boolean shift = (modifiers & GLFW.GLFW_MOD_SHIFT) != 0; - if (ctrl && keyCode == GLFW.GLFW_KEY_A) { - selectAllSliderText(ui); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_C) { - ClipboardUtil.copy(selectedOrAllSliderText(ui)); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_V) { - insertSliderText(setting, ClipboardUtil.get()); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_X) { - ClipboardUtil.copy(selectedOrAllSliderText(ui)); - deleteSliderSelection(ui); - return true; - } - switch (keyCode) { - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> { - commitSliderEdit(setting, true); - return true; - } - case GLFW.GLFW_KEY_ESCAPE -> { - cancelSliderEdit(setting); - return true; - } - case GLFW.GLFW_KEY_BACKSPACE -> { - if (!deleteSliderSelection(ui) && ui.editCursor > 0) { - ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor - 1) + ui.editBuffer.substring(ui.editCursor); - ui.editCursor--; - } - validateSliderLive(setting, ui); - return true; - } - case GLFW.GLFW_KEY_DELETE -> { - if (!deleteSliderSelection(ui) && ui.editCursor < ui.editBuffer.length()) { - ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor) + ui.editBuffer.substring(ui.editCursor + 1); - } - validateSliderLive(setting, ui); - return true; - } - case GLFW.GLFW_KEY_LEFT -> { - moveSliderCursor(ui, -1, shift); - return true; - } - case GLFW.GLFW_KEY_RIGHT -> { - moveSliderCursor(ui, 1, shift); - return true; - } - case GLFW.GLFW_KEY_HOME -> { - setSliderCursor(ui, 0, shift); - return true; - } - case GLFW.GLFW_KEY_END -> { - setSliderCursor(ui, ui.editBuffer.length(), shift); - return true; - } - } - return true; + return SliderTextInputHandler.keyPressed(setting, keyCode, scanCode, modifiers); } static boolean charTyped(SliderSetting setting, char chr, int modifiers) { - SliderSetting.UiState ui = setting.ui(); - if (!ui.editing) return false; - if (chr == ',' || chr == '.') { - if (sliderInteger(setting) || sliderTextHasDecimal(ui.editBuffer)) { - pulseSliderError(ui); - return true; - } - insertSliderTextRaw(ui, "."); - validateSliderLive(setting, ui); - return true; - } - if (chr == '-') { - if (setting.value().getMin().doubleValue() >= 0.0) { - pulseSliderError(ui); - return true; - } - if (hasSliderSelection(ui)) deleteSliderSelection(ui); - if (ui.editCursor != 0 || ui.editBuffer.indexOf('-') >= 0) { - pulseSliderError(ui); - return true; - } - insertSliderTextRaw(ui, "-"); - validateSliderLive(setting, ui); - return true; - } - if (chr >= '0' && chr <= '9') { - insertSliderTextRaw(ui, String.valueOf(chr)); - validateSliderLive(setting, ui); - return true; - } - pulseSliderError(ui); - return true; + return SliderTextInputHandler.charTyped(setting, chr, modifiers); } - static float getHeight(SliderSetting setting) { - return m(58f, 24f); - } - - private static boolean sliderInteger(SliderSetting setting) { - Object current = setting.value().get(); - return current instanceof Integer || current instanceof Long; - } - - private static void beginSliderEdit(SliderSetting setting) { - SliderSetting.UiState ui = setting.ui(); - ui.editing = true; - ui.dragging = false; - ui.editBuffer = String.valueOf(setting.value().get()).replace(',', '.'); - ui.editCursor = ui.editBuffer.length(); - ui.editSelection.clear(); - ui.errorAnim = 0f; - ui.cursorBlink = 0f; - } - - private static void cancelSliderEdit(SliderSetting setting) { - SliderSetting.UiState ui = setting.ui(); - ui.editing = false; - ui.editBuffer = ""; - ui.editCursor = 0; - ui.editSelection.clear(); - ui.errorAnim = 0f; - } - - private static void commitSliderEdit(SliderSetting setting, boolean save) { - SliderSetting.UiState ui = setting.ui(); - String raw = ui.editBuffer == null ? "" : ui.editBuffer.trim().replace(',', '.'); - if (!sliderTextCanCommit(setting, raw)) { - pulseSliderError(ui); - return; - } - try { - double parsed = Double.parseDouble(raw); - double min = setting.value().getMin().doubleValue(); - double max = setting.value().getMax().doubleValue(); - parsed = Math.max(min, Math.min(max, parsed)); - if (sliderInteger(setting)) parsed = Math.round(parsed); - else parsed = Math.round(parsed * 1000d) / 1000d; - N next = setting.value().castToType(parsed); - setting.value().set(next); - ui.editing = false; - ui.editBuffer = ""; - ui.editCursor = 0; - ui.editSelection.clear(); - if (save && setting.getParent() != null) setting.getParent().saveConfig(); - } catch (Throwable ignored) { - pulseSliderError(ui); - } - } - - private static boolean sliderTextCanCommit(SliderSetting setting, String raw) { - if (raw == null) return false; - String text = raw.trim().replace(',', '.'); - if (text.isEmpty() || text.equals("-") || text.equals(".") || text.equals("-.")) return false; - if (sliderInteger(setting) && text.indexOf('.') >= 0) return false; - try { - double parsed = Double.parseDouble(text); - return Double.isFinite(parsed); - } catch (Throwable ignored) { - return false; - } - } - - private static String sanitizeSliderText(String text, boolean integer) { - if (text == null) return ""; - StringBuilder out = new StringBuilder(); - boolean dot = false; - for (int i = 0; i < text.length(); i++) { - char c = text.charAt(i); - if (c >= '0' && c <= '9') { - out.append(c); - } else if (c == '-' && out.length() == 0) { - out.append('-'); - } else if (!integer && (c == '.' || c == ',') && !dot) { - out.append('.'); - dot = true; - } - } - return out.toString(); - } - - private static boolean sliderTextHasDecimal(String text) { - return text != null && (text.indexOf('.') >= 0 || text.indexOf(',') >= 0); - } - - private static void validateSliderLive(SliderSetting setting, SliderSetting.UiState ui) { - if (ui.editBuffer == null || ui.editBuffer.isEmpty() || ui.editBuffer.equals("-") || ui.editBuffer.equals(".")) - return; - if (!sliderTextCanCommit(setting, ui.editBuffer)) pulseSliderError(ui); - } - - private static void setSliderEditCursorFromMouse(SliderSetting setting, float mx, boolean shift) { - SliderSetting.UiState ui = setting.ui(); - TextRenderer font = modules() ? UnifiedSettingsSkin.fontRegular() : ClickGuiRenderer.getIosevkaRegular(); - int cursor = caretFromText(font, ui.editBuffer == null ? "" : ui.editBuffer, ui.valueTextSize <= 0f ? m(17f, 6.8f) : ui.valueTextSize, ui.valueTextX, mx); - setSliderCursor(ui, cursor, shift); - } - - private static void selectAllSliderText(SliderSetting.UiState ui) { - ui.editSelection.begin(0, 0); - ui.editSelection.updateCaret(0, ui.editBuffer == null ? 0 : ui.editBuffer.length()); - ui.editCursor = ui.editBuffer == null ? 0 : ui.editBuffer.length(); - } - - private static boolean hasSliderSelection(SliderSetting.UiState ui) { - return ui.editSelection.hasRange(); - } - - private static int sliderSelStart(SliderSetting.UiState ui) { - return hasSliderSelection(ui) ? Math.max(0, Math.min(ui.editSelection.start(), ui.editBuffer.length())) : -1; - } - - private static int sliderSelEnd(SliderSetting.UiState ui) { - return hasSliderSelection(ui) ? Math.max(0, Math.min(ui.editSelection.end(), ui.editBuffer.length())) : -1; - } - - private static String selectedOrAllSliderText(SliderSetting.UiState ui) { - if (hasSliderSelection(ui)) return ui.editBuffer.substring(sliderSelStart(ui), sliderSelEnd(ui)); - return ui.editBuffer == null ? "" : ui.editBuffer; - } - - private static boolean deleteSliderSelection(SliderSetting.UiState ui) { - if (!hasSliderSelection(ui)) return false; - int start = sliderSelStart(ui); - int end = sliderSelEnd(ui); - ui.editBuffer = ui.editBuffer.substring(0, start) + ui.editBuffer.substring(end); - ui.editCursor = start; - ui.editSelection.clear(); - return true; - } - - private static void insertSliderText(SliderSetting setting, String text) { - String sanitized = sanitizeSliderText(text, sliderInteger(setting)); - if (sanitized.isEmpty()) { - pulseSliderError(setting.ui()); - return; - } - SliderSetting.UiState ui = setting.ui(); - if (hasSliderSelection(ui)) deleteSliderSelection(ui); - for (int i = 0; i < sanitized.length(); i++) { - char c = sanitized.charAt(i); - if (c == '.' && (sliderInteger(setting) || sliderTextHasDecimal(ui.editBuffer))) { - pulseSliderError(ui); - continue; - } - if (c == '-' && (setting.value().getMin().doubleValue() >= 0.0 || ui.editCursor != 0 || ui.editBuffer.indexOf('-') >= 0)) { - pulseSliderError(ui); - continue; - } - insertSliderTextRaw(ui, String.valueOf(c)); - } - validateSliderLive(setting, ui); - } - - private static void insertSliderTextRaw(SliderSetting.UiState ui, String text) { - if (text == null || text.isEmpty()) return; - deleteSliderSelection(ui); - int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); - ui.editBuffer = ui.editBuffer.substring(0, cursor) + text + ui.editBuffer.substring(cursor); - ui.editCursor = cursor + text.length(); - ui.editSelection.clear(); - } - - private static void moveSliderCursor(SliderSetting.UiState ui, int dir, boolean shift) { - setSliderCursor(ui, Math.max(0, Math.min(ui.editBuffer.length(), ui.editCursor + dir)), shift); - } - - private static void setSliderCursor(SliderSetting.UiState ui, int pos, boolean shift) { - int next = Math.max(0, Math.min(ui.editBuffer == null ? 0 : ui.editBuffer.length(), pos)); - if (shift) { - if (!ui.editSelection.hasRange()) ui.editSelection.begin(0, ui.editCursor); - ui.editSelection.updateCaret(0, next); - } else { - ui.editSelection.clear(); - } - ui.editCursor = next; - ui.cursorBlink = 0f; - } - - private static void pulseSliderError(SliderSetting.UiState ui) { - ui.errorAnim = 1f; - } - - private static void setSliderValueFromMouse(SliderSetting setting, float mx, float trackX, float trackW, double min, double max) { - float percent = UnifiedSettingsSkin.clamp01((mx - trackX) / Math.max(1f, trackW)); - double nextRaw = min + (max - min) * percent; - if (setting.value().get() instanceof Integer || setting.value().get() instanceof Long) - nextRaw = Math.round(nextRaw); - else nextRaw = Math.round(nextRaw * 100d) / 100d; - N current = setting.value().get(); - N next = setting.value().castToType(nextRaw); - if (Double.compare(current.doubleValue(), next.doubleValue()) != 0) { - setting.value().set(next); - ClickGuiSounds.sliderMove(); - } - } - - static void render(ModeSetting setting, float x, float y, float w, float mx, float my) { - UnifiedSettingsSkin.syncTheme(); - ModeSetting.UiState ui = setting.ui(); - ui.baseX = x; - ui.baseY = y; - ui.baseW = w; - layoutMode(setting); - - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float size = m(17f, 6.5f); - ClickGuiRenderer.drawText(font, setting.getDisplayName(), x + m(5f, 5f), y + m(4f, 1.3f), size, UnifiedSettingsSkin.TEXT_PRIMARY, false); - renderOptionContainer(x + m(5f, 5f), y + m(24f, 9.7f), ui.selectW, optionContainerHeightMode(ui), false); - - for (ModeSetting.OptionLayout opt : ui.optionLayouts) { - float ox = x + opt.x(); - float oy = y + opt.y(); - boolean active = opt.getId().equals(setting.selectedId()); - boolean hover = UnifiedSettingsSkin.inside(mx, my, ox - m(2f, 2f), oy - m(1f, 1f), opt.w() + m(4f, 4f), m(16f, 8f)); - float hoverAnim = AnimationUtility.approach(ui.hoverAnims.getOrDefault(opt.getId(), 0f), hover ? 1f : 0f, 0.20f); - ui.hoverAnims.put(opt.getId(), hoverAnim); - int color = active ? UnifiedSettingsSkin.ACCENT : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, hoverAnim * 0.50f); - ClickGuiRenderer.drawText(font, opt.label(), ox, oy, size, color, false); - } - } - - // ------------------------------------------------------------ - // Mode / Group chips - // ------------------------------------------------------------ - - static void mouseClicked(ModeSetting setting, double mx, double my, int button) { - if (button != 0) return; - ModeSetting.UiState ui = setting.ui(); - for (ModeSetting.OptionLayout opt : ui.optionLayouts) { - float ox = ui.baseX + opt.x(); - float oy = ui.baseY + opt.y(); - if (!UnifiedSettingsSkin.inside(mx, my, ox - m(2f, 2f), oy - m(1f, 1f), opt.w() + m(4f, 4f), m(16f, 8f))) - continue; - String before = setting.selectedId(); - setting.selectId(opt.getId()); - if (!opt.getId().equals(before)) ClickGuiSounds.changeMode(); - if (setting.onChange() != null) setting.onChange().run(); - if (setting.getParent() != null) setting.getParent().saveConfig(); - return; - } - } - - static float getHeight(ModeSetting setting) { - layoutMode(setting); - return setting.ui().cachedHeight; - } - - private static void layoutMode(ModeSetting setting) { - ModeSetting.UiState ui = setting.ui(); - float width = ui.baseW > 0f ? ui.baseW : m(160f, 115f); - int count = setting.optionIds().size(); - if (Float.isFinite(ui.lastLayoutW) && Math.abs(ui.lastLayoutW - width) <= 0.5f && ui.layoutOptionCount == count) - return; - ui.optionLayouts.clear(); - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float size = m(17f, 6.5f); - float maxW = Math.max(1f, width - m(10f, 10f)); - float offsetX = 0f, offsetY = 0f, maxRowW = 0f; - for (String id : setting.optionIds()) { - String label = setting.getOptionDisplayName(id); - float tw = UnifiedSettingsSkin.textWidth(font, label, size) + m(2f, 2f); - if (offsetX + tw >= maxW && offsetX > 0f) { - maxRowW = Math.max(maxRowW, offsetX); - offsetX = 0f; - offsetY += m(16f, 8f); - } - ui.optionLayouts.add(new ModeSetting.OptionLayout(id, label, m(7f, 6f) + offsetX, m(27f, 10.7f) + offsetY, tw)); - offsetX += tw; - } - maxRowW = Math.max(maxRowW, offsetX); - ui.selectW = Math.max(0f, maxRowW + m(2f, 2f)); - ui.cachedHeight = m(45f, 22f) + offsetY; - ui.lastLayoutW = width; - ui.layoutOptionCount = count; - } - - static void render(GroupSetting setting, float x, float y, float w, float mx, float my) { - UnifiedSettingsSkin.syncTheme(); - GroupSetting.UiState ui = setting.ui(); - ui.baseX = x; - ui.baseY = y; - ui.baseW = w; - layoutGroup(setting); - - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float size = m(17f, 6.5f); - ClickGuiRenderer.drawText(font, setting.getDisplayName(), x + m(5f, 5f), y + m(4f, 1.7f), size, UnifiedSettingsSkin.TEXT_PRIMARY, false); - renderOptionContainer(x + m(6f, 6f), y + m(24f, 9.7f), Math.max(1f, containerWidth(ui.optionLayouts)), optionContainerHeightGroup(ui), false); - - for (GroupSetting.OptionLayout opt : ui.optionLayouts) { - float ox = x + opt.x(); - float oy = y + opt.y(); - boolean active = setting.value().get(opt.getId()); - boolean hover = UnifiedSettingsSkin.inside(mx, my, ox - m(2f, 2f), oy - m(1f, 1f), opt.w() + m(4f, 4f), m(16f, 8f)); - float hoverAnim = AnimationUtility.approach(ui.hoverAnims.getOrDefault(opt.getId(), 0f), hover ? 1f : 0f, 0.20f); - float activeAnim = AnimationUtility.approach(ui.selectAnims.getOrDefault(opt.getId(), active ? 1f : 0f), active ? 1f : 0f, 0.22f); - ui.hoverAnims.put(opt.getId(), hoverAnim); - ui.selectAnims.put(opt.getId(), activeAnim); - int color = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.72f + hoverAnim * 0.28f); - color = UnifiedSettingsSkin.mix(color, UnifiedSettingsSkin.ACCENT, activeAnim); - ClickGuiRenderer.drawText(font, opt.label(), ox, oy, size, color, false); - } - } - - static void mouseClicked(GroupSetting setting, double mx, double my, int button) { - if (button != 0) return; - GroupSetting.UiState ui = setting.ui(); - for (GroupSetting.OptionLayout opt : ui.optionLayouts) { - float ox = ui.baseX + opt.x(); - float oy = ui.baseY + opt.y(); - if (!UnifiedSettingsSkin.inside(mx, my, ox - m(2f, 2f), oy - m(1f, 1f), opt.w() + m(4f, 4f), m(16f, 8f))) - continue; - setting.value().set(opt.getId(), !setting.value().get(opt.getId())); - ClickGuiSounds.changeMode(); - if (setting.getParent() != null) setting.getParent().saveConfig(); - return; - } - } - - static float getHeight(GroupSetting setting) { - layoutGroup(setting); - return setting.ui().cachedHeight; - } - - private static void layoutGroup(GroupSetting setting) { - GroupSetting.UiState ui = setting.ui(); - float width = ui.baseW > 0f ? ui.baseW : m(160f, 115f); - int count = visibleGroupCount(setting); - if (Float.isFinite(ui.lastLayoutW) && Math.abs(ui.lastLayoutW - width) <= 0.5f && ui.layoutOptionCount == count) - return; - ui.optionLayouts.clear(); - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float size = m(17f, 6.5f); - float maxW = Math.max(1f, width - m(10f, 10f)); - float offsetX = 0f, offsetY = 0f, maxRowW = 0f; - Set alive = new HashSet<>(); - for (String id : setting.value().getAll().keySet()) { - if (!setting.isOptionVisible(id)) continue; - String label = setting.getOptionDisplayName(id); - float tw = UnifiedSettingsSkin.textWidth(font, label, size) + m(4f, 4f); - if (offsetX + tw >= maxW && offsetX > 0f) { - maxRowW = Math.max(maxRowW, offsetX); - offsetX = 0f; - offsetY += m(16f, 8f); - } - ui.optionLayouts.add(new GroupSetting.OptionLayout(id, label, m(8f, 8f) + offsetX, m(27f, 10.7f) + offsetY, tw)); - offsetX += tw; - alive.add(id); - } - maxRowW = Math.max(maxRowW, offsetX); - ui.cachedHeight = m(45f, 22f) + offsetY; - ui.lastLayoutW = width; - ui.layoutOptionCount = count; - ui.hoverAnims.keySet().removeIf(key -> !alive.contains(key)); - ui.selectAnims.keySet().removeIf(key -> !alive.contains(key)); - } - - private static int visibleGroupCount(GroupSetting setting) { - int count = 0; - for (String id : setting.value().getAll().keySet()) if (setting.isOptionVisible(id)) count++; - return count; - } - - private static float containerWidth(java.util.List layouts) { - float max = 0f; - for (GroupSetting.OptionLayout opt : layouts) max = Math.max(max, opt.x() - m(6f, 6f) + opt.w()); - return max + m(0.5f, 0.5f); - } - - private static float optionContainerHeightMode(ModeSetting.UiState ui) { - float max = m(10f, 10f); - for (ModeSetting.OptionLayout opt : ui.optionLayouts) max = Math.max(max, opt.y() - m(19f, 9.7f) + m(16f, 8f)); - return max; - } - - private static float optionContainerHeightGroup(GroupSetting.UiState ui) { - float max = m(10f, 10f); - for (GroupSetting.OptionLayout opt : ui.optionLayouts) max = Math.max(max, opt.y() - m(19f, 9.7f) + m(16f, 8f)); - return max; - } - - private static void renderOptionContainer(float x, float y, float w, float h, boolean active) { - float alpha = active ? 0.22f : 0.12f; - if (active) { - UnifiedSettingsSkin.drawAccent(x, y, Math.max(1f, w), Math.max(m(14f, 10f), h), m(3f, 3f), alpha); - } else { - UnifiedSettingsSkin.drawSurface(x, y, Math.max(1f, w), Math.max(m(14f, 10f), h), m(3f, 3f), 0.34f); - } - } - - static void render(TextSetting setting, float x, float y, float w, float mx, float my) { - UnifiedSettingsSkin.syncTheme(); - TextSetting.UiState ui = setting.ui(); - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float labelSize = m(15.5f, 6.3f); - float fieldSize = m(14f, 6.1f); - float fx = x + m(5f, 5f); - float fy = y + m(23f, 11.5f); - float fw = Math.max(1f, w - m(10f, 10f)); - float fh = m(20f, 13f); - String value = setting.getEditorText(); - ui.fieldX = fx; - ui.fieldY = fy; - ui.fieldW = fw; - ui.fieldH = fh; - - boolean hover = UnifiedSettingsSkin.inside(mx, my, fx, fy, fw, fh); - float dt = AnimationUtility.deltaTime(); - ui.hoverAnim = AnimationUtility.approach(ui.hoverAnim, hover ? 1f : 0f, dt, 13f); - ui.focusAnim = AnimationUtility.approach(ui.focusAnim, ui.editing ? 1f : 0f, dt, 12f); - ui.errorAnim = AnimationUtility.approach(ui.errorAnim, 0f, dt, 7f); - if (ui.editing) ui.cursorBlink += dt * 2.2f; - else ui.cursorBlink = 0f; - - ClickGuiRenderer.drawText(font, UnifiedSettingsSkin.fit(font, setting.getDisplayName(), labelSize, fw), fx, y + m(5f, 2.5f), labelSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); - float fieldAnim = Math.max(ui.hoverAnim * 0.65f, ui.focusAnim); - int bg = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, fieldAnim), 56 + Math.round(fieldAnim * 42f)); - int stroke = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 58), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 155), ui.focusAnim); - stroke = UnifiedSettingsSkin.mix(stroke, 0xFFFF5F66, ui.errorAnim); - if (UnifiedSettingsSkin.SURFACE_GRADIENT_ENABLED) { - UnifiedSettingsSkin.drawSurface(fx, fy, fw, fh, m(5f, 3.5f), 0.55f + fieldAnim * 0.32f); - } else { - ClickGuiRenderer.drawRoundedRect(fx, fy, fw, fh, m(5f, 3.5f), bg); - } - ClickGuiRenderer.drawRoundedRectStroke(fx, fy, fw, fh, m(5f, 3.5f), m(0.7f, 0.45f), stroke); - - String text = ui.editing ? ui.editBuffer : (value == null ? "" : value); - String placeholder = "text..."; - float pad = m(6f, 4f); - float textX = fx + pad; - float textY = fy + (fh - UnifiedSettingsSkin.textHeight(font, fieldSize)) * 0.5f - m(0.2f, 0.15f); - float clipW = Math.max(1f, fw - pad * 2f); - if (ui.editing) ensureTextCursorVisible(ui, font, ui.editBuffer, fieldSize, clipW); - else ui.textScroll = 0f; - float drawX = textX - ui.textScroll; - ui.textX = drawX; - ui.textY = textY; - ui.textSize = fieldSize; - boolean clip = ScissorFunction.pushRaw(textX, fy, clipW, fh); - if (ui.editing) { - renderInlineSelection(font, ui.editBuffer, textSelStart(ui), textSelEnd(ui), drawX, textY, fieldSize, fh, fy); - ClickGuiRenderer.drawText(font, ui.editBuffer, drawX, textY, fieldSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); - if (((int) (ui.cursorBlink * 2f) & 1) == 0) { - int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); - float cx = drawX + UnifiedSettingsSkin.textWidth(font, ui.editBuffer.substring(0, cursor), fieldSize) + m(0.5f, 0.3f); - ClickGuiRenderer.drawRect(cx, fy + m(3f, 2f), m(0.65f, 0.4f), fh - m(6f, 4f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_PRIMARY, 205)); - } - } else { - boolean empty = text.isBlank(); - String draw = empty ? placeholder : UnifiedSettingsSkin.fit(font, text, fieldSize, fw - pad * 2f); - ClickGuiRenderer.drawText(font, draw, textX, textY, fieldSize, empty ? UnifiedSettingsSkin.TEXT_FAINT : UnifiedSettingsSkin.TEXT_PRIMARY, false); - } - if (clip) ScissorFunction.pop(); - } - - // ------------------------------------------------------------ - // Text / TextList - // ------------------------------------------------------------ - - static void mouseClicked(TextSetting setting, double mx, double my, int button) { - if (button != 0) return; - TextSetting.UiState ui = setting.ui(); - if (UnifiedSettingsSkin.inside(mx, my, ui.fieldX, ui.fieldY, ui.fieldW, ui.fieldH)) { - beginTextEdit(setting); - setTextCursorFromMouse(setting, (float) mx, false); - } else if (ui.editing) { - commitTextEdit(setting, true); - } - } - - static void mouseClickedOutside(TextSetting setting, double mx, double my, int button) { - if (button != 0) return; - if (setting.ui().editing) commitTextEdit(setting, true); - } - - static boolean keyPressed(TextSetting setting, int keyCode, int scanCode, int modifiers) { - TextSetting.UiState ui = setting.ui(); - if (!ui.editing) return false; - boolean ctrl = (modifiers & GLFW.GLFW_MOD_CONTROL) != 0; - boolean shift = (modifiers & GLFW.GLFW_MOD_SHIFT) != 0; - if (ctrl && keyCode == GLFW.GLFW_KEY_A) { - selectAllText(ui); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_C) { - ClipboardUtil.copy(selectedOrAllText(ui)); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_V) { - insertTextText(setting, ClipboardUtil.get()); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_X) { - ClipboardUtil.copy(selectedOrAllText(ui)); - deleteTextSelection(ui); - return true; - } - switch (keyCode) { - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> { - commitTextEdit(setting, true); - return true; - } - case GLFW.GLFW_KEY_ESCAPE -> { - cancelTextEdit(setting); - return true; - } - case GLFW.GLFW_KEY_BACKSPACE -> { - if (!deleteTextSelection(ui) && ui.editCursor > 0) { - ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor - 1) + ui.editBuffer.substring(ui.editCursor); - ui.editCursor--; - } - return true; - } - case GLFW.GLFW_KEY_DELETE -> { - if (!deleteTextSelection(ui) && ui.editCursor < ui.editBuffer.length()) - ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor) + ui.editBuffer.substring(ui.editCursor + 1); - return true; - } - case GLFW.GLFW_KEY_LEFT -> { - setTextCursor(ui, ui.editCursor - 1, shift); - return true; - } - case GLFW.GLFW_KEY_RIGHT -> { - setTextCursor(ui, ui.editCursor + 1, shift); - return true; - } - case GLFW.GLFW_KEY_HOME -> { - setTextCursor(ui, 0, shift); - return true; - } - case GLFW.GLFW_KEY_END -> { - setTextCursor(ui, ui.editBuffer.length(), shift); - return true; - } - } - return true; - } - - static boolean charTyped(TextSetting setting, char chr, int modifiers) { - TextSetting.UiState ui = setting.ui(); - if (!ui.editing) return false; - if (chr == '\n' || chr == '\r') return true; - insertTextText(setting, String.valueOf(chr)); - return true; - } - - static float getHeight(TextSetting setting) { - return m(50f, 28f); - } - - private static void beginTextEdit(TextSetting setting) { - TextSetting.UiState ui = setting.ui(); - if (!ui.editing) { - ui.editBuffer = setting.getEditorText(); - ui.editCursor = ui.editBuffer.length(); - ui.editSelection.clear(); - ui.errorAnim = 0f; - } - ui.editing = true; - ui.cursorBlink = 0f; - } - - private static void cancelTextEdit(TextSetting setting) { - TextSetting.UiState ui = setting.ui(); - ui.editing = false; - ui.editBuffer = setting.getEditorText(); - ui.editCursor = ui.editBuffer.length(); - ui.textScroll = 0f; - ui.editSelection.clear(); - ui.errorAnim = 0f; - } - - private static void commitTextEdit(TextSetting setting, boolean save) { - TextSetting.UiState ui = setting.ui(); - setting.applyEditorText(ui.editBuffer == null ? "" : ui.editBuffer); - ui.editing = false; - ui.textScroll = 0f; - ui.editSelection.clear(); - if (!save && setting.getParent() != null) setting.getParent().saveConfig(); - } - - private static void setTextCursorFromMouse(TextSetting setting, float mx, boolean shift) { - TextSetting.UiState ui = setting.ui(); - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - int cursor = caretFromText(font, ui.editBuffer == null ? "" : ui.editBuffer, ui.textSize <= 0f ? m(14f, 6.1f) : ui.textSize, ui.textX, mx); - setTextCursor(ui, cursor, shift); - } - - private static void setTextCursor(TextSetting.UiState ui, int pos, boolean shift) { - int next = Math.max(0, Math.min(ui.editBuffer == null ? 0 : ui.editBuffer.length(), pos)); - if (shift) { - if (!ui.editSelection.hasRange()) ui.editSelection.begin(0, ui.editCursor); - ui.editSelection.updateCaret(0, next); - } else { - ui.editSelection.clear(); - } - ui.editCursor = next; - ui.cursorBlink = 0f; - } - - private static void insertTextText(TextSetting setting, String text) { - TextSetting.UiState ui = setting.ui(); - if (text == null || text.isEmpty()) return; - deleteTextSelection(ui); - String clean = text.replace("\r", "").replace("\n", " "); - int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); - ui.editBuffer = ui.editBuffer.substring(0, cursor) + clean + ui.editBuffer.substring(cursor); - ui.editCursor = cursor + clean.length(); - ui.editSelection.clear(); - } - - private static void ensureTextCursorVisible(TextSetting.UiState ui, TextRenderer font, String text, float size, float visibleW) { - String safe = text == null ? "" : text; - int cursor = Math.max(0, Math.min(ui.editCursor, safe.length())); - float textW = UnifiedSettingsSkin.textWidth(font, safe, size); - float maxScroll = Math.max(0f, textW - visibleW); - float caretX = UnifiedSettingsSkin.textWidth(font, safe.substring(0, cursor), size); - float margin = Math.min(m(8f, 4f), visibleW * 0.35f); - - if (caretX - ui.textScroll > visibleW - margin) { - ui.textScroll = caretX - visibleW + margin; - } else if (caretX - ui.textScroll < margin) { - ui.textScroll = caretX - margin; - } - ui.textScroll = Math.max(0f, Math.min(maxScroll, ui.textScroll)); - } - - private static void selectAllText(TextSetting.UiState ui) { - ui.editSelection.begin(0, 0); - ui.editSelection.updateCaret(0, ui.editBuffer == null ? 0 : ui.editBuffer.length()); - ui.editCursor = ui.editBuffer == null ? 0 : ui.editBuffer.length(); - } - - private static String selectedOrAllText(TextSetting.UiState ui) { - if (hasTextSelection(ui)) return ui.editBuffer.substring(textSelStart(ui), textSelEnd(ui)); - return ui.editBuffer == null ? "" : ui.editBuffer; - } - - private static boolean hasTextSelection(TextSetting.UiState ui) { - return ui.editSelection.hasRange(); - } - - private static int textSelStart(TextSetting.UiState ui) { - return hasTextSelection(ui) ? Math.max(0, Math.min(ui.editSelection.start(), ui.editBuffer.length())) : -1; - } - - private static int textSelEnd(TextSetting.UiState ui) { - return hasTextSelection(ui) ? Math.max(0, Math.min(ui.editSelection.end(), ui.editBuffer.length())) : -1; - } - - private static boolean deleteTextSelection(TextSetting.UiState ui) { - if (!hasTextSelection(ui)) return false; - int start = textSelStart(ui); - int end = textSelEnd(ui); - ui.editBuffer = ui.editBuffer.substring(0, start) + ui.editBuffer.substring(end); - ui.editCursor = start; - ui.editSelection.clear(); - return true; - } - - static void render(TextListSetting setting, float x, float y, float w, float mx, float my) { - UnifiedSettingsSkin.syncTheme(); - TextListSetting.UiState ui = setting.ui(); - ui.lastX = x; - ui.lastY = y; - ui.lastW = w; - - if (isInlineTextList(setting)) { - renderInlineTextList(setting, x, y, w, mx, my); - return; - } - - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float labelSize = m(15.5f, 6.4f); - float small = m(11.5f, 5.7f); - float bh = m(18f, 13f); - float editW = Math.max(m(36f, 28f), UnifiedSettingsSkin.textWidth(font, "Edit", small) + m(12f, 12f)); - float labelX = x + m(5f, 5f); - float labelMax = Math.max(m(50f, 34f), w - editW - m(22f, 16f)); - java.util.List labelLines = ClickGuiRenderer.wrapText(font, setting.getDisplayName(), labelSize, labelMax, 2); - if (labelLines.isEmpty()) labelLines = java.util.List.of(setting.getDisplayName()); - float lineH = UnifiedSettingsSkin.textHeight(font, labelSize); - float lineGap = m(2f, 0.7f); - float textBlockH = labelLines.size() * lineH + Math.max(0, labelLines.size() - 1) * lineGap; - float rowH = Math.max(m(44f, 24f), textBlockH + m(14f, 8f)); - float bx = x + w - m(9f, 9f) - editW; - float by = y + (rowH - bh) * 0.5f; - ui.lastButtonX = bx; - ui.lastButtonY = by; - ui.lastButtonW = editW; - ui.lastButtonH = bh; - boolean hover = UnifiedSettingsSkin.inside(mx, my, bx, by, editW, bh); - ui.moduleHoverAnim = AnimationUtility.approach(ui.moduleHoverAnim, hover ? 1f : 0f, AnimationUtility.deltaTime(), 13f); - float labelY = y + (rowH - textBlockH) * 0.5f; - for (int i = 0; i < labelLines.size(); i++) { - ClickGuiRenderer.drawText(font, labelLines.get(i), labelX, labelY + i * (lineH + lineGap), labelSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); - } - renderChipButton(bx, by, editW, bh, "Edit", ui.moduleHoverAnim, false); - } - - private static void renderInlineTextList(TextListSetting setting, float x, float y, float w, float mx, float my) { - TextListSetting.UiState ui = setting.ui(); - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float labelSize = m(15.5f, 6.3f); - float fieldSize = m(14f, 6.1f); - float rowH = inlineTextListHeight(); - String label = setting.getDisplayName(); - float labelY = y + m(5f, 2.5f); - float fieldY = y + m(23f, 11.5f); - float fieldH = m(20f, 13f); - float fieldX = x + m(5f, 5f); - float fieldW = Math.max(1f, w - m(10f, 10f)); - ui.fieldX = fieldX; - ui.fieldY = fieldY; - ui.fieldW = fieldW; - ui.fieldH = fieldH; - boolean hover = UnifiedSettingsSkin.inside(mx, my, fieldX, fieldY, fieldW, fieldH); - float dt = AnimationUtility.deltaTime(); - ui.fieldHoverAnim = AnimationUtility.approach(ui.fieldHoverAnim, hover ? 1f : 0f, dt, 13f); - ui.fieldFocusAnim = AnimationUtility.approach(ui.fieldFocusAnim, ui.editing ? 1f : 0f, dt, 12f); - ui.fieldErrorAnim = AnimationUtility.approach(ui.fieldErrorAnim, 0f, dt, 7f); - if (ui.editing) ui.cursorBlink += dt * 2.2f; - else ui.cursorBlink = 0f; - - ClickGuiRenderer.drawText(font, UnifiedSettingsSkin.fit(font, label, labelSize, fieldW), fieldX, labelY, labelSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); - float fieldAnim = Math.max(ui.fieldHoverAnim * 0.65f, ui.fieldFocusAnim); - int bg = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, fieldAnim), 56 + Math.round(fieldAnim * 42f)); - int stroke = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 58), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 155), ui.fieldFocusAnim); - stroke = UnifiedSettingsSkin.mix(stroke, 0xFFFF5F66, ui.fieldErrorAnim); - if (UnifiedSettingsSkin.SURFACE_GRADIENT_ENABLED) { - UnifiedSettingsSkin.drawSurface(fieldX, fieldY, fieldW, fieldH, m(5f, 3.5f), 0.55f + fieldAnim * 0.32f); - } else { - ClickGuiRenderer.drawRoundedRect(fieldX, fieldY, fieldW, fieldH, m(5f, 3.5f), bg); - } - ClickGuiRenderer.drawRoundedRectStroke(fieldX, fieldY, fieldW, fieldH, m(5f, 3.5f), m(0.7f, 0.45f), stroke); - - String current = firstTextListEntry(setting); - String text = ui.editing ? ui.editBuffer : current; - if (text == null) text = ""; - String placeholder = "value..."; - float pad = m(6f, 4f); - float textX = fieldX + pad; - float textY = fieldY + (fieldH - UnifiedSettingsSkin.textHeight(font, fieldSize)) * 0.5f - m(0.2f, 0.15f); - boolean clip = ScissorFunction.pushRaw(textX, fieldY, Math.max(1f, fieldW - pad * 2f), fieldH); - if (ui.editing) { - renderInlineSelection(font, ui.editBuffer, textListSelStart(ui), textListSelEnd(ui), textX, textY, fieldSize, fieldH, fieldY); - ClickGuiRenderer.drawText(font, ui.editBuffer, textX, textY, fieldSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); - if (((int) (ui.cursorBlink * 2f) & 1) == 0) { - int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); - float cx = textX + UnifiedSettingsSkin.textWidth(font, ui.editBuffer.substring(0, cursor), fieldSize) + m(0.5f, 0.3f); - ClickGuiRenderer.drawRect(cx, fieldY + m(3f, 2f), m(0.65f, 0.4f), fieldH - m(6f, 4f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_PRIMARY, 205)); - } - } else { - boolean empty = text.isBlank(); - String draw = empty ? placeholder : UnifiedSettingsSkin.fit(font, text, fieldSize, fieldW - pad * 2f); - ClickGuiRenderer.drawText(font, draw, textX, textY, fieldSize, empty ? UnifiedSettingsSkin.TEXT_FAINT : UnifiedSettingsSkin.TEXT_PRIMARY, false); - } - if (clip) ScissorFunction.pop(); - } - - static void mouseClicked(TextListSetting setting, double mx, double my, int button) { - if (button != 0) return; - TextListSetting.UiState ui = setting.ui(); - if (isInlineTextList(setting)) { - if (UnifiedSettingsSkin.inside(mx, my, ui.fieldX, ui.fieldY, ui.fieldW, ui.fieldH)) { - beginTextListEdit(setting); - setTextListCursorFromMouse(setting, (float) mx, false); - } else if (ui.editing) { - commitTextListEdit(setting, true); - } - return; - } - if (!UnifiedSettingsSkin.inside(mx, my, ui.lastButtonX, ui.lastButtonY, ui.lastButtonW, ui.lastButtonH)) return; - if (setting.getPickerMode() == TextListSetting.PickerMode.TEXT) { - ClickGuiRenderer.openTextEditor(setting, setting.getDisplayName(), setting.getEditorText(), ui.lastButtonX, ui.lastButtonY, ui.lastButtonW); - } else { - ClickGuiRenderer.openPicker(setting, setting.getDisplayName(), setting.getPickerMode()); - } - } - - static void mouseClickedOutside(TextListSetting setting, double mx, double my, int button) { - if (button != 0 || !isInlineTextList(setting)) return; - if (setting.ui().editing) commitTextListEdit(setting, true); - } - - static boolean keyPressed(TextListSetting setting, int keyCode, int scanCode, int modifiers) { - if (!isInlineTextList(setting)) return false; - TextListSetting.UiState ui = setting.ui(); - if (!ui.editing) return false; - boolean ctrl = (modifiers & GLFW.GLFW_MOD_CONTROL) != 0; - boolean shift = (modifiers & GLFW.GLFW_MOD_SHIFT) != 0; - if (ctrl && keyCode == GLFW.GLFW_KEY_A) { - selectAllTextList(ui); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_C) { - ClipboardUtil.copy(selectedOrAllTextList(ui)); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_V) { - insertTextListText(setting, ClipboardUtil.get()); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_X) { - ClipboardUtil.copy(selectedOrAllTextList(ui)); - deleteTextListSelection(ui); - return true; - } - switch (keyCode) { - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> { - commitTextListEdit(setting, true); - return true; - } - case GLFW.GLFW_KEY_ESCAPE -> { - cancelTextListEdit(setting); - return true; - } - case GLFW.GLFW_KEY_BACKSPACE -> { - if (!deleteTextListSelection(ui) && ui.editCursor > 0) { - ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor - 1) + ui.editBuffer.substring(ui.editCursor); - ui.editCursor--; - } - return true; - } - case GLFW.GLFW_KEY_DELETE -> { - if (!deleteTextListSelection(ui) && ui.editCursor < ui.editBuffer.length()) - ui.editBuffer = ui.editBuffer.substring(0, ui.editCursor) + ui.editBuffer.substring(ui.editCursor + 1); - return true; - } - case GLFW.GLFW_KEY_LEFT -> { - setTextListCursor(ui, ui.editCursor - 1, shift); - return true; - } - case GLFW.GLFW_KEY_RIGHT -> { - setTextListCursor(ui, ui.editCursor + 1, shift); - return true; - } - case GLFW.GLFW_KEY_HOME -> { - setTextListCursor(ui, 0, shift); - return true; - } - case GLFW.GLFW_KEY_END -> { - setTextListCursor(ui, ui.editBuffer.length(), shift); - return true; - } - } - return true; - } - - static boolean charTyped(TextListSetting setting, char chr, int modifiers) { - if (!isInlineTextList(setting)) return false; - TextListSetting.UiState ui = setting.ui(); - if (!ui.editing) return false; - if (chr == '\n' || chr == '\r') return true; - insertTextListText(setting, String.valueOf(chr)); - return true; - } - - static float getHeight(TextListSetting setting) { - return isInlineTextList(setting) ? inlineTextListHeight() : textListButtonHeight(setting); - } - - private static boolean isInlineTextList(TextListSetting setting) { - return setting.getPickerMode() == TextListSetting.PickerMode.TEXT && setting.isSingleLine(); - } - - private static float inlineTextListHeight() { - return m(50f, 28f); - } - - private static String firstTextListEntry(TextListSetting setting) { - Set set = setting.getValueSet(); - if (set == null || set.isEmpty()) return ""; - return set.iterator().next(); - } - - private static float textListButtonHeight(TextListSetting setting) { - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float width = setting.ui().lastW > 0f ? setting.ui().lastW : m(170f, 115f); - float labelSize = m(15.5f, 6.4f); - float small = m(11.5f, 5.7f); - float editW = Math.max(m(36f, 28f), UnifiedSettingsSkin.textWidth(font, "Edit", small) + m(12f, 12f)); - float labelMax = Math.max(m(50f, 34f), width - editW - m(22f, 16f)); - java.util.List labelLines = ClickGuiRenderer.wrapText(font, setting.getDisplayName(), labelSize, labelMax, 2); - int lines = Math.max(1, labelLines.size()); - float lineH = UnifiedSettingsSkin.textHeight(font, labelSize); - float textBlockH = lines * lineH + Math.max(0, lines - 1) * m(2f, 0.7f); - return Math.max(m(44f, 24f), textBlockH + m(14f, 8f)); - } - - private static void beginTextListEdit(TextListSetting setting) { - TextListSetting.UiState ui = setting.ui(); - if (!ui.editing) { - ui.editBuffer = firstTextListEntry(setting); - ui.editCursor = ui.editBuffer.length(); - ui.editSelection.clear(); - ui.fieldErrorAnim = 0f; - } - ui.editing = true; - ui.cursorBlink = 0f; - } - - private static void cancelTextListEdit(TextListSetting setting) { - TextListSetting.UiState ui = setting.ui(); - ui.editing = false; - ui.editBuffer = firstTextListEntry(setting); - ui.editCursor = ui.editBuffer.length(); - ui.editSelection.clear(); - ui.fieldErrorAnim = 0f; - } - - private static void commitTextListEdit(TextListSetting setting, boolean save) { - TextListSetting.UiState ui = setting.ui(); - String raw = ui.editBuffer == null ? "" : ui.editBuffer.trim(); - java.util.LinkedHashSet next = new java.util.LinkedHashSet<>(); - if (!raw.isEmpty()) next.add(setting.normalizeEntry(raw)); - setting.value().set(next); - ui.editing = false; - ui.editSelection.clear(); - if (save && setting.getParent() != null) setting.getParent().saveConfig(); - } - - private static void setTextListCursorFromMouse(TextListSetting setting, float mx, boolean shift) { - TextListSetting.UiState ui = setting.ui(); - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float size = m(14f, 6.1f); - int cursor = caretFromText(font, ui.editBuffer == null ? "" : ui.editBuffer, size, ui.fieldX + m(6f, 4f), mx); - setTextListCursor(ui, cursor, shift); - } - - private static void setTextListCursor(TextListSetting.UiState ui, int pos, boolean shift) { - int next = Math.max(0, Math.min(ui.editBuffer == null ? 0 : ui.editBuffer.length(), pos)); - if (shift) { - if (!ui.editSelection.hasRange()) ui.editSelection.begin(0, ui.editCursor); - ui.editSelection.updateCaret(0, next); - } else { - ui.editSelection.clear(); - } - ui.editCursor = next; - ui.cursorBlink = 0f; - } - - private static void insertTextListText(TextListSetting setting, String text) { - TextListSetting.UiState ui = setting.ui(); - if (text == null || text.isEmpty()) return; - deleteTextListSelection(ui); - String clean = text.replace("\r", "").replace("\n", " "); - int cursor = Math.max(0, Math.min(ui.editCursor, ui.editBuffer.length())); - ui.editBuffer = ui.editBuffer.substring(0, cursor) + clean + ui.editBuffer.substring(cursor); - ui.editCursor = cursor + clean.length(); - ui.editSelection.clear(); - } - - private static void selectAllTextList(TextListSetting.UiState ui) { - ui.editSelection.begin(0, 0); - ui.editSelection.updateCaret(0, ui.editBuffer == null ? 0 : ui.editBuffer.length()); - ui.editCursor = ui.editBuffer == null ? 0 : ui.editBuffer.length(); - } - - private static String selectedOrAllTextList(TextListSetting.UiState ui) { - if (hasTextListSelection(ui)) return ui.editBuffer.substring(textListSelStart(ui), textListSelEnd(ui)); - return ui.editBuffer == null ? "" : ui.editBuffer; - } - - private static boolean hasTextListSelection(TextListSetting.UiState ui) { - return ui.editSelection.hasRange(); - } - - private static int textListSelStart(TextListSetting.UiState ui) { - return hasTextListSelection(ui) ? Math.max(0, Math.min(ui.editSelection.start(), ui.editBuffer.length())) : -1; - } - - private static int textListSelEnd(TextListSetting.UiState ui) { - return hasTextListSelection(ui) ? Math.max(0, Math.min(ui.editSelection.end(), ui.editBuffer.length())) : -1; - } - - private static boolean deleteTextListSelection(TextListSetting.UiState ui) { - if (!hasTextListSelection(ui)) return false; - int start = textListSelStart(ui); - int end = textListSelEnd(ui); - ui.editBuffer = ui.editBuffer.substring(0, start) + ui.editBuffer.substring(end); - ui.editCursor = start; - ui.editSelection.clear(); - return true; - } - - static void render(KeyBindSetting setting, float x, float y, float w, float mx, float my) { - UnifiedSettingsSkin.syncTheme(); - KeyBindSetting.UiState ui = setting.ui(); - String pending = ClickGuiRenderer.getPendingBindDisplay(); - String display = ui.waiting ? (pending == null ? "..." : pending) : setting.getValue().get(); - renderBindBase(setting.getDisplayName(), display, null, ui.waiting, x, y, w, mx, my, ui); - } - - // ------------------------------------------------------------ - // Key binds - // ------------------------------------------------------------ - - static void mouseClicked(KeyBindSetting setting, double mx, double my, int button) { - if (button != 0) return; - KeyBindSetting.UiState ui = setting.ui(); - if (!UnifiedSettingsSkin.inside(mx, my, ui.lastBx, ui.lastBy, ui.lastBw, ui.lastBh)) return; - ui.waiting = true; - ClickGuiRenderer.beginKeyBind(setting); - } - - static float getHeight(KeyBindSetting setting) { - return bindHeight(setting.ui().lastW, setting.getDisplayName(), setting.getValue().get(), null); - } - - static void render(FunctionBindSetting setting, float x, float y, float w, float mx, float my) { - UnifiedSettingsSkin.syncTheme(); - FunctionBindSetting.UiState ui = setting.ui(); - String pending = ClickGuiRenderer.getPendingBindDisplay(); - String display = ui.waiting ? (pending == null ? "..." : pending) : setting.get(); - String modeText = setting.mode() == BindMode.HOLD ? "Hold" : "Press"; - renderBindBase(setting.getDisplayName(), display, modeText, ui.waiting, x, y, w, mx, my, ui); - } - - static void mouseClicked(FunctionBindSetting setting, double mx, double my, int button) { - if (button != 0) return; - FunctionBindSetting.UiState ui = setting.ui(); - if (!UnifiedSettingsSkin.inside(mx, my, ui.lastBx, ui.lastBy, ui.lastBw, ui.lastBh)) return; - ui.waiting = true; - ClickGuiRenderer.beginKeyBind(setting); - } - - static float getHeight(FunctionBindSetting setting) { - String modeText = setting.mode() == BindMode.HOLD ? "Hold" : "Press"; - return bindHeight(setting.ui().lastW, setting.getDisplayName(), setting.get(), modeText); - } - - private static void renderBindBase(String label, String display, String modeText, boolean waiting, float x, float y, float w, float mx, float my, Object uiObj) { - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float size = m(17f, 7.0f); - float small = m(11.5f, 5.7f); - String displayText = display == null || display.isBlank() ? "NONE" : display; - boolean none = displayText.equalsIgnoreCase("NONE"); - float pad = m(6f, 5f); - float gap = m(4f, 4f); - float chipPad = m(7f, 5f); - float chipH = m(22f, 13.5f); - float minLabelW = m(72f, 38f); - float modeW = modeText == null ? 0f : Math.max(m(36f, 25f), UnifiedSettingsSkin.textWidth(font, modeText, small) + m(10f, 8f)); - float modeBlockW = modeW > 0f ? modeW + gap : 0f; - float rawTextW = UnifiedSettingsSkin.textWidth(font, displayText, size); - float wantedChipW = rawTextW + chipPad * 2f; - - float sameLineMaxChipW = Math.max(m(48f, 30f), w - pad * 3f - modeBlockW - minLabelW); - boolean nextLine = sameLineMaxChipW < m(48f, 30f); - float maxChipW = nextLine - ? Math.max(m(48f, 30f), w - pad * 2f - modeBlockW) - : sameLineMaxChipW; - float chipW = Math.max(m(48f, 30f), Math.min(wantedChipW, maxChipW)); - float labelMax = nextLine ? w - pad * 2f : Math.max(1f, w - pad * 3f - modeBlockW - chipW); - if (!nextLine && labelMax < minLabelW) { - nextLine = true; - maxChipW = Math.max(m(48f, 30f), w - pad * 2f - modeBlockW); - chipW = Math.max(m(48f, 30f), Math.min(wantedChipW, maxChipW)); - labelMax = w - pad * 2f; - } - - float rowH = nextLine ? m(48f, 31f) : m(38f, 22f); - float cardX = x + m(2f, 2f); - float cardY = y + m(3f, 2f); - float cardW = Math.max(1f, w - m(4f, 4f)); - float cardH = Math.max(m(30f, 18f), rowH - m(6f, 4f)); - float cardRadius = m(8f, 5f); - boolean hover = UnifiedSettingsSkin.inside(mx, my, cardX, cardY, cardW, cardH); - float hoverAnim = bindHoverAnim(uiObj, hover); - float waitAnim = bindWaitAnim(uiObj, waiting); - - UnifiedSettingsSkin.drawCard(cardX, cardY, cardW, cardH, cardRadius, 0.38f + hoverAnim * 0.24f + waitAnim * 0.10f); - if (hoverAnim > 0.001f || waitAnim > 0.001f) { - int strokeA = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(hoverAnim * 72f)); - int strokeB = UnifiedSettingsSkin.accentGradientStart(waitAnim * 0.70f); - ClickGuiRenderer.drawRoundedRectStroke(cardX, cardY, cardW, cardH, cardRadius, m(0.65f, 0.42f), UnifiedSettingsSkin.mix(strokeA, strokeB, Math.max(waitAnim, hoverAnim * 0.28f))); - } - - float labelY = y + (nextLine ? m(7f, 4f) : (rowH - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f); - float chipY = nextLine ? y + m(27f, 16f) : y + (rowH - chipH) * 0.5f; - float chipX; - float modeX = 0f; - float modeY = chipY; - if (nextLine) { - chipX = cardX + pad; - if (modeW > 0f) modeX = x + w - pad - modeW; - } else { - chipX = x + w - pad - chipW; - if (modeW > 0f) modeX = chipX - gap - modeW; - } - - int labelColor = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.72f + hoverAnim * 0.18f + waitAnim * 0.10f); - ClickGuiRenderer.drawText(font, UnifiedSettingsSkin.fit(font, label, size, Math.max(1f, labelMax)), cardX + pad, labelY, size, labelColor, false); - if (modeW > 0f) renderSmallModeChip(modeX, modeY, modeW, chipH, modeText, small, hoverAnim, waitAnim); - - float chipInset = m(0.8f, 0.45f); - float chipDrawX = chipX + chipInset; - float chipDrawY = chipY + chipInset; - float chipDrawW = Math.max(1f, chipW - chipInset * 2f); - float chipDrawH = Math.max(1f, chipH - chipInset * 2f); - float chipRadius = Math.max(0f, m(6f, 4f) - chipInset); - if (waiting) { - UnifiedSettingsSkin.drawAccent(chipDrawX, chipDrawY, chipDrawW, chipDrawH, chipRadius, 0.62f + hoverAnim * 0.18f); - ClickGuiRenderer.drawRoundedRectStrokeGradient(chipDrawX, chipDrawY, chipDrawW, chipDrawH, chipRadius, m(0.75f, 0.45f), UnifiedSettingsSkin.accentGradientStart(0.92f), UnifiedSettingsSkin.accentGradientEnd(0.92f), UnifiedSettingsSkin.ACCENT_GRADIENT_ANGLE); - } else { - UnifiedSettingsSkin.drawSurface(chipDrawX, chipDrawY, chipDrawW, chipDrawH, chipRadius, none ? 0.30f + hoverAnim * 0.12f : 0.46f + hoverAnim * 0.16f); - int chipStroke = none - ? UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(34f + hoverAnim * 36f)) - : UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, Math.round(48f + hoverAnim * 54f)); - ClickGuiRenderer.drawRoundedRectStroke(chipDrawX, chipDrawY, chipDrawW, chipDrawH, chipRadius, m(0.65f, 0.42f), chipStroke); - } - - float contentX = chipX + chipPad; - float contentW = Math.max(1f, chipW - chipPad * 2f); - float textX = contentX; - if (rawTextW <= contentW) { - textX = chipX + (chipW - rawTextW) * 0.5f; - } - float textY = chipY + (chipH - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f; - boolean textClip = ScissorFunction.pushRaw(contentX, chipY, contentW, chipH); - int valueColor = waiting - ? 0xFFFFFFFF - : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, none ? 0.20f + hoverAnim * 0.12f : 0.82f + hoverAnim * 0.12f); - if (rawTextW > contentW + 0.5f) { - drawBindMarquee(font, displayText, contentX, textY, rawTextW, contentW, size, valueColor); - } else { - ClickGuiRenderer.drawText(font, displayText, textX, textY, size, valueColor, false); - } - if (textClip) ScissorFunction.pop(); - - if (uiObj instanceof KeyBindSetting.UiState ui) { - ui.lastX = x; - ui.lastY = y; - ui.lastW = w; - ui.lastH = rowH; - ui.lastBx = chipX; - ui.lastBy = chipY; - ui.lastBw = chipW; - ui.lastBh = chipH; - } else if (uiObj instanceof FunctionBindSetting.UiState ui) { - ui.lastX = x; - ui.lastY = y; - ui.lastW = w; - ui.lastH = rowH; - ui.lastBx = chipX; - ui.lastBy = chipY; - ui.lastBw = chipW; - ui.lastBh = chipH; - } - } - - private static float bindHoverAnim(Object uiObj, boolean hover) { - float dt = AnimationUtility.deltaTime(); - if (uiObj instanceof KeyBindSetting.UiState ui) { - ui.hoverAnim = AnimationUtility.approach(ui.hoverAnim, hover ? 1f : 0f, dt, 12f); - return ui.hoverAnim; - } - if (uiObj instanceof FunctionBindSetting.UiState ui) { - ui.hoverAnim = AnimationUtility.approach(ui.hoverAnim, hover ? 1f : 0f, dt, 12f); - return ui.hoverAnim; - } - return hover ? 1f : 0f; - } - - private static float bindWaitAnim(Object uiObj, boolean waiting) { - float dt = AnimationUtility.deltaTime(); - if (uiObj instanceof KeyBindSetting.UiState ui) { - ui.waitAnim = AnimationUtility.approach(ui.waitAnim, waiting ? 1f : 0f, dt, 14f); - return ui.waitAnim; - } - if (uiObj instanceof FunctionBindSetting.UiState ui) { - ui.waitAnim = AnimationUtility.approach(ui.waitAnim, waiting ? 1f : 0f, dt, 14f); - return ui.waitAnim; - } - return waiting ? 1f : 0f; - } - - private static void renderSmallModeChip(float x, float y, float w, float h, String text, float size, float hoverAnim, float waitAnim) { - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float inset = m(0.8f, 0.45f); - float dx = x + inset; - float dy = y + inset; - float dw = Math.max(1f, w - inset * 2f); - float dh = Math.max(1f, h - inset * 2f); - float radius = Math.max(0f, m(6f, 4f) - inset); - int bg = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, 0.45f + hoverAnim * 0.25f + waitAnim * 0.20f); - ClickGuiRenderer.drawRoundedRect(dx, dy, dw, dh, radius, bg); - ClickGuiRenderer.drawRoundedRectStroke(dx, dy, dw, dh, radius, m(0.55f, 0.35f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(34f + hoverAnim * 24f + waitAnim * 30f))); - String fitted = UnifiedSettingsSkin.fit(font, text, size, Math.max(1f, w - m(6f, 6f))); - float tw = UnifiedSettingsSkin.textWidth(font, fitted, size); - int color = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, waitAnim * 0.35f + hoverAnim * 0.15f); - ClickGuiRenderer.drawText(font, fitted, x + (w - tw) * 0.5f, y + (h - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f, size, color, false); - } - - private static float bindHeight(float lastW, String label, String display, String modeText) { - float w = lastW > 0f ? lastW : m(160f, 115f); - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float size = m(17f, 7.0f); - float small = m(11.5f, 5.7f); - float pad = m(6f, 5f); - float gap = m(4f, 4f); - float chipPad = m(7f, 5f); - float minLabelW = m(72f, 38f); - float modeW = modeText == null ? 0f : Math.max(m(36f, 25f), UnifiedSettingsSkin.textWidth(font, modeText, small) + m(10f, 8f)); - float modeBlockW = modeW > 0f ? modeW + gap : 0f; - String displayText = display == null || display.isBlank() ? "NONE" : display; - float wantedChipW = UnifiedSettingsSkin.textWidth(font, displayText, size) + chipPad * 2f; - float sameLineMaxChipW = Math.max(m(48f, 30f), w - pad * 3f - modeBlockW - minLabelW); - boolean nextLine = sameLineMaxChipW < m(48f, 30f); - if (!nextLine) { - float chipW = Math.max(m(48f, 30f), Math.min(wantedChipW, sameLineMaxChipW)); - float labelMax = w - pad * 3f - modeBlockW - chipW; - nextLine = labelMax < minLabelW; - } - return nextLine ? m(48f, 31f) : m(38f, 22f); - } - - static void render(ColorSetting setting, float x, float y, float w, float mx, float my) { - UnifiedSettingsSkin.syncTheme(); - ColorSetting.UiState ui = setting.ui(); - ColorValue value = setting.value(); - boolean hasAlpha = value.supportsAlpha(); - ui.lastX = x; - ui.lastY = y; - ui.lastW = w; - if (!ui.hexFocused && !colorDragActive(ui)) syncColorFromValue(ui, value); - ui.rainbow = value.isRainbow(); - if (ui.rainbow) clearColorFocus(ui); - - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float labelSize = m(18f, 7f); - float previewW = m(34f, 20f); - float previewH = m(16f, 10f); - float previewX = x + w - previewW - m(5f, 5f); - float previewY = y + (colorHeaderH() - previewH) * 0.5f; - String label = UnifiedSettingsSkin.fit(font, setting.getDisplayName(), labelSize, Math.max(1f, previewX - x - m(12f, 12f))); - ClickGuiRenderer.drawText(font, label, x + m(7f, 7f), y + (colorHeaderH() - UnifiedSettingsSkin.textHeight(font, labelSize)) * 0.5f, labelSize, UnifiedSettingsSkin.TEXT_PRIMARY, false); - renderColorPreview(previewX, previewY, previewW, previewH, value.getArgb(), m(3f, 3f)); - ui.previewGlowAnim = AnimationUtility.approach(ui.previewGlowAnim, ui.editing ? 1f : UnifiedSettingsSkin.inside(mx, my, previewX, previewY, previewW, previewH) ? 0.55f : 0f, 0.20f); - - if (ui.expandAnim <= 0.001f) return; - layoutColor(ui, x, y, w, hasAlpha); - updateColorDrag(ui, value, mx, my, hasAlpha); - float reveal = colorReveal(ui); - float slide = ui.editing ? (1f - reveal) * m(8f, 8f) : (1f - reveal) * m(6f, 6f); - float clipY = y + colorHeaderH(); - float clipH = (colorExpandedHeight(ui, hasAlpha) + m(5f, 5f)) * reveal; - boolean clipped = clipH > 0.5f && ScissorFunction.pushRaw(x, clipY, w, clipH); - - float cx = ui.squareX; - float cy = ui.squareY + slide; - float containerX = cx - m(5f, 5f); - float containerY = cy - m(5f, 5f); - float containerW = x + w - m(5f, 5f) - containerX; - float containerH = colorExpandedHeight(ui, hasAlpha); - UnifiedSettingsSkin.drawSurface(containerX, containerY, containerW, containerH, m(6f, 6f), 0.90f); - - renderColorSquare(ui, cy); - renderHueBar(ui, slide); - if (hasAlpha) { - renderChecker(ui.alphaX, ui.alphaY + slide, ui.alphaW, ui.alphaH, m(3f, 3f), m(3f, 3f)); - renderAlphaBar(ui, slide); - } - if (ui.rgbExpandAnim > 0.001f) renderRgbBars(ui, hasAlpha, slide); - renderColorMarkers(ui, hasAlpha, slide); - renderColorPresets(ui, value, mx, my, slide); - renderHexInput(ui, value, mx, my, slide); - renderColorActions(ui, value, mx, my, slide); - if (clipped) ScissorFunction.pop(); + static float getHeight(SliderSetting setting) { + return SliderSettingRenderer.getHeight(setting); } // ------------------------------------------------------------ // Color // ------------------------------------------------------------ + static void render(ColorSetting setting, float x, float y, float w, float mx, float my) { + ColorSettingRenderer.render(setting, x, y, w, mx, my); + } + static void mouseClicked(ColorSetting setting, double mx, double my, int button) { - if (button != 0 && button != 1 && button != 2) return; - ColorSetting.UiState ui = setting.ui(); - ColorValue value = setting.value(); - boolean hasAlpha = value.supportsAlpha(); - float pw = m(34f, 20f); - float ph = m(16f, 10f); - float px = ui.lastX + ui.lastW - pw - m(5f, 5f); - float py = ui.lastY + (colorHeaderH() - ph) * 0.5f; - boolean previewHit = UnifiedSettingsSkin.inside(mx, my, px, py, pw, ph); - boolean headerHit = UnifiedSettingsSkin.inside(mx, my, ui.lastX, ui.lastY, ui.lastW, colorHeaderH()); - if (button == 0 && headerHit) { - ui.editing = !ui.editing; - clearColorFocus(ui); - return; - } - if (!ui.editing) return; - layoutColor(ui, ui.lastX, ui.lastY, ui.lastW, hasAlpha); - if (handleColorPresetClick(setting, value, ui, mx, my, button)) return; - if (button != 0) return; - if (UnifiedSettingsSkin.inside(mx, my, ui.hexX, ui.hexY, ui.hexW, ui.hexH)) { - beginHexEdit(ui, value); - setHexCursorFromMouse(ui, (float) mx, false); - return; - } - if (ui.hexFocused) { - if (!commitHexEdit(setting, value, ui, true)) return; - } - if (UnifiedSettingsSkin.inside(mx, my, ui.sliderX, ui.sliderY, ui.sliderW, ui.sliderH)) { - ui.showRgbBars = !ui.showRgbBars; - clearColorFocus(ui); - return; - } - if (UnifiedSettingsSkin.inside(mx, my, ui.rnbX, ui.rnbY, ui.rnbW, ui.rnbH)) { - value.set(value.isRainbow() ? value.rainbowFallbackHex() : value.toRainbowValue()); - syncColorFromValue(ui, value); - clearColorFocus(ui); - if (setting.getParent() != null) setting.getParent().saveConfig(); - return; - } - if (value.isRainbow()) return; - clearColorFocus(ui); - if (UnifiedSettingsSkin.inside(mx, my, ui.squareX, ui.squareY, ui.squareW, ui.squareH)) { - ui.sbFocused = true; - return; - } - if (UnifiedSettingsSkin.inside(mx, my, ui.hueX - m(2f, 2f), ui.hueY, ui.hueW + m(4f, 4f), ui.hueH)) { - ui.hFocused = true; - return; - } - if (hasAlpha && UnifiedSettingsSkin.inside(mx, my, ui.alphaX - m(2f, 2f), ui.alphaY, ui.alphaW + m(4f, 4f), ui.alphaH)) { - ui.aFocused = true; - return; - } - if (ui.showRgbBars && ui.rgbExpandAnim > 0.20f) { - if (UnifiedSettingsSkin.inside(mx, my, ui.rX, ui.rY, ui.rW, ui.rH)) { - ui.rFocused = true; - return; - } - if (UnifiedSettingsSkin.inside(mx, my, ui.gX, ui.gY, ui.gW, ui.gH)) { - ui.gFocused = true; - return; - } - if (UnifiedSettingsSkin.inside(mx, my, ui.bX, ui.bY, ui.bW, ui.bH)) { - ui.bFocused = true; - return; - } - if (hasAlpha && UnifiedSettingsSkin.inside(mx, my, ui.aX, ui.aY, ui.aW, ui.aH)) ui.aRgbFocused = true; - } + ColorSettingRenderer.mouseClicked(setting, mx, my, button); } static void mouseReleased(ColorSetting setting, double mx, double my, int button) { - if (button != 0) return; - ColorSetting.UiState ui = setting.ui(); - boolean changed = ui.sbFocused || ui.hFocused || ui.aFocused || ui.rFocused || ui.gFocused || ui.bFocused || ui.aRgbFocused; - ui.presetsScrollbarDragging = false; - clearColorFocus(ui); - if (changed && setting.getParent() != null) setting.getParent().saveConfig(); + ColorSettingRenderer.mouseReleased(setting, mx, my, button); } static void mouseClickedOutside(ColorSetting setting, double mx, double my, int button) { - if (button != 0) return; - ColorSetting.UiState ui = setting.ui(); - if (ui.hexFocused) { - commitHexEdit(setting, setting.value(), ui, true); - } - ui.presetsScrollbarDragging = false; - clearColorFocus(ui); + ColorSettingRenderer.mouseClickedOutside(setting, mx, my, button); } static boolean keyPressed(ColorSetting setting, int keyCode, int scanCode, int modifiers) { - ColorSetting.UiState ui = setting.ui(); - if (!ui.hexFocused) return false; - ColorValue value = setting.value(); - boolean ctrl = (modifiers & GLFW.GLFW_MOD_CONTROL) != 0; - if (ctrl && keyCode == GLFW.GLFW_KEY_A) { - selectAllHex(ui); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_C) { - ClipboardUtil.copy("#" + selectedOrAllHex(ui)); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_V) { - insertHexText(ui, ClipboardUtil.get()); - return true; - } - if (ctrl && keyCode == GLFW.GLFW_KEY_X) { - ClipboardUtil.copy("#" + selectedOrAllHex(ui)); - deleteHexSelection(ui); - return true; - } - switch (keyCode) { - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_KP_ENTER -> { - commitHexEdit(setting, value, ui, true); - return true; - } - case GLFW.GLFW_KEY_ESCAPE -> { - cancelHexEdit(ui, value); - return true; - } - case GLFW.GLFW_KEY_BACKSPACE -> { - if (!deleteHexSelection(ui) && ui.hexCursor > 0) { - ui.hexBuffer = ui.hexBuffer.substring(0, ui.hexCursor - 1) + ui.hexBuffer.substring(ui.hexCursor); - ui.hexCursor--; - } - return true; - } - case GLFW.GLFW_KEY_DELETE -> { - if (!deleteHexSelection(ui) && ui.hexCursor < ui.hexBuffer.length()) - ui.hexBuffer = ui.hexBuffer.substring(0, ui.hexCursor) + ui.hexBuffer.substring(ui.hexCursor + 1); - return true; - } - case GLFW.GLFW_KEY_LEFT -> { - moveHexCursor(ui, -1, (modifiers & GLFW.GLFW_MOD_SHIFT) != 0); - return true; - } - case GLFW.GLFW_KEY_RIGHT -> { - moveHexCursor(ui, 1, (modifiers & GLFW.GLFW_MOD_SHIFT) != 0); - return true; - } - case GLFW.GLFW_KEY_HOME -> { - setHexCursor(ui, 0, (modifiers & GLFW.GLFW_MOD_SHIFT) != 0); - return true; - } - case GLFW.GLFW_KEY_END -> { - setHexCursor(ui, ui.hexBuffer.length(), (modifiers & GLFW.GLFW_MOD_SHIFT) != 0); - return true; - } - } - return true; + return ColorSettingHexInput.keyPressed(setting, keyCode, scanCode, modifiers); } static boolean charTyped(ColorSetting setting, char chr, int modifiers) { - ColorSetting.UiState ui = setting.ui(); - if (!ui.hexFocused) return false; - if (isHexChar(chr)) { - insertHexText(ui, String.valueOf(chr)); - } else if (chr == '#') { - // accepted as no-op so pasted/manual values with # don't flash error - } else { - ui.hexErrorAnim = 1f; - } - return true; + return ColorSettingHexInput.charTyped(setting, chr, modifiers); } static boolean mouseScrolled(ColorSetting setting, double mx, double my, double amount) { - ColorSetting.UiState ui = setting.ui(); - if (!ui.editing || !ui.presetsExpanded || ui.presetsMaxScroll <= 0.5f) return false; - float slide = (1f - colorReveal(ui)) * m(8f, 8f); - float listY = ui.presetListY + slide; - if (!UnifiedSettingsSkin.inside(mx, my, ui.presetListX, listY, ui.presetListW, Math.max(1f, ui.presetListH))) - return false; - ui.presetsScroll = AnimationUtility.clamp(ui.presetsScroll - (float) amount * m(16f, 12f), 0f, ui.presetsMaxScroll); - return true; + return ColorSettingRenderer.mouseScrolled(setting, mx, my, amount); } static float getHeight(ColorSetting setting) { - ColorSetting.UiState ui = setting.ui(); - boolean hasAlpha = setting.value().supportsAlpha(); - float dt = AnimationUtility.deltaTime(); - ui.expandAnim = AnimationUtility.approach(ui.expandAnim, ui.editing ? 1f : 0f, dt, ui.editing ? 5.2f : 4.0f); - ui.expandAnim = AnimationUtility.snap(ui.expandAnim, ui.editing ? 1f : 0f, 0.001f); - ui.rgbExpandAnim = AnimationUtility.approach(ui.rgbExpandAnim, ui.showRgbBars ? 1f : 0f, dt, ui.showRgbBars ? 10f : 9f); - ui.rgbExpandAnim = AnimationUtility.snap(ui.rgbExpandAnim, ui.showRgbBars ? 1f : 0f, 0.002f); - ui.presetsExpandAnim = AnimationUtility.approach(ui.presetsExpandAnim, ui.presetsExpanded ? 1f : 0f, dt, ui.presetsExpanded ? 9.5f : 8.5f); - ui.presetsExpandAnim = AnimationUtility.snap(ui.presetsExpandAnim, ui.presetsExpanded ? 1f : 0f, 0.002f); - return colorHeaderH() + colorExpandedHeight(ui, hasAlpha) * colorLayoutAnim(ui); - } - - private static void layoutColor(ColorSetting.UiState ui, float x, float y, float w, boolean hasAlpha) { - int verticalBars = hasAlpha ? 2 : 1; - float sidePad = m(5f, 5f); - float rightInset = m(5f, 4f); - float barW = m(6f, 4f); - float barGap = m(7f, 5f); - ui.squareX = x + sidePad; - ui.squareY = y + colorHeaderH() + m(6f, 5f); - ui.squareH = m(82f, 60f); - ui.squareW = Math.max(m(74f, 44f), w - sidePad * 2f - rightInset - verticalBars * barW - verticalBars * barGap); - ui.hueX = ui.squareX + ui.squareW + barGap; - ui.hueY = ui.squareY; - ui.hueW = barW; - ui.hueH = ui.squareH; - if (hasAlpha) { - ui.alphaX = ui.hueX + barW + barGap; - ui.alphaY = ui.squareY; - ui.alphaW = barW; - ui.alphaH = ui.squareH; - } else { - ui.alphaX = ui.hueX; - ui.alphaY = ui.hueY; - ui.alphaW = 0f; - ui.alphaH = 0f; - } - float rgbReveal = colorRgbReveal(ui); - int rgbBars = hasAlpha ? 4 : 3; - float rgbGapY = m(5f, 5f); - float rgbH = m(9f, 7f); - float valueColumn = m(25f, 18f); - float rgbBlockFull = m(8f, 7f) + rgbBars * rgbH + Math.max(0, rgbBars - 1) * rgbGapY; - float rgbBlockH = rgbBlockFull * rgbReveal; - ui.rX = ui.squareX; - ui.rY = ui.squareY + ui.squareH + m(8f, 7f); - ui.rW = Math.max(1f, ui.squareW - valueColumn); - ui.rH = rgbH; - ui.gX = ui.rX; - ui.gY = ui.rY + rgbH + rgbGapY; - ui.gW = ui.rW; - ui.gH = ui.rH; - ui.bX = ui.rX; - ui.bY = ui.gY + rgbH + rgbGapY; - ui.bW = ui.rW; - ui.bH = ui.rH; - if (hasAlpha) { - ui.aX = ui.rX; - ui.aY = ui.bY + rgbH + rgbGapY; - ui.aW = ui.rW; - ui.aH = ui.rH; - } else { - ui.aX = ui.rX; - ui.aY = ui.bY; - ui.aW = 0f; - ui.aH = 0f; - } - ui.rgbBottom = ui.squareY + ui.squareH + rgbBlockH; - - float actionX = ui.squareX; - float actionW = Math.max(1f, x + w - m(10f, 10f) - actionX); - float gap = m(4f, 4f); - ui.presetX = actionX; - ui.presetY = ui.rgbBottom + m(6f, 4f); - ui.presetW = actionW; - ui.presetH = m(20f, 12f); - - float presetButtonW = m(20f, 14f); - ui.presetToggleW = presetButtonW; - ui.savePresetW = presetButtonW; - ui.deletePresetW = presetButtonW; - ui.presetToggleX = actionX + actionW - presetButtonW * 3f; - ui.savePresetX = ui.presetToggleX + presetButtonW; - ui.deletePresetX = ui.savePresetX + presetButtonW; - ui.savePresetY = ui.presetY; - ui.deletePresetY = ui.presetY; - ui.presetToggleY = ui.presetY; - ui.savePresetH = ui.presetH; - ui.deletePresetH = ui.presetH; - ui.presetToggleH = ui.presetH; - - float listReveal = colorPresetReveal(ui); - float listGap = m(5f, 3f); - float listFullH = m(44f, 31f); - ui.presetListX = actionX; - ui.presetListY = ui.presetY + ui.presetH + listGap; - ui.presetListW = actionW; - ui.presetListH = listFullH * listReveal; - - ui.hexX = actionX; - ui.hexY = ui.presetY + ui.presetH + (listGap + listFullH) * listReveal + m(5f, 3f); - ui.hexW = actionW; - ui.hexH = m(18f, 12f); - float actionY = ui.hexY + ui.hexH + m(5f, 3f); - float bw = Math.max(1f, (actionW - gap) / 2f); - float bh = m(17f, 10.5f); - ui.sliderX = actionX; - ui.sliderY = actionY; - ui.sliderW = bw; - ui.sliderH = bh; - ui.rnbX = ui.sliderX + bw + gap; - ui.rnbY = actionY; - ui.rnbW = bw; - ui.rnbH = bh; - } - - private static void renderColorPreview(float x, float y, float w, float h, int color, float radius) { - ClickGuiRenderer.drawRoundedRect(x, y, w, h, radius, color); - } - - private static void renderColorSquare(ColorSetting.UiState ui, float y) { - int left = hsbToArgb(ui.hue, 0f, 1f, 255); - int right = hsbToArgb(ui.hue, 1f, 1f, 255); - ClickGuiRenderer.drawRoundedRect(ui.squareX, y, ui.squareW, ui.squareH, m(6f, 6f), right); - ClickGuiRenderer.drawGradientRect(ui.squareX, y, ui.squareW, ui.squareH, left, right, right, left); - ClickGuiRenderer.drawGradientRect(ui.squareX, y, ui.squareW, ui.squareH, 0x00FFFFFF, 0x00FFFFFF, 0xFF000000, 0xFF000000); - } - - private static void renderHueBar(ColorSetting.UiState ui, float slide) { - int steps = Math.max(1, Math.round(ui.hueH)); - for (int i = 0; i < steps; i++) { - float h = i / Math.max(1f, ui.hueH - 1f); - ClickGuiRenderer.drawCircle(ui.hueX + ui.hueW * 0.5f, ui.hueY + slide + i, ui.hueW * 0.5f, hsbToArgb(h, 1f, 1f, 255)); - } - } - - private static void renderAlphaBar(ColorSetting.UiState ui, float slide) { - int rgb = hsbToArgb(ui.hue, ui.saturation, ui.brightness, 255); - ClickGuiRenderer.drawGradientRect(ui.alphaX, ui.alphaY + slide, ui.alphaW, ui.alphaH, withAlpha(rgb, 255), withAlpha(rgb, 255), withAlpha(rgb, 0), withAlpha(rgb, 0)); - } - - private static void renderRgbBars(ColorSetting.UiState ui, boolean hasAlpha, float slide) { - float reveal = colorRgbReveal(ui); - if (reveal <= 0.001f) return; - int alpha = hasAlpha ? ui.alpha : 255; - float top = ui.rY + slide - m(2f, 2f); - float bottom = (hasAlpha ? ui.aY + ui.aH : ui.bY + ui.bH) + slide + m(2f, 2f); - boolean clip = ScissorFunction.pushRaw(ui.rX - m(10f, 8f), top, ui.rW + m(40f, 28f), Math.max(1f, (bottom - top) * reveal)); - renderRgbBar("R", ui.rX, ui.rY + slide, ui.rW, ui.rH, (alpha << 24) | (ui.green << 8) | ui.blue, (alpha << 24) | (255 << 16) | (ui.green << 8) | ui.blue, ui.red / 255f, ui.red); - renderRgbBar("G", ui.gX, ui.gY + slide, ui.gW, ui.gH, (alpha << 24) | (ui.red << 16) | ui.blue, (alpha << 24) | (ui.red << 16) | (255 << 8) | ui.blue, ui.green / 255f, ui.green); - renderRgbBar("B", ui.bX, ui.bY + slide, ui.bW, ui.bH, (alpha << 24) | (ui.red << 16) | (ui.green << 8), (alpha << 24) | (ui.red << 16) | (ui.green << 8) | 255, ui.blue / 255f, ui.blue); - if (hasAlpha) { - renderChecker(ui.aX + m(8f, 8f), ui.aY + slide, Math.max(1f, ui.aW - m(16f, 8f)), ui.aH, m(3f, 3f), m(2.5f, 2.5f)); - renderRgbBar("A", ui.aX, ui.aY + slide, ui.aW, ui.aH, (ui.red << 16) | (ui.green << 8) | ui.blue, (255 << 24) | (ui.red << 16) | (ui.green << 8) | ui.blue, ui.alpha / 255f, ui.alpha); - } - if (clip) ScissorFunction.pop(); - } - - private static void renderRgbBar(String label, float x, float y, float w, float h, int c0, int c1, float progress, int value) { - TextRenderer font = UnifiedSettingsSkin.fontLight(); - float size = m(11f, 5.5f); - ClickGuiRenderer.drawText(font, label, x, y - m(0.3f, 0.3f), size, UnifiedSettingsSkin.TEXT_MUTED, false); - float bx = x + m(8f, 8f); - float bw = Math.max(1f, w - m(16f, 8f)); - ClickGuiRenderer.drawGradientRect(bx, y, bw, h, c0, c1, c1, c0); - float px = bx + UnifiedSettingsSkin.clamp01(progress) * bw; - ClickGuiRenderer.drawRoundedRect(px - m(1f, 1f), y - m(1f, 1f), m(2f, 2f), h + m(2f, 2f), m(1f, 1f), UnifiedSettingsSkin.TEXT_PRIMARY); - String valueText = Integer.toString(Math.max(0, Math.min(255, value))); - float valueSize = m(10.5f, 5.2f); - float valueX = x + w + m(3f, 3f); - float valueY = y + (h - UnifiedSettingsSkin.textHeight(font, valueSize)) * 0.5f - m(0.2f, 0.15f); - ClickGuiRenderer.drawText(font, valueText, valueX, valueY, valueSize, UnifiedSettingsSkin.TEXT_MUTED, false); - } - - private static void renderColorPresets(ColorSetting.UiState ui, ColorValue value, float mx, float my, float slide) { - float y = ui.presetY + slide; - float swatch = m(12f, 8f); - float gap = m(4f, 3f); - int labelColor = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_MUTED, 190); - Renderer2D.COLOR.svg("palette", ui.presetX, y + (ui.presetH - swatch) * 0.5f, swatch, swatch, - SvgRenderOptions.overrideColor(labelColor)); - float sx = ui.presetX + swatch + gap; - float available = Math.max(1f, ui.presetToggleX - gap - sx); - java.util.List presets = ColorPresetStore.presets(); - int max = Math.max(1, (int) Math.floor(available / (swatch + gap))); - for (int i = 0; i < Math.min(max, presets.size()); i++) { - float px = sx + i * (swatch + gap); - int color = presets.get(i); - boolean hover = UnifiedSettingsSkin.inside(mx, my, px, y + (ui.presetH - swatch) * 0.5f, swatch, swatch); - renderPresetSwatch(px, y + (ui.presetH - swatch) * 0.5f, swatch, presetDisplayColor(value, color), hover, value.supportsAlpha()); - } - - float dt = AnimationUtility.deltaTime(); - ui.presetsToggleHoverAnim = AnimationUtility.approach(ui.presetsToggleHoverAnim, UnifiedSettingsSkin.inside(mx, my, ui.presetToggleX, y, ui.presetToggleW, ui.presetToggleH) ? 1f : 0f, dt, 14f); - ui.savePresetHoverAnim = AnimationUtility.approach(ui.savePresetHoverAnim, UnifiedSettingsSkin.inside(mx, my, ui.savePresetX, y, ui.savePresetW, ui.savePresetH) ? 1f : 0f, dt, 14f); - ui.deletePresetHoverAnim = AnimationUtility.approach(ui.deletePresetHoverAnim, UnifiedSettingsSkin.inside(mx, my, ui.deletePresetX, y, ui.deletePresetW, ui.deletePresetH) ? 1f : 0f, dt, 14f); - renderColorPresetActionGroup(ui, y); - - float reveal = colorPresetReveal(ui); - if (reveal <= 0.035f) { - ui.presetsMaxScroll = 0f; - ui.presetsContentH = 0f; - ui.presetsViewportH = 0f; - ui.presetListH = 0f; - ui.presetScrollbarX = ui.presetScrollbarY = ui.presetScrollbarW = ui.presetScrollbarH = 0f; - return; - } - - float listY = ui.presetListY + slide; - float listH = ui.presetListH; - if (listH <= m(2f, 1.2f)) { - ui.presetsMaxScroll = 0f; - return; - } - float pad = m(5f, 4f); - UnifiedSettingsSkin.drawSurface(ui.presetListX, listY, ui.presetListW, listH, m(6f, 4f), 0.68f * reveal); - if (UnifiedSettingsSkin.STROKE_GRADIENT_ENABLED) { - UnifiedSettingsSkin.drawStroke(ui.presetListX, listY, ui.presetListW, listH, m(6f, 4f), m(0.65f, 0.42f), 0.32f * reveal); - } else { - ClickGuiRenderer.drawRoundedRectStroke(ui.presetListX, listY, ui.presetListW, listH, m(6f, 4f), m(0.65f, 0.42f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, Math.round(58f * reveal))); - } - - int cols = Math.max(1, (int) Math.floor((ui.presetListW - pad * 2f - m(7f, 5f)) / (swatch + gap))); - int rows = (int) Math.ceil(presets.size() / (double) cols); - float rowH = swatch + gap; - ui.presetsContentH = Math.max(0f, rows * rowH - gap); - ui.presetsViewportH = Math.max(1f, listH - pad * 2f); - ui.presetsMaxScroll = Math.max(0f, ui.presetsContentH - ui.presetsViewportH); - ui.presetsScroll = AnimationUtility.clamp(ui.presetsScroll, 0f, ui.presetsMaxScroll); - - boolean clip = ScissorFunction.pushRaw(ui.presetListX + pad, listY + pad, Math.max(1f, ui.presetListW - pad * 2f - (ui.presetsMaxScroll > 0.5f ? m(5f, 4f) : 0f)), ui.presetsViewportH); - for (int i = 0; i < presets.size(); i++) { - int col = i % cols; - int row = i / cols; - float px = ui.presetListX + pad + col * (swatch + gap); - float py = listY + pad + row * rowH - ui.presetsScroll; - if (py + swatch < listY + pad - 1f || py > listY + pad + ui.presetsViewportH + 1f) continue; - boolean hover = UnifiedSettingsSkin.inside(mx, my, px, py, swatch, swatch); - renderPresetSwatch(px, py, swatch, presetDisplayColor(value, presets.get(i)), hover, value.supportsAlpha()); - } - if (clip) ScissorFunction.pop(); - - if (ui.presetsMaxScroll > 0.5f) { - ui.presetScrollbarW = m(2.5f, 1.7f); - ui.presetScrollbarX = ui.presetListX + ui.presetListW - pad - ui.presetScrollbarW; - ui.presetScrollbarY = listY + pad; - ui.presetScrollbarH = ui.presetsViewportH; - ui.presetScrollbarHandleH = Math.max(m(12f, 8f), ui.presetScrollbarH * (ui.presetScrollbarH / (ui.presetScrollbarH + ui.presetsMaxScroll))); - ui.presetScrollbarHandleY = ui.presetScrollbarY + (ui.presetScrollbarH - ui.presetScrollbarHandleH) * (ui.presetsScroll / Math.max(1f, ui.presetsMaxScroll)); - boolean barHover = UnifiedSettingsSkin.inside(mx, my, ui.presetScrollbarX - m(3f, 2f), ui.presetScrollbarY, ui.presetScrollbarW + m(6f, 4f), ui.presetScrollbarH) || ui.presetsScrollbarDragging; - ui.presetsScrollbarHoverAnim = AnimationUtility.approach(ui.presetsScrollbarHoverAnim, barHover ? 1f : 0f, dt, 14f); - ClickGuiRenderer.drawRoundedRect(ui.presetScrollbarX, ui.presetScrollbarY, ui.presetScrollbarW, ui.presetScrollbarH, ui.presetScrollbarW * 0.5f, UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 42)); - ClickGuiRenderer.drawRoundedRect(ui.presetScrollbarX, ui.presetScrollbarHandleY, ui.presetScrollbarW, ui.presetScrollbarHandleH, ui.presetScrollbarW * 0.5f, UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_MUTED, 95 + Math.round(65f * ui.presetsScrollbarHoverAnim))); - if (ui.presetsScrollbarDragging) { - updatePresetScrollbarDrag(ui, my); - } - } else { - ui.presetScrollbarX = ui.presetScrollbarY = ui.presetScrollbarW = ui.presetScrollbarH = 0f; - } - } - - private static void renderPresetSwatch(float x, float y, float size, int color, boolean hover, boolean alphaContext) { - int stroke = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, hover ? 130 : 78); - if (alphaContext || ((color >>> 24) & 0xFF) < 255) { - renderChecker(x, y, size, size, m(3f, 2f), m(3f, 2f)); - } - ClickGuiRenderer.drawRoundedRect(x, y, size, size, m(3f, 2f), color); - ClickGuiRenderer.drawRoundedRectStroke(x, y, size, size, m(3f, 2f), m(0.7f, 0.45f), stroke); - } - - private static int presetDisplayColor(ColorValue value, int argb) { - return value.supportsAlpha() ? argb : (0xFF000000 | (argb & 0x00FFFFFF)); - } - - private static void renderColorPresetActionGroup(ColorSetting.UiState ui, float y) { - float x = ui.presetToggleX; - float w = ui.presetToggleW + ui.savePresetW + ui.deletePresetW; - float h = ui.presetToggleH; - float hover = Math.max(ui.presetsToggleHoverAnim, Math.max(ui.savePresetHoverAnim, ui.deletePresetHoverAnim)); - float active = ui.presetsExpanded ? 1f : 0f; - if (ui.presetsExpanded) { - UnifiedSettingsSkin.drawAccent(x, y, w, h, m(5f, 4f), 0.32f + hover * 0.16f); - } else { - UnifiedSettingsSkin.drawSurface(x, y, w, h, m(5f, 4f), 0.58f + hover * 0.24f); - } - int stroke = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 62), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 150), active); - stroke = UnifiedSettingsSkin.mix(stroke, UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_MUTED, 120), hover * 0.35f); - if (UnifiedSettingsSkin.STROKE_GRADIENT_ENABLED || ui.presetsExpanded) { - ClickGuiRenderer.drawRoundedRectStrokeGradient(x, y, w, h, m(5f, 4f), m(0.7f, 0.45f), UnifiedSettingsSkin.accentGradientStart(0.58f + active * 0.20f), UnifiedSettingsSkin.accentGradientEnd(0.58f + active * 0.20f), UnifiedSettingsSkin.ACCENT_GRADIENT_ANGLE); - } else { - ClickGuiRenderer.drawRoundedRectStroke(x, y, w, h, m(5f, 4f), m(0.7f, 0.45f), stroke); - } - - float sepW = m(0.7f, 0.45f); - int sep = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 55 + Math.round(35f * hover)); - ClickGuiRenderer.drawRect(ui.savePresetX, y + m(3f, 2f), sepW, h - m(6f, 4f), sep); - ClickGuiRenderer.drawRect(ui.deletePresetX, y + m(3f, 2f), sepW, h - m(6f, 4f), sep); - - renderPresetActionIcon("folder-closed", ui.presetToggleX, y, ui.presetToggleW, h, ui.presetsToggleHoverAnim, ui.presetsExpanded); - renderPresetActionIcon("heart-plus", ui.savePresetX, y, ui.savePresetW, h, ui.savePresetHoverAnim, false); - renderPresetActionIcon("minus", ui.deletePresetX, y, ui.deletePresetW, h, ui.deletePresetHoverAnim, false); - } - - private static void renderPresetActionIcon(String icon, float x, float y, float w, float h, float hoverAnim, boolean active) { - float size = Math.min(m(11f, 7f), Math.max(m(8f, 5f), Math.min(w, h) - m(5f, 3f))); - int color = active - ? UnifiedSettingsSkin.ACCENT - : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.55f + hoverAnim * 0.35f); - Renderer2D.COLOR.svg(icon, x + (w - size) * 0.5f, y + (h - size) * 0.5f, size, size, - SvgRenderOptions.overrideColor(color)); - } - - private static void renderHexInput(ColorSetting.UiState ui, ColorValue value, float mx, float my, float slide) { - float y = ui.hexY + slide; - boolean hover = UnifiedSettingsSkin.inside(mx, my, ui.hexX, y, ui.hexW, ui.hexH); - float dt = AnimationUtility.deltaTime(); - ui.hexAnim = AnimationUtility.approach(ui.hexAnim, ui.hexFocused ? 1f : hover ? 0.55f : 0f, dt, 13f); - ui.hexErrorAnim = AnimationUtility.approach(ui.hexErrorAnim, 0f, dt, 7.5f); - if (ui.hexFocused) ui.hexCursorBlink += dt * 2.2f; - else ui.hexCursorBlink = 0f; - int bg = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, ui.hexAnim), 58 + Math.round(35f * ui.hexAnim)); - int stroke = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 70), 0xFFFF5F66, ui.hexErrorAnim); - ClickGuiRenderer.drawRoundedRect(ui.hexX, y, ui.hexW, ui.hexH, m(5f, 3f), bg); - ClickGuiRenderer.drawRoundedRectStroke(ui.hexX, y, ui.hexW, ui.hexH, m(5f, 3f), m(0.7f, 0.45f), stroke); - int icon = UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_MUTED, 185); - Renderer2D.COLOR.svg("brush", ui.hexX + m(5f, 3f), y + (ui.hexH - m(9f, 6f)) * 0.5f, m(9f, 6f), m(9f, 6f), - SvgRenderOptions.overrideColor(icon)); - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float size = m(11.5f, 5.4f); - String text = ui.hexFocused ? ui.hexBuffer : displayHex(value, value.supportsAlpha()); - String label = "HEX"; - float tx = ui.hexX + m(18f, 12f); - ClickGuiRenderer.drawText(font, label, tx, y + (ui.hexH - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f, size, UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_MUTED, 175), false); - float labelW = UnifiedSettingsSkin.textWidth(font, label, size) + m(5f, 4f); - int textColor = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_PRIMARY, 0xFFFF7777, ui.hexErrorAnim); - float textX = tx + labelW; - float textY = y + (ui.hexH - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f; - float textClipW = Math.max(1f, ui.hexW - (textX - ui.hexX) - m(25f, 17f)); - boolean hexClip = ScissorFunction.pushRaw(textX, y, textClipW, ui.hexH); - String prefix = "#"; - String draw = prefix + text; - if (ui.hexFocused) { - renderInlineSelection(font, text, hexSelStart(ui), hexSelEnd(ui), textX + UnifiedSettingsSkin.textWidth(font, prefix, size), textY, size, ui.hexH, y); - ClickGuiRenderer.drawText(font, draw, textX, textY, size, textColor, false); - if (((int) (ui.hexCursorBlink * 2f) & 1) == 0) { - int cursor = Math.max(0, Math.min(ui.hexCursor, ui.hexBuffer.length())); - float cx = textX + UnifiedSettingsSkin.textWidth(font, prefix + ui.hexBuffer.substring(0, cursor), size) + m(0.5f, 0.3f); - ClickGuiRenderer.drawRect(cx, y + m(3f, 2f), m(0.65f, 0.4f), ui.hexH - m(6f, 4f), UnifiedSettingsSkin.withAlpha(textColor, 190)); - } - } else { - String display = "#" + UnifiedSettingsSkin.fit(font, text, size, textClipW); - ClickGuiRenderer.drawText(font, display, textX, textY, size, textColor, false); - } - if (hexClip) ScissorFunction.pop(); - float preview = ui.hexH - m(5f, 3f); - float px = ui.hexX + ui.hexW - preview - m(3f, 2f); - renderChecker(px, y + (ui.hexH - preview) * 0.5f, preview, preview, m(3f, 2f), m(3f, 2f)); - ClickGuiRenderer.drawRoundedRect(px, y + (ui.hexH - preview) * 0.5f, preview, preview, m(3f, 2f), value.getArgb()); - } - - private static void renderColorMarkers(ColorSetting.UiState ui, boolean hasAlpha, float slide) { - float sbX = ui.squareX + ui.saturation * ui.squareW; - float sbY = ui.squareY + slide + (1f - ui.brightness) * ui.squareH; - ClickGuiRenderer.drawCircle(sbX, sbY, m(4f, 4f), 0xFF000000); - ClickGuiRenderer.drawCircle(sbX, sbY, m(3f, 3f), 0xFFFFFFFF); - float hueY = ui.hueY + slide + ui.hue * Math.max(1f, ui.hueH - 1f); - ClickGuiRenderer.drawCircle(ui.hueX + ui.hueW * 0.5f, hueY, m(4f, 4f), 0xFF000000); - ClickGuiRenderer.drawCircle(ui.hueX + ui.hueW * 0.5f, hueY, m(3f, 3f), 0xFFFFFFFF); - if (hasAlpha) { - float alphaY = ui.alphaY + slide + (1f - ui.alpha / 255f) * Math.max(1f, ui.alphaH - 1f); - ClickGuiRenderer.drawCircle(ui.alphaX + ui.alphaW * 0.5f, alphaY, m(4f, 4f), 0xFF000000); - ClickGuiRenderer.drawCircle(ui.alphaX + ui.alphaW * 0.5f, alphaY, m(3f, 3f), 0xFFFFFFFF); - } - } - - private static void renderColorActions(ColorSetting.UiState ui, ColorValue value, float mx, float my, float slide) { - float dt = AnimationUtility.deltaTime(); - boolean rgbHover = UnifiedSettingsSkin.inside(mx, my, ui.sliderX, ui.sliderY + slide, ui.sliderW, ui.sliderH); - boolean rnbHover = UnifiedSettingsSkin.inside(mx, my, ui.rnbX, ui.rnbY + slide, ui.rnbW, ui.rnbH); - ui.sliderHoverAnim = AnimationUtility.approach(ui.sliderHoverAnim, rgbHover ? 1f : 0f, dt, 14f); - ui.rnbHoverAnim = AnimationUtility.approach(ui.rnbHoverAnim, rnbHover ? 1f : 0f, dt, 14f); - ui.rnbOffAnim = AnimationUtility.approach(ui.rnbOffAnim, value.isRainbow() ? 0f : 1f, dt, 8f); - renderChipButton(ui.sliderX, ui.sliderY + slide, ui.sliderW, ui.sliderH, "RGB", ui.sliderHoverAnim, ui.showRgbBars); - renderRainbowChipButton(ui.rnbX, ui.rnbY + slide, ui.rnbW, ui.rnbH, ui.rnbHoverAnim, value.isRainbow()); - } - - private static boolean handleColorPresetClick(ColorSetting setting, ColorValue value, ColorSetting.UiState ui, double mx, double my, int button) { - if (button != 0 && button != 1) return false; - float slide = (1f - colorReveal(ui)) * m(8f, 8f); - float rowY = ui.presetY + slide; - float swatch = m(12f, 8f); - float gap = m(4f, 3f); - float sx = ui.presetX + swatch + gap; - float available = Math.max(1f, ui.presetToggleX - gap - sx); - java.util.List presets = ColorPresetStore.presets(); - int max = Math.max(1, (int) Math.floor(available / (swatch + gap))); - for (int i = 0; i < Math.min(max, presets.size()); i++) { - float px = sx + i * (swatch + gap); - if (!UnifiedSettingsSkin.inside(mx, my, px, rowY + (ui.presetH - swatch) * 0.5f, swatch, swatch)) continue; - int color = presets.get(i); - if (button == 1) ColorPresetStore.removeExact(color); - else applyColor(value, color); - syncColorFromValue(ui, value); - if (setting.getParent() != null) setting.getParent().saveConfig(); - return true; - } - if (button == 0 && UnifiedSettingsSkin.inside(mx, my, ui.presetToggleX, rowY, ui.presetToggleW, ui.presetToggleH)) { - ui.presetsExpanded = !ui.presetsExpanded; - return true; - } - if (button == 0 && UnifiedSettingsSkin.inside(mx, my, ui.savePresetX, rowY, ui.savePresetW, ui.savePresetH)) { - ColorPresetStore.add(value.getArgb()); - return true; - } - if (button == 0 && UnifiedSettingsSkin.inside(mx, my, ui.deletePresetX, rowY, ui.deletePresetW, ui.deletePresetH)) { - ColorPresetStore.removeClosest(value.getArgb()); - return true; - } - - if (ui.presetsExpanded && ui.presetsExpandAnim > 0.05f) { - float listY = ui.presetListY + slide; - if (button == 0 && ui.presetsMaxScroll > 0.5f && UnifiedSettingsSkin.inside(mx, my, ui.presetScrollbarX - m(3f, 2f), ui.presetScrollbarY, ui.presetScrollbarW + m(6f, 4f), ui.presetScrollbarH)) { - ui.presetsScrollbarDragging = true; - ui.presetsScrollbarDragOffset = (float) my - ui.presetScrollbarHandleY; - updatePresetScrollbarDrag(ui, (float) my); - return true; - } - if (UnifiedSettingsSkin.inside(mx, my, ui.presetListX, listY, ui.presetListW, Math.max(1f, ui.presetListH))) { - float pad = m(5f, 4f); - float innerX = ui.presetListX + pad; - float innerY = listY + pad; - int cols = Math.max(1, (int) Math.floor((ui.presetListW - pad * 2f - m(7f, 5f)) / (swatch + gap))); - float rowH = swatch + gap; - float localX = (float) mx - innerX; - float localY = (float) my - innerY + ui.presetsScroll; - int col = (int) Math.floor(localX / (swatch + gap)); - int row = (int) Math.floor(localY / rowH); - if (col >= 0 && col < cols && row >= 0) { - float cellX = col * (swatch + gap); - float cellY = row * rowH; - if (localX >= cellX && localX <= cellX + swatch && localY >= cellY && localY <= cellY + swatch) { - int index = row * cols + col; - if (index >= 0 && index < presets.size()) { - int color = presets.get(index); - if (button == 1) ColorPresetStore.removeExact(color); - else applyColor(value, color); - syncColorFromValue(ui, value); - if (setting.getParent() != null) setting.getParent().saveConfig(); - return true; - } - } - } - } - } - return false; - } - - private static void beginHexEdit(ColorSetting.UiState ui, ColorValue value) { - ui.hexFocused = true; - ui.hexBuffer = displayHex(value, value.supportsAlpha()); - ui.hexCursor = ui.hexBuffer.length(); - ui.hexSelection.clear(); - ui.hexErrorAnim = 0f; - } - - private static void cancelHexEdit(ColorSetting.UiState ui, ColorValue value) { - ui.hexFocused = false; - ui.hexBuffer = displayHex(value, value.supportsAlpha()); - ui.hexCursor = ui.hexBuffer.length(); - ui.hexSelection.clear(); - ui.hexErrorAnim = 0f; - } - - private static boolean commitHexEdit(ColorSetting setting, ColorValue value, ColorSetting.UiState ui, boolean save) { - Integer parsed = parseHexInput(ui.hexBuffer, value.supportsAlpha()); - if (parsed == null) { - ui.hexErrorAnim = 1f; - return false; - } - applyColor(value, parsed); - syncColorFromValue(ui, value); - ui.hexFocused = false; - ui.hexSelection.clear(); - if (save && setting.getParent() != null) setting.getParent().saveConfig(); - return true; - } - - private static String displayHex(ColorValue value, boolean hasAlpha) { - int argb = value.isRainbow() ? parseFallbackHex(value.rainbowFallbackHex(), value.getArgb()) : value.getArgb(); - if (hasAlpha) - return String.format("%02X%02X%02X%02X", (argb >>> 24) & 0xFF, (argb >>> 16) & 0xFF, (argb >>> 8) & 0xFF, argb & 0xFF); - return String.format("%02X%02X%02X", (argb >>> 16) & 0xFF, (argb >>> 8) & 0xFF, argb & 0xFF); - } - - private static int parseFallbackHex(String hex, int fallback) { - Integer parsed = parseHexInput(hex, true); - return parsed == null ? fallback : parsed; - } - - private static Integer parseHexInput(String raw, boolean hasAlpha) { - if (raw == null) return null; - StringBuilder clean = new StringBuilder(); - String t = raw.trim(); - if (t.startsWith("#")) t = t.substring(1); - if (t.startsWith("0x") || t.startsWith("0X")) t = t.substring(2); - for (int i = 0; i < t.length(); i++) { - char c = t.charAt(i); - if (isHexChar(c)) clean.append(Character.toUpperCase(c)); - } - String s = clean.toString(); - try { - if (s.length() == 3) { - int r = Integer.parseInt(s.substring(0, 1) + s.substring(0, 1), 16); - int g = Integer.parseInt(s.substring(1, 2) + s.substring(1, 2), 16); - int b = Integer.parseInt(s.substring(2, 3) + s.substring(2, 3), 16); - return 0xFF000000 | (r << 16) | (g << 8) | b; - } - if (s.length() == 6) { - return (int) (0xFF000000L | Long.parseUnsignedLong(s, 16)); - } - if (hasAlpha && s.length() == 8) { - return (int) Long.parseUnsignedLong(s, 16); - } - if (!hasAlpha && s.length() == 8) { - return (int) (0xFF000000L | (Long.parseUnsignedLong(s.substring(2), 16) & 0xFFFFFFL)); - } - } catch (Throwable ignored) { - } - return null; - } - - private static boolean isHexChar(char c) { - return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); - } - - private static void insertHexText(ColorSetting.UiState ui, String text) { - if (text == null || text.isEmpty()) return; - deleteHexSelection(ui); - StringBuilder insert = new StringBuilder(); - for (int i = 0; i < text.length(); i++) { - char c = text.charAt(i); - if (isHexChar(c)) insert.append(Character.toUpperCase(c)); - } - if (insert.length() == 0) { - ui.hexErrorAnim = 1f; - return; - } - int maxLen = 8; - int allowed = Math.max(0, maxLen - ui.hexBuffer.length()); - if (insert.length() > allowed) { - insert.setLength(allowed); - ui.hexErrorAnim = 1f; - } - if (insert.length() == 0) return; - ui.hexBuffer = ui.hexBuffer.substring(0, ui.hexCursor) + insert + ui.hexBuffer.substring(ui.hexCursor); - ui.hexCursor += insert.length(); - } - - private static void selectAllHex(ColorSetting.UiState ui) { - ui.hexSelection.begin(0, 0); - ui.hexSelection.updateCaret(0, ui.hexBuffer == null ? 0 : ui.hexBuffer.length()); - ui.hexCursor = ui.hexBuffer == null ? 0 : ui.hexBuffer.length(); - } - - private static String selectedOrAllHex(ColorSetting.UiState ui) { - if (hasHexSelection(ui)) return ui.hexBuffer.substring(hexSelStart(ui), hexSelEnd(ui)); - return ui.hexBuffer == null ? "" : ui.hexBuffer; - } - - private static boolean hasHexSelection(ColorSetting.UiState ui) { - return ui.hexSelection.hasRange(); - } - - private static int hexSelStart(ColorSetting.UiState ui) { - return hasHexSelection(ui) ? Math.max(0, Math.min(ui.hexSelection.start(), ui.hexBuffer.length())) : -1; - } - - private static int hexSelEnd(ColorSetting.UiState ui) { - return hasHexSelection(ui) ? Math.max(0, Math.min(ui.hexSelection.end(), ui.hexBuffer.length())) : -1; - } - - private static boolean deleteHexSelection(ColorSetting.UiState ui) { - if (!hasHexSelection(ui)) return false; - int start = hexSelStart(ui); - int end = hexSelEnd(ui); - ui.hexBuffer = ui.hexBuffer.substring(0, start) + ui.hexBuffer.substring(end); - ui.hexCursor = start; - ui.hexSelection.clear(); - return true; - } - - private static void moveHexCursor(ColorSetting.UiState ui, int dir, boolean shift) { - setHexCursor(ui, Math.max(0, Math.min(ui.hexBuffer.length(), ui.hexCursor + dir)), shift); - } - - private static void setHexCursor(ColorSetting.UiState ui, int pos, boolean shift) { - int next = Math.max(0, Math.min(ui.hexBuffer == null ? 0 : ui.hexBuffer.length(), pos)); - if (shift) { - if (!ui.hexSelection.hasRange()) ui.hexSelection.begin(0, ui.hexCursor); - ui.hexSelection.updateCaret(0, next); - } else { - ui.hexSelection.clear(); - } - ui.hexCursor = next; - ui.hexCursorBlink = 0f; - } - - private static void setHexCursorFromMouse(ColorSetting.UiState ui, float mx, boolean shift) { - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - float size = m(11.5f, 5.4f); - String label = "HEX"; - float tx = ui.hexX + m(18f, 12f); - float labelW = UnifiedSettingsSkin.textWidth(font, label, size) + m(5f, 4f); - float textX = tx + labelW + UnifiedSettingsSkin.textWidth(font, "#", size); - int cursor = caretFromText(font, ui.hexBuffer == null ? "" : ui.hexBuffer, size, textX, mx); - setHexCursor(ui, cursor, shift); - } - - private static void updateColorDrag(ColorSetting.UiState ui, ColorValue value, float mx, float my, boolean hasAlpha) { - if (value.isRainbow()) return; - if (ui.sbFocused) { - ui.saturation = UnifiedSettingsSkin.clamp01((mx - ui.squareX) / Math.max(1f, ui.squareW)); - ui.brightness = UnifiedSettingsSkin.clamp01(1f - ((my - ui.squareY) / Math.max(1f, ui.squareH))); - setColorFromHsb(ui, value); - } - if (ui.hFocused) { - ui.hue = UnifiedSettingsSkin.clamp01((my - ui.hueY) / Math.max(1f, ui.hueH)); - setColorFromHsb(ui, value); - } - if (hasAlpha && ui.aFocused) { - ui.alpha = Math.round(UnifiedSettingsSkin.clamp01(1f - ((my - ui.alphaY) / Math.max(1f, ui.alphaH))) * 255f); - setColorFromHsb(ui, value); - } - if (ui.rFocused) { - ui.red = Math.round(UnifiedSettingsSkin.clamp01((mx - ui.rX) / Math.max(1f, ui.rW)) * 255f); - setColorFromRgb(ui, value); - } - if (ui.gFocused) { - ui.green = Math.round(UnifiedSettingsSkin.clamp01((mx - ui.gX) / Math.max(1f, ui.gW)) * 255f); - setColorFromRgb(ui, value); - } - if (ui.bFocused) { - ui.blue = Math.round(UnifiedSettingsSkin.clamp01((mx - ui.bX) / Math.max(1f, ui.bW)) * 255f); - setColorFromRgb(ui, value); - } - if (hasAlpha && ui.aRgbFocused) { - ui.alpha = Math.round(UnifiedSettingsSkin.clamp01((mx - ui.aX) / Math.max(1f, ui.aW)) * 255f); - setColorFromRgb(ui, value); - } - } - - private static float colorHeaderH() { - return m(48f, 18f); - } - - private static float colorExpandedHeight(ColorSetting.UiState ui, boolean hasAlpha) { - int bars = hasAlpha ? 4 : 3; - float rgbBlock = (m(8f, 7f) + bars * m(9f, 7f) + (bars - 1) * m(5f, 5f)) * colorRgbReveal(ui); - float presets = m(20f, 12f); - float presetsExpanded = (m(5f, 3f) + m(44f, 31f)) * colorPresetReveal(ui); - float hex = m(18f, 12f); - float actions = m(17f, 10.5f); - return Math.max(0f, colorHeaderH() + m(6f, 5f) + m(82f, 60f) + rgbBlock + m(6f, 4f) + presets + presetsExpanded + m(5f, 3f) + hex + m(5f, 3f) + actions + m(14f, 8f) - colorHeaderH()); - } - - private static float colorRgbReveal(ColorSetting.UiState ui) { - return AnimationUtility.easeInOutCubic(UnifiedSettingsSkin.clamp01(ui.rgbExpandAnim)); - } - - private static float colorPresetReveal(ColorSetting.UiState ui) { - return AnimationUtility.easeInOutCubic(UnifiedSettingsSkin.clamp01(ui.presetsExpandAnim)); - } - - private static void updatePresetScrollbarDrag(ColorSetting.UiState ui, float my) { - if (ui.presetsMaxScroll <= 0.5f) return; - float track = Math.max(1f, ui.presetScrollbarH - ui.presetScrollbarHandleH); - float handleY = AnimationUtility.clamp(my - ui.presetsScrollbarDragOffset, ui.presetScrollbarY, ui.presetScrollbarY + track); - float t = (handleY - ui.presetScrollbarY) / track; - ui.presetsScroll = AnimationUtility.clamp(t * ui.presetsMaxScroll, 0f, ui.presetsMaxScroll); - } - - private static float colorLayoutAnim(ColorSetting.UiState ui) { - float t = UnifiedSettingsSkin.clamp01(ui.expandAnim); - return ui.editing ? AnimationUtility.clamp(AnimationUtility.easeOutBack(t, 0.42f), 0f, 1.02f) : 1f - AnimationUtility.easeInCubic(1f - t); - } - - private static float colorReveal(ColorSetting.UiState ui) { - float t = UnifiedSettingsSkin.clamp01(ui.expandAnim); - if (ui.editing) return AnimationUtility.easeInOutCubic(UnifiedSettingsSkin.clamp01((t - 0.08f) / 0.92f)); - return 1f - AnimationUtility.easeInCubic(1f - t); - } - - private static void syncColorFromValue(ColorSetting.UiState ui, ColorValue value) { - int argb = value.getArgb(); - ui.lastArgb = argb; - ui.red = (argb >>> 16) & 0xFF; - ui.green = (argb >>> 8) & 0xFF; - ui.blue = argb & 0xFF; - ui.alpha = (argb >>> 24) & 0xFF; - float[] hsb = Color.RGBtoHSB(ui.red, ui.green, ui.blue, null); - if (hsb[1] > 0.0001f && hsb[2] > 0.0001f) ui.hue = hsb[0]; - ui.saturation = hsb[1]; - ui.brightness = hsb[2]; - } - - private static void setColorFromHsb(ColorSetting.UiState ui, ColorValue value) { - int rgb = Color.HSBtoRGB(ui.hue, ui.saturation, ui.brightness) & 0x00FFFFFF; - ui.red = (rgb >>> 16) & 0xFF; - ui.green = (rgb >>> 8) & 0xFF; - ui.blue = rgb & 0xFF; - applyColor(value, ((value.supportsAlpha() ? ui.alpha : 255) << 24) | rgb); - } - - private static void setColorFromRgb(ColorSetting.UiState ui, ColorValue value) { - float[] hsb = Color.RGBtoHSB(ui.red, ui.green, ui.blue, null); - if (hsb[1] > 0.0001f && hsb[2] > 0.0001f) ui.hue = hsb[0]; - ui.saturation = hsb[1]; - ui.brightness = hsb[2]; - applyColor(value, ((value.supportsAlpha() ? ui.alpha : 255) << 24) | (ui.red << 16) | (ui.green << 8) | ui.blue); - } - - private static void applyColor(ColorValue value, int argb) { - if (value.supportsAlpha()) - value.set(String.format("#%02X%02X%02X%02X", (argb >>> 24) & 0xFF, (argb >>> 16) & 0xFF, (argb >>> 8) & 0xFF, argb & 0xFF)); - else value.set(String.format("#%02X%02X%02X", (argb >>> 16) & 0xFF, (argb >>> 8) & 0xFF, argb & 0xFF)); - } - - private static void pasteColor(ColorSetting setting, ColorValue value) { - applyColor(value, ClickGuiRenderer.getColorClipboard()); - syncColorFromValue(setting.ui(), value); - if (setting.getParent() != null) setting.getParent().saveConfig(); - } - - private static boolean colorDragActive(ColorSetting.UiState ui) { - return ui.sbFocused || ui.hFocused || ui.aFocused || ui.rFocused || ui.gFocused || ui.bFocused || ui.aRgbFocused; - } - - private static void clearColorFocus(ColorSetting.UiState ui) { - ui.sbFocused = false; - ui.hFocused = false; - ui.aFocused = false; - ui.rFocused = false; - ui.gFocused = false; - ui.bFocused = false; - ui.aRgbFocused = false; - } - - private static int hsbToArgb(float h, float s, float b, int a) { - return (Math.max(0, Math.min(255, a)) << 24) | (Color.HSBtoRGB(h, s, b) & 0x00FFFFFF); - } - - private static int withAlpha(int argb, int a) { - return (argb & 0x00FFFFFF) | ((Math.max(0, Math.min(255, a)) & 0xFF) << 24); - } - - private static int caretFromText(TextRenderer font, String text, float size, float textX, float mx) { - if (text == null || text.isEmpty()) return 0; - float rel = mx - textX; - if (rel <= 0f) return 0; - for (int i = 1; i <= text.length(); i++) { - float prev = UnifiedSettingsSkin.textWidth(font, text.substring(0, i - 1), size); - float cur = UnifiedSettingsSkin.textWidth(font, text.substring(0, i), size); - if (rel < (prev + cur) * 0.5f) return i - 1; - } - return text.length(); + return ColorSettingRenderer.getHeight(setting); } // ------------------------------------------------------------ - // Common helpers + // Text // ------------------------------------------------------------ - private static void renderInlineSelection(TextRenderer font, String text, int start, int end, float textX, float textY, float size, float fieldH, float fieldY) { - if (text == null || start < 0 || end < 0 || start == end) return; - int a = Math.max(0, Math.min(start, text.length())); - int b = Math.max(0, Math.min(end, text.length())); - if (a == b) return; - if (a > b) { - int t = a; - a = b; - b = t; - } - float x0 = textX + UnifiedSettingsSkin.textWidth(font, text.substring(0, a), size); - float x1 = textX + UnifiedSettingsSkin.textWidth(font, text.substring(0, b), size); - float h = Math.max(m(8f, 5f), UnifiedSettingsSkin.textHeight(font, size) + m(3f, 2f)); - float y = fieldY > 0f ? fieldY + (fieldH - h) * 0.5f : textY - m(1.5f, 0.7f); - ClickGuiRenderer.drawRoundedRect(x0, y, Math.max(m(1f, 0.7f), x1 - x0), h, m(2f, 1.5f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 92)); + static void render(TextSetting setting, float x, float y, float w, float mx, float my) { + TextSettingRenderer.render(setting, x, y, w, mx, my); } - private static void renderRainbowChipButton(float x, float y, float w, float h, float hoverAnim, boolean active) { - float t = (System.nanoTime() % 3_000_000_000L) / 3_000_000_000f; - int c0 = hsbToArgb((t + 0.00f) % 1f, 0.80f, 1.0f, active ? 205 : 92 + Math.round(hoverAnim * 34f)); - int c1 = hsbToArgb((t + 0.18f) % 1f, 0.80f, 1.0f, active ? 215 : 96 + Math.round(hoverAnim * 38f)); - int c2 = hsbToArgb((t + 0.36f) % 1f, 0.80f, 1.0f, active ? 215 : 96 + Math.round(hoverAnim * 38f)); - int c3 = hsbToArgb((t + 0.54f) % 1f, 0.80f, 1.0f, active ? 205 : 92 + Math.round(hoverAnim * 34f)); - if (active) { - ClickGuiRenderer.drawRoundedRectGradient(x, y, w, h, m(4f, 4f), c0, c2, 25f + t * 360f); - ClickGuiRenderer.drawRoundedRect(x, y, w, h, m(4f, 4f), UnifiedSettingsSkin.withAlpha(0xFF000000, 18 - Math.round(hoverAnim * 6f))); - ClickGuiRenderer.drawRoundedRectStrokeGradient(x, y, w, h, m(4f, 4f), m(0.8f, 0.45f), c0, c2, 25f + t * 360f); - } else { - int bg = UnifiedSettingsSkin.mix(UnifiedSettingsSkin.SURFACE_SOFT, UnifiedSettingsSkin.SURFACE_HOVER, hoverAnim * 0.75f); - ClickGuiRenderer.drawRoundedRect(x, y, w, h, m(4f, 4f), UnifiedSettingsSkin.withAlpha(bg, 70 + Math.round(hoverAnim * 42f))); - if (hoverAnim > 0.02f) { - ClickGuiRenderer.drawRoundedRectGradient(x, y, w, h, m(4f, 4f), UnifiedSettingsSkin.withAlpha(c0, Math.round(52f * hoverAnim)), UnifiedSettingsSkin.withAlpha(c2, Math.round(52f * hoverAnim)), 25f + t * 360f); - ClickGuiRenderer.drawRoundedRectStrokeGradient(x, y, w, h, m(4f, 4f), m(0.7f, 0.45f), UnifiedSettingsSkin.withAlpha(c0, 80 + Math.round(96f * hoverAnim)), UnifiedSettingsSkin.withAlpha(c2, 80 + Math.round(96f * hoverAnim)), 25f + t * 360f); - } else { - ClickGuiRenderer.drawRoundedRectStroke(x, y, w, h, m(4f, 4f), m(0.7f, 0.45f), UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 72)); - } - } - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - String label = "RNB"; - float size = Math.min(m(13f, 6f), Math.max(m(10f, 4.8f), (w - m(4f, 4f)) / Math.max(1f, label.length()) * 1.45f)); - float tw = UnifiedSettingsSkin.textWidth(font, label, size); - float ty = y + (h - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f - m(0.2f, 0.2f); - int labelColor = active ? 0xFFFFFFFF : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, 0xFFFFFFFF, hoverAnim * 0.62f); - ClickGuiRenderer.drawText(font, label, x + Math.max(m(2f, 2f), (w - tw) * 0.5f), ty, size, labelColor, false); + static void mouseClicked(TextSetting setting, double mx, double my, int button) { + TextSettingRenderer.mouseClicked(setting, mx, my, button); } - private static void renderChipButton(float x, float y, float w, float h, String label, float hoverAnim, boolean active) { - TextRenderer font = UnifiedSettingsSkin.fontMedium(); - int bg = active ? UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 70) : UnifiedSettingsSkin.SURFACE_SOFT; - bg = UnifiedSettingsSkin.mix(bg, UnifiedSettingsSkin.SURFACE_HOVER, hoverAnim * 0.72f); - ClickGuiRenderer.drawRoundedRect(x, y, w, h, m(4f, 4f), bg); - int stroke = active - ? UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.ACCENT, 135 + Math.round(hoverAnim * 55f)) - : UnifiedSettingsSkin.withAlpha(UnifiedSettingsSkin.TEXT_FAINT, 58 + Math.round(hoverAnim * 65f)); - ClickGuiRenderer.drawRoundedRectStroke(x, y, w, h, m(4f, 4f), m(0.7f, 0.45f), stroke); - float size = Math.min(m(13f, 6f), Math.max(m(10f, 4.8f), (w - m(4f, 4f)) / Math.max(1f, label.length()) * 1.45f)); - float tw = UnifiedSettingsSkin.textWidth(font, label, size); - float ty = y + (h - UnifiedSettingsSkin.textHeight(font, size)) * 0.5f - m(0.2f, 0.2f); - int color = active ? UnifiedSettingsSkin.ACCENT : UnifiedSettingsSkin.mix(UnifiedSettingsSkin.TEXT_MUTED, UnifiedSettingsSkin.TEXT_PRIMARY, 0.68f + hoverAnim * 0.32f); - ClickGuiRenderer.drawText(font, label, x + Math.max(m(2f, 2f), (w - tw) * 0.5f), ty, size, color, false); + static void mouseClickedOutside(TextSetting setting, double mx, double my, int button) { + TextSettingRenderer.mouseClickedOutside(setting, mx, my, button); } - private static void renderChecker(float x, float y, float w, float h, float cell, float radius) { - int light = 0xFFE7E7E7; - int dark = 0xFF777777; - ClickGuiRenderer.drawRoundedRect(x, y, w, h, radius, light); - float safeCell = Math.max(1f, cell); - int cols = Math.max(1, (int) Math.ceil(w / safeCell)); - int rows = Math.max(1, (int) Math.ceil(h / safeCell)); - boolean clipped = ScissorFunction.pushRaw(x, y, w, h); - for (int row = 0; row < rows; row++) { - for (int col = 0; col < cols; col++) { - if (((row + col) & 1) == 0) continue; - ClickGuiRenderer.drawRect(x + col * safeCell, y + row * safeCell, safeCell, safeCell, dark); - } - } - if (clipped) ScissorFunction.pop(); + static boolean keyPressed(TextSetting setting, int keyCode, int scanCode, int modifiers) { + return TextSettingTextInputHandler.keyPressed(setting, keyCode, scanCode, modifiers); } - private static float calculateTextBoxHeight(TextRenderer font, String text, float size, float maxW) { - String safe = text == null || text.isEmpty() ? " " : text; - int lines = Math.max(1, ClickGuiRenderer.wrapText(font, safe, size, maxW, 6).size()); - return m(5f, 5f) + lines * UnifiedSettingsSkin.textHeight(font, size) + Math.max(0, lines - 1) * m(1f, 1f); + static boolean charTyped(TextSetting setting, char chr, int modifiers) { + return TextSettingTextInputHandler.charTyped(setting, chr, modifiers); } - private static void drawWrappedText(TextRenderer font, String text, float x, float y, float size, float maxW, int color, int maxLines) { - java.util.List lines = ClickGuiRenderer.wrapText(font, text == null ? "" : text, size, maxW, maxLines); - float cy = y; - for (String line : lines) { - ClickGuiRenderer.drawText(font, line, x, cy, size, color, false); - cy += UnifiedSettingsSkin.textHeight(font, size) + m(1f, 1f); - } + static float getHeight(TextSetting setting) { + return TextSettingRenderer.getHeight(setting); } - private static void drawBindMarquee( - TextRenderer font, - String text, - float x, - float y, - float fullWidth, - float viewWidth, - float fontSize, - int color - ) { - final float speed = 22.0f; - final float gap = 14.0f; - final float pauseSec = 0.8f; + // ------------------------------------------------------------ + // TextList + // ------------------------------------------------------------ - if (text == null || text.isEmpty()) return; - if (speed <= 0.0f) { - ClickGuiRenderer.drawText(font, text, x, y, fontSize, color, false); - return; - } - - float cycleDistance = fullWidth + gap; - float cycleTime = pauseSec + cycleDistance / speed; - if (cycleTime <= 0.0f) { - ClickGuiRenderer.drawText(font, text, x, y, fontSize, color, false); - return; - } - - float now = net.minecraft.util.Util.getMillis() / 1000.0f; - float t = now % cycleTime; - - float offset = 0.0f; - if (t > pauseSec) { - offset = -(t - pauseSec) * speed; - } - - ClickGuiRenderer.drawText(font, text, x + offset, y, fontSize, color, false); - - if (cycleDistance > viewWidth * 0.5f) { - ClickGuiRenderer.drawText(font, text, x + offset + cycleDistance, y, fontSize, color, false); - } + static void render(TextListSetting setting, float x, float y, float w, float mx, float my) { + TextListSettingRenderer.render(setting, x, y, w, mx, my); } - private record LayoutBoolean(String[] lines, float lineH, float labelY, float controlY, float rowH) { + static void mouseClicked(TextListSetting setting, double mx, double my, int button) { + TextListSettingRenderer.mouseClicked(setting, mx, my, button); + } + + static void mouseClickedOutside(TextListSetting setting, double mx, double my, int button) { + TextListSettingRenderer.mouseClickedOutside(setting, mx, my, button); + } + + static boolean keyPressed(TextListSetting setting, int keyCode, int scanCode, int modifiers) { + return TextListTextEditHandler.keyPressed(setting, keyCode, scanCode, modifiers); + } + + static boolean charTyped(TextListSetting setting, char chr, int modifiers) { + return TextListTextEditHandler.charTyped(setting, chr, modifiers); + } + + static float getHeight(TextListSetting setting) { + return TextListSettingRenderer.getHeight(setting); + } + + // ------------------------------------------------------------ + // Group / Mode chips + // ------------------------------------------------------------ + + static void render(GroupSetting setting, float x, float y, float w, float mx, float my) { + GroupSettingRenderer.render(setting, x, y, w, mx, my); + } + + static void mouseClicked(GroupSetting setting, double mx, double my, int button) { + GroupSettingRenderer.mouseClicked(setting, mx, my, button); + } + + static float getHeight(GroupSetting setting) { + return GroupSettingRenderer.getHeight(setting); + } + + static void render(ModeSetting setting, float x, float y, float w, float mx, float my) { + ModeSettingRenderer.render(setting, x, y, w, mx, my); + } + + static void mouseClicked(ModeSetting setting, double mx, double my, int button) { + ModeSettingRenderer.mouseClicked(setting, mx, my, button); + } + + static float getHeight(ModeSetting setting) { + return ModeSettingRenderer.getHeight(setting); + } + + // ------------------------------------------------------------ + // Key binds + // ------------------------------------------------------------ + + static void render(KeyBindSetting setting, float x, float y, float w, float mx, float my) { + KeyBindSettingRenderer.render(setting, x, y, w, mx, my); + } + + static void mouseClicked(KeyBindSetting setting, double mx, double my, int button) { + KeyBindSettingRenderer.mouseClicked(setting, mx, my, button); + } + + static float getHeight(KeyBindSetting setting) { + return KeyBindSettingRenderer.getHeight(setting); + } + + static void render(FunctionBindSetting setting, float x, float y, float w, float mx, float my) { + FunctionBindSettingRenderer.render(setting, x, y, w, mx, my); + } + + static void mouseClicked(FunctionBindSetting setting, double mx, double my, int button) { + FunctionBindSettingRenderer.mouseClicked(setting, mx, my, button); + } + + static float getHeight(FunctionBindSetting setting) { + return FunctionBindSettingRenderer.getHeight(setting); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/UnifiedSettingsSkin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/UnifiedSettingsSkin.java index 7c46b90..5d0c895 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/UnifiedSettingsSkin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/settings/UnifiedSettingsSkin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiHintOverlay.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiHintOverlay.java index 91e578b..2a26712 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiHintOverlay.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiHintOverlay.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiI18n.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiI18n.java index 9952eca..814534f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiI18n.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiI18n.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiMath.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiMath.java index 77450d1..8582691 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiMath.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiMath.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiRichTextRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiRichTextRenderer.java index b532eae..7ed57dd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiRichTextRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/clickgui/util/ClickGuiRichTextRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/AbstractHudElement.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/AbstractHudElement.java index eb875c8..d964b24 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/AbstractHudElement.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/AbstractHudElement.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/BaseHudElement.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/BaseHudElement.java index 471884e..4a662f7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/BaseHudElement.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/BaseHudElement.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/CooldownRender.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/CooldownRender.java index 5e66d71..9f4107d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/CooldownRender.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/CooldownRender.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudAnchorX.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudAnchorX.java index b77dc59..65200da 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudAnchorX.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudAnchorX.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudAnchorY.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudAnchorY.java index 35b8de1..c5193bb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudAnchorY.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudAnchorY.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementAutoLoader.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementAutoLoader.java index e266807..00bdcb5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementAutoLoader.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementAutoLoader.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementInfo.java index 7207db2..e4850e8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementInfo.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementRegister.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementRegister.java index f55b87c..1b4c640 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementRegister.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElementRegister.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElements.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElements.java index bf5dd56..1f16175 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElements.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudElements.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudGlobalConfig.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudGlobalConfig.java index 1dcbe7f..abbc091 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudGlobalConfig.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudGlobalConfig.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudRenderSpace.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudRenderSpace.java index 41de97b..9fce72c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudRenderSpace.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudRenderSpace.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudRenderUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudRenderUtil.java index d27f34d..b5a5a1c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudRenderUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudRenderUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudTextEffects.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudTextEffects.java index b039c74..8f01af8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudTextEffects.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/HudTextEffects.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/WidgetAnchorSide.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/WidgetAnchorSide.java index a13ae75..d3791bb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/WidgetAnchorSide.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/WidgetAnchorSide.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableHudElement.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableHudElement.java index da8e2f0..aa044f9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableHudElement.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableHudElement.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableHudElementRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableHudElementRegistry.java index b4c8afe..19e6c12 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableHudElementRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableHudElementRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,7 +25,7 @@ import dev.loki.lovisual.render.engine.profiler.RenderProfiler2D; import dev.loki.lovisual.render.engine.text.FontInfo; import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import dev.loki.lovisual.render.helpers.SystemCursor; import dev.loki.lovisual.util.input.KeyManager; import dev.loki.lovisual.util.logging.DebugLog; @@ -76,16 +76,6 @@ public enum DraggableHudElementRegistry { } } - public static void clearRuntimeReferences() { - cancelDragging(); - WIDGETS.clear(); - editorWidgetId = null; - forceVisible = false; - cachedLinkTheme = null; - cachedLinkColors = null; - clearSnapPreview(); - } - public static List getWidgets() { return Collections.unmodifiableList(WIDGETS); } @@ -95,7 +85,7 @@ public enum DraggableHudElementRegistry { } public static boolean isEnabled(String id) { - if (!RuntimeGate.canRunHud()) return false; + if (!Lifecycle.canRunHud()) return false; DraggableHudElement w = findById(id); return w != null && w.isEnabled(); } @@ -115,7 +105,7 @@ public enum DraggableHudElementRegistry { } public static boolean isEnabled(Class type) { - if (!RuntimeGate.canRunHud()) return false; + if (!Lifecycle.canRunHud()) return false; DraggableHudElement w = get(type); return w != null && w.isEnabled(); } @@ -139,7 +129,7 @@ public enum DraggableHudElementRegistry { } public static boolean hasEngineWork(HudPhase phase, boolean foreground) { - if (!RuntimeGate.canRunHud()) return false; + if (!Lifecycle.canRunHud()) return false; if (foreground && dragging != null) return true; for (DraggableHudElement w : WIDGETS) { @@ -149,7 +139,7 @@ public enum DraggableHudElementRegistry { } public static boolean hasEngineWidgetWork(String id) { - if (!RuntimeGate.canRunHud()) return false; + if (!Lifecycle.canRunHud()) return false; if (id == null || id.isBlank()) return false; if (editorWidgetId != null && !editorWidgetId.equals(id)) return false; @@ -165,7 +155,7 @@ public enum DraggableHudElementRegistry { TextRenderer textRenderer, net.minecraft.client.gui.GuiGraphicsExtractor ctx, float tickDelta) { - if (!RuntimeGate.canRunHud()) { + if (!Lifecycle.canRunHud()) { cancelDragging(); return; } @@ -233,7 +223,7 @@ public enum DraggableHudElementRegistry { TextRenderer textRenderer, net.minecraft.client.gui.GuiGraphicsExtractor ctx, float tickDelta) { - if (!RuntimeGate.canRunHud()) { + if (!Lifecycle.canRunHud()) { cancelDragging(); return; } @@ -288,7 +278,7 @@ public enum DraggableHudElementRegistry { TextRenderer textRenderer, net.minecraft.client.gui.GuiGraphicsExtractor ctx, float tickDelta) { - if (!RuntimeGate.canRunHud()) { + if (!Lifecycle.canRunHud()) { cancelDragging(); return; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableLayoutValue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableLayoutValue.java index fecb32f..1c0955e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableLayoutValue.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/DraggableLayoutValue.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Admins.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Admins.java index f9d441a..aa3b3c4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Admins.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Admins.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Armor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Armor.java index f497efb..8e1824e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Armor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Armor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/BetterChat.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/BetterChat.java index 1257c35..4ad48d4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/BetterChat.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/BetterChat.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -22,7 +22,7 @@ import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; import dev.loki.lovisual.render.engine.math.HudScale; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import java.util.Map; @@ -74,7 +74,7 @@ public final class BetterChat extends DraggableHudElement { } public static boolean isActive() { - return RuntimeGate.canRunHud() && DraggableHudElementRegistry.isEnabled(BetterChat.class); + return Lifecycle.canRunHud() && DraggableHudElementRegistry.isEnabled(BetterChat.class); } public float widthRatio() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Cooldowns.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Cooldowns.java index 10bfcb9..374ecec 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Cooldowns.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Cooldowns.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Coordinates.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Coordinates.java index 3653b1a..4848c8e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Coordinates.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Coordinates.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Fps.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Fps.java index 0ceca84..0dd4f55 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Fps.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Fps.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/GameTime.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/GameTime.java index ecea8f7..c2bc87c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/GameTime.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/GameTime.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/HudNotifier.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/HudNotifier.java index 59c89a5..37a8ca9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/HudNotifier.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/HudNotifier.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -38,7 +38,6 @@ import dev.loki.lovisual.render.engine.svg.SvgRenderOptions; import dev.loki.lovisual.render.engine.text.FontInfo; import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; import dev.loki.lovisual.util.wav.CustomSoundEngine; import java.util.ArrayList; @@ -390,7 +389,7 @@ public final class HudNotifier extends DraggableHudElement implements ModuleStat private void renderEngineInternal(Renderer2D renderer, TextRenderer textRenderer) { - if (RuntimeGate.isPanic()) return; + if (mc == null || mc.level == null || mc.player == null) return; HudGlobalConfig hud = HudGlobalConfig.get(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/HudPanelLayoutModes.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/HudPanelLayoutModes.java index a947216..7a16c4d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/HudPanelLayoutModes.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/HudPanelLayoutModes.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Inventory.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Inventory.java index 235139a..72c7cbf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Inventory.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Inventory.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Itemizer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Itemizer.java index cb60894..6dfe890 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Itemizer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Itemizer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -44,7 +44,7 @@ import java.util.Map; @HudElementRegister(order = 200) public final class Itemizer extends DraggableHudElement { - private static final String LAYOUT_ID = "combatant:api/hud/draggable/itemizer"; + private static final String LAYOUT_ID = "lovisual:api/hud/draggable/itemizer"; private static final float BASE_ICON_CARD = 24.0f; private static final float BASE_COMPACT_W = 72.0f; private static final float BASE_COMPACT_H = 24.0f; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Keybinds.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Keybinds.java index 071d736..9378863 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Keybinds.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Keybinds.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/MediaPlayer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/MediaPlayer.java index 486eef9..06c0975 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/MediaPlayer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/MediaPlayer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Memory.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Memory.java index 68693c2..781acca 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Memory.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Memory.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ModuleList.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ModuleList.java index 2c96b1c..1a44f52 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ModuleList.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ModuleList.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Ping.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Ping.java index e646e04..3240cd2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Ping.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Ping.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Potions.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Potions.java index b08388a..4694750 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Potions.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Potions.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Radar.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Radar.java index 2d20804..09ee5fa 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Radar.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Radar.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Scoreboard.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Scoreboard.java index 3ab8f7c..6b23b26 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Scoreboard.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Scoreboard.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedInventoryHudPanel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedInventoryHudPanel.java index 406741e..b8bb8ef 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedInventoryHudPanel.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedInventoryHudPanel.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -26,7 +26,7 @@ import java.util.ArrayList; import java.util.List; final class ScriptedInventoryHudPanel { - private static final String LAYOUT_ID = "combatant:api/hud/draggable/inventory_panel"; + private static final String LAYOUT_ID = "lovisual:api/hud/draggable/inventory_panel"; private final UiScriptModuleHandle moduleHandle = HudScriptLayouts.handle(LAYOUT_ID); private final CachedUiScriptRuntime runtime = new CachedUiScriptRuntime(HudScriptLayouts.runtimeReporter()); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedListHudPanel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedListHudPanel.java index d049051..c6cc294 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedListHudPanel.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedListHudPanel.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -54,7 +54,7 @@ final class ScriptedListHudPanel { static final float ROW_STEP = 11.0f; static final float PANEL_RADIUS = 4.0f; static final float PANEL_STROKE = 0.55f; - private static final String LAYOUT_ID = "combatant:api/hud/draggable/list_panel"; + private static final String LAYOUT_ID = "lovisual:api/hud/draggable/list_panel"; private final UiScriptModuleHandle moduleHandle = HudScriptLayouts.handle(LAYOUT_ID); private final CachedUiScriptRuntime runtime = new CachedUiScriptRuntime(HudScriptLayouts.runtimeReporter()); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedTriangulatorHudPanel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedTriangulatorHudPanel.java index d4b8f72..f6c2029 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedTriangulatorHudPanel.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/ScriptedTriangulatorHudPanel.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,7 +25,7 @@ import java.util.ArrayList; import java.util.List; final class ScriptedTriangulatorHudPanel { - private static final String LAYOUT_ID = "combatant:api/hud/draggable/triangulator"; + private static final String LAYOUT_ID = "lovisual:api/hud/draggable/triangulator"; private final UiScriptModuleHandle moduleHandle = HudScriptLayouts.handle(LAYOUT_ID); private final CachedUiScriptRuntime runtime = new CachedUiScriptRuntime(HudScriptLayouts.runtimeReporter()); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/SpeedBps.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/SpeedBps.java index 0c62e59..fda2b7b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/SpeedBps.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/SpeedBps.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/SystemTime.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/SystemTime.java index f338164..e2cb2ad 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/SystemTime.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/SystemTime.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHud.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHud.java index c5aefea..7a63296 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHud.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHud.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,58 +8,25 @@ package dev.loki.lovisual.features.gui.hud.draggable.impl; -import dev.loki.lovisual.features.theme.Theme; import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.util.screen.ClientScreen; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.client.gui.screens.ChatScreen; -import net.minecraft.resources.Identifier; -import net.minecraft.util.Util; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import dev.loki.lovisual.config.SettingDef; import dev.loki.lovisual.config.common.CommonSettingSchemas; import dev.loki.lovisual.features.gui.hud.HudElementRegister; import dev.loki.lovisual.features.gui.hud.HudGlobalConfig; -import dev.loki.lovisual.features.gui.hud.HudRenderUtil; import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElement; -import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; -import dev.loki.lovisual.features.theme.Themes; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.AutoAnchor; -import dev.loki.lovisual.features.module.modules.combat.AutoBed; -import dev.loki.lovisual.features.module.modules.combat.AutoCrystal; -import dev.loki.lovisual.render.engine.animation.AnimationUtility; -import dev.loki.lovisual.render.engine.color.RenderColor; import dev.loki.lovisual.render.engine.math.HudScale; -import dev.loki.lovisual.render.engine.profiler.ProfilerPhase; -import dev.loki.lovisual.render.engine.profiler.RenderProfiler2D; import dev.loki.lovisual.render.engine.renderer.Renderer2D; -import dev.loki.lovisual.render.engine.text.FontInfo; -import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.util.player.PlayerHealthResolver; -import dev.loki.lovisual.util.player.PlayerSkinResolver; -import dev.loki.lovisual.util.player.effect.StatusEffectTracker; -import dev.loki.lovisual.util.player.effect.StatusEffectView; import dev.loki.lovisual.util.pvp.opponents.TotemPopCounter; -import dev.loki.lovisual.util.pvp.opponents.TotemPopSnapshot; -import dev.loki.lovisual.util.target.TargetManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; -import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import static dev.loki.lovisual.features.theme.Theme.theme; - @HudElementRegister(order = 60) public final class TargetHud extends DraggableHudElement { @@ -69,194 +36,185 @@ public final class TargetHud extends DraggableHudElement { } - private static final float BASE_WIDTH = 112.0f; - private static final float BASE_HEIGHT = 40.0f; - private static final float FACE_SIZE = 24.0f; - private static final float FACE_X = 9.0f; - private static final float FACE_Y = 8.0f; - private static final float FACE_RADIUS = 4.0f; - private static final float CONTENT_GAP = 6.0f; - private static final float CONTENT_X_OFFSET = -2.0f; - private static final float CONTENT_Y_OFFSET = -1.0f; - private static final float PANEL_INSET = 2.0f; - private static final float PANEL_RADIUS = 6.0f; - private static final float NAME_Y = 13.0f; - private static final float BAR_Y_OFFSET = 12.0f; - private static final float BAR_WIDTH = 64.0f; - private static final float BAR_HEIGHT = 4.0f; - private static final float BAR_RADIUS = 2.0f; - private static final float NAME_TEXT_SCALE = 0.34f; - private static final float DISTANCE_TEXT_SCALE = 0.32f; - private static final float HP_TEXT_SCALE = 0.34f; - private static final float ARC_HP_TEXT_SCALE = 0.28f; - private static final float DISTANCE_Y_OFFSET = 8.0f; - private static final float ARC_CENTER_Y = 18.0f; - private static final float ARC_RIGHT_INSET = 13.8f; - private static final float ARC_RADIUS = 9.9f; - private static final float ARC_THICKNESS = 3.5f; - private static final float ARC_RESERVED_WIDTH = 34.0f; - private static final float PLACEHOLDER_TEXT_SCALE = 0.62f; - private static final float BASE_NAME_SCROLL_SPEED = 22.0f; - private static final float BASE_NAME_SCROLL_GAP = 14.0f; - private static final float BASE_NAME_FADE = 12.0f; - private static final float NAME_SCROLL_PAUSE_SEC = 0.8f; - private static final float EFFECTS_PANEL_GAP = 3.0f; - private static final float EFFECTS_CHIP_HEIGHT = 10.0f; - private static final float EFFECTS_CHIP_RADIUS = 3.0f; - private static final float EFFECTS_CHIP_PAD_X = 3.0f; - private static final float EFFECTS_CHIP_GAP = 2.0f; - private static final float EFFECTS_ICON_SIZE = 8.0f; - private static final float EFFECTS_TEXT_GAP = 2.0f; - private static final float EFFECTS_TEXT_SCALE = 0.22f; - private static final float EQUIPMENT_TOP_GAP = 2.0f; - private static final float EQUIPMENT_BOTTOM_PAD = 2.0f; - private static final float EQUIPMENT_SLOT = 11.0f; - private static final float EQUIPMENT_GAP = 2.0f; - private static final float EQUIPMENT_TEXT_SCALE = 0.22f; - private static final float EQUIPMENT_ROW_Y_OFFSET = 1.15f; - private static final long HIT_FLASH_MS = 220L; - private static final float HEALTH_SPEED = 6.0f; - private static final float BAR_SPEED = 4.0f; - private static final float BAR_TAIL_FADE_LENGTH = BAR_HEIGHT; - private static final float ARC_TAIL_FADE_DEGREES = 20.0f; - private static final float PROGRESS_SNAP_EPSILON = 0.0005f; - private static final float DISTANCE_SPEED = 7.0f; - private static final float EQUIPMENT_SPEED = 7.0f; - private static final float HEALTH_TEXT_STEP = 0.25f; - private static final float HEALTH_TEXT_SMALL_STEP = 0.10f; - private static final float HEALTH_ZERO_CLAMP = 0.05f; - private static final float HEALTH_ZERO_SNAP_THRESHOLD = 0.60f; - private static final float TOTEM_BADGE_BOTTOM_PAD = 1.45f; - private static final float TOTEM_BADGE_ICON_SIZE = 8.0f; - private static final float TOTEM_BADGE_TEXT_GAP = 1.25f; - private static final float TOTEM_BADGE_TEXT_SCALE = 0.24f; - private static final float TOTEM_BADGE_ANIM_SPEED = 10.0f; - private static final float TOTEM_BADGE_PULSE_SPEED = 8.0f; - private static ItemStack totemBadgeStack; + static final float BASE_WIDTH = 112.0f; + static final float BASE_HEIGHT = 40.0f; + static final float FACE_SIZE = 24.0f; + static final float FACE_X = 9.0f; + static final float FACE_Y = 8.0f; + static final float FACE_RADIUS = 4.0f; + static final float CONTENT_GAP = 6.0f; + static final float CONTENT_X_OFFSET = -2.0f; + static final float CONTENT_Y_OFFSET = -1.0f; + static final float PANEL_INSET = 2.0f; + static final float PANEL_RADIUS = 6.0f; + static final float NAME_Y = 13.0f; + static final float BAR_Y_OFFSET = 12.0f; + static final float BAR_WIDTH = 64.0f; + static final float BAR_HEIGHT = 4.0f; + static final float BAR_RADIUS = 2.0f; + static final float NAME_TEXT_SCALE = 0.34f; + static final float DISTANCE_TEXT_SCALE = 0.32f; + static final float HP_TEXT_SCALE = 0.34f; + static final float ARC_HP_TEXT_SCALE = 0.28f; + static final float DISTANCE_Y_OFFSET = 8.0f; + static final float ARC_CENTER_Y = 18.0f; + static final float ARC_RIGHT_INSET = 13.8f; + static final float ARC_RADIUS = 9.9f; + static final float ARC_THICKNESS = 3.5f; + static final float ARC_RESERVED_WIDTH = 34.0f; + static final float PLACEHOLDER_TEXT_SCALE = 0.62f; + static final float BASE_NAME_SCROLL_SPEED = 22.0f; + static final float BASE_NAME_SCROLL_GAP = 14.0f; + static final float BASE_NAME_FADE = 12.0f; + static final float NAME_SCROLL_PAUSE_SEC = 0.8f; + static final float EFFECTS_PANEL_GAP = 3.0f; + static final float EFFECTS_CHIP_HEIGHT = 10.0f; + static final float EFFECTS_CHIP_RADIUS = 3.0f; + static final float EFFECTS_CHIP_PAD_X = 3.0f; + static final float EFFECTS_CHIP_GAP = 2.0f; + static final float EFFECTS_ICON_SIZE = 8.0f; + static final float EFFECTS_TEXT_GAP = 2.0f; + static final float EFFECTS_TEXT_SCALE = 0.22f; + static final float EQUIPMENT_TOP_GAP = 2.0f; + static final float EQUIPMENT_BOTTOM_PAD = 2.0f; + static final float EQUIPMENT_SLOT = 11.0f; + static final float EQUIPMENT_GAP = 2.0f; + static final float EQUIPMENT_ROW_Y_OFFSET = 1.15f; + static final long HIT_FLASH_MS = 220L; + static final float HEALTH_SPEED = 6.0f; + static final float BAR_SPEED = 4.0f; + static final float BAR_TAIL_FADE_LENGTH = BAR_HEIGHT; + static final float ARC_TAIL_FADE_DEGREES = 20.0f; + static final float PROGRESS_SNAP_EPSILON = 0.0005f; + static final float DISTANCE_SPEED = 7.0f; + static final float EQUIPMENT_SPEED = 7.0f; + static final float HEALTH_TEXT_STEP = 0.25f; + static final float HEALTH_TEXT_SMALL_STEP = 0.10f; + static final float HEALTH_ZERO_CLAMP = 0.05f; + static final float HEALTH_ZERO_SNAP_THRESHOLD = 0.60f; + static final float TOTEM_BADGE_BOTTOM_PAD = 1.45f; + static final float TOTEM_BADGE_ICON_SIZE = 8.0f; + static final float TOTEM_BADGE_TEXT_GAP = 1.25f; + static final float TOTEM_BADGE_TEXT_SCALE = 0.24f; + static final float TOTEM_BADGE_ANIM_SPEED = 10.0f; + static final float TOTEM_BADGE_PULSE_SPEED = 8.0f; - private static ItemStack totemBadgeStack() { - if (totemBadgeStack == null || totemBadgeStack.isEmpty()) { - totemBadgeStack = new ItemStack(Items.TOTEM_OF_UNDYING); - } - return totemBadgeStack; - } + static final float FACE_U0 = 8f / 64f; + static final float FACE_V0 = 8f / 64f; + static final float FACE_U1 = 16f / 64f; + static final float FACE_V1 = 16f / 64f; + static final float HAT_U0 = 40f / 64f; + static final float HAT_V0 = 8f / 64f; + static final float HAT_U1 = 48f / 64f; + static final float HAT_V1 = 16f / 64f; - private static final float FACE_U0 = 8f / 64f; - private static final float FACE_V0 = 8f / 64f; - private static final float FACE_U1 = 16f / 64f; - private static final float FACE_V1 = 16f / 64f; - private static final float HAT_U0 = 40f / 64f; - private static final float HAT_V0 = 8f / 64f; - private static final float HAT_U1 = 48f / 64f; - private static final float HAT_V1 = 16f / 64f; + static final String COLOR_THEME = "Theme"; + static final String COLOR_CUSTOM = "Custom"; + static final String EFFECT_NONE = "None"; + static final String EFFECT_BLUR = "Blur"; + static final String EFFECT_GLASS = "Glass"; + static final String EFFECTS_OFF = "Off"; + static final String EFFECTS_COMPACT = "Compact"; + static final String EQUIPMENT_OFF = "Off"; + static final String EQUIPMENT_COMPACT = "Compact"; + static final String HP_MODE_LINE = "Line"; + static final String HP_MODE_ARC = "Arc"; - private static final String COLOR_THEME = "Theme"; - private static final String COLOR_CUSTOM = "Custom"; - private static final String EFFECT_NONE = "None"; - private static final String EFFECT_BLUR = "Blur"; - private static final String EFFECT_GLASS = "Glass"; - private static final String EFFECTS_OFF = "Off"; - private static final String EFFECTS_COMPACT = "Compact"; - private static final String EQUIPMENT_OFF = "Off"; - private static final String EQUIPMENT_COMPACT = "Compact"; - private static final String HP_MODE_LINE = "Line"; - private static final String HP_MODE_ARC = "Arc"; + static final ConcurrentHashMap HIT_FLASH_MS_BY_ID = new ConcurrentHashMap<>(); - private static final ConcurrentHashMap HIT_FLASH_MS_BY_ID = new ConcurrentHashMap<>(); + final Minecraft mc = Minecraft.getInstance(); + final HudGlobalConfig hud = HudGlobalConfig.get(); - private final Minecraft mc = Minecraft.getInstance(); - private final HudGlobalConfig hud = HudGlobalConfig.get(); - - private final NumberValue scale = + final NumberValue scale = new NumberValue<>("target_scale", 3.28, 0.5, 4.0); - private final NumberValue holdMs = + final NumberValue holdMs = new NumberValue<>("target_hold_ms", 1000, 0, 5000); - private final BooleanValue totemPopCounter = TotemPopCounter.enabledValue(); - private final NumberValue totemPopResetSeconds = TotemPopCounter.resetAfterSecondsValue(); - private final RGBColorValue totemPopTextColor = + final BooleanValue totemPopCounter = TotemPopCounter.enabledValue(); + final NumberValue totemPopResetSeconds = TotemPopCounter.resetAfterSecondsValue(); + final RGBColorValue totemPopTextColor = new RGBColorValue("target_totem_pop_text_color", "RNB#FFFFFF"); - private final BooleanValue marquee = + final BooleanValue marquee = new BooleanValue("target_marquee", true); - private final BooleanValue playersOnly = + final BooleanValue playersOnly = new BooleanValue("target_players_only", false); - private final ModeValue effectsMode = + final ModeValue effectsMode = new ModeValue("target_effects_mode", "Off", EFFECTS_OFF, EFFECTS_COMPACT); - private final BooleanValue effectsSelf = + final BooleanValue effectsSelf = new BooleanValue("target_effects_self", true); - private final ModeValue equipmentMode = + final ModeValue equipmentMode = new ModeValue("target_equipment_mode", "Off", EQUIPMENT_OFF, EQUIPMENT_COMPACT); - private final ModeValue hpMode = + final ModeValue hpMode = new ModeValue("target_hp_mode", "Arc", HP_MODE_LINE, HP_MODE_ARC); - private final ModeValue colorMode = + final ModeValue colorMode = new ModeValue("target_color_mode", "Theme", COLOR_THEME, COLOR_CUSTOM); - private final RGBAColorValue bg = + final RGBAColorValue bg = new RGBAColorValue("target_bg", "#F7343434"); - private final RGBAColorValue bg2 = + final RGBAColorValue bg2 = new RGBAColorValue("target_bg_secondary", "#F7161616"); - private final RGBColorValue stroke = + final RGBColorValue stroke = new RGBColorValue("target_stroke", "#5A5A5A"); - private final NumberValue blurAlpha = + final NumberValue blurAlpha = new NumberValue<>("target_blur_alpha", 255, 0, 255); - private final NumberValue bgAlpha = + final NumberValue bgAlpha = new NumberValue<>("target_bg_alpha", 162, 0, 255); - private final RGBColorValue text = + final RGBColorValue text = new RGBColorValue("target_text", "#FFFFFF"); - private final RGBColorValue textSecondary = + final RGBColorValue textSecondary = new RGBColorValue("target_text_secondary", "#D7D7D7"); - private final RGBColorValue barBg = + final RGBColorValue barBg = new RGBColorValue("target_bar_bg", "#1E1E1E"); - private final RGBColorValue healthStart = + final RGBColorValue healthStart = new RGBColorValue("target_health_start", "#F3F3F3"); - private final RGBColorValue healthEnd = + final RGBColorValue healthEnd = new RGBColorValue("target_health_end", "#9E9E9E"); - private final RGBColorValue trail = + final RGBColorValue trail = new RGBColorValue("target_trail", "#373737"); - private final RGBColorValue absorptionStart = + final RGBColorValue absorptionStart = new RGBColorValue("target_absorption_start", "#FFC300"); - private final RGBColorValue absorptionEnd = + final RGBColorValue absorptionEnd = new RGBColorValue("target_absorption_end", "#FFD96B"); - private final RGBColorValue hitOuter = + final RGBColorValue hitOuter = new RGBColorValue("target_hit_outer", "#FF5A5A"); - private final RGBColorValue hitInner = + final RGBColorValue hitInner = new RGBColorValue("target_hit_inner", "#FF7373"); - private final ModeValue bgEffect = + final ModeValue bgEffect = new ModeValue("target_bg_effect", "Glass", EFFECT_NONE, EFFECT_BLUR, EFFECT_GLASS); - private final BooleanValue hitAnim = + final BooleanValue hitAnim = new BooleanValue("target_hit_anim", true); - private final NumberValue hitPulse = + final NumberValue hitPulse = new NumberValue<>("target_hit_pulse", 1.0, 0.0, 2.0); - private LivingEntity displayTarget; - private float visibilityAnimation; - private float healthAnimation; - private float trailAnimation; - private float absorptionAnimation; - private float effectsAnimation; - private float equipmentAnimation; - private float totemPopAnimation; - private float totemPopTextPulse; - private int totemPopLastCount; - private UUID totemPopTargetId; - private float displayedHealth; - private float displayedDistance; - private long lastSeenMs; - private long waveStartMs = System.currentTimeMillis(); + LivingEntity displayTarget; + float visibilityAnimation; + float healthAnimation; + float trailAnimation; + float absorptionAnimation; + float effectsAnimation; + float equipmentAnimation; + float totemPopAnimation; + float totemPopTextPulse; + int totemPopLastCount; + UUID totemPopTargetId; + float displayedHealth; + float displayedDistance; + long lastSeenMs; + long waveStartMs = System.currentTimeMillis(); - private int uiBgPrimary; - private int uiBgSecondary; - private int uiStroke; - private int uiTextPrimary; - private int uiTextSecondary; - private int uiBarBackground; - private int uiHealthStart; - private int uiHealthEnd; - private float uiHealthGradientAngle; - private int uiTrail; - private int uiAbsorptionStart; - private int uiAbsorptionEnd; - private float uiAbsorptionGradientAngle; - private int uiHitOuter; - private int uiHitInner; + int uiBgPrimary; + int uiBgSecondary; + int uiStroke; + int uiTextPrimary; + int uiTextSecondary; + int uiBarBackground; + int uiHealthStart; + int uiHealthEnd; + float uiHealthGradientAngle; + int uiTrail; + int uiAbsorptionStart; + int uiAbsorptionEnd; + float uiAbsorptionGradientAngle; + int uiHitOuter; + int uiHitInner; public TargetHud() { super("target_hud", "TargetHUD", true); @@ -267,140 +225,6 @@ public final class TargetHud extends DraggableHudElement { HIT_FLASH_MS_BY_ID.put(target.getId(), System.currentTimeMillis()); } - private static float snapToStep(float value, float step) { - if (step <= 0.0f) return value; - return Math.round(value / step) * step; - } - - private static float formatDisplayHealth(float health) { - float clamped = Math.max(0.0f, health); - if (clamped <= HEALTH_ZERO_CLAMP) { - return 0.0f; - } - float step = clamped < 1.0f ? HEALTH_TEXT_SMALL_STEP : HEALTH_TEXT_STEP; - float snapped = snapToStep(clamped, step); - return snapped <= HEALTH_ZERO_CLAMP ? 0.0f : snapped; - } - - private static String formatHealth(float health) { - if (health >= 100.0f) { - return Integer.toString(Math.round(health)); - } - if (health >= 10.0f) { - return String.format(Locale.ROOT, "%.1f", health); - } - return String.format(Locale.ROOT, "%.2f", health); - } - - private static String formatDistance(float distance) { - if (distance >= 100.0f) { - return Integer.toString(Math.round(distance)); - } - return String.format(Locale.ROOT, "%.1f", distance); - } - - private static int[] buildWaveColors(long elapsedMs, - float waveSpeedMs, - float alphaFactor, - int startColor, - int endColor) { - float phase = (elapsedMs % (long) waveSpeedMs) / waveSpeedMs * (float) Math.PI * 2.0f; - int[] colors = new int[4]; - for (int i = 0; i < 2; i++) { - float wave = ((float) Math.sin(phase - i * 1.5f) + 1.0f) * 0.5f; - int mixed = HudRenderUtil.mixColor(startColor, endColor, wave); - colors[i * 2] = HudRenderUtil.scaleAlpha(mixed, alphaFactor); - colors[i * 2 + 1] = colors[i * 2]; - } - return colors; - } - - private static void drawAnimatedArcGradient(Renderer2D renderer, - float centerX, - float centerY, - float radius, - float thickness, - float startAngle, - float sweep, - float softness, - float alphaFactor, - int startColor, - int endColor, - float baseAngle, - float speedMs, - long elapsedMs, - float phaseOffset) { - float safeSpeed = Math.max(1.0f, speedMs); - float phase = (elapsedMs / safeSpeed) * (float) Math.PI * 2.0f + phaseOffset; - float animatedAngle = baseAngle - + (elapsedMs / safeSpeed) * 92.0f - + (float) Math.sin(phase * 0.63f) * 26.0f; - float pulseA = ((float) Math.sin(phase) + 1.0f) * 0.5f; - float pulseB = ((float) Math.sin(phase + 1.95f) + 1.0f) * 0.5f; - - int c0 = HudRenderUtil.mixColor(startColor, endColor, pulseA * 0.24f); - int c1 = HudRenderUtil.mixColor(endColor, startColor, pulseB * 0.18f); - int drawStart = HudRenderUtil.scaleAlpha(c0, alphaFactor); - int drawEnd = HudRenderUtil.scaleAlpha(c1, alphaFactor); - float offsetPx = (float) Math.sin(phase * 0.71f) * radius * 0.58f; - - renderer.arcStrokeGradient( - centerX, - centerY, - radius, - thickness, - startAngle, - startAngle + sweep, - softness, - drawStart, - drawEnd, - animatedAngle, - offsetPx - ); - - } - - private static float tailFade(float visibleLength, float fadeLength) { - if (fadeLength <= 0.0f) return visibleLength > 0.0f ? 1.0f : 0.0f; - return AnimationUtility.smoothstep(AnimationUtility.clamp01(visibleLength / fadeLength)); - } - - private static float measureText(TextRenderer renderer, String text, float scale) { - renderer.begin(scale, false, false); - try { - return (float) renderer.getWidth(text, false); - } finally { - renderer.end(); - } - } - - private static String trimText(TextRenderer renderer, String text, float maxWidth, float scale) { - if (text == null || text.isEmpty()) return ""; - renderer.begin(scale, false, false); - try { - if (renderer.getWidth(text, false) <= maxWidth) return text; - String value = text; - while (!value.isEmpty()) { - String candidate = value + "..."; - if (renderer.getWidth(candidate, false) <= maxWidth) { - return candidate; - } - value = value.substring(0, value.length() - 1); - } - return ""; - } finally { - renderer.end(); - } - } - - private static int rgba(int red, int green, int blue, int alpha) { - int r = Math.max(0, Math.min(255, red)); - int g = Math.max(0, Math.min(255, green)); - int b = Math.max(0, Math.min(255, blue)); - int a = Math.max(0, Math.min(255, alpha)); - return (a << 24) | (r << 16) | (g << 8) | b; - } - @Override protected void defineSettings(List defs) { defs.add(SettingDef.number(scale)); @@ -458,1230 +282,59 @@ public final class TargetHud extends DraggableHudElement { float tickDelta, int screenW, int screenH) { - try (ProfilerPhase.Scope ignored = ProfilerPhase.scope("2d:target_hud:main"); - RenderProfiler2D.Section ignoredSection = RenderProfiler2D.section("target_hud:main")) { - boolean preview = DraggableHudElementRegistry.isForceVisible(); - if (mc == null || (mc.player == null && !preview)) return; - - long now = System.currentTimeMillis(); - LivingEntity target = resolveTarget(preview); - updateDisplayTarget(target, now); - - boolean shouldShow = shouldShow(target, now); - float dt = AnimationUtility.deltaTime(); - visibilityAnimation = HudRenderUtil.animateVisibility(visibilityAnimation, shouldShow); - - if (!shouldShow && visibilityAnimation <= 0.001f) { - displayTarget = null; - width = 0f; - height = 0f; - return; - } - if (displayTarget == null) return; - - updatePalette(); - - float hudScale = HudScale.scale(screenW, screenH) * scale.get().floatValue(); - float alphaFactor = AnimationUtility.easeOutCubic(visibilityAnimation); - float hitPulseFactor = computeHitPulse(now); - EffectLayout boundsEffects = buildEffectLayout(displayTarget, preview, textRenderer, hudScale); - boolean hasEffects = !boundsEffects.chips().isEmpty(); - float effectsTarget = hasEffects ? 1.0f : 0.0f; - effectsAnimation = AnimationUtility.approach(effectsAnimation, effectsTarget, dt, EQUIPMENT_SPEED); - effectsAnimation = AnimationUtility.snap(effectsAnimation, effectsTarget, 0.001f); - EquipmentLayout boundsEquipment = buildEquipmentLayout(displayTarget, preview, textRenderer, hudScale); - boolean hasEquipment = !boundsEquipment.entries().isEmpty(); - float equipmentTarget = hasEquipment ? 1.0f : 0.0f; - equipmentAnimation = AnimationUtility.approach(equipmentAnimation, equipmentTarget, dt, EQUIPMENT_SPEED); - equipmentAnimation = AnimationUtility.snap(equipmentAnimation, equipmentTarget, 0.001f); - float scalePulse = hitAnim.get() - ? 1.0f + hitPulseFactor * 0.018f * hitPulse.get().floatValue() - : 1.0f; - float widgetScale = HudRenderUtil.visibilityScale(visibilityAnimation); - - float panelWidthLogical = BASE_WIDTH; - float panelHeightLogical = BASE_HEIGHT; - - float targetWidth = panelWidthLogical * hudScale; - float targetHeight = panelHeightLogical * hudScale; - width = HudRenderUtil.animateDimension(width, targetWidth); - height = HudRenderUtil.animateDimension(height, targetHeight); - - float widthFactor = targetWidth <= 0.0f ? 1.0f : width / targetWidth; - float heightFactor = targetHeight <= 0.0f ? 1.0f : height / targetHeight; - float dimensionFactor = Math.max(0.0f, Math.min(widthFactor, heightFactor)); - float scaleFactor = hudScale * dimensionFactor * widgetScale * scalePulse; - - float drawW = panelWidthLogical * scaleFactor; - float drawH = panelHeightLogical * scaleFactor; - float panelDrawW = panelWidthLogical * scaleFactor; - float panelDrawH = panelHeightLogical * scaleFactor; - float drawX = x + (width - drawW) * 0.5f; - float drawY = y + (height - drawH) * 0.5f; - - float panelBaseX = drawX + (drawW - panelDrawW) * 0.5f; - float panelBaseY = drawY; - float panelX = panelBaseX + PANEL_INSET * scaleFactor; - float panelY = panelBaseY + PANEL_INSET * scaleFactor; - float panelW = panelDrawW - PANEL_INSET * 2f * scaleFactor; - float panelH = panelDrawH - PANEL_INSET * 2f * scaleFactor; - float panelRadius = PANEL_RADIUS * scaleFactor; - - boolean glassEnabled = isGlassEffect(); - boolean blurEnabled = isBlurEffect(); - TotemPopSnapshot totemPopSnapshot = resolveTotemPopSnapshot(displayTarget); - updateTotemPopAnimation(displayTarget, totemPopSnapshot, dt); - - if (glassEnabled) { - drawGlass(panelX, panelY, panelW, panelH, panelRadius, alphaFactor); - } else if (blurEnabled) { - drawBlur(panelX, panelY, panelW, panelH, panelRadius, uiBgPrimary, alphaFactor); - } - - drawBackground(renderer, panelX, panelY, panelW, panelH, panelRadius, alphaFactor, glassEnabled); - drawHitPulse(renderer, panelX, panelY, panelW, panelH, panelRadius, alphaFactor, hitPulseFactor); - drawFace(renderer, textRenderer, ctx, displayTarget, panelX, panelY, scaleFactor, alphaFactor, totemPopSnapshot); - drawContent(renderer, textRenderer, displayTarget, panelX, panelY, panelDrawW, scaleFactor, alphaFactor, now, dt); - if (effectsAnimation > 0.01f) { - EffectLayout drawEffects = buildEffectLayout(displayTarget, preview, textRenderer, scaleFactor); - float effectsY = panelY - drawEffects.height(); - drawEffects(renderer, textRenderer, drawEffects, panelX, effectsY, panelW, scaleFactor, alphaFactor * effectsAnimation, glassEnabled); - } - if (equipmentAnimation > 0.01f) { - EquipmentLayout drawEquipment = buildEquipmentLayout(displayTarget, preview, textRenderer, scaleFactor); - drawEquipment(renderer, textRenderer, ctx, drawEquipment, panelX, panelY + panelH, panelW, drawEquipment.height(), scaleFactor, alphaFactor * equipmentAnimation, glassEnabled); - } - } + TargetHudRenderer.render(this, renderer, textRenderer, ctx, tickDelta, screenW, screenH); } - private void updateDisplayTarget(LivingEntity target, long now) { - if (target != null) { - if (displayTarget != target) { - displayTarget = target; - PlayerHealthResolver.HealthSnapshot health = PlayerHealthResolver.resolve(target); - float baseMaxHealth = Math.max(1.0f, target.getMaxHealth()); - float realHealth = Math.max(0.0f, health.totalHealth() - health.absorption()); - displayedHealth = health.totalHealth(); - healthAnimation = realHealth / baseMaxHealth; - trailAnimation = healthAnimation; - absorptionAnimation = health.absorption() / baseMaxHealth; - displayedDistance = mc.player != null ? mc.player.distanceTo(target) : 0.0f; - waveStartMs = now; - } - lastSeenMs = now; - return; - } - - if (displayTarget == mc.player && !(ClientScreen.current() instanceof ChatScreen)) { - lastSeenMs = 0L; - } + float hudX() { + return x; } - private boolean shouldShow(LivingEntity target, long now) { - if (target != null) return true; - return displayTarget != null && lastSeenMs > 0L && now - lastSeenMs <= Math.max(0L, holdMs.get()); + float hudY() { + return y; } - private LivingEntity resolveTarget(boolean preview) { - LivingEntity target = TargetManager.getTarget(); - if (target != null && playersOnly.get() && !(target instanceof Player)) { - target = null; - } - if (target == null && (preview || ClientScreen.current() instanceof ChatScreen)) { - target = mc.player; - } - return target; + float hudWidth() { + return width; } - private void updatePalette() { - if (isThemeMode()) { - int panelAlpha = bgAlpha.get(); - uiBgPrimary = HudRenderUtil.setAlpha(theme().windowBg(), panelAlpha); - uiBgSecondary = HudRenderUtil.setAlpha( - HudRenderUtil.mixColor(theme().surface(), theme().windowHeader(), 0.35f), - panelAlpha - ); - uiStroke = HudRenderUtil.setAlpha( - HudRenderUtil.mixColor(theme().windowStroke(), theme().strokeSoft(), 0.4f), - Math.min(panelAlpha, 190) - ); - uiTextPrimary = theme().textPrimary(); - uiTextSecondary = theme().textMuted(); - uiBarBackground = HudRenderUtil.setAlpha( - HudRenderUtil.mixColor(theme().surface(), 0xFF000000, 0.18f), - 200 - ); - Themes.ThemeEntry entry = Theme.currentEntry(); - Themes.GradientSpec healthGradient = entry != null && entry.cardGradient() != null && entry.cardGradient().enabled() - ? entry.cardGradient() - : null; - if (healthGradient != null) { - uiHealthStart = healthGradient.start(); - uiHealthEnd = healthGradient.end(); - uiHealthGradientAngle = healthGradient.angleDeg(); - } else { - uiHealthStart = theme().accent(); - uiHealthEnd = HudRenderUtil.mixColor(theme().accentSoft(), theme().textPrimary(), 0.18f); - uiHealthGradientAngle = 45.0f; - } - uiTrail = HudRenderUtil.setAlpha( - HudRenderUtil.mixColor(theme().surface(), theme().accentSoft(), 0.22f), - 170 - ); - uiAbsorptionStart = 0xFFFFB400; - uiAbsorptionEnd = 0xFFFFE17A; - uiAbsorptionGradientAngle = uiHealthGradientAngle + 90.0f; - uiHitOuter = HudRenderUtil.mixColor(theme().accentSoft(), 0xFFFF6767, 0.45f); - uiHitInner = HudRenderUtil.mixColor(theme().accent(), 0xFFFFC2C2, 0.22f); - return; - } - - uiBgPrimary = bg.getArgb(); - uiBgSecondary = bg2.getArgb(); - uiStroke = stroke.getArgb(); - uiTextPrimary = text.getArgb(); - uiTextSecondary = textSecondary.getArgb(); - uiBarBackground = barBg.getArgb(); - uiHealthStart = healthStart.getArgb(); - uiHealthEnd = healthEnd.getArgb(); - uiHealthGradientAngle = 45.0f; - uiTrail = trail.getArgb(); - uiAbsorptionStart = absorptionStart.getArgb(); - uiAbsorptionEnd = absorptionEnd.getArgb(); - uiAbsorptionGradientAngle = 135.0f; - uiHitOuter = hitOuter.getArgb(); - uiHitInner = hitInner.getArgb(); + float hudHeight() { + return height; } - private void drawBackground(Renderer2D renderer, - float x, - float y, - float width, - float height, - float radius, - float alphaFactor, - boolean glassEnabled) { - if (glassEnabled) { - renderer.roundedRect(x, y, width, height, radius, 1.0f, HudRenderUtil.glassPanelBackground(alphaFactor)); - return; - } - - int primary = HudRenderUtil.scaleAlpha(uiBgPrimary, alphaFactor); - int secondary = HudRenderUtil.scaleAlpha(uiBgSecondary, alphaFactor); - - if (isThemeMode()) { - HudRenderUtil.drawHudBackground(renderer, x, y, width, height, radius, 1.0f, primary, true); - } else { - renderer.roundedRectGradientQuad(x, y, width, height, radius, 1.0f, primary, secondary, primary, secondary); - } - - renderer.roundedRectStroke( - x, y, width, height, radius, 1.0f, - 0.35f * radius / PANEL_RADIUS, - HudRenderUtil.scaleAlpha(uiStroke, alphaFactor) - ); + void setHudSize(float w, float h) { + width = w; + height = h; } - private void drawFace(Renderer2D renderer, - TextRenderer textRenderer, - GuiGraphicsExtractor ctx, - LivingEntity target, - float x, - float y, - float scaleFactor, - float alphaFactor, - TotemPopSnapshot totemPopSnapshot) { - float faceSize = FACE_SIZE * scaleFactor; - float faceX = x + (FACE_X + CONTENT_X_OFFSET) * scaleFactor; - float faceY = y + (FACE_Y + CONTENT_Y_OFFSET) * scaleFactor; - float faceRadius = FACE_RADIUS * scaleFactor; - - float hurtPercent = target.hurtTime > 0 ? Math.min(1.0f, target.hurtTime / 10.0f) : 0.0f; - int red = 255; - int green = Math.round(255.0f * (1.0f - hurtPercent)); - int blue = Math.round(255.0f * (1.0f - hurtPercent)); - int tint = rgba(red, green, blue, Math.round(255.0f * alphaFactor)); - - if (target instanceof Player player) { - drawPlayerFace(player, faceX, faceY, faceSize, faceRadius, tint); - } else { - drawPlaceholderFace(renderer, textRenderer, target, faceX, faceY, faceSize, faceRadius, alphaFactor, hurtPercent); - } - - drawTotemPopBadge(renderer, textRenderer, totemPopSnapshot, faceX, faceY, faceSize, faceRadius, scaleFactor, alphaFactor); - } - - private TotemPopSnapshot resolveTotemPopSnapshot(LivingEntity target) { - if (!(target instanceof Player player)) { - return TotemPopSnapshot.empty(null); - } - return TotemPopCounter.snapshot(player.getUUID()); - } - - private void updateTotemPopAnimation(LivingEntity target, - TotemPopSnapshot snapshot, - float dt) { - UUID id = target instanceof Player player ? player.getUUID() : null; - if (id == null || !id.equals(totemPopTargetId)) { - totemPopTargetId = id; - totemPopAnimation = 0.0f; - totemPopTextPulse = 0.0f; - totemPopLastCount = 0; - } - - int count = snapshot != null ? Math.max(0, snapshot.count()) : 0; - if (count > 0 && count != totemPopLastCount) { - totemPopLastCount = count; - totemPopTextPulse = 1.0f; - } else if (count <= 0) { - totemPopLastCount = 0; - } - - float targetAnimation = snapshot != null && snapshot.visible() ? 1.0f : 0.0f; - totemPopAnimation = AnimationUtility.approach(totemPopAnimation, targetAnimation, dt, TOTEM_BADGE_ANIM_SPEED); - totemPopAnimation = AnimationUtility.snap(totemPopAnimation, targetAnimation, 0.001f); - totemPopTextPulse = AnimationUtility.approach(totemPopTextPulse, 0.0f, dt, TOTEM_BADGE_PULSE_SPEED); - totemPopTextPulse = AnimationUtility.snap(totemPopTextPulse, 0.0f, 0.001f); - } - - private void drawTotemPopBadge(Renderer2D renderer, - TextRenderer textRenderer, - TotemPopSnapshot snapshot, - float faceX, - float faceY, - float faceSize, - float faceRadius, - float scaleFactor, - float alphaFactor) { - if (snapshot == null || snapshot.count() <= 0 || totemPopAnimation <= 0.001f) { - return; - } - - float anim = AnimationUtility.easeInOutCubic(totemPopAnimation); - float visualAlpha = alphaFactor * anim; - if (visualAlpha <= 0.001f) { - return; - } - - String text = "x" + snapshot.count(); - TextRenderer badgeRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); - float pulse = AnimationUtility.easeOutBack(totemPopTextPulse, 1.12f); - float groupScale = (0.86f + 0.14f * anim) * (1.0f + 0.13f * pulse); - float textScale = TOTEM_BADGE_TEXT_SCALE * scaleFactor * groupScale; - float iconSize = Math.min(faceSize * 0.38f, TOTEM_BADGE_ICON_SIZE * scaleFactor * groupScale); - float gap = TOTEM_BADGE_TEXT_GAP * scaleFactor; - float textWidth = measureText(badgeRenderer, text, textScale); - float textHeight = getTextHeight(badgeRenderer, textScale); - float groupWidth = iconSize + gap + textWidth; - float groupHeight = Math.max(iconSize, textHeight); - - float groupX = faceX + (faceSize - groupWidth) * 0.5f; - float groupY = faceY + faceSize - groupHeight - TOTEM_BADGE_BOTTOM_PAD * scaleFactor - - (1.0f - anim) * 1.4f * scaleFactor; - float iconX = groupX; - float iconY = groupY + (groupHeight - iconSize) * 0.5f; - drawItem(renderer, totemBadgeStack(), iconX, iconY, Math.max(0.1f, iconSize / 16.0f), 713, visualAlpha); - - float textX = iconX + iconSize + gap; - float textY = groupY + (groupHeight - textHeight) * 0.5f - 0.12f * scaleFactor; - int textColor = HudRenderUtil.setAlpha(totemPopTextColor.getArgb(), Math.round(255.0f * visualAlpha)); - badgeRenderer.begin(textScale, false, false); - try { - badgeRenderer.render(text, textX, textY, new RenderColor(textColor), true); - } finally { - badgeRenderer.end(); - } - } - - private void drawPlayerFace(Player player, - float x, - float y, - float size, - float radius, - int tint) { - Identifier skin = PlayerSkinResolver.resolveProfileSkin(player.getGameProfile()); - if (skin == null) return; - - Renderer2D.TEXTURE.roundedTexRect( - x, y, size, size, - radius, 1.0f, - FACE_U0, FACE_V0, FACE_U1, FACE_V1, - tint, - skin - ); - - float hatSize = size * 1.1f; - float hatOffset = (hatSize - size) * 0.5f; - Renderer2D.TEXTURE.roundedTexRect( - x - hatOffset, y - hatOffset, hatSize, hatSize, - radius * 1.05f, 1.0f, - HAT_U0, HAT_V0, HAT_U1, HAT_V1, - tint, - skin - ); - } - - private void drawPlaceholderFace(Renderer2D renderer, - TextRenderer textRenderer, - LivingEntity target, - float x, - float y, - float size, - float radius, - float alphaFactor, - float hurtPercent) { - int light = HudRenderUtil.scaleAlpha(HudRenderUtil.mixColor(uiBgSecondary, uiHealthEnd, 0.28f), alphaFactor); - int dark = HudRenderUtil.scaleAlpha(HudRenderUtil.mixColor(uiBgPrimary, 0xFF000000, 0.22f), alphaFactor); - renderer.roundedRectGradient(x, y, size, size, radius, 1.0f, light, dark, 90.0f); - renderer.roundedRectStroke( - x, y, size, size, radius, 1.0f, - 0.65f * size / FACE_SIZE, - HudRenderUtil.scaleAlpha(uiStroke, alphaFactor) - ); - - String name = target.getName().getString(); - String letter = name.isEmpty() ? "?" : name.substring(0, 1).toUpperCase(Locale.ROOT); - TextRenderer faceRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); - float textScale = PLACEHOLDER_TEXT_SCALE * scale.get().floatValue() * HudScale.scale( - mc.getWindow().getGuiScaledWidth(), - mc.getWindow().getGuiScaledHeight() - ); - faceRenderer.begin(textScale, false, false); - try { - float textWidth = (float) faceRenderer.getWidth(letter, false); - float textHeight = (float) faceRenderer.getHeight(false); - float tx = x + (size - textWidth) * 0.5f; - float ty = y + (size - textHeight) * 0.5f - scale.get().floatValue(); - int letterColor = HudRenderUtil.scaleAlpha( - HudRenderUtil.mixColor(uiTextPrimary, uiTextSecondary, hurtPercent * 0.35f), - alphaFactor - ); - faceRenderer.render(letter, tx, ty, new RenderColor(letterColor), false); - } finally { - faceRenderer.end(); - } - } - - private void drawContent(Renderer2D renderer, - TextRenderer textRenderer, - LivingEntity target, - float x, - float y, - float drawWidth, - float scaleFactor, - float alphaFactor, - long now, - float dt) { - float contentX = x + (FACE_X + FACE_SIZE + CONTENT_GAP + CONTENT_X_OFFSET) * scaleFactor; - float nameY = y + (NAME_Y + CONTENT_Y_OFFSET) * scaleFactor; - - PlayerHealthResolver.HealthSnapshot resolved = PlayerHealthResolver.resolve(target); - float health = Math.max(0.0f, resolved.totalHealth() - resolved.absorption()); - float maxHealth = Math.max(1.0f, target.getMaxHealth()); - float absorption = Math.max(0.0f, resolved.absorption()); - - float targetDisplayHealth = health + absorption; - displayedHealth = AnimationUtility.approach(displayedHealth, targetDisplayHealth, dt, HEALTH_SPEED); - displayedHealth = AnimationUtility.snap(displayedHealth, targetDisplayHealth, 0.02f); - if (targetDisplayHealth <= HEALTH_ZERO_CLAMP && displayedHealth <= HEALTH_ZERO_SNAP_THRESHOLD) { - displayedHealth = 0.0f; - } - - float targetHealthFraction = AnimationUtility.clamp01(health / maxHealth); - float targetAbsorptionFraction = AnimationUtility.clamp01(absorption / maxHealth); - healthAnimation = AnimationUtility.approach(healthAnimation, targetHealthFraction, dt, BAR_SPEED); - healthAnimation = AnimationUtility.snap(healthAnimation, targetHealthFraction, PROGRESS_SNAP_EPSILON); - if (targetHealthFraction > trailAnimation) { - trailAnimation = targetHealthFraction; - } - trailAnimation = AnimationUtility.approach(trailAnimation, targetHealthFraction, dt, BAR_SPEED - 0.5f); - trailAnimation = AnimationUtility.snap(trailAnimation, targetHealthFraction, PROGRESS_SNAP_EPSILON); - absorptionAnimation = AnimationUtility.approach(absorptionAnimation, targetAbsorptionFraction, dt, BAR_SPEED); - absorptionAnimation = AnimationUtility.snap(absorptionAnimation, targetAbsorptionFraction, PROGRESS_SNAP_EPSILON); - - boolean selfTarget = target == mc.player; - if (!selfTarget) { - float targetDistance = mc.player != null ? mc.player.distanceTo(target) : 0.0f; - displayedDistance = AnimationUtility.approach(displayedDistance, targetDistance, dt, DISTANCE_SPEED); - displayedDistance = AnimationUtility.snap(displayedDistance, targetDistance, 0.01f); - } - - String hpText = formatHealth(formatDisplayHealth(displayedHealth)); - String distanceText = selfTarget ? "" : formatDistance(displayedDistance) + "m"; - String moduleStatus = resolveModuleStatus(target); - String metaText = moduleStatus != null ? moduleStatus : distanceText; - float panelWidth = drawWidth - PANEL_INSET * 4f * scaleFactor; - TextRenderer labelRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); - TextRenderer metaRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); - boolean arcMode = isArcHealthMode(); - float hpTextScale = (arcMode ? ARC_HP_TEXT_SCALE : HP_TEXT_SCALE) * scaleFactor; - float hpWidth = measureText(labelRenderer, hpText, hpTextScale); - float contentReserve = arcMode - ? ARC_RESERVED_WIDTH * scaleFactor - : hpWidth + 12.0f * scaleFactor; - float maxNameWidth = Math.max(12.0f * scaleFactor, panelWidth - FACE_SIZE * scaleFactor - CONTENT_GAP * scaleFactor - contentReserve); - String rawName = target.getName().getString(); - String name = trimText(labelRenderer, rawName, maxNameWidth, NAME_TEXT_SCALE * scaleFactor); - String meta = trimText(metaRenderer, metaText, maxNameWidth, DISTANCE_TEXT_SCALE * scaleFactor); - float nameScale = NAME_TEXT_SCALE * scaleFactor; - float rawNameWidth = measureText(labelRenderer, rawName, nameScale); - boolean useMarquee = marquee.get() && rawNameWidth > maxNameWidth * 1.01f; - - int nameColor = HudRenderUtil.scaleAlpha(uiTextPrimary, alphaFactor); - int hpColor = HudRenderUtil.scaleAlpha(uiTextSecondary, alphaFactor); - int distanceColor = HudRenderUtil.scaleAlpha(uiTextSecondary, alphaFactor); - - if (useMarquee) { - drawScrollingText( - labelRenderer, - rawName, - contentX, - nameY, - rawNameWidth, - maxNameWidth, - nameScale, - scaleFactor, - alphaFactor, - nameColor - ); - } else { - labelRenderer.begin(nameScale, false, false); - try { - labelRenderer.render(name, contentX, nameY, new RenderColor(nameColor), false); - } finally { - labelRenderer.end(); - } - } - - if (arcMode) { - metaRenderer.begin(DISTANCE_TEXT_SCALE * scaleFactor, false, false); - try { - metaRenderer.render( - meta, - contentX, - nameY + DISTANCE_Y_OFFSET * scaleFactor, - new RenderColor(distanceColor), - false - ); - } finally { - metaRenderer.end(); - } - - drawHealthArc(renderer, textRenderer, x, y, panelWidth, scaleFactor, alphaFactor, hpText, hpColor, now); - return; - } - - labelRenderer.begin(HP_TEXT_SCALE * scaleFactor, false, false); - try { - float hpX = x + panelWidth - hpWidth + CONTENT_X_OFFSET * scaleFactor; - labelRenderer.render(hpText, hpX, nameY, new RenderColor(hpColor), false); - } finally { - labelRenderer.end(); - } - - float barX = contentX; - float barY = nameY + BAR_Y_OFFSET * scaleFactor; - float barWidth = BAR_WIDTH * scaleFactor; - float barHeight = BAR_HEIGHT * scaleFactor; - float barRadius = BAR_RADIUS * scaleFactor; - - renderer.roundedRect( - barX, barY, barWidth, barHeight, barRadius, 1.0f, - HudRenderUtil.scaleAlpha(uiBarBackground, alphaFactor) - ); - - float trailPercent = AnimationUtility.clamp01(trailAnimation); - float healthPercent = AnimationUtility.clamp01(healthAnimation); - if (trailPercent > healthPercent + 0.001f) { - float trailFade = tailFade(BAR_WIDTH * trailPercent, BAR_TAIL_FADE_LENGTH); - int trailColor = HudRenderUtil.scaleAlpha(uiTrail, alphaFactor * trailFade); - renderer.roundedProgressRectGradient( - barX, barY, barWidth, barHeight, barRadius, 1.0f, - trailPercent, false, trailColor, trailColor, 0.0f, 0.0f - ); - } - - long elapsedMs = Math.max(0L, now - waveStartMs); - - if (healthPercent > 0.0001f) { - float healthFade = tailFade(BAR_WIDTH * healthPercent, BAR_TAIL_FADE_LENGTH); - int[] healthWave = buildWaveColors(elapsedMs, 1500f, alphaFactor * healthFade, uiHealthStart, uiHealthEnd); - renderer.roundedProgressRectGradient( - barX, barY, barWidth, barHeight, barRadius, 1.0f, - healthPercent, false, healthWave[0], healthWave[2], 90.0f, 0.0f - ); - } - - float absorptionPercent = AnimationUtility.clamp01(absorptionAnimation); - if (absorptionPercent > 0.0001f) { - float absorptionFade = tailFade(BAR_WIDTH * absorptionPercent, BAR_TAIL_FADE_LENGTH); - int[] absorptionWave = buildWaveColors(elapsedMs, 1200f, alphaFactor * absorptionFade, uiAbsorptionStart, uiAbsorptionEnd); - renderer.roundedProgressRectGradient( - barX, barY, barWidth, barHeight, barRadius, 1.0f, - absorptionPercent, false, absorptionWave[0], absorptionWave[2], 90.0f, 0.0f - ); - } - } - - private String resolveModuleStatus(LivingEntity target) { - if (target == null) { - return null; - } - - AutoCrystal autoCrystal = Modules.get(AutoCrystal.class); - if (autoCrystal != null) { - String status = autoCrystal.getTargetHudStatus(target); - if (status != null && !status.isBlank()) { - return status; - } - } - - AutoAnchor autoAnchor = Modules.get(AutoAnchor.class); - if (autoAnchor != null) { - String status = autoAnchor.getTargetHudStatus(target); - if (status != null && !status.isBlank()) { - return status; - } - } - - AutoBed autoBed = Modules.get(AutoBed.class); - if (autoBed != null) { - String status = autoBed.getTargetHudStatus(target); - if (status != null && !status.isBlank()) { - return status; - } - } - - return null; - } - - private void drawScrollingText(TextRenderer renderer, - String text, - float x, - float y, - float fullWidth, - float viewWidth, - float scale, - float baseScale, - float alpha, - int color) { - float speed = BASE_NAME_SCROLL_SPEED * baseScale; - float gap = BASE_NAME_SCROLL_GAP * baseScale; - if (speed <= 0.0f) { - return; - } - - float cycleDistance = fullWidth + gap; - float cycleTime = NAME_SCROLL_PAUSE_SEC + (cycleDistance / speed); - if (cycleTime <= 0.0f) { - return; - } - - float now = Util.getMillis() / 1000.0f; - float t = now % cycleTime; - float offset = 0.0f; - if (t > NAME_SCROLL_PAUSE_SEC) { - offset = -(t - NAME_SCROLL_PAUSE_SEC) * speed; - } - - RenderColor renderColor = new RenderColor(HudRenderUtil.scaleAlpha(color, alpha)); - float fade = Math.min(viewWidth * 0.25f, BASE_NAME_FADE * baseScale); - renderer.begin(scale, false, false); - try { - renderer.renderHorizontalFadeClipped(text, x + offset, y, renderColor, x, x + viewWidth, fade, fade, false); - if (cycleDistance > viewWidth * 0.5f) { - renderer.renderHorizontalFadeClipped(text, x + offset + cycleDistance, y, renderColor, - x, x + viewWidth, fade, fade, false); - } - } finally { - renderer.end(); - } - } - - private float getTextHeight(TextRenderer renderer, float scale) { - renderer.begin(scale, false, false); - try { - return (float) renderer.getHeight(false); - } finally { - renderer.end(); - } - } - - private void drawHealthArc(Renderer2D renderer, - TextRenderer textRenderer, - float x, - float y, - float panelWidth, - float scaleFactor, - float alphaFactor, - String hpText, - int hpTextColor, - long now) { - float centerX = x + panelWidth - ARC_RIGHT_INSET * scaleFactor + CONTENT_X_OFFSET * scaleFactor; - float centerY = y + ARC_CENTER_Y * scaleFactor + CONTENT_Y_OFFSET * scaleFactor; - float radius = ARC_RADIUS * scaleFactor; - float thickness = ARC_THICKNESS * scaleFactor; - float softness = Math.max(0.35f, 0.45f * scaleFactor); - - int ringBackground = HudRenderUtil.scaleAlpha( - HudRenderUtil.mixColor(uiBarBackground, 0xFF000000, 0.34f), - alphaFactor * 0.55f - ); - renderer.arcStroke(centerX, centerY, radius, thickness, 0.0f, 360.0f, softness, ringBackground); - - float healthPercent = AnimationUtility.clamp01(healthAnimation); - - float healthSweep = 360.0f * healthPercent; - if (healthSweep > 0.001f) { - float healthFade = tailFade(healthSweep, ARC_TAIL_FADE_DEGREES); - drawAnimatedArcGradient( - renderer, - centerX, - centerY, - radius, - thickness, - 0.0f, - healthSweep, - softness, - alphaFactor * healthFade, - uiHealthStart, - uiHealthEnd, - uiHealthGradientAngle, - 1700f, - now - waveStartMs, - 0.0f - ); - } - - float absorptionPercent = AnimationUtility.clamp01(absorptionAnimation); - float absorptionSweep = 360.0f * absorptionPercent; - if (absorptionSweep > 0.001f) { - float absorptionThickness = Math.max(1.6f * scaleFactor, thickness * 0.9f); - float absorptionFade = tailFade(absorptionSweep, ARC_TAIL_FADE_DEGREES); - drawAnimatedArcGradient( - renderer, - centerX, - centerY, - radius, - absorptionThickness, - 0.0f, - absorptionSweep, - softness, - alphaFactor * absorptionFade, - uiAbsorptionStart, - uiAbsorptionEnd, - uiAbsorptionGradientAngle, - 1300f, - now - waveStartMs, - 1.35f - ); - } - - TextRenderer hpRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); - float hpScale = ARC_HP_TEXT_SCALE * scaleFactor; - hpRenderer.begin(hpScale, false, false); - try { - float textWidth = (float) hpRenderer.getWidth(hpText, false); - float textHeight = (float) hpRenderer.getHeight(false); - hpRenderer.render( - hpText, - centerX - textWidth * 0.5f, - centerY - textHeight * 0.5f, - new RenderColor(hpTextColor), - false - ); - } finally { - hpRenderer.end(); - } - } - - private void drawEquipment(Renderer2D renderer, - TextRenderer textRenderer, - GuiGraphicsExtractor ctx, - EquipmentLayout layout, - float x, - float y, - float panelWidth, - float equipmentHeight, - float scaleFactor, - float alphaFactor, - boolean glassEnabled) { - if (ctx == null || layout.entries().isEmpty() || alphaFactor <= 0.01f) { - return; - } - - float rowX = x + Math.max(0.0f, (panelWidth - layout.width()) * 0.5f); - float rowY = y + Math.max(0.0f, equipmentHeight - layout.height()) + (EQUIPMENT_ROW_Y_OFFSET * scaleFactor); - - float slotHeight = EQUIPMENT_SLOT * scaleFactor; - float radius = 2.2f * scaleFactor; - List itemTasks = new ArrayList<>(layout.entries().size()); - int slotFillLeft = HudRenderUtil.scaleAlpha( - HudRenderUtil.mixColor(uiBarBackground, uiBgPrimary, 0.34f), - alphaFactor - ); - int slotFillRight = HudRenderUtil.scaleAlpha( - HudRenderUtil.mixColor(uiBgSecondary, uiBarBackground, 0.24f), - alphaFactor * 0.96f - ); - int slotStroke = HudRenderUtil.scaleAlpha( - HudRenderUtil.mixColor(uiStroke, uiBgSecondary, 0.10f), - alphaFactor * 0.46f - ); - int slotHighlight = HudRenderUtil.scaleAlpha( - HudRenderUtil.mixColor(uiTextPrimary, uiBgPrimary, 0.88f), - alphaFactor * 0.08f - ); - float itemScale = Math.max(0.35f, (slotHeight - 3.0f * scaleFactor) / 16.0f); - float cursorX = rowX; - for (EquipmentEntry entry : layout.entries()) { - if (glassEnabled) { - drawGlassCard(cursorX, rowY, entry.width(), slotHeight, radius, scaleFactor, alphaFactor); - renderer.roundedRect(cursorX, rowY, entry.width(), slotHeight, radius, 1.0f, - HudRenderUtil.glassSmallBackground(alphaFactor)); - } else { - renderer.roundedRectGradientQuad( - cursorX, rowY, entry.width(), slotHeight, radius, 1.0f, - slotFillLeft, slotFillRight, slotFillRight, slotFillLeft - ); - renderer.roundedRectStroke(cursorX, rowY, entry.width(), slotHeight, radius, 1.0f, 0.5f * scaleFactor, slotStroke); - renderer.roundedRect( - cursorX + 0.75f * scaleFactor, - rowY + 0.75f * scaleFactor, - Math.max(0.0f, entry.width() - 1.5f * scaleFactor), - Math.max(0.6f, 0.75f * scaleFactor), - Math.max(0.5f, radius * 0.45f), - 1.0f, - slotHighlight - ); - } - - if (entry.stack() != null && !entry.stack().isEmpty()) { - float itemX = cursorX + 1.5f * scaleFactor; - float itemY = rowY + (slotHeight - 16.0f * itemScale) * 0.5f; - itemTasks.add(new EquipmentRenderTask(entry.stack(), itemX, itemY, itemScale)); - } else { - drawEmptyEquipmentCross(renderer, cursorX, rowY, entry.width(), slotHeight, scaleFactor, alphaFactor); - } - - cursorX += entry.width() + EQUIPMENT_GAP * scaleFactor; - } - if (!itemTasks.isEmpty()) { - int seed = 0; - for (EquipmentRenderTask task : itemTasks) { - drawItem(renderer, task.stack(), task.x(), task.y(), task.scale(), seed++, alphaFactor); - } - } - } - - private void drawEffects(Renderer2D renderer, - TextRenderer textRenderer, - EffectLayout layout, - float x, - float y, - float panelWidth, - float scaleFactor, - float alphaFactor, - boolean glassEnabled) { - if (layout.chips().isEmpty() || alphaFactor <= 0.01f) { - return; - } - - float chipHeight = EFFECTS_CHIP_HEIGHT * scaleFactor; - float rowX = x + (panelWidth - layout.width()) * 0.5f; - float rowY = y + (layout.height() - chipHeight) * 0.5f; - float radius = EFFECTS_CHIP_RADIUS * scaleFactor; - int fill = glassEnabled - ? HudRenderUtil.glassSmallBackground(alphaFactor) - : HudRenderUtil.scaleAlpha(HudRenderUtil.mixColor(uiBgPrimary, uiBgSecondary, 0.4f), alphaFactor); - int stroke = glassEnabled - ? 0 - : HudRenderUtil.scaleAlpha(uiStroke, alphaFactor * 0.5f); - int iconColor = HudRenderUtil.scaleAlpha(uiTextPrimary, alphaFactor); - int textColor = HudRenderUtil.scaleAlpha(uiTextSecondary, alphaFactor); - - TextRenderer chipRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); - float textScale = EFFECTS_TEXT_SCALE * scaleFactor; - float textHeight = 0.0f; - chipRenderer.begin(textScale, false, false); - try { - textHeight = (float) chipRenderer.getHeight(false); - float cursorX = rowX; - for (EffectChip chip : layout.chips()) { - if (glassEnabled) { - drawGlassCard(cursorX, rowY, chip.width(), chipHeight, radius, scaleFactor, alphaFactor); - } - renderer.roundedRect(cursorX, rowY, chip.width(), chipHeight, radius, 1.0f, fill); - if (!glassEnabled) { - renderer.roundedRectStroke(cursorX, rowY, chip.width(), chipHeight, radius, 1.0f, 0.45f * scaleFactor, stroke); - } - - float iconX = cursorX + EFFECTS_CHIP_PAD_X * scaleFactor; - float iconY = rowY + (chipHeight - EFFECTS_ICON_SIZE * scaleFactor) * 0.5f; - if (chip.iconId() != null) { - Renderer2D.TEXTURE.roundedTexRect( - iconX, - iconY, - EFFECTS_ICON_SIZE * scaleFactor, - EFFECTS_ICON_SIZE * scaleFactor, - 2.0f * scaleFactor, - 1.0f, - iconColor, - chip.iconId() - ); - } - - if (!chip.text().isEmpty()) { - float textX = iconX + EFFECTS_ICON_SIZE * scaleFactor + EFFECTS_TEXT_GAP * scaleFactor; - float textY = rowY + (chipHeight - textHeight) * 0.5f; - chipRenderer.render(chip.text(), textX, textY, new RenderColor(textColor), false); - } - - cursorX += chip.width() + EFFECTS_CHIP_GAP * scaleFactor; - } - } finally { - chipRenderer.end(); - } - } - - private void drawHitPulse(Renderer2D renderer, - float x, - float y, - float width, - float height, - float radius, - float alphaFactor, - float pulse) { - if (!hitAnim.get() || pulse <= 0.001f) return; - - float scaledPulse = pulse * hitPulse.get().floatValue(); - float spread = 6.0f * (0.65f + scaledPulse); - int outerColor = HudRenderUtil.scaleAlpha(uiHitOuter, 0.58f * scaledPulse * alphaFactor); - int innerColor = HudRenderUtil.scaleAlpha(uiHitInner, 0.92f * scaledPulse * alphaFactor); - - renderer.roundedRectStroke( - x - spread * 0.4f, - y - spread * 0.4f, - width + spread * 0.8f, - height + spread * 0.8f, - radius + spread * 0.15f, - 1.0f, - 0.85f + scaledPulse, - outerColor - ); - renderer.roundedRectStroke(x, y, width, height, radius, 1.0f, 0.9f + scaledPulse, innerColor); - } - - private void drawBlur(float x, float y, float width, float height, float radius, int tintRgb, float alphaFactor) { - if (!hasEffect() || width <= 0.0f || height <= 0.0f) return; - float quality = hud.getBlurRadius(); - float brightness = 1.0f; - float alpha = (blurAlpha.get() / 255.0f) * alphaFactor; - Renderer2D.COLOR.blurRect(x, y, width, height, radius, quality, brightness, alpha, 0xFFFFFF); - } - - private void drawGlass(float x, float y, float width, float height, float radius, float alphaFactor) { - float blurStrength = (blurAlpha.get() / 255.0f) * alphaFactor; - float glassAlpha = alphaFactor; - float glassScale = PANEL_RADIUS <= 0.0f ? 1.0f : radius / PANEL_RADIUS; - HudRenderUtil.drawLiquidGlass(x, y, width, height, radius, glassScale, true, blurStrength, glassAlpha); - } - - private void drawGlassCard(float x, - float y, - float width, - float height, - float radius, - float scaleFactor, - float alphaFactor) { - float blurStrength = (blurAlpha.get() / 255.0f) * alphaFactor; - HudRenderUtil.drawLiquidGlass(x, y, width, height, radius, scaleFactor, true, blurStrength, alphaFactor); - } - - private void drawItem(Renderer2D renderer, - ItemStack stack, - float x, - float y, - float itemScale, - int seed, - float alphaFactor) { - if (renderer == null || stack == null || stack.isEmpty() || alphaFactor <= 0.001f) { - return; - } - - double previousAlpha = renderer.getAlpha(); - renderer.setAlpha(previousAlpha * AnimationUtility.clamp01(alphaFactor)); - try { - renderer.item(stack, x, y, itemScale, seed, Renderer2D.ITEM_OVERLAY_NONE, null); - } finally { - renderer.setAlpha(previousAlpha); - } - } - - private float computeHitPulse(long now) { - if (displayTarget == null) return 0.0f; - Long hitAt = HIT_FLASH_MS_BY_ID.get(displayTarget.getId()); - if (hitAt == null) return 0.0f; - - float elapsed = now - hitAt; - if (elapsed >= HIT_FLASH_MS) { - HIT_FLASH_MS_BY_ID.remove(displayTarget.getId()); - return 0.0f; - } - float t = 1.0f - elapsed / HIT_FLASH_MS; - return AnimationUtility.easeOutCubic(AnimationUtility.clamp01(t)); - } - - private EquipmentLayout buildEquipmentLayout(LivingEntity target, - boolean preview, - TextRenderer textRenderer, - float scale) { - if (!isEquipmentEnabled() || target == null || textRenderer == null || scale <= 0.0f) { - return new EquipmentLayout(List.of(), 0.0f, 0.0f); - } - - List entries = collectEquipmentEntries(target, preview, textRenderer, scale); - if (entries.isEmpty()) { - return new EquipmentLayout(List.of(), 0.0f, 0.0f); - } - - float totalWidth = 0.0f; - for (int i = 0; i < entries.size(); i++) { - totalWidth += entries.get(i).width(); - if (i < entries.size() - 1) { - totalWidth += EQUIPMENT_GAP * scale; - } - } - float totalHeight = EQUIPMENT_TOP_GAP * scale + EQUIPMENT_SLOT * scale + EQUIPMENT_BOTTOM_PAD * scale; - return new EquipmentLayout(entries, totalWidth, totalHeight); - } - - private EffectLayout buildEffectLayout(LivingEntity target, - boolean preview, - TextRenderer textRenderer, - float scale) { - if (!isEffectsEnabled() || target == null || textRenderer == null || scale <= 0.0f) { - return new EffectLayout(List.of(), 0.0f, 0.0f); - } - - List effects = collectTargetEffects(target, preview); - if (effects.isEmpty()) { - return new EffectLayout(List.of(), 0.0f, 0.0f); - } - - List chips = new ArrayList<>(); - TextRenderer chipRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); - float textScale = EFFECTS_TEXT_SCALE * scale; - int limit = Math.min(4, effects.size()); - float totalWidth = 0.0f; - - for (int i = 0; i < limit; i++) { - MobEffectInstance inst = effects.get(i); - Identifier iconId = resolveEffectIcon(inst); - String text = compactEffectText(target.getId(), inst); - float width = EFFECTS_CHIP_PAD_X * 2.0f * scale + EFFECTS_ICON_SIZE * scale; - if (!text.isEmpty()) { - width += EFFECTS_TEXT_GAP * scale + measureText(chipRenderer, text, textScale); - } - chips.add(new EffectChip(inst, iconId, text, width)); - totalWidth += width; - if (i < limit - 1) { - totalWidth += EFFECTS_CHIP_GAP * scale; - } - } - - float totalHeight = (EFFECTS_CHIP_HEIGHT + EFFECTS_PANEL_GAP) * scale; - return new EffectLayout(chips, totalWidth, totalHeight); - } - - private List collectEquipmentEntries(LivingEntity target, - boolean preview, - TextRenderer textRenderer, - float scale) { - List entries = new ArrayList<>(); - - if (preview) { - ItemStack sword = new ItemStack(Items.DIAMOND_SWORD); - ItemStack apple = new ItemStack(Items.GOLDEN_APPLE); - ItemStack head = new ItemStack(Items.DIAMOND_HELMET); - ItemStack chest = new ItemStack(Items.DIAMOND_CHESTPLATE); - ItemStack legs = new ItemStack(Items.DIAMOND_LEGGINGS); - ItemStack feet = new ItemStack(Items.DIAMOND_BOOTS); - - sword.setDamageValue(Math.max(1, sword.getMaxDamage() / 6)); - head.setDamageValue(Math.max(1, head.getMaxDamage() / 3)); - chest.setDamageValue(Math.max(1, chest.getMaxDamage() / 2)); - legs.setDamageValue(Math.max(1, legs.getMaxDamage() / 4)); - feet.setDamageValue(Math.max(1, feet.getMaxDamage() / 5)); - - addEquipmentEntry(entries, sword, scale); - addEquipmentEntry(entries, apple, scale); - addEquipmentEntry(entries, head, scale); - addEquipmentEntry(entries, chest, scale); - addEquipmentEntry(entries, legs, scale); - addEquipmentEntry(entries, feet, scale); - return entries; - } - - addEquipmentEntry(entries, target.getMainHandItem(), scale); - addEquipmentEntry(entries, target.getOffhandItem(), scale); - addEquipmentEntry(entries, target.getItemBySlot(EquipmentSlot.HEAD), scale); - addEquipmentEntry(entries, target.getItemBySlot(EquipmentSlot.CHEST), scale); - addEquipmentEntry(entries, target.getItemBySlot(EquipmentSlot.LEGS), scale); - addEquipmentEntry(entries, target.getItemBySlot(EquipmentSlot.FEET), scale); - return entries; - } - - private void addEquipmentEntry(List entries, - ItemStack stack, - float scale) { - float baseWidth = EQUIPMENT_SLOT * scale; - entries.add(new EquipmentEntry(stack == null ? ItemStack.EMPTY : stack, baseWidth)); - } - - private List collectTargetEffects(LivingEntity target, boolean preview) { - if (target == null) { - return List.of(); - } - if (target == mc.player && !effectsSelf.get() && !preview) { - return List.of(); - } - if (target instanceof Player player) { - StatusEffectView.sync(mc); - List effects = StatusEffectView.collectHudEffects(player); - if (!effects.isEmpty() || !preview) { - return effects; - } - } else { - List direct = new ArrayList<>(target.getActiveEffects()); - if (!direct.isEmpty()) { - return direct; - } - } - - if (!preview) { - return List.of(); - } - - List sample = new ArrayList<>(); - sample.add(new MobEffectInstance(net.minecraft.world.effect.MobEffects.STRENGTH, 2450, 1)); - sample.add(new MobEffectInstance(net.minecraft.world.effect.MobEffects.FIRE_RESISTANCE, 1640, 0)); - sample.add(new MobEffectInstance(net.minecraft.world.effect.MobEffects.RESISTANCE, 920, 0)); - return sample; - } - - private Identifier resolveEffectIcon(MobEffectInstance inst) { - if (inst == null) { - return null; - } - return inst.getEffect().unwrapKey() - .map(key -> Identifier.fromNamespaceAndPath("minecraft", "textures/mob_effect/" + key.identifier().getPath() + ".png")) - .orElse(null); - } - - private String compactEffectText(int entityId, MobEffectInstance inst) { - if (inst == null) { - return ""; - } - String duration = formatEffectDuration(entityId, inst); - if (!duration.isEmpty()) { - return duration; - } - int level = inst.getAmplifier() + 1; - return level > 1 ? roman(level) : ""; - } - - private String formatEffectDuration(int entityId, MobEffectInstance inst) { - if (inst == null) { - return ""; - } - if (StatusEffectTracker.shouldHideDuration(entityId, inst.getEffect())) { - return ""; - } - int ticks = inst.getDuration(); - if (ticks < 0 || ticks >= 32767) { - return ""; - } - int totalSeconds = Math.max(0, ticks / 20); - int minutes = totalSeconds / 60; - int seconds = totalSeconds % 60; - return seconds < 10 ? minutes + ":0" + seconds : minutes + ":" + seconds; - } - - private String roman(int n) { - return switch (n) { - case 1 -> "I"; - case 2 -> "II"; - case 3 -> "III"; - case 4 -> "IV"; - case 5 -> "V"; - default -> Integer.toString(n); - }; - } - - private boolean isThemeMode() { + boolean isThemeMode() { return COLOR_THEME.equals(colorMode.get()); } - private boolean isCustomMode() { + boolean isCustomMode() { return COLOR_CUSTOM.equals(colorMode.get()); } - private boolean hasEffect() { + boolean hasEffect() { return !EFFECT_NONE.equals(bgEffect.get()); } - private boolean isBlurEffect() { + boolean isBlurEffect() { return EFFECT_BLUR.equals(bgEffect.get()); } - private boolean isGlassEffect() { + boolean isGlassEffect() { return EFFECT_GLASS.equals(bgEffect.get()); } - private boolean isEffectsEnabled() { + boolean isEffectsEnabled() { return !EFFECTS_OFF.equals(effectsMode.get()); } - private boolean isEquipmentEnabled() { + boolean isEquipmentEnabled() { return !EQUIPMENT_OFF.equals(equipmentMode.get()); } - private boolean isArcHealthMode() { + boolean isArcHealthMode() { return HP_MODE_ARC.equals(hpMode.get()); } - - private void drawEmptyEquipmentCross(Renderer2D renderer, - float x, - float y, - float width, - float height, - float scaleFactor, - float alphaFactor) { - float inset = Math.max(2.0f * scaleFactor, width * 0.28f); - float stroke = Math.max(0.6f, 0.85f * scaleFactor); - int color = HudRenderUtil.scaleAlpha(uiTextSecondary, alphaFactor); - renderer.line(x + inset, y + inset, x + width - inset, y + height - inset, color); - renderer.line(x + width - inset, y + inset, x + inset, y + height - inset, color); - if (stroke > 1.0f) { - float nudge = stroke * 0.35f; - renderer.line(x + inset + nudge, y + inset, x + width - inset + nudge, y + height - inset, color); - renderer.line(x + width - inset - nudge, y + inset, x + inset - nudge, y + height - inset, color); - } - } - - private record EquipmentEntry(ItemStack stack, float width) { - } - - private record EquipmentLayout(List entries, float width, float height) { - } - - private record EquipmentRenderTask(ItemStack stack, float x, float y, float scale) { - } - - private record EffectChip(MobEffectInstance effect, Identifier iconId, String text, float width) { - } - - private record EffectLayout(List chips, float width, float height) { - } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudArcRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudArcRenderer.java new file mode 100644 index 0000000..915905d --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudArcRenderer.java @@ -0,0 +1,179 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.FontInfo; +import dev.loki.lovisual.render.engine.text.Fonts; +import dev.loki.lovisual.render.engine.text.TextRenderer; + +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud.*; + +final class TargetHudArcRenderer { + + private TargetHudArcRenderer() { + } + + static void drawHealthArc(TargetHud element, + Renderer2D renderer, + TextRenderer textRenderer, + float x, + float y, + float panelWidth, + float scaleFactor, + float alphaFactor, + String hpText, + int hpTextColor, + long now) { + float centerX = x + panelWidth - ARC_RIGHT_INSET * scaleFactor + CONTENT_X_OFFSET * scaleFactor; + float centerY = y + ARC_CENTER_Y * scaleFactor + CONTENT_Y_OFFSET * scaleFactor; + float radius = ARC_RADIUS * scaleFactor; + float thickness = ARC_THICKNESS * scaleFactor; + float softness = Math.max(0.35f, 0.45f * scaleFactor); + + int ringBackground = HudRenderUtil.scaleAlpha( + HudRenderUtil.mixColor(element.uiBarBackground, 0xFF000000, 0.34f), + alphaFactor * 0.55f + ); + renderer.arcStroke(centerX, centerY, radius, thickness, 0.0f, 360.0f, softness, ringBackground); + + float healthPercent = AnimationUtility.clamp01(element.healthAnimation); + + float healthSweep = 360.0f * healthPercent; + if (healthSweep > 0.001f) { + float healthFade = tailFade(healthSweep, ARC_TAIL_FADE_DEGREES); + drawAnimatedArcGradient( + renderer, + centerX, + centerY, + radius, + thickness, + 0.0f, + healthSweep, + softness, + alphaFactor * healthFade, + element.uiHealthStart, + element.uiHealthEnd, + element.uiHealthGradientAngle, + 1700f, + now - element.waveStartMs, + 0.0f + ); + } + + float absorptionPercent = AnimationUtility.clamp01(element.absorptionAnimation); + float absorptionSweep = 360.0f * absorptionPercent; + if (absorptionSweep > 0.001f) { + float absorptionThickness = Math.max(1.6f * scaleFactor, thickness * 0.9f); + float absorptionFade = tailFade(absorptionSweep, ARC_TAIL_FADE_DEGREES); + drawAnimatedArcGradient( + renderer, + centerX, + centerY, + radius, + absorptionThickness, + 0.0f, + absorptionSweep, + softness, + alphaFactor * absorptionFade, + element.uiAbsorptionStart, + element.uiAbsorptionEnd, + element.uiAbsorptionGradientAngle, + 1300f, + now - element.waveStartMs, + 1.35f + ); + } + + TextRenderer hpRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); + float hpScale = ARC_HP_TEXT_SCALE * scaleFactor; + hpRenderer.begin(hpScale, false, false); + try { + float textWidth = (float) hpRenderer.getWidth(hpText, false); + float textHeight = (float) hpRenderer.getHeight(false); + hpRenderer.render( + hpText, + centerX - textWidth * 0.5f, + centerY - textHeight * 0.5f, + new RenderColor(hpTextColor), + false + ); + } finally { + hpRenderer.end(); + } + } + + static void drawAnimatedArcGradient(Renderer2D renderer, + float centerX, + float centerY, + float radius, + float thickness, + float startAngle, + float sweep, + float softness, + float alphaFactor, + int startColor, + int endColor, + float baseAngle, + float speedMs, + long elapsedMs, + float phaseOffset) { + float safeSpeed = Math.max(1.0f, speedMs); + float phase = (elapsedMs / safeSpeed) * (float) Math.PI * 2.0f + phaseOffset; + float animatedAngle = baseAngle + + (elapsedMs / safeSpeed) * 92.0f + + (float) Math.sin(phase * 0.63f) * 26.0f; + float pulseA = ((float) Math.sin(phase) + 1.0f) * 0.5f; + float pulseB = ((float) Math.sin(phase + 1.95f) + 1.0f) * 0.5f; + + int c0 = HudRenderUtil.mixColor(startColor, endColor, pulseA * 0.24f); + int c1 = HudRenderUtil.mixColor(endColor, startColor, pulseB * 0.18f); + int drawStart = HudRenderUtil.scaleAlpha(c0, alphaFactor); + int drawEnd = HudRenderUtil.scaleAlpha(c1, alphaFactor); + float offsetPx = (float) Math.sin(phase * 0.71f) * radius * 0.58f; + + renderer.arcStrokeGradient( + centerX, + centerY, + radius, + thickness, + startAngle, + startAngle + sweep, + softness, + drawStart, + drawEnd, + animatedAngle, + offsetPx + ); + + } + + static int[] buildWaveColors(long elapsedMs, + float waveSpeedMs, + float alphaFactor, + int startColor, + int endColor) { + float phase = (elapsedMs % (long) waveSpeedMs) / waveSpeedMs * (float) Math.PI * 2.0f; + int[] colors = new int[4]; + for (int i = 0; i < 2; i++) { + float wave = ((float) Math.sin(phase - i * 1.5f) + 1.0f) * 0.5f; + int mixed = HudRenderUtil.mixColor(startColor, endColor, wave); + colors[i * 2] = HudRenderUtil.scaleAlpha(mixed, alphaFactor); + colors[i * 2 + 1] = colors[i * 2]; + } + return colors; + } + + static float tailFade(float visibleLength, float fadeLength) { + if (fadeLength <= 0.0f) return visibleLength > 0.0f ? 1.0f : 0.0f; + return AnimationUtility.smoothstep(AnimationUtility.clamp01(visibleLength / fadeLength)); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudContentRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudContentRenderer.java new file mode 100644 index 0000000..74de54c --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudContentRenderer.java @@ -0,0 +1,193 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.FontInfo; +import dev.loki.lovisual.render.engine.text.Fonts; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.player.PlayerHealthResolver; +import net.minecraft.world.entity.LivingEntity; + +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud.*; +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHudFormatter.*; + +final class TargetHudContentRenderer { + + private TargetHudContentRenderer() { + } + + static void drawContent(TargetHud element, + Renderer2D renderer, + TextRenderer textRenderer, + LivingEntity target, + float x, + float y, + float drawWidth, + float scaleFactor, + float alphaFactor, + long now, + float dt) { + float contentX = x + (FACE_X + FACE_SIZE + CONTENT_GAP + CONTENT_X_OFFSET) * scaleFactor; + float nameY = y + (NAME_Y + CONTENT_Y_OFFSET) * scaleFactor; + + PlayerHealthResolver.HealthSnapshot resolved = PlayerHealthResolver.resolve(target); + float health = Math.max(0.0f, resolved.totalHealth() - resolved.absorption()); + float maxHealth = Math.max(1.0f, target.getMaxHealth()); + float absorption = Math.max(0.0f, resolved.absorption()); + + float targetDisplayHealth = health + absorption; + element.displayedHealth = AnimationUtility.approach(element.displayedHealth, targetDisplayHealth, dt, HEALTH_SPEED); + element.displayedHealth = AnimationUtility.snap(element.displayedHealth, targetDisplayHealth, 0.02f); + if (targetDisplayHealth <= HEALTH_ZERO_CLAMP && element.displayedHealth <= HEALTH_ZERO_SNAP_THRESHOLD) { + element.displayedHealth = 0.0f; + } + + float targetHealthFraction = AnimationUtility.clamp01(health / maxHealth); + float targetAbsorptionFraction = AnimationUtility.clamp01(absorption / maxHealth); + element.healthAnimation = AnimationUtility.approach(element.healthAnimation, targetHealthFraction, dt, BAR_SPEED); + element.healthAnimation = AnimationUtility.snap(element.healthAnimation, targetHealthFraction, PROGRESS_SNAP_EPSILON); + if (targetHealthFraction > element.trailAnimation) { + element.trailAnimation = targetHealthFraction; + } + element.trailAnimation = AnimationUtility.approach(element.trailAnimation, targetHealthFraction, dt, BAR_SPEED - 0.5f); + element.trailAnimation = AnimationUtility.snap(element.trailAnimation, targetHealthFraction, PROGRESS_SNAP_EPSILON); + element.absorptionAnimation = AnimationUtility.approach(element.absorptionAnimation, targetAbsorptionFraction, dt, BAR_SPEED); + element.absorptionAnimation = AnimationUtility.snap(element.absorptionAnimation, targetAbsorptionFraction, PROGRESS_SNAP_EPSILON); + + boolean selfTarget = target == element.mc.player; + if (!selfTarget) { + float targetDistance = element.mc.player != null ? element.mc.player.distanceTo(target) : 0.0f; + element.displayedDistance = AnimationUtility.approach(element.displayedDistance, targetDistance, dt, DISTANCE_SPEED); + element.displayedDistance = AnimationUtility.snap(element.displayedDistance, targetDistance, 0.01f); + } + + String hpText = formatHealth(formatDisplayHealth(element.displayedHealth)); + String distanceText = selfTarget ? "" : formatDistance(element.displayedDistance) + "m"; + String moduleStatus = resolveModuleStatus(); + String metaText = moduleStatus != null ? moduleStatus : distanceText; + float panelWidth = drawWidth - PANEL_INSET * 4f * scaleFactor; + TextRenderer labelRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); + TextRenderer metaRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); + boolean arcMode = element.isArcHealthMode(); + float hpTextScale = (arcMode ? ARC_HP_TEXT_SCALE : HP_TEXT_SCALE) * scaleFactor; + float hpWidth = TargetHudTextRenderer.measureText(labelRenderer, hpText, hpTextScale); + float contentReserve = arcMode + ? ARC_RESERVED_WIDTH * scaleFactor + : hpWidth + 12.0f * scaleFactor; + float maxNameWidth = Math.max(12.0f * scaleFactor, panelWidth - FACE_SIZE * scaleFactor - CONTENT_GAP * scaleFactor - contentReserve); + String rawName = target.getName().getString(); + String name = TargetHudTextRenderer.trimText(labelRenderer, rawName, maxNameWidth, NAME_TEXT_SCALE * scaleFactor); + String meta = TargetHudTextRenderer.trimText(metaRenderer, metaText, maxNameWidth, DISTANCE_TEXT_SCALE * scaleFactor); + float nameScale = NAME_TEXT_SCALE * scaleFactor; + float rawNameWidth = TargetHudTextRenderer.measureText(labelRenderer, rawName, nameScale); + boolean useMarquee = element.marquee.get() && rawNameWidth > maxNameWidth * 1.01f; + + int nameColor = HudRenderUtil.scaleAlpha(element.uiTextPrimary, alphaFactor); + int hpColor = HudRenderUtil.scaleAlpha(element.uiTextSecondary, alphaFactor); + int distanceColor = HudRenderUtil.scaleAlpha(element.uiTextSecondary, alphaFactor); + + if (useMarquee) { + TargetHudTextRenderer.drawScrollingText( + labelRenderer, + rawName, + contentX, + nameY, + rawNameWidth, + maxNameWidth, + nameScale, + scaleFactor, + alphaFactor, + nameColor + ); + } else { + labelRenderer.begin(nameScale, false, false); + try { + labelRenderer.render(name, contentX, nameY, new RenderColor(nameColor), false); + } finally { + labelRenderer.end(); + } + } + + if (arcMode) { + metaRenderer.begin(DISTANCE_TEXT_SCALE * scaleFactor, false, false); + try { + metaRenderer.render( + meta, + contentX, + nameY + DISTANCE_Y_OFFSET * scaleFactor, + new RenderColor(distanceColor), + false + ); + } finally { + metaRenderer.end(); + } + + TargetHudArcRenderer.drawHealthArc(element, renderer, textRenderer, x, y, panelWidth, scaleFactor, alphaFactor, hpText, hpColor, now); + return; + } + + labelRenderer.begin(HP_TEXT_SCALE * scaleFactor, false, false); + try { + float hpX = x + panelWidth - hpWidth + CONTENT_X_OFFSET * scaleFactor; + labelRenderer.render(hpText, hpX, nameY, new RenderColor(hpColor), false); + } finally { + labelRenderer.end(); + } + + float barX = contentX; + float barY = nameY + BAR_Y_OFFSET * scaleFactor; + float barWidth = BAR_WIDTH * scaleFactor; + float barHeight = BAR_HEIGHT * scaleFactor; + float barRadius = BAR_RADIUS * scaleFactor; + + renderer.roundedRect( + barX, barY, barWidth, barHeight, barRadius, 1.0f, + HudRenderUtil.scaleAlpha(element.uiBarBackground, alphaFactor) + ); + + float trailPercent = AnimationUtility.clamp01(element.trailAnimation); + float healthPercent = AnimationUtility.clamp01(element.healthAnimation); + if (trailPercent > healthPercent + 0.001f) { + float trailFade = TargetHudArcRenderer.tailFade(BAR_WIDTH * trailPercent, BAR_TAIL_FADE_LENGTH); + int trailColor = HudRenderUtil.scaleAlpha(element.uiTrail, alphaFactor * trailFade); + renderer.roundedProgressRectGradient( + barX, barY, barWidth, barHeight, barRadius, 1.0f, + trailPercent, false, trailColor, trailColor, 0.0f, 0.0f + ); + } + + long elapsedMs = Math.max(0L, now - element.waveStartMs); + + if (healthPercent > 0.0001f) { + float healthFade = TargetHudArcRenderer.tailFade(BAR_WIDTH * healthPercent, BAR_TAIL_FADE_LENGTH); + int[] healthWave = TargetHudArcRenderer.buildWaveColors(elapsedMs, 1500f, alphaFactor * healthFade, element.uiHealthStart, element.uiHealthEnd); + renderer.roundedProgressRectGradient( + barX, barY, barWidth, barHeight, barRadius, 1.0f, + healthPercent, false, healthWave[0], healthWave[2], 90.0f, 0.0f + ); + } + + float absorptionPercent = AnimationUtility.clamp01(element.absorptionAnimation); + if (absorptionPercent > 0.0001f) { + float absorptionFade = TargetHudArcRenderer.tailFade(BAR_WIDTH * absorptionPercent, BAR_TAIL_FADE_LENGTH); + int[] absorptionWave = TargetHudArcRenderer.buildWaveColors(elapsedMs, 1200f, alphaFactor * absorptionFade, element.uiAbsorptionStart, element.uiAbsorptionEnd); + renderer.roundedProgressRectGradient( + barX, barY, barWidth, barHeight, barRadius, 1.0f, + absorptionPercent, false, absorptionWave[0], absorptionWave[2], 90.0f, 0.0f + ); + } + } + + private static String resolveModuleStatus() { + return null; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudEffectsRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudEffectsRenderer.java new file mode 100644 index 0000000..8c8d4bb --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudEffectsRenderer.java @@ -0,0 +1,173 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.FontInfo; +import dev.loki.lovisual.render.engine.text.Fonts; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.player.effect.StatusEffectView; +import net.minecraft.resources.Identifier; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; + +import java.util.ArrayList; +import java.util.List; + +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud.*; +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHudFormatter.*; + +final class TargetHudEffectsRenderer { + + private TargetHudEffectsRenderer() { + } + + static EffectLayout buildEffectLayout(TargetHud element, + LivingEntity target, + boolean preview, + TextRenderer textRenderer, + float scale) { + if (!element.isEffectsEnabled() || target == null || textRenderer == null || scale <= 0.0f) { + return new EffectLayout(List.of(), 0.0f, 0.0f); + } + + List effects = collectTargetEffects(element, target, preview); + if (effects.isEmpty()) { + return new EffectLayout(List.of(), 0.0f, 0.0f); + } + + List chips = new ArrayList<>(); + TextRenderer chipRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); + float textScale = EFFECTS_TEXT_SCALE * scale; + int limit = Math.min(4, effects.size()); + float totalWidth = 0.0f; + + for (int i = 0; i < limit; i++) { + MobEffectInstance inst = effects.get(i); + Identifier iconId = resolveEffectIcon(inst); + String text = compactEffectText(target.getId(), inst); + float width = EFFECTS_CHIP_PAD_X * 2.0f * scale + EFFECTS_ICON_SIZE * scale; + if (!text.isEmpty()) { + width += EFFECTS_TEXT_GAP * scale + TargetHudTextRenderer.measureText(chipRenderer, text, textScale); + } + chips.add(new EffectChip(inst, iconId, text, width)); + totalWidth += width; + if (i < limit - 1) { + totalWidth += EFFECTS_CHIP_GAP * scale; + } + } + + float totalHeight = (EFFECTS_CHIP_HEIGHT + EFFECTS_PANEL_GAP) * scale; + return new EffectLayout(chips, totalWidth, totalHeight); + } + + static void drawEffects(TargetHud element, + Renderer2D renderer, + TextRenderer textRenderer, + EffectLayout layout, + float x, + float y, + float panelWidth, + float scaleFactor, + float alphaFactor, + boolean glassEnabled) { + if (layout.chips().isEmpty() || alphaFactor <= 0.01f) { + return; + } + + float chipHeight = EFFECTS_CHIP_HEIGHT * scaleFactor; + float rowX = x + (panelWidth - layout.width()) * 0.5f; + float rowY = y + (layout.height() - chipHeight) * 0.5f; + float radius = EFFECTS_CHIP_RADIUS * scaleFactor; + int fill = glassEnabled + ? HudRenderUtil.glassSmallBackground(alphaFactor) + : HudRenderUtil.scaleAlpha(HudRenderUtil.mixColor(element.uiBgPrimary, element.uiBgSecondary, 0.4f), alphaFactor); + int stroke = glassEnabled + ? 0 + : HudRenderUtil.scaleAlpha(element.uiStroke, alphaFactor * 0.5f); + int iconColor = HudRenderUtil.scaleAlpha(element.uiTextPrimary, alphaFactor); + int textColor = HudRenderUtil.scaleAlpha(element.uiTextSecondary, alphaFactor); + + TextRenderer chipRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); + float textScale = EFFECTS_TEXT_SCALE * scaleFactor; + float textHeight = 0.0f; + chipRenderer.begin(textScale, false, false); + try { + textHeight = (float) chipRenderer.getHeight(false); + float cursorX = rowX; + for (EffectChip chip : layout.chips()) { + if (glassEnabled) { + TargetHudPanelRenderer.drawGlassCard(element, cursorX, rowY, chip.width(), chipHeight, radius, scaleFactor, alphaFactor); + } + renderer.roundedRect(cursorX, rowY, chip.width(), chipHeight, radius, 1.0f, fill); + if (!glassEnabled) { + renderer.roundedRectStroke(cursorX, rowY, chip.width(), chipHeight, radius, 1.0f, 0.45f * scaleFactor, stroke); + } + + float iconX = cursorX + EFFECTS_CHIP_PAD_X * scaleFactor; + float iconY = rowY + (chipHeight - EFFECTS_ICON_SIZE * scaleFactor) * 0.5f; + if (chip.iconId() != null) { + Renderer2D.TEXTURE.roundedTexRect( + iconX, + iconY, + EFFECTS_ICON_SIZE * scaleFactor, + EFFECTS_ICON_SIZE * scaleFactor, + 2.0f * scaleFactor, + 1.0f, + iconColor, + chip.iconId() + ); + } + + if (!chip.text().isEmpty()) { + float textX = iconX + EFFECTS_ICON_SIZE * scaleFactor + EFFECTS_TEXT_GAP * scaleFactor; + float textY = rowY + (chipHeight - textHeight) * 0.5f; + chipRenderer.render(chip.text(), textX, textY, new RenderColor(textColor), false); + } + + cursorX += chip.width() + EFFECTS_CHIP_GAP * scaleFactor; + } + } finally { + chipRenderer.end(); + } + } + + private static List collectTargetEffects(TargetHud element, LivingEntity target, boolean preview) { + if (target == null) { + return List.of(); + } + if (target == element.mc.player && !element.effectsSelf.get() && !preview) { + return List.of(); + } + if (target instanceof Player player) { + StatusEffectView.sync(element.mc); + List effects = StatusEffectView.collectHudEffects(player); + if (!effects.isEmpty() || !preview) { + return effects; + } + } else { + List direct = new ArrayList<>(target.getActiveEffects()); + if (!direct.isEmpty()) { + return direct; + } + } + + if (!preview) { + return List.of(); + } + + List sample = new ArrayList<>(); + sample.add(new MobEffectInstance(net.minecraft.world.effect.MobEffects.STRENGTH, 2450, 1)); + sample.add(new MobEffectInstance(net.minecraft.world.effect.MobEffects.FIRE_RESISTANCE, 1640, 0)); + sample.add(new MobEffectInstance(net.minecraft.world.effect.MobEffects.RESISTANCE, 920, 0)); + return sample; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudEquipmentRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudEquipmentRenderer.java new file mode 100644 index 0000000..31d224c --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudEquipmentRenderer.java @@ -0,0 +1,195 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +import java.util.ArrayList; +import java.util.List; + +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud.*; + +final class TargetHudEquipmentRenderer { + + private TargetHudEquipmentRenderer() { + } + + static EquipmentLayout buildEquipmentLayout(TargetHud element, LivingEntity target, boolean preview, TextRenderer textRenderer, float scale) { + if (!element.isEquipmentEnabled() || target == null || textRenderer == null || scale <= 0.0f) { + return new EquipmentLayout(List.of(), 0.0f, 0.0f); + } + + List entries = collectEquipmentEntries(target, preview, textRenderer, scale); + if (entries.isEmpty()) { + return new EquipmentLayout(List.of(), 0.0f, 0.0f); + } + + float totalWidth = 0.0f; + for (int i = 0; i < entries.size(); i++) { + totalWidth += entries.get(i).width(); + if (i < entries.size() - 1) { + totalWidth += EQUIPMENT_GAP * scale; + } + } + float totalHeight = EQUIPMENT_TOP_GAP * scale + EQUIPMENT_SLOT * scale + EQUIPMENT_BOTTOM_PAD * scale; + return new EquipmentLayout(entries, totalWidth, totalHeight); + } + + private static List collectEquipmentEntries(LivingEntity target, boolean preview, TextRenderer textRenderer, float scale) { + List entries = new ArrayList<>(); + + if (preview) { + ItemStack sword = new ItemStack(Items.DIAMOND_SWORD); + ItemStack apple = new ItemStack(Items.GOLDEN_APPLE); + ItemStack head = new ItemStack(Items.DIAMOND_HELMET); + ItemStack chest = new ItemStack(Items.DIAMOND_CHESTPLATE); + ItemStack legs = new ItemStack(Items.DIAMOND_LEGGINGS); + ItemStack feet = new ItemStack(Items.DIAMOND_BOOTS); + + sword.setDamageValue(Math.max(1, sword.getMaxDamage() / 6)); + head.setDamageValue(Math.max(1, head.getMaxDamage() / 3)); + chest.setDamageValue(Math.max(1, chest.getMaxDamage() / 2)); + legs.setDamageValue(Math.max(1, legs.getMaxDamage() / 4)); + feet.setDamageValue(Math.max(1, feet.getMaxDamage() / 5)); + + addEquipmentEntry(entries, sword, scale); + addEquipmentEntry(entries, apple, scale); + addEquipmentEntry(entries, head, scale); + addEquipmentEntry(entries, chest, scale); + addEquipmentEntry(entries, legs, scale); + addEquipmentEntry(entries, feet, scale); + return entries; + } + + addEquipmentEntry(entries, target.getMainHandItem(), scale); + addEquipmentEntry(entries, target.getOffhandItem(), scale); + addEquipmentEntry(entries, target.getItemBySlot(EquipmentSlot.HEAD), scale); + addEquipmentEntry(entries, target.getItemBySlot(EquipmentSlot.CHEST), scale); + addEquipmentEntry(entries, target.getItemBySlot(EquipmentSlot.LEGS), scale); + addEquipmentEntry(entries, target.getItemBySlot(EquipmentSlot.FEET), scale); + return entries; + } + + private static void addEquipmentEntry(List entries, ItemStack stack, float scale) { + float baseWidth = EQUIPMENT_SLOT * scale; + entries.add(new EquipmentEntry(stack == null ? ItemStack.EMPTY : stack, baseWidth)); + } + + static void drawEquipment(TargetHud element, Renderer2D renderer, TextRenderer textRenderer, GuiGraphicsExtractor ctx, + EquipmentLayout layout, float x, float y, float panelWidth, float equipmentHeight, + float scaleFactor, float alphaFactor, boolean glassEnabled) { + if (ctx == null || layout.entries().isEmpty() || alphaFactor <= 0.01f) { + return; + } + + float rowX = x + Math.max(0.0f, (panelWidth - layout.width()) * 0.5f); + float rowY = y + Math.max(0.0f, equipmentHeight - layout.height()) + (EQUIPMENT_ROW_Y_OFFSET * scaleFactor); + + float slotHeight = EQUIPMENT_SLOT * scaleFactor; + float radius = 2.2f * scaleFactor; + List itemTasks = new ArrayList<>(layout.entries().size()); + int slotFillLeft = HudRenderUtil.scaleAlpha( + HudRenderUtil.mixColor(element.uiBarBackground, element.uiBgPrimary, 0.34f), + alphaFactor + ); + int slotFillRight = HudRenderUtil.scaleAlpha( + HudRenderUtil.mixColor(element.uiBgSecondary, element.uiBarBackground, 0.24f), + alphaFactor * 0.96f + ); + int slotStroke = HudRenderUtil.scaleAlpha( + HudRenderUtil.mixColor(element.uiStroke, element.uiBgSecondary, 0.10f), + alphaFactor * 0.46f + ); + int slotHighlight = HudRenderUtil.scaleAlpha( + HudRenderUtil.mixColor(element.uiTextPrimary, element.uiBgPrimary, 0.88f), + alphaFactor * 0.08f + ); + float itemScale = Math.max(0.35f, (slotHeight - 3.0f * scaleFactor) / 16.0f); + float cursorX = rowX; + for (EquipmentEntry entry : layout.entries()) { + if (glassEnabled) { + TargetHudPanelRenderer.drawGlassCard(element, cursorX, rowY, entry.width(), slotHeight, radius, scaleFactor, alphaFactor); + renderer.roundedRect(cursorX, rowY, entry.width(), slotHeight, radius, 1.0f, + HudRenderUtil.glassSmallBackground(alphaFactor)); + } else { + renderer.roundedRectGradientQuad( + cursorX, rowY, entry.width(), slotHeight, radius, 1.0f, + slotFillLeft, slotFillRight, slotFillRight, slotFillLeft + ); + renderer.roundedRectStroke(cursorX, rowY, entry.width(), slotHeight, radius, 1.0f, 0.5f * scaleFactor, slotStroke); + renderer.roundedRect( + cursorX + 0.75f * scaleFactor, + rowY + 0.75f * scaleFactor, + Math.max(0.0f, entry.width() - 1.5f * scaleFactor), + Math.max(0.6f, 0.75f * scaleFactor), + Math.max(0.5f, radius * 0.45f), + 1.0f, + slotHighlight + ); + } + + if (entry.stack() != null && !entry.stack().isEmpty()) { + float itemX = cursorX + 1.5f * scaleFactor; + float itemY = rowY + (slotHeight - 16.0f * itemScale) * 0.5f; + itemTasks.add(new EquipmentRenderTask(entry.stack(), itemX, itemY, itemScale)); + } else { + drawEmptyEquipmentCross(element, renderer, cursorX, rowY, entry.width(), slotHeight, scaleFactor, alphaFactor); + } + + cursorX += entry.width() + EQUIPMENT_GAP * scaleFactor; + } + if (!itemTasks.isEmpty()) { + int seed = 0; + for (EquipmentRenderTask task : itemTasks) { + drawItem(renderer, task.stack(), task.x(), task.y(), task.scale(), seed++, alphaFactor); + } + } + } + + static void drawItem(Renderer2D renderer, ItemStack stack, float x, float y, float itemScale, int seed, float alphaFactor) { + if (renderer == null || stack == null || stack.isEmpty() || alphaFactor <= 0.001f) { + return; + } + + double previousAlpha = renderer.getAlpha(); + renderer.setAlpha(previousAlpha * AnimationUtility.clamp01(alphaFactor)); + try { + renderer.item(stack, x, y, itemScale, seed, Renderer2D.ITEM_OVERLAY_NONE, null); + } finally { + renderer.setAlpha(previousAlpha); + } + } + + private static void drawEmptyEquipmentCross(TargetHud element, + Renderer2D renderer, + float x, + float y, + float width, + float height, + float scaleFactor, + float alphaFactor) { + float inset = Math.max(2.0f * scaleFactor, width * 0.28f); + float stroke = Math.max(0.6f, 0.85f * scaleFactor); + int color = HudRenderUtil.scaleAlpha(element.uiTextSecondary, alphaFactor); + renderer.line(x + inset, y + inset, x + width - inset, y + height - inset, color); + renderer.line(x + width - inset, y + inset, x + inset, y + height - inset, color); + if (stroke > 1.0f) { + float nudge = stroke * 0.35f; + renderer.line(x + inset + nudge, y + inset, x + width - inset + nudge, y + height - inset, color); + renderer.line(x + width - inset - nudge, y + inset, x + inset - nudge, y + height - inset, color); + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudFaceRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudFaceRenderer.java new file mode 100644 index 0000000..a190507 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudFaceRenderer.java @@ -0,0 +1,187 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.math.HudScale; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.FontInfo; +import dev.loki.lovisual.render.engine.text.Fonts; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.player.PlayerSkinResolver; +import dev.loki.lovisual.util.pvp.opponents.TotemPopSnapshot; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.resources.Identifier; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +import java.util.Locale; +import java.util.UUID; + +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud.*; + +final class TargetHudFaceRenderer { + + private static ItemStack totemBadgeStack; + + private TargetHudFaceRenderer() { + } + + private static ItemStack totemBadgeStack() { + if (totemBadgeStack == null || totemBadgeStack.isEmpty()) { + totemBadgeStack = new ItemStack(Items.TOTEM_OF_UNDYING); + } + return totemBadgeStack; + } + + static void updateTotemPopAnimation(TargetHud element, LivingEntity target, TotemPopSnapshot snapshot, float dt) { + UUID id = target instanceof Player player ? player.getUUID() : null; + if (id == null || !id.equals(element.totemPopTargetId)) { + element.totemPopTargetId = id; + element.totemPopAnimation = 0.0f; + element.totemPopTextPulse = 0.0f; + element.totemPopLastCount = 0; + } + + int count = snapshot != null ? Math.max(0, snapshot.count()) : 0; + if (count > 0 && count != element.totemPopLastCount) { + element.totemPopLastCount = count; + element.totemPopTextPulse = 1.0f; + } else if (count <= 0) { + element.totemPopLastCount = 0; + } + + float targetAnimation = snapshot != null && snapshot.visible() ? 1.0f : 0.0f; + element.totemPopAnimation = AnimationUtility.approach(element.totemPopAnimation, targetAnimation, dt, TOTEM_BADGE_ANIM_SPEED); + element.totemPopAnimation = AnimationUtility.snap(element.totemPopAnimation, targetAnimation, 0.001f); + element.totemPopTextPulse = AnimationUtility.approach(element.totemPopTextPulse, 0.0f, dt, TOTEM_BADGE_PULSE_SPEED); + element.totemPopTextPulse = AnimationUtility.snap(element.totemPopTextPulse, 0.0f, 0.001f); + } + + static void drawFace(TargetHud element, Renderer2D renderer, TextRenderer textRenderer, GuiGraphicsExtractor ctx, LivingEntity target, float x, float y, float scaleFactor, float alphaFactor, TotemPopSnapshot totemPopSnapshot) { + float faceSize = FACE_SIZE * scaleFactor; + float faceX = x + (FACE_X + CONTENT_X_OFFSET) * scaleFactor; + float faceY = y + (FACE_Y + CONTENT_Y_OFFSET) * scaleFactor; + float faceRadius = FACE_RADIUS * scaleFactor; + + float hurtPercent = target.hurtTime > 0 ? Math.min(1.0f, target.hurtTime / 10.0f) : 0.0f; + int red = 255; + int green = Math.round(255.0f * (1.0f - hurtPercent)); + int blue = Math.round(255.0f * (1.0f - hurtPercent)); + int tint = TargetHudFormatter.rgba(red, green, blue, Math.round(255.0f * alphaFactor)); + + if (target instanceof Player player) { + drawPlayerFace(player, faceX, faceY, faceSize, faceRadius, tint); + } else { + drawPlaceholderFace(element, renderer, textRenderer, target, faceX, faceY, faceSize, faceRadius, alphaFactor, hurtPercent); + } + + drawTotemPopBadge(element, renderer, textRenderer, totemPopSnapshot, faceX, faceY, faceSize, faceRadius, scaleFactor, alphaFactor); + } + + private static void drawPlayerFace(Player player, float x, float y, float size, float radius, int tint) { + Identifier skin = PlayerSkinResolver.resolveProfileSkin(player.getGameProfile()); + if (skin == null) return; + + Renderer2D.TEXTURE.roundedTexRect( + x, y, size, size, + radius, 1.0f, + FACE_U0, FACE_V0, FACE_U1, FACE_V1, + tint, + skin + ); + + float hatSize = size * 1.1f; + float hatOffset = (hatSize - size) * 0.5f; + Renderer2D.TEXTURE.roundedTexRect( + x - hatOffset, y - hatOffset, hatSize, hatSize, + radius * 1.05f, 1.0f, + HAT_U0, HAT_V0, HAT_U1, HAT_V1, + tint, + skin + ); + } + + static void drawPlaceholderFace(TargetHud element, Renderer2D renderer, TextRenderer textRenderer, LivingEntity target, float x, float y, float size, float radius, float alphaFactor, float hurtPercent) { + int light = HudRenderUtil.scaleAlpha(HudRenderUtil.mixColor(element.uiBgSecondary, element.uiHealthEnd, 0.28f), alphaFactor); + int dark = HudRenderUtil.scaleAlpha(HudRenderUtil.mixColor(element.uiBgPrimary, 0xFF000000, 0.22f), alphaFactor); + renderer.roundedRectGradient(x, y, size, size, radius, 1.0f, light, dark, 90.0f); + renderer.roundedRectStroke( + x, y, size, size, radius, 1.0f, + 0.65f * size / FACE_SIZE, + HudRenderUtil.scaleAlpha(element.uiStroke, alphaFactor) + ); + + String name = target.getName().getString(); + String letter = name.isEmpty() ? "?" : name.substring(0, 1).toUpperCase(Locale.ROOT); + TextRenderer faceRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); + float textScale = PLACEHOLDER_TEXT_SCALE * element.scale.get().floatValue() * HudScale.scale( + element.mc.getWindow().getGuiScaledWidth(), + element.mc.getWindow().getGuiScaledHeight() + ); + faceRenderer.begin(textScale, false, false); + try { + float textWidth = (float) faceRenderer.getWidth(letter, false); + float textHeight = (float) faceRenderer.getHeight(false); + float tx = x + (size - textWidth) * 0.5f; + float ty = y + (size - textHeight) * 0.5f - element.scale.get().floatValue(); + int letterColor = HudRenderUtil.scaleAlpha( + HudRenderUtil.mixColor(element.uiTextPrimary, element.uiTextSecondary, hurtPercent * 0.35f), + alphaFactor + ); + faceRenderer.render(letter, tx, ty, new RenderColor(letterColor), false); + } finally { + faceRenderer.end(); + } + } + + static void drawTotemPopBadge(TargetHud element, Renderer2D renderer, TextRenderer textRenderer, TotemPopSnapshot snapshot, float faceX, float faceY, float faceSize, float faceRadius, float scaleFactor, float alphaFactor) { + if (snapshot == null || snapshot.count() <= 0 || element.totemPopAnimation <= 0.001f) { + return; + } + + float anim = AnimationUtility.easeInOutCubic(element.totemPopAnimation); + float visualAlpha = alphaFactor * anim; + if (visualAlpha <= 0.001f) { + return; + } + + String text = "x" + snapshot.count(); + TextRenderer badgeRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); + float pulse = AnimationUtility.easeOutBack(element.totemPopTextPulse, 1.12f); + float groupScale = (0.86f + 0.14f * anim) * (1.0f + 0.13f * pulse); + float textScale = TOTEM_BADGE_TEXT_SCALE * scaleFactor * groupScale; + float iconSize = Math.min(faceSize * 0.38f, TOTEM_BADGE_ICON_SIZE * scaleFactor * groupScale); + float gap = TOTEM_BADGE_TEXT_GAP * scaleFactor; + float textWidth = TargetHudTextRenderer.measureText(badgeRenderer, text, textScale); + float textHeight = TargetHudTextRenderer.getTextHeight(badgeRenderer, textScale); + float groupWidth = iconSize + gap + textWidth; + float groupHeight = Math.max(iconSize, textHeight); + + float groupX = faceX + (faceSize - groupWidth) * 0.5f; + float groupY = faceY + faceSize - groupHeight - TOTEM_BADGE_BOTTOM_PAD * scaleFactor + - (1.0f - anim) * 1.4f * scaleFactor; + float iconX = groupX; + float iconY = groupY + (groupHeight - iconSize) * 0.5f; + TargetHudEquipmentRenderer.drawItem(renderer, totemBadgeStack(), iconX, iconY, Math.max(0.1f, iconSize / 16.0f), 713, visualAlpha); + + float textX = iconX + iconSize + gap; + float textY = groupY + (groupHeight - textHeight) * 0.5f - 0.12f * scaleFactor; + int textColor = HudRenderUtil.setAlpha(element.totemPopTextColor.getArgb(), Math.round(255.0f * visualAlpha)); + badgeRenderer.begin(textScale, false, false); + try { + badgeRenderer.render(text, textX, textY, new RenderColor(textColor), true); + } finally { + badgeRenderer.end(); + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudFormatter.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudFormatter.java new file mode 100644 index 0000000..de5d3f2 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudFormatter.java @@ -0,0 +1,111 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import dev.loki.lovisual.util.player.effect.StatusEffectTracker; +import net.minecraft.resources.Identifier; +import net.minecraft.world.effect.MobEffectInstance; + +import java.util.Locale; + +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud.*; + +final class TargetHudFormatter { + + private TargetHudFormatter() { + } + + static float snapToStep(float value, float step) { + if (step <= 0.0f) return value; + return Math.round(value / step) * step; + } + + static float formatDisplayHealth(float health) { + float clamped = Math.max(0.0f, health); + if (clamped <= HEALTH_ZERO_CLAMP) { + return 0.0f; + } + float step = clamped < 1.0f ? HEALTH_TEXT_SMALL_STEP : HEALTH_TEXT_STEP; + float snapped = snapToStep(clamped, step); + return snapped <= HEALTH_ZERO_CLAMP ? 0.0f : snapped; + } + + static String formatHealth(float health) { + if (health >= 100.0f) { + return Integer.toString(Math.round(health)); + } + if (health >= 10.0f) { + return String.format(Locale.ROOT, "%.1f", health); + } + return String.format(Locale.ROOT, "%.2f", health); + } + + static String formatDistance(float distance) { + if (distance >= 100.0f) { + return Integer.toString(Math.round(distance)); + } + return String.format(Locale.ROOT, "%.1f", distance); + } + + static Identifier resolveEffectIcon(MobEffectInstance inst) { + if (inst == null) { + return null; + } + return inst.getEffect().unwrapKey() + .map(key -> Identifier.fromNamespaceAndPath("minecraft", "textures/mob_effect/" + key.identifier().getPath() + ".png")) + .orElse(null); + } + + static String compactEffectText(int entityId, MobEffectInstance inst) { + if (inst == null) { + return ""; + } + String duration = formatEffectDuration(entityId, inst); + if (!duration.isEmpty()) { + return duration; + } + int level = inst.getAmplifier() + 1; + return level > 1 ? roman(level) : ""; + } + + static String formatEffectDuration(int entityId, MobEffectInstance inst) { + if (inst == null) { + return ""; + } + if (StatusEffectTracker.shouldHideDuration(entityId, inst.getEffect())) { + return ""; + } + int ticks = inst.getDuration(); + if (ticks < 0 || ticks >= 32767) { + return ""; + } + int totalSeconds = Math.max(0, ticks / 20); + int minutes = totalSeconds / 60; + int seconds = totalSeconds % 60; + return seconds < 10 ? minutes + ":0" + seconds : minutes + ":" + seconds; + } + + static int rgba(int red, int green, int blue, int alpha) { + int r = Math.max(0, Math.min(255, red)); + int g = Math.max(0, Math.min(255, green)); + int b = Math.max(0, Math.min(255, blue)); + int a = Math.max(0, Math.min(255, alpha)); + return (a << 24) | (r << 16) | (g << 8) | b; + } + + static String roman(int n) { + return switch (n) { + case 1 -> "I"; + case 2 -> "II"; + case 3 -> "III"; + case 4 -> "IV"; + case 5 -> "V"; + default -> Integer.toString(n); + }; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudModel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudModel.java new file mode 100644 index 0000000..9591df4 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudModel.java @@ -0,0 +1,29 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import net.minecraft.resources.Identifier; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +record EquipmentEntry(ItemStack stack, float width) { +} + +record EquipmentLayout(List entries, float width, float height) { +} + +record EquipmentRenderTask(ItemStack stack, float x, float y, float scale) { +} + +record EffectChip(MobEffectInstance effect, Identifier iconId, String text, float width) { +} + +record EffectLayout(List chips, float width, float height) { +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudPanelRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudPanelRenderer.java new file mode 100644 index 0000000..8e5ab13 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudPanelRenderer.java @@ -0,0 +1,118 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; + +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud.PANEL_RADIUS; + +final class TargetHudPanelRenderer { + + private TargetHudPanelRenderer() { + } + + static void drawBackground(TargetHud element, + Renderer2D renderer, + float x, + float y, + float width, + float height, + float radius, + float alphaFactor, + boolean glassEnabled) { + if (glassEnabled) { + renderer.roundedRect(x, y, width, height, radius, 1.0f, HudRenderUtil.glassPanelBackground(alphaFactor)); + return; + } + + int primary = HudRenderUtil.scaleAlpha(element.uiBgPrimary, alphaFactor); + int secondary = HudRenderUtil.scaleAlpha(element.uiBgSecondary, alphaFactor); + + if (element.isThemeMode()) { + HudRenderUtil.drawHudBackground(renderer, x, y, width, height, radius, 1.0f, primary, true); + } else { + renderer.roundedRectGradientQuad(x, y, width, height, radius, 1.0f, primary, secondary, primary, secondary); + } + + renderer.roundedRectStroke( + x, y, width, height, radius, 1.0f, + 0.35f * radius / PANEL_RADIUS, + HudRenderUtil.scaleAlpha(element.uiStroke, alphaFactor) + ); + } + + static void drawHitPulse(TargetHud element, + Renderer2D renderer, + float x, + float y, + float width, + float height, + float radius, + float alphaFactor, + float pulse) { + if (!element.hitAnim.get() || pulse <= 0.001f) return; + + float scaledPulse = pulse * element.hitPulse.get().floatValue(); + float spread = 6.0f * (0.65f + scaledPulse); + int outerColor = HudRenderUtil.scaleAlpha(element.uiHitOuter, 0.58f * scaledPulse * alphaFactor); + int innerColor = HudRenderUtil.scaleAlpha(element.uiHitInner, 0.92f * scaledPulse * alphaFactor); + + renderer.roundedRectStroke( + x - spread * 0.4f, + y - spread * 0.4f, + width + spread * 0.8f, + height + spread * 0.8f, + radius + spread * 0.15f, + 1.0f, + 0.85f + scaledPulse, + outerColor + ); + renderer.roundedRectStroke(x, y, width, height, radius, 1.0f, 0.9f + scaledPulse, innerColor); + } + + static void drawBlur(TargetHud element, + float x, + float y, + float width, + float height, + float radius, + int tintRgb, + float alphaFactor) { + if (!element.hasEffect() || width <= 0.0f || height <= 0.0f) return; + float quality = element.hud.getBlurRadius(); + float brightness = 1.0f; + float alpha = (element.blurAlpha.get() / 255.0f) * alphaFactor; + Renderer2D.COLOR.blurRect(x, y, width, height, radius, quality, brightness, alpha, 0xFFFFFF); + } + + static void drawGlass(TargetHud element, + float x, + float y, + float width, + float height, + float radius, + float alphaFactor) { + float blurStrength = (element.blurAlpha.get() / 255.0f) * alphaFactor; + float glassAlpha = alphaFactor; + float glassScale = PANEL_RADIUS <= 0.0f ? 1.0f : radius / PANEL_RADIUS; + HudRenderUtil.drawLiquidGlass(x, y, width, height, radius, glassScale, true, blurStrength, glassAlpha); + } + + static void drawGlassCard(TargetHud element, + float x, + float y, + float width, + float height, + float radius, + float scaleFactor, + float alphaFactor) { + float blurStrength = (element.blurAlpha.get() / 255.0f) * alphaFactor; + HudRenderUtil.drawLiquidGlass(x, y, width, height, radius, scaleFactor, true, blurStrength, alphaFactor); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudRenderer.java new file mode 100644 index 0000000..a670e06 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudRenderer.java @@ -0,0 +1,190 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; +import dev.loki.lovisual.features.theme.Theme; +import dev.loki.lovisual.features.theme.Themes; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.math.HudScale; +import dev.loki.lovisual.render.engine.profiler.ProfilerPhase; +import dev.loki.lovisual.render.engine.profiler.RenderProfiler2D; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.pvp.opponents.TotemPopSnapshot; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.world.entity.LivingEntity; + +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud.*; +import static dev.loki.lovisual.features.theme.Theme.theme; + +final class TargetHudRenderer { + + private TargetHudRenderer() { + } + + static void render(TargetHud element, Renderer2D renderer, TextRenderer textRenderer, GuiGraphicsExtractor ctx, float tickDelta, int screenW, int screenH) { + try (ProfilerPhase.Scope ignored = ProfilerPhase.scope("2d:target_hud:main"); + RenderProfiler2D.Section ignoredSection = RenderProfiler2D.section("target_hud:main")) { + boolean preview = DraggableHudElementRegistry.isForceVisible(); + if (element.mc == null || (element.mc.player == null && !preview)) return; + long now = System.currentTimeMillis(); + LivingEntity target = TargetHudTargetResolver.resolveTarget(element, preview); + TargetHudTargetResolver.updateDisplayTarget(element, target, now); + boolean shouldShow = TargetHudTargetResolver.shouldShow(element, target, now); + float dt = AnimationUtility.deltaTime(); + element.visibilityAnimation = HudRenderUtil.animateVisibility(element.visibilityAnimation, shouldShow); + if (!shouldShow && element.visibilityAnimation <= 0.001f) { + element.displayTarget = null; + element.setHudSize(0f, 0f); + return; + } + if (element.displayTarget == null) return; + updatePalette(element); + float hudScale = HudScale.scale(screenW, screenH) * element.scale.get().floatValue(); + float alphaFactor = AnimationUtility.easeOutCubic(element.visibilityAnimation); + float hitPulseFactor = computeHitPulse(element, now); + EffectLayout boundsEffects = TargetHudEffectsRenderer.buildEffectLayout(element, element.displayTarget, preview, textRenderer, hudScale); + boolean hasEffects = !boundsEffects.chips().isEmpty(); + float effectsTarget = hasEffects ? 1.0f : 0.0f; + element.effectsAnimation = AnimationUtility.approach(element.effectsAnimation, effectsTarget, dt, EQUIPMENT_SPEED); + element.effectsAnimation = AnimationUtility.snap(element.effectsAnimation, effectsTarget, 0.001f); + EquipmentLayout boundsEquipment = TargetHudEquipmentRenderer.buildEquipmentLayout(element, element.displayTarget, preview, textRenderer, hudScale); + boolean hasEquipment = !boundsEquipment.entries().isEmpty(); + float equipmentTarget = hasEquipment ? 1.0f : 0.0f; + element.equipmentAnimation = AnimationUtility.approach(element.equipmentAnimation, equipmentTarget, dt, EQUIPMENT_SPEED); + element.equipmentAnimation = AnimationUtility.snap(element.equipmentAnimation, equipmentTarget, 0.001f); + float scalePulse = element.hitAnim.get() + ? 1.0f + hitPulseFactor * 0.018f * element.hitPulse.get().floatValue() + : 1.0f; + float widgetScale = HudRenderUtil.visibilityScale(element.visibilityAnimation); + float panelWidthLogical = BASE_WIDTH; + float panelHeightLogical = BASE_HEIGHT; + float targetWidth = panelWidthLogical * hudScale; + float targetHeight = panelHeightLogical * hudScale; + element.setHudSize(HudRenderUtil.animateDimension(element.hudWidth(), targetWidth), HudRenderUtil.animateDimension(element.hudHeight(), targetHeight)); + float widthFactor = targetWidth <= 0.0f ? 1.0f : element.hudWidth() / targetWidth; + float heightFactor = targetHeight <= 0.0f ? 1.0f : element.hudHeight() / targetHeight; + float dimensionFactor = Math.max(0.0f, Math.min(widthFactor, heightFactor)); + float scaleFactor = hudScale * dimensionFactor * widgetScale * scalePulse; + float drawW = panelWidthLogical * scaleFactor; + float drawH = panelHeightLogical * scaleFactor; + float panelDrawW = panelWidthLogical * scaleFactor; + float panelDrawH = panelHeightLogical * scaleFactor; + float drawX = element.hudX() + (element.hudWidth() - drawW) * 0.5f; + float drawY = element.hudY() + (element.hudHeight() - drawH) * 0.5f; + float panelBaseX = drawX + (drawW - panelDrawW) * 0.5f; + float panelBaseY = drawY; + float panelX = panelBaseX + PANEL_INSET * scaleFactor; + float panelY = panelBaseY + PANEL_INSET * scaleFactor; + float panelW = panelDrawW - PANEL_INSET * 2f * scaleFactor; + float panelH = panelDrawH - PANEL_INSET * 2f * scaleFactor; + float panelRadius = PANEL_RADIUS * scaleFactor; + + boolean glassEnabled = element.isGlassEffect(); + boolean blurEnabled = element.isBlurEffect(); + TotemPopSnapshot totemPopSnapshot = TargetHudTargetResolver.resolveTotemPopSnapshot(element, element.displayTarget); + TargetHudFaceRenderer.updateTotemPopAnimation(element, element.displayTarget, totemPopSnapshot, dt); + + if (glassEnabled) { + TargetHudPanelRenderer.drawGlass(element, panelX, panelY, panelW, panelH, panelRadius, alphaFactor); + } else if (blurEnabled) { + TargetHudPanelRenderer.drawBlur(element, panelX, panelY, panelW, panelH, panelRadius, element.uiBgPrimary, alphaFactor); + } + + TargetHudPanelRenderer.drawBackground(element, renderer, panelX, panelY, panelW, panelH, panelRadius, alphaFactor, glassEnabled); + TargetHudPanelRenderer.drawHitPulse(element, renderer, panelX, panelY, panelW, panelH, panelRadius, alphaFactor, hitPulseFactor); + TargetHudFaceRenderer.drawFace(element, renderer, textRenderer, ctx, element.displayTarget, panelX, panelY, scaleFactor, alphaFactor, totemPopSnapshot); + TargetHudContentRenderer.drawContent(element, renderer, textRenderer, element.displayTarget, panelX, panelY, panelDrawW, scaleFactor, alphaFactor, now, dt); + if (element.effectsAnimation > 0.01f) { + EffectLayout drawEffects = TargetHudEffectsRenderer.buildEffectLayout(element, element.displayTarget, preview, textRenderer, scaleFactor); + float effectsY = panelY - drawEffects.height(); + TargetHudEffectsRenderer.drawEffects(element, renderer, textRenderer, drawEffects, panelX, effectsY, panelW, scaleFactor, alphaFactor * element.effectsAnimation, glassEnabled); + } + if (element.equipmentAnimation > 0.01f) { + EquipmentLayout drawEquipment = TargetHudEquipmentRenderer.buildEquipmentLayout(element, element.displayTarget, preview, textRenderer, scaleFactor); + TargetHudEquipmentRenderer.drawEquipment(element, renderer, textRenderer, ctx, drawEquipment, panelX, panelY + panelH, panelW, drawEquipment.height(), scaleFactor, alphaFactor * element.equipmentAnimation, glassEnabled); + } + } + } + + static void updatePalette(TargetHud element) { + if (element.isThemeMode()) { + int panelAlpha = element.bgAlpha.get(); + element.uiBgPrimary = HudRenderUtil.setAlpha(theme().windowBg(), panelAlpha); + element.uiBgSecondary = HudRenderUtil.setAlpha( + HudRenderUtil.mixColor(theme().surface(), theme().windowHeader(), 0.35f), + panelAlpha + ); + element.uiStroke = HudRenderUtil.setAlpha( + HudRenderUtil.mixColor(theme().windowStroke(), theme().strokeSoft(), 0.4f), + Math.min(panelAlpha, 190) + ); + element.uiTextPrimary = theme().textPrimary(); + element.uiTextSecondary = theme().textMuted(); + element.uiBarBackground = HudRenderUtil.setAlpha( + HudRenderUtil.mixColor(theme().surface(), 0xFF000000, 0.18f), + 200 + ); + Themes.ThemeEntry entry = Theme.currentEntry(); + Themes.GradientSpec healthGradient = entry != null && entry.cardGradient() != null && entry.cardGradient().enabled() + ? entry.cardGradient() + : null; + if (healthGradient != null) { + element.uiHealthStart = healthGradient.start(); + element.uiHealthEnd = healthGradient.end(); + element.uiHealthGradientAngle = healthGradient.angleDeg(); + } else { + element.uiHealthStart = theme().accent(); + element.uiHealthEnd = HudRenderUtil.mixColor(theme().accentSoft(), theme().textPrimary(), 0.18f); + element.uiHealthGradientAngle = 45.0f; + } + element.uiTrail = HudRenderUtil.setAlpha( + HudRenderUtil.mixColor(theme().surface(), theme().accentSoft(), 0.22f), + 170 + ); + element.uiAbsorptionStart = 0xFFFFB400; + element.uiAbsorptionEnd = 0xFFFFE17A; + element.uiAbsorptionGradientAngle = element.uiHealthGradientAngle + 90.0f; + element.uiHitOuter = HudRenderUtil.mixColor(theme().accentSoft(), 0xFFFF6767, 0.45f); + element.uiHitInner = HudRenderUtil.mixColor(theme().accent(), 0xFFFFC2C2, 0.22f); + return; + } + + element.uiBgPrimary = element.bg.getArgb(); + element.uiBgSecondary = element.bg2.getArgb(); + element.uiStroke = element.stroke.getArgb(); + element.uiTextPrimary = element.text.getArgb(); + element.uiTextSecondary = element.textSecondary.getArgb(); + element.uiBarBackground = element.barBg.getArgb(); + element.uiHealthStart = element.healthStart.getArgb(); + element.uiHealthEnd = element.healthEnd.getArgb(); + element.uiHealthGradientAngle = 45.0f; + element.uiTrail = element.trail.getArgb(); + element.uiAbsorptionStart = element.absorptionStart.getArgb(); + element.uiAbsorptionEnd = element.absorptionEnd.getArgb(); + element.uiAbsorptionGradientAngle = 135.0f; + element.uiHitOuter = element.hitOuter.getArgb(); + element.uiHitInner = element.hitInner.getArgb(); + } + + static float computeHitPulse(TargetHud element, long now) { + if (element.displayTarget == null) return 0.0f; + Long hitAt = HIT_FLASH_MS_BY_ID.get(element.displayTarget.getId()); + if (hitAt == null) return 0.0f; + + float elapsed = now - hitAt; + if (elapsed >= HIT_FLASH_MS) { + HIT_FLASH_MS_BY_ID.remove(element.displayTarget.getId()); + return 0.0f; + } + float t = 1.0f - elapsed / HIT_FLASH_MS; + return AnimationUtility.easeOutCubic(AnimationUtility.clamp01(t)); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudTargetResolver.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudTargetResolver.java new file mode 100644 index 0000000..a43ebfc --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudTargetResolver.java @@ -0,0 +1,69 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import dev.loki.lovisual.util.player.PlayerHealthResolver; +import dev.loki.lovisual.util.pvp.opponents.TotemPopCounter; +import dev.loki.lovisual.util.pvp.opponents.TotemPopSnapshot; +import dev.loki.lovisual.util.screen.ClientScreen; +import dev.loki.lovisual.util.target.TargetManager; +import net.minecraft.client.gui.screens.ChatScreen; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; + +final class TargetHudTargetResolver { + + private TargetHudTargetResolver() { + } + + static LivingEntity resolveTarget(TargetHud element, boolean preview) { + LivingEntity target = TargetManager.getTarget(); + if (target != null && element.playersOnly.get() && !(target instanceof Player)) { + target = null; + } + if (target == null && (preview || ClientScreen.current() instanceof ChatScreen)) { + target = element.mc.player; + } + return target; + } + + static void updateDisplayTarget(TargetHud element, LivingEntity target, long now) { + if (target != null) { + if (element.displayTarget != target) { + element.displayTarget = target; + PlayerHealthResolver.HealthSnapshot health = PlayerHealthResolver.resolve(target); + float baseMaxHealth = Math.max(1.0f, target.getMaxHealth()); + float realHealth = Math.max(0.0f, health.totalHealth() - health.absorption()); + element.displayedHealth = health.totalHealth(); + element.healthAnimation = realHealth / baseMaxHealth; + element.trailAnimation = element.healthAnimation; + element.absorptionAnimation = health.absorption() / baseMaxHealth; + element.displayedDistance = element.mc.player != null ? element.mc.player.distanceTo(target) : 0.0f; + element.waveStartMs = now; + } + element.lastSeenMs = now; + return; + } + + if (element.displayTarget == element.mc.player && !(ClientScreen.current() instanceof ChatScreen)) { + element.lastSeenMs = 0L; + } + } + + static boolean shouldShow(TargetHud element, LivingEntity target, long now) { + if (target != null) return true; + return element.displayTarget != null && element.lastSeenMs > 0L && now - element.lastSeenMs <= Math.max(0L, element.holdMs.get()); + } + + static TotemPopSnapshot resolveTotemPopSnapshot(TargetHud element, LivingEntity target) { + if (!(target instanceof Player player)) { + return TotemPopSnapshot.empty(null); + } + return TotemPopCounter.snapshot(player.getUUID()); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudTextRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudTextRenderer.java new file mode 100644 index 0000000..ec577d7 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TargetHudTextRenderer.java @@ -0,0 +1,101 @@ +/* + * 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.features.gui.hud.draggable.impl; + +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import net.minecraft.util.Util; + +import static dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud.*; + +final class TargetHudTextRenderer { + + private TargetHudTextRenderer() { + } + + static float measureText(TextRenderer renderer, String text, float scale) { + renderer.begin(scale, false, false); + try { + return (float) renderer.getWidth(text, false); + } finally { + renderer.end(); + } + } + + static float getTextHeight(TextRenderer renderer, float scale) { + renderer.begin(scale, false, false); + try { + return (float) renderer.getHeight(false); + } finally { + renderer.end(); + } + } + + static String trimText(TextRenderer renderer, String text, float maxWidth, float scale) { + if (text == null || text.isEmpty()) return ""; + renderer.begin(scale, false, false); + try { + if (renderer.getWidth(text, false) <= maxWidth) return text; + String value = text; + while (!value.isEmpty()) { + String candidate = value + "..."; + if (renderer.getWidth(candidate, false) <= maxWidth) { + return candidate; + } + value = value.substring(0, value.length() - 1); + } + return ""; + } finally { + renderer.end(); + } + } + + static void drawScrollingText(TextRenderer renderer, + String text, + float x, + float y, + float fullWidth, + float viewWidth, + float scale, + float baseScale, + float alpha, + int color) { + float speed = BASE_NAME_SCROLL_SPEED * baseScale; + float gap = BASE_NAME_SCROLL_GAP * baseScale; + if (speed <= 0.0f) { + return; + } + + float cycleDistance = fullWidth + gap; + float cycleTime = NAME_SCROLL_PAUSE_SEC + (cycleDistance / speed); + if (cycleTime <= 0.0f) { + return; + } + + float now = Util.getMillis() / 1000.0f; + float t = now % cycleTime; + float offset = 0.0f; + if (t > NAME_SCROLL_PAUSE_SEC) { + offset = -(t - NAME_SCROLL_PAUSE_SEC) * speed; + } + + RenderColor renderColor = new RenderColor(HudRenderUtil.scaleAlpha(color, alpha)); + float fade = Math.min(viewWidth * 0.25f, BASE_NAME_FADE * baseScale); + renderer.begin(scale, false, false); + try { + renderer.renderHorizontalFadeClipped(text, x + offset, y, renderColor, x, x + viewWidth, fade, fade, false); + if (cycleDistance > viewWidth * 0.5f) { + renderer.renderHorizontalFadeClipped(text, x + offset + cycleDistance, y, renderColor, + x, x + viewWidth, fade, fade, false); + } + } finally { + renderer.end(); + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TimerIndicator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TimerIndicator.java index 63514c3..b7547ca 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TimerIndicator.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/TimerIndicator.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -18,8 +18,6 @@ import dev.loki.lovisual.features.gui.hud.HudGlobalConfig; import dev.loki.lovisual.features.gui.hud.HudRenderUtil; import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElement; import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.Timer; import dev.loki.lovisual.render.engine.color.RenderColor; import dev.loki.lovisual.render.engine.math.HudScale; import dev.loki.lovisual.render.engine.renderer.Renderer2D; @@ -93,8 +91,7 @@ public final class TimerIndicator extends DraggableHudElement { return; } - float charge = Timer.getEnergy01(); - renderThunder(renderer, textRenderer, screenW, screenH, charge); + renderThunder(renderer, textRenderer, screenW, screenH, 0.0f); } private void renderThunder(Renderer2D renderer, @@ -188,9 +185,7 @@ public final class TimerIndicator extends DraggableHudElement { } private boolean isTimerIndicatorActive() { - Timer timer = Modules.get(Timer.class); - if (timer == null || !timer.isEnabled()) return false; - Timer.Mode mode = timer.getMode(); - return mode != null && mode != Timer.Mode.NORMAL; + // TODO: movement.Timer module was removed; rework indicator when a replacement exists. + return false; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Tps.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Tps.java index bf80d6d..30087fc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Tps.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Tps.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Triangulator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Triangulator.java index ca3dfbc..3902926 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Triangulator.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/draggable/impl/Triangulator.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/StaticHudElementBootstrap.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/StaticHudElementBootstrap.java index 6ac20ac..911eaab 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/StaticHudElementBootstrap.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/StaticHudElementBootstrap.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/StaticHudElementRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/StaticHudElementRegistry.java index 8c0ba71..e271242 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/StaticHudElementRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/StaticHudElementRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,7 +15,7 @@ import dev.loki.lovisual.features.module.HudPhase; import dev.loki.lovisual.render.engine.math.HudScale; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import java.util.ArrayList; import java.util.Collections; @@ -37,10 +37,6 @@ public enum StaticHudElementRegistry { ELEMENTS.add(element); } - public static void clearRuntimeReferences() { - ELEMENTS.clear(); - } - public static List getAll() { return Collections.unmodifiableList(ELEMENTS); } @@ -64,7 +60,7 @@ public enum StaticHudElementRegistry { } public static void tickAll() { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; for (AbstractHudElement e : ELEMENTS) { e.onTick(); } @@ -89,7 +85,7 @@ public enum StaticHudElementRegistry { } public static boolean hasEngineWork(HudPhase phase, HudRenderSpace space, boolean foreground) { - if (!RuntimeGate.canRunHud()) return false; + if (!Lifecycle.canRunHud()) return false; for (AbstractHudElement element : ELEMENTS) { if (element == null || !element.isEnabled()) continue; if (!element.usesEngineRenderer()) continue; @@ -101,7 +97,7 @@ public enum StaticHudElementRegistry { } public static boolean handleMouseButton(int button, boolean pressed) { - if (!RuntimeGate.canRunHud()) return false; + if (!Lifecycle.canRunHud()) return false; if (!pressed) return false; Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.getWindow() == null) return false; @@ -147,7 +143,7 @@ public enum StaticHudElementRegistry { GuiGraphicsExtractor ctx, float tickDelta, boolean foreground) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.getWindow() == null) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/BetterButtons.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/BetterButtons.java index 9b245c5..e462a61 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/BetterButtons.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/BetterButtons.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -39,7 +39,6 @@ import dev.loki.lovisual.render.engine.text.FontInfo; import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; import dev.loki.lovisual.render.helpers.ScissorFunction; -import dev.loki.lovisual.runtime.RuntimeGate; import dev.loki.lovisual.util.text.LegacyTextUtil; import dev.loki.lovisual.util.text.TextRenderUtil; @@ -201,7 +200,7 @@ public final class BetterButtons extends AbstractHudElement { if (tooltips == null || !tooltips.useCustomGuiTooltips()) { return; } - WidgetTooltipHolder state = ((ClickableWidgetAccessor) widget).combatant$getTooltipState(); + WidgetTooltipHolder state = ((ClickableWidgetAccessor) widget).lovisual$getTooltipState(); if (state == null) return; Tooltip tooltip = state.get(); if (tooltip == null) return; @@ -601,8 +600,8 @@ public final class BetterButtons extends AbstractHudElement { renderButton(ctx, widget, null, hover, enabled, focused); TextIconButtonWidgetAccessor accessor = (TextIconButtonWidgetAccessor) widget; - int texW = accessor.combatant$getTextureWidth(); - int texH = accessor.combatant$getTextureHeight(); + int texW = accessor.lovisual$getTextureWidth(); + int texH = accessor.lovisual$getTextureHeight(); int iconX; int iconY = widget.getY() + widget.getHeight() / 2 - texH / 2; if (iconOnly) { @@ -611,7 +610,7 @@ public final class BetterButtons extends AbstractHudElement { iconX = widget.getX() + widget.getWidth() - texW - 2; } boolean hoverState = widget.isActive() && (widget.isHoveredOrFocused() || focused || hover > 0.001f); - Identifier spriteId = accessor.combatant$getTexture().get(widget.isActive(), hoverState); + Identifier spriteId = accessor.lovisual$getTexture().get(widget.isActive(), hoverState); float sx = parallaxShiftX(widget, hover); float sy = parallaxShiftY(widget, hover); drawGuiSprite(spriteId, Math.round(iconX + sx), Math.round(iconY + sy), texW, texH, widget.getAlpha()); @@ -867,7 +866,7 @@ public final class BetterButtons extends AbstractHudElement { private static void markRounded(AbstractWidget widget, float radius) { if (widget instanceof IRoundedHitbox rounded) { - rounded.combatant$setRoundedHitbox(radius); + rounded.lovisual$setRoundedHitbox(radius); } } @@ -933,7 +932,7 @@ public final class BetterButtons extends AbstractHudElement { } public boolean useUiButtons() { - return !RuntimeGate.isPanic() && isEnabled(); + return isEnabled(); } private boolean isGradientStyle() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/BetterTooltips.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/BetterTooltips.java index e1955b4..e1f78cf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/BetterTooltips.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/BetterTooltips.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -41,7 +41,6 @@ import dev.loki.lovisual.render.engine.renderer.ui.runtime.script.UiScriptModule import dev.loki.lovisual.render.engine.text.FontInfo; import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; import dev.loki.lovisual.util.input.KeyManager; import dev.loki.lovisual.util.item.TopEnchantUtil; @@ -58,7 +57,7 @@ public final class BetterTooltips extends AbstractHudElement { public static final String GROUP_TOOLTIP_GUI = "vanilla_tooltip_gui"; public static final String GROUP_TOOLTIP_ITEMS = "vanilla_tooltip_items"; public static final String GROUP_SHULKER_PREVIEW = "vanilla_shulker_preview"; - private static final String TOOLTIP_PANEL_LAYOUT_ID = "combatant:api/hud/static/tooltip_panel"; + private static final String TOOLTIP_PANEL_LAYOUT_ID = "lovisual:api/hud/static/tooltip_panel"; private static final int TOOLTIP_PAD_X = 4; private static final int TOOLTIP_PAD_Y = 3; private static final float TOOLTIP_STROKE_WIDTH = 0.55f; @@ -678,25 +677,25 @@ public final class BetterTooltips extends AbstractHudElement { } public boolean useCustomGuiTooltips() { - if (RuntimeGate.isPanic()) return false; + BetterButtons buttons = BetterButtons.get(); if (buttons != null && buttons.useUiButtons()) return true; return isEnabled(); } public boolean useCustomItemTooltips() { - if (RuntimeGate.isPanic()) return false; + BetterButtons buttons = BetterButtons.get(); if (buttons != null && buttons.useUiButtons()) return true; return itemTooltipEnabled.get(); } public boolean isItemInfoColorizeEnabled() { - return !RuntimeGate.isPanic() && itemInfoColorize.get(); + return itemInfoColorize.get(); } public boolean isTooltipAlphaEnabled() { - return !RuntimeGate.isPanic() && anyTooltipsEnabled(); + return anyTooltipsEnabled(); } public int tooltipColor() { @@ -704,7 +703,7 @@ public final class BetterTooltips extends AbstractHudElement { } public boolean isShulkerPreviewEnabled() { - return !RuntimeGate.isPanic() && shulkerPreviewEnabled.get(); + return shulkerPreviewEnabled.get(); } public void setShulkerPreviewEnabled(boolean value) { @@ -730,7 +729,7 @@ public final class BetterTooltips extends AbstractHudElement { } public boolean isShulkerPreviewHeld() { - if (RuntimeGate.isPanic()) return false; + return KeyManager.isHeldAllowScreen(bindingName(shulkerPreviewHold)); } @@ -787,7 +786,7 @@ public final class BetterTooltips extends AbstractHudElement { } private boolean anyTooltipsEnabled() { - if (RuntimeGate.isPanic()) return false; + if (useCustomGuiTooltips()) return true; if (itemTooltipEnabled.get()) return true; return shulkerPreviewEnabled.get(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomBar.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomBar.java index e595d81..6441840 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomBar.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomBar.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -31,12 +31,11 @@ import dev.loki.lovisual.render.engine.animation.AnimationUtility; import dev.loki.lovisual.render.engine.color.RenderColor; import dev.loki.lovisual.render.engine.core.ViewportContext; import dev.loki.lovisual.render.engine.math.ColorMath; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; import dev.loki.lovisual.render.helpers.PlayerHeadRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; import dev.loki.lovisual.util.input.KeyManager; import dev.loki.lovisual.util.map.MapPlayersCache; import dev.loki.lovisual.util.player.PlayerSkinResolver; @@ -230,11 +229,11 @@ public final class CustomBar extends AbstractHudElement { int x = Mth.floor((mc.getWindow().getGuiScaledWidth() - XP_BAR_WIDTH) * 0.5f); int y = Mth.floor(mc.getWindow().getGuiScaledHeight() - 22f - XP_BAR_OFFSET - XP_BAR_HEIGHT); BarColors colors = colors(bm); - ctx.blitSprite(CombatantRenderPipelines.GUI_TEXTURE_LOOKUP, XP_BACKGROUND, x, y, 182, 5, + ctx.blitSprite(LoVisualRenderPipelines.GUI_TEXTURE_LOOKUP, XP_BACKGROUND, x, y, 182, 5, applyBarAlpha(colors.trackTexture(), bm)); int progress = (int) (Mth.clamp(mc.player.experienceProgress, 0.0f, 1.0f) * 183.0f); if (progress > 0) { - ctx.blitSprite(CombatantRenderPipelines.GUI_TEXTURE_LOOKUP, XP_PROGRESS, 182, 5, 0, 0, x, y, progress, 5, + ctx.blitSprite(LoVisualRenderPipelines.GUI_TEXTURE_LOOKUP, XP_PROGRESS, 182, 5, 0, 0, x, y, progress, 5, applyBarAlpha(colors.fillTexture(), bm)); } } @@ -262,16 +261,16 @@ public final class CustomBar extends AbstractHudElement { int x = Mth.floor((mc.getWindow().getGuiScaledWidth() - XP_BAR_WIDTH) * 0.5f); int y = Mth.floor(mc.getWindow().getGuiScaledHeight() - 22f - XP_BAR_OFFSET - XP_BAR_HEIGHT); BarColors colors = colors(bm); - ctx.blitSprite(CombatantRenderPipelines.GUI_TEXTURE_LOOKUP, JUMP_BACKGROUND, x, y, 182, 5, + ctx.blitSprite(LoVisualRenderPipelines.GUI_TEXTURE_LOOKUP, JUMP_BACKGROUND, x, y, 182, 5, applyBarAlpha(colors.trackTexture(), bm)); if (mount.getJumpCooldown() > 0) { - ctx.blitSprite(CombatantRenderPipelines.GUI_TEXTURE_LOOKUP, JUMP_COOLDOWN, x, y, 182, 5, + ctx.blitSprite(LoVisualRenderPipelines.GUI_TEXTURE_LOOKUP, JUMP_COOLDOWN, x, y, 182, 5, applyBarAlpha(colors.fillTexture(), bm)); return; } int progress = Mth.lerpDiscrete(mc.player.getJumpRidingScale(), 0, 182); if (progress > 0) { - ctx.blitSprite(CombatantRenderPipelines.GUI_TEXTURE_LOOKUP, JUMP_PROGRESS, 182, 5, 0, 0, x, y, progress, 5, + ctx.blitSprite(LoVisualRenderPipelines.GUI_TEXTURE_LOOKUP, JUMP_PROGRESS, 182, 5, 0, 0, x, y, progress, 5, applyBarAlpha(colors.fillTexture(), bm)); } } @@ -348,7 +347,7 @@ public final class CustomBar extends AbstractHudElement { if (bm == null || !bm.isHudBarEnabled() || !bm.isHotbarXpBarEnabled()) return; int x = Mth.floor((mc.getWindow().getGuiScaledWidth() - XP_BAR_WIDTH) * 0.5f); int y = Mth.floor(mc.getWindow().getGuiScaledHeight() - 22f - XP_BAR_OFFSET - LOCATOR_BAR_HEIGHT); - ctx.blitSprite(CombatantRenderPipelines.GUI_TEXTURE_LOOKUP, LOCATOR_BACKGROUND, x, y, 182, 5, + ctx.blitSprite(LoVisualRenderPipelines.GUI_TEXTURE_LOOKUP, LOCATOR_BACKGROUND, x, y, 182, 5, applyBarAlpha(colors(bm).locatorTexture(), bm)); } @@ -516,7 +515,7 @@ public final class CustomBar extends AbstractHudElement { ? Mth.floor(headY + headSize + LOCATOR_ARROW_GAP) : Mth.floor(headY - LOCATOR_ARROW_H - LOCATOR_ARROW_GAP); ctx.blitSprite( - CombatantRenderPipelines.GUI_TEXTURE_LOOKUP, + LoVisualRenderPipelines.GUI_TEXTURE_LOOKUP, arrow, xOffset, yOffset, @@ -1224,7 +1223,7 @@ public final class CustomBar extends AbstractHudElement { } public boolean isHudBarEnabled() { - return !RuntimeGate.isPanic() && isEnabled(); + return isEnabled(); } public float getHudOverlayAlphaFactor() { @@ -1239,11 +1238,11 @@ public final class CustomBar extends AbstractHudElement { } public boolean isHotbarXpBarEnabled() { - return !RuntimeGate.isPanic() && xpBar.get(); + return xpBar.get(); } public boolean isHotbarXpBarShowLevel() { - return !RuntimeGate.isPanic() && xpBarShowLevel.get(); + return xpBarShowLevel.get(); } public BarMode getHotbarBarMode() { @@ -1318,7 +1317,7 @@ public final class CustomBar extends AbstractHudElement { } public boolean isLocatorSearchEnabled() { - return !RuntimeGate.isPanic() && locatorModeEnabled() && locatorSearchEnabled.get(); + return locatorModeEnabled() && locatorSearchEnabled.get(); } public Set getLocatorSearchPlayers() { @@ -1350,7 +1349,7 @@ public final class CustomBar extends AbstractHudElement { } public boolean isLocatorLabelsEnabled() { - return !RuntimeGate.isPanic() && locatorModeEnabled() && locatorLabels.get(); + return locatorModeEnabled() && locatorLabels.get(); } public boolean isLocatorLabelDistanceEnabled() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomHealthBar.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomHealthBar.java index 8d4c9a6..13117b4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomHealthBar.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomHealthBar.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -31,7 +31,6 @@ import dev.loki.lovisual.render.engine.renderer.ui.runtime.script.UiScriptModule import dev.loki.lovisual.render.engine.renderer.ui.runtime.script.UiScriptModuleHandle; import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; import java.util.List; @@ -41,7 +40,7 @@ import static dev.loki.lovisual.features.theme.Theme.theme; public final class CustomHealthBar extends AbstractHudElement { public static final CustomHealthBar INSTANCE = new CustomHealthBar(); - private static final String LAYOUT_ID = "combatant:api/hud/static/custom_health_bar"; + private static final String LAYOUT_ID = "lovisual:api/hud/static/custom_health_bar"; private static final float HEALTH_BAR_WIDTH = 81f; private static final float HEALTH_BAR_HEIGHT = 9f; private static final float HEALTH_BAR_RADIUS = 5.0f; @@ -275,7 +274,7 @@ public final class CustomHealthBar extends AbstractHudElement { } public boolean isHudHealthEnabled() { - return !RuntimeGate.isPanic() && isEnabled(); + return isEnabled(); } public float getHudHealthAlphaFactor() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomHotbar.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomHotbar.java index dd984f0..a6ec7ef 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomHotbar.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/CustomHotbar.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,7 +25,6 @@ import dev.loki.lovisual.mixins.accessors.PlayerInventoryAccessor; import dev.loki.lovisual.render.engine.animation.AnimationUtility; import dev.loki.lovisual.render.engine.math.ColorMath; import dev.loki.lovisual.render.engine.renderer.Renderer2D; -import dev.loki.lovisual.runtime.RuntimeGate; import java.util.List; @@ -326,7 +325,7 @@ public final class CustomHotbar extends AbstractHudElement { } private static int getSelectedSlot(LocalPlayer player) { - return ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); + return ((PlayerInventoryAccessor) player.getInventory()).lovisual$getSelectedSlot(); } private static OffHandMode getOffHandMode() { @@ -390,7 +389,7 @@ public final class CustomHotbar extends AbstractHudElement { } public boolean isHudHotbarEnabled() { - return !RuntimeGate.isPanic() && isEnabled(); + return isEnabled(); } public OffHandMode getHotbarOffHandMode() { @@ -448,11 +447,11 @@ public final class CustomHotbar extends AbstractHudElement { } public boolean isHotbarBlurEnabled() { - return !RuntimeGate.isPanic() && isBlurEffect(); + return isBlurEffect(); } public boolean isHotbarGlassEnabled() { - return !RuntimeGate.isPanic() && isGlassEffect(); + return isGlassEffect(); } public int getHotbarBlurAlpha() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/DynamicIsland.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/DynamicIsland.java index 9642f23..aef9505 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/DynamicIsland.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/DynamicIsland.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -34,7 +34,7 @@ import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.features.module.modules.misc.ClickGui; import dev.loki.lovisual.mixins.accessors.BossHealthOverlayAccessor; import dev.loki.lovisual.render.engine.animation.AnimationUtility; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.RenderPhaseScope; import dev.loki.lovisual.render.engine.core.ViewportContext; @@ -55,7 +55,7 @@ import dev.loki.lovisual.render.engine.renderer.ui.runtime.script.UiScriptModule import dev.loki.lovisual.render.engine.text.FontInfo; import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import dev.loki.lovisual.util.media.MediaSessionService; import dev.loki.lovisual.util.media.RepeatMode; import dev.loki.lovisual.util.pvp.PvpState; @@ -71,7 +71,7 @@ import static dev.loki.lovisual.features.theme.Theme.theme; public final class DynamicIsland extends AbstractHudElement { public static final DynamicIsland INSTANCE = new DynamicIsland(); - private static final String LAYOUT_ID = "combatant:api/hud/static/dynamic_island"; + private static final String LAYOUT_ID = "lovisual:api/hud/static/dynamic_island"; private static final float TOP_Y = 18f; private static final float CLOSED_HEIGHT = 35f; @@ -472,7 +472,7 @@ public final class DynamicIsland extends AbstractHudElement { } private void renderScreenOverlayInternal(GuiGraphicsExtractor ctx, float tickDelta) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; if (mc == null || mc.getWindow() == null || ctx == null) return; Screen currentScreen = ClientScreen.current(); boolean clickGuiOverlay = isEnabled() && clickGuiEnabled(); @@ -488,9 +488,9 @@ public final class DynamicIsland extends AbstractHudElement { mc.getWindow().getHeight() ))); - CombatantRenderSystem.updateFrameTiming(tickDelta, tickDelta, tickDelta); + LoVisualRenderSystem.updateFrameTiming(tickDelta, tickDelta, tickDelta); ViewportContext.beginUnscaledLogical(ctx); - try (RenderPhaseScope ignored = CombatantRenderSystem.phase(RenderPhase.SCREEN_TOP, "2d:screen:dynamic_island")) { + try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.SCREEN_TOP, "2d:screen:dynamic_island")) { Renderer2D.COLOR.begin(); renderEngineInternal(Renderer2D.COLOR, TextRenderer.get(), ctx, tickDelta, screenW, screenH, true); Renderer2D.COLOR.render(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/SwapTooltip.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/SwapTooltip.java index 1b9efc7..4faa8f4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/SwapTooltip.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/SwapTooltip.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,7 +20,6 @@ import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.text.FontInfo; import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; import net.minecraft.client.Minecraft; import net.minecraft.util.Util; @@ -239,7 +238,7 @@ public final class SwapTooltip extends AbstractHudElement { } private boolean useSwapTooltip() { - return !RuntimeGate.isPanic() && isEnabled(); + return isEnabled(); } @Override diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/CustomTabList.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/CustomTabList.java index e024d01..844e8ba 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/CustomTabList.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/CustomTabList.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,7 +17,7 @@ import dev.loki.lovisual.features.gui.hud.HudRenderSpace; import dev.loki.lovisual.features.gui.hud.HudRenderUtil; import dev.loki.lovisual.features.module.HudPhase; import dev.loki.lovisual.features.relations.CategoryType; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.RenderPhaseScope; import dev.loki.lovisual.render.engine.core.ViewportContext; @@ -27,7 +27,7 @@ import dev.loki.lovisual.render.engine.animation.AnimationUtility; import dev.loki.lovisual.render.engine.color.RenderColor; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.helpers.PlayerHeadRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.network.chat.Component; @@ -94,7 +94,7 @@ public final class CustomTabList extends AbstractHudElement { } public static boolean shouldReplaceVanilla() { - return RuntimeGate.canRunHud() + return Lifecycle.canRunHud() && INSTANCE != null && INSTANCE.isEnabled() && INSTANCE.canRenderReplacement(); @@ -108,7 +108,7 @@ public final class CustomTabList extends AbstractHudElement { private void renderVanillaTabStratumInternal(GuiGraphicsExtractor ctx, int guiWidth) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; if (mc == null || mc.getWindow() == null || ctx == null) return; int screenW = Math.max(1, Math.round(HudScale.virtualWidth( mc.getWindow().getWidth(), @@ -119,14 +119,14 @@ public final class CustomTabList extends AbstractHudElement { mc.getWindow().getHeight() ))); - CombatantRenderSystem.ensureFrameContext(); - CombatantRenderSystem.updateFrameTiming( + LoVisualRenderSystem.ensureFrameContext(); + LoVisualRenderSystem.updateFrameTiming( TickDelta.tickProgress(false), TickDelta.frameDeltaTicks(), TickDelta.fixedDeltaTicks() ); ViewportContext.beginCurrentStratumUnscaledLogical(ctx); - try (RenderPhaseScope ignored = CombatantRenderSystem.phase(RenderPhase.SCREEN_TOP, "2d:vanilla_stratum:tab_list")) { + try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.SCREEN_TOP, "2d:vanilla_stratum:tab_list")) { Renderer2D.COLOR.begin(); renderTab(Renderer2D.COLOR, ctx, TickDelta.tickProgress(false), screenW, screenH, true); Renderer2D.COLOR.render(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabListAnimator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabListAnimator.java index 0b2ce3c..a6ea9a1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabListAnimator.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabListAnimator.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabListModel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabListModel.java index ea0bd3e..9b6ff29 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabListModel.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabListModel.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -262,7 +262,7 @@ final class TabListModel { private static Component tabText(PlayerTabOverlay overlay, boolean header) { if (!(overlay instanceof PlayerTabOverlayAccessor accessor)) return null; - Component value = header ? accessor.combatant$getHeader() : accessor.combatant$getFooter(); + Component value = header ? accessor.lovisual$getHeader() : accessor.lovisual$getFooter(); if (value == null || value.getString().isBlank()) return null; return LegacyTextUtil.convertLegacyCodes(value); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabRichTextRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabRichTextRenderer.java index adb5c84..128567d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabRichTextRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/nondraggable/impl/tab/TabRichTextRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/CompactHudStatModel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/CompactHudStatModel.java index 84f7716..e035ba2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/CompactHudStatModel.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/CompactHudStatModel.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/HudScriptLayouts.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/HudScriptLayouts.java index d03d6c3..df76c72 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/HudScriptLayouts.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/HudScriptLayouts.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/ScriptableHudStatWidget.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/ScriptableHudStatWidget.java index af08e94..6ce459c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/ScriptableHudStatWidget.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/ScriptableHudStatWidget.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/ScriptedCompactHudStatRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/ScriptedCompactHudStatRenderer.java index c2e1196..7d801d2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/ScriptedCompactHudStatRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/hud/script/ScriptedCompactHudStatRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -21,7 +21,7 @@ import dev.loki.lovisual.render.engine.text.TextRenderer; public final class ScriptedCompactHudStatRenderer { public static final ScriptedCompactHudStatRenderer INSTANCE = new ScriptedCompactHudStatRenderer(); - private static final String LAYOUT_ID = "combatant:api/hud/draggable/compact_stat"; + private static final String LAYOUT_ID = "lovisual:api/hud/draggable/compact_stat"; private final Minecraft mc = Minecraft.getInstance(); private final UiScriptModuleHandle moduleHandle = HudScriptLayouts.handle(LAYOUT_ID); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualAddonManagerScreen.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualAddonManagerScreen.java index 1ac59fe..dbf1cad 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualAddonManagerScreen.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualAddonManagerScreen.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -105,7 +105,7 @@ public final class LoVisualAddonManagerScreen extends Screen { private TextRenderer bodyRenderer; public LoVisualAddonManagerScreen(Screen parent) { - super(Component.translatable("screen.combatant.addon_manager.title")); + super(Component.translatable("screen.lovisual.addon_manager.title")); this.parent = parent; } @@ -233,14 +233,14 @@ public final class LoVisualAddonManagerScreen extends Screen { float x = l.leftX + 5f * SCALE; float y = l.topY; float w = LEFT_W - 10f * SCALE; - draw(titleRenderer, tr("screen.combatant.addon_manager.header"), l.leftX + 8f * SCALE, y + 7f * SCALE, TITLE_FONT, c.title); + draw(titleRenderer, tr("screen.lovisual.addon_manager.header"), l.leftX + 8f * SCALE, y + 7f * SCALE, TITLE_FONT, c.title); renderSelectedDetails(x, y + 27f * SCALE, w, c, selected, mouseX, mouseY); float metricsY = y + 75f * SCALE; float metricStep = METRIC_H + METRIC_GAP; - renderMetricLine(x, metricsY, w, tr("screen.combatant.addon_manager.installed"), String.valueOf(addons.size()), "package", c, inside(mouseX, mouseY, x, metricsY, w, METRIC_H)); - renderMetricLine(x, metricsY + metricStep, w, tr("screen.combatant.addon_manager.active"), String.valueOf(active), "check", c, inside(mouseX, mouseY, x, metricsY + metricStep, w, METRIC_H)); - renderMetricLine(x, metricsY + metricStep * 2f, w, tr("screen.combatant.addon_manager.issues"), errors + "/" + warnings, errors > 0 ? "folder-x" : "folder-clock", c, inside(mouseX, mouseY, x, metricsY + metricStep * 2f, w, METRIC_H)); + renderMetricLine(x, metricsY, w, tr("screen.lovisual.addon_manager.installed"), String.valueOf(addons.size()), "package", c, inside(mouseX, mouseY, x, metricsY, w, METRIC_H)); + renderMetricLine(x, metricsY + metricStep, w, tr("screen.lovisual.addon_manager.active"), String.valueOf(active), "check", c, inside(mouseX, mouseY, x, metricsY + metricStep, w, METRIC_H)); + renderMetricLine(x, metricsY + metricStep * 2f, w, tr("screen.lovisual.addon_manager.issues"), errors + "/" + warnings, errors > 0 ? "folder-x" : "folder-clock", c, inside(mouseX, mouseY, x, metricsY + metricStep * 2f, w, METRIC_H)); if (statusVisible()) { float statusY = y + LEFT_TOP_H - 15f * SCALE; @@ -257,12 +257,12 @@ public final class LoVisualAddonManagerScreen extends Screen { float half = (w - GAP) * 0.5f; renderAction(x, y, half, BUTTON_H, selected != null && selected.enabled() - ? tr("screen.combatant.addon_manager.disable") - : tr("screen.combatant.addon_manager.enable"), selected != null && selected.enabled(), selected != null && selected.enabled() ? "toggle-left" : "toggle-right", toggleHover, togglePress, c); - renderAction(x + half + GAP, y, half, BUTTON_H, tr("screen.combatant.addon_manager.scan"), false, "folder-sync", scanHover, scanPress, c); - renderAction(x, y + 17f * SCALE, half, BUTTON_H, tr("screen.combatant.addon_manager.mods"), false, "folder-open", modsHover, modsPress, c); - renderAction(x + half + GAP, y + 17f * SCALE, half, BUTTON_H, tr("screen.combatant.addon_manager.config"), false, "folder-cog", configHover, configPress, c); - renderAction(x, y + 34f * SCALE, w, BUTTON_H, tr("screen.combatant.addon_manager.back"), false, "x", backHover, backPress, c); + ? tr("screen.lovisual.addon_manager.disable") + : tr("screen.lovisual.addon_manager.enable"), selected != null && selected.enabled(), selected != null && selected.enabled() ? "toggle-left" : "toggle-right", toggleHover, togglePress, c); + renderAction(x + half + GAP, y, half, BUTTON_H, tr("screen.lovisual.addon_manager.scan"), false, "folder-sync", scanHover, scanPress, c); + renderAction(x, y + 17f * SCALE, half, BUTTON_H, tr("screen.lovisual.addon_manager.mods"), false, "folder-open", modsHover, modsPress, c); + renderAction(x + half + GAP, y + 17f * SCALE, half, BUTTON_H, tr("screen.lovisual.addon_manager.config"), false, "folder-cog", configHover, configPress, c); + renderAction(x, y + 34f * SCALE, w, BUTTON_H, tr("screen.lovisual.addon_manager.back"), false, "x", backHover, backPress, c); } private void renderList(Layout l, PanelColors c, float mouseX, float mouseY) { @@ -367,7 +367,7 @@ public final class LoVisualAddonManagerScreen extends Screen { withAlpha(c.surface, 160), withAlpha(c.surfaceHover, 170), withAlpha(0xFF0D1118, 178), withAlpha(0xFF0D1118, 178)); Renderer2D.COLOR.roundedRectStrokeCorners(x, y, w, h, LEFT_CARD_R, LEFT_CARD_R, LEFT_CARD_R, LEFT_CARD_R, 0.55f, HudRenderUtil.mixColor(c.stroke, c.strokeSoft, 0.36f)); if (selected == null) { - drawCentered(bodyRenderer, tr("screen.combatant.addon_manager.empty"), x + w * 0.5f, y + 17f * SCALE, BODY_FONT, c.mutedLabel); + drawCentered(bodyRenderer, tr("screen.lovisual.addon_manager.empty"), x + w * 0.5f, y + 17f * SCALE, BODY_FONT, c.mutedLabel); return; } float iconBox = 18f * SCALE; @@ -408,13 +408,13 @@ public final class LoVisualAddonManagerScreen extends Screen { float iconX = x + 7.0f * SCALE; float iconY = centerY - iconSize * 0.5f; drawSvgGradient("folder-tree", iconX, iconY, iconSize, iconSize, c); - String title = tr("screen.combatant.addon_manager.list"); + String title = tr("screen.lovisual.addon_manager.list"); float titleX = x + 25.0f * SCALE; float titleW = Math.max(1f, w - 33f * SCALE); float titleY = centerY - 4.8f * SCALE; drawFitOrMarquee(titleRenderer, title, titleX, titleY, TITLE_FONT, titleW, c.title, inside(mouseX, mouseY, titleX, titleY - 1.5f * SCALE, titleW, 12f * SCALE)); if (!scanIssues.isEmpty()) { - String label = tr("screen.combatant.addon_manager.status.scanned", scanIssues.size()); + String label = tr("screen.lovisual.addon_manager.status.scanned", scanIssues.size()); float labelW = Math.min(w * 0.34f, Math.max(42f * SCALE, width(bodyRenderer, label, SMALL_FONT))); float labelX = x + w - labelW - 8f * SCALE; drawFitOrMarquee(bodyRenderer, label, labelX, centerY - 3.6f * SCALE, SMALL_FONT, labelW, c.muted, inside(mouseX, mouseY, labelX, centerY - 5f * SCALE, labelW, 10f * SCALE)); @@ -429,7 +429,7 @@ public final class LoVisualAddonManagerScreen extends Screen { Renderer2D.COLOR.roundedRectGradientQuad(boxX, boxY, boxW, boxH, 7f * SCALE, 1f, c.detailTop, c.detailTop, c.detailBottom, c.detailBottom); Renderer2D.COLOR.roundedRectStrokeGradient(boxX, boxY, boxW, boxH, 7f * SCALE, 1.2f, 0.5f, c.strokeSoft, c.stroke, 90f); drawSvgGradient("folder-open", boxX + boxW * 0.5f - 8f * SCALE, boxY + 7f * SCALE, 16f * SCALE, 16f * SCALE, c); - drawCentered(bodyRenderer, tr("screen.combatant.addon_manager.empty"), boxX + boxW * 0.5f, boxY + 27f * SCALE, SMALL_FONT, c.muted); + drawCentered(bodyRenderer, tr("screen.lovisual.addon_manager.empty"), boxX + boxW * 0.5f, boxY + 27f * SCALE, SMALL_FONT, c.muted); } private float miniStatusWidth(String label) { @@ -557,20 +557,20 @@ public final class LoVisualAddonManagerScreen extends Screen { if (inside(mouseX, mouseY, x + half + GAP, y, half, BUTTON_H)) { scanPress = 1f; scanIssues = AddonManager.scan(); - setStatus(scanIssues.isEmpty() ? "" : tr("screen.combatant.addon_manager.status.scanned", scanIssues.size())); + setStatus(scanIssues.isEmpty() ? "" : tr("screen.lovisual.addon_manager.status.scanned", scanIssues.size())); return true; } if (inside(mouseX, mouseY, x, y + 17f * SCALE, half, BUTTON_H)) { modsPress = 1f; if (openPath(FabricLoader.getInstance().getGameDir().resolve("mods"))) { - setStatus(tr("screen.combatant.addon_manager.status.opened_mods")); + setStatus(tr("screen.lovisual.addon_manager.status.opened_mods")); } return true; } if (inside(mouseX, mouseY, x + half + GAP, y + 17f * SCALE, half, BUTTON_H)) { configPress = 1f; - if (openPath(FabricLoader.getInstance().getConfigDir().resolve("combatant").resolve("addons"))) { - setStatus(tr("screen.combatant.addon_manager.status.opened_config")); + if (openPath(FabricLoader.getInstance().getConfigDir().resolve("lovisual").resolve("addons"))) { + setStatus(tr("screen.lovisual.addon_manager.status.opened_config")); } return true; } @@ -686,7 +686,7 @@ public final class LoVisualAddonManagerScreen extends Screen { Util.getPlatform().openUri(path.toUri()); return true; } catch (Throwable ignored) { - setStatus(tr("screen.combatant.addon_manager.status.open_failed")); + setStatus(tr("screen.lovisual.addon_manager.status.open_failed")); return false; } } @@ -703,23 +703,23 @@ public final class LoVisualAddonManagerScreen extends Screen { } private String statusText(AddonSnapshot addon) { - if (!addon.enabled()) return tr("screen.combatant.addon_manager.status.disabled_short"); + if (!addon.enabled()) return tr("screen.lovisual.addon_manager.status.disabled_short"); return switch (addon.status()) { - case ACTIVE -> tr("screen.combatant.addon_manager.state.active"); - case ERROR -> tr("screen.combatant.addon_manager.state.error"); - case DISABLED -> tr("screen.combatant.addon_manager.state.disabled"); - case SUSPENDED -> tr("screen.combatant.addon_manager.state.suspended"); - case SHUTDOWN -> tr("screen.combatant.addon_manager.state.shutdown"); + case ACTIVE -> tr("screen.lovisual.addon_manager.state.active"); + case ERROR -> tr("screen.lovisual.addon_manager.state.error"); + case DISABLED -> tr("screen.lovisual.addon_manager.state.disabled"); + case SUSPENDED -> tr("screen.lovisual.addon_manager.state.suspended"); + case SHUTDOWN -> tr("screen.lovisual.addon_manager.state.shutdown"); default -> addon.status().name().toLowerCase(Locale.ROOT); }; } private String countsText(AddonSnapshot addon) { int hud = addon.draggableHudElements() + addon.staticHudElements(); - return tr("screen.combatant.addon_manager.metric.modules") + " " + addon.modules() - + " · " + tr("screen.combatant.addon_manager.metric.hud") + " " + hud - + " · " + tr("screen.combatant.addon_manager.metric.commands") + " " + addon.commands() - + " · " + tr("screen.combatant.addon_manager.metric.gui") + " " + addon.clickGuiSections(); + return tr("screen.lovisual.addon_manager.metric.modules") + " " + addon.modules() + + " · " + tr("screen.lovisual.addon_manager.metric.hud") + " " + hud + + " · " + tr("screen.lovisual.addon_manager.metric.commands") + " " + addon.commands() + + " · " + tr("screen.lovisual.addon_manager.metric.gui") + " " + addon.clickGuiSections(); } private int statusColor(AddonSnapshot addon, PanelColors c) { @@ -924,7 +924,7 @@ public final class LoVisualAddonManagerScreen extends Screen { if (addon == null) return ""; AddonIssue issue = primaryIssue(addon); if (issue != null) return issueText(issue); - if (addon.restartRequired()) return tr("screen.combatant.addon_manager.restart_required"); + if (addon.restartRequired()) return tr("screen.lovisual.addon_manager.restart_required"); return addonDescription(addon); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualAltManagerScreen.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualAltManagerScreen.java index 0e758f7..d948788 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualAltManagerScreen.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualAltManagerScreen.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -136,7 +136,7 @@ public final class LoVisualAltManagerScreen extends Screen { } public LoVisualAltManagerScreen(Screen parent, boolean microsoftMode) { - super(Component.translatable("screen.combatant.alt_manager.title")); + super(Component.translatable("screen.lovisual.alt_manager.title")); this.parent = parent; this.microsoftMode = microsoftMode; } @@ -280,10 +280,10 @@ public final class LoVisualAltManagerScreen extends Screen { } private void renderTopPanel(float mouseX, float mouseY, float x, float y, PanelColors c) { - drawCentered(titleRenderer, tr("screen.combatant.alt_manager.account_panel"), x + LEFT_W * 0.5f - 8f * SCALE, y + 7f * SCALE, TITLE_FONT, c.title); + drawCentered(titleRenderer, tr("screen.lovisual.alt_manager.account_panel"), x + LEFT_W * 0.5f - 8f * SCALE, y + 7f * SCALE, TITLE_FONT, c.title); renderModeToggle(mouseX, mouseY, x + 5f * SCALE, y + 27f * SCALE, LEFT_W - 10f * SCALE, 13f * SCALE, c); - draw(bodyRenderer, microsoftMode ? tr("screen.combatant.alt_manager.microsoft_login") : tr("screen.combatant.alt_manager.nickname"), x + 5f * SCALE, y + 47f * SCALE, LABEL_FONT, c.label); + draw(bodyRenderer, microsoftMode ? tr("screen.lovisual.alt_manager.microsoft_login") : tr("screen.lovisual.alt_manager.nickname"), x + 5f * SCALE, y + 47f * SCALE, LABEL_FONT, c.label); float fieldX = x + 5f * SCALE; float fieldY = y + 57f * SCALE; @@ -305,23 +305,23 @@ public final class LoVisualAltManagerScreen extends Screen { String authAction = microsoftMode ? (microsoftUserCode.isBlank() - ? (microsoftAuthPending ? tr("screen.combatant.alt_manager.waiting") : tr("screen.combatant.alt_manager.authorize")) - : tr("screen.combatant.alt_manager.copy_code")) - : tr("screen.combatant.alt_manager.random"); + ? (microsoftAuthPending ? tr("screen.lovisual.alt_manager.waiting") : tr("screen.lovisual.alt_manager.authorize")) + : tr("screen.lovisual.alt_manager.copy_code")) + : tr("screen.lovisual.alt_manager.random"); if (microsoftMode) { renderSvgAction(buttonX, randomY, buttonW, TOP_BUTTON_H, c, false, authAction, "user-check", randomHoverAnim, randomPressAnim); } else { renderAction(buttonX, randomY, buttonW, TOP_BUTTON_H, c, false, authAction, iconRenderer, "R", randomHoverAnim, randomPressAnim); } if (microsoftMode) { - renderSvgAction(buttonX, openSiteY, buttonW, TOP_BUTTON_H, c, false, tr("screen.combatant.alt_manager.open_site"), "external-link", openSiteHoverAnim, openSitePressAnim); + renderSvgAction(buttonX, openSiteY, buttonW, TOP_BUTTON_H, c, false, tr("screen.lovisual.alt_manager.open_site"), "external-link", openSiteHoverAnim, openSitePressAnim); } - renderAction(buttonX, clearY, buttonW, TOP_BUTTON_H, c, true, tr("screen.combatant.alt_manager.clear_all"), guiIconRenderer, "O", clearHoverAnim, clearPressAnim); + renderAction(buttonX, clearY, buttonW, TOP_BUTTON_H, c, true, tr("screen.lovisual.alt_manager.clear_all"), guiIconRenderer, "O", clearHoverAnim, clearPressAnim); } private void renderActivePanel(GuiGraphicsExtractor context, float x, float y, PanelColors c) { - drawCentered(titleRenderer, tr("screen.combatant.alt_manager.active_session"), x + LEFT_W * 0.5f - 15f * SCALE, y + 6f * SCALE, TITLE_FONT, c.title); + drawCentered(titleRenderer, tr("screen.lovisual.alt_manager.active_session"), x + LEFT_W * 0.5f - 15f * SCALE, y + 6f * SCALE, TITLE_FONT, c.title); float cardX = x + 5f * SCALE; float cardY = y + 24f * SCALE; @@ -333,7 +333,7 @@ public final class LoVisualAltManagerScreen extends Screen { String activeName = accountConfig.getActiveAccountName(); if (activeName == null || activeName.isBlank()) { - drawCentered(bodyRenderer, tr("screen.combatant.alt_manager.no_account_selected"), cardX + cardW * 0.5f, cardY + 10.2f * SCALE, EMPTY_FONT, c.mutedLabel); + drawCentered(bodyRenderer, tr("screen.lovisual.alt_manager.no_account_selected"), cardX + cardW * 0.5f, cardY + 10.2f * SCALE, EMPTY_FONT, c.mutedLabel); return; } float faceX = cardX + 5f * SCALE; @@ -351,11 +351,11 @@ public final class LoVisualAltManagerScreen extends Screen { } private void renderAccountsPanel(GuiGraphicsExtractor context, float mouseX, float mouseY, float x, float y, PanelColors c) { - draw(titleRenderer, tr("screen.combatant.alt_manager.accounts_list"), x + 8f * SCALE, y + 7f * SCALE, TITLE_FONT, c.title); + draw(titleRenderer, tr("screen.lovisual.alt_manager.accounts_list"), x + 8f * SCALE, y + 7f * SCALE, TITLE_FONT, c.title); List accounts = accountConfig.getSortedAccounts(); if (accounts.isEmpty()) { - drawCentered(bodyRenderer, tr("screen.combatant.alt_manager.no_accounts_added"), x + RIGHT_W * 0.5f, y + RIGHT_H * 0.5f + 2f * SCALE, EMPTY_FONT, c.mutedLabel); + drawCentered(bodyRenderer, tr("screen.lovisual.alt_manager.no_accounts_added"), x + RIGHT_W * 0.5f, y + RIGHT_H * 0.5f + 2f * SCALE, EMPTY_FONT, c.mutedLabel); return; } @@ -456,7 +456,7 @@ public final class LoVisualAltManagerScreen extends Screen { private void renderAuthBadge(AccountEntry entry, float x, float y, PanelColors c) { boolean microsoft = entry != null && entry.isMicrosoft(); - String label = microsoft ? tr("screen.combatant.alt_manager.badge.microsoft") : tr("screen.combatant.alt_manager.badge.offline"); + String label = microsoft ? tr("screen.lovisual.alt_manager.badge.microsoft") : tr("screen.lovisual.alt_manager.badge.offline"); float padX = 3.2f * SCALE; float badgeW = width(bodyRenderer, label, BADGE_FONT) + padX * 2f; float badgeH = 7f * SCALE; @@ -472,9 +472,9 @@ public final class LoVisualAltManagerScreen extends Screen { private void renderModeToggle(float mouseX, float mouseY, float x, float y, float w, float h, PanelColors c) { float gap = 2f * SCALE; float itemW = (w - gap) * 0.5f; - renderModeButton(x, y, itemW, h, c, tr("screen.combatant.alt_manager.mode.offline"), !microsoftMode, + renderModeButton(x, y, itemW, h, c, tr("screen.lovisual.alt_manager.mode.offline"), !microsoftMode, inside(mouseX, mouseY, x, y, itemW, h), offlineModeHoverAnim, offlineModePressAnim); - renderModeButton(x + itemW + gap, y, itemW, h, c, tr("screen.combatant.alt_manager.mode.microsoft"), microsoftMode, + renderModeButton(x + itemW + gap, y, itemW, h, c, tr("screen.lovisual.alt_manager.mode.microsoft"), microsoftMode, inside(mouseX, mouseY, x + itemW + gap, y, itemW, h), microsoftModeHoverAnim, microsoftModePressAnim); } @@ -512,13 +512,13 @@ public final class LoVisualAltManagerScreen extends Screen { String display; int color; if (!microsoftUserCode.isBlank()) { - display = tr("screen.combatant.alt_manager.code", microsoftUserCode); + display = tr("screen.lovisual.alt_manager.code", microsoftUserCode); color = c.title; } else if (!microsoftStatus.isBlank()) { display = microsoftStatus; color = microsoftAuthPending ? c.title : c.muted; } else { - display = tr("screen.combatant.alt_manager.ready_to_sign_in"); + display = tr("screen.lovisual.alt_manager.ready_to_sign_in"); color = c.mutedLabel; } draw(bodyRenderer, ellipsize(display, FIELD_FONT, w - 8f * SCALE), x + 4f * SCALE, y + 4.3f * SCALE, FIELD_FONT, color); @@ -542,7 +542,7 @@ public final class LoVisualAltManagerScreen extends Screen { } boolean caretOn = nicknameFieldFocused && AnimationUtility.blink(500L); - String display = nicknameText.isEmpty() && !nicknameFieldFocused ? tr("screen.combatant.alt_manager.enter_nick") : nicknameText + (caretOn ? "|" : ""); + String display = nicknameText.isEmpty() && !nicknameFieldFocused ? tr("screen.lovisual.alt_manager.enter_nick") : nicknameText + (caretOn ? "|" : ""); draw(bodyRenderer, display, x + 4f * SCALE, y + 4.3f * SCALE, FIELD_FONT, nicknameText.isEmpty() && !nicknameFieldFocused ? c.mutedLabel : c.title); } @@ -851,7 +851,7 @@ public final class LoVisualAltManagerScreen extends Screen { microsoftAuthPending = true; microsoftUserCode = ""; microsoftVerificationUrl = ""; - microsoftStatus = tr("screen.combatant.alt_manager.status.requesting_code"); + microsoftStatus = tr("screen.lovisual.alt_manager.status.requesting_code"); MicrosoftAuthService.requestDeviceCode() .thenCompose(code -> { @@ -873,14 +873,14 @@ public final class LoVisualAltManagerScreen extends Screen { } microsoftUserCode = code.userCode(); microsoftVerificationUrl = code.verificationUri().toString(); - microsoftStatus = tr("screen.combatant.alt_manager.status.use_link"); + microsoftStatus = tr("screen.lovisual.alt_manager.status.use_link"); copyMicrosoftAuthData(); } private void finishMicrosoftAuthorization(MicrosoftSessionResult session, Throwable throwable) { microsoftAuthPending = false; if (throwable != null) { - microsoftStatus = tr("screen.combatant.alt_manager.status.auth_failed"); + microsoftStatus = tr("screen.lovisual.alt_manager.status.auth_failed"); microsoftUserCode = ""; microsoftVerificationUrl = ""; Throwable root = unwrap(throwable); @@ -892,7 +892,7 @@ public final class LoVisualAltManagerScreen extends Screen { AccountEntry entry = accountConfig.addMicrosoftAccount(session); if (entry == null) { - microsoftStatus = tr("screen.combatant.alt_manager.status.auth_failed"); + microsoftStatus = tr("screen.lovisual.alt_manager.status.auth_failed"); microsoftUserCode = ""; microsoftVerificationUrl = ""; return; @@ -900,7 +900,7 @@ public final class LoVisualAltManagerScreen extends Screen { accountConfig.setActiveAccount(entry); SkinManager.getSkin(entry.getName()); - microsoftStatus = tr("screen.combatant.alt_manager.status.authorized", entry.getName()); + microsoftStatus = tr("screen.lovisual.alt_manager.status.authorized", entry.getName()); microsoftUserCode = ""; microsoftVerificationUrl = ""; clampScroll(); @@ -909,10 +909,10 @@ public final class LoVisualAltManagerScreen extends Screen { private void copyMicrosoftAuthData() { if (!microsoftUserCode.isBlank()) { ClipboardUtil.copy(microsoftUserCode); - microsoftStatus = tr("screen.combatant.alt_manager.status.code_copied"); + microsoftStatus = tr("screen.lovisual.alt_manager.status.code_copied"); } else if (!microsoftVerificationUrl.isBlank()) { ClipboardUtil.copy(microsoftVerificationUrl); - microsoftStatus = tr("screen.combatant.alt_manager.status.link_copied"); + microsoftStatus = tr("screen.lovisual.alt_manager.status.link_copied"); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualMainMenuScreen.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualMainMenuScreen.java index b056339..cfe3c33 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualMainMenuScreen.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualMainMenuScreen.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -41,7 +41,6 @@ import dev.loki.lovisual.render.engine.text.FontInfo; import dev.loki.lovisual.render.engine.text.Fonts; import dev.loki.lovisual.render.engine.text.TextRenderer; import dev.loki.lovisual.render.helpers.PlayerHeadRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; import dev.loki.lovisual.util.logging.DebugLog; import java.time.LocalDate; @@ -128,10 +127,6 @@ public final class LoVisualMainMenuScreen extends Screen { @Override public void extractRenderState(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta) { - if (RuntimeGate.isPanic()) { - if (minecraft != null) ClientScreen.show(minecraft, null); - return; - } if (shouldUseVanillaTitleScreen()) { switchToVanillaTitleScreen(null); return; @@ -390,8 +385,8 @@ public final class LoVisualMainMenuScreen extends Screen { TextRenderer title = Fonts.renderer("Inter", FontInfo.Type.Bold, TextRenderer.get()); TextRenderer body = Fonts.renderer("InterMedium", FontInfo.Type.Regular, title); float textX = headX + AUTH_WARNING_HEAD + 8f * MENU_SCALE; - drawText(title, tr("screen.combatant.main_menu.auth_warning.title"), textX, y + 12.2f * MENU_SCALE, 0.72f * MENU_SCALE, withAlpha(0xFFFFFF, Math.round(opacity * 245f))); - String message = tr("screen.combatant.main_menu.auth_warning.body", entry.getName()); + drawText(title, tr("screen.lovisual.main_menu.auth_warning.title"), textX, y + 12.2f * MENU_SCALE, 0.72f * MENU_SCALE, withAlpha(0xFFFFFF, Math.round(opacity * 245f))); + String message = tr("screen.lovisual.main_menu.auth_warning.body", entry.getName()); drawText(body, ellipsize(body, message, 0.55f * MENU_SCALE, b.x + b.w - textX - 10f * MENU_SCALE), textX, y + 25.4f * MENU_SCALE, 0.55f * MENU_SCALE, withAlpha(0xC8D0DC, Math.round(opacity * 225f))); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualProxyManagerScreen.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualProxyManagerScreen.java index 44f62d1..f4b5b40 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualProxyManagerScreen.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/gui/mainmenu/LoVisualProxyManagerScreen.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -77,7 +77,7 @@ public final class LoVisualProxyManagerScreen extends Screen { private TextRenderer bodyRenderer; public LoVisualProxyManagerScreen(Screen parent) { - super(Component.translatable("screen.combatant.proxy_manager.title")); + super(Component.translatable("screen.lovisual.proxy_manager.title")); this.parent = parent; } @@ -198,24 +198,24 @@ public final class LoVisualProxyManagerScreen extends Screen { c.headerTopLeft, c.headerTopRight, c.headerBottomRight, c.headerBottomLeft); Renderer2D.COLOR.roundedRectStrokeGradient(b.x, b.y, PANEL_W, PANEL_H, PANEL_R, 1f, 1f, HudRenderUtil.mixColor(c.stroke, 0xFFFFFFFF, 0.04f), c.stroke, 90f); - drawCentered(titleRenderer, tr("screen.combatant.proxy_manager.header"), b.x + PANEL_W * 0.5f, b.y + 7f * SCALE, TITLE_FONT, c.title); + drawCentered(titleRenderer, tr("screen.lovisual.proxy_manager.header"), b.x + PANEL_W * 0.5f, b.y + 7f * SCALE, TITLE_FONT, c.title); float innerX = b.x + 8f * SCALE; float innerW = PANEL_W - 16f * SCALE; float rowY = b.y + 28f * SCALE; - renderToggle(innerX, rowY, 66f * SCALE, 13f * SCALE, tr("screen.combatant.proxy_manager.enabled"), enabled, enableHover, enablePress, c); + renderToggle(innerX, rowY, 66f * SCALE, 13f * SCALE, tr("screen.lovisual.proxy_manager.enabled"), enabled, enableHover, enablePress, c); renderTypeToggle(innerX + 72f * SCALE, rowY, innerW - 72f * SCALE, 13f * SCALE, c); float fieldY = b.y + 53f * SCALE; - renderField(Field.ADDRESS, tr("screen.combatant.proxy_manager.address"), tr("screen.combatant.proxy_manager.placeholder.address"), innerX, fieldY, innerW, c); - renderField(Field.USERNAME, tr("screen.combatant.proxy_manager.username"), tr("screen.combatant.proxy_manager.placeholder.optional"), innerX, fieldY + 27f * SCALE, innerW, c); - renderField(Field.PASSWORD, tr("screen.combatant.proxy_manager.password"), tr("screen.combatant.proxy_manager.placeholder.optional"), innerX, fieldY + 54f * SCALE, innerW, c); + renderField(Field.ADDRESS, tr("screen.lovisual.proxy_manager.address"), tr("screen.lovisual.proxy_manager.placeholder.address"), innerX, fieldY, innerW, c); + renderField(Field.USERNAME, tr("screen.lovisual.proxy_manager.username"), tr("screen.lovisual.proxy_manager.placeholder.optional"), innerX, fieldY + 27f * SCALE, innerW, c); + renderField(Field.PASSWORD, tr("screen.lovisual.proxy_manager.password"), tr("screen.lovisual.proxy_manager.placeholder.optional"), innerX, fieldY + 54f * SCALE, innerW, c); float buttonY = b.y + PANEL_H - 26f * SCALE; float third = (innerW - GAP * 2f) / 3f; - renderAction(innerX, buttonY, third, BUTTON_H, tr("screen.combatant.proxy_manager.save"), false, saveHover, savePress, c); - renderAction(innerX + third + GAP, buttonY, third, BUTTON_H, tr("screen.combatant.proxy_manager.clear"), true, clearHover, clearPress, c); - renderAction(innerX + (third + GAP) * 2f, buttonY, third, BUTTON_H, tr("screen.combatant.proxy_manager.back"), false, backHover, backPress, c); + renderAction(innerX, buttonY, third, BUTTON_H, tr("screen.lovisual.proxy_manager.save"), false, saveHover, savePress, c); + renderAction(innerX + third + GAP, buttonY, third, BUTTON_H, tr("screen.lovisual.proxy_manager.clear"), true, clearHover, clearPress, c); + renderAction(innerX + (third + GAP) * 2f, buttonY, third, BUTTON_H, tr("screen.lovisual.proxy_manager.back"), false, backHover, backPress, c); String info = status.isBlank() ? currentSummary() : status; draw(bodyRenderer, ellipsize(info, FIELD_FONT, innerW), innerX, b.y + PANEL_H - 42f * SCALE, FIELD_FONT, c.muted); @@ -305,7 +305,7 @@ public final class LoVisualProxyManagerScreen extends Screen { if (inside(mouseX, mouseY, innerX, rowY, 66f * SCALE, 13f * SCALE)) { enabled = !enabled; enablePress = 1f; - status = enabled ? tr("screen.combatant.proxy_manager.status.enabled") : tr("screen.combatant.proxy_manager.status.disabled"); + status = enabled ? tr("screen.lovisual.proxy_manager.status.enabled") : tr("screen.lovisual.proxy_manager.status.disabled"); return true; } @@ -365,7 +365,7 @@ public final class LoVisualProxyManagerScreen extends Screen { private void saveProxy() { String address = values[Field.ADDRESS.index].trim(); if (!address.isEmpty() && !ProxyEntry.isValidIpPort(address)) { - status = tr("screen.combatant.proxy_manager.status.invalid_address"); + status = tr("screen.lovisual.proxy_manager.status.invalid_address"); return; } if (address.isEmpty()) { @@ -377,8 +377,8 @@ public final class LoVisualProxyManagerScreen extends Screen { ProxyBackend.setDefaultProxy(entry); ProxyBackend.setEnabled(enabled); status = address.isEmpty() - ? tr("screen.combatant.proxy_manager.status.cleared") - : tr("screen.combatant.proxy_manager.status.saved", type.name()); + ? tr("screen.lovisual.proxy_manager.status.cleared") + : tr("screen.lovisual.proxy_manager.status.saved", type.name()); } private void clearProxy() { @@ -390,13 +390,13 @@ public final class LoVisualProxyManagerScreen extends Screen { focusedField = null; ProxyBackend.setDefaultProxy(ProxyEntry.empty()); ProxyBackend.setEnabled(false); - status = tr("screen.combatant.proxy_manager.status.cleared"); + status = tr("screen.lovisual.proxy_manager.status.cleared"); } private String currentSummary() { - if (!enabled) return tr("screen.combatant.proxy_manager.status.disabled"); + if (!enabled) return tr("screen.lovisual.proxy_manager.status.disabled"); String address = values[Field.ADDRESS.index].trim(); - if (address.isEmpty()) return tr("screen.combatant.proxy_manager.status.enabled_no_address"); + if (address.isEmpty()) return tr("screen.lovisual.proxy_manager.status.enabled_no_address"); return type.name() + " " + address; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/HudPhase.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/HudPhase.java index 8572433..d424f92 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/HudPhase.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/HudPhase.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Module.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Module.java index 91d5427..973e7a5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Module.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Module.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -24,7 +24,7 @@ import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.text.FontInfo; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import dev.loki.lovisual.util.input.KeyManager; import dev.loki.lovisual.util.logging.DebugLog; import net.minecraft.client.resources.language.I18n; @@ -931,7 +931,7 @@ public abstract class Module implements ConfigObject, ConfigNameProvider, Settin } public final void setEnabled(boolean state, ModuleActivationSource source) { - if (state && !RuntimeGate.canRunModules() && !(this instanceof RuntimeControlModule)) { + if (state && !Lifecycle.isActive()) { return; } ModuleActivationSource normalizedSource = normalizeActivationSource(state, source); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleActivationSource.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleActivationSource.java index dfc6751..88e9893 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleActivationSource.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleActivationSource.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleAutoLoader.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleAutoLoader.java index d41dccd..e99a180 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleAutoLoader.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleAutoLoader.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleCategory.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleCategory.java index 51c1d6e..d221a4f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleCategory.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleCategory.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleInfo.java index adb2dc8..23918a5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleInfo.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleManager.java index c57ddc7..44b91c4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -22,8 +22,7 @@ import dev.loki.lovisual.render.engine.profiler.RenderProfiler3D; 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.runtime.RuntimeGate; -import dev.loki.lovisual.runtime.RuntimeShutdownContext; +import dev.loki.lovisual.Lifecycle; import dev.loki.lovisual.util.input.KeyManager; import dev.loki.lovisual.util.logging.DebugLog; @@ -47,8 +46,6 @@ public enum ModuleManager { private static boolean suppressToggleSound = false; @Setter private static boolean suppressToggleNotifications = false; - private static List softPanicEnabledModules = Collections.emptyList(); - private static boolean runtimeReleased = false; static { for (HudPhase phase : HudPhase.values()) { @@ -62,7 +59,6 @@ public enum ModuleManager { } public static void register(Module module) { - if (runtimeReleased || RuntimeGate.isJarReplacementMode()) return; if (module == null) { DebugLog.error("Skipping null module registration"); return; @@ -141,18 +137,14 @@ public enum ModuleManager { } public static Module get(String name) { - if (runtimeReleased || RuntimeGate.isJarReplacementMode()) return null; if (name == null || name.isBlank()) return null; Module module = byId.get(normalizeName(name)); - if (module != null && !RuntimeGate.canRunModules() && !(module instanceof RuntimeControlModule)) return null; return module; } public static T get(Class type) { - if (runtimeReleased || RuntimeGate.isJarReplacementMode()) return null; if (type == null) return null; Module module = byType.get(type); - if (module != null && !RuntimeGate.canRunModules() && !(module instanceof RuntimeControlModule)) return null; return module == null ? null : type.cast(module); } @@ -178,7 +170,7 @@ public enum ModuleManager { public static void tickAll() { Minecraft mc = Minecraft.getInstance(); if (mc.player == null) return; - if (!RuntimeGate.canRunModules()) return; + if (!Lifecycle.isActive()) return; Module[] snapshot = modulesSnapshot; for (Module m : snapshot) { @@ -190,7 +182,7 @@ public enum ModuleManager { } public static void frameAll(float frameDeltaTicks) { - if (!RuntimeGate.canRunModules()) return; + if (!Lifecycle.isActive()) return; Module[] snapshot = modulesSnapshot; for (Module m : snapshot) { if (m.isEnabled() && ModuleExtensionManager.beforeFrame(m, frameDeltaTicks)) { @@ -204,7 +196,7 @@ public enum ModuleManager { GuiGraphicsExtractor ctx, float tickDelta) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; Module[] phaseModules = HUD_PHASE_SNAPSHOTS.get(phase); if (phaseModules == null) return; @@ -217,7 +209,7 @@ public enum ModuleManager { } public static void renderHudEngine(HudPhase phase, Renderer2D renderer, TextRenderer textRenderer, GuiGraphicsExtractor ctx, float tickDelta) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; Module[] phaseModules = HUD_PHASE_SNAPSHOTS.get(phase); if (phaseModules == null) return; @@ -240,7 +232,7 @@ public enum ModuleManager { } public static void renderHudEngineForeground(HudPhase phase, Renderer2D renderer, TextRenderer textRenderer, GuiGraphicsExtractor ctx, float tickDelta) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; Module[] phaseModules = HUD_PHASE_SNAPSHOTS.get(phase); if (phaseModules == null) return; @@ -260,7 +252,7 @@ public enum ModuleManager { } private static boolean hasEnabledHudPhaseModule(HudPhase phase) { - if (!RuntimeGate.canRunHud()) return false; + if (!Lifecycle.canRunHud()) return false; Module[] phaseModules = HUD_PHASE_SNAPSHOTS.get(phase); if (phaseModules == null) return false; @@ -276,7 +268,7 @@ public enum ModuleManager { public static void renderWorld(WorldPhase phase, PoseStack matrices, SubmitNodeCollector consumers, float tickDelta) { - if (!RuntimeGate.canRunRender()) return; + if (!Lifecycle.canRunRender()) return; Module[] phaseModules = WORLD_PHASE_SNAPSHOTS.get(phase); if (phaseModules == null) return; @@ -289,7 +281,7 @@ public enum ModuleManager { } public static void renderWorldEngine(WorldPhase phase, Renderer3D renderer, Renderer3D depthRenderer, float tickDelta) { - if (!RuntimeGate.canRunRender()) return; + if (!Lifecycle.canRunRender()) return; Module[] phaseModules = WORLD_PHASE_SNAPSHOTS.get(phase); if (phaseModules == null) return; @@ -312,11 +304,10 @@ public enum ModuleManager { // --------------------------- public static void handleModuleKeybinds() { - if (!RuntimeGate.canRunModules()) return; + if (!Lifecycle.isActive()) return; boolean soundSuppressedThisPass = false; Module[] snapshot = modulesSnapshot; for (Module m : snapshot) { - if (m instanceof RuntimeControlModule) continue; if (KeyManager.wasPressed(m.name())) { setSuppressToggleSound(soundSuppressedThisPass); m.toggleFromKeybind(); @@ -326,15 +317,6 @@ public enum ModuleManager { setSuppressToggleSound(false); } - public static void tickRuntimeControllers() { - Module[] snapshot = modulesSnapshot; - for (Module module : snapshot) { - if (module instanceof RuntimeControlModule controller) { - controller.onRuntimeControlTick(); - } - } - } - public static List getEnabledModulesNames() { List list = new ArrayList<>(); Module[] snapshot = modulesSnapshot; @@ -359,12 +341,11 @@ public enum ModuleManager { * View of all registered modules (do not modify). */ public static List getModules() { - if (runtimeReleased || RuntimeGate.isJarReplacementMode()) return List.of(); return modulesView; } public static void setEnabledModules(List names) { - if (!RuntimeGate.canRunModules() && !RuntimeGate.canRunRuntimeController()) return; + if (!Lifecycle.isActive()) return; boolean prev = suppressToggleNotifications; suppressToggleNotifications = true; try { @@ -392,7 +373,7 @@ public enum ModuleManager { public static boolean isEnabled(String name) { Module m = get(name); - return m != null && m.isEnabled() && (RuntimeGate.canRunModules() || m instanceof RuntimeControlModule); + return m != null && m.isEnabled(); } public static void setEnabled(String name, boolean enabled) { @@ -402,7 +383,7 @@ public enum ModuleManager { public static void setEnabled(String name, boolean enabled, ModuleActivationSource source) { Module m = get(name); if (m == null) return; - if (enabled && !RuntimeGate.canRunModules() && !(m instanceof RuntimeControlModule)) return; + if (enabled && !Lifecycle.isActive()) return; if (enabled && name.equals("clickgui")) { if (ClientScreen.current(Minecraft.getInstance()) != null) { @@ -519,80 +500,19 @@ public enum ModuleManager { return modulesSnapshot.length; } - public static void shutdownForRuntime(RuntimeShutdownContext context) { - if (context == null) return; + public static void disableAll() { Module[] snapshot = modulesSnapshot; - List enabled = new ArrayList<>(); - int disabled = 0; boolean prevNotifications = suppressToggleNotifications; suppressToggleNotifications = true; try { for (Module module : snapshot) { - if (module == null) continue; - if (module.isEnabled()) { - enabled.add(module.name()); - if (!(module instanceof RuntimeControlModule)) { - module.setRuntimeEnabledTransient(false); - disabled++; - } + if (module != null && module.isEnabled()) { + module.setEnabled(false, ModuleActivationSource.INTERNAL); } } } finally { suppressToggleNotifications = prevNotifications; } - if (!context.jarReplacement()) { - softPanicEnabledModules = enabled; - } - context.increment("modules_disabled", disabled); - if (context.jarReplacement()) { - releaseRuntimeReferences(context); - } - } - - public static void restoreAfterSoftPanic(String reason) { - if (runtimeReleased || RuntimeGate.isJarReplacementMode()) return; - List restore = softPanicEnabledModules; - softPanicEnabledModules = Collections.emptyList(); - if (restore == null || restore.isEmpty()) return; - ObjectOpenHashSet enabledNames = new ObjectOpenHashSet<>(); - for (String name : restore) { - if (name != null && !name.isBlank()) { - enabledNames.add(normalizeName(name)); - } - } - boolean prevNotifications = suppressToggleNotifications; - suppressToggleNotifications = true; - try { - for (Module module : modulesSnapshot) { - if (module == null || module instanceof RuntimeControlModule) continue; - if (enabledNames.contains(normalizeName(module.name()))) { - module.setRuntimeEnabledTransient(true); - } - } - } finally { - suppressToggleNotifications = prevNotifications; - } - } - - private static void releaseRuntimeReferences(RuntimeShutdownContext context) { - runtimeReleased = true; - int moduleCount = modules.size(); - Events.BUS.clear(); - modules.clear(); - byId.clear(); - byType.clear(); - for (HudPhase phase : HudPhase.values()) { - HUD_PHASE_MODULES.get(phase).clear(); - HUD_PHASE_SNAPSHOTS.put(phase, new Module[0]); - } - for (WorldPhase phase : WorldPhase.values()) { - WORLD_PHASE_MODULES.get(phase).clear(); - WORLD_PHASE_SNAPSHOTS.put(phase, new Module[0]); - } - listeners.clear(); - listenerSnapshot = new ModuleStateListener[0]; - modulesSnapshot = new Module[0]; - context.increment("module_references_released", moduleCount); } private static String normalizeName(String name) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleRegister.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleRegister.java index 915b67a..6ca2f97 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleRegister.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleRegister.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleStateListener.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleStateListener.java index d33bb5a..9b27971 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleStateListener.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/ModuleStateListener.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Modules.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Modules.java index 0bbaa09..d31df37 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Modules.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Modules.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,32 +7,31 @@ package dev.loki.lovisual.features.module; -import dev.loki.lovisual.runtime.ClientRuntime; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; public enum Modules { ; public static T get(Class type) { - if (!RuntimeGate.canRunModules()) return null; + if (!Lifecycle.isActive()) return null; return ModuleManager.get(type); } public static T require(Class type) { - if (!RuntimeGate.canRunModules()) { - throw new IllegalStateException("Modules are not available while runtime state is " + ClientRuntime.state()); + if (!Lifecycle.isActive()) { + throw new IllegalStateException("Modules are not available yet"); } return ModuleManager.require(type); } public static boolean enabled(Class type) { - if (!RuntimeGate.canRunModules()) return false; + if (!Lifecycle.isActive()) return false; T module = get(type); return module != null && module.isEnabled(); } public static boolean enabled(String id) { - if (!RuntimeGate.canRunModules()) return false; + if (!Lifecycle.isActive()) return false; return ModuleManager.isEnabled(id); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Notifier.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Notifier.java index 85471a7..8e9d625 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Notifier.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/Notifier.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/RuntimeControlModule.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/RuntimeControlModule.java deleted file mode 100644 index 7c408c3..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/RuntimeControlModule.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module; - -public interface RuntimeControlModule { - void onRuntimeControlTick(); -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/WorldPhase.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/WorldPhase.java index dd80083..273be59 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/WorldPhase.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/WorldPhase.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AttributeSwap.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AttributeSwap.java deleted file mode 100644 index 31c1652..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AttributeSwap.java +++ /dev/null @@ -1,1922 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.MultiPlayerGameMode; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Holder; -import net.minecraft.core.component.DataComponents; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket; -import net.minecraft.util.Mth; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.EquipmentSlotGroup; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.attributes.Attribute; -import net.minecraft.world.entity.ai.attributes.AttributeModifier; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.item.enchantment.Enchantments; -import net.minecraft.world.item.equipment.Equippable; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.PointedDripstoneBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SpeleothemThickness; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.values.BooleanMapValue; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.ModeValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.EventSync; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.NoFall; -import dev.loki.lovisual.features.module.modules.player.AutoTotem; -import dev.loki.lovisual.mixins.accessors.PlayerInventoryAccessor; -import dev.loki.lovisual.util.combat.AttackUtil; -import dev.loki.lovisual.util.combat.protocol.CombatProtocolHeuristics; -import dev.loki.lovisual.util.logging.DebugLog; -import dev.loki.lovisual.util.player.ResetAttackCooldown; -import dev.loki.lovisual.util.player.inventory.InventorySwap; -import dev.loki.lovisual.util.player.simulation.PlayerSimulationCache; -import dev.loki.lovisual.util.combat.protocol.ProtocolUtil; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.concurrent.ThreadLocalRandom; - -//todo Description -@ModuleInfo( - id = "attributeswap", - displayName = "AttributeSwap", - category = ModuleCategory.COMBAT -) -public class AttributeSwap extends Module { - - private static final int HOTBAR_RESET_TICKS = 0; - private static final double MIN_MEANINGFUL_MACE_FALL_DISTANCE = 1.6; - private static final long FAST_AURA_MACE_DELAY_MIN_MS = 140L; - private static final long FAST_AURA_MACE_DELAY_MAX_MS = 230L; - private static final int CHEST_SCREEN_SLOT = 6; - private static final int CYCLE_NONE = 0; - private static final int CYCLE_WAIT_NORMAL_ATTACK = 1; - private static final int CYCLE_WAIT_MACE_SYNC = 2; - private static final int CYCLE_WAIT_ELYTRA_RESTORE = 3; - private static final int WIND_BURST_ABSORPTION_MIN_TICKS = 200; - private static final int WIND_BURST_PREDICTION_TICKS = 140; - private static final double WIND_BURST_EXPLOSION_RADIUS = 3.5; - private static final double WIND_BURST_SWEEP_MARGIN = 0.04; - private static final String ACTION_SHIELD_BREAKER = "shield_breaker"; - private static final String ACTION_HEIGHT_MACE = "height_mace"; - private static final String ACTION_BEST_DAMAGE_WEAPON = "best_damage_weapon"; - private final Minecraft mc = Minecraft.getInstance(); - private final BooleanMapValue actions = - group( - "attributeSwapActions", - "actions", - actionDefaults() - ); - private final BooleanMapValue protocolHeuristicSources = - group( - "attributeSwapProtocolHeuristics", - "protocol_heuristics", - CombatProtocolHeuristics.defaultSourceToggles() - ); - private final ModeValue searchMode = - visibleWhen(modeCommon( - "attributeSwapSearch", - "search_scope", - CommonSettingSchemas.INVENTORY_SEARCH_SCOPE, - "HOTBAR", - "HOTBAR", - "INVENTORY" - ), this::isHeightMaceEnabled); - private final EnumValue bestDamageWeaponMode = - visibleWhen(enumSetting( - "attributeSwapBestDamageWeaponMode", - "best_damage_weapon_mode", - BestDamageWeaponMode.BOTH, - BestDamageWeaponMode.values() - ), this::isBestDamageWeaponEnabled); - private final BooleanValue onlyPlayers = - boolCommon( - "attributeSwapOnlyPlayers", - "only_players", - CommonSettingSchemas.COMBAT_ONLY_PLAYERS, - true - ); - private final NumberValue minFallDistance = - visibleWhen(numCommon( - "attributeSwapMinFallDistance", - "min_fall_distance", - CommonSettingSchemas.COMBAT_MIN_FALL_DISTANCE, - 2.0, - MIN_MEANINGFUL_MACE_FALL_DISTANCE, - 20.0 - ), this::isHeightMaceEnabled); - private final BooleanValue restoreItem = - boolCommon( - "attributeSwapRestoreItem", - "restore_item", - CommonSettingSchemas.INVENTORY_RESTORE_ITEM, - true - ); - private final BooleanValue autoElytraCycle = - visibleWhen(bool( - "attributeSwapAutoElytraCycle", - "auto_elytra_cycle", - true - ), this::isHeightMaceEnabled); - private final BooleanValue autoGlideAfterRestore = - visibleWhen(bool( - "attributeSwapAutoGlideAfterRestore", - "auto_glide_after_restore", - false - ), this::isAutoElytraCycleEnabled); - private final NumberValue autoGlideDelay = - visibleWhen(num( - "attributeSwapAutoGlideDelay", - "auto_glide_delay", - 2, - 1, - 10 - ), () -> isAutoElytraCycleEnabled() && autoGlideAfterRestore.get()); - private final NumberValue minDownVelocity = - visibleWhen(num( - "attributeSwapMinDownVelocity", - "min_down_velocity", - 0.08, - 0.01, - 1.0 - ), this::isAutoElytraCycleEnabled); - private final NumberValue minApproachSpeed = - visibleWhen(num( - "attributeSwapMinApproachSpeed", - "min_approach_speed", - 0.25, - 0.0, - 3.0 - ), this::isAutoElytraCycleEnabled); - private final NumberValue predictionTicks = - visibleWhen(num( - "attributeSwapPredictionTicks", - "prediction_ticks", - 8, - 1, - 20 - ), this::isAutoElytraCycleEnabled); - private final NumberValue maxPredictedHorizontalDistance = - visibleWhen(num( - "attributeSwapMaxPredictedHorizontalDistance", - "max_predicted_horizontal_distance", - 4.5, - 1.5, - 8.0 - ), this::isAutoElytraCycleEnabled); - private final NumberValue elytraCycleTimeout = - visibleWhen(num( - "attributeSwapElytraCycleTimeout", - "elytra_cycle_timeout", - 5, - 1, - 12 - ), this::isAutoElytraCycleEnabled); - private final BooleanValue windBurstSafety = - visibleWhen(bool( - "attributeSwapWindBurstSafety", - "wind_burst_safety", - true - ), this::isHeightMaceEnabled); - private final NumberValue windBurstMinRemainingHealth = - visibleWhen(num( - "attributeSwapWindBurstMinRemainingHealth", - "wind_burst_min_remaining_health", - 6.0f, - 0.5f, - 40.0f - ), this::isWindBurstSafetyEnabled); - private final BooleanValue windBurstStrictElytra = - visibleWhen(bool( - "attributeSwapWindBurstStrictElytra", - "wind_burst_strict_elytra", - false - ), this::isWindBurstSafetyEnabled); - private final BooleanValue windBurstDebugLog = - visibleWhen(bool( - "attributeSwapWindBurstDebugLog", - "wind_burst_debug_log", - false - ), this::isWindBurstSafetyEnabled); - private int pendingTargetId = -1; - private boolean pendingKeepSprint = false; - private int pendingRestoreSyncId = -1; - private int pendingRestoreFromScreenSlot = -1; - private int pendingRestoreToScreenSlot = -1; - private int pendingRestoreAge = -1; - private boolean elytraCycleActive; - private int elytraCycleTargetId = -1; - private int elytraReturnInventorySlot = -1; - private int elytraCycleExpireAge = -1; - private int elytraCycleStage = CYCLE_NONE; - private int elytraMaceAttackAge = -1; - private int elytraRestoreAge = -1; - private boolean elytraCycleKeepSprint; - private boolean queuedRestoreGlide; - private int restoreGlideAge = -1; - private int restoreGlideExpireAge = -1; - private long lastFastAuraMaceAttackMs; - private long nextFastAuraMaceDelayMs = randomFastAuraMaceDelay(); - private boolean externalTargetBlocking = false; - private int auraControlTicks = 0; - private boolean attributeSwapSequence = false; - private int lastAttributeSwapTargetId = -1; - private int lastAttributeSwapAge = -1; - - private static Map actionDefaults() { - LinkedHashMap defaults = new LinkedHashMap<>(); - defaults.put(ACTION_SHIELD_BREAKER, true); - defaults.put(ACTION_HEIGHT_MACE, true); - defaults.put(ACTION_BEST_DAMAGE_WEAPON, true); - return defaults; - } - - public static QueueResult queueAttackResult(LivingEntity target, boolean keepSprint) { - AttributeSwap attributeSwap = Modules.get(AttributeSwap.class); - return attributeSwap != null ? attributeSwap.queueAttack(target, keepSprint) : QueueResult.PASS; - } - - public static boolean shouldBypassAuraCooldownFor(LocalPlayer player, LivingEntity target) { - AttributeSwap attributeSwap = Modules.get(AttributeSwap.class); - return attributeSwap != null && attributeSwap.shouldBypassAuraCooldown(player, target); - } - - public static void afterNormalAttackIfActive(LivingEntity target, boolean keepSprint) { - AttributeSwap attributeSwap = Modules.get(AttributeSwap.class); - if (attributeSwap != null) { - attributeSwap.afterNormalAttack(target, keepSprint); - } - } - - public static void handleAuraTarget(LivingEntity target, boolean breakShields) { - AttributeSwap attributeSwap = Modules.get(AttributeSwap.class); - if (attributeSwap == null || !attributeSwap.isEnabled()) return; - - attributeSwap.suppressCrosshairForAuraTick(); - - if (breakShields && target instanceof Player player) { - attributeSwap.handleExternalTarget(player); - } else { - attributeSwap.handleExternalTarget(null); - } - } - - public static void clearAuraControlIfActive() { - AttributeSwap attributeSwap = Modules.get(AttributeSwap.class); - if (attributeSwap != null) { - attributeSwap.clearAuraControl(); - } - } - - public static boolean tryBreakShieldPostAttack(LivingEntity target, boolean keepSprint, boolean enabled) { - AttributeSwap attributeSwap = Modules.get(AttributeSwap.class); - if (attributeSwap == null || !attributeSwap.isEnabled()) return false; - return attributeSwap.tryPostAttackAttributeSwap(target, keepSprint, enabled); - } - - public static boolean tryBreakShieldAfterClientAttack(Entity target) { - AttributeSwap attributeSwap = Modules.get(AttributeSwap.class); - if (attributeSwap == null || !attributeSwap.isEnabled() || attributeSwap.isAuraControlled()) return false; - if (!(target instanceof LivingEntity)) return false; - - Minecraft mc = Minecraft.getInstance(); - if (!(mc.hitResult instanceof EntityHitResult ehr) || ehr.getEntity() != target) { - return false; - } - - return attributeSwap.tryAttributeSwapAfterClientAttack(target); - } - - private static boolean isBlockingShieldTarget(LivingEntity target) { - if (!(target instanceof Player player)) { - return false; - } - return player.isBlocking() || isUsingShieldStatic(player); - } - - private static boolean isUsingShieldStatic(Player target) { - return target != null - && target.isUsingItem() - && target.getUseItem().is(Items.SHIELD); - } - - private static AABB union(AABB a, AABB b) { - return new AABB( - Math.min(a.minX, b.minX), - Math.min(a.minY, b.minY), - Math.min(a.minZ, b.minZ), - Math.max(a.maxX, b.maxX), - Math.max(a.maxY, b.maxY), - Math.max(a.maxZ, b.maxZ) - ); - } - - private static double lerp(double delta, double start, double end) { - return start + delta * (end - start); - } - - private static String format3(double value) { - return String.format(java.util.Locale.ROOT, "%.3f", value); - } - - private static long randomFastAuraMaceDelay() { - return ThreadLocalRandom.current().nextLong( - FAST_AURA_MACE_DELAY_MIN_MS, - FAST_AURA_MACE_DELAY_MAX_MS + 1 - ); - } - - private boolean isActionEnabled(String action) { - return actions.get(action); - } - - private boolean isHeightMaceEnabled() { - return isActionEnabled(ACTION_HEIGHT_MACE); - } - - private boolean isBestDamageWeaponEnabled() { - return isActionEnabled(ACTION_BEST_DAMAGE_WEAPON); - } - - private boolean shouldUseBestDamageWeaponForAura() { - return isBestDamageWeaponEnabled() && bestDamageWeaponMode.get().usesAura(); - } - - private boolean shouldUseBestDamageWeaponForNextHit() { - return isBestDamageWeaponEnabled() && bestDamageWeaponMode.get().usesNextHit(); - } - - private boolean isAutoElytraCycleEnabled() { - return isHeightMaceEnabled() && autoElytraCycle.get(); - } - - private boolean isWindBurstSafetyEnabled() { - return isHeightMaceEnabled() && windBurstSafety.get(); - } - - @Override - public void onDisable() { - pendingTargetId = -1; - pendingKeepSprint = false; - clearPendingRestore(); - restoreElytraIfNeeded(); - clearRestoreGlide(); - clearAuraControl(); - clearAttributeSwapSequence(); - InventorySwap.INSTANCE.releaseHotbar(this); - } - - @Override - public void onTick() { - if (isEnabled()) { - InventorySwap.INSTANCE.tick(); - flushPendingRestore(); - tickElytraCycle(); - tickRestoreGlide(); - tickAuraControl(); - externalTargetBlocking = false; - } - } - - public QueueResult queueAttack(LivingEntity target, boolean keepSprint) { - if (!isEnabled()) return QueueResult.PASS; - if (mc.player == null || mc.gameMode == null || mc.level == null) return QueueResult.PASS; - if (!isValidTarget(target)) return QueueResult.PASS; - - if (elytraCycleActive) { - if (elytraCycleTargetId != target.getId()) { - restoreElytraIfNeeded(); - return QueueResult.PASS; - } - - elytraCycleKeepSprint = keepSprint; - return elytraCycleStage == CYCLE_WAIT_MACE_SYNC - ? QueueResult.SUPPRESS - : QueueResult.PASS; - } - - - if (isBlockingShieldTarget(target)) { - return QueueResult.PASS; - } - - if (isHeightMaceEnabled()) { - int maceSlot = findDesiredMaceSlot(mc.player, target); - if (maceSlot != -1) { - if (tryStartElytraCycle(mc.player, target, keepSprint)) { - return QueueResult.PASS; - } - - boolean fastAuraMace = shouldBypassAuraCooldown(mc.player, target, maceSlot); - if (fastAuraMace && maceSlot < 9) { - return attackWithLeasedHotbar(mc.player, target, keepSprint, maceSlot) - ? QueueResult.HANDLE - : QueueResult.SUPPRESS; - } - - if (!canAttackNow(mc.player)) return QueueResult.PASS; - - queuePendingMaceAttack(target, keepSprint); - return QueueResult.HANDLE; - } - } - - return tryBestDamageWeaponForAura(target, keepSprint); - } - - public boolean shouldBypassAuraCooldown(LocalPlayer player, LivingEntity target) { - int maceSlot = findDesiredHotbarMaceSlot(player, target); - return shouldBypassAuraCooldown(player, target, maceSlot); - } - - private void queuePendingMaceAttack(LivingEntity target, boolean keepSprint) { - pendingTargetId = target.getId(); - pendingKeepSprint = keepSprint; - } - - @EventHandler(priority = -2000) - private void onSync(EventSync event) { - flushPendingRestore(); - if (!isEnabled()) return; - tickElytraCycleSync(); - tickRestoreGlideSync(); - if (pendingTargetId == -1) return; - - LocalPlayer player = mc.player; - MultiPlayerGameMode manager = mc.gameMode; - int targetId = pendingTargetId; - boolean keepSprint = pendingKeepSprint; - pendingTargetId = -1; - pendingKeepSprint = false; - if (player == null || manager == null || mc.level == null) return; - if (player.isUsingItem()) return; - - Entity entity = mc.level.getEntity(targetId); - if (!(entity instanceof LivingEntity target) || !isValidTarget(target)) return; - - int maceSlot = findDesiredMaceSlot(player, target); - if (maceSlot == -1) return; - - if (maceSlot < 9) { - attackWithLeasedHotbar(player, target, keepSprint, maceSlot); - return; - } - - PlayerInventoryAccessor inv = (PlayerInventoryAccessor) player.getInventory(); - int selectedSlot = inv.combatant$getSelectedSlot(); - int syncId = player.inventoryMenu != null ? player.inventoryMenu.containerId : -1; - int maceScreenSlot = InventorySwap.mapInventoryToScreenSlot(maceSlot); - int selectedScreenSlot = InventorySwap.mapHotbarToScreenSlot(selectedSlot); - boolean needsSwap = maceScreenSlot != selectedScreenSlot; - if (needsSwap) { - if (syncId < 0) return; - InventorySwap.INSTANCE.swapScreenSlots(maceScreenSlot, selectedScreenSlot); - } - try { - if (!AttackUtil.attackCurrentItem(mc, target, keepSprint)) return; - ResetAttackCooldown.resetAttackCooldown(player); - restoreElytraIfNeeded(); - } finally { - if (needsSwap && restoreItem.get()) { - schedulePendingRestore(player.tickCount, syncId, maceScreenSlot, selectedScreenSlot); - } - } - } - - private boolean attackWithLeasedHotbar(LocalPlayer player, - LivingEntity target, - boolean keepSprint, - int hotbarSlot) { - return attackWithLeasedHotbar(player, target, keepSprint, hotbarSlot, true); - } - - private boolean attackWithLeasedHotbar(LocalPlayer player, - LivingEntity target, - boolean keepSprint, - int hotbarSlot, - boolean updateFastMaceDelay) { - int resetTicks = restoreItem.get() ? 1 : HOTBAR_RESET_TICKS; - if (!InventorySwap.INSTANCE.leaseHotbar(this, hotbarSlot, resetTicks)) return false; - if (!AttackUtil.attackCurrentItem(mc, target, keepSprint)) return false; - ResetAttackCooldown.resetAttackCooldown(player); - if (updateFastMaceDelay) { - lastFastAuraMaceAttackMs = System.currentTimeMillis(); - nextFastAuraMaceDelayMs = randomFastAuraMaceDelay(); - } - return true; - } - - private boolean attackWithAttributeHotbar(LocalPlayer player, - LivingEntity target, - boolean keepSprint, - int hotbarSlot) { - if (player == null || target == null || !InventorySwap.INSTANCE.leaseHotbar(this, hotbarSlot, 0)) { - return false; - } - - attributeSwapSequence = true; - lastAttributeSwapTargetId = target.getId(); - lastAttributeSwapAge = player.tickCount; - try { - if (!AttackUtil.attackCurrentItem(mc, target, keepSprint)) return false; - ResetAttackCooldown.resetAttackCooldown(player); - return true; - } finally { - attributeSwapSequence = false; - InventorySwap.INSTANCE.releaseHotbar(this); - } - } - - private boolean wasAttributeSwapUsedThisTick(LivingEntity target) { - LocalPlayer player = mc.player; - return player != null - && target != null - && lastAttributeSwapTargetId == target.getId() - && lastAttributeSwapAge == player.tickCount; - } - - private void clearAttributeSwapSequence() { - attributeSwapSequence = false; - lastAttributeSwapTargetId = -1; - lastAttributeSwapAge = -1; - } - - private void tickAuraControl() { - if (auraControlTicks > 0) { - auraControlTicks--; - } - } - - public void afterNormalAttack(LivingEntity target, boolean keepSprint) { - if (!isEnabled()) return; - if (!elytraCycleActive) { - return; - } - if (target == null || target.getId() != elytraCycleTargetId) return; - if (elytraCycleStage != CYCLE_WAIT_NORMAL_ATTACK) return; - - LocalPlayer player = mc.player; - if (player == null) return; - if (!isValidTarget(target) || target.getHealth() <= 0.0f) { - restoreElytraIfNeeded(); - return; - } - elytraCycleKeepSprint = keepSprint; - elytraCycleStage = CYCLE_WAIT_MACE_SYNC; - elytraMaceAttackAge = player.tickCount + 1; - } - - public void suppressCrosshairForAuraTick() { - auraControlTicks = 2; - } - - public boolean isAuraControlled() { - return auraControlTicks > 0; - } - - public void clearAuraControl() { - auraControlTicks = 0; - externalTargetBlocking = false; - } - - public void handleExternalTarget(Player target) { - if (!isEnabled() || mc.player == null) return; - - auraControlTicks = 2; - externalTargetBlocking = isUsingShield(target); - } - - public boolean tryPostAttackAttributeSwap(LivingEntity target, boolean keepSprint, boolean allowShieldBreak) { - if (!isEnabled()) return false; - suppressCrosshairForAuraTick(); - - return allowShieldBreak && target instanceof Player player && tryBreakShield(player, keepSprint); - } - - public boolean tryAttributeSwapAfterClientAttack(Entity target) { - if (!isEnabled() || isAuraControlled()) return false; - if (!(target instanceof LivingEntity living)) return false; - if (!(mc.hitResult instanceof EntityHitResult ehr) || ehr.getEntity() != target) { - return false; - } - - return tryPostAttackAttributeSwap(living, false, true); - } - - public boolean tryBreakShield(Player target, boolean keepSprint) { - if (!isActionEnabled(ACTION_SHIELD_BREAKER)) return false; - if (attributeSwapSequence) return false; - if (mc.player == null || mc.gameMode == null) return false; - if (target == null || !target.isAlive() || target.isRemoved()) return false; - if (wasAttributeSwapUsedThisTick(target)) return false; - if (!isUsingShield(target)) return false; - if (!isShieldFacingPlayer(target)) return false; - - int axeSlot = findHotbarAxeSlot(mc.player); - if (axeSlot == -1) return false; - - int selected = ((PlayerInventoryAccessor) mc.player.getInventory()).combatant$getSelectedSlot(); - if (axeSlot == selected && isAxe(mc.player.getMainHandItem())) return false; - - return attackWithAttributeHotbar(mc.player, target, keepSprint, axeSlot); - } - - private boolean attackMaceNow(LocalPlayer player, - LivingEntity target, - boolean keepSprint, - int maceSlot) { - if (maceSlot < 9) { - return attackWithLeasedHotbar(player, target, keepSprint, maceSlot); - } - - if (player.inventoryMenu == null) return false; - - int selectedSlot = ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); - int syncId = player.inventoryMenu.containerId; - int maceScreenSlot = InventorySwap.mapInventoryToScreenSlot(maceSlot); - int selectedScreenSlot = InventorySwap.mapHotbarToScreenSlot(selectedSlot); - boolean needsSwap = maceScreenSlot != selectedScreenSlot; - if (needsSwap) { - InventorySwap.INSTANCE.swapScreenSlots(maceScreenSlot, selectedScreenSlot); - } - - try { - if (!AttackUtil.attackCurrentItem(mc, target, keepSprint)) return false; - ResetAttackCooldown.resetAttackCooldown(player); - return true; - } finally { - if (needsSwap && restoreItem.get()) { - schedulePendingRestore(player.tickCount, syncId, maceScreenSlot, selectedScreenSlot); - } - } - } - - public boolean handleManualAttack() { - if (!isEnabled()) { - return false; - } - - LocalPlayer player = mc.player; - MultiPlayerGameMode manager = mc.gameMode; - if (player == null || manager == null || mc.level == null) { - return false; - } - - LivingEntity target = resolveCrosshairTarget(); - if (!isValidTarget(target)) return false; - if (isBlockingShieldTarget(target)) return false; - - if (isHeightMaceEnabled() && canAttackNow(player)) { - int maceSlot = findDesiredMaceSlot(player, target); - if (maceSlot != -1) { - int selectedSlot = ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); - if (maceSlot == selectedSlot && player.getMainHandItem().is(Items.MACE)) { - return false; - } - - if (maceSlot < 9) { - if (!InventorySwap.INSTANCE.leaseHotbar(this, maceSlot, HOTBAR_RESET_TICKS)) return false; - try { - if (!AttackUtil.attackCurrentItem(mc, target, false)) return false; - ResetAttackCooldown.resetAttackCooldown(player); - return true; - } finally { - if (restoreItem.get()) { - InventorySwap.INSTANCE.releaseHotbar(this); - } - } - } - - if (player.inventoryMenu == null) { - return false; - } - - int syncId = player.inventoryMenu.containerId; - int maceScreenSlot = InventorySwap.mapInventoryToScreenSlot(maceSlot); - int selectedScreenSlot = InventorySwap.mapHotbarToScreenSlot(selectedSlot); - boolean needsSwap = maceScreenSlot != selectedScreenSlot; - if (needsSwap) { - InventorySwap.INSTANCE.swapScreenSlots(maceScreenSlot, selectedScreenSlot); - } - try { - if (!AttackUtil.attackCurrentItem(mc, target, false)) return false; - ResetAttackCooldown.resetAttackCooldown(player); - return true; - } finally { - if (needsSwap && restoreItem.get()) { - InventorySwap.INSTANCE.swapScreenSlots(maceScreenSlot, selectedScreenSlot); - } - } - } - } - - BestWeaponPrepareResult bestWeaponPrepare = prepareBestDamageWeaponForNextHit(player, target); - return bestWeaponPrepare == BestWeaponPrepareResult.FAILED; - } - - private void schedulePendingRestore(int currentAge, int syncId, int fromScreenSlot, int toScreenSlot) { - pendingRestoreSyncId = syncId; - pendingRestoreFromScreenSlot = fromScreenSlot; - pendingRestoreToScreenSlot = toScreenSlot; - pendingRestoreAge = currentAge + 1; - } - - private void flushPendingRestore() { - if (pendingRestoreAge == -1) { - return; - } - - LocalPlayer player = mc.player; - MultiPlayerGameMode manager = mc.gameMode; - if (player == null || manager == null) { - clearPendingRestore(); - return; - } - - if (player.tickCount < pendingRestoreAge) { - return; - } - - InventorySwap.INSTANCE.swapScreenSlots(pendingRestoreFromScreenSlot, pendingRestoreToScreenSlot); - clearPendingRestore(); - } - - private void clearPendingRestore() { - pendingRestoreSyncId = -1; - pendingRestoreFromScreenSlot = -1; - pendingRestoreToScreenSlot = -1; - pendingRestoreAge = -1; - } - - private boolean tryStartElytraCycle(LocalPlayer player, LivingEntity target, boolean keepSprint) { - if (!isAutoElytraCycleEnabled()) return false; - if (elytraCycleActive) return false; - if (player == null || target == null || player.inventoryMenu == null) return false; - if (!player.isFallFlying()) return false; - if (!player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA)) return false; - if (player.getMainHandItem().is(Items.MACE)) return false; - if (player.getAttackStrengthScale(0.5f) < 1.0f) return false; - if (!isVectorFallingDown(player)) return false; - if (!isHorizontallyMovingIntoTarget(player, target)) return false; - - int swapSlot = findElytraRemovalSlot(player); - if (swapSlot == -1) return false; - - int invScreenSlot = InventorySwap.mapInventoryToScreenSlot(swapSlot); - if (!InventorySwap.INSTANCE.swapScreenSlots(invScreenSlot, CHEST_SCREEN_SLOT)) return false; - - elytraCycleActive = true; - elytraCycleTargetId = target.getId(); - elytraReturnInventorySlot = swapSlot; - elytraCycleExpireAge = player.tickCount + elytraCycleTimeout.get(); - elytraCycleStage = CYCLE_WAIT_NORMAL_ATTACK; - elytraMaceAttackAge = -1; - elytraRestoreAge = -1; - elytraCycleKeepSprint = keepSprint; - return true; - } - - private void tickElytraCycleSync() { - if (!elytraCycleActive) return; - if (elytraCycleStage != CYCLE_WAIT_MACE_SYNC) return; - - LocalPlayer player = mc.player; - if (player == null || mc.level == null) { - clearElytraCycle(); - return; - } - - if (player.tickCount < elytraMaceAttackAge) return; - - Entity entity = mc.level.getEntity(elytraCycleTargetId); - if (!(entity instanceof LivingEntity target) || !isValidTarget(target) || target.getHealth() <= 0.0f) { - restoreElytraIfNeeded(); - return; - } - - int maceSlot = findDesiredMaceSlot(player, target); - if (maceSlot == -1) { - restoreElytraIfNeeded(); - return; - } - - if (!attackMaceNow(player, target, elytraCycleKeepSprint, maceSlot)) { - restoreElytraIfNeeded(); - return; - } - - elytraCycleStage = CYCLE_WAIT_ELYTRA_RESTORE; - elytraRestoreAge = player.tickCount + (maceSlot < 9 || !restoreItem.get() ? 1 : 2); - } - - private void tickElytraCycle() { - if (!elytraCycleActive) return; - - LocalPlayer player = mc.player; - if (player == null || mc.level == null) { - clearElytraCycle(); - return; - } - - Entity entity = mc.level.getEntity(elytraCycleTargetId); - boolean expired = elytraCycleExpireAge >= 0 && player.tickCount >= elytraCycleExpireAge; - if (expired || !(entity instanceof LivingEntity living) || !isValidTarget(living)) { - restoreElytraIfNeeded(); - return; - } - - if (elytraCycleStage == CYCLE_WAIT_ELYTRA_RESTORE && player.tickCount >= elytraRestoreAge) { - restoreElytraIfNeeded(); - } - } - - private void restoreElytraIfNeeded() { - if (!elytraCycleActive) return; - - LocalPlayer player = mc.player; - if (player == null || player.inventoryMenu == null) { - clearElytraCycle(); - return; - } - - boolean restored = false; - if (player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA)) { - restored = true; - } else if (elytraReturnInventorySlot >= 0 && elytraReturnInventorySlot < 36 - && player.getInventory().getItem(elytraReturnInventorySlot).is(Items.ELYTRA)) { - restored = InventorySwap.INSTANCE.swapScreenSlots( - InventorySwap.mapInventoryToScreenSlot(elytraReturnInventorySlot), - CHEST_SCREEN_SLOT - ); - } - - if (restored) { - queueRestoreGlide(player); - clearElytraCycle(); - return; - } - - clearElytraCycle(); - } - - private void queueRestoreGlide(LocalPlayer player) { - if (!autoGlideAfterRestore.get()) return; - if (player == null) return; - if (player.isFallFlying()) return; - if (player.isPassenger()) return; - if (player.getAbilities().flying) return; - if (player.onGround() || player.isInWater() || player.isInLava()) return; - - int delay = Math.max(1, autoGlideDelay.get()); - queuedRestoreGlide = true; - restoreGlideAge = player.tickCount + delay; - restoreGlideExpireAge = player.tickCount + delay + 10; - } - - private void tickRestoreGlide() { - if (!queuedRestoreGlide) return; - - LocalPlayer player = mc.player; - if (player == null || player.isFallFlying()) { - clearRestoreGlide(); - return; - } - - if (restoreGlideExpireAge >= 0 && player.tickCount > restoreGlideExpireAge) { - clearRestoreGlide(); - return; - } - - if (player.tickCount < restoreGlideAge) { - return; - } - - if (!canStartRestoreGlide(player)) { - clearRestoreGlide(); - } - } - - private void tickRestoreGlideSync() { - if (!queuedRestoreGlide) return; - - LocalPlayer player = mc.player; - if (player == null) { - clearRestoreGlide(); - return; - } - - if (player.tickCount < restoreGlideAge) return; - if (player.isFallFlying()) { - clearRestoreGlide(); - return; - } - - if (!canStartRestoreGlide(player)) { - clearRestoreGlide(); - return; - } - - if (player.getDeltaMovement().y > 0.0) { - restoreGlideAge = player.tickCount + 1; - return; - } - - if (mc.getConnection() == null) return; - - if (player.tryToStartFallFlying()) { - if (player.isFallFlying()) { - mc.getConnection().send(new ServerboundPlayerCommandPacket( - player, - ServerboundPlayerCommandPacket.Action.START_FALL_FLYING - )); - clearRestoreGlide(); - } else { - restoreGlideAge = player.tickCount + 1; - } - } else { - restoreGlideAge = player.tickCount + 1; - } - } - - private boolean canStartRestoreGlide(LocalPlayer player) { - if (player == null) return false; - if (player.isFallFlying()) return false; - if (player.isPassenger()) return false; - if (player.getAbilities().flying) return false; - if (!player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA)) return false; - if (player.isInWater() || player.isInLava()) return false; - return !player.onGround(); - } - - private void clearRestoreGlide() { - queuedRestoreGlide = false; - restoreGlideAge = -1; - restoreGlideExpireAge = -1; - } - - private void clearElytraCycle() { - elytraCycleActive = false; - elytraCycleTargetId = -1; - elytraReturnInventorySlot = -1; - elytraCycleExpireAge = -1; - elytraCycleStage = CYCLE_NONE; - elytraMaceAttackAge = -1; - elytraRestoreAge = -1; - elytraCycleKeepSprint = false; - } - - public boolean isElytraCycleActive() { - return isEnabled() && elytraCycleActive; - } - - private boolean shouldBypassAuraCooldown(LocalPlayer player, LivingEntity target, int maceSlot) { - if (!isEnabled()) return false; - if (!isHeightMaceEnabled()) return false; - if (player == null || !isValidTarget(target)) return false; - if (elytraCycleActive) return false; - if (player.isUsingItem()) return false; - if (maceSlot < 0 || maceSlot >= 9) return false; - if (isBlockingShieldTarget(target)) return false; - if (System.currentTimeMillis() - lastFastAuraMaceAttackMs < nextFastAuraMaceDelayMs) return false; - return !player.getMainHandItem().is(Items.MACE) - || ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot() != maceSlot; - } - - private boolean canAttackNow(LocalPlayer player) { - if (player == null) return false; - if (player.isUsingItem()) return false; - return player.getAttackStrengthScale(0.5f) >= 1.0f; - } - - private boolean canUseBestDamageWeaponNow(LocalPlayer player) { - if (player == null) return false; - if (player.isUsingItem()) return false; - return isLegacyAttackProtocol() || canAttackNow(player); - } - - private QueueResult tryBestDamageWeaponForAura(LivingEntity target, boolean keepSprint) { - LocalPlayer player = mc.player; - if (!shouldUseBestDamageWeaponForAura()) return QueueResult.PASS; - if (!canUseBestDamageWeaponNow(player)) return QueueResult.PASS; - - BestWeaponPrepareResult result = prepareBestDamageWeaponForAttack(player, target); - return switch (result) { - case NONE, PREPARED -> QueueResult.PASS; - case FAILED -> QueueResult.SUPPRESS; - }; - } - - private BestWeaponPrepareResult prepareBestDamageWeaponForNextHit(LocalPlayer player, LivingEntity target) { - if (!shouldUseBestDamageWeaponForNextHit()) return BestWeaponPrepareResult.NONE; - if (!canUseBestDamageWeaponNow(player)) return BestWeaponPrepareResult.NONE; - return prepareBestDamageWeaponForAttack(player, target); - } - - private BestWeaponPrepareResult prepareBestDamageWeaponForAttack(LocalPlayer player, LivingEntity target) { - int weaponSlot = findBestDamageWeaponSlot(player, target); - if (weaponSlot == -1) return BestWeaponPrepareResult.NONE; - return selectBestDamageWeaponSlot(player, weaponSlot) - ? BestWeaponPrepareResult.PREPARED - : BestWeaponPrepareResult.FAILED; - } - - private boolean selectBestDamageWeaponSlot(LocalPlayer player, int hotbarSlot) { - if (player == null || hotbarSlot < 0 || hotbarSlot >= 9) return false; - int selectedSlot = ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); - if (selectedSlot == hotbarSlot) return true; - return InventorySwap.INSTANCE.selectHotbar(hotbarSlot); - } - - private boolean isLegacyAttackProtocol() { - return ProtocolUtil.isLegacyAttackProtocol(protocolHeuristicSources.getAll()); - } - - private boolean shouldUseSmartMace(LocalPlayer player, LivingEntity target, ItemStack maceStack) { - if (player == null || target == null || maceStack == null || !maceStack.is(Items.MACE)) return false; - if (!isValidTarget(target)) return false; - if (isBlockingShieldTarget(target)) return false; - - ItemStack currentStack = player.getMainHandItem(); - double currentDamage = estimateAppliedAttackDamage(player, target, currentStack); - double maceDamage = estimateAppliedAttackDamage(player, target, maceStack); - return maceDamage > currentDamage + 0.05; - } - - private double estimateAppliedAttackDamage(LocalPlayer player, LivingEntity target, ItemStack stack) { - return estimateAppliedAttackDamage(player, target, stack, 1.0); - } - - private double estimateAppliedAttackDamage(LocalPlayer player, LivingEntity target, ItemStack stack, double cooldownProgress) { - if (player == null || target == null) return 0.0; - - double rawDamage = estimateRawAttackDamage(player, target, stack, cooldownProgress); - return applyEstimatedArmorReduction(target, rawDamage, stack); - } - - private double estimateRawAttackDamage(LocalPlayer player, LivingEntity target, ItemStack stack) { - return estimateRawAttackDamage(player, target, stack, 1.0); - } - - private double estimateRawAttackDamage(LocalPlayer player, LivingEntity target, ItemStack stack, double cooldownProgress) { - double safeCooldown = Mth.clamp(cooldownProgress, 0.0, 1.0); - double damage = 1.0 + getMainHandAttackDamage(stack); - damage += estimateWeaponEnchantmentDamageBonus(target, stack); - if (safeCooldown < 1.0) { - damage *= 0.2 + safeCooldown * safeCooldown * 0.8; - } - damage += estimateMaceBonusDamage(player, target, stack); - - if (safeCooldown > 0.9 && canEstimateCriticalHit(player, target)) { - damage *= 1.5; - } - - return Math.max(0.0, damage); - } - - private double estimateWeaponEnchantmentDamageBonus(LivingEntity target, ItemStack stack) { - if (target == null || stack == null || stack.isEmpty()) return 0.0; - - int sharpness = getEnchantmentLevel(stack, Enchantments.SHARPNESS); - double bonus = sharpness > 0 ? 0.5 * sharpness + 0.5 : 0.0; - - int smite = getEnchantmentLevel(stack, Enchantments.SMITE); - if (smite > 0 && target.getType().builtInRegistryHolder().is(net.minecraft.tags.EntityTypeTags.SENSITIVE_TO_SMITE)) { - bonus += 2.5 * smite; - } - - int bane = getEnchantmentLevel(stack, Enchantments.BANE_OF_ARTHROPODS); - if (bane > 0 && target.getType().builtInRegistryHolder().is(net.minecraft.tags.EntityTypeTags.SENSITIVE_TO_BANE_OF_ARTHROPODS)) { - bonus += 2.5 * bane; - } - - return bonus; - } - - private double estimateMaceBonusDamage(LocalPlayer player, LivingEntity target, ItemStack stack) { - if (player == null || target == null || stack == null || !stack.is(Items.MACE)) return 0.0; - if (!shouldMaceSmashApply(player)) return 0.0; - - double fallDistance = Math.max(0.0, player.fallDistance); - double baseSmash; - if (fallDistance <= 3.0) { - baseSmash = 4.0 * fallDistance; - } else if (fallDistance <= 8.0) { - baseSmash = 12.0 + 2.0 * (fallDistance - 3.0); - } else { - baseSmash = 22.0 + fallDistance - 8.0; - } - - int densityLevel = getEnchantmentLevel(stack, Enchantments.DENSITY); - double densityBonus = densityLevel > 0 ? 0.5 * densityLevel * fallDistance : 0.0; - return baseSmash + densityBonus; - } - - private boolean shouldMaceSmashApply(LocalPlayer player) { - return player != null && player.fallDistance > 1.5f && !player.isFallFlying(); - } - - private double applyEstimatedArmorReduction(LivingEntity target, double damage, ItemStack weaponStack) { - if (target == null || damage <= 0.0) return 0.0; - - double armor = target.getAttributeValue(Attributes.ARMOR); - if (armor <= 0.0) return damage; - - double toughness = target.getAttributeValue(Attributes.ARMOR_TOUGHNESS); - double toughnessFactor = 2.0 + toughness / 4.0; - double armorEffectiveness = Mth.clamp( - armor - damage / toughnessFactor, - armor * 0.2, - 20.0 - ) / 25.0; - - int breachLevel = getEnchantmentLevel(weaponStack, Enchantments.BREACH); - if (breachLevel > 0) { - armorEffectiveness = Mth.clamp(armorEffectiveness - 0.15 * breachLevel, 0.0, 1.0); - } - - return damage * (1.0 - armorEffectiveness); - } - - private boolean canEstimateCriticalHit(LocalPlayer player, LivingEntity target) { - return player != null - && target != null - && player.fallDistance > 0.0f - && !player.onGround() - && !player.onClimbable() - && !player.isInWater() - && !player.hasEffect(MobEffects.BLINDNESS) - && !player.isPassenger() - && !player.isSprinting(); - } - - private LivingEntity resolveCrosshairTarget() { - if (!(mc.hitResult instanceof EntityHitResult ehr)) return null; - if (!(ehr.getEntity() instanceof LivingEntity living)) return null; - return living; - } - - private boolean isValidTarget(LivingEntity target) { - if (target == null || !target.isAlive() || target.isRemoved()) return false; - return !onlyPlayers.get() || target instanceof Player; - } - - private double getMainHandAttackDamage(ItemStack stack) { - if (stack == null || stack.isEmpty()) return 0.0; - - final double[] add = {0.0}; - final double[] mulBase = {0.0}; - final double[] mulTotal = {1.0}; - stack.forEachModifier(EquipmentSlotGroup.MAINHAND, (attribute, modifier, display) -> { - if (!attribute.equals(Attributes.ATTACK_DAMAGE)) { - return; - } - - AttributeModifier.Operation op = modifier.operation(); - double amount = modifier.amount(); - if (op == AttributeModifier.Operation.ADD_VALUE) { - add[0] += amount; - } else if (op == AttributeModifier.Operation.ADD_MULTIPLIED_BASE) { - mulBase[0] += amount; - } else if (op == AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL) { - mulTotal[0] *= 1.0 + amount; - } - }); - - return (add[0] + mulBase[0]) * mulTotal[0]; - } - - private double getMainHandAttackSpeed(LocalPlayer player, ItemStack stack) { - return estimateMainHandAttributeValue(player, stack, Attributes.ATTACK_SPEED, 4.0); - } - - private double estimateMainHandAttributeValue(LocalPlayer player, - ItemStack stack, - Holder attribute, - double fallbackBase) { - double base = player != null ? player.getAttributeBaseValue(attribute) : fallbackBase; - if (stack == null || stack.isEmpty()) return Math.max(0.1, base); - - final double[] add = {0.0}; - final double[] mulBase = {0.0}; - final double[] mulTotal = {1.0}; - stack.forEachModifier(EquipmentSlotGroup.MAINHAND, (candidateAttribute, modifier, display) -> { - if (!candidateAttribute.equals(attribute)) { - return; - } - - AttributeModifier.Operation op = modifier.operation(); - double amount = modifier.amount(); - if (op == AttributeModifier.Operation.ADD_VALUE) { - add[0] += amount; - } else if (op == AttributeModifier.Operation.ADD_MULTIPLIED_BASE) { - mulBase[0] += amount; - } else if (op == AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL) { - mulTotal[0] *= 1.0 + amount; - } - }); - - double value = (base + add[0] + base * mulBase[0]) * mulTotal[0]; - return Math.max(0.1, value); - } - - private int findBestDamageWeaponSlot(LocalPlayer player, LivingEntity target) { - if (player == null || target == null) return -1; - if (!isValidTarget(target)) return -1; - if (isBlockingShieldTarget(target)) return -1; - - ItemStack currentStack = player.getMainHandItem(); - - int selectedSlot = ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); - double currentScore = estimateBestDamageWeaponScore(player, target, currentStack); - double bestScore = currentScore + 0.05; - int bestSlot = -1; - - for (int i = 0; i < 9; i++) { - if (i == selectedSlot) continue; - - ItemStack stack = player.getInventory().getItem(i); - if (!isBestDamageWeaponCandidate(stack)) continue; - - double score = estimateBestDamageWeaponScore(player, target, stack); - if (score > bestScore) { - bestScore = score; - bestSlot = i; - } - } - - return bestSlot; - } - - private boolean isBestDamageWeaponCandidate(ItemStack stack) { - if (stack == null || stack.isEmpty()) return false; - return getMainHandAttackDamage(stack) > 0.0; - } - - private double estimateBestDamageWeaponScore(LocalPlayer player, LivingEntity target, ItemStack stack) { - if (player == null || target == null || stack == null) return 0.0; - - double damage = estimateAppliedAttackDamage(player, target, stack, 1.0); - if (isLegacyAttackProtocol()) { - return damage; - } - - double attackSpeed = getMainHandAttackSpeed(player, stack); - return damage * attackSpeed; - } - - private int findHotbarAxeSlot(LocalPlayer player) { - if (player == null) return -1; - for (int i = 0; i < 9; i++) { - ItemStack stack = player.getInventory().getItem(i); - if (isAxe(stack)) return i; - } - return -1; - } - - private boolean isAxe(ItemStack stack) { - return stack != null && ( - stack.is(Items.WOODEN_AXE) || - stack.is(Items.STONE_AXE) || - stack.is(Items.IRON_AXE) || - stack.is(Items.GOLDEN_AXE) || - stack.is(Items.DIAMOND_AXE) || - stack.is(Items.NETHERITE_AXE) - ); - } - - private boolean isUsingShield(Player target) { - return target != null - && target.isUsingItem() - && target.getUseItem().is(Items.SHIELD); - } - - private boolean isShieldFacingPlayer(Player target) { - if (mc.player == null || target == null) return false; - - Vec3 toPlayer = mc.player.getBoundingBox().getCenter().subtract(target.getEyePosition()); - float yawToPlayer = (float) Math.toDegrees(Math.atan2(toPlayer.z, toPlayer.x)) - 90.0f; - float diff = Mth.wrapDegrees(target.getYRot() - yawToPlayer); - - return Math.abs(diff) < 90.0f; - } - - private boolean isVectorFallingDown(LocalPlayer player) { - Vec3 velocity = player.getDeltaMovement(); - if (velocity.y > -minDownVelocity.get()) return false; - - double predictedFall = predictUnglidedFallDistance(player, predictionTicks.get()); - return predictedFall >= minFallDistance.get(); - } - - private double predictUnglidedFallDistance(LocalPlayer player, int ticks) { - double fall = Math.max(0.0, player.fallDistance); - double yVelocity = player.getDeltaMovement().y; - int safeTicks = Math.max(1, ticks); - - for (int i = 0; i < safeTicks; i++) { - if (yVelocity < 0.0) { - fall += -yVelocity; - } - yVelocity = (yVelocity - 0.08) * 0.9800000190734863; - } - - return fall; - } - - private boolean isHorizontallyMovingIntoTarget(LocalPlayer player, LivingEntity target) { - Vec3 velocity = player.getDeltaMovement(); - Vec3 horizontalVelocity = new Vec3(velocity.x, 0.0, velocity.z); - double horizontalSpeed = horizontalVelocity.length(); - if (horizontalSpeed <= 1.0E-4) return false; - - int ticks = predictionTicks.get(); - Vec3 playerPos = predictedLocalPlayerPos(player, ticks); - Vec3 targetPos = predictedTargetPos(target, ticks); - Vec3 toTarget = new Vec3( - targetPos.x - playerPos.x, - 0.0, - targetPos.z - playerPos.z - ); - double distance = toTarget.length(); - if (distance <= 1.0E-4) return true; - - double approachSpeed = horizontalVelocity.dot(toTarget.scale(1.0 / distance)); - if (approachSpeed < minApproachSpeed.get()) return false; - - Vec3 projectedPlayer = playerPos.add(horizontalVelocity.scale(ticks)); - double currentDistance = horizontalDistance(playerPos, targetPos); - double projectedDistance = horizontalDistance(projectedPlayer, targetPos); - return projectedDistance < currentDistance - && projectedDistance <= maxPredictedHorizontalDistance.get(); - } - - private Vec3 predictedLocalPlayerPos(LocalPlayer player, int ticks) { - PlayerSimulationCache.SimulatedPlayerCache simulation = PlayerSimulationCache.getSimulationForLocalPlayer(); - if (simulation == null) { - return player.position().add(player.getDeltaMovement().scale(Math.max(1, ticks))); - } - - return simulation.getSnapshotAt(Math.max(1, ticks)).pos(); - } - - private Vec3 predictedTargetPos(LivingEntity target, int ticks) { - if (target instanceof Player playerTarget) { - return PlayerSimulationCache.getSimulationForOtherPlayers(playerTarget) - .getSnapshotAt(Math.max(1, ticks)) - .pos(); - } - return target.position().add(target.getDeltaMovement().scale(Math.max(1, ticks))); - } - - private double horizontalDistance(Vec3 a, Vec3 b) { - double dx = a.x - b.x; - double dz = a.z - b.z; - return Math.sqrt(dx * dx + dz * dz); - } - - private int findElytraRemovalSlot(LocalPlayer player) { - int selectedSlot = ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); - int bestChestSlot = -1; - int bestChestScore = -1; - int firstEmptySlot = -1; - - for (int i = 0; i < 36; i++) { - if (i == selectedSlot) continue; - - ItemStack stack = player.getInventory().getItem(i); - if (stack.isEmpty()) { - if (firstEmptySlot == -1) firstEmptySlot = i; - continue; - } - - int score = getChestDefenseScore(stack); - if (score > bestChestScore) { - bestChestScore = score; - bestChestSlot = i; - } - } - - if (bestChestSlot != -1) return bestChestSlot; - return firstEmptySlot; - } - - private int getChestDefenseScore(ItemStack stack) { - if (!isChestplate(stack)) return 0; - - int base = - stack.is(Items.LEATHER_CHESTPLATE) ? 3 : - stack.is(Items.COPPER_CHESTPLATE) ? 4 : - stack.is(Items.CHAINMAIL_CHESTPLATE) ? 5 : - stack.is(Items.GOLDEN_CHESTPLATE) ? 5 : - stack.is(Items.IRON_CHESTPLATE) ? 6 : - stack.is(Items.DIAMOND_CHESTPLATE) ? 8 : - stack.is(Items.NETHERITE_CHESTPLATE) ? 9 : 0; - return base; - } - - private boolean isChestplate(ItemStack stack) { - if (stack == null || stack.isEmpty() || stack.is(Items.ELYTRA)) return false; - Equippable equippable = stack.get(DataComponents.EQUIPPABLE); - return equippable != null && equippable.slot() == EquipmentSlot.CHEST; - } - - private int findDesiredMaceSlot(LocalPlayer player, LivingEntity target) { - int start = 0; - int end = "INVENTORY".equalsIgnoreCase(searchMode.get()) ? 36 : 9; - return findBestDamageMaceSlot(player, target, start, end); - } - - private int findDesiredHotbarMaceSlot(LocalPlayer player, LivingEntity target) { - if (player == null) return -1; - return findBestDamageMaceSlot(player, target, 0, 9); - } - - private int findBestDamageMaceSlot(LocalPlayer player, LivingEntity target, int startInclusive, int endExclusive) { - if (player == null || target == null) return -1; - - int selectedSlot = ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); - double currentDamage = estimateAppliedAttackDamage(player, target, player.getMainHandItem()); - double bestDamage = currentDamage + 0.05; - int bestSlot = -1; - - for (int i = startInclusive; i < endExclusive; i++) { - if (i == selectedSlot) continue; - - ItemStack stack = player.getInventory().getItem(i); - if (!stack.is(Items.MACE)) continue; - if (isUnsafeWindBurstMace(player, stack)) continue; - if (!shouldUseSmartMace(player, target, stack)) continue; - - double damage = estimateAppliedAttackDamage(player, target, stack); - if (damage > bestDamage) { - bestDamage = damage; - bestSlot = i; - } - } - - return bestSlot; - } - - private int getEnchantmentLevel(ItemStack stack, net.minecraft.resources.ResourceKey key) { - if (stack == null || stack.isEmpty() || mc.level == null) return 0; - var registry = mc.level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT); - Enchantment enchantment = registry.getValue(key); - if (enchantment == null) return 0; - Holder entry = registry.wrapAsHolder(enchantment); - return EnchantmentHelper.getItemEnchantmentLevel(entry, stack); - } - - private boolean isUnsafeWindBurstMace(LocalPlayer player, ItemStack mace) { - if (!isWindBurstSafetyEnabled()) return false; - if (player == null || mc.level == null || mace == null || mace.isEmpty()) return false; - - int windBurstLevel = getEnchantmentLevel(mace, Enchantments.WIND_BURST); - if (windBurstLevel <= 0) return false; - - NoFall noFall = Modules.get(NoFall.class); - if (noFall != null && noFall.isEnabled()) { - logWindBurstDecision(player, windBurstLevel, null, null, "ALLOW_NOFALL", false); - return false; - } - - float healthBudget = getWindBurstHealthBudget(player); - float minRemainingHealth = windBurstMinRemainingHealth.get(); - if (healthBudget <= minRemainingHealth) { - logWindBurstDecision(player, windBurstLevel, null, null, "BLOCK_CURRENT_HP_AT_OR_BELOW_LIMIT", true); - return true; - } - - WindBurstImpulse impulse = calculateWindBurstImpulse(player, windBurstLevel); - PredictedWindBurstFall fall = predictWindBurstFall(player, impulse.vertical()); - FallDamageEstimate damage = estimateFallDamage(player, fall.fallDistance(), fall.damagePerDistance()); - float predictedDamage = damage.finalDamage(); - float remainingHealth = healthBudget - predictedDamage; - if (remainingHealth >= minRemainingHealth) { - logWindBurstDecision(player, windBurstLevel, impulse, fall, damage, "ALLOW_PREDICTED_HP_OK", false); - return false; - } - - if (!windBurstStrictElytra.get() && hasElytraFallback(player)) { - logWindBurstDecision(player, windBurstLevel, impulse, fall, damage, "ALLOW_ELYTRA_FALLBACK", false); - return false; - } - - requestAutoTotemForWindBurst(player); - boolean unsafe = !hasTotemInOffhand(player); - logWindBurstDecision(player, windBurstLevel, impulse, fall, damage, unsafe ? "BLOCK_PREDICTED_HP_LOW" : "ALLOW_OFFHAND_TOTEM", unsafe); - return unsafe; - } - - private boolean hasTotemInOffhand(LocalPlayer player) { - return player != null && player.getOffhandItem().is(Items.TOTEM_OF_UNDYING); - } - - private void requestAutoTotemForWindBurst(LocalPlayer player) { - AutoTotem autoTotem = Modules.get(AutoTotem.class); - if (autoTotem != null) { - autoTotem.ensureTotemForDanger(player); - } - } - - private PredictedWindBurstFall predictWindBurstFall(LocalPlayer player, double verticalImpulse) { - AABB baseBox = player.getBoundingBox(); - Vec3 offset = Vec3.ZERO; - Vec3 velocity = player.getDeltaMovement().add(0.0, verticalImpulse, 0.0); - double fallDistance = Math.max(0.0, player.fallDistance); - double maxRise = 0.0; - int ceilingCuts = 0; - - for (int tick = 1; tick <= WIND_BURST_PREDICTION_TICKS; tick++) { - Vec3 previousOffset = offset; - offset = offset.add(velocity); - maxRise = Math.max(maxRise, offset.y); - - AABB previousBox = baseBox.move(previousOffset); - AABB nextBox = baseBox.move(offset); - AABB swept = union(previousBox, nextBox).inflate(WIND_BURST_SWEEP_MARGIN); - if (hasSolidCollision(player, swept)) { - if (velocity.y > 0.0) { - ceilingCuts++; - offset = previousOffset; - velocity = new Vec3(velocity.x * 0.4, 0.0, velocity.z * 0.4); - continue; - } - - BlockState landingState = getLandingBlockState(player, nextBox); - double damageFallDistance = isStalagmiteTip(landingState) ? fallDistance + 2.5 : fallDistance; - return new PredictedWindBurstFall( - damageFallDistance, - getFallDamagePerDistance(landingState), - tick, - blockId(landingState), - ceilingCuts, - maxRise, - false - ); - } - - if (velocity.y < 0.0) { - fallDistance += -velocity.y; - } - - velocity = new Vec3( - velocity.x * 0.91, - (velocity.y - 0.08) * 0.9800000190734863, - velocity.z * 0.91 - ); - } - - return new PredictedWindBurstFall(fallDistance, 1.0f, WIND_BURST_PREDICTION_TICKS, "timeout", ceilingCuts, maxRise, true); - } - - private WindBurstImpulse calculateWindBurstImpulse(LocalPlayer player, int windBurstLevel) { - Vec3 explosionPos = player.position(); - Vec3 affectedPos = player.getEyePosition(); - double blastDiameter = WIND_BURST_EXPLOSION_RADIUS * 2.0; - double distanceRatio = Math.sqrt(player.distanceToSqr(explosionPos)) / blastDiameter; - if (distanceRatio > 1.0) { - return new WindBurstImpulse(0.0, 0.0, distanceRatio, getWindBurstKnockbackMultiplier(windBurstLevel), 0.0); - } - - Vec3 direction = affectedPos.subtract(explosionPos); - if (direction.lengthSqr() < 1.0E-6) { - direction = new Vec3(0.0, 1.0, 0.0); - } else { - direction = direction.normalize(); - } - - double exposure = calculateExplosionExposure(explosionPos, player); - double resistance = player.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE); - double multiplier = getWindBurstKnockbackMultiplier(windBurstLevel); - double vertical = direction.y - * (1.0 - distanceRatio) - * exposure - * multiplier - * (1.0 - resistance); - return new WindBurstImpulse(vertical, exposure, distanceRatio, multiplier, resistance); - } - - private double calculateExplosionExposure(Vec3 source, LocalPlayer player) { - AABB box = player.getBoundingBox(); - double xStep = 1.0 / ((box.maxX - box.minX) * 2.0 + 1.0); - double yStep = 1.0 / ((box.maxY - box.minY) * 2.0 + 1.0); - double zStep = 1.0 / ((box.maxZ - box.minZ) * 2.0 + 1.0); - double xOffset = (1.0 - Math.floor(1.0 / xStep) * xStep) / 2.0; - double zOffset = (1.0 - Math.floor(1.0 / zStep) * zStep) / 2.0; - int clear = 0; - int total = 0; - - for (double x = 0.0; x <= 1.0; x += xStep) { - for (double y = 0.0; y <= 1.0; y += yStep) { - for (double z = 0.0; z <= 1.0; z += zStep) { - Vec3 sample = new Vec3( - lerp(x, box.minX, box.maxX) + xOffset, - lerp(y, box.minY, box.maxY), - lerp(z, box.minZ, box.maxZ) + zOffset - ); - HitResult hit = mc.level.clip(new ClipContext( - sample, - source, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - if (hit.getType() == HitResult.Type.MISS) { - clear++; - } - total++; - } - } - } - - return total == 0 ? 0.0 : (double) clear / total; - } - - private double getWindBurstKnockbackMultiplier(int level) { - return switch (level) { - case 1 -> 1.2; - case 2 -> 1.75; - case 3 -> 2.2; - default -> 1.2 + Math.max(0, level - 1) * 0.5; - }; - } - - private FallDamageEstimate estimateFallDamage(LocalPlayer player, double fallDistance, float damagePerDistance) { - if (player == null || fallDistance <= 0.0 || damagePerDistance <= 0.0f) { - return new FallDamageEstimate(0.0, 0.0f, 0.0, 0.0, 0.0, 0.0f, 0); - } - - double safeFallDistance = player.getAttributeValue(Attributes.SAFE_FALL_DISTANCE); - double fallMultiplier = player.getAttributeValue(Attributes.FALL_DAMAGE_MULTIPLIER); - double unsafeFallDistance = fallDistance + 1.0E-6 - safeFallDistance; - int rawDamage = (int) Math.floor( - unsafeFallDistance - * damagePerDistance - * fallMultiplier - ); - if (rawDamage <= 0) { - return new FallDamageEstimate(rawDamage, 0.0f, unsafeFallDistance, safeFallDistance, fallMultiplier, 0.0f, 0); - } - - float amount = rawDamage; - int resistanceReduction = 0; - MobEffectInstance resistance = player.getEffect(MobEffects.RESISTANCE); - if (resistance != null) { - resistanceReduction = (resistance.getAmplifier() + 1) * 5; - amount = Math.max(amount * (25 - resistanceReduction) / 25.0f, 0.0f); - } - - float protection = getFallProtectionAmount(player); - if (protection > 0.0f) { - amount *= 1.0f - Math.min(protection, 20.0f) / 25.0f; - } - - return new FallDamageEstimate(rawDamage, Math.max(0.0f, amount), unsafeFallDistance, safeFallDistance, fallMultiplier, protection, resistanceReduction); - } - - private float getFallProtectionAmount(LocalPlayer player) { - float protection = 0.0f; - for (EquipmentSlot slot : EquipmentSlot.values()) { - ItemStack stack = player.getItemBySlot(slot); - if (stack == null || stack.isEmpty()) continue; - protection += getEnchantmentLevel(stack, Enchantments.PROTECTION); - } - protection += getEnchantmentLevel(player.getItemBySlot(EquipmentSlot.FEET), Enchantments.FEATHER_FALLING) * 3.0f; - return protection; - } - - private float getWindBurstHealthBudget(LocalPlayer player) { - float absorption = Math.max(0.0f, player.getAbsorptionAmount()); - MobEffectInstance absorptionEffect = player.getEffect(MobEffects.ABSORPTION); - if (absorptionEffect != null && absorptionEffect.getDuration() < WIND_BURST_ABSORPTION_MIN_TICKS) { - absorption = 0.0f; - } - return Math.max(0.0f, player.getHealth()) + absorption; - } - - private boolean hasElytraFallback(LocalPlayer player) { - if (player == null) return false; - if (player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA)) return true; - - for (int i = 0; i < 36; i++) { - if (player.getInventory().getItem(i).is(Items.ELYTRA)) { - return true; - } - } - - return false; - } - - private float getFallDamagePerDistance(BlockState landingState) { - if (landingState == null) return 1.0f; - if (landingState.is(Blocks.WATER) - || landingState.is(Blocks.POWDER_SNOW) - || landingState.is(Blocks.COBWEB) - || landingState.is(Blocks.SLIME_BLOCK)) { - return 0.0f; - } - if (landingState.is(Blocks.HAY_BLOCK) || landingState.is(Blocks.HONEY_BLOCK)) { - return 0.2f; - } - if (isStalagmiteTip(landingState)) { - return 2.0f; - } - return 1.0f; - } - - private BlockState getLandingBlockState(LocalPlayer player, AABB nextBox) { - BlockPos pos = BlockPos.containing(nextBox.getCenter().x, nextBox.minY - 0.001, nextBox.getCenter().z); - BlockState state = mc.level.getBlockState(pos); - if (state.isAir()) { - state = mc.level.getBlockState(pos.below()); - } - return state; - } - - private boolean isStalagmiteTip(BlockState state) { - return state != null - && state.is(Blocks.POINTED_DRIPSTONE) - && state.getValue(PointedDripstoneBlock.TIP_DIRECTION) == Direction.UP - && state.getValue(net.minecraft.world.level.block.SpeleothemBlock.THICKNESS) == SpeleothemThickness.TIP; - } - - private boolean hasSolidCollision(LocalPlayer player, AABB box) { - for (var shape : mc.level.getBlockCollisions(player, box)) { - if (!shape.isEmpty()) { - return true; - } - } - return false; - } - - private String blockId(BlockState state) { - if (state == null) return "null"; - return BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString(); - } - - private void logWindBurstDecision(LocalPlayer player, - int windBurstLevel, - WindBurstImpulse impulse, - PredictedWindBurstFall fall, - String reason, - boolean blocked) { - logWindBurstDecision(player, windBurstLevel, impulse, fall, null, reason, blocked); - } - - private void logWindBurstDecision(LocalPlayer player, - int windBurstLevel, - WindBurstImpulse impulse, - PredictedWindBurstFall fall, - FallDamageEstimate damage, - String reason, - boolean blocked) { - if (!windBurstDebugLog.get() || player == null) return; - - MobEffectInstance resistance = player.getEffect(MobEffects.RESISTANCE); - MobEffectInstance absorptionEffect = player.getEffect(MobEffects.ABSORPTION); - float absorption = Math.max(0.0f, player.getAbsorptionAmount()); - int absorptionTicks = absorptionEffect != null ? absorptionEffect.getDuration() : -1; - boolean absorptionCounted = absorption <= 0.0f - || absorptionEffect == null - || absorptionTicks >= WIND_BURST_ABSORPTION_MIN_TICKS; - - DebugLog.info( - "[AttributeSwap][WindBurst] decision=%s blocked=%s wind=%d hp=%.2f absorption=%.2f absorptionTicks=%d absorptionCounted=%s budget=%.2f minRemain=%.2f noFall=%s elytraFallback=%s strictElytra=%s offhandTotem=%s fallDistance=%.2f velocity=(%.3f,%.3f,%.3f) impulseY=%s exposure=%s distRatio=%s kbMul=%s explosionRes=%s predictedFall=%s rawDamage=%s finalDamage=%s unsafeFall=%s safeFall=%s fallMul=%s protection=%s resistReduction=%s landing=%s tick=%s ceilingCuts=%s maxRise=%s timedOut=%s", - reason, - blocked, - windBurstLevel, - player.getHealth(), - absorption, - absorptionTicks, - absorptionCounted, - getWindBurstHealthBudget(player), - windBurstMinRemainingHealth.get(), - Modules.enabled(NoFall.class), - hasElytraFallback(player), - windBurstStrictElytra.get(), - hasTotemInOffhand(player), - player.fallDistance, - player.getDeltaMovement().x, - player.getDeltaMovement().y, - player.getDeltaMovement().z, - impulse != null ? format3(impulse.vertical()) : "n/a", - impulse != null ? format3(impulse.exposure()) : "n/a", - impulse != null ? format3(impulse.distanceRatio()) : "n/a", - impulse != null ? format3(impulse.knockbackMultiplier()) : "n/a", - impulse != null ? format3(impulse.explosionResistance()) : "n/a", - fall != null ? format3(fall.fallDistance()) : "n/a", - damage != null ? format3(damage.rawDamage()) : "n/a", - damage != null ? format3(damage.finalDamage()) : "n/a", - damage != null ? format3(damage.unsafeFallDistance()) : "n/a", - damage != null ? format3(damage.safeFallDistance()) : "n/a", - damage != null ? format3(damage.fallDamageMultiplier()) : "n/a", - damage != null ? format3(damage.protection()) : "n/a", - damage != null ? damage.resistanceReduction() : "n/a", - fall != null ? fall.landingBlock() : "n/a", - fall != null ? fall.tick() : "n/a", - fall != null ? fall.ceilingCuts() : "n/a", - fall != null ? format3(fall.maxRise()) : "n/a", - fall != null ? fall.timedOut() : "n/a" - ); - } - - private enum BestWeaponPrepareResult { - NONE, - PREPARED, - FAILED - } - - public enum QueueResult { - PASS, - SUPPRESS, - HANDLE - } - - public enum BestDamageWeaponMode implements EnumValue.IdProvider { - AURA_NEXT_HIT("aura_next_hit", true, false), - NEXT_HIT("next_hit", false, true), - BOTH("both", true, true); - - private final String id; - private final boolean aura; - private final boolean nextHit; - - BestDamageWeaponMode(String id, boolean aura, boolean nextHit) { - this.id = id; - this.aura = aura; - this.nextHit = nextHit; - } - - @Override - public String getId() { - return id; - } - - boolean usesAura() { - return aura; - } - - boolean usesNextHit() { - return nextHit; - } - } - - private record WindBurstImpulse(double vertical, - double exposure, - double distanceRatio, - double knockbackMultiplier, - double explosionResistance) { - } - - private record PredictedWindBurstFall(double fallDistance, - float damagePerDistance, - int tick, - String landingBlock, - int ceilingCuts, - double maxRise, - boolean timedOut) { - } - - private record FallDamageEstimate(double rawDamage, - float finalDamage, - double unsafeFallDistance, - double safeFallDistance, - double fallDamageMultiplier, - float protection, - int resistanceReduction) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoAnchor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoAnchor.java deleted file mode 100644 index 1b6e187..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoAnchor.java +++ /dev/null @@ -1,1147 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.common.impl.TargetFilters; -import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.RotationUpdateEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.WorldPhase; -import dev.loki.lovisual.features.module.modules.combat.autoanchor.*; -import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.renderer.Renderer3D; -import dev.loki.lovisual.render.engine.text.FontInfo; -import dev.loki.lovisual.render.engine.text.Fonts; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.render.engine.text.WorldTextRenderer; -import dev.loki.lovisual.util.aiming.RestrictedSingleUseAction; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.combat.CombatRotationModeUtil; -import dev.loki.lovisual.util.combat.RubberHandUseUtil; -import dev.loki.lovisual.util.item.FoodUtil; -import dev.loki.lovisual.util.entity.simulation.PositionExtrapolation; -import dev.loki.lovisual.util.player.inventory.InventorySearchScope; -import dev.loki.lovisual.util.player.inventory.InventorySwap; -import dev.loki.lovisual.util.player.inventory.InventorySwapVisibility; -import dev.loki.lovisual.util.player.simulation.PlayerSimulationCache; -import dev.loki.lovisual.util.target.TargetManager; -import dev.loki.lovisual.util.target.TargetingUtil; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.RespawnAnchorBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -@ModuleInfo( - id = "autoanchor", - displayName = "AutoAnchor", - aliases = {"AnchorAura", "Anchor"}, - category = ModuleCategory.COMBAT, - description = "module.autoanchor.description" -) -public class AutoAnchor extends Module { - private static final int ROTATION_PRIORITY = 34; - private static final long DAMAGE_RESET_MS = 1000L; - private static final long PENDING_ANCHOR_PLACE_CONFIRM_TIMEOUT_MS = 2500L; - private static final long PENDING_ANCHOR_ACTION_CONFIRM_TIMEOUT_MS = 750L; - private static final double TEXT_Y_OFFSET = 0.10; - private static final double TEXT_WORLD_SCALE = 0.025; - private static final double TEXT_SCALE = 1.0; - private static final double TEXT_GAP_SCALE = 1.0; - private final Minecraft mc = Minecraft.getInstance(); - - private final BooleanValue placeEnabled = boolCommon("autoanchorPlace", CommonSettingSchemas.PLACE, true); - private final BooleanValue explodeEnabled = boolCommon("autoanchorExplode", CommonSettingSchemas.EXPLODE, true); - private final EnumValue timing = enumCommon("autoanchorTiming", "timing", CommonSettingSchemas.TIMING, Timing.NORMAL); - private final NumberValue calcDelay = numCommon("autoanchorCalcDelay", "calc_delay", CommonSettingSchemas.CALC_DELAY, 100, 0, 500); - private final NumberValue placeDelay = numCommon( - "autoanchorPlaceDelay", - "place_delay", - CommonSettingSchemas.PLACEMENT_DELAY, - 0, - 0, - 1000 - ); - private final NumberValue lowPlaceDelay = numCommon("autoanchorLowPlaceDelay", "low_place_delay", CommonSettingSchemas.LOW_PLACE_DELAY, 550, 0, 1000); - private final NumberValue explodeDelay = numCommon( - "autoanchorExplodeDelay", - "explode_delay", - CommonSettingSchemas.PLACEMENT_BREAK_DELAY, - 0, - 0, - 1000 - ); - private final NumberValue lowExplodeDelay = numCommon("autoanchorLowExplodeDelay", "low_explode_delay", CommonSettingSchemas.LOW_EXPLODE_DELAY, 550, 0, 1000); - private final NumberValue placeRange = numCommon( - "autoanchorPlaceRange", - "place_range", - CommonSettingSchemas.PLACEMENT_RANGE, - 5.0f, - 1.0f, - 6.0f - ); - private final NumberValue wallRange = numCommon( - "autoanchorWallRange", - "wall_range", - CommonSettingSchemas.PLACEMENT_WALL_RANGE, - 3.5f, - 0.0f, - 6.0f - ); - private final EnumValue placementMode = enumCommon( - "autoanchorPlacementMode", - "placement_mode", - CommonSettingSchemas.PLACEMENT_MODE, - AutoAnchorPlacementMode.DEFAULT, - AutoAnchorPlacementMode.values() - ); - private final BooleanValue airPlace = boolCommon("autoanchorAirPlace", "air_place", CommonSettingSchemas.AIR_PLACE, false); - private final NumberValue targetRange = numCommon( - "autoanchorTargetRange", - "target_range", - CommonSettingSchemas.COMBAT_RANGE, - 10.0f, - 1.0f, - 15.0f - ); - private final BooleanMapValue targetToggles = groupCommon( - "autoanchorTargets", - "targets", - CommonSettingSchemas.TARGET_FILTERS - ); - private final EnumValue priority = enumCommon( - "autoanchorPriority", - "priority", - CommonSettingSchemas.COMBAT_PRIORITY, - TargetingUtil.TargetPriority.DISTANCE, - TargetingUtil.TargetPriority.values() - ); - private final NumberValue minDamage = numCommon("autoanchorMinDamage", "min_damage", CommonSettingSchemas.MIN_DAMAGE, 6.0f, 0.0f, 36.0f); - private final NumberValue faceplaceHealth = numCommon("autoanchorFaceplaceHealth", "faceplace_health", CommonSettingSchemas.FACEPLACE_HEALTH, 5.0f, 0.0f, 36.0f); - private final NumberValue maxSelfDamage = numCommon("autoanchorMaxSelfDamage", "max_self_damage", CommonSettingSchemas.MAX_SELF_DAMAGE, 10.0f, 0.0f, 36.0f); - private final NumberValue predictTicks = numCommon( - "autoanchorPredictTicks", - "predict_ticks", - CommonSettingSchemas.PLACEMENT_PREDICTION, - 3, - 0, - 20 - ); - private final NumberValue selfPredictTicks = numCommon("autoanchorSelfPredictTicks", "self_predict_ticks", CommonSettingSchemas.SELF_PREDICT_TICKS, 3, 0, 20); - private final BooleanValue unsafeDimensionOnly = boolCommon("autoanchorUnsafeDimensionOnly", "unsafe_dimension_only", CommonSettingSchemas.UNSAFE_DIMENSION_ONLY, true); - private final BooleanValue pauseMining = boolCommon("autoanchorPauseMining", "pause_mining", CommonSettingSchemas.PAUSE_MINING, true); - private final BooleanValue pauseEating = boolCommon("autoanchorPauseEating", "pause_eating", CommonSettingSchemas.PAUSE_EATING, true); - private final NumberValue pauseHealth = numCommon( - "autoanchorPauseHealth", - "pause_health", - CommonSettingSchemas.PLAYER_HEALTH_THRESHOLD, - 8.0f, - 0.0f, - 20.0f - ); - private final EnumValue swapScope = enumCommon( - "autoanchorSwapScope", - "swap_scope", - CommonSettingSchemas.INVENTORY_SEARCH_SCOPE, - InventorySearchScope.FULL, - InventorySearchScope.values() - ); - private final EnumValue swapVisibility = enumCommon( - "autoanchorSwapVisibility", - "swap_visibility", - CommonSettingSchemas.INVENTORY_SWAP_VISIBILITY, - InventorySwapVisibility.SILENT, - InventorySwapVisibility.values() - ); - private final BooleanValue restoreItem = boolCommon( - "autoanchorRestoreItem", - "restore_item", - CommonSettingSchemas.INVENTORY_RESTORE_ITEM, - true - ); - private final ModeValue attackMode = modeCommon( - "autoanchorAttackMode", - "attack_mode", - CommonSettingSchemas.COMBAT_ATTACK_MODE, - CombatRotationModeUtil.MODE_ROTATIONS, - CombatRotationModeUtil.MODE_ROTATIONS, - CombatRotationModeUtil.MODE_NO_ROTATIONS - ); - private final EnumValue movementCorrection = visibleWhen(enumCommon( - "autoanchorMovementCorrection", - "movement_correction", - CommonSettingSchemas.PLACEMENT_MOVEMENT_CORRECTION, - MovementCorrection.SILENT, - MovementCorrection.values() - ), this::usesRotationSettings); - private final NumberValue rotationResetTicks = visibleWhen(numCommon( - "autoanchorRotationResetTicks", - "rotation_reset_ticks", - CommonSettingSchemas.ROTATION_RESET_TICKS, - 1, - 1, - 20 - ), this::usesRotationSettings); - private final NumberValue rotationResetThreshold = visibleWhen(numCommon( - "autoanchorRotationResetThreshold", - "rotation_reset_threshold", - CommonSettingSchemas.ROTATION_RESET_THRESHOLD, - 2.0f, - 0.1f, - 15.0f - ), this::usesRotationSettings); - private final BooleanValue renderEnabled = boolCommon( - "autoanchorRender", - "render", - CommonSettingSchemas.PLACEMENT_RENDER, - true - ); - private final EnumValue renderMode = enumCommon( - "autoanchorRenderMode", - "render_mode", - CommonSettingSchemas.PLACEMENT_RENDER_MODE, - RenderMode.FADE, - RenderMode.values() - ); - private final BooleanValue renderSelfDamage = boolCommon("autoanchorRenderSelfDamage", CommonSettingSchemas.RENDER_SELF_DAMAGE, true); - private final BooleanValue drawDamage = boolCommon("autoanchorRenderDamage", CommonSettingSchemas.RENDER_DAMAGE, true); - private final RGBAColorValue fillColor = common(color("autoanchorFillColor", "#5A285AFF"), CommonSettingSchemas.FILL_COLOR); - private final RGBAColorValue lineColor = common(color("autoanchorLineColor", "#FFAA55FF"), CommonSettingSchemas.LINE_COLOR); - private final NumberValue lineWidth = numCommon("autoanchorLineWidth", CommonSettingSchemas.LINE_WIDTH, 2.0f, 1.0f, 6.0f); - private final RGBAColorValue textColor = common(color("autoanchorTextColor", "#FFFFFFFF"), CommonSettingSchemas.TEXT_COLOR); - private final NumberValue slideDelay = visibleWhen(numCommon("autoanchorSlideDelay", CommonSettingSchemas.SLIDE_DELAY, 200, 1, 1000), - () -> renderMode.get() == RenderMode.SLIDE); - private final NumberValue fadeTime = visibleWhen(numCommon("autoanchorFadeTime", CommonSettingSchemas.FADE_TIME, 500, 100, 2000), - () -> renderMode.get() == RenderMode.FADE); - - private final AutoAnchorPlanner planner = new AutoAnchorPlanner(); - private final AutoAnchorPlanner.Context plannerContext = new PlannerContext(); - private final AutoAnchorEntityBlocker entityBlocker = new AutoAnchorEntityBlocker(); - private final Map renderPositions = new ConcurrentHashMap<>(); - - private LivingEntity target; - private AutoAnchorData bestPlace; - private AutoAnchorData bestExplode; - private BlockPos renderPos; - private BlockPos prevRenderPos; - private BlockPos bestPosition; - private int renderTick; - private int renderStartTick; - private long lastPlaceMs; - private long lastExplodeMs; - private long lastDamageUpdateMs; - private long lastCalcMs; - private BlockPos pendingAnchorPos; - private AutoAnchorData pendingAnchorData; - private PendingAnchorPhase pendingAnchorPhase; - private long pendingAnchorActionMs; - private float renderDamage; - private float renderSelfDamageValue; - private boolean lowDamageMode; - private int lastScanned; - private int lastCandidates; - private int lastSafeCandidates; - private int lastSelfDamageRejects; - - @Override - public WorldPhase getWorldPhase() { - return WorldPhase.AFTER_POST_PROCESS; - } - - @Override - public void onEnable() { - resetState(); - } - - @Override - public void onDisable() { - resetState(); - RotationManager.INSTANCE.clear(this); - TargetManager.setAutoAnchorTarget(null); - } - - @Override - public void onTick() { - if (!isEnabled()) return; - renderTick++; - InventorySwap.INSTANCE.tick(); - purgeExpiredRenderPositions(); - if (System.currentTimeMillis() - lastDamageUpdateMs > DAMAGE_RESET_MS && renderPositions.isEmpty()) { - renderDamage = 0.0f; - renderSelfDamageValue = 0.0f; - } - } - - @EventHandler(priority = 24) - private void onRotationUpdate(RotationUpdateEvent event) { - if (event.getType() != RotationUpdateEvent.Type.PRE) { - return; - } - if (!isEnabled()) return; - - if (mc.player == null || mc.level == null || mc.gameMode == null) { - clearCombatState(); - TargetManager.setAutoAnchorTarget(null); - return; - } - - target = findCombatTarget(); - TargetManager.setAutoAnchorTarget(target); - updateCandidates(); - - if (timing.get() == Timing.NORMAL) { - runCombatCycle(); - } - } - - @EventHandler(priority = -24) - private void onRotationUpdatePost(RotationUpdateEvent event) { - if (event.getType() != RotationUpdateEvent.Type.POST) { - return; - } - if (!isEnabled() || timing.get() != Timing.SEQUENTIAL) return; - runCombatCycle(); - } - - @Override - public void onRenderWorldEngine(Renderer3D renderer, Renderer3D depthRenderer, float tickDelta) { - if (!isEnabled() || mc.player == null || mc.level == null) return; - if (renderEnabled.get()) { - renderPlacement(renderer, tickDelta); - } - } - - private void updateCandidates() { - if (target == null || shouldPause()) { - bestPlace = null; - bestExplode = null; - lastCalcMs = 0L; - return; - } - - long now = System.currentTimeMillis(); - long delay = Math.max(0, calcDelay.get()); - if (delay > 0L && now - lastCalcMs < delay) { - return; - } - lastCalcMs = now; - - AutoAnchorPlanner.ScanResult result = planner.scan( - plannerContext, - target, - resolvePredictedPosition(target, predictTicks.get()), - Mth.ceil(placeRange.get()) - ); - bestPlace = result.bestPlace(); - bestExplode = result.bestExplode(); - lastScanned = result.scanned(); - lastCandidates = result.candidates(); - lastSafeCandidates = result.safeCandidates(); - lastSelfDamageRejects = result.selfDamageRejects(); - - AutoAnchorData renderData = bestExplode != null ? bestExplode : bestPlace; - if (renderData != null) { - setRenderCandidate(renderData); - lowDamageMode = !AutoAnchorDamageRules.shouldOverrideMinDamage(target, renderData.damage(), faceplaceHealth.get()) - && renderData.damage() < minDamage.get(); - } else if (renderPositions.isEmpty()) { - bestPosition = null; - } - } - - private void runCombatCycle() { - if (mc.player == null || mc.level == null || shouldPause()) { - RotationManager.INSTANCE.clear(this); - return; - } - - if (continuePendingAnchorCycle()) { - return; - } - - if (target == null) { - RotationManager.INSTANCE.clear(this); - return; - } - - if (explodeEnabled.get() && bestExplode != null && hasExplodeDelayElapsed()) { - beginPendingAnchor(bestExplode, bestExplode.charges() > 0 - ? PendingAnchorPhase.DETONATING - : PendingAnchorPhase.CHARGING); - continuePendingAnchorCycle(); - return; - } - - if (placeEnabled.get() && bestPlace != null && hasPlaceDelayElapsed()) { - beginPendingAnchor(bestPlace, PendingAnchorPhase.PLACING); - continuePendingAnchorCycle(); - return; - } - - RotationManager.INSTANCE.clear(this); - } - - private void executeWithRotation(AutoAnchorData data, Runnable action) { - if (data == null || action == null || mc.player == null) return; - if (!usesRotationSettings()) { - RotationManager.INSTANCE.clear(this); - action.run(); - return; - } - - RotationTarget rotationTarget = new RotationTarget( - Rotation.lookingAt(data.hitResult().getLocation(), mc.player.getEyePosition()).normalize(), - target, - List.of(), - rotationResetTicks.get(), - rotationResetThreshold.get(), - true, - movementCorrection.get(), - new RestrictedSingleUseAction(action) - ); - RotationManager.INSTANCE.setRotationTarget(rotationTarget, ROTATION_PRIORITY, this); - } - - private void placeReservedAnchor(AutoAnchorData data) { - if (data == null || data.pos() == null || data.existingAnchor() || !hasPlaceDelayElapsed() || shouldPause()) { - return; - } - if (!data.pos().equals(pendingAnchorPos) || pendingAnchorPhase != PendingAnchorPhase.PLACING) { - return; - } - if (target == null) { - clearPendingAnchor(); - return; - } - - AutoAnchorData refreshed = planner.evaluate(plannerContext, data.pos(), target); - if (refreshed == null) { - clearPendingAnchor(); - return; - } - if (refreshed.existingAnchor()) { - pendingAnchorData = refreshed; - pendingAnchorPhase = refreshed.charges() > 0 ? PendingAnchorPhase.DETONATING : PendingAnchorPhase.CHARGING; - pendingAnchorActionMs = 0L; - return; - } - - boolean placed = AutoAnchorActionUtil.placeAnchor( - mc, - this, - refreshed.hitResult(), - swapScope.get(), - swapVisibility.get(), - restoreItem.get() - ); - if (!placed) return; - - long now = System.currentTimeMillis(); - lastPlaceMs = now; - pendingAnchorActionMs = now; - pendingAnchorData = refreshed; - pendingAnchorPhase = PendingAnchorPhase.WAITING_FOR_ANCHOR; - markPlaced(refreshed); - } - - private boolean continuePendingAnchorCycle() { - if (pendingAnchorPos == null || pendingAnchorPhase == null) { - return false; - } - if (mc.player == null || mc.level == null) { - clearPendingAnchor(); - return false; - } - if (shouldPause()) { - RotationManager.INSTANCE.clear(this); - return true; - } - - long now = System.currentTimeMillis(); - BlockState state = mc.level.getBlockState(pendingAnchorPos); - boolean anchorPresent = state.is(Blocks.RESPAWN_ANCHOR); - int charges = anchorPresent ? getAnchorCharges(state) : 0; - - if (anchorPresent && (pendingAnchorPhase == PendingAnchorPhase.PLACING - || pendingAnchorPhase == PendingAnchorPhase.WAITING_FOR_ANCHOR)) { - pendingAnchorPhase = charges > 0 ? PendingAnchorPhase.DETONATING : PendingAnchorPhase.CHARGING; - pendingAnchorActionMs = 0L; - } - - if (!anchorPresent && (pendingAnchorPhase == PendingAnchorPhase.CHARGING - || pendingAnchorPhase == PendingAnchorPhase.WAITING_FOR_CHARGE - || pendingAnchorPhase == PendingAnchorPhase.DETONATING - || pendingAnchorPhase == PendingAnchorPhase.WAITING_FOR_DETONATION)) { - clearPendingAnchor(); - return false; - } - - switch (pendingAnchorPhase) { - case PLACING -> { - AutoAnchorData data = resolvePendingPlaceData(); - if (data == null) { - clearPendingAnchor(); - return false; - } - pendingAnchorData = data; - if (hasPlaceDelayElapsed()) { - executeWithRotation(data, () -> placeReservedAnchor(data)); - } else { - RotationManager.INSTANCE.clear(this); - } - return true; - } - case WAITING_FOR_ANCHOR -> { - if (anchorPresent) { - pendingAnchorPhase = charges > 0 ? PendingAnchorPhase.DETONATING : PendingAnchorPhase.CHARGING; - pendingAnchorActionMs = 0L; - return continuePendingAnchorCycle(); - } - if (now - pendingAnchorActionMs >= PENDING_ANCHOR_PLACE_CONFIRM_TIMEOUT_MS) { - clearPendingAnchor(); - return false; - } - RotationManager.INSTANCE.clear(this); - return true; - } - case CHARGING -> { - if (!anchorPresent) { - clearPendingAnchor(); - return false; - } - AutoAnchorData data = resolvePendingAnchorData(pendingAnchorPos, state); - if (data == null) { - RotationManager.INSTANCE.clear(this); - return true; - } - pendingAnchorData = data; - if (data.charges() > 0) { - pendingAnchorPhase = PendingAnchorPhase.DETONATING; - pendingAnchorActionMs = 0L; - return continuePendingAnchorCycle(); - } - if (hasExplodeDelayElapsed()) { - executeWithRotation(data, () -> chargeReservedAnchor(data)); - } else { - RotationManager.INSTANCE.clear(this); - } - return true; - } - case WAITING_FOR_CHARGE -> { - if (!anchorPresent) { - clearPendingAnchor(); - return false; - } - if (charges > 0) { - pendingAnchorPhase = PendingAnchorPhase.DETONATING; - pendingAnchorActionMs = 0L; - return continuePendingAnchorCycle(); - } - if (now - pendingAnchorActionMs >= PENDING_ANCHOR_ACTION_CONFIRM_TIMEOUT_MS) { - pendingAnchorPhase = PendingAnchorPhase.CHARGING; - pendingAnchorActionMs = 0L; - return continuePendingAnchorCycle(); - } - RotationManager.INSTANCE.clear(this); - return true; - } - case DETONATING -> { - if (!anchorPresent) { - clearPendingAnchor(); - return false; - } - AutoAnchorData data = resolvePendingAnchorData(pendingAnchorPos, state); - if (data == null) { - RotationManager.INSTANCE.clear(this); - return true; - } - pendingAnchorData = data; - if (data.charges() <= 0) { - pendingAnchorPhase = PendingAnchorPhase.CHARGING; - pendingAnchorActionMs = 0L; - return continuePendingAnchorCycle(); - } - if (explodeEnabled.get() && hasExplodeDelayElapsed()) { - executeWithRotation(data, () -> detonateReservedAnchor(data)); - } else { - RotationManager.INSTANCE.clear(this); - } - return true; - } - case WAITING_FOR_DETONATION -> { - if (!anchorPresent) { - clearPendingAnchor(); - return false; - } - if (now - pendingAnchorActionMs >= PENDING_ANCHOR_ACTION_CONFIRM_TIMEOUT_MS) { - pendingAnchorPhase = PendingAnchorPhase.DETONATING; - pendingAnchorActionMs = 0L; - return continuePendingAnchorCycle(); - } - RotationManager.INSTANCE.clear(this); - return true; - } - } - return true; - } - - private AutoAnchorData resolvePendingPlaceData() { - if (pendingAnchorPos == null || target == null) { - return null; - } - AutoAnchorData evaluated = planner.evaluate(plannerContext, pendingAnchorPos, target); - if (evaluated != null) { - return evaluated; - } - return pendingAnchorData != null && pendingAnchorPos.equals(pendingAnchorData.pos()) - ? pendingAnchorData - : null; - } - - private AutoAnchorData resolvePendingAnchorData(BlockPos pos, BlockState state) { - if (pos == null || state == null || mc.player == null || mc.level == null) { - return null; - } - - AutoAnchorData evaluated = target != null ? planner.evaluate(plannerContext, pos, target) : null; - if (evaluated != null && evaluated.existingAnchor()) { - return evaluated; - } - - BlockHitResult hit = AutoAnchorInteractionUtil.getAnchorInteractResult( - mc.level, - mc.player, - pos, - placementMode.get(), - placeRange.get(), - wallRange.get() - ); - if (hit == null) { - return null; - } - - AutoAnchorData fallback = pendingAnchorData != null && pos.equals(pendingAnchorData.pos()) ? pendingAnchorData : null; - return new AutoAnchorData( - pos, - hit, - fallback != null ? fallback.damage() : renderDamage, - fallback != null ? fallback.selfDamage() : renderSelfDamageValue, - fallback != null && fallback.overrideDamage(), - true, - getAnchorCharges(state) - ); - } - - private void chargeReservedAnchor(AutoAnchorData data) { - if (data == null || data.pos() == null || !hasExplodeDelayElapsed() || shouldPause()) return; - if (!data.pos().equals(pendingAnchorPos) || pendingAnchorPhase != PendingAnchorPhase.CHARGING) return; - - BlockHitResult anchorHit = AutoAnchorInteractionUtil.getAnchorInteractResult( - mc.level, - mc.player, - data.pos(), - placementMode.get(), - placeRange.get(), - wallRange.get() - ); - if (anchorHit == null) return; - - boolean charged = AutoAnchorActionUtil.chargeAnchor( - mc, - anchorHit, - swapScope.get(), - swapVisibility.get(), - restoreItem.get() - ); - if (!charged) return; - - long now = System.currentTimeMillis(); - lastExplodeMs = now; - pendingAnchorActionMs = now; - pendingAnchorPhase = PendingAnchorPhase.WAITING_FOR_CHARGE; - pendingAnchorData = new AutoAnchorData( - data.pos(), - anchorHit, - data.damage(), - data.selfDamage(), - data.overrideDamage(), - true, - Math.max(1, data.charges() + 1) - ); - markPlaced(pendingAnchorData); - } - - private void detonateReservedAnchor(AutoAnchorData data) { - if (data == null || !hasExplodeDelayElapsed() || shouldPause()) return; - if (!data.pos().equals(pendingAnchorPos) || pendingAnchorPhase != PendingAnchorPhase.DETONATING) return; - - BlockHitResult anchorHit = AutoAnchorInteractionUtil.getAnchorInteractResult( - mc.level, - mc.player, - data.pos(), - placementMode.get(), - placeRange.get(), - wallRange.get() - ); - if (anchorHit == null) return; - - boolean detonated = AutoAnchorActionUtil.detonateAnchor( - mc, - anchorHit, - swapScope.get(), - swapVisibility.get(), - restoreItem.get() - ); - if (!detonated) return; - - long now = System.currentTimeMillis(); - lastExplodeMs = now; - pendingAnchorActionMs = now; - pendingAnchorPhase = PendingAnchorPhase.WAITING_FOR_DETONATION; - pendingAnchorData = data; - markPlaced(data); - } - - private void beginPendingAnchor(AutoAnchorData data, PendingAnchorPhase phase) { - if (data == null || data.pos() == null || phase == null) return; - if (pendingAnchorPos != null && !pendingAnchorPos.equals(data.pos())) { - return; - } - if (pendingAnchorPos == null) { - pendingAnchorActionMs = 0L; - } - pendingAnchorPos = data.pos(); - pendingAnchorData = data; - pendingAnchorPhase = phase; - } - - - private int getAnchorCharges(BlockState state) { - if (state == null || !state.hasProperty(RespawnAnchorBlock.CHARGE)) { - return 0; - } - return state.getValue(RespawnAnchorBlock.CHARGE); - } - - private void clearPendingAnchor() { - pendingAnchorPos = null; - pendingAnchorData = null; - pendingAnchorPhase = null; - pendingAnchorActionMs = 0L; - } - - private boolean shouldPause() { - if (mc.player == null || mc.level == null || mc.gameMode == null) return true; - if (unsafeDimensionOnly.get() && mc.level.dimension() == Level.NETHER) return true; - if (pauseMining.get() && mc.gameMode.isDestroying()) return true; - if (pauseEating.get() - && mc.player.isUsingItem() - && FoodUtil.isFood(mc.player.getUseItem()) - && !RubberHandUseUtil.canBypassCurrentUse(mc)) return true; - return mc.player.getHealth() + mc.player.getAbsorptionAmount() < pauseHealth.get(); - } - - private boolean hasPlaceDelayElapsed() { - return System.currentTimeMillis() - lastPlaceMs >= Math.max(0, lowDamageMode ? lowPlaceDelay.get() : placeDelay.get()); - } - - private boolean hasExplodeDelayElapsed() { - return System.currentTimeMillis() - lastExplodeMs >= Math.max(0, lowDamageMode ? lowExplodeDelay.get() : explodeDelay.get()); - } - - private long getPlaceDelayRemainingMs() { - return Math.max(0L, Math.max(0, lowDamageMode ? lowPlaceDelay.get() : placeDelay.get()) - (System.currentTimeMillis() - lastPlaceMs)); - } - - private long getExplodeDelayRemainingMs() { - return Math.max(0L, Math.max(0, lowDamageMode ? lowExplodeDelay.get() : explodeDelay.get()) - (System.currentTimeMillis() - lastExplodeMs)); - } - - private void setRenderCandidate(AutoAnchorData data) { - bestPosition = data.pos(); - renderDamage = Math.max(0.0f, data.damage()); - renderSelfDamageValue = Math.max(0.0f, data.selfDamage()); - lastDamageUpdateMs = System.currentTimeMillis(); - } - - private void markPlaced(AutoAnchorData data) { - if (data == null || data.pos() == null) return; - BlockPos pos = data.pos(); - if (!pos.equals(renderPos)) { - renderStartTick = renderTick; - prevRenderPos = renderPos; - renderPos = pos; - } - setRenderCandidate(data); - renderPositions.put(pos, System.currentTimeMillis()); - } - - private void renderPlacement(Renderer3D renderer, float tickDelta) { - String damageText = buildDamageText(); - if (damageText.isEmpty() && renderPositions.isEmpty() && renderPos == null) { - return; - } - - if (renderMode.get() == RenderMode.FADE) { - renderFade(renderer); - return; - } - - BlockPos activePos = renderPositions.isEmpty() ? bestPosition : renderPos; - if (activePos == null) return; - - if (renderMode.get() == RenderMode.SLIDE) { - BlockPos slideTo = renderPositions.isEmpty() ? bestPosition : renderPos; - BlockPos from = prevRenderPos != null ? prevRenderPos : slideTo; - renderBox(renderer, AutoAnchorRenderUtil.lerpBox(new AABB(from), new AABB(slideTo), getSlideProgress(tickDelta)), 1.0f); - } else { - renderBox(renderer, new AABB(activePos), 1.0f); - } - } - - private float getSlideProgress(float tickDelta) { - float clampedTickDelta = Mth.clamp(tickDelta, 0.0f, 1.0f); - float durationTicks = Math.max(1.0f, slideDelay.get() / 50.0f); - return Mth.clamp((renderTick - renderStartTick + clampedTickDelta) / durationTicks, 0.0f, 1.0f); - } - - private void renderFade(Renderer3D renderer) { - long now = System.currentTimeMillis(); - int lifetime = Math.max(1, fadeTime.get()); - List> entries = new ArrayList<>(renderPositions.entrySet()); - for (Map.Entry entry : entries) { - long age = now - entry.getValue(); - if (age > lifetime) { - renderPositions.remove(entry.getKey()); - continue; - } - float alpha = 1.0f - (age / (float) lifetime); - renderBox(renderer, new AABB(entry.getKey()), alpha); - } - } - - private void renderBox(Renderer3D renderer, AABB box, float alpha) { - int fillArgb = AutoAnchorRenderUtil.applyOpacity(fillColor.getArgb(), alpha); - int lineArgb = AutoAnchorRenderUtil.applyOpacity(lineColor.getArgb(), alpha); - AutoAnchorRenderUtil.addFilledBox(renderer, box, fillArgb); - - float prevWidth = RenderState.lineWidth; - RenderState.lineWidth = Math.max(0.5f, lineWidth.get()); - try { - AutoAnchorRenderUtil.addOutlineBox(renderer, box, lineArgb); - } finally { - RenderState.lineWidth = prevWidth; - } - - if (drawDamage.get()) { - renderDamageText(renderer, box.getCenter(), alpha); - } - } - - private void renderDamageText(Renderer3D renderer, Vec3 anchor, float alpha) { - String mainText = AutoAnchorRenderUtil.formatDamage(renderDamage); - if (mainText.isEmpty()) return; - - int mainArgb = AutoAnchorRenderUtil.applyOpacity(textColor.getArgb(), alpha); - TextRenderer bold = Fonts.renderer("Iosevka", FontInfo.Type.Bold, TextRenderer.get()); - WorldTextRenderer.Options baseOptions = WorldTextRenderer.Options.defaults() - .withScale(TEXT_SCALE) - .withWorldScale(TEXT_WORLD_SCALE) - .withDepthMode(Renderer3D.DepthMode.NONE) - .withShadow(true) - .withOffset(0.0, TEXT_Y_OFFSET); - - if (!renderSelfDamage.get() || renderSelfDamageValue <= 0.0f) { - WorldTextRenderer.drawBillboard( - renderer, - bold, - mainText, - anchor, - baseOptions.withCentered(true).withColor(new RenderColor(mainArgb)) - ); - return; - } - - String tailText = " / " + AutoAnchorRenderUtil.formatDamage(renderSelfDamageValue); - TextRenderer medium = Fonts.renderer("Iosevka", FontInfo.Type.Regular, TextRenderer.get()); - double mainWidth = AutoAnchorRenderUtil.measureWidth(bold, mainText, TEXT_SCALE); - double tailWidth = AutoAnchorRenderUtil.measureWidth(medium, tailText, TEXT_GAP_SCALE); - double startX = -(mainWidth + tailWidth) * 0.5; - - double drawnMain = WorldTextRenderer.drawBillboard( - renderer, - bold, - mainText, - anchor, - baseOptions.withCentered(false) - .withOffset(startX, TEXT_Y_OFFSET) - .withColor(new RenderColor(mainArgb)) - ); - - WorldTextRenderer.drawBillboard( - renderer, - medium, - tailText, - anchor, - baseOptions.withCentered(false) - .withScale(TEXT_GAP_SCALE) - .withOffset(startX + drawnMain, TEXT_Y_OFFSET) - .withColor(new RenderColor(mainArgb)) - ); - } - - private void purgeExpiredRenderPositions() { - long now = System.currentTimeMillis(); - long lifetime = Math.max(1, fadeTime.get()); - renderPositions.entrySet().removeIf(entry -> now - entry.getValue() > lifetime); - } - - public String getTargetHudStatus(LivingEntity hudTarget) { - if (!isEnabled() || hudTarget == null || target == null || hudTarget != target) return null; - if (mc.player == null || mc.level == null) return "Idle"; - if (shouldPause()) return "Paused"; - if (!AutoAnchorActionUtil.hasAnchor(mc, swapScope.get())) return "No anchors"; - if (!AutoAnchorActionUtil.hasGlowstone(mc, swapScope.get())) return "No glowstone"; - - if (explodeEnabled.get() && bestExplode != null) { - long wait = getExplodeDelayRemainingMs(); - if (wait > 0L) return "Explode in " + wait + "ms"; - return usesRotationSettings() ? "Rotate -> anchor" : "Exploding"; - } - if (placeEnabled.get() && bestPlace != null) { - long wait = getPlaceDelayRemainingMs(); - if (wait > 0L) return "Anchor in " + wait + "ms"; - return usesRotationSettings() ? "Rotate -> anchor" : "Placing anchor"; - } - if (lastSelfDamageRejects > 0 || (lastCandidates > 0 && lastSafeCandidates <= 0)) return "Self dmg"; - if (lastScanned <= 0) return "No scan"; - return "No anchor"; - } - - private LivingEntity findCombatTarget() { - if (mc.player == null || mc.level == null) return null; - TargetingUtil.TargetingSettings settings = new TargetingUtil.TargetingSettings( - targetRange.get(), - 180.0f, - targetToggles.get(TargetFilters.PLAYERS_ONLY), - targetToggles.get(TargetFilters.IGNORE_FRIENDS), - targetToggles.get(TargetFilters.IGNORE_STAFF), - targetToggles.get(TargetFilters.IGNORE_ENEMIES), - targetToggles.get(TargetFilters.IGNORE_NAKED), - targetToggles.get(TargetFilters.IGNORE_ENTITIES), - targetToggles.get(TargetFilters.VISIBLE_ONLY), - priority.get() - ); - return TargetingUtil.findBestTarget(mc, settings); - } - - private Vec3 resolvePredictedPosition(LivingEntity entity, int ticks) { - if (entity == null || ticks <= 0) { - return entity != null ? entity.position() : Vec3.ZERO; - } - if (entity instanceof Player player) { - PlayerSimulationCache.SimulatedPlayerCache simulation = - player == mc.player - ? PlayerSimulationCache.getSimulationForLocalPlayer() - : PlayerSimulationCache.getSimulationForOtherPlayers(player); - if (simulation != null) { - return simulation.getSnapshotAt(ticks).pos(); - } - } - return PositionExtrapolation.getBestForEntity(entity).getPositionInTicks(ticks); - } - - private boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage) { - return AutoAnchorDamageRules.shouldOverrideMaxSelfDamage( - mc.player, - target, - damage, - selfDamage, - maxSelfDamage.get() - ); - } - - private boolean isSafe(float damage, float selfDamage, boolean overrideDamage) { - return AutoAnchorDamageRules.isSafe(mc.player, selfDamage, overrideDamage); - } - - private BlockHitResult getInteractResult(BlockPos pos, boolean existingAnchor) { - return AutoAnchorInteractionUtil.getInteractResult( - mc.level, - mc.player, - pos, - existingAnchor, - airPlace.get(), - placementMode.get(), - placeRange.get(), - wallRange.get() - ); - } - - - private boolean usesRotationSettings() { - return CombatRotationModeUtil.usesRotations(attackMode); - } - - private String buildDamageText() { - String main = AutoAnchorRenderUtil.formatDamage(renderDamage); - if (main.isEmpty()) return ""; - if (!renderSelfDamage.get() || renderSelfDamageValue <= 0.0f) return main; - return main + " / " + AutoAnchorRenderUtil.formatDamage(renderSelfDamageValue); - } - - private void clearCombatState() { - target = null; - bestPlace = null; - bestExplode = null; - bestPosition = null; - clearPendingAnchor(); - RotationManager.INSTANCE.clear(this); - lastScanned = 0; - lastCandidates = 0; - lastSafeCandidates = 0; - lastSelfDamageRejects = 0; - } - - private void resetState() { - target = null; - bestPlace = null; - bestExplode = null; - renderPos = null; - prevRenderPos = null; - bestPosition = null; - renderTick = 0; - renderStartTick = 0; - lastPlaceMs = 0L; - lastExplodeMs = 0L; - lastDamageUpdateMs = 0L; - lastCalcMs = 0L; - clearPendingAnchor(); - renderDamage = 0.0f; - renderSelfDamageValue = 0.0f; - lowDamageMode = false; - renderPositions.clear(); - lastScanned = 0; - lastCandidates = 0; - lastSafeCandidates = 0; - lastSelfDamageRejects = 0; - } - - private final class PlannerContext implements AutoAnchorPlanner.Context { - @Override - public LocalPlayer player() { - return mc.player; - } - - @Override - public ClientLevel level() { - return mc.level; - } - - @Override - public Vec3 resolvePredictedPosition(LivingEntity entity, int ticks) { - return AutoAnchor.this.resolvePredictedPosition(entity, ticks); - } - - @Override - public BlockHitResult getInteractResult(BlockPos pos, boolean existingAnchor) { - return AutoAnchor.this.getInteractResult(pos, existingAnchor); - } - - @Override - public boolean isBlockedByEntity(BlockPos pos) { - return entityBlocker.isBlocked(mc.level, pos); - } - - @Override - public boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage) { - return AutoAnchor.this.shouldOverrideMaxSelfDamage(damage, selfDamage); - } - - @Override - public boolean isSafe(float damage, float selfDamage, boolean overrideDamage) { - return AutoAnchor.this.isSafe(damage, selfDamage, overrideDamage); - } - - @Override - public float minDamage() { - return minDamage.get(); - } - - @Override - public float faceplaceHealth() { - return faceplaceHealth.get(); - } - - @Override - public float maxSelfDamage() { - return maxSelfDamage.get(); - } - - @Override - public int predictTicks() { - return predictTicks.get(); - } - - @Override - public int selfPredictTicks() { - return selfPredictTicks.get(); - } - - @Override - public boolean allowAirPlace() { - return airPlace.get(); - } - - @Override - public float placeRange() { - return placeRange.get(); - } - } - - private enum Timing { - NORMAL, - SEQUENTIAL - } - - private enum PendingAnchorPhase { - PLACING, - WAITING_FOR_ANCHOR, - CHARGING, - WAITING_FOR_CHARGE, - DETONATING, - WAITING_FOR_DETONATION - } - - private enum RenderMode { - FADE, - SLIDE, - DEFAULT - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoAttack.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoAttack.java deleted file mode 100644 index 81216eb..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoAttack.java +++ /dev/null @@ -1,587 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -/* - * Inspired by LiquidBounce (https://github.com/CCBlueX/LiquidBounce). - */ - -import dev.loki.lovisual.config.values.*; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; -import net.minecraft.tags.ItemTags; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.HitResult; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.common.impl.TargetFilters; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.EventSync; -import dev.loki.lovisual.events.impl.PacketEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.relations.CategoryRules; -import dev.loki.lovisual.features.relations.CategoryType; -import dev.loki.lovisual.features.relations.EntityFilters; -import dev.loki.lovisual.util.click.AttackPressing; -import dev.loki.lovisual.util.click.ClickHumanizer; -import dev.loki.lovisual.util.click.ClickScheduler; -import dev.loki.lovisual.util.combat.CombatStrikeController; -import dev.loki.lovisual.util.item.FoodUtil; -import dev.loki.lovisual.util.player.ResetAttackCooldown; -import dev.loki.lovisual.util.combat.protocol.CombatProtocolHeuristics; -import dev.loki.lovisual.util.combat.protocol.ProtocolUtil; - -import java.util.LinkedHashMap; - - -//todo Description -@ModuleInfo( - id = "triggerbot", - displayName = "TriggerBot", - category = ModuleCategory.COMBAT -) -public class AutoAttack extends Module { - - private static final int MAX_CPS = 100; - private static final String TOGGLE_HUMANIZE_MISS = "miss"; - private static final String TOGGLE_HUMANIZE_SWING = "miss_swing"; - private static final String TOGGLE_HUMANIZE_PAUSE = "pause"; - private final Minecraft mc = Minecraft.getInstance(); - private final ModeValue mode = - mode( - "autoattack_mode", - "mode", - "hold", - "hold", - "auto" - ); - private final EnumValue objective = - enumCommon( - "autoattack_objective", - "objective", - CommonSettingSchemas.COMBAT_OBJECTIVE, - ObjectiveType.ANY, - ObjectiveType.values() - ); - private final NumberValue cpsMin = - visibleWhen(numCommon( - "autoattack_cps_min", - "cps_min", - CommonSettingSchemas.COMBAT_CPS_MIN, - 8, - 1, - MAX_CPS - ), () -> objective.get() != ObjectiveType.BLOCK && !isAutoMode()); - private final NumberValue cpsMax = - visibleWhen(numCommon( - "autoattack_cps_max", - "cps_max", - CommonSettingSchemas.COMBAT_CPS_MAX, - 12, - 1, - MAX_CPS - ), () -> objective.get() != ObjectiveType.BLOCK && !isAutoMode()); - private final ClickScheduler clicker = new ClickScheduler(cpsMin.get(), cpsMax.get()); - private final BooleanValue delayOnBroken = - visibleWhen(bool( - "autoattack_delay_on_broken", - "delay_on_broken", - true - ), () -> objective.get() != ObjectiveType.BLOCK); - private final EnumValue weapon = - visibleWhen(enumCommon( - "autoattack_weapon", - "weapon", - CommonSettingSchemas.COMBAT_WEAPON, - WeaponType.ANY, - WeaponType.values() - ), () -> objective.get() != ObjectiveType.BLOCK); - private final EnumValue onItemUse = - visibleWhen(enumCommon( - "autoattack_on_item_use", - "on_item_use", - CommonSettingSchemas.COMBAT_ON_ITEM_USE, - UseMode.WAIT, - UseMode.values() - ), () -> objective.get() != ObjectiveType.BLOCK); - private final NumberValue delayPostStopUse = - visibleWhen(num( - "autoattack_delay_post_stop_use", - "delay_post_stop_use", - 0, - 0, - 20 - ), () -> objective.get() != ObjectiveType.BLOCK && onItemUse.get() != UseMode.IGNORE); - private final BooleanMapValue targetToggles = - visibleWhen(common( - group( - "autoattack_toggles", - "targets", - targetFilterDefaults() - ), - CommonSettingSchemas.TARGET_FILTERS.commonI18nKey() - ), () -> objective.get() == ObjectiveType.ENEMY); - private final BooleanMapValue humanizeToggles = - visibleWhen(group( - "autoattack_humanize_toggles", - "humanize_toggles", - humanizeDefaults() - ), () -> objective.get() != ObjectiveType.BLOCK && !isAutoMode()); - private final NumberValue humanizeMissRate = - visibleWhen(num( - "autoattack_humanize_miss_rate", - "humanize_miss_rate", - 8, - 1, - 100 - ), () -> objective.get() != ObjectiveType.BLOCK - && !isAutoMode() - && humanizeToggles.get(TOGGLE_HUMANIZE_MISS)); - private final NumberValue humanizeSwingRate = - visibleWhen(num( - "autoattack_humanize_swing_rate", - "humanize_swing_rate", - 5, - 1, - 100 - ), () -> objective.get() != ObjectiveType.BLOCK - && !isAutoMode() - && humanizeToggles.get(TOGGLE_HUMANIZE_SWING)); - private final NumberValue humanizePauseRate = - visibleWhen(num( - "autoattack_humanize_pause_rate", - "humanize_pause_rate", - 5, - 1, - 100 - ), () -> objective.get() != ObjectiveType.BLOCK - && !isAutoMode() - && humanizeToggles.get(TOGGLE_HUMANIZE_PAUSE)); - private final NumberValue humanizePauseMin = - visibleWhen(num( - "autoattack_humanize_pause_min", - "humanize_pause_min", - 1, - 1, - 10 - ), () -> objective.get() != ObjectiveType.BLOCK - && !isAutoMode() - && humanizeToggles.get(TOGGLE_HUMANIZE_PAUSE)); - private final NumberValue humanizePauseMax = - visibleWhen(num( - "autoattack_humanize_pause_max", - "humanize_pause_max", - 2, - 1, - 20 - ), () -> objective.get() != ObjectiveType.BLOCK - && !isAutoMode() - && humanizeToggles.get(TOGGLE_HUMANIZE_PAUSE)); - private final ClickHumanizer humanizer = new ClickHumanizer( - humanizeToggles, - humanizeMissRate, - humanizeSwingRate, - humanizePauseRate, - humanizePauseMin, - humanizePauseMax, - TOGGLE_HUMANIZE_MISS, - TOGGLE_HUMANIZE_SWING, - TOGGLE_HUMANIZE_PAUSE - ); - private final EnumValue protocolMode = - visibleWhen(enumCommon( - "autoattack_protocol_mode", - "protocol_mode", - CommonSettingSchemas.COMBAT_PROTOCOL, - ProtocolMode.AUTO, - ProtocolMode.values() - ), () -> objective.get() != ObjectiveType.BLOCK); - private final BooleanMapValue protocolHeuristicSources = - visibleWhen(protocolHeuristics( - "autoattack_protocol_heuristics", - "protocol_heuristics", - CommonSettingSchemas.COMBAT_PROTOCOL_HEURISTICS - ), () -> objective.get() != ObjectiveType.BLOCK && protocolMode.get() == ProtocolMode.AUTO); - private long lastFinishBreak = 0L; - private int postUseDelayTicks = 0; - private boolean wasUsingItem = false; - private int lastSyncHandledAge = -1; - - private static LinkedHashMap targetFilterDefaults() { - LinkedHashMap defaults = new LinkedHashMap<>(); - defaults.put(TargetFilters.PLAYERS_ONLY, false); - defaults.put(TargetFilters.IGNORE_FRIENDS, true); - defaults.put(TargetFilters.IGNORE_STAFF, true); - defaults.put(TargetFilters.IGNORE_ENEMIES, false); - defaults.put(TargetFilters.IGNORE_ENTITIES, true); - defaults.put(TargetFilters.VISIBLE_ONLY, false); - return defaults; - } - - private static LinkedHashMap humanizeDefaults() { - LinkedHashMap defaults = new LinkedHashMap<>(); - defaults.put(TOGGLE_HUMANIZE_MISS, false); - defaults.put(TOGGLE_HUMANIZE_SWING, false); - defaults.put(TOGGLE_HUMANIZE_PAUSE, false); - return defaults; - } - - @Override - public void onEnable() { - clicker.reset(); - lastFinishBreak = 0L; - postUseDelayTicks = 0; - wasUsingItem = false; - lastSyncHandledAge = -1; - humanizer.reset(); - } - - @Override - public void onDisable() { - clicker.reset(); - postUseDelayTicks = 0; - wasUsingItem = false; - lastSyncHandledAge = -1; - humanizer.reset(); - } - - @Override - public void onTick() { - } - - @EventHandler(priority = -1000) - private void onSync(EventSync event) { - if (!isEnabled()) return; - if (mc.player == null || mc.options == null) return; - if (mc.player.tickCount == lastSyncHandledAge) return; - lastSyncHandledAge = mc.player.tickCount; - - clicker.setCps(cpsMin.get(), cpsMax.get()); - clicker.tick(); - - boolean attackInput = mc.options.keyAttack.isDown(); - HitResult hit = resolveHitResult(mc.player); - if (objective.get() == ObjectiveType.BLOCK) { - // Let vanilla handle block breaking; no CPS/humanize in this mode. - wasUsingItem = mc.player.isUsingItem(); - return; - } - boolean autoMode = isAutoMode(); - - if (!attackInput && !autoMode) { - wasUsingItem = mc.player.isUsingItem(); - return; - } - - // In auto mode, only process entity clicks (avoid block/air spam). - if (autoMode && !(hit instanceof EntityHitResult)) { - wasUsingItem = mc.player.isUsingItem(); - return; - } - - if (!isWeaponSelected(mc.player)) return; - - if (mc.gameMode != null && mc.gameMode.isDestroying()) { - return; - } - - if (delayOnBroken.get() && System.currentTimeMillis() - lastFinishBreak < 300L) { - return; - } - - boolean usingItem = mc.player.isUsingItem(); - boolean usingShield = usingItem - && (mc.player.getUseItem().is(Items.SHIELD) - || mc.player.getOffhandItem().is(Items.SHIELD)); - boolean usingFood = usingItem && FoodUtil.isFood(mc.player.getUseItem()); - - RubberHand rh = Modules.get(RubberHand.class); - boolean rhEnabled = rh != null && rh.isEnabled(); - boolean bypassItemUseLogic = false; - - if (usingItem && rhEnabled) { - if (usingShield) { - if (!rh.canAttackWhileShield()) { - wasUsingItem = true; - return; - } - bypassItemUseLogic = true; - } else if (usingFood) { - if (!rh.canAttackWhileEating()) { - wasUsingItem = true; - return; - } - bypassItemUseLogic = true; - } - } - - if (!usingItem && wasUsingItem && onItemUse.get() != UseMode.IGNORE) { - int delay = delayPostStopUse.get(); - if (delay > 0) { - postUseDelayTicks = delay; - } - } - - if (postUseDelayTicks > 0) { - postUseDelayTicks--; - wasUsingItem = usingItem; - return; - } - - if (usingItem && !bypassItemUseLogic) { - switch (onItemUse.get()) { - case WAIT -> { - wasUsingItem = true; - return; - } - case STOP -> { - mc.player.releaseUsingItem(); - postUseDelayTicks = delayPostStopUse.get(); - wasUsingItem = false; - return; - } - case IGNORE -> { - // continue - } - } - } - - wasUsingItem = usingItem; - - if (!isOnObjective(hit)) return; - - int clickCount = 1; - if (!autoMode) { - clickCount = resolveClickCountForCurrentProtocol(); - if (clickCount <= 0) return; - } - - if (!autoMode) { - ClickHumanizer.Decision decision = humanizer.decide(); - switch (decision) { - case PAUSE -> { - return; - } - case MISS_SWING -> { - mc.player.swing(InteractionHand.MAIN_HAND); - return; - } - case MISS -> { - return; - } - case CLICK -> { - // proceed - } - } - } - - if (hit instanceof EntityHitResult entityHit) { - if (!(entityHit.getEntity() instanceof LivingEntity living) || !canAttackNow(mc.player, living)) { - return; - } - } - performClick(mc.player, hit, clickCount); - } - - @EventHandler - public void onPacketSend(PacketEvent.Send event) { - if (!isEnabled()) return; - if (!delayOnBroken.get()) return; - if (event.getPacket() instanceof ServerboundPlayerActionPacket pkt - && pkt.getAction() == ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK) { - lastFinishBreak = System.currentTimeMillis(); - } - } - - private HitResult resolveHitResult(LocalPlayer player) { - HitResult hit = mc.hitResult; - Reach reach = Modules.get(Reach.class); - if ((hit == null || hit.getType() != HitResult.Type.ENTITY) - && reach != null && reach.isEnabled()) { - EntityHitResult reachHit = reach.raycastEntities(player); - if (reachHit != null) { - hit = reachHit; - } - } - return hit; - } - - private boolean isOnObjective(HitResult hit) { - return switch (objective.get()) { - case ENEMY -> hit instanceof EntityHitResult eHit && isValidTarget(eHit.getEntity()); - case ENTITY -> hit instanceof EntityHitResult; - case BLOCK -> hit instanceof BlockHitResult; - case ANY -> true; - }; - } - - private boolean isValidTarget(Entity entity) { - if (!(entity instanceof LivingEntity living) || !living.isAlive()) return false; - if (mc.player == null) return false; - - if (targetToggles.get(TargetFilters.PLAYERS_ONLY) && !(living instanceof Player)) { - return false; - } - - if (targetToggles.get(TargetFilters.VISIBLE_ONLY) && !mc.player.hasLineOfSight(living)) { - return false; - } - - if (targetToggles.get(TargetFilters.IGNORE_ENTITIES)) { - var id = BuiltInRegistries.ENTITY_TYPE.getKey(living.getType()); - if (id != null && EntityFilters.get().isIgnoredEntity(id.toString())) { - return false; - } - } - - if (living instanceof Player p) { - CategoryType type = CategoryRules.determine(p.getGameProfile().name()); - if (type == CategoryType.BEDWARS_SELF) return false; - if (targetToggles.get(TargetFilters.IGNORE_FRIENDS) && type == CategoryType.FRIEND) return false; - if (targetToggles.get(TargetFilters.IGNORE_STAFF) && type == CategoryType.STAFF) return false; - return !targetToggles.get(TargetFilters.IGNORE_ENEMIES) - || (type != CategoryType.ENEMY && type != CategoryType.BEDWARS_ENEMY); - } - - return true; - } - - private boolean isWeaponSelected(LocalPlayer player) { - ItemStack stack = player.getMainHandItem(); - return switch (weapon.get()) { - case SWORD -> stack.is(ItemTags.SWORDS); - case AXE -> stack.is(ItemTags.AXES); - case BOTH -> stack.is(ItemTags.SWORDS) || stack.is(ItemTags.AXES); - case ANY -> true; - }; - } - - private void performClick(LocalPlayer player, HitResult hit, int clickCount) { - boolean legacyProtocol = isLegacyAttackProtocol(); - if (hit instanceof EntityHitResult eHit) { - Entity target = eHit.getEntity(); - if (objective.get() == ObjectiveType.ENEMY && !isValidTarget(target)) { - return; - } - - Reach reach = Modules.get(Reach.class); - if (reach != null && reach.isEnabled()) { - mc.hitResult = eHit; - } - - if (target instanceof LivingEntity living) { - CombatStrikeController.INSTANCE.tryAttack( - mc, - living, - legacyProtocol, - clickCount, - CombatStrikeController.SprintResetMode.LEGIT, - false, - null - ); - } - return; - } - - if (objective.get() == ObjectiveType.BLOCK) { - for (int i = 0; i < clickCount; i++) { - player.swing(InteractionHand.MAIN_HAND); - if (legacyProtocol) { - ResetAttackCooldown.resetAttackCooldown(player); - } - } - } - } - - public boolean isAutoMode() { - return "auto".equalsIgnoreCase(mode.get()); - } - - public boolean shouldBlockBreaking() { - return objective.get() != ObjectiveType.BLOCK; - } - - private int resolveClickCountForCurrentProtocol() { - if (!isLegacyAttackProtocol()) { - return 1; - } - - int clickCount = clicker.getClicksAt(0); - if (clickCount <= 0) { - return 0; - } - - return clickCount; - } - - private boolean canAttackNow(LocalPlayer player, LivingEntity target) { - if (player == null) return false; - return AttackPressing.INSTANCE.isCooldownComplete(player, target, isLegacyAttackProtocol(), 0); - } - - private boolean isLegacyAttackProtocol() { - return switch (protocolMode.get()) { - case AUTO -> ProtocolUtil.isLegacyAttackProtocol(protocolHeuristicSources.getAll()); - case FORCE_1_8 -> true; - case FORCE_1_9 -> false; - }; - } - - public boolean usesLegacyProtocol() { - return isLegacyAttackProtocol(); - } - - public enum ObjectiveType { - ENEMY, - ENTITY, - BLOCK, - ANY - } - - public enum WeaponType { - SWORD, - AXE, - BOTH, - ANY - } - - public enum UseMode { - WAIT, - STOP, - IGNORE - } - - @Getter - @RequiredArgsConstructor - public enum ProtocolMode implements EnumValue.IdProvider { - AUTO("auto"), - FORCE_1_8("1.8"), - FORCE_1_9("1.9"); - - private final String id; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoBed.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoBed.java deleted file mode 100644 index 45ab25c..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoBed.java +++ /dev/null @@ -1,1192 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.common.impl.TargetFilters; -import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.RotationUpdateEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.WorldPhase; -import dev.loki.lovisual.features.module.modules.combat.autobed.*; -import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.renderer.Renderer3D; -import dev.loki.lovisual.render.engine.text.FontInfo; -import dev.loki.lovisual.render.engine.text.Fonts; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.render.engine.text.WorldTextRenderer; -import dev.loki.lovisual.util.aiming.RestrictedSingleUseAction; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.combat.CombatRotationModeUtil; -import dev.loki.lovisual.util.combat.RubberHandUseUtil; -import dev.loki.lovisual.util.item.FoodUtil; -import dev.loki.lovisual.util.entity.simulation.PositionExtrapolation; -import dev.loki.lovisual.util.player.inventory.InventorySearchScope; -import dev.loki.lovisual.util.player.inventory.InventorySwap; -import dev.loki.lovisual.util.player.inventory.InventorySwapVisibility; -import dev.loki.lovisual.util.player.simulation.PlayerSimulationCache; -import dev.loki.lovisual.util.target.TargetManager; -import dev.loki.lovisual.util.target.TargetingUtil; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -@ModuleInfo( - id = "autobed", - displayName = "AutoBed", - aliases = {"BedAura", "Bed"}, - category = ModuleCategory.COMBAT, - description = "module.autobed.description" -) -public class AutoBed extends Module { - private static final int ROTATION_PRIORITY = 33; - private static final long DAMAGE_RESET_MS = 1000L; - private static final long PENDING_BED_PLACE_CONFIRM_TIMEOUT_MS = 180L; - private static final long PENDING_BED_EXPLODE_CONFIRM_TIMEOUT_MS = 320L; - private static final double TEXT_Y_OFFSET = 0.10; - private static final double TEXT_WORLD_SCALE = 0.025; - private static final double TEXT_SCALE = 1.0; - private static final double TEXT_GAP_SCALE = 1.0; - - private final Minecraft mc = Minecraft.getInstance(); - - private final BooleanValue placeEnabled = boolCommon("autobedPlace", "place", CommonSettingSchemas.PLACE, true); - private final BooleanValue explodeEnabled = boolCommon("autobedExplode", "explode", CommonSettingSchemas.EXPLODE, true); - private final BooleanValue instantExplode = bool("autobedInstantExplode", "instant_explode", true); - private final EnumValue timing = enumCommon("autobedTiming", "timing", CommonSettingSchemas.TIMING, Timing.NORMAL); - private final NumberValue calcDelay = numCommon("autobedCalcDelay", "calc_delay", CommonSettingSchemas.CALC_DELAY, 100, 0, 500); - private final NumberValue placeDelay = numCommon( - "autobedPlaceDelay", - "place_delay", - CommonSettingSchemas.PLACEMENT_DELAY, - 0, - 0, - 1000 - ); - private final NumberValue lowPlaceDelay = numCommon("autobedLowPlaceDelay", "low_place_delay", CommonSettingSchemas.LOW_PLACE_DELAY, 550, 0, 1000); - private final NumberValue explodeDelay = numCommon( - "autobedExplodeDelay", - "explode_delay", - CommonSettingSchemas.PLACEMENT_BREAK_DELAY, - 0, - 0, - 1000 - ); - private final NumberValue lowExplodeDelay = numCommon("autobedLowExplodeDelay", "low_explode_delay", CommonSettingSchemas.LOW_EXPLODE_DELAY, 550, 0, 1000); - private final NumberValue placeRange = numCommon( - "autobedPlaceRange", - "place_range", - CommonSettingSchemas.PLACEMENT_RANGE, - 5.0f, - 1.0f, - 6.0f - ); - private final NumberValue wallRange = numCommon( - "autobedWallRange", - "wall_range", - CommonSettingSchemas.PLACEMENT_WALL_RANGE, - 3.5f, - 0.0f, - 6.0f - ); - private final EnumValue placementMode = enumCommon( - "autobedPlacementMode", - "placement_mode", - CommonSettingSchemas.PLACEMENT_MODE, - AutoBedPlacementMode.DEFAULT, - AutoBedPlacementMode.values() - ); - private final NumberValue targetRange = numCommon( - "autobedTargetRange", - "target_range", - CommonSettingSchemas.COMBAT_RANGE, - 10.0f, - 1.0f, - 15.0f - ); - private final BooleanMapValue targetToggles = groupCommon( - "autobedTargets", - "targets", - CommonSettingSchemas.TARGET_FILTERS - ); - private final EnumValue priority = enumCommon( - "autobedPriority", - "priority", - CommonSettingSchemas.COMBAT_PRIORITY, - TargetingUtil.TargetPriority.DISTANCE, - TargetingUtil.TargetPriority.values() - ); - private final NumberValue minDamage = numCommon("autobedMinDamage", "min_damage", CommonSettingSchemas.MIN_DAMAGE, 6.0f, 0.0f, 36.0f); - private final NumberValue faceplaceHealth = numCommon("autobedFaceplaceHealth", "faceplace_health", CommonSettingSchemas.FACEPLACE_HEALTH, 5.0f, 0.0f, 36.0f); - private final NumberValue maxSelfDamage = numCommon("autobedMaxSelfDamage", "max_self_damage", CommonSettingSchemas.MAX_SELF_DAMAGE, 10.0f, 0.0f, 36.0f); - private final NumberValue predictTicks = numCommon( - "autobedPredictTicks", - "predict_ticks", - CommonSettingSchemas.PLACEMENT_PREDICTION, - 3, - 0, - 20 - ); - private final NumberValue selfPredictTicks = numCommon("autobedSelfPredictTicks", "self_predict_ticks", CommonSettingSchemas.SELF_PREDICT_TICKS, 3, 0, 20); - private final BooleanValue pauseMining = boolCommon("autobedPauseMining", "pause_mining", CommonSettingSchemas.PAUSE_MINING, true); - private final BooleanValue pauseEating = boolCommon("autobedPauseEating", "pause_eating", CommonSettingSchemas.PAUSE_EATING, true); - private final NumberValue pauseHealth = numCommon( - "autobedPauseHealth", - "pause_health", - CommonSettingSchemas.PLAYER_HEALTH_THRESHOLD, - 8.0f, - 0.0f, - 20.0f - ); - private final EnumValue swapScope = enumCommon( - "autobedSwapScope", - "swap_scope", - CommonSettingSchemas.INVENTORY_SEARCH_SCOPE, - InventorySearchScope.FULL, - InventorySearchScope.values() - ); - private final EnumValue swapVisibility = enumCommon( - "autobedSwapVisibility", - "swap_visibility", - CommonSettingSchemas.INVENTORY_SWAP_VISIBILITY, - InventorySwapVisibility.SILENT, - InventorySwapVisibility.values() - ); - private final BooleanValue restoreItem = boolCommon( - "autobedRestoreItem", - "restore_item", - CommonSettingSchemas.INVENTORY_RESTORE_ITEM, - true - ); - private final ModeValue attackMode = modeCommon( - "autobedAttackMode", - "attack_mode", - CommonSettingSchemas.COMBAT_ATTACK_MODE, - CombatRotationModeUtil.MODE_ROTATIONS, - CombatRotationModeUtil.MODE_ROTATIONS, - CombatRotationModeUtil.MODE_NO_ROTATIONS - ); - private final EnumValue movementCorrection = visibleWhen(enumCommon( - "autobedMovementCorrection", - "movement_correction", - CommonSettingSchemas.PLACEMENT_MOVEMENT_CORRECTION, - MovementCorrection.SILENT, - MovementCorrection.values() - ), this::usesRotationSettings); - private final NumberValue rotationResetTicks = visibleWhen(numCommon( - "autobedRotationResetTicks", - "rotation_reset_ticks", - CommonSettingSchemas.ROTATION_RESET_TICKS, - 1, - 1, - 20 - ), this::usesRotationSettings); - private final NumberValue rotationResetThreshold = visibleWhen(numCommon( - "autobedRotationResetThreshold", - "rotation_reset_threshold", - CommonSettingSchemas.ROTATION_RESET_THRESHOLD, - 2.0f, - 0.1f, - 15.0f - ), this::usesRotationSettings); - private final BooleanValue renderEnabled = boolCommon( - "autobedRender", - "render", - CommonSettingSchemas.PLACEMENT_RENDER, - true - ); - private final EnumValue renderMode = enumCommon( - "autobedRenderMode", - "render_mode", - CommonSettingSchemas.PLACEMENT_RENDER_MODE, - RenderMode.FADE, - RenderMode.values() - ); - private final BooleanValue renderSelfDamage = boolCommon("autobedRenderSelfDamage", "render_self_damage", CommonSettingSchemas.RENDER_SELF_DAMAGE, true); - private final BooleanValue drawDamage = boolCommon("autobedRenderDamage", "render_damage", CommonSettingSchemas.RENDER_DAMAGE, true); - private final RGBAColorValue fillColor = common(color("autobedFillColor", "#5A285AFF"), CommonSettingSchemas.FILL_COLOR); - private final RGBAColorValue lineColor = common(color("autobedLineColor", "#FFAA55FF"), CommonSettingSchemas.LINE_COLOR); - private final NumberValue lineWidth = numCommon("autobedLineWidth", "line_width", CommonSettingSchemas.LINE_WIDTH, 2.0f, 1.0f, 6.0f); - private final RGBAColorValue textColor = common(color("autobedTextColor", "#FFFFFFFF"), CommonSettingSchemas.TEXT_COLOR); - private final NumberValue slideDelay = visibleWhen(numCommon("autobedSlideDelay", "slide_delay", CommonSettingSchemas.SLIDE_DELAY, 200, 1, 1000), - () -> renderMode.get() == RenderMode.SLIDE); - private final NumberValue fadeTime = visibleWhen(numCommon("autobedFadeTime", "fade_time", CommonSettingSchemas.FADE_TIME, 500, 100, 2000), - () -> renderMode.get() == RenderMode.FADE); - - private final AutoBedPlanner planner = new AutoBedPlanner(); - private final AutoBedPlanner.Context plannerContext = new PlannerContext(); - private final AutoBedEntityBlocker entityBlocker = new AutoBedEntityBlocker(); - private final Map renderPositions = new ConcurrentHashMap<>(); - - private LivingEntity target; - private AutoBedData bestPlace; - private AutoBedData bestExplode; - private BlockPos renderFootPos; - private BlockPos renderHeadPos; - private BlockPos prevRenderFootPos; - private BlockPos prevRenderHeadPos; - private BlockPos bestFootPos; - private BlockPos bestHeadPos; - private int renderTick; - private int renderStartTick; - private long lastPlaceMs; - private long lastExplodeMs; - private long lastDamageUpdateMs; - private long lastCalcMs; - private AutoBedData pendingBedData; - private long pendingBedSinceMs; - private boolean pendingBedPlaceSent; - private boolean pendingBedExplodeSent; - private long pendingBedExplodeSentMs; - private float renderDamage; - private float renderSelfDamageValue; - private boolean lowDamageMode; - private int lastScanned; - private int lastCandidates; - private int lastSafeCandidates; - private int lastSelfDamageRejects; - private String disabledReason; - - @Override - public WorldPhase getWorldPhase() { - return WorldPhase.AFTER_POST_PROCESS; - } - - @Override - protected String getUnavailableReason() { - if (mc != null && mc.level != null && !isExplosiveBedDimension(mc.level)) { - return "Nether/End only"; - } - return ""; - } - - @Override - public void onEnable() { - resetState(); - } - - @Override - public void onDisable() { - resetState(); - RotationManager.INSTANCE.clear(this); - TargetManager.setAutoBedTarget(null); - } - - @Override - public void onTick() { - if (!isEnabled()) return; - renderTick++; - InventorySwap.INSTANCE.tick(); - purgeExpiredRenderPositions(); - if (System.currentTimeMillis() - lastDamageUpdateMs > DAMAGE_RESET_MS && renderPositions.isEmpty()) { - renderDamage = 0.0f; - renderSelfDamageValue = 0.0f; - } - } - - @EventHandler(priority = 23) - private void onRotationUpdate(RotationUpdateEvent event) { - if (event.getType() != RotationUpdateEvent.Type.PRE) return; - if (!isEnabled()) return; - - if (mc.player == null || mc.level == null || mc.gameMode == null) { - clearCombatState(); - TargetManager.setAutoBedTarget(null); - return; - } - - if (!isExplosiveBedDimension(mc.level)) { - disabledReason = "Wrong dimension"; - clearCombatState(); - TargetManager.setAutoBedTarget(null); - RotationManager.INSTANCE.clear(this); - return; - } - disabledReason = null; - - target = findCombatTarget(); - TargetManager.setAutoBedTarget(target); - updateCandidates(); - - if (timing.get() == Timing.NORMAL) { - runCombatCycle(); - } - } - - @EventHandler(priority = -23) - private void onRotationUpdatePost(RotationUpdateEvent event) { - if (event.getType() != RotationUpdateEvent.Type.POST) return; - if (!isEnabled() || timing.get() != Timing.SEQUENTIAL) return; - runCombatCycle(); - } - - @Override - public void onRenderWorldEngine(Renderer3D renderer, Renderer3D depthRenderer, float tickDelta) { - if (!isEnabled() || mc.player == null || mc.level == null) return; - if (renderEnabled.get()) { - renderPlacement(renderer, tickDelta); - } - } - - private void updateCandidates() { - if (target == null || shouldPause()) { - bestPlace = null; - bestExplode = null; - lastCalcMs = 0L; - return; - } - - long now = System.currentTimeMillis(); - long delay = Math.max(0, calcDelay.get()); - if (delay > 0L && now - lastCalcMs < delay) { - return; - } - lastCalcMs = now; - - AutoBedPlanner.ScanResult result = planner.scan( - plannerContext, - target, - resolvePredictedPosition(target, predictTicks.get()), - Mth.ceil(placeRange.get()) - ); - bestPlace = result.bestPlace(); - bestExplode = result.bestExplode(); - lastScanned = result.scanned(); - lastCandidates = result.candidates(); - lastSafeCandidates = result.safeCandidates(); - lastSelfDamageRejects = result.selfDamageRejects(); - - AutoBedData renderData = bestExplode != null ? bestExplode : bestPlace; - if (renderData != null) { - setRenderCandidate(renderData); - lowDamageMode = !AutoBedDamageRules.shouldOverrideMinDamage(target, renderData.damage(), faceplaceHealth.get()) - && renderData.damage() < minDamage.get(); - } else if (renderPositions.isEmpty()) { - bestFootPos = null; - bestHeadPos = null; - } - } - - private void runCombatCycle() { - if (mc.player == null || mc.level == null) { - clearPendingBed(); - RotationManager.INSTANCE.clear(this); - return; - } - if (shouldPause()) { - RotationManager.INSTANCE.clear(this); - return; - } - - if (continuePendingBedCycle()) { - return; - } - - if (target == null) { - RotationManager.INSTANCE.clear(this); - return; - } - - if (explodeEnabled.get() && bestExplode != null && hasExplodeDelayElapsed()) { - executeWithRotation(bestExplode, false, () -> explodeBed(bestExplode)); - return; - } - - if (placeEnabled.get() && bestPlace != null && hasPlaceDelayElapsed()) { - executeWithRotation(bestPlace, true, () -> placeBed(bestPlace)); - return; - } - - RotationManager.INSTANCE.clear(this); - } - - private void executeWithRotation(AutoBedData data, boolean placing, Runnable action) { - if (data == null || action == null || mc.player == null) return; - if (!usesRotationSettings()) { - RotationManager.INSTANCE.clear(this); - action.run(); - return; - } - - Rotation rotation = rotationFor(data, placing); - RotationTarget rotationTarget = new RotationTarget( - rotation, - target, - List.of(), - rotationResetTicks.get(), - rotationResetThreshold.get(), - true, - movementCorrection.get(), - new RestrictedSingleUseAction(action) - ); - RotationManager.INSTANCE.setRotationTarget(rotationTarget, ROTATION_PRIORITY, this); - } - - private Rotation rotationFor(AutoBedData data, boolean placing) { - BlockHitResult hit = placing ? data.placeHitResult() : data.explodeHitResult(); - Vec3 point = hit != null ? hit.getLocation() : data.explosionVec(); - Rotation look = Rotation.lookingAt(point, mc.player.getEyePosition()); - if (placing) { - return new Rotation(AutoBedInteractionUtil.yawForFacing(data.facing()), look.pitch()).normalize(); - } - return look.normalize(); - } - - private void placeBed(AutoBedData data) { - if (data == null || data.existingBed() || !hasPlaceDelayElapsed() || shouldPause()) return; - AutoBedData refreshed = planner.evaluate(plannerContext, data, target); - if (refreshed == null || refreshed.existingBed()) { - clearPendingBedIfMatches(data); - return; - } - - setPendingBed(refreshed, true); - boolean placed = AutoBedActionUtil.placeBed( - mc, - this, - refreshed.placeHitResult(), - swapScope.get(), - swapVisibility.get(), - restoreItem.get() - ); - if (!placed) { - clearPendingBedIfMatches(refreshed); - return; - } - - lastPlaceMs = System.currentTimeMillis(); - pendingBedSinceMs = lastPlaceMs; - markPlaced(refreshed); - } - - private void explodeBed(AutoBedData data) { - if (data == null || !hasExplodeDelayElapsed() || shouldPause()) return; - AutoBedData refreshed = planner.evaluate(plannerContext, data, target); - if (refreshed == null || !refreshed.existingBed()) { - clearPendingBedIfMatches(data); - return; - } - - setPendingBed(refreshed, false); - detonatePendingBed(refreshed); - } - - private boolean continuePendingBedCycle() { - if (pendingBedData == null) { - return false; - } - if (mc.player == null || mc.level == null) { - clearPendingBed(); - return false; - } - - long now = System.currentTimeMillis(); - BlockPos bedPos = findPendingBedInteractPos(); - if (bedPos == null) { - if (pendingBedExplodeSent) { - clearPendingBed(); - return false; - } - if (pendingBedPlaceSent && now - pendingBedSinceMs < PENDING_BED_PLACE_CONFIRM_TIMEOUT_MS) { - RotationManager.INSTANCE.clear(this); - return true; - } - clearPendingBed(); - return false; - } - - AutoBedData pendingData = resolvePendingBedData(bedPos); - if (pendingData == null) { - if (now - pendingBedSinceMs < PENDING_BED_PLACE_CONFIRM_TIMEOUT_MS) { - RotationManager.INSTANCE.clear(this); - return true; - } - clearPendingBed(); - return false; - } - - pendingBedData = pendingData; - pendingBedSinceMs = now; - - if (pendingBedExplodeSent) { - if (isPendingBedBlock(bedPos) && now - pendingBedExplodeSentMs < PENDING_BED_EXPLODE_CONFIRM_TIMEOUT_MS) { - RotationManager.INSTANCE.clear(this); - return true; - } - pendingBedExplodeSent = false; - pendingBedExplodeSentMs = 0L; - if (!isPendingBedBlock(bedPos)) { - clearPendingBed(); - return false; - } - } - - if (!explodeEnabled.get()) { - clearPendingBed(); - return false; - } - - if (hasPendingExplodeDelayElapsed()) { - executeWithRotation(pendingData, false, () -> detonatePendingBed(pendingData)); - return true; - } - - RotationManager.INSTANCE.clear(this); - return true; - } - - private void detonatePendingBed(AutoBedData data) { - if (data == null || data.explodeHitResult() == null || !hasPendingExplodeDelayElapsed() || shouldPause()) return; - - boolean exploded = AutoBedActionUtil.explodeBed( - mc, - this, - data.explodeHitResult(), - swapScope.get(), - swapVisibility.get(), - restoreItem.get() - ); - if (!exploded) return; - - lastExplodeMs = System.currentTimeMillis(); - pendingBedExplodeSent = true; - pendingBedExplodeSentMs = lastExplodeMs; - markPlaced(data); - } - - private AutoBedData resolvePendingBedData(BlockPos bedPos) { - if (pendingBedData == null || bedPos == null || mc.player == null || mc.level == null) { - return null; - } - - BlockHitResult hit = findPendingBedInteractResult(bedPos); - if (hit == null) { - return null; - } - - var state = mc.level.getBlockState(hit.getBlockPos()); - if (!AutoBedInteractionUtil.isBedBlock(state)) { - return null; - } - - BlockPos footPos = AutoBedInteractionUtil.resolveFootPos(state, hit.getBlockPos()); - BlockPos headPos = AutoBedInteractionUtil.resolveHeadPos(state, hit.getBlockPos()); - if (footPos == null || headPos == null) { - return null; - } - - AutoBedData template = new AutoBedData( - footPos, - headPos, - AutoBedInteractionUtil.bedFacing(state), - hit.getBlockPos(), - pendingBedData.placeHitResult(), - hit, - AutoBedInteractionUtil.bedExplosionVec(hit.getBlockPos()), - pendingBedData.damage(), - pendingBedData.selfDamage(), - pendingBedData.overrideDamage(), - true - ); - AutoBedData evaluated = target != null ? planner.evaluate(plannerContext, template, target) : null; - if (evaluated != null && evaluated.existingBed()) { - return evaluated; - } - - return template; - } - - private BlockPos findPendingBedInteractPos() { - if (pendingBedData == null || mc.level == null) { - return null; - } - - BlockPos preferred = pendingBedData.interactPos(); - if (isPendingBedBlock(preferred)) return preferred; - if (isPendingBedBlock(pendingBedData.footPos())) return pendingBedData.footPos(); - if (isPendingBedBlock(pendingBedData.headPos())) return pendingBedData.headPos(); - - // If placement yaw was not applied exactly, vanilla can still place the bed at the same clicked foot - // but with another horizontal head direction. Adopt that real client-side bed immediately instead of - // sitting in Waiting bed until the confirm timeout expires. - BlockPos adopted = findBedTouchingPendingPlacement(); - if (adopted != null) return adopted; - return null; - } - - private BlockHitResult findPendingBedInteractResult(BlockPos preferred) { - if (preferred != null && isPendingBedBlock(preferred)) { - BlockHitResult hit = getBedInteractResult(preferred); - if (hit != null) return hit; - } - - BlockPos foot = pendingBedData.footPos(); - if (foot != null && isPendingBedBlock(foot)) { - BlockHitResult hit = getBedInteractResult(foot); - if (hit != null) return hit; - } - - BlockPos head = pendingBedData.headPos(); - if (head != null && isPendingBedBlock(head)) { - BlockHitResult hit = getBedInteractResult(head); - if (hit != null) return hit; - } - - BlockPos adopted = findBedTouchingPendingPlacement(); - if (adopted != null) { - BlockHitResult hit = getBedInteractResult(adopted); - if (hit != null) return hit; - } - return null; - } - - private BlockPos findBedTouchingPendingPlacement() { - if (pendingBedData == null || mc.level == null) return null; - BlockPos foot = pendingBedData.footPos(); - BlockPos head = pendingBedData.headPos(); - - BlockPos direct = findBedAtOrAdjacent(foot); - if (direct != null) return direct; - return findBedAtOrAdjacent(head); - } - - private BlockPos findBedAtOrAdjacent(BlockPos origin) { - if (origin == null || mc.level == null) return null; - if (isAdoptablePendingBedBlock(origin)) return origin; - for (Direction direction : Direction.Plane.HORIZONTAL) { - BlockPos pos = origin.relative(direction); - if (isAdoptablePendingBedBlock(pos)) { - return pos; - } - } - return null; - } - - private boolean isPendingBedBlock(BlockPos pos) { - if (pos == null || mc.level == null || pendingBedData == null || !mc.level.isInWorldBounds(pos)) return false; - var state = mc.level.getBlockState(pos); - if (!AutoBedInteractionUtil.isBedBlock(state)) return false; - BlockPos footPos = AutoBedInteractionUtil.resolveFootPos(state, pos); - BlockPos headPos = AutoBedInteractionUtil.resolveHeadPos(state, pos); - if (positionsEqual(footPos, pendingBedData.footPos()) && positionsEqual(headPos, pendingBedData.headPos())) { - return true; - } - return pendingBedPlaceSent && overlapsPendingBed(footPos, headPos); - } - - private boolean isAdoptablePendingBedBlock(BlockPos pos) { - if (pos == null || mc.level == null || pendingBedData == null || !mc.level.isInWorldBounds(pos)) return false; - var state = mc.level.getBlockState(pos); - if (!AutoBedInteractionUtil.isBedBlock(state)) return false; - BlockPos footPos = AutoBedInteractionUtil.resolveFootPos(state, pos); - BlockPos headPos = AutoBedInteractionUtil.resolveHeadPos(state, pos); - return overlapsPendingBed(footPos, headPos); - } - - private boolean overlapsPendingBed(BlockPos footPos, BlockPos headPos) { - if (pendingBedData == null) return false; - return positionsEqual(footPos, pendingBedData.footPos()) - || positionsEqual(footPos, pendingBedData.headPos()) - || positionsEqual(headPos, pendingBedData.footPos()) - || positionsEqual(headPos, pendingBedData.headPos()); - } - - private boolean positionsEqual(BlockPos first, BlockPos second) { - return first != null && first.equals(second); - } - - private void setPendingBed(AutoBedData data, boolean placeSent) { - if (data == null) { - clearPendingBed(); - return; - } - if (pendingBedData == null - || !positionsEqual(data.footPos(), pendingBedData.footPos()) - || !positionsEqual(data.headPos(), pendingBedData.headPos())) { - pendingBedSinceMs = System.currentTimeMillis(); - pendingBedExplodeSent = false; - pendingBedExplodeSentMs = 0L; - } - pendingBedData = data; - pendingBedPlaceSent = placeSent || !data.existingBed(); - } - - private void clearPendingBedIfMatches(AutoBedData data) { - if (data == null || pendingBedData == null) return; - if (positionsEqual(data.footPos(), pendingBedData.footPos()) - && positionsEqual(data.headPos(), pendingBedData.headPos())) { - clearPendingBed(); - } - } - - private void clearPendingBed() { - pendingBedData = null; - pendingBedSinceMs = 0L; - pendingBedPlaceSent = false; - pendingBedExplodeSent = false; - pendingBedExplodeSentMs = 0L; - } - - private boolean shouldPause() { - if (mc.player == null || mc.level == null || mc.gameMode == null) return true; - if (!isExplosiveBedDimension(mc.level)) { - disabledReason = "Wrong dimension"; - return true; - } - disabledReason = null; - if (pauseMining.get() && mc.gameMode.isDestroying()) return true; - if (pauseEating.get() - && mc.player.isUsingItem() - && FoodUtil.isFood(mc.player.getUseItem()) - && !RubberHandUseUtil.canBypassCurrentUse(mc)) return true; - return mc.player.getHealth() + mc.player.getAbsorptionAmount() < pauseHealth.get(); - } - - private boolean isExplosiveBedDimension(ClientLevel level) { - return level != null && (level.dimension() == Level.NETHER || level.dimension() == Level.END); - } - - private boolean hasPlaceDelayElapsed() { - return System.currentTimeMillis() - lastPlaceMs >= Math.max(0, lowDamageMode ? lowPlaceDelay.get() : placeDelay.get()); - } - - private boolean hasExplodeDelayElapsed() { - return System.currentTimeMillis() - lastExplodeMs >= Math.max(0, lowDamageMode ? lowExplodeDelay.get() : explodeDelay.get()); - } - - private boolean hasPendingExplodeDelayElapsed() { - return (pendingBedPlaceSent && instantExplode.get()) || hasExplodeDelayElapsed(); - } - - private long getPlaceDelayRemainingMs() { - return Math.max(0L, Math.max(0, lowDamageMode ? lowPlaceDelay.get() : placeDelay.get()) - (System.currentTimeMillis() - lastPlaceMs)); - } - - private long getExplodeDelayRemainingMs() { - return Math.max(0L, Math.max(0, lowDamageMode ? lowExplodeDelay.get() : explodeDelay.get()) - (System.currentTimeMillis() - lastExplodeMs)); - } - - private long getPendingExplodeDelayRemainingMs() { - if (pendingBedPlaceSent && instantExplode.get()) return 0L; - return getExplodeDelayRemainingMs(); - } - - private void setRenderCandidate(AutoBedData data) { - bestFootPos = data.footPos(); - bestHeadPos = data.headPos(); - renderDamage = Math.max(0.0f, data.damage()); - renderSelfDamageValue = Math.max(0.0f, data.selfDamage()); - lastDamageUpdateMs = System.currentTimeMillis(); - } - - private void markPlaced(AutoBedData data) { - if (data == null || data.footPos() == null || data.headPos() == null) return; - if (!data.footPos().equals(renderFootPos) || !data.headPos().equals(renderHeadPos)) { - renderStartTick = renderTick; - prevRenderFootPos = renderFootPos; - prevRenderHeadPos = renderHeadPos; - renderFootPos = data.footPos(); - renderHeadPos = data.headPos(); - } - setRenderCandidate(data); - renderPositions.put(data.footPos(), System.currentTimeMillis()); - renderPositions.put(data.headPos(), System.currentTimeMillis()); - } - - private void renderPlacement(Renderer3D renderer, float tickDelta) { - String damageText = buildDamageText(); - if (damageText.isEmpty() && renderPositions.isEmpty() && renderFootPos == null) { - return; - } - - if (renderMode.get() == RenderMode.FADE) { - renderFade(renderer); - return; - } - - BlockPos activeFoot = renderPositions.isEmpty() ? bestFootPos : renderFootPos; - BlockPos activeHead = renderPositions.isEmpty() ? bestHeadPos : renderHeadPos; - if (activeFoot == null || activeHead == null) return; - - if (renderMode.get() == RenderMode.SLIDE) { - BlockPos slideFoot = renderPositions.isEmpty() ? bestFootPos : renderFootPos; - BlockPos slideHead = renderPositions.isEmpty() ? bestHeadPos : renderHeadPos; - BlockPos fromFoot = prevRenderFootPos != null ? prevRenderFootPos : slideFoot; - BlockPos fromHead = prevRenderHeadPos != null ? prevRenderHeadPos : slideHead; - renderBox(renderer, AutoBedRenderUtil.lerpBox(bedBox(fromFoot, fromHead), bedBox(slideFoot, slideHead), getSlideProgress(tickDelta)), 1.0f); - } else { - renderBox(renderer, bedBox(activeFoot, activeHead), 1.0f); - } - } - - private AABB bedBox(BlockPos foot, BlockPos head) { - return new AABB(foot).minmax(new AABB(head)); - } - - private float getSlideProgress(float tickDelta) { - float clampedTickDelta = Mth.clamp(tickDelta, 0.0f, 1.0f); - float durationTicks = Math.max(1.0f, slideDelay.get() / 50.0f); - return Mth.clamp((renderTick - renderStartTick + clampedTickDelta) / durationTicks, 0.0f, 1.0f); - } - - private void renderFade(Renderer3D renderer) { - long now = System.currentTimeMillis(); - int lifetime = Math.max(1, fadeTime.get()); - List> entries = new ArrayList<>(renderPositions.entrySet()); - for (Map.Entry entry : entries) { - long age = now - entry.getValue(); - if (age > lifetime) { - renderPositions.remove(entry.getKey()); - continue; - } - float alpha = 1.0f - (age / (float) lifetime); - renderBox(renderer, new AABB(entry.getKey()), alpha); - } - } - - private void renderBox(Renderer3D renderer, AABB box, float alpha) { - int fillArgb = AutoBedRenderUtil.applyOpacity(fillColor.getArgb(), alpha); - int lineArgb = AutoBedRenderUtil.applyOpacity(lineColor.getArgb(), alpha); - AutoBedRenderUtil.addFilledBox(renderer, box, fillArgb); - - float prevWidth = RenderState.lineWidth; - RenderState.lineWidth = Math.max(0.5f, lineWidth.get()); - try { - AutoBedRenderUtil.addOutlineBox(renderer, box, lineArgb); - } finally { - RenderState.lineWidth = prevWidth; - } - - if (drawDamage.get()) { - renderDamageText(renderer, box.getCenter(), alpha); - } - } - - private void renderDamageText(Renderer3D renderer, Vec3 anchor, float alpha) { - String mainText = AutoBedRenderUtil.formatDamage(renderDamage); - if (mainText.isEmpty()) return; - - int mainArgb = AutoBedRenderUtil.applyOpacity(textColor.getArgb(), alpha); - TextRenderer bold = Fonts.renderer("Iosevka", FontInfo.Type.Bold, TextRenderer.get()); - WorldTextRenderer.Options baseOptions = WorldTextRenderer.Options.defaults() - .withScale(TEXT_SCALE) - .withWorldScale(TEXT_WORLD_SCALE) - .withDepthMode(Renderer3D.DepthMode.NONE) - .withShadow(true) - .withOffset(0.0, TEXT_Y_OFFSET); - - if (!renderSelfDamage.get() || renderSelfDamageValue <= 0.0f) { - WorldTextRenderer.drawBillboard( - renderer, - bold, - mainText, - anchor, - baseOptions.withCentered(true).withColor(new RenderColor(mainArgb)) - ); - return; - } - - String tailText = " / " + AutoBedRenderUtil.formatDamage(renderSelfDamageValue); - TextRenderer medium = Fonts.renderer("Iosevka", FontInfo.Type.Regular, TextRenderer.get()); - double mainWidth = AutoBedRenderUtil.measureWidth(bold, mainText, TEXT_SCALE); - double tailWidth = AutoBedRenderUtil.measureWidth(medium, tailText, TEXT_GAP_SCALE); - double startX = -(mainWidth + tailWidth) * 0.5; - - double drawnMain = WorldTextRenderer.drawBillboard( - renderer, - bold, - mainText, - anchor, - baseOptions.withCentered(false) - .withOffset(startX, TEXT_Y_OFFSET) - .withColor(new RenderColor(mainArgb)) - ); - - WorldTextRenderer.drawBillboard( - renderer, - medium, - tailText, - anchor, - baseOptions.withCentered(false) - .withScale(TEXT_GAP_SCALE) - .withOffset(startX + drawnMain, TEXT_Y_OFFSET) - .withColor(new RenderColor(mainArgb)) - ); - } - - private void purgeExpiredRenderPositions() { - long now = System.currentTimeMillis(); - long lifetime = Math.max(1, fadeTime.get()); - renderPositions.entrySet().removeIf(entry -> now - entry.getValue() > lifetime); - } - - public String getTargetHudStatus(LivingEntity hudTarget) { - if (!isEnabled()) return null; - if (disabledReason != null) return disabledReason; - if (hudTarget == null || target == null || hudTarget != target) return null; - if (mc.player == null || mc.level == null) return "Idle"; - if (!isExplosiveBedDimension(mc.level)) return "Wrong dimension"; - if (shouldPause()) return "Paused"; - if (!AutoBedActionUtil.hasBed(mc, swapScope.get())) return "No beds"; - - if (pendingBedData != null) { - if (pendingBedExplodeSent) return "Confirming bed"; - if (findPendingBedInteractPos() != null) { - long wait = getPendingExplodeDelayRemainingMs(); - if (wait > 0L) return "Bed in " + wait + "ms"; - return usesRotationSettings() ? "Rotate -> bed" : "Exploding bed"; - } - return "Waiting bed"; - } - if (explodeEnabled.get() && bestExplode != null) { - long wait = getExplodeDelayRemainingMs(); - if (wait > 0L) return "Bed in " + wait + "ms"; - return usesRotationSettings() ? "Rotate -> bed" : "Exploding bed"; - } - if (placeEnabled.get() && bestPlace != null) { - long wait = getPlaceDelayRemainingMs(); - if (wait > 0L) return "Bed in " + wait + "ms"; - return usesRotationSettings() ? "Rotate -> bed" : "Placing bed"; - } - if (lastSelfDamageRejects > 0 || (lastCandidates > 0 && lastSafeCandidates <= 0)) return "Self dmg"; - if (lastScanned <= 0) return "No scan"; - return "No bed"; - } - - private LivingEntity findCombatTarget() { - if (mc.player == null || mc.level == null) return null; - TargetingUtil.TargetingSettings settings = new TargetingUtil.TargetingSettings( - targetRange.get(), - 180.0f, - targetToggles.get(TargetFilters.PLAYERS_ONLY), - targetToggles.get(TargetFilters.IGNORE_FRIENDS), - targetToggles.get(TargetFilters.IGNORE_STAFF), - targetToggles.get(TargetFilters.IGNORE_ENEMIES), - targetToggles.get(TargetFilters.IGNORE_NAKED), - targetToggles.get(TargetFilters.IGNORE_ENTITIES), - targetToggles.get(TargetFilters.VISIBLE_ONLY), - priority.get() - ); - return TargetingUtil.findBestTarget(mc, settings); - } - - private Vec3 resolvePredictedPosition(LivingEntity entity, int ticks) { - if (entity == null || ticks <= 0) { - return entity != null ? entity.position() : Vec3.ZERO; - } - if (entity instanceof Player player) { - PlayerSimulationCache.SimulatedPlayerCache simulation = - player == mc.player - ? PlayerSimulationCache.getSimulationForLocalPlayer() - : PlayerSimulationCache.getSimulationForOtherPlayers(player); - if (simulation != null) { - return simulation.getSnapshotAt(ticks).pos(); - } - } - return PositionExtrapolation.getBestForEntity(entity).getPositionInTicks(ticks); - } - - private boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage) { - return AutoBedDamageRules.shouldOverrideMaxSelfDamage( - mc.player, - target, - damage, - selfDamage, - maxSelfDamage.get() - ); - } - - private boolean isSafe(float damage, float selfDamage, boolean overrideDamage) { - return AutoBedDamageRules.isSafe(mc.player, selfDamage, overrideDamage); - } - - private BlockHitResult getPlaceInteractResult(BlockPos footPos, BlockPos headPos) { - return AutoBedInteractionUtil.getPlaceSupportInteract( - mc.level, - mc.player, - footPos, - headPos, - placementMode.get(), - placeRange.get(), - wallRange.get() - ); - } - - private BlockHitResult getBedInteractResult(BlockPos pos) { - return AutoBedInteractionUtil.getBedInteractResult( - mc.level, - mc.player, - pos, - placementMode.get(), - placeRange.get(), - wallRange.get() - ); - } - - private boolean usesRotationSettings() { - return CombatRotationModeUtil.usesRotations(attackMode); - } - - private String buildDamageText() { - String main = AutoBedRenderUtil.formatDamage(renderDamage); - if (main.isEmpty()) return ""; - if (!renderSelfDamage.get() || renderSelfDamageValue <= 0.0f) return main; - return main + " / " + AutoBedRenderUtil.formatDamage(renderSelfDamageValue); - } - - private void clearCombatState() { - target = null; - bestPlace = null; - bestExplode = null; - bestFootPos = null; - bestHeadPos = null; - clearPendingBed(); - RotationManager.INSTANCE.clear(this); - lastScanned = 0; - lastCandidates = 0; - lastSafeCandidates = 0; - lastSelfDamageRejects = 0; - } - - private void resetState() { - target = null; - bestPlace = null; - bestExplode = null; - renderFootPos = null; - renderHeadPos = null; - prevRenderFootPos = null; - prevRenderHeadPos = null; - bestFootPos = null; - bestHeadPos = null; - renderTick = 0; - renderStartTick = 0; - lastPlaceMs = 0L; - lastExplodeMs = 0L; - lastDamageUpdateMs = 0L; - lastCalcMs = 0L; - clearPendingBed(); - renderDamage = 0.0f; - renderSelfDamageValue = 0.0f; - lowDamageMode = false; - renderPositions.clear(); - lastScanned = 0; - lastCandidates = 0; - lastSafeCandidates = 0; - lastSelfDamageRejects = 0; - disabledReason = null; - } - - private final class PlannerContext implements AutoBedPlanner.Context { - @Override - public LocalPlayer player() { - return mc.player; - } - - @Override - public ClientLevel level() { - return mc.level; - } - - @Override - public LivingEntity target() { - return AutoBed.this.target; - } - - @Override - public Vec3 resolvePredictedPosition(LivingEntity entity, int ticks) { - return AutoBed.this.resolvePredictedPosition(entity, ticks); - } - - @Override - public BlockHitResult getPlaceInteractResult(BlockPos footPos, BlockPos headPos) { - return AutoBed.this.getPlaceInteractResult(footPos, headPos); - } - - @Override - public BlockHitResult getBedInteractResult(BlockPos pos) { - return AutoBed.this.getBedInteractResult(pos); - } - - @Override - public boolean isBlockedByEntity(BlockPos footPos, BlockPos headPos) { - return entityBlocker.isBlocked(mc.level, footPos, headPos); - } - - @Override - public boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage) { - return AutoBed.this.shouldOverrideMaxSelfDamage(damage, selfDamage); - } - - @Override - public boolean isSafe(float damage, float selfDamage, boolean overrideDamage) { - return AutoBed.this.isSafe(damage, selfDamage, overrideDamage); - } - - @Override - public float minDamage() { - return minDamage.get(); - } - - @Override - public float faceplaceHealth() { - return faceplaceHealth.get(); - } - - @Override - public float maxSelfDamage() { - return maxSelfDamage.get(); - } - - @Override - public int predictTicks() { - return predictTicks.get(); - } - - @Override - public int selfPredictTicks() { - return selfPredictTicks.get(); - } - - @Override - public float placeRange() { - return placeRange.get(); - } - } - - private enum Timing { - NORMAL, - SEQUENTIAL - } - - private enum RenderMode { - FADE, - SLIDE, - DEFAULT - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoBow.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoBow.java deleted file mode 100644 index c91e9a5..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoBow.java +++ /dev/null @@ -1,1195 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.client.multiplayer.MultiPlayerGameMode; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.CrossbowItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec2; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.common.impl.TargetFilters; -import dev.loki.lovisual.config.values.BooleanMapValue; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.EventSync; -import dev.loki.lovisual.events.impl.KeybindIsPressedEvent; -import dev.loki.lovisual.events.impl.RotationUpdateEvent; -import dev.loki.lovisual.features.module.HudPhase; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.relations.CategoryRules; -import dev.loki.lovisual.features.relations.CategoryType; -import dev.loki.lovisual.features.relations.EntityFilters; -import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.core.ViewportContext; -import dev.loki.lovisual.render.engine.math.HudScale; -import dev.loki.lovisual.render.engine.renderer.Renderer2D; -import dev.loki.lovisual.render.engine.text.FontInfo; -import dev.loki.lovisual.render.engine.text.Fonts; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.render.helpers.ScreenProjection; -import dev.loki.lovisual.render.helpers.TickDelta; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.aiming.raytrace.RotationRaytrace; -import dev.loki.lovisual.util.projectile.ProjectilePredictionUtil; -import dev.loki.lovisual.util.target.TargetManager; -import dev.loki.lovisual.util.target.TargetingUtil; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; - -//todo Description -@ModuleInfo( - id = "autobow", - displayName = "AutoBow", - category = ModuleCategory.COMBAT -) -public class AutoBow extends Module { - - private static final int COLOR_IDLE = 0x66FFFFFF; - private static final int COLOR_WAIT = 0xFFFFD45A; - private static final int COLOR_LOCK = 0xFF59C9FF; - private static final int COLOR_SHOOT = 0xFF69FF9C; - private static final int TEXT_SHADOW = 0xAA000000; - private static final float RING_SOFTNESS = 1.15f; - private static final float TEXT_SCALE = 1.0f; - private static final float TEXT_OFFSET = 20.0f; - private static final int ROTATION_PRIORITY = 50; - private static final int TRIDENT_THROW_THRESHOLD_TICKS = 10; - private static final int BOW_FULL_PULL_RELEASE_TICKS = 21; - private static final int CROSSBOW_RELEASE_EXTRA_TICKS = 1; - private static final int TRIDENT_RELEASE_EXTRA_TICKS = 1; - private static final float LOCK_RETAIN_MARGIN = 6.0f; - private static final double CLOSE_DIRECT_AIM_RANGE = 6.0; - private static final double TARGET_BOX_INFLATE = 0.08; - private final Minecraft mc = Minecraft.getInstance(); - - private final NumberValue range = num("autobowRange", 48.0, 4.0, 160.0); - private final EnumValue priority = - enumCommon( - "autobowPriority", - "priority", - CommonSettingSchemas.COMBAT_PRIORITY, - TargetingUtil.TargetPriority.DISTANCE, - TargetingUtil.TargetPriority.values() - ); - private final EnumValue mode = - enumMode("autobowMode", AutomationMode.FULL_AUTO, AutomationMode.values()); - private final EnumValue movementCorrection = - enumCommon( - "autobowMovementCorrection", - "movement_correction", - CommonSettingSchemas.ROTATION_MOVEMENT_CORRECTION, - MovementCorrection.SILENT, - MovementCorrection.values() - ); - private final NumberValue rotationResetTicks = - numCommon( - "autobowRotationResetTicks", - "rotation_reset_ticks", - CommonSettingSchemas.ROTATION_RESET_TICKS, - 1, - 1, - 20 - ); - private final NumberValue rotationResetThreshold = - numCommon( - "autobowRotationResetThreshold", - "rotation_reset_threshold", - CommonSettingSchemas.ROTATION_RESET_THRESHOLD, - 2.0f, - 0.1f, - 15.0f - ); - private final NumberValue hudRadius = num("autobowHudRadius", 64.0, 12.0, 240.0); - private final NumberValue hudThickness = num("autobowHudThickness", 2.5, 1.0, 8.0); - private final NumberValue priorityDistanceLeeway = - num("autobowPriorityDistanceLeeway", 6.0, 0.0, 24.0); - private final NumberValue aimThreshold = num("autobowAimThreshold", 1.5f, 0.25f, 6.0f); - private final BooleanValue bowRapidFire = bool("autobowBowRapidFire", false); - private final NumberValue chargedTicks = num("autobowChargedTicks", 15, 3, 20); - private final NumberValue chargedRandom = num("autobowChargedRandom", 0, 0, 10); - private final NumberValue delayBetweenShots = - num("autobowDelayBetweenShots", 0.0, 0.0, 5.0); - private final BooleanMapValue toggles = groupCommon( - "autobow_toggles", - "toggles", - CommonSettingSchemas.TARGET_FILTERS - ); - - private Snapshot lastSnapshot = Snapshot.hidden(); - private long lastShotAtMs; - private boolean forceReleaseUse; - private boolean forceHoldUse; - private Integer currentChargeRandom; - private int snapshotTick = Integer.MIN_VALUE; - private LivingEntity preferredTarget; - private PendingUse pendingUse; - private boolean rotationRequested; - - @Override - public HudPhase getHudPhase() { - return HudPhase.LAST; - } - - @Override - public void onEnable() { - lastShotAtMs = 0L; - lastSnapshot = Snapshot.hidden(); - forceReleaseUse = false; - forceHoldUse = false; - currentChargeRandom = null; - snapshotTick = Integer.MIN_VALUE; - preferredTarget = null; - pendingUse = null; - rotationRequested = false; - } - - @Override - public void onDisable() { - lastSnapshot = Snapshot.hidden(); - forceReleaseUse = false; - forceHoldUse = false; - currentChargeRandom = null; - snapshotTick = Integer.MIN_VALUE; - preferredTarget = null; - pendingUse = null; - releaseRotationIfRequested(); - TargetManager.setModuleTarget(null); - } - - @EventHandler(priority = 100) - private void onKeybindIsPressed(KeybindIsPressedEvent event) { - if (!isEnabled() || mc.options == null) { - return; - } - if (event.getKeyBinding() != mc.options.keyUse) { - return; - } - if (!forceReleaseUse) { - if (forceHoldUse) { - event.setPressed(true); - } - return; - } - - event.setPressed(false); - } - - @Override - public void onTick() { - if (!isEnabled()) return; - - Snapshot snapshot = getSnapshot(TickDelta.get()); - boolean canRotate = canRotateForWeaponState(mc.player, snapshot.weapon()); - boolean inside = snapshot.insideRadius(); - forceHoldUse = shouldHoldUseForFullAuto(snapshot); - TargetManager.setModuleTarget(inside ? snapshot.target() : null); - - if (mode.get() == AutomationMode.FULL_AUTO && inside) { - tryAutoDraw(snapshot); - } - - if (mode.get() != AutomationMode.FULL_AUTO) { - return; - } - - if (!inside || snapshot.state() != HudState.SHOOT) { - return; - } - - tryAutoShoot(snapshot); - } - - public void onInputCycleHandled() { - forceReleaseUse = false; - } - - public boolean shouldCancelVanillaDoItemUse() { - if (!isEnabled() || mc.player == null) { - return false; - } - - if (pendingUse != null) { - return true; - } - - Snapshot snapshot = getSnapshot(TickDelta.get()); - ActiveWeapon weapon = snapshot.weapon(); - return weapon != null - && weapon.type() == WeaponType.CROSSBOW - && snapshot.target() != null - && snapshot.insideRadius(); - } - - @EventHandler(priority = -1000) - private void onSync(EventSync event) { - if (!isEnabled()) { - return; - } - - LocalPlayer player = mc.player; - MultiPlayerGameMode manager = mc.gameMode; - PendingUse use = pendingUse; - if (player == null || manager == null || use == null) { - return; - } - - if (player.tickCount > use.expireAge()) { - pendingUse = null; - return; - } - - ItemStack stack = player.getItemInHand(use.hand()); - if (!canUseStackForAction(player, stack, use.action())) { - pendingUse = null; - return; - } - - Rotation rotation = use.rotation(); - if (rotation == null) { - pendingUse = null; - return; - } - - pendingUse = null; - event.setRotation(rotation.yaw(), rotation.pitch(), true); - - float prevYaw = player.getYRot(); - float prevPitch = player.getXRot(); - player.setYRot(rotation.yaw()); - player.setXRot(rotation.pitch()); - event.addPostAction(() -> { - player.setYRot(prevYaw); - player.setXRot(prevPitch); - }); - - InteractionResult result = manager.useItem(player, use.hand()); - if (result.consumesAction()) { - if (use.action() == UseAction.FIRE_CROSSBOW) { - lastShotAtMs = System.currentTimeMillis(); - } - } - } - - @Override - public void onRenderHudEngine(Renderer2D renderer, TextRenderer textRenderer, GuiGraphicsExtractor ctx, float tickDelta) { - if (!isEnabled() || ctx == null) return; - if (mc.player == null || mc.level == null) return; - if (!mc.options.getCameraType().isFirstPerson()) return; - - Snapshot snapshot = getSnapshot(tickDelta); - if (!snapshot.showHud()) { - return; - } - - int fbw = mc.getWindow().getWidth(); - int fbh = mc.getWindow().getHeight(); - float logicalWidth = HudScale.virtualWidth(fbw, fbh); - float logicalHeight = HudScale.virtualHeight(fbw, fbh); - float centerX = logicalWidth * 0.5f; - float centerY = logicalHeight * 0.5f; - float radiusValue = hudRadius.get().floatValue(); - float thicknessValue = hudThickness.get().floatValue(); - int color = snapshot.state().color; - - ViewportContext.beginUnscaledLogical(ctx); - try { - renderer.circleStroke(centerX, centerY, radiusValue, thicknessValue, RING_SOFTNESS, color); - if (snapshot.state().cross) { - float halfLength = radiusValue * 0.64f; - drawCross(renderer, centerX, centerY, halfLength, Math.max(1.0f, thicknessValue * 0.8f), color); - } - renderStateText(textRenderer, centerX, centerY - radiusValue - TEXT_OFFSET, snapshot.state()); - } finally { - ViewportContext.beginUnscaled(ctx); - } - } - - @EventHandler(priority = 15) - private void onRotationUpdate(RotationUpdateEvent event) { - if (event.getType() != RotationUpdateEvent.Type.PRE) { - return; - } - - if (!isEnabled()) return; - - Snapshot snapshot = getSnapshot(TickDelta.get()); - boolean canRotate = canRotateForWeaponState(mc.player, snapshot.weapon()); - boolean inside = snapshot.insideRadius(); - TargetManager.setModuleTarget(inside ? snapshot.target() : null); - - if (!snapshot.shouldRotate() || !canRotate) { - releaseRotationIfRequested(); - return; - } - - RotationTarget target = new RotationTarget( - snapshot.solution(), - snapshot.target(), - List.of(), - rotationResetTicks.get(), - rotationResetThreshold.get(), - true, - movementCorrection.get(), - null - ); - RotationManager.INSTANCE.setRotationTarget(target, ROTATION_PRIORITY, this); - rotationRequested = true; - } - - private void releaseRotationIfRequested() { - if (!rotationRequested) { - return; - } - - RotationManager.INSTANCE.release(this); - rotationRequested = false; - } - - private Snapshot evaluateSnapshot(float tickDelta) { - LocalPlayer player = mc.player; - if (player == null || mc.level == null) { - return Snapshot.hidden(); - } - - ActiveWeapon weapon = findActiveWeapon(player); - if (weapon == null) { - return Snapshot.hidden(); - } - - int fbw = mc.getWindow().getWidth(); - int fbh = mc.getWindow().getHeight(); - float logicalWidth = HudScale.virtualWidth(fbw, fbh); - float logicalHeight = HudScale.virtualHeight(fbw, fbh); - float baseRadius = hudRadius.get().floatValue(); - TargetingUtil.TargetingSettings settings = buildTargetingSettings(); - if (player.isUsingItem() && preferredTarget != null) { - Snapshot lockedSnapshot = evaluateTargetCandidate( - player, - weapon, - preferredTarget, - logicalWidth, - logicalHeight, - tickDelta, - baseRadius + LOCK_RETAIN_MARGIN, - false - ); - if (lockedSnapshot != null) { - return lockedSnapshot; - } - preferredTarget = null; - return Snapshot.idle(weapon); - } - - if (preferredTarget != null) { - Snapshot stickySnapshot = evaluateTargetCandidate( - player, - weapon, - preferredTarget, - logicalWidth, - logicalHeight, - tickDelta, - baseRadius + LOCK_RETAIN_MARGIN, - true - ); - if (stickySnapshot != null) { - return stickySnapshot; - } - preferredTarget = null; - } - - for (LivingEntity target : getPrioritizedCandidates(settings)) { - Snapshot candidate = evaluateTargetCandidate( - player, - weapon, - target, - logicalWidth, - logicalHeight, - tickDelta, - baseRadius, - true - ); - if (candidate == null) { - continue; - } - - preferredTarget = candidate.target(); - return candidate; - } - - preferredTarget = null; - - if (mode.get() == AutomationMode.FULL_AUTO && player.isUsingItem()) { - return Snapshot.idle(weapon); - } - - return Snapshot.idle(weapon); - } - - private List getPrioritizedCandidates(TargetingUtil.TargetingSettings settings) { - List sortedByPriority = TargetingUtil.findTargets(mc, settings); - if (sortedByPriority.isEmpty() || mc.player == null) { - return sortedByPriority; - } - - TargetingUtil.TargetPriority selectedPriority = settings.priority(); - if (selectedPriority == null || selectedPriority == TargetingUtil.TargetPriority.DISTANCE) { - return sortedByPriority; - } - - TargetingUtil.TargetingSettings distanceSettings = new TargetingUtil.TargetingSettings( - settings.range(), - settings.fov(), - settings.playersOnly(), - settings.ignoreFriends(), - settings.ignoreStaff(), - settings.ignoreEnemies(), - settings.ignoreNaked(), - settings.ignoreEntities(), - settings.visibleOnly(), - TargetingUtil.TargetPriority.DISTANCE - ); - - List byDistance = TargetingUtil.findTargets(mc, distanceSettings); - if (byDistance.isEmpty()) { - return sortedByPriority; - } - - LivingEntity distanceAnchor = byDistance.get(0); - if (!settings.playersOnly()) { - for (LivingEntity candidate : byDistance) { - if (candidate instanceof Player) { - distanceAnchor = candidate; - break; - } - } - } - - double nearestDistance = Math.sqrt(TargetingUtil.distanceToEntityBoxSq(mc.player.getEyePosition(), distanceAnchor)); - double maxAllowedDistance = nearestDistance + priorityDistanceLeeway.get(); - - List closePool = new ArrayList<>(); - for (LivingEntity target : sortedByPriority) { - double distance = Math.sqrt(TargetingUtil.distanceToEntityBoxSq(mc.player.getEyePosition(), target)); - if (distance <= maxAllowedDistance) { - closePool.add(target); - } - } - - return closePool.isEmpty() ? sortedByPriority : closePool; - } - - private Snapshot refreshSnapshot(float tickDelta) { - if (mc.player == null) { - snapshotTick = Integer.MIN_VALUE; - return lastSnapshot = Snapshot.hidden(); - } - - snapshotTick = mc.player.tickCount; - lastSnapshot = evaluateSnapshot(tickDelta); - return lastSnapshot; - } - - private Snapshot getSnapshot(float tickDelta) { - if (mc.player == null) { - snapshotTick = Integer.MIN_VALUE; - return Snapshot.hidden(); - } - - if (snapshotTick != mc.player.tickCount) { - return refreshSnapshot(tickDelta); - } - return lastSnapshot; - } - - private Snapshot evaluateTargetCandidate(LocalPlayer player, - ActiveWeapon weapon, - LivingEntity target, - float logicalWidth, - float logicalHeight, - float tickDelta, - float radius, - boolean requireReachableTrajectory) { - if (target == null || !target.isAlive() || target.isRemoved()) { - return null; - } - - Vec2 point = projectTargetToLogical(target, logicalWidth, logicalHeight, tickDelta); - if (!isInsideCircle(point, logicalWidth, logicalHeight, radius)) { - return null; - } - - boolean directlyVisible = hasDirectSightToTarget(player, target); - if (toggles.get(TargetFilters.VISIBLE_ONLY) && !directlyVisible) { - return null; - } - - Rotation solution = ProjectilePredictionUtil.calculateForItem( - player, - weapon.stack(), - target, - shouldUseFullPowerAim(weapon) - ); - if (solution == null && directlyVisible - && TargetingUtil.distanceToEntityBoxSq(player.getEyePosition(), target) - <= CLOSE_DIRECT_AIM_RANGE * CLOSE_DIRECT_AIM_RANGE) { - var direct = RotationRaytrace.raytraceBox( - player.getEyePosition(), - target.getBoundingBox().inflate(TARGET_BOX_INFLATE), - CLOSE_DIRECT_AIM_RANGE, - 0.0 - ); - solution = direct != null ? direct.rotation() : null; - } - if (solution == null) { - return null; - } - - Rotation normalized = solution.normalize(); - boolean trajectoryReady = ProjectilePredictionUtil.getHypotheticalHit( - player, - weapon.stack(), - normalized, - living -> living == target, - shouldUseFullPowerAim(weapon) - ) == target; - if (requireReachableTrajectory && !trajectoryReady && !directlyVisible) { - return null; - } - - boolean chargeReady = isChargeReady(player, weapon); - boolean aimReady = RotationManager.INSTANCE.getServerRotation().approximatelyEquals(normalized, aimThreshold.get()); - boolean shootReady = mode.get() == AutomationMode.FULL_AUTO - && chargeReady - && aimReady - && (trajectoryReady || directlyVisible) - && canAutoShoot(player, weapon, target); - HudState state; - if (shootReady) { - state = HudState.SHOOT; - } else if (!chargeReady) { - state = HudState.WAIT; - } else if (mode.get() == AutomationMode.AIM_ONLY) { - state = HudState.SHOOT; - } else { - state = HudState.LOCK; - } - return Snapshot.withState(weapon, target, normalized, point, true, chargeReady, aimReady, state); - } - - private TargetingUtil.TargetingSettings buildTargetingSettings() { - return new TargetingUtil.TargetingSettings( - range.get(), - 180.0f, - toggles.get(TargetFilters.PLAYERS_ONLY), - toggles.get(TargetFilters.IGNORE_FRIENDS), - toggles.get(TargetFilters.IGNORE_STAFF), - toggles.get(TargetFilters.IGNORE_ENEMIES), - toggles.get(TargetFilters.IGNORE_NAKED), - toggles.get(TargetFilters.IGNORE_ENTITIES), - false, - priority.get() - ); - } - - private ActiveWeapon findActiveWeapon(LocalPlayer player) { - if (player.isUsingItem()) { - InteractionHand activeHand = player.getUsedItemHand(); - ItemStack activeStack = player.getUseItem(); - if (activeStack.is(Items.BOW)) { - return new ActiveWeapon(activeHand, activeStack, WeaponType.BOW); - } - if (activeStack.is(Items.CROSSBOW)) { - return new ActiveWeapon(activeHand, activeStack, WeaponType.CROSSBOW); - } - if (activeStack.is(Items.TRIDENT)) { - return new ActiveWeapon(activeHand, activeStack, WeaponType.TRIDENT); - } - } - - for (InteractionHand hand : InteractionHand.values()) { - ItemStack stack = player.getItemInHand(hand); - if (stack.isEmpty()) { - continue; - } - if (stack.is(Items.CROSSBOW) && CrossbowItem.isCharged(stack)) { - return new ActiveWeapon(hand, stack, WeaponType.CROSSBOW); - } - if (stack.is(Items.BOW)) { - return new ActiveWeapon(hand, stack, WeaponType.BOW); - } - if (stack.is(Items.CROSSBOW)) { - return new ActiveWeapon(hand, stack, WeaponType.CROSSBOW); - } - if (stack.is(Items.TRIDENT)) { - return new ActiveWeapon(hand, stack, WeaponType.TRIDENT); - } - } - - return null; - } - - private boolean shouldAlwaysShowBow(LocalPlayer player, ActiveWeapon weapon) { - return weapon.type() == WeaponType.BOW - && (!player.isUsingItem() || player.getUsedItemHand() != weapon.hand()); - } - - private boolean canRotateForWeaponState(LocalPlayer player, ActiveWeapon weapon) { - if (player == null || weapon == null) { - return false; - } - - return switch (weapon.type()) { - case BOW, TRIDENT -> player.isUsingItem() && player.getUsedItemHand() == weapon.hand(); - case CROSSBOW -> isCrossbowReadyForRotation(player, weapon); - }; - } - - private boolean isCrossbowReadyForRotation(LocalPlayer player, ActiveWeapon weapon) { - if (CrossbowItem.isCharged(weapon.stack())) { - return true; - } - - // Crossbow should keep tracking throughout the whole charge window, - // otherwise it feels inconsistent compared to bow and may never settle in time. - return player.isUsingItem() && player.getUsedItemHand() == weapon.hand(); - } - - private boolean shouldHoldUseForFullAuto(Snapshot snapshot) { - if (mode.get() != AutomationMode.FULL_AUTO || snapshot == null) { - return false; - } - - if (!snapshot.insideRadius() || snapshot.target() == null) { - return false; - } - - ActiveWeapon weapon = snapshot.weapon(); - if (weapon == null) { - return false; - } - - return switch (weapon.type()) { - case BOW, TRIDENT -> false; - case CROSSBOW -> !CrossbowItem.isCharged(weapon.stack()); - }; - } - - private boolean shouldUseFullPowerAim(ActiveWeapon weapon) { - return weapon != null && weapon.type() == WeaponType.BOW; - } - - private boolean isChargeReady(LocalPlayer player, ActiveWeapon weapon) { - return switch (weapon.type()) { - case BOW -> isBowChargeReady(player, weapon); - case CROSSBOW -> CrossbowItem.isCharged(weapon.stack()) - || (player.isUsingItem() - && player.getUsedItemHand() == weapon.hand() - && player.getTicksUsingItem() >= CrossbowItem.getChargeDuration(weapon.stack(), player) + CROSSBOW_RELEASE_EXTRA_TICKS); - case TRIDENT -> player.isUsingItem() - && player.getUsedItemHand() == weapon.hand() - && player.getTicksUsingItem() > TRIDENT_THROW_THRESHOLD_TICKS + TRIDENT_RELEASE_EXTRA_TICKS; - }; - } - - private int getBowChargeThreshold() { - return chargedTicks.get() + getChargedRandom(); - } - - private boolean isBowChargeReady(LocalPlayer player, ActiveWeapon weapon) { - if (!player.isUsingItem() || player.getUsedItemHand() != weapon.hand()) { - return false; - } - - if (bowRapidFire.get()) { - return player.getTicksUsingItem() > getBowChargeThreshold(); - } - - return player.getTicksUsingItem() >= BOW_FULL_PULL_RELEASE_TICKS; - } - - private int getChargedRandom() { - if (currentChargeRandom == null) { - updateChargeRandom(); - } - return currentChargeRandom; - } - - private void updateChargeRandom() { - int random = chargedRandom.get(); - if (random <= 0) { - currentChargeRandom = 0; - return; - } - - int offset = (int) Math.round(ThreadLocalRandom.current().nextGaussian() * (random / 2.0)); - currentChargeRandom = Mth.clamp(offset, -random, random); - } - - private Vec2 projectTargetToLogical(LivingEntity target, float logicalWidth, float logicalHeight, float tickDelta) { - if (target == null || mc.gameRenderer == null || mc.player == null) { - return null; - } - - AABB box = target.getBoundingBox().inflate(TARGET_BOX_INFLATE); - float centerX = logicalWidth * 0.5f; - float centerY = logicalHeight * 0.5f; - - Vec3 eye = mc.gameRenderer.mainCamera().position(); - Vec3 look = mc.player.getViewVector(tickDelta).normalize(); - if (box.contains(eye) - || box.clip(eye, eye.add(look.scale(range.get()))).isPresent()) { - return new Vec2(centerX, centerY); - } - - double[] xs = {box.minX, box.maxX}; - double[] ys = {box.minY, box.maxY}; - double[] zs = {box.minZ, box.maxZ}; - - float minX = Float.POSITIVE_INFINITY; - float minY = Float.POSITIVE_INFINITY; - float maxX = Float.NEGATIVE_INFINITY; - float maxY = Float.NEGATIVE_INFINITY; - int projectedCount = 0; - - for (double x : xs) { - for (double y : ys) { - for (double z : zs) { - Vec2 projected = projectWorldToLogical( - new Vec3(x, y, z), - logicalWidth, - logicalHeight, - tickDelta - ); - if (projected == null) { - continue; - } - - minX = Math.min(minX, projected.x); - minY = Math.min(minY, projected.y); - maxX = Math.max(maxX, projected.x); - maxY = Math.max(maxY, projected.y); - projectedCount++; - } - } - } - - Vec2 projectedCenter = projectWorldToLogical(box.getCenter(), logicalWidth, logicalHeight, tickDelta); - if (projectedCenter != null) { - minX = Math.min(minX, projectedCenter.x); - minY = Math.min(minY, projectedCenter.y); - maxX = Math.max(maxX, projectedCenter.x); - maxY = Math.max(maxY, projectedCenter.y); - projectedCount++; - } - - if (projectedCount == 0) { - return null; - } - - return new Vec2( - Mth.clamp(centerX, minX, maxX), - Mth.clamp(centerY, minY, maxY) - ); - } - - private Vec2 projectWorldToLogical(Vec3 worldPos, float logicalWidth, float logicalHeight, float tickDelta) { - int framebufferWidth = mc.getWindow().getWidth(); - int framebufferHeight = mc.getWindow().getHeight(); - if (framebufferWidth <= 0 || framebufferHeight <= 0) { - return null; - } - - Vec3 screen = ScreenProjection.worldToScreen(worldPos, tickDelta); - if (screen == null) { - return null; - } - - float x = (float) (screen.x / framebufferWidth * logicalWidth); - float y = (float) (screen.y / framebufferHeight * logicalHeight); - return new Vec2(x, y); - } - - private Vec2 projectRotationToLogical(LocalPlayer player, Rotation solution, float logicalWidth, float logicalHeight, float tickDelta) { - if (player == null || mc.gameRenderer == null) { - return null; - } - int framebufferWidth = mc.getWindow().getWidth(); - int framebufferHeight = mc.getWindow().getHeight(); - if (framebufferWidth <= 0 || framebufferHeight <= 0) { - return null; - } - - Vec3 origin = mc.gameRenderer.mainCamera().position(); - Vec3 probe = origin.add(solution.directionVector().normalize().scale(96.0)); - Vec3 screen = ScreenProjection.worldToScreen(probe, tickDelta); - if (screen == null) { - return null; - } - - float x = (float) (screen.x / framebufferWidth * logicalWidth); - float y = (float) (screen.y / framebufferHeight * logicalHeight); - return new Vec2(x, y); - } - - private boolean isInsideCircle(Vec2 point, float logicalWidth, float logicalHeight) { - return isInsideCircle(point, logicalWidth, logicalHeight, hudRadius.get().floatValue()); - } - - private boolean isInsideCircle(Vec2 point, float logicalWidth, float logicalHeight, float radiusValue) { - if (point == null) { - return false; - } - - float centerX = logicalWidth * 0.5f; - float centerY = logicalHeight * 0.5f; - float dx = point.x - centerX; - float dy = point.y - centerY; - return dx * dx + dy * dy <= radiusValue * radiusValue; - } - - private void renderStateText(TextRenderer textRenderer, float centerX, float y, HudState state) { - if (state.label.isEmpty()) { - return; - } - - TextRenderer renderer = Fonts.renderer("OnestMedium", FontInfo.Type.Regular, textRenderer); - float width = (float) renderer.getWidth(state.label, false) * TEXT_SCALE; - float height = (float) renderer.getHeight(false) * TEXT_SCALE; - float x = centerX - width * 0.5f; - float baseY = y - height * 0.5f; - - renderer.begin(TEXT_SCALE); - renderer.render(state.label, x + 1.0f, baseY + 1.0f, new RenderColor(TEXT_SHADOW), false); - renderer.render(state.label, x, baseY, new RenderColor(state.color), false); - renderer.end(); - } - - private void drawCross(Renderer2D renderer, float centerX, float centerY, float halfLength, float thickness, int color) { - drawThickLine(renderer, centerX - halfLength, centerY - halfLength, centerX + halfLength, centerY + halfLength, thickness, color); - drawThickLine(renderer, centerX - halfLength, centerY + halfLength, centerX + halfLength, centerY - halfLength, thickness, color); - } - - private void drawThickLine(Renderer2D renderer, float x1, float y1, float x2, float y2, float thickness, int color) { - float dx = x2 - x1; - float dy = y2 - y1; - float length = Mth.sqrt(dx * dx + dy * dy); - if (length <= 0.0f) { - return; - } - - float nx = -dy / length; - float ny = dx / length; - int layers = Math.max(1, Math.round(thickness)); - float start = -(layers - 1) * 0.5f; - for (int i = 0; i < layers; i++) { - float offset = start + i; - float ox = nx * offset; - float oy = ny * offset; - renderer.line(x1 + ox, y1 + oy, x2 + ox, y2 + oy, color); - } - } - - private void tryAutoShoot(Snapshot snapshot) { - LocalPlayer player = mc.player; - MultiPlayerGameMode manager = mc.gameMode; - if (player == null || manager == null) { - return; - } - - ActiveWeapon weapon = snapshot.weapon(); - if (weapon == null) { - return; - } - - long now = System.currentTimeMillis(); - long delayMs = (long) (delayBetweenShots.get() * 1000.0); - if (!canAutoShoot(player, weapon, snapshot.target())) { - return; - } - - switch (weapon.type()) { - case BOW, TRIDENT -> { - if (now - lastShotAtMs < delayMs) { - return; - } - if (player.isUsingItem() && player.getUsedItemHand() == weapon.hand()) { - forceReleaseUse = true; - if (weapon.type() == WeaponType.BOW) { - updateChargeRandom(); - } - lastShotAtMs = now; - } - } - case CROSSBOW -> { - if (player.isUsingItem() && player.getUsedItemHand() == weapon.hand()) { - if (player.getTicksUsingItem() >= CrossbowItem.getChargeDuration(weapon.stack(), player)) { - forceReleaseUse = true; - } - return; - } - if (now - lastShotAtMs < delayMs) { - return; - } - if (CrossbowItem.isCharged(weapon.stack())) { - Rotation shotRotation = snapshot.solution(); - if (shotRotation != null && pendingUse == null) { - pendingUse = new PendingUse( - weapon.hand(), - shotRotation, - player.tickCount + 1, - UseAction.FIRE_CROSSBOW - ); - } - } - } - } - } - - private void tryAutoDraw(Snapshot snapshot) { - LocalPlayer player = mc.player; - if (player == null || mc.gameMode == null) { - return; - } - - ActiveWeapon weapon = snapshot.weapon(); - if (weapon == null) { - return; - } - - if (player.isUsingItem()) { - return; - } - - if (snapshot.target() == null || !snapshot.insideRadius()) { - return; - } - - switch (weapon.type()) { - case BOW, TRIDENT -> { - } - case CROSSBOW -> { - if (!CrossbowItem.isCharged(weapon.stack()) && pendingUse == null) { - pendingUse = new PendingUse( - weapon.hand(), - snapshot.solution(), - player.tickCount + 1, - UseAction.CHARGE_CROSSBOW - ); - } - } - } - } - - private boolean canUseStackForAction(LocalPlayer player, ItemStack stack, UseAction action) { - if (stack == null || stack.isEmpty()) { - return false; - } - - return switch (action) { - case CHARGE_CROSSBOW -> !player.isUsingItem() - && stack.is(Items.CROSSBOW) - && !CrossbowItem.isCharged(stack); - case FIRE_CROSSBOW -> stack.is(Items.CROSSBOW) && CrossbowItem.isCharged(stack); - }; - } - - private boolean canAutoShoot(LocalPlayer player, ActiveWeapon weapon, LivingEntity target) { - if (player == null || weapon == null || target == null) { - return false; - } - - long now = System.currentTimeMillis(); - long delayMs = (long) (delayBetweenShots.get() * 1000.0); - if (weapon.type() != WeaponType.CROSSBOW && now - lastShotAtMs < delayMs) { - return false; - } - - Rotation serverRotation = RotationManager.INSTANCE.getServerRotation(); - if (serverRotation == null) { - return false; - } - - LivingEntity hypotheticalHit = ProjectilePredictionUtil.getHypotheticalHit( - player, - weapon.stack(), - serverRotation, - this::matchesHypotheticalTarget - ); - if (hypotheticalHit == null && !hasDirectSightToTarget(player, target)) { - return false; - } - - return weapon.type() != WeaponType.CROSSBOW || player.isUsingItem() || now - lastShotAtMs >= delayMs; - } - - private boolean hasDirectSightToTarget(LocalPlayer player, LivingEntity target) { - if (player == null || target == null) { - return false; - } - - return RotationRaytrace.canSeeBox( - player.getEyePosition(), - target.getBoundingBox(), - range.get(), - 0.0 - ); - } - - private boolean matchesHypotheticalTarget(LivingEntity living) { - if (living == null || mc.player == null || mc.level == null) { - return false; - } - if (!living.isAlive() || living.isRemoved()) { - return false; - } - if (toggles.get(TargetFilters.PLAYERS_ONLY) && !(living instanceof net.minecraft.world.entity.player.Player)) { - return false; - } - if (toggles.get(TargetFilters.VISIBLE_ONLY) && !mc.player.hasLineOfSight(living)) { - return false; - } - if (TargetingUtil.distanceToEntityBoxSq(mc.player.getEyePosition(), living) > range.get() * range.get()) { - return false; - } - if (toggles.get(TargetFilters.IGNORE_ENTITIES) && !(living instanceof net.minecraft.world.entity.player.Player)) { - var id = BuiltInRegistries.ENTITY_TYPE.getKey(living.getType()); - if (id != null && EntityFilters.get().isIgnoredEntity(id.toString())) { - return false; - } - } - - if (living instanceof net.minecraft.world.entity.player.Player player) { - CategoryType type = CategoryRules.determine(player.getGameProfile().name()); - if (type == CategoryType.BEDWARS_SELF) { - return false; - } - if (toggles.get(TargetFilters.IGNORE_FRIENDS) && type == CategoryType.FRIEND) { - return false; - } - if (toggles.get(TargetFilters.IGNORE_STAFF) && type == CategoryType.STAFF) { - return false; - } - if (toggles.get(TargetFilters.IGNORE_ENEMIES) && (type == CategoryType.ENEMY || type == CategoryType.BEDWARS_ENEMY)) { - return false; - } - return !toggles.get(TargetFilters.IGNORE_NAKED) || !TargetingUtil.isNaked(player); - } - - return true; - } - - private enum WeaponType { - BOW, - CROSSBOW, - TRIDENT - } - - private enum AutomationMode implements EnumValue.IdProvider { - FULL_AUTO("full_auto"), - AIM_ONLY("aim_only"); - - private final String id; - - AutomationMode(String id) { - this.id = id; - } - - @Override - public String id() { - return id; - } - } - - private enum HudState { - IDLE("", COLOR_IDLE, false), - WAIT("WAIT", COLOR_WAIT, false), - LOCK("LOCK", COLOR_LOCK, false), - SHOOT("SHOOT", COLOR_SHOOT, false); - - private final String label; - private final int color; - private final boolean cross; - - HudState(String label, int color, boolean cross) { - this.label = label; - this.color = color; - this.cross = cross; - } - } - - private enum UseAction { - CHARGE_CROSSBOW, - FIRE_CROSSBOW - } - - private record ActiveWeapon(InteractionHand hand, ItemStack stack, WeaponType type) { - } - - private record PendingUse(InteractionHand hand, Rotation rotation, int expireAge, UseAction action) { - } - - private record Snapshot( - boolean showHud, - ActiveWeapon weapon, - LivingEntity target, - Rotation solution, - Vec2 logicalPoint, - boolean insideRadius, - boolean chargeReady, - boolean aimReady, - HudState state - ) { - private static Snapshot hidden() { - return new Snapshot(false, null, null, null, null, false, false, false, HudState.IDLE); - } - - private static Snapshot idle(ActiveWeapon weapon) { - return new Snapshot(true, weapon, null, null, null, false, false, false, HudState.IDLE); - } - - private static Snapshot waiting(ActiveWeapon weapon) { - return new Snapshot(true, weapon, null, null, null, false, false, false, HudState.WAIT); - } - - private static Snapshot withState(ActiveWeapon weapon, - LivingEntity target, - Rotation solution, - Vec2 logicalPoint, - boolean insideRadius, - boolean chargeReady, - boolean aimReady, - HudState state) { - return new Snapshot(true, weapon, target, solution, logicalPoint, insideRadius, chargeReady, aimReady, state); - } - - private boolean shouldRotate() { - return weapon != null && target != null && solution != null && insideRadius; - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoCrystal.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoCrystal.java deleted file mode 100644 index 6abc0a3..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/AutoCrystal.java +++ /dev/null @@ -1,1516 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.features.module.modules.combat.autocrystal.*; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.boss.enderdragon.EndCrystal; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.common.impl.TargetFilters; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.PacketEvent; -import dev.loki.lovisual.events.impl.RotationUpdateEvent; -import dev.loki.lovisual.features.gui.clickgui.settings.FunctionBindSetting; -import dev.loki.lovisual.features.module.Notifier; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.WorldPhase; -import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.renderer.Renderer3D; -import dev.loki.lovisual.render.engine.text.FontInfo; -import dev.loki.lovisual.render.engine.text.Fonts; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.render.engine.text.WorldTextRenderer; -import dev.loki.lovisual.util.aiming.RestrictedSingleUseAction; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.data.RotationWithVector; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.aiming.raytrace.RotationRaytrace; -import dev.loki.lovisual.util.combat.CombatRotationModeUtil; -import dev.loki.lovisual.util.entity.simulation.PositionExtrapolation; -import dev.loki.lovisual.util.player.inventory.InventorySwap; -import dev.loki.lovisual.util.player.simulation.PlayerSimulationCache; -import dev.loki.lovisual.util.target.TargetManager; -import dev.loki.lovisual.util.target.TargetingUtil; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -//todo Description -@ModuleInfo( - id = "autocrystal", - displayName = "AutoCrystal", - aliases = "CrystalAura", - category = ModuleCategory.COMBAT -) -public class AutoCrystal extends Module { - - private static final int ROTATION_PRIORITY = 35; - private static final int HOTBAR_RESET_TICKS = 2; - private static final String ACTION_BASE = "base"; - - private static final double INTERACT_MARKER_RADIUS = 0.05; - private static final long DAMAGE_RESET_MS = 1000L; - private static final int BASE_HOTBAR_RESET_TICKS = 2; - private static final float BASE_INITIATIVE_MIN_DAMAGE = 1.5f; - private static final double TEXT_Y_OFFSET = 0.10; - private static final double TEXT_WORLD_SCALE = 0.025; - private static final double TEXT_SCALE = 1.0; - private static final double TEXT_GAP_SCALE = 1.0; - private static final double TARGET_SEARCH_RANGE = 12.0; - - private final Minecraft mc = Minecraft.getInstance(); - - private final BooleanValue renderEnabled = - boolCommon( - "autocrystalRender", - "render", - CommonSettingSchemas.PLACEMENT_RENDER, - true - ); - private final EnumValue renderMode = - enumCommon( - "autocrystalRenderMode", - "render_mode", - CommonSettingSchemas.PLACEMENT_RENDER_MODE, - RenderMode.FADE, - RenderMode.values() - ); - private final BooleanValue renderSelfDamage = boolCommon("autocrystalRenderSelfDamage", CommonSettingSchemas.RENDER_SELF_DAMAGE, true); - private final BooleanValue drawDamage = boolCommon("autocrystalRenderDamage", CommonSettingSchemas.RENDER_DAMAGE, true); - private final BooleanValue placeEnabled = boolCommon("autocrystalPlace", CommonSettingSchemas.PLACE, true); - private final NumberValue placeDelay = - visibleWhen(numCommon( - "autocrystalPlaceDelay", - "place_delay", - CommonSettingSchemas.PLACEMENT_DELAY, - 0, - 0, - 1000 - ), placeEnabled::get); - private final BooleanValue breakEnabled = boolCommon("autocrystalBreak", CommonSettingSchemas.BREAK, true); - private final NumberValue breakDelay = - visibleWhen(numCommon( - "autocrystalBreakDelay", - "break_delay", - CommonSettingSchemas.PLACEMENT_BREAK_DELAY, - 0, - 0, - 1000 - ), breakEnabled::get); - private final NumberValue placeRange = - numCommon( - "autocrystalPlaceRange", - "place_range", - CommonSettingSchemas.PLACEMENT_RANGE, - 5.0f, - 1.0f, - 6.0f - ); - private final EnumValue placementMode = - visibleWhen(enumCommon( - "autocrystalPlacementMode", - "placement_mode", - CommonSettingSchemas.PLACEMENT_MODE, - AutoCrystalPlacementMode.DEFAULT, - AutoCrystalPlacementMode.values() - ), placeEnabled::get); - private final NumberValue wallRange = - visibleWhen(numCommon( - "autocrystalWallRange", - "wall_range", - CommonSettingSchemas.PLACEMENT_WALL_RANGE, - 5.0f, - 0.0f, - 6.0f - ), () -> placeEnabled.get() && placementMode.get() == AutoCrystalPlacementMode.DEFAULT); - private final NumberValue breakRange = - numCommon( - "autocrystalBreakRange", - "break_range", - CommonSettingSchemas.PLACEMENT_BREAK_RANGE, - 5.0f, - 1.0f, - 6.0f - ); - private final NumberValue breakWallRange = - numCommon( - "autocrystalBreakWallRange", - "break_wall_range", - CommonSettingSchemas.PLACEMENT_BREAK_WALL_RANGE, - 5.0f, - 0.0f, - 6.0f - ); - private final BooleanMapValue targetToggles = groupCommon( - "autocrystalTargets", - "targets", - CommonSettingSchemas.TARGET_FILTERS - ); - private final EnumValue priority = - enumCommon( - "autocrystalPriority", - "priority", - CommonSettingSchemas.COMBAT_PRIORITY, - TargetingUtil.TargetPriority.DISTANCE, - TargetingUtil.TargetPriority.values() - ); - private final NumberValue minDamage = - numCommon("autocrystalMinDamage", CommonSettingSchemas.MIN_DAMAGE, 4.0f, 0.0f, 36.0f); - private final NumberValue faceplaceHealth = - numCommon("autocrystalFaceplaceHealth", CommonSettingSchemas.FACEPLACE_HEALTH, 10.0f, 0.0f, 36.0f); - private final NumberValue maxSelfDamage = - numCommon("autocrystalMaxSelfDamage", CommonSettingSchemas.MAX_SELF_DAMAGE, 8.0f, 0.0f, 36.0f); - private final NumberValue confirmTime = - visibleWhen(num("autocrystalConfirmTime", 150, 10, 2000), placeEnabled::get); - private final NumberValue predictTicks = - numCommon("autocrystalPredictTicks", CommonSettingSchemas.PLACEMENT_PREDICTION, 0, 0, 20); - private final NumberValue selfPredictTicks = - numCommon("autocrystalSelfPredictTicks", CommonSettingSchemas.SELF_PREDICT_TICKS, 0, 0, 20); - private final BooleanValue ignoreTerrain = - bool("autocrystalIgnoreTerrain", true); - private final ModeValue attackMode = - modeCommon( - "autocrystalAttackMode", - "attack_mode", - CommonSettingSchemas.COMBAT_ATTACK_MODE, - CombatRotationModeUtil.MODE_ROTATIONS, - CombatRotationModeUtil.MODE_ROTATIONS, - CombatRotationModeUtil.MODE_NO_ROTATIONS - ); - private final EnumValue movementCorrection = - visibleWhen(enumCommon( - "autocrystalMovementCorrection", - "movement_correction", - CommonSettingSchemas.PLACEMENT_MOVEMENT_CORRECTION, - MovementCorrection.SILENT, - MovementCorrection.values() - ), () -> placeEnabled.get() && usesRotationSettings()); - private final NumberValue rotationResetTicks = - visibleWhen(numCommon( - "autocrystalRotationResetTicks", - "rotation_reset_ticks", - CommonSettingSchemas.ROTATION_RESET_TICKS, - 1, - 1, - 20 - ), () -> placeEnabled.get() && usesRotationSettings()); - private final NumberValue rotationResetThreshold = - visibleWhen(numCommon( - "autocrystalRotationResetThreshold", - "rotation_reset_threshold", - CommonSettingSchemas.ROTATION_RESET_THRESHOLD, - 2.0f, - 0.1f, - 15.0f - ), () -> placeEnabled.get() && usesRotationSettings()); - private final RGBAColorValue fillColor = - common(color("autocrystalFillColor", "#285A9CFF"), CommonSettingSchemas.FILL_COLOR); - private final RGBAColorValue lineColor = - common(color("autocrystalLineColor", "#FF9BE4FF"), CommonSettingSchemas.LINE_COLOR); - private final NumberValue lineWidth = - numCommon("autocrystalLineWidth", CommonSettingSchemas.LINE_WIDTH, 2.0f, 1.0f, 6.0f); - private final RGBAColorValue textColor = - common(color("autocrystalTextColor", "#FFFFFFFF"), CommonSettingSchemas.TEXT_COLOR); - private final NumberValue slideDelay = - visibleWhen(numCommon("autocrystalSlideDelay", CommonSettingSchemas.SLIDE_DELAY, 200, 1, 1000), - () -> renderMode.get() == RenderMode.SLIDE); - private final NumberValue fadeTime = - visibleWhen(numCommon("autocrystalFadeTime", CommonSettingSchemas.FADE_TIME, 500, 100, 2000), - () -> renderMode.get() == RenderMode.FADE); - private final BooleanValue extrapolationEnabled = - bool("autocrystalRenderExtrapolation", false); - private final RGBAColorValue extrapolationColor = - visibleWhen(color("autocrystalExtrapolationColor", "#FFFFFFFF"), extrapolationEnabled::get); - private final NumberValue extrapolationTicks = - visibleWhen(num("autocrystalExtrapolationTicks", 1.0f, 0.0f, 20.0f), - extrapolationEnabled::get); - private final BooleanValue interactEnabled = - bool("autocrystalRenderInteractVector", true); - private final RGBAColorValue interactColor = - visibleWhen(color("autocrystalInteractColor", "#FFFF5555"), interactEnabled::get); - private final FunctionBindSetting baseToggle = - action(ACTION_BASE, "NONE", BindMode.PRESS) - .hudLabel("AutoCrystalBase") - .hudToggle(this::isBaseActive); - private final NumberValue baseMinDamageDelta = - numCommon("autocrystalBaseMinDamageDelta", "base_min_damage_delta", CommonSettingSchemas.MIN_DAMAGE, 5.0f, 0.0f, 20.0f); - private final NumberValue basePlaceDelay = - numCommon("autocrystalBasePlaceDelay", "base_place_delay", CommonSettingSchemas.PLACEMENT_DELAY, 0, 0, 3000); - private final NumberValue baseCalcDelay = - numCommon("autocrystalBaseCalcDelay", "base_calc_delay", CommonSettingSchemas.CALC_DELAY, 50, 0, 3000); - private final BooleanValue baseNotify = - bool("autocrystalBaseNotify", "base_notify", true); - private final BooleanValue baseDisableNoObby = - bool("autocrystalBaseDisableNoObby", "base_disable_no_obby", false); - - private final AutoCrystalBasePlanner basePlanner = new AutoCrystalBasePlanner(); - private final AutoCrystalBaseContext baseContext = new AutoCrystalBaseContext(); - private final AutoCrystalPlacementPlanner placementPlanner = new AutoCrystalPlacementPlanner(); - private final AutoCrystalPlacementPlanner.Context placementContext = new AutoCrystalPlacementContext(); - private final Map renderPositions = new ConcurrentHashMap<>(); - private final AutoCrystalTracker crystalTracker = new AutoCrystalTracker(); - private final AutoCrystalEntityBlocker entityBlocker = new AutoCrystalEntityBlocker(); - - private LivingEntity target; - private AutoCrystalPlaceData bestCandidate; - private AutoCrystalCrystalData bestCrystal; - private EndCrystal secondaryCrystal; - private AutoCrystalPlaceData currentData; - private AutoCrystalBasePlanner.BaseData bestBaseCandidate; - private BlockPos renderPos; - private BlockPos prevRenderPos; - private BlockPos bestPosition; - private Vec3 interactVector; - private int renderTick; - private int renderStartTick; - private long lastDamageUpdateMs; - private long lastPlaceMs; - private long lastBreakMs; - private long lastBaseCalcMs; - private long lastBasePlaceMs; - private float renderDamage; - private float renderSelfDamageValue; - private boolean baseActive; - private long lastDebugStateLogMs; - private int lastPlaceCandidateCount; - private int lastPlaceSafeCount; - private int lastBreakCandidateCount; - private int lastBreakSafeCount; - private int lastPlaceSelfDamageRejectCount; - private int lastBreakSelfDamageRejectCount; - private int lastBaseCandidateCount; - private int lastBaseScannedCount; - private int lastBaseSafeCount; - private int lastBaseWorthCount; - private int lastBaseDeltaCount; - - private static void debugLog(String pattern, Object... args) { - // if (!DebugLog.isEnabled()) { - // return; - // } - // DebugLog.info("[AutoCrystalDebug] " + pattern, args); - } - - @Override - public WorldPhase getWorldPhase() { - return WorldPhase.AFTER_POST_PROCESS; - } - - @Override - public void onEnable() { - resetVisualState(); - } - - @Override - public void onDisable() { - resetVisualState(); - RotationManager.INSTANCE.clear(this); - InventorySwap.INSTANCE.releaseHotbar(this); - TargetManager.setAutoCrystalTarget(null); - } - - @Override - public void onTick() { - if (!isEnabled()) return; - renderTick++; - if (isActionPressedOnce(ACTION_BASE)) { - baseActive = !baseActive; - bestBaseCandidate = null; - Notifier.state("AutoCrystalBase", baseActive); - } - InventorySwap.INSTANCE.tick(); - if (isBaseActive() && baseDisableNoObby.get() && mc.player != null && findObsidianHand(mc.player) == null) { - Notifier.warning("AutoCrystalBase: no obsidian"); - baseActive = false; - bestBaseCandidate = null; - return; - } - crystalTracker.tick(mc); - purgeExpiredRenderPositions(); - if (System.currentTimeMillis() - lastDamageUpdateMs > DAMAGE_RESET_MS && renderPositions.isEmpty()) { - renderDamage = 0.0f; - renderSelfDamageValue = 0.0f; - } - } - - @EventHandler - private void onPacketReceivePost(PacketEvent.ReceivePost event) { - if (!isEnabled() || mc.level == null) { - return; - } - - if (event.getPacket() instanceof ClientboundAddEntityPacket spawn) { - if (spawn.getType() != net.minecraft.world.entity.EntityTypes.END_CRYSTAL) { - return; - } - - var entity = mc.level.getEntity(spawn.getId()); - if (entity instanceof EndCrystal crystal) { - crystalTracker.removeAwaitingPositionsNear(crystal); - } - } - } - - @EventHandler(priority = 25) - private void onRotationUpdate(RotationUpdateEvent event) { - if (event.getType() != RotationUpdateEvent.Type.PRE) { - return; - } - - if (!isEnabled()) return; - if (mc.player == null || mc.level == null || mc.gameMode == null) { - clearPlacementState(); - TargetManager.setAutoCrystalTarget(null); - return; - } - - target = findCombatTarget(); - TargetManager.setAutoCrystalTarget(target); - updateBestPosition(); - updateBestCrystal(); - updateBestBasePosition(); - debugState(); - - if (tryBreakCrystal()) { - return; - } - - if (tryPlaceBase()) { - return; - } - - if (!placeEnabled.get()) { - RotationManager.INSTANCE.clear(this); - return; - } - - AutoCrystalPlaceData candidate = bestCandidate; - if (candidate == null) { - RotationManager.INSTANCE.clear(this); - return; - } - - if (!hasPlaceDelayElapsed()) { - return; - } - - AutoCrystalHand crystalHand = findCrystalHand(mc.player); - if (crystalHand == null) { - return; - } - - if (!usesRotationSettings()) { - RotationManager.INSTANCE.clear(this); - tryPlaceCrystal(candidate.pos()); - return; - } - - BlockHitResult bestHitResult = candidate.bhr(); - if (bestHitResult == null) { - return; - } - - RotationTarget rotationTarget = new RotationTarget( - Rotation.lookingAt(bestHitResult.getLocation(), mc.player.getEyePosition()).normalize(), - target, - List.of(), - rotationResetTicks.get(), - rotationResetThreshold.get(), - true, - movementCorrection.get(), - new RestrictedSingleUseAction(() -> tryPlaceCrystal(candidate.pos())) - ); - RotationManager.INSTANCE.setRotationTarget(rotationTarget, ROTATION_PRIORITY, this); - } - - @Override - public void onRenderWorldEngine(Renderer3D renderer, Renderer3D depthRenderer, float tickDelta) { - if (!isEnabled() || mc.player == null || mc.level == null) return; - - if (renderEnabled.get()) { - renderPlacement(renderer, tickDelta); - } - - if (extrapolationEnabled.get() && target != null) { - renderExtrapolation(renderer, target); - } - - if (interactEnabled.get() && interactVector != null) { - renderInteractVector(renderer, interactVector, interactColor.getArgb()); - } - } - - public void setRenderCandidate(BlockPos pos, float damage, float selfDamage, Vec3 interactVec) { - bestPosition = pos; - interactVector = interactVec; - renderDamage = Math.max(0.0f, damage); - renderSelfDamageValue = Math.max(0.0f, selfDamage); - lastDamageUpdateMs = System.currentTimeMillis(); - } - - public void clearRenderCandidate() { - bestCandidate = null; - currentData = null; - bestPosition = null; - interactVector = null; - if (renderPositions.isEmpty()) { - renderDamage = 0.0f; - renderSelfDamageValue = 0.0f; - renderPos = null; - prevRenderPos = null; - } - } - - public void markPlaced(BlockPos pos) { - if (pos == null) return; - long now = System.currentTimeMillis(); - if (!pos.equals(renderPos)) { - renderStartTick = renderTick; - prevRenderPos = renderPos; - renderPos = pos; - } - renderPositions.put(pos, now); - lastDamageUpdateMs = now; - } - - public void markPlaced(BlockPos pos, float damage, float selfDamage, Vec3 interactVec) { - setRenderCandidate(pos, damage, selfDamage, interactVec); - markPlaced(pos); - } - - private void renderPlacement(Renderer3D renderer, float tickDelta) { - String damageText = buildDamageText(); - if (damageText.isEmpty() && renderPositions.isEmpty() && renderPos == null) { - return; - } - - if (renderMode.get() == RenderMode.FADE) { - renderFade(renderer); - return; - } - - BlockPos activePos = renderPositions.isEmpty() ? bestPosition : renderPos; - if (activePos == null) { - return; - } - - if (renderMode.get() == RenderMode.SLIDE) { - BlockPos slideTo = renderPositions.isEmpty() ? bestPosition : renderPos; - BlockPos from = prevRenderPos != null ? prevRenderPos : slideTo; - renderBox(renderer, AutoCrystalRenderUtil.lerpBox(new AABB(from), new AABB(slideTo), getSlideProgress(tickDelta)), 1.0f); - } else { - renderBox(renderer, new AABB(activePos), 1.0f); - } - } - - - private float getSlideProgress(float tickDelta) { - float clampedTickDelta = Mth.clamp(tickDelta, 0.0f, 1.0f); - float durationTicks = Math.max(1.0f, slideDelay.get() / 50.0f); - return Mth.clamp((renderTick - renderStartTick + clampedTickDelta) / durationTicks, 0.0f, 1.0f); - } - - private void renderFade(Renderer3D renderer) { - long now = System.currentTimeMillis(); - int lifetime = Math.max(1, fadeTime.get()); - List> entries = new ArrayList<>(renderPositions.entrySet()); - for (Map.Entry entry : entries) { - long age = now - entry.getValue(); - if (age > lifetime) { - renderPositions.remove(entry.getKey()); - continue; - } - - float alpha = 1.0f - (age / (float) lifetime); - renderBox(renderer, new AABB(entry.getKey()), alpha); - } - } - - private void renderBox(Renderer3D renderer, AABB box, float alpha) { - int fillArgb = AutoCrystalRenderUtil.applyOpacity(fillColor.getArgb(), alpha); - int lineArgb = AutoCrystalRenderUtil.applyOpacity(lineColor.getArgb(), alpha); - - AutoCrystalRenderUtil.addFilledBox(renderer, box, fillArgb); - - float prevWidth = RenderState.lineWidth; - RenderState.lineWidth = Math.max(0.5f, lineWidth.get()); - try { - AutoCrystalRenderUtil.addOutlineBox(renderer, box, lineArgb); - } finally { - RenderState.lineWidth = prevWidth; - } - - if (drawDamage.get()) { - renderDamageText(renderer, box.getCenter(), alpha); - } - } - - private void renderDamageText(Renderer3D renderer, Vec3 anchor, float alpha) { - String mainText = AutoCrystalRenderUtil.formatDamage(renderDamage); - if (mainText.isEmpty()) return; - - int mainArgb = AutoCrystalRenderUtil.applyOpacity(textColor.getArgb(), alpha); - TextRenderer bold = Fonts.renderer("Iosevka", FontInfo.Type.Bold, TextRenderer.get()); - WorldTextRenderer.Options baseOptions = WorldTextRenderer.Options.defaults() - .withScale(TEXT_SCALE) - .withWorldScale(TEXT_WORLD_SCALE) - .withDepthMode(Renderer3D.DepthMode.NONE) - .withShadow(true) - .withOffset(0.0, TEXT_Y_OFFSET); - - if (!renderSelfDamage.get()) { - WorldTextRenderer.drawBillboard( - renderer, - bold, - mainText, - anchor, - baseOptions.withCentered(true).withColor(new RenderColor(mainArgb)) - ); - return; - } - - String tailText = " / " + AutoCrystalRenderUtil.formatDamage(renderSelfDamageValue); - if (renderSelfDamageValue <= 0.0f) { - WorldTextRenderer.drawBillboard( - renderer, - bold, - mainText, - anchor, - baseOptions.withCentered(true).withColor(new RenderColor(mainArgb)) - ); - return; - } - - TextRenderer medium = Fonts.renderer("Iosevka", FontInfo.Type.Regular, TextRenderer.get()); - double mainWidth = AutoCrystalRenderUtil.measureWidth(bold, mainText, TEXT_SCALE); - double tailWidth = AutoCrystalRenderUtil.measureWidth(medium, tailText, TEXT_GAP_SCALE); - double startX = -(mainWidth + tailWidth) * 0.5; - - double drawnMain = WorldTextRenderer.drawBillboard( - renderer, - bold, - mainText, - anchor, - baseOptions.withCentered(false) - .withOffset(startX, TEXT_Y_OFFSET) - .withColor(new RenderColor(mainArgb)) - ); - - WorldTextRenderer.drawBillboard( - renderer, - medium, - tailText, - anchor, - baseOptions.withCentered(false) - .withScale(TEXT_GAP_SCALE) - .withOffset(startX + drawnMain, TEXT_Y_OFFSET) - .withColor(new RenderColor(mainArgb)) - ); - } - - private void renderExtrapolation(Renderer3D renderer, LivingEntity living) { - AABB box = PositionExtrapolation.getBestForEntity(living).getBoxInTicks(extrapolationTicks.get()); - int argb = extrapolationColor.getArgb(); - float prevWidth = RenderState.lineWidth; - RenderState.lineWidth = 1.0f; - try { - AutoCrystalRenderUtil.addOutlineBox(renderer, box, argb); - } finally { - RenderState.lineWidth = prevWidth; - } - } - - private void renderInteractVector(Renderer3D renderer, Vec3 vec, int argb) { - AABB box = new AABB( - vec.x - INTERACT_MARKER_RADIUS, - vec.y - INTERACT_MARKER_RADIUS, - vec.z - INTERACT_MARKER_RADIUS, - vec.x + INTERACT_MARKER_RADIUS, - vec.y + INTERACT_MARKER_RADIUS, - vec.z + INTERACT_MARKER_RADIUS - ); - AutoCrystalRenderUtil.addFilledBox(renderer, box, AutoCrystalRenderUtil.applyOpacity(argb, 0.6f)); - - float prevWidth = RenderState.lineWidth; - RenderState.lineWidth = 1.0f; - try { - AutoCrystalRenderUtil.addOutlineBox(renderer, box, argb); - } finally { - RenderState.lineWidth = prevWidth; - } - } - - private void purgeExpiredRenderPositions() { - long now = System.currentTimeMillis(); - long lifetime = Math.max(1, fadeTime.get()); - renderPositions.entrySet().removeIf(entry -> now - entry.getValue() > lifetime); - } - - private void updateBestPosition() { - if (mc.player == null || mc.level == null || target == null) { - clearRenderCandidate(); - currentData = null; - return; - } - - AutoCrystalPlacementPlanner.PlaceScanResult result = placementPlanner.findBestPlace( - placementContext, - target, - mc.player.position(), - Mth.ceil(placeRange.get()) - ); - lastPlaceCandidateCount = result.scannedCandidates(); - lastPlaceSelfDamageRejectCount = result.selfDamageRejects(); - lastPlaceSafeCount = result.safeCandidates(); - debugLog("place-candidates total=%d scan=%s", result.safeCandidates(), result.debug()); - - AutoCrystalPlaceData best = result.best(); - if (best == null) { - clearRenderCandidate(); - currentData = null; - return; - } - - bestCandidate = best; - currentData = best; - setRenderCandidate(best.pos(), best.damage(), best.selfDamage(), best.bhr().getLocation()); - } - - private void updateBestBasePosition() { - if (!isBaseActive() || !placeEnabled.get() || mc.player == null || mc.level == null || target == null) { - bestBaseCandidate = null; - lastBaseCandidateCount = 0; - return; - } - - long now = System.currentTimeMillis(); - if (now - lastBaseCalcMs < Math.max(0, baseCalcDelay.get())) { - return; - } - lastBaseCalcMs = now; - - if (findObsidianHand(mc.player) == null) { - bestBaseCandidate = null; - lastBaseCandidateCount = 0; - return; - } - - bestBaseCandidate = basePlanner.findBest( - baseContext, - target, - List.of(target.position()), - Mth.ceil(placeRange.get()), - baseMinDamageDelta.get() - ); - lastBaseScannedCount = basePlanner.lastScanned(); - lastBaseCandidateCount = basePlanner.lastCandidates(); - lastBaseSafeCount = basePlanner.lastSafeCandidates(); - lastBaseWorthCount = basePlanner.lastWorthCandidates(); - lastBaseDeltaCount = basePlanner.lastDeltaCandidates(); - } - - private AutoCrystalBasePlanner.BaseData getBasePlaceData(BlockPos pos, LivingEntity currentTarget) { - return AutoCrystalBaseEvaluator.getBaseData(baseContext, pos, currentTarget); - } - - private boolean canEvaluateBaseAt(BlockPos pos) { - return AutoCrystalBaseEvaluator.canEvaluateBaseAt(mc.level, pos); - } - - private void updateBestCrystal() { - if (mc.player == null || mc.level == null || target == null) { - bestCrystal = null; - secondaryCrystal = null; - return; - } - - if (secondaryCrystal != null) { - if (canAttackCrystal(secondaryCrystal)) { - AutoCrystalCrystalData crystalData = placementPlanner.evaluateCrystal(placementContext, target, secondaryCrystal); - bestCrystal = crystalData; - if (crystalData != null) { - renderDamage = crystalData.damage(); - renderSelfDamageValue = crystalData.selfDamage(); - } - lastBreakCandidateCount = crystalData != null ? 1 : 0; - lastBreakSelfDamageRejectCount = crystalData != null - && crystalData.selfDamage() > maxSelfDamage.get() - && !crystalData.overrideDamage() ? 1 : 0; - lastBreakSafeCount = crystalData != null - && isSafe(crystalData.damage(), crystalData.selfDamage(), crystalData.overrideDamage()) ? 1 : 0; - } else { - bestCrystal = null; - lastBreakCandidateCount = 0; - lastBreakSafeCount = 0; - lastBreakSelfDamageRejectCount = 0; - } - secondaryCrystal = null; - debugLog("break-candidates total=%d", bestCrystal != null ? 1 : 0); - return; - } - - AutoCrystalPlacementPlanner.BreakScanResult result = placementPlanner.findBestCrystal(placementContext, target); - bestCrystal = result.best(); - if (bestCrystal != null) { - renderDamage = bestCrystal.damage(); - renderSelfDamageValue = bestCrystal.selfDamage(); - } - lastBreakCandidateCount = result.scannedCandidates(); - lastBreakSafeCount = result.safeCandidates(); - debugLog("break-candidates total=%d", result.safeCandidates()); - } - - private AutoCrystalPlaceValidationResult validatePlaceCrystal(BlockPos pos, boolean calcPhase) { - if (mc.level == null) { - return AutoCrystalPlaceValidationResult.INVALID_BASE; - } - - var state = mc.level.getBlockState(pos); - if (!state.is(Blocks.OBSIDIAN) && !state.is(Blocks.BEDROCK)) { - return AutoCrystalPlaceValidationResult.INVALID_BASE; - } - - if (!mc.level.isEmptyBlock(pos.above())) { - return AutoCrystalPlaceValidationResult.BLOCKED_AIR; - } - - if (isPositionBlockedByEntity(pos, calcPhase)) { - return AutoCrystalPlaceValidationResult.BLOCKED_ENTITY; - } - - return AutoCrystalPlaceValidationResult.OK; - } - - - private boolean isPositionBlockedByEntity(BlockPos pos, boolean calcPhase) { - AutoCrystalEntityBlocker.Result result = entityBlocker.check( - mc.level, - mc.player, - pos, - calcPhase, - this::isDeadCrystal, - this::isCrystalBlocked, - this::canAttackCrystal - ); - if (result.secondaryCrystal() != null) { - secondaryCrystal = result.secondaryCrystal(); - } - return result.blocked(); - } - - private boolean canAttackCrystal(EndCrystal crystal) { - return placementPlanner.canAttackCrystal(placementContext, target, crystal); - } - - private boolean shouldOverrideMinDamage(LivingEntity currentTarget, float damage) { - return AutoCrystalDamageRules.shouldOverrideMinDamage(currentTarget, damage, faceplaceHealth.get()); - } - - private boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage) { - return AutoCrystalDamageRules.shouldOverrideMaxSelfDamage( - mc.player, - target, - damage, - selfDamage, - maxSelfDamage.get() - ); - } - - private boolean isSafe(float damage, float selfDamage, boolean overrideDamage) { - return AutoCrystalDamageRules.isSafe(mc.player, selfDamage, overrideDamage); - } - - private boolean tryBreakCrystal() { - if (!breakEnabled.get() || !hasBreakDelayElapsed() || mc.player == null) { - return false; - } - - AutoCrystalCrystalData candidate = bestCrystal; - if (candidate == null || candidate.crystal() == null || !candidate.crystal().isAlive()) { - debugLog("break-skip reason=no-candidate"); - return false; - } - - EndCrystal crystal = candidate.crystal(); - if (!usesRotationSettings()) { - RotationManager.INSTANCE.clear(this); - attackCrystal(crystal, null); - return true; - } - - RotationWithVector rotation = RotationRaytrace.raytraceBox( - mc.player.getEyePosition(), - crystal.getBoundingBox(), - breakRange.get(), - breakWallRange.get() - ); - if (rotation == null) { - rotation = new RotationWithVector( - Rotation.lookingAt(crystal.position(), mc.player.getEyePosition()).normalize(), - crystal.position() - ); - } - - Rotation attackRotation = rotation.rotation().normalize(); - RotationTarget rotationTarget = new RotationTarget( - attackRotation, - crystal, - List.of(), - rotationResetTicks.get(), - rotationResetThreshold.get(), - true, - movementCorrection.get(), - new RestrictedSingleUseAction(() -> attackCrystal(crystal, attackRotation)) - ); - RotationManager.INSTANCE.setRotationTarget(rotationTarget, ROTATION_PRIORITY, this); - return true; - } - - private boolean tryPlaceBase() { - if (!isBaseActive() || !placeEnabled.get() || !hasBasePlaceDelayElapsed() || mc.player == null) { - return false; - } - - AutoCrystalBasePlanner.BaseData candidate = bestBaseCandidate; - if (candidate == null) { - return false; - } - - if (findObsidianHand(mc.player) == null) { - return false; - } - - AutoCrystalBasePlanner.BaseData refreshed = getBasePlaceData(candidate.position(), target); - if (refreshed == null - || !isWorthBaseDamage(refreshed.damage()) - || !isEnoughBaseDamageDelta(refreshed.damage(), baseMinDamageDelta.get())) { - return false; - } - - if (!usesRotationSettings()) { - placeBase(refreshed); - return true; - } - - RotationTarget rotationTarget = new RotationTarget( - Rotation.lookingAt(refreshed.hitResult().getLocation(), mc.player.getEyePosition()).normalize(), - target, - List.of(), - rotationResetTicks.get(), - rotationResetThreshold.get(), - true, - movementCorrection.get(), - new RestrictedSingleUseAction(() -> placeBase(refreshed)) - ); - RotationManager.INSTANCE.setRotationTarget(rotationTarget, ROTATION_PRIORITY, this); - return true; - } - - private void placeBase(AutoCrystalBasePlanner.BaseData data) { - LocalPlayer player = mc.player; - if (player == null || mc.level == null || mc.gameMode == null || data == null) { - return; - } - - AutoCrystalBasePlanner.BaseData refreshed = getBasePlaceData(data.position(), target); - if (refreshed == null || !hasBasePlaceDelayElapsed()) { - return; - } - if (!isWorthBaseDamage(refreshed.damage()) - || !isEnoughBaseDamageDelta(refreshed.damage(), baseMinDamageDelta.get())) { - return; - } - - AutoCrystalHand hand = findObsidianHand(player); - if (hand == null) { - return; - } - - if (hand.hotbarSlot() >= 0) { - InventorySwap.INSTANCE.leaseHotbar(this, hand.hotbarSlot(), BASE_HOTBAR_RESET_TICKS); - } - - float damageDelta = refreshed.damage() - getCurrentCrystalDamage(); - mc.gameMode.useItemOn(player, hand.hand(), refreshed.hitResult()); - player.swing(hand.hand()); - lastBasePlaceMs = System.currentTimeMillis(); - bestBaseCandidate = null; - markPlaced(refreshed.position(), refreshed.damage(), refreshed.selfDamage(), refreshed.hitResult().getLocation()); - - if (baseNotify.get()) { - Notifier.info("AutoCrystalBase placed at X:" + refreshed.position().getX() - + " Y:" + refreshed.position().getY() - + " Z:" + refreshed.position().getZ() - + " +" + AutoCrystalRenderUtil.formatDamage(damageDelta)); - } - } - - private void tryPlaceCrystal(BlockPos pos) { - LocalPlayer player = mc.player; - if (player == null || mc.level == null || mc.gameMode == null || pos == null) { - debugLog("place-skip reason=invalid-state pos=%s", pos); - return; - } - - LivingEntity currentTarget = target; - AutoCrystalPlaceData placeData = currentTarget != null ? getPlaceData(pos, currentTarget) : null; - if (!hasPlaceDelayElapsed() || placeData == null) { - debugLog("place-skip reason=delay-or-invalid pos=%s", pos); - return; - } - - if (isPositionBlockedByEntity(pos, false)) { - debugLog("place-skip reason=blocked-entity pos=%s", pos); - return; - } - - AutoCrystalHand hand = findCrystalHand(player); - if (hand == null) { - debugLog("place-skip reason=no-crystal-hand"); - return; - } - - BlockHitResult hitResult = placeData.bhr(); - debugLog("place-attempt pos=%s hand=%s slot=%d hit=%s side=%s", - pos, hand.hand(), hand.hotbarSlot(), hitResult.getBlockPos(), hitResult.getDirection()); - - if (hand.hotbarSlot() >= 0) { - InventorySwap.INSTANCE.leaseHotbar(this, hand.hotbarSlot(), HOTBAR_RESET_TICKS); - } - - mc.gameMode.useItemOn(player, hand.hand(), hitResult); - debugLog("place-result pos=%s packet=sent", pos); - player.swing(hand.hand()); - lastPlaceMs = System.currentTimeMillis(); - crystalTracker.addAwaitingPosition(mc, mc.level, pos.immutable()); - - markPlaced(pos, placeData.damage(), placeData.selfDamage(), hitResult.getLocation()); - } - - private void attackCrystal(EndCrystal crystal, Rotation attackRotation) { - LocalPlayer player = mc.player; - if (player == null || mc.level == null || crystal == null || mc.getConnection() == null) { - debugLog("break-skip reason=invalid-state"); - return; - } - - if (!hasBreakDelayElapsed() || !crystal.isAlive() || crystal.isRemoved() || !canAttackCrystal(crystal)) { - debugLog("break-skip reason=delay-or-dead id=%d", crystal.getId()); - return; - } - - debugLog("break-attempt id=%d pos=%.2f %.2f %.2f", crystal.getId(), crystal.getX(), crystal.getY(), crystal.getZ()); - mc.gameMode.attack(player, crystal); - player.swing(InteractionHand.MAIN_HAND); - lastBreakMs = System.currentTimeMillis(); - crystalTracker.onCrystalAttack(mc, crystal); - crystalTracker.markNearbyCrystalsDead(mc.level, crystal); - } - - private boolean isCrystalBlocked(int id) { - return crystalTracker.isCrystalBlocked(mc, id); - } - - private boolean isDeadCrystal(int id) { - return crystalTracker.isDeadCrystal(id); - } - - private AutoCrystalPlaceData getPlaceData(BlockPos pos, LivingEntity currentTarget) { - return placementPlanner.getPlaceData(placementContext, pos, currentTarget); - } - - private BlockHitResult getInteractResult(BlockPos pos, Vec3 crystalVec) { - return AutoCrystalInteractionUtil.getCrystalInteractResult( - mc.level, - mc.player, - pos, - crystalVec, - placementMode.get(), - placeRange.get(), - wallRange.get() - ); - } - - private AutoCrystalHand findCrystalHand(LocalPlayer player) { - return AutoCrystalInteractionUtil.findCrystalHand(player); - } - - private AutoCrystalHand findObsidianHand(LocalPlayer player) { - return AutoCrystalInteractionUtil.findObsidianHand(player); - } - - private boolean hasPlaceDelayElapsed() { - return System.currentTimeMillis() - lastPlaceMs >= Math.max(0, placeDelay.get()); - } - - private boolean hasBreakDelayElapsed() { - return System.currentTimeMillis() - lastBreakMs >= Math.max(0, breakDelay.get()); - } - - private boolean hasBasePlaceDelayElapsed() { - return System.currentTimeMillis() - lastBasePlaceMs >= Math.max(0, basePlaceDelay.get()); - } - - private long getPlaceDelayRemainingMs() { - return Math.max(0L, Math.max(0, placeDelay.get()) - (System.currentTimeMillis() - lastPlaceMs)); - } - - private long getBreakDelayRemainingMs() { - return Math.max(0L, Math.max(0, breakDelay.get()) - (System.currentTimeMillis() - lastBreakMs)); - } - - private long getBasePlaceDelayRemainingMs() { - return Math.max(0L, Math.max(0, basePlaceDelay.get()) - (System.currentTimeMillis() - lastBasePlaceMs)); - } - - public String getTargetHudStatus(LivingEntity hudTarget) { - if (!isEnabled() || hudTarget == null) { - return null; - } - if (target == null || hudTarget != target) { - return null; - } - if (mc.player == null || mc.level == null) { - return "Idle"; - } - - if (breakEnabled.get()) { - AutoCrystalCrystalData crystalData = bestCrystal; - EndCrystal crystal = crystalData != null ? crystalData.crystal() : null; - if (crystal != null && crystal.isAlive() && !crystal.isRemoved()) { - long breakWait = getBreakDelayRemainingMs(); - if (breakWait > 0L) { - return "Attack in " + breakWait + "ms"; - } - return usesRotationSettings() ? "Rotate -> attack" : "Attacking"; - } - if (lastBreakSelfDamageRejectCount > 0 || (lastBreakCandidateCount > 0 && lastBreakSafeCount <= 0)) { - return "Self dmg"; - } - } - - if (placeEnabled.get()) { - String baseFailureStatus = null; - if (isBaseActive()) { - if (findObsidianHand(mc.player) == null) { - return "No obsidian"; - } - if (bestBaseCandidate != null) { - long baseWait = getBasePlaceDelayRemainingMs(); - if (baseWait > 0L) { - return "Base in " + baseWait + "ms"; - } - return usesRotationSettings() ? "Rotate -> base" : "Placing base"; - } - - baseFailureStatus = baseStatus(); - if (shouldShowBaseStatus(baseFailureStatus)) { - return baseFailureStatus; - } - } - - if (findCrystalHand(mc.player) == null) { - return "No crystals"; - } - - if (bestCandidate != null) { - long placeWait = getPlaceDelayRemainingMs(); - if (placeWait > 0L) { - return "Attack in " + placeWait + "ms"; - } - return usesRotationSettings() ? "Rotate -> attack" : "Attacking"; - } - if (lastPlaceSelfDamageRejectCount > 0 || (lastPlaceCandidateCount > 0 && lastPlaceSafeCount <= 0)) { - return "Self dmg"; - } - - return baseFailureStatus != null ? baseFallbackStatus(baseFailureStatus) : "No place"; - } - - if (breakEnabled.get()) { - return "No crystal"; - } - - return "Idle"; - } - - private String baseStatus() { - if (lastBaseScannedCount <= 0) return "No base scan"; - if (lastBaseCandidateCount <= 0) return "No base interact"; - if (lastBaseSafeCount <= 0) return "Base self dmg"; - if (lastBaseWorthCount <= 0) return "Base low dmg"; - if (lastBaseDeltaCount <= 0) return "Base delta"; - return "No base"; - } - - private boolean shouldShowBaseStatus(String status) { - return !"Base delta".equals(status); - } - - private String baseFallbackStatus(String status) { - return "Base delta".equals(status) ? "No place" : status; - } - - private LivingEntity findCombatTarget() { - if (mc.player == null || mc.level == null) { - return null; - } - - TargetingUtil.TargetingSettings settings = new TargetingUtil.TargetingSettings( - TARGET_SEARCH_RANGE, - 180.0f, - targetToggles.get(TargetFilters.PLAYERS_ONLY), - targetToggles.get(TargetFilters.IGNORE_FRIENDS), - targetToggles.get(TargetFilters.IGNORE_STAFF), - targetToggles.get(TargetFilters.IGNORE_ENEMIES), - targetToggles.get(TargetFilters.IGNORE_NAKED), - targetToggles.get(TargetFilters.IGNORE_ENTITIES), - targetToggles.get(TargetFilters.VISIBLE_ONLY), - priority.get() - ); - - return TargetingUtil.findBestTarget(mc, settings); - } - - private void debugState() { - // long now = System.currentTimeMillis(); - // if (!DebugLog.isEnabled() || now - lastDebugStateLogMs < DEBUG_LOG_INTERVAL_MS) { - // return; - // } - // lastDebugStateLogMs = now; - // - // String targetName = target != null ? target.getName().getString() : "null"; - // String placePos = bestCandidate != null ? String.valueOf(bestCandidate.pos()) : "null"; - // String breakId = bestCrystal != null && bestCrystal.crystal() != null ? String.valueOf(bestCrystal.crystal().getId()) : "null"; - // debugLog("state target=%s place=%s break=%s renderPos=%s", - // targetName, placePos, breakId, renderPos); - } - - private boolean isSpawnNearPendingPlace(ClientboundAddEntityPacket spawn, BlockPos pos) { - AABB crystalBox = AutoCrystalInteractionUtil.predictedCrystalBox(pos); - return crystalBox.contains(spawn.getX(), spawn.getY(), spawn.getZ()); - } - - private Vec3 resolvePredictedPosition(LivingEntity entity, int ticks) { - if (entity == null || ticks <= 0) { - return entity != null ? entity.position() : Vec3.ZERO; - } - - if (entity instanceof net.minecraft.world.entity.player.Player player) { - PlayerSimulationCache.SimulatedPlayerCache simulation = - player == mc.player - ? PlayerSimulationCache.getSimulationForLocalPlayer() - : PlayerSimulationCache.getSimulationForOtherPlayers(player); - if (simulation != null) { - return simulation.getSnapshotAt(ticks).pos(); - } - } - - return PositionExtrapolation.getBestForEntity(entity).getPositionInTicks(ticks); - } - - private void clearPlacementState() { - clearRenderCandidate(); - bestCrystal = null; - bestBaseCandidate = null; - target = null; - crystalTracker.clear(); - RotationManager.INSTANCE.clear(this); - lastPlaceCandidateCount = 0; - lastPlaceSafeCount = 0; - lastBreakCandidateCount = 0; - lastBreakSafeCount = 0; - lastPlaceSelfDamageRejectCount = 0; - lastBreakSelfDamageRejectCount = 0; - lastBaseCandidateCount = 0; - lastBaseScannedCount = 0; - lastBaseSafeCount = 0; - lastBaseWorthCount = 0; - lastBaseDeltaCount = 0; - } - - private void resetVisualState() { - target = null; - bestCandidate = null; - bestCrystal = null; - bestBaseCandidate = null; - renderPos = null; - prevRenderPos = null; - bestPosition = null; - interactVector = null; - renderTick = 0; - renderStartTick = 0; - lastDamageUpdateMs = 0L; - lastPlaceMs = 0L; - lastBreakMs = 0L; - lastBaseCalcMs = 0L; - lastBasePlaceMs = 0L; - renderDamage = 0.0f; - renderSelfDamageValue = 0.0f; - baseActive = false; - renderPositions.clear(); - crystalTracker.clear(); - lastPlaceCandidateCount = 0; - lastPlaceSafeCount = 0; - lastBreakCandidateCount = 0; - lastBreakSafeCount = 0; - lastPlaceSelfDamageRejectCount = 0; - lastBreakSelfDamageRejectCount = 0; - lastBaseCandidateCount = 0; - lastBaseScannedCount = 0; - lastBaseSafeCount = 0; - lastBaseWorthCount = 0; - lastBaseDeltaCount = 0; - } - - private String buildDamageText() { - String main = AutoCrystalRenderUtil.formatDamage(renderDamage); - if (main.isEmpty()) return ""; - if (!renderSelfDamage.get() || renderSelfDamageValue <= 0.0f) { - return main; - } - return main + " / " + AutoCrystalRenderUtil.formatDamage(renderSelfDamageValue); - } - - private float getCurrentCrystalDamage() { - if (currentData != null) { - return currentData.damage(); - } - if (bestCrystal != null) { - return bestCrystal.damage(); - } - return 0.0f; - } - - private boolean hasCurrentCrystalPlan() { - return currentData != null || bestCrystal != null; - } - - private boolean isWorthBaseDamage(float damage) { - if (!hasCurrentCrystalPlan()) { - return shouldOverrideMinDamage(target, damage) || damage >= BASE_INITIATIVE_MIN_DAMAGE; - } - return shouldOverrideMinDamage(target, damage) || damage > minDamage.get(); - } - - private boolean isEnoughBaseDamageDelta(float damage, float minDamageDelta) { - float delta = Math.max(0.0f, minDamageDelta); - if (!hasCurrentCrystalPlan()) { - return damage >= Math.max(BASE_INITIATIVE_MIN_DAMAGE, delta); - } - return damage >= getCurrentCrystalDamage() + delta; - } - - private boolean usesRotationSettings() { - return CombatRotationModeUtil.usesRotations(attackMode); - } - - private boolean isBaseActive() { - return baseActive; - } - - private final class AutoCrystalBaseContext implements AutoCrystalBasePlanner.Context, AutoCrystalBaseEvaluator.Context { - @Override - public boolean canEvaluateBaseAt(BlockPos pos) { - return AutoCrystal.this.canEvaluateBaseAt(pos); - } - - @Override - public AutoCrystalBasePlanner.BaseData getBaseData(BlockPos pos, LivingEntity target) { - return getBasePlaceData(pos, target); - } - - @Override - public boolean isSafe(float damage, float selfDamage, boolean overrideDamage) { - return AutoCrystal.this.isSafe(damage, selfDamage, overrideDamage); - } - - @Override - public boolean hasCurrentCrystalPlan() { - return AutoCrystal.this.hasCurrentCrystalPlan(); - } - - @Override - public float currentCrystalDamage() { - return getCurrentCrystalDamage(); - } - - @Override - public boolean isWorthBaseDamage(float damage) { - return AutoCrystal.this.isWorthBaseDamage(damage); - } - - @Override - public boolean isEnoughBaseDamageDelta(float damage, float minDamageDelta) { - return AutoCrystal.this.isEnoughBaseDamageDelta(damage, minDamageDelta); - } - - @Override - public LocalPlayer player() { - return mc.player; - } - - @Override - public ClientLevel level() { - return mc.level; - } - - @Override - public Vec3 resolvePredictedPosition(LivingEntity entity, int ticks) { - return AutoCrystal.this.resolvePredictedPosition(entity, ticks); - } - - @Override - public boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage) { - return AutoCrystal.this.shouldOverrideMaxSelfDamage(damage, selfDamage); - } - - @Override - public float placeRange() { - return placeRange.get(); - } - - @Override - public float maxSelfDamage() { - return maxSelfDamage.get(); - } - - @Override - public int predictTicks() { - return predictTicks.get(); - } - - @Override - public int selfPredictTicks() { - return selfPredictTicks.get(); - } - - @Override - public boolean ignoreTerrain() { - return ignoreTerrain.get(); - } - } - - private final class AutoCrystalPlacementContext implements AutoCrystalPlacementPlanner.Context { - @Override - public LocalPlayer player() { - return mc.player; - } - - @Override - public Iterable entities() { - return mc.level != null ? mc.level.entitiesForRendering() : List.of(); - } - - @Override - public Vec3 resolvePredictedPosition(LivingEntity entity, int ticks) { - return AutoCrystal.this.resolvePredictedPosition(entity, ticks); - } - - @Override - public AutoCrystalPlaceValidationResult validatePlaceCrystal(BlockPos pos, boolean calcPhase) { - return AutoCrystal.this.validatePlaceCrystal(pos, calcPhase); - } - - @Override - public BlockHitResult getInteractResult(BlockPos pos, Vec3 crystalVec) { - return AutoCrystal.this.getInteractResult(pos, crystalVec); - } - - @Override - public boolean isDeadCrystal(int id) { - return AutoCrystal.this.isDeadCrystal(id); - } - - @Override - public boolean isCrystalBlocked(int id) { - return AutoCrystal.this.isCrystalBlocked(id); - } - - @Override - public boolean shouldOverrideMinDamage(LivingEntity target, float damage) { - return AutoCrystal.this.shouldOverrideMinDamage(target, damage); - } - - @Override - public boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage) { - return AutoCrystal.this.shouldOverrideMaxSelfDamage(damage, selfDamage); - } - - @Override - public boolean isSafe(float damage, float selfDamage, boolean overrideDamage) { - return AutoCrystal.this.isSafe(damage, selfDamage, overrideDamage); - } - - @Override - public float minDamage() { - return minDamage.get(); - } - - @Override - public float faceplaceHealth() { - return faceplaceHealth.get(); - } - - @Override - public float maxSelfDamage() { - return maxSelfDamage.get(); - } - - @Override - public float breakRange() { - return breakRange.get(); - } - - @Override - public float breakWallRange() { - return breakWallRange.get(); - } - - @Override - public int predictTicks() { - return predictTicks.get(); - } - - @Override - public int selfPredictTicks() { - return selfPredictTicks.get(); - } - - @Override - public boolean ignoreTerrain() { - return ignoreTerrain.get(); - } - } - - private enum RenderMode { - FADE, - SLIDE, - DEFAULT - } - -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Backtrack.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Backtrack.java deleted file mode 100644 index b4238ce..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Backtrack.java +++ /dev/null @@ -1,410 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import net.minecraft.world.entity.Entity; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.config.values.RGBAColorValue; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.WorldPhase; -import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; -import dev.loki.lovisual.render.engine.renderer.Renderer3D; -import dev.loki.lovisual.render.engine.uniform.MeshBuilder; -import dev.loki.lovisual.util.network.BacktrackController; - -/** - * Backtrack module front-end for the shared BlinkManager-backed incoming packet controller. - */ -//todo Description -@ModuleInfo( - id = "backtrack", - displayName = "Backtrack", - category = ModuleCategory.COMBAT -) -public final class Backtrack extends Module { - - private final NumberValue minRange = numCommon( - "backtrackMinRange", - "range_min", - CommonSettingSchemas.COMBAT_BACKTRACK_RANGE_MIN, - 0.0f, - 0.0f, - 10.0f - ); - - private final NumberValue maxRange = numCommon( - "backtrackMaxRange", - "range_max", - CommonSettingSchemas.COMBAT_BACKTRACK_RANGE_MAX, - 3.0f, - 0.0f, - 10.0f - ); - - private final NumberValue minDelay = numCommon( - "backtrackMinDelay", - "delay_min", - CommonSettingSchemas.COMBAT_BACKTRACK_DELAY_MIN, - 100, - 0, - 1000 - ); - private final NumberValue maxDelay = numCommon( - "backtrackMaxDelay", - "delay_max", - CommonSettingSchemas.COMBAT_BACKTRACK_DELAY_MAX, - 150, - 0, - 1000 - ); - - private final NumberValue minNextBacktrackDelay = numCommon( - "backtrackMinNextDelay", - "next_delay_min", - CommonSettingSchemas.COMBAT_BACKTRACK_NEXT_DELAY_MIN, - 0, - 0, - 2000 - ); - - private final NumberValue maxNextBacktrackDelay = numCommon( - "backtrackMaxNextDelay", - "next_delay_max", - CommonSettingSchemas.COMBAT_BACKTRACK_NEXT_DELAY_MAX, - 10, - 0, - 2000 - ); - - private final NumberValue trackingBuffer = numCommon( - "backtrackTrackingBuffer", - "tracking_buffer", - CommonSettingSchemas.COMBAT_BACKTRACK_TRACKING_BUFFER, - 500, - 0, - 2000 - ); - - private final NumberValue chance = numCommon( - "backtrackChance", - "chance", - CommonSettingSchemas.COMBAT_BACKTRACK_CHANCE, - 100.0f, - 0.0f, - 100.0f - ); - - private final BooleanValue pauseOnHurtTime = boolCommon( - "backtrackPauseOnHurtTime", - "pause_on_hurt_time", - CommonSettingSchemas.COMBAT_BACKTRACK_PAUSE_ON_HURT_TIME, - false - ); - - private final NumberValue hurtTime = visibleWhen(numCommon( - "backtrackHurtTime", - "hurt_time", - CommonSettingSchemas.COMBAT_BACKTRACK_HURT_TIME, - 3, - 0, - 10 - ), pauseOnHurtTime::get); - - private final EnumValue targetMode = enumCommon( - "backtrackTargetMode", - "target_mode", - CommonSettingSchemas.COMBAT_BACKTRACK_TARGET_MODE, - BacktrackController.TargetMode.ATTACK, - BacktrackController.TargetMode.class - ); - - private final NumberValue lastAttackTime = visibleWhen(numCommon( - "backtrackLastAttackTime", - "last_attack_time", - CommonSettingSchemas.COMBAT_BACKTRACK_LAST_ATTACK_TIME, - 1000, - 0, - 5000 - ), () -> targetMode.get() == BacktrackController.TargetMode.ATTACK); - - private final BooleanValue render = boolCommon( - "backtrackRender", - "render", - CommonSettingSchemas.COMBAT_BACKTRACK_RENDER, - true - ); - - private final RGBAColorValue fillColor = visibleWhen(color( - "backtrackFillColor", - "fill_color", - "#552D8CFF" - ), render::get); - - private final RGBAColorValue lineColor = visibleWhen(color( - "backtrackLineColor", - "line_color", - "#FF9BE4FF" - ), render::get); - - private final NumberValue lineWidth = visibleWhen(numCommon( - "backtrackLineWidth", - "line_width", - CommonSettingSchemas.COMBAT_BACKTRACK_LINE_WIDTH, - 1.5f, - 0.5f, - 6.0f - ), render::get); - - private BacktrackController.Config appliedConfig; - - private static void addBodyModel(MeshBuilder tris, MeshBuilder lines, Entity entity, Vec3 feet, int fillArgb, int lineArgb) { - AABB currentBox = entity.getBoundingBox(); - double width = clamp(Math.max(currentBox.getXsize(), currentBox.getZsize()), 0.35, 1.35); - double height = clamp(currentBox.getYsize(), 0.75, 3.2); - float yaw = entity.getYRot(); - - double depth = width * 0.32; - double legHeight = height * 0.43; - double torsoHeight = height * 0.34; - double headSize = Math.min(width * 0.58, height * 0.24); - - double legWidth = width * 0.20; - double legDepth = depth * 0.85; - double legOffset = width * 0.14; - double torsoWidth = width * 0.58; - double armWidth = width * 0.17; - double armOffset = torsoWidth * 0.5 + armWidth * 0.6; - - addBodyPart(tris, lines, feet, -legOffset, legHeight * 0.5, 0.0, legWidth, legHeight, legDepth, yaw, fillArgb, lineArgb); - addBodyPart(tris, lines, feet, legOffset, legHeight * 0.5, 0.0, legWidth, legHeight, legDepth, yaw, fillArgb, lineArgb); - addBodyPart(tris, lines, feet, 0.0, legHeight + torsoHeight * 0.5, 0.0, torsoWidth, torsoHeight, depth, yaw, fillArgb, lineArgb); - addBodyPart(tris, lines, feet, -armOffset, legHeight + torsoHeight * 0.5, 0.0, armWidth, torsoHeight * 0.95, depth * 0.9, yaw, fillArgb, lineArgb); - addBodyPart(tris, lines, feet, armOffset, legHeight + torsoHeight * 0.5, 0.0, armWidth, torsoHeight * 0.95, depth * 0.9, yaw, fillArgb, lineArgb); - addBodyPart(tris, lines, feet, 0.0, height - headSize * 0.5, 0.0, headSize, headSize, headSize, yaw, fillArgb, lineArgb); - } - - private static void addBodyPart(MeshBuilder tris, - MeshBuilder lines, - Vec3 origin, - double centerX, - double centerY, - double centerZ, - double sizeX, - double sizeY, - double sizeZ, - float yaw, - int fillArgb, - int lineArgb) { - Vec3[] corners = orientedBoxCorners(origin, centerX, centerY, centerZ, sizeX, sizeY, sizeZ, yaw); - - quad(tris, corners[0], corners[1], corners[2], corners[3], fillArgb); - quad(tris, corners[4], corners[7], corners[6], corners[5], fillArgb); - quad(tris, corners[0], corners[4], corners[5], corners[1], fillArgb); - quad(tris, corners[3], corners[2], corners[6], corners[7], fillArgb); - quad(tris, corners[1], corners[5], corners[6], corners[2], fillArgb); - quad(tris, corners[0], corners[3], corners[7], corners[4], fillArgb); - - line(lines, corners[0], corners[1], lineArgb); - line(lines, corners[1], corners[2], lineArgb); - line(lines, corners[2], corners[3], lineArgb); - line(lines, corners[3], corners[0], lineArgb); - line(lines, corners[4], corners[5], lineArgb); - line(lines, corners[5], corners[6], lineArgb); - line(lines, corners[6], corners[7], lineArgb); - line(lines, corners[7], corners[4], lineArgb); - line(lines, corners[0], corners[4], lineArgb); - line(lines, corners[1], corners[5], lineArgb); - line(lines, corners[2], corners[6], lineArgb); - line(lines, corners[3], corners[7], lineArgb); - } - - private static Vec3[] orientedBoxCorners(Vec3 origin, - double centerX, - double centerY, - double centerZ, - double sizeX, - double sizeY, - double sizeZ, - float yaw) { - double halfX = sizeX * 0.5; - double halfY = sizeY * 0.5; - double halfZ = sizeZ * 0.5; - - return new Vec3[]{ - transformBodyVertex(origin, centerX - halfX, centerY - halfY, centerZ - halfZ, yaw), - transformBodyVertex(origin, centerX + halfX, centerY - halfY, centerZ - halfZ, yaw), - transformBodyVertex(origin, centerX + halfX, centerY - halfY, centerZ + halfZ, yaw), - transformBodyVertex(origin, centerX - halfX, centerY - halfY, centerZ + halfZ, yaw), - transformBodyVertex(origin, centerX - halfX, centerY + halfY, centerZ - halfZ, yaw), - transformBodyVertex(origin, centerX + halfX, centerY + halfY, centerZ - halfZ, yaw), - transformBodyVertex(origin, centerX + halfX, centerY + halfY, centerZ + halfZ, yaw), - transformBodyVertex(origin, centerX - halfX, centerY + halfY, centerZ + halfZ, yaw) - }; - } - - private static Vec3 transformBodyVertex(Vec3 origin, double localX, double localY, double localZ, float yaw) { - double radians = Math.toRadians(-yaw); - double sin = Math.sin(radians); - double cos = Math.cos(radians); - double x = localX * cos - localZ * sin; - double z = localX * sin + localZ * cos; - return new Vec3(origin.x + x, origin.y + localY, origin.z + z); - } - - private static double clamp(double value, double min, double max) { - return Math.max(min, Math.min(max, value)); - } - - private static void quad(MeshBuilder mesh, - double x1, double y1, double z1, - double x2, double y2, double z2, - double x3, double y3, double z3, - double x4, double y4, double z4, - int argb) { - mesh.ensureQuadCapacity(); - putVertex(mesh, x1, y1, z1, argb); - int i1 = mesh.next(); - putVertex(mesh, x2, y2, z2, argb); - int i2 = mesh.next(); - putVertex(mesh, x3, y3, z3, argb); - int i3 = mesh.next(); - putVertex(mesh, x4, y4, z4, argb); - int i4 = mesh.next(); - mesh.quad(i1, i2, i3, i4); - } - - private static void quad(MeshBuilder mesh, Vec3 p1, Vec3 p2, Vec3 p3, Vec3 p4, int argb) { - quad(mesh, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, p3.x, p3.y, p3.z, p4.x, p4.y, p4.z, argb); - } - - private static void line(MeshBuilder mesh, - double x1, double y1, double z1, - double x2, double y2, double z2, - int argb) { - mesh.ensureLineCapacity(); - putVertex(mesh, x1, y1, z1, argb); - int i1 = mesh.next(); - putVertex(mesh, x2, y2, z2, argb); - int i2 = mesh.next(); - mesh.line(i1, i2); - } - - private static void line(MeshBuilder mesh, Vec3 p1, Vec3 p2, int argb) { - line(mesh, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, argb); - } - - private static void putVertex(MeshBuilder mesh, double x, double y, double z, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - mesh.vec3(x, y, z).color(r, g, b, a); - } - - @Override - public void onEnable() { - syncControllerConfig(); - BacktrackController.INSTANCE.setEnabled(true); - } - - @Override - public void onDisable() { - BacktrackController.INSTANCE.setEnabled(false); - appliedConfig = null; - } - - @Override - public void onTick() { - if (!isEnabled()) { - return; - } - syncControllerConfig(); - } - - @Override - public WorldPhase getWorldPhase() { - return WorldPhase.END_MAIN; - } - - @Override - public void onRenderWorldEngine(Renderer3D renderer, Renderer3D depthRenderer, float tickDelta) { - if (!isEnabled() || !render.get() || renderer == null) { - return; - } - if (!BacktrackController.INSTANCE.shouldRenderTrackedBody()) { - return; - } - - Entity target = BacktrackController.INSTANCE.getTarget(); - Vec3 trackedPosition = BacktrackController.INSTANCE.getTrackedPosition(); - if (target == null || trackedPosition == null || trackedPosition.equals(Vec3.ZERO)) { - return; - } - - MeshBuilder tris = renderer.batch(CombatantRenderPipelines.WORLD_COLORED, Renderer3D.DepthMode.NONE); - float previousLineWidth = RenderState.lineWidth; - MeshBuilder lines; - try { - RenderState.lineWidth = Math.max(0.5f, lineWidth.get()); - lines = renderer.batch(CombatantRenderPipelines.WORLD_COLORED_LINES, Renderer3D.DepthMode.NONE); - } finally { - RenderState.lineWidth = previousLineWidth; - } - - addBodyModel(tris, lines, target, trackedPosition, fillColor.getArgb(), lineColor.getArgb()); - } - - private void syncControllerConfig() { - BacktrackController.Config config = buildConfig(); - if (!config.equals(appliedConfig) || !config.equals(BacktrackController.INSTANCE.getConfig())) { - BacktrackController.INSTANCE.configure(config); - appliedConfig = config; - } - } - - private BacktrackController.Config buildConfig() { - float min = minRange.get(); - float max = maxRange.get(); - if (targetMode.get() == BacktrackController.TargetMode.ATTACK) { - min = 0.0f; - } - int minDelayMs = minDelay.get(); - int maxDelayMs = maxDelay.get(); - int minNextDelayMs = minNextBacktrackDelay.get(); - int maxNextDelayMs = maxNextBacktrackDelay.get(); - - return new BacktrackController.Config( - Math.min(min, max), - Math.max(min, max), - Math.min(minDelayMs, maxDelayMs), - Math.max(minDelayMs, maxDelayMs), - Math.min(minNextDelayMs, maxNextDelayMs), - Math.max(minNextDelayMs, maxNextDelayMs), - trackingBuffer.get(), - Math.round(chance.get()), - pauseOnHurtTime.get(), - hurtTime.get(), - lastAttackTime.get(), - targetMode.get() - ); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Criticals.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Criticals.java deleted file mode 100644 index 5e2d9af..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Criticals.java +++ /dev/null @@ -1,766 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import dev.loki.lovisual.util.combat.AttackUtil; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.vehicle.boat.Boat; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.phys.AABB; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.events.impl.PacketEvent; -import dev.loki.lovisual.events.impl.PlayerJumpEvent; -import dev.loki.lovisual.events.impl.SprintControlEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.Flight; -import dev.loki.lovisual.features.module.modules.movement.Timer; -import dev.loki.lovisual.mixins.accessors.ServerboundMovePlayerPacketAccessor; -import dev.loki.lovisual.util.click.ClickScheduler; -import dev.loki.lovisual.util.target.TargetManager; - -//todo Description -@ModuleInfo( - id = "criticals", - displayName = "Criticals", - category = ModuleCategory.COMBAT -) -public final class Criticals extends Module { - - private static final float VANILLA_JUMP_MOTION = 0.42f; - private static final int JUMP_CRIT_LEAD_TICKS = 4; - private static final int VULCAN_297_JUMP_RECOVERY_TICKS = 8; - private static final int VULCAN_297_LANDING_RECOVERY_TICKS = 2; - private final Minecraft mc = Minecraft.getInstance(); - private final EnumValue mode = - enumMode( - "mode", - Mode.JUMP, - Mode.values() - ); - private final EnumValue selectionMode = - enumCommon( - "selection_mode", - "selection_mode", - CommonSettingSchemas.COMBAT_CRITICALS, - SelectionMode.SMART, - SelectionMode.values() - ); - private final BooleanValue whenSprinting = - boolCommon( - "when_sprinting", - "when_sprinting", - CommonSettingSchemas.COMBAT_WHEN_SPRINTING, - false - ); - private final EnumValue stopSprintingMode = - visibleWhen(enumCommon( - "stop_sprinting_mode", - "stop_sprinting_mode", - CommonSettingSchemas.COMBAT_STOP_SPRINTING, - StopSprintingMode.LEGIT, - StopSprintingMode.values() - ), whenSprinting::get); - private final NumberValue jumpHeight = - visibleWhen(num( - "jump_height", - "jump_height", - 0.42f, - 0.1f, - 0.42f - ), () -> mode.get() == Mode.JUMP); - private final NumberValue jumpRange = - visibleWhen(numCommon( - "jump_range", - "range", - CommonSettingSchemas.COMBAT_RANGE, - 4.0f, - 1.0f, - 6.0f - ), () -> mode.get() == Mode.JUMP); - private final BooleanValue optimizeForCooldown = - visibleWhen(bool( - "optimize_for_cooldown", - "optimize_for_cooldown", - true - ), () -> mode.get() == Mode.JUMP); - private final BooleanValue canBeSeen = - visibleWhen(bool( - "can_be_seen", - "can_be_seen", - true - ), () -> mode.get() == Mode.JUMP); - private final EnumValue packetMode = - visibleWhen(enumMode( - "packet_mode", - PacketMode.NO_CHEAT_PLUS, - PacketMode.values() - ), () -> mode.get() == Mode.PACKET); - private final EnumValue packetType = - visibleWhen(enumMode( - "packet_type", - PacketType.FULL, - PacketType.values() - ), () -> mode.get() == Mode.PACKET); - private final NumberValue timerSpeed = - visibleWhen(num( - "timer_speed", - "timer_speed", - 0.8f, - 0.1f, - 1.0f - ), () -> mode.get() == Mode.TIMER); - private final NumberValue timerRange = - visibleWhen(num( - "timer_range", - "timer_range", - 4.0f, - 0.0f, - 10.0f - ), () -> mode.get() == Mode.TIMER); - private Mode killAuraModeOverride; - private SelectionMode killAuraSelectionOverride; - private boolean adjustNextJump; - private int lastJumpInputAge = -1; - private int lastPreparedAttackAge = -1; - private int lastPreparedTargetId = Integer.MIN_VALUE; - private int vulcan297JumpRecoveryTicks; - private int vulcan297LandingRecoveryTicks; - private boolean vulcan297WasAirborne; - - @Override - public void onEnable() { - adjustNextJump = false; - lastJumpInputAge = -1; - resetVulcan297State(); - resetPreparedAttack(); - Timer.clearExternalTickTimer(); - } - - @Override - public void onDisable() { - adjustNextJump = false; - lastJumpInputAge = -1; - resetVulcan297State(); - resetPreparedAttack(); - Timer.clearExternalTickTimer(); - } - - public void setKillAuraOverrides(Mode modeOverride, SelectionMode selectionOverride) { - killAuraModeOverride = modeOverride; - killAuraSelectionOverride = selectionOverride; - } - - public void clearKillAuraOverrides() { - killAuraModeOverride = null; - killAuraSelectionOverride = null; - } - - @Override - public void onTick() { - if (!isEnabled()) return; - - if (getMode() == Mode.TIMER) { - Entity target = getTargetInRange(timerRange.get()); - if (target != null && wouldDoCriticalHit(shouldAttemptCritWhileSprinting())) { - Timer.setExternalTickTimer(timerSpeed.get()); - } else { - Timer.clearExternalTickTimer(); - } - } else { - Timer.clearExternalTickTimer(); - } - - updateVulcan297State(currentPlayer()); - } - - @EventHandler - private void onMovementInput(MovementInputEvent event) { - if (!isEnabled() || getMode() != Mode.JUMP) return; - - LocalPlayer player = currentPlayer(); - if (player == null) return; - Entity target = getTargetInRange(); - - if (target != null && shouldAutoJumpCrit(target) && player.onGround()) { - event.setJump(true); - adjustNextJump = true; - } - - if (event.isJump()) { - lastJumpInputAge = player.tickCount; - } - } - - @EventHandler - private void onPlayerJump(PlayerJumpEvent event) { - if (isEnabled() && getMode() == Mode.VULCAN_297) { - vulcan297JumpRecoveryTicks = VULCAN_297_JUMP_RECOVERY_TICKS; - vulcan297LandingRecoveryTicks = VULCAN_297_LANDING_RECOVERY_TICKS; - vulcan297WasAirborne = true; - return; - } - - if (!isEnabled() || getMode() != Mode.JUMP) return; - - if (adjustNextJump && Math.abs(event.getMotion() - VANILLA_JUMP_MOTION) < 1.0E-4f) { - event.setMotion(jumpHeight.get()); - } - adjustNextJump = false; - } - - @EventHandler - private void onSprintControl(SprintControlEvent event) { - if (!shouldStopSprintingNow()) return; - - StopSprintingMode stopMode = stopSprintingMode.get(); - if (stopMode == StopSprintingMode.LEGIT) { - if (event.getSource() == SprintControlEvent.Source.MOVEMENT_TICK - || event.getSource() == SprintControlEvent.Source.INPUT) { - event.setSprint(false); - } - } else if (stopMode == StopSprintingMode.ON_NETWORK) { - if (event.getSource() == SprintControlEvent.Source.NETWORK - || event.getSource() == SprintControlEvent.Source.INPUT) { - event.setSprint(false); - } - } - } - - public boolean isCriticalHit(Entity target) { - return isCriticalHitInternal(target, false); - } - - private boolean isCriticalHitInternal(Entity target, boolean ignoreEnabledState) { - if (!ignoreEnabledState && !isEnabled()) return true; - boolean ignoreSprint = shouldAttemptCritWhileSprinting(); - return switch (getSelectionMode()) { - case IGNORE -> true; - case SMART -> switch (getMode()) { - case PACKET, NO_GROUND, VULCAN_297 -> canDoCriticalHit(true, ignoreSprint); - case JUMP, TIMER -> !shouldWaitForCrit(target, true); - case OFF -> true; - }; - case ALWAYS -> switch (getMode()) { - case PACKET, NO_GROUND, VULCAN_297 -> canDoCriticalHit(true, ignoreSprint); - case JUMP, TIMER -> wouldDoCriticalHit(ignoreSprint); - case OFF -> true; - }; - }; - } - - public boolean shouldStopSprinting(ClickScheduler clicker, Entity target) { - if (!shouldStopSprintingBase()) return false; - if (getSelectionMode() == SelectionMode.IGNORE) return false; - - LocalPlayer player = currentPlayer(); - if (player == null) return false; - if (target == null) return false; - if (!canAttemptCriticalAttack(target)) return false; - if (usesNaturalCriticalState() && player.onGround()) return false; - - return clicker != null && clicker.willClickAt(1); - } - - public boolean shouldStopSprintingOnAttack(ClickScheduler clicker, Entity target) { - return shouldStopSprinting(clicker, target) - && stopSprintingMode.get() == StopSprintingMode.ON_ATTACK; - } - - public boolean shouldAttack(Entity target) { - return shouldAttack(null, target); - } - - public boolean shouldAttack(ClickScheduler clicker, Entity target) { - return shouldAttackInternal(clicker, target, false); - } - - private boolean shouldAttackInternal(ClickScheduler clicker, - Entity target, - boolean ignoreEnabledState) { - if (target == null) return false; - LocalPlayer player = currentPlayer(); - if (player == null) return false; - - if (getMode() == Mode.JUMP && getSelectionMode() != SelectionMode.IGNORE && canUseJumpCriticalState(target)) { - if (player.onGround()) return false; - if (player.getDeltaMovement().y > 0.0) return false; - if (clicker != null && !clicker.willClickAt(2) && player.fallDistance <= 0.0f) return false; - } - - return isCriticalHitInternal(target, ignoreEnabledState); - } - - /** - * Runs attack gate with temporary KillAura-specific selection override. - * Keeps Criticals internals (mode checks, jump state checks, click lookahead) intact. - */ - public boolean shouldAttackForKillAura(ClickScheduler clicker, - Entity target, - SelectionMode selectionOverride, - boolean ignoreSprintAfterReset) { - if (target == null) return false; - LocalPlayer player = currentPlayer(); - if (player == null) return false; - - SelectionMode selection = selectionOverride != null ? selectionOverride : selectionMode.get(); - if (selection == SelectionMode.IGNORE) { - return true; - } - - boolean ignoreSprint = ignoreSprintAfterReset || shouldAttemptCritWhileSprinting(); - if (canUseKillAuraJumpCriticalState(target)) { - if (selection == SelectionMode.ALWAYS) { - return isNaturalCriticalReady(ignoreSprint); - } - if (selection == SelectionMode.SMART - && player.onGround() - && hasJumpIntent(player) - && shouldForceJumpCrit(target)) { - return false; - } - if (shouldHoldKillAuraForNaturalCrit(player, ignoreSprint)) { - return isNaturalCriticalReady(ignoreSprint); - } - } - - return switch (selection) { - case SMART -> !shouldWaitForCrit(target, true); - case ALWAYS -> wouldDoCriticalHit(ignoreSprint); - case IGNORE -> true; - }; - } - - public boolean shouldControlTargetStrafeJump(Entity target) { - if (!isEnabled() || target == null) { - return false; - } - if (getSelectionMode() == SelectionMode.IGNORE) { - return false; - } - return canUseJumpCriticalState(target); - } - - public void beforeAttack(Minecraft mc, LocalPlayer player, Entity target) { - if (mc == null || player == null || target == null || !isEnabled()) return; - if (isAttackAlreadyPrepared(player, target)) return; - markAttackPrepared(player, target); - - if (stopSprintingMode.get() == StopSprintingMode.ON_ATTACK - && whenSprinting.get() - && getSelectionMode() != SelectionMode.IGNORE - && canAttemptCriticalAttack(target)) { - AttackUtil.sendStopSprinting(mc, player); - } - - if (getMode() == Mode.PACKET && canDoCriticalHit(true, shouldAttemptCritWhileSprinting())) { - performPacketCritical(mc, player, target); - } else if (getMode() == Mode.VULCAN_297 - && canDoCriticalHit(true, shouldAttemptCritWhileSprinting()) - && canPerformVulcan297Critical(player)) { - performVulcan297Critical(mc, player); - } - } - - public boolean shouldStopSprinting() { - return shouldStopSprintingBase(); - } - - @EventHandler - private void onPacketSend(PacketEvent.Send event) { - if (!isEnabled()) return; - - if (getMode() == Mode.NO_GROUND && event.getPacket() instanceof ServerboundMovePlayerPacket move) { - ((ServerboundMovePlayerPacketAccessor) move).combatant$setOnGround(false); - } - } - - private boolean shouldStopSprintingBase() { - if (!isEnabled() || !whenSprinting.get()) return false; - if (stopSprintingMode.get() == StopSprintingMode.NONE) return false; - if (getSelectionMode() == SelectionMode.IGNORE) return false; - return canAttemptCriticalAttack(getTargetInRange()); - } - - private boolean shouldStopSprintingNow() { - if (!shouldStopSprintingBase()) return false; - - Entity target = getTargetInRange(); - if (target == null) return false; - - KillAura killAura = Modules.get(KillAura.class); - if (killAura != null && killAura.isEnabled()) { - return shouldStopSprinting(killAura.getClickScheduler(), target); - } - - return false; - } - - public boolean allowsCriticalHit(boolean ignoreOnGround) { - LocalPlayer player = currentPlayer(); - if (player == null) return false; - - Flight flight = Modules.get(Flight.class); - if (flight != null && flight.isEnabled()) return false; - if (player.isFallFlying()) return false; - if (player.isInWater() || player.isUnderWater() || player.isInLava()) return false; - if (player.isPassenger() || player.getVehicle() instanceof Boat) return false; - if (player.onClimbable() || player.isNoGravity()) return false; - if (player.getAbilities().flying) return false; - if (player.isUsingItem()) return false; - if (player.hasEffect(MobEffects.BLINDNESS) - || player.hasEffect(MobEffects.LEVITATION) - || player.hasEffect(MobEffects.SLOW_FALLING)) return false; - if (!ignoreOnGround && player.onGround()) return false; - AABB box = player.getBoundingBox(); - BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); - int minX = (int) Math.floor(box.minX); - int maxX = (int) Math.floor(box.maxX); - int minY = (int) Math.floor(box.minY); - int maxY = (int) Math.floor(box.maxY); - int minZ = (int) Math.floor(box.minZ); - int maxZ = (int) Math.floor(box.maxZ); - for (int x = minX; x <= maxX; x++) { - for (int y = minY; y <= maxY; y++) { - for (int z = minZ; z <= maxZ; z++) { - pos.set(x, y, z); - BlockState state = player.level().getBlockState(pos); - if (state.is(Blocks.COBWEB)) return false; - FluidState fluid = player.level().getFluidState(pos); - if (fluid.is(FluidTags.WATER) || fluid.is(FluidTags.LAVA)) return false; - } - } - } - - return true; - } - - public boolean canDoCriticalHit(boolean ignoreOnGround, boolean ignoreSprint) { - LocalPlayer player = currentPlayer(); - if (player == null) return false; - - return allowsCriticalHit(ignoreOnGround) - && player.getAttackStrengthScale(0.5f) > 0.9f - && (!player.isSprinting() || ignoreSprint); - } - - public boolean wouldDoCriticalHit(boolean ignoreSprint) { - LocalPlayer player = currentPlayer(); - if (player == null) return false; - - return isNaturalCriticalReady(ignoreSprint); - } - - private boolean isNaturalCriticalReady(boolean ignoreSprint) { - LocalPlayer player = currentPlayer(); - if (player == null) return false; - - return canDoCriticalHit(false, ignoreSprint) - && player.fallDistance > 0.0f - && player.getDeltaMovement().y <= 0.0; - } - - private boolean shouldHoldKillAuraForNaturalCrit(LocalPlayer player, boolean ignoreSprint) { - if (player == null || player.onGround()) return false; - return ignoreSprint || !player.isSprinting(); - } - - private boolean hasJumpIntent(LocalPlayer player) { - if (player == null) return false; - if (mc.options != null && mc.options.keyJump.isDown()) return true; - return lastJumpInputAge >= 0 && player.tickCount - lastJumpInputAge <= 1; - } - - public boolean shouldWaitForCrit(Entity target, boolean ignoreState) { - LocalPlayer player = currentPlayer(); - if (player == null || target == null) return false; - if (!ignoreState && (!isEnabled() || getMode() != Mode.JUMP)) return false; - if (player.isFallFlying()) return false; - if (!allowsCriticalHit(false) || player.getDeltaMovement().y < -0.08) return false; - if (player.fallDistance > 0.0f) return false; - if (player.distanceToSqr(target) > jumpRange.get() * jumpRange.get()) return false; - - return player.getDeltaMovement().y > 0.0 - && player.getAttackStrengthScale(0.5f) > 0.9f; - } - - private boolean shouldWaitForJump() { - LocalPlayer player = currentPlayer(); - if (player == null || !allowsCriticalHit(true) || getMode() != Mode.JUMP) return false; - return player.getAttackStrengthScale(0.5f) < 0.9f; - } - - private Entity getTargetInRange() { - return getTargetInRange(jumpRange.get()); - } - - private Entity getTargetInRange(float rangeValue) { - LocalPlayer player = currentPlayer(); - Entity target = getPreferredTarget(); - if (player == null || target == null || !target.isAlive()) return null; - if (player.distanceToSqr(target) > rangeValue * rangeValue) return null; - if (canBeSeen.get() && !player.hasLineOfSight(target)) return null; - return target; - } - - private LocalPlayer currentPlayer() { - return mc != null ? mc.player : null; - } - - private boolean usesNaturalCriticalState() { - return getMode() == Mode.JUMP || getMode() == Mode.TIMER; - } - - private boolean shouldForceJumpCrit(Entity target) { - LocalPlayer player = currentPlayer(); - if (player == null || target == null) return false; - if (getMode() != Mode.JUMP) return false; - if (!allowsCriticalHit(true)) return false; - if (player.distanceToSqr(target) > jumpRange.get() * jumpRange.get()) return false; - if (canBeSeen.get() && !player.hasLineOfSight(target)) return false; - return !optimizeForCooldown.get() || !shouldWaitForJump(); - } - - private boolean shouldAttemptCritWhileSprinting() { - return isEnabled() && whenSprinting.get() && stopSprintingMode.get() == StopSprintingMode.NONE; - } - - private boolean canAttemptCriticalAttack(Entity target) { - if (target == null) return false; - boolean ignoreSprint = shouldAttemptCritWhileSprinting(); - return switch (getMode()) { - case PACKET, NO_GROUND, VULCAN_297 -> canDoCriticalHit(true, ignoreSprint); - case JUMP, TIMER -> getTargetInRange() != null; - case OFF -> false; - }; - } - - private boolean canUseJumpCriticalState(Entity target) { - LocalPlayer player = currentPlayer(); - if (player == null || target == null) return false; - if (getMode() != Mode.JUMP) return false; - if (!allowsCriticalHit(true)) return false; - if (player.distanceToSqr(target) > jumpRange.get() * jumpRange.get()) return false; - return !canBeSeen.get() || player.hasLineOfSight(target); - } - - private boolean canUseKillAuraJumpCriticalState(Entity target) { - LocalPlayer player = currentPlayer(); - if (player == null || target == null) return false; - if (!allowsCriticalHit(true)) return false; - if (player.distanceToSqr(target) > jumpRange.get() * jumpRange.get()) return false; - return !canBeSeen.get() || player.hasLineOfSight(target); - } - - private boolean shouldAutoJumpCrit(Entity target) { - if (!shouldForceJumpCrit(target)) return false; - - KillAura killAura = Modules.get(KillAura.class); - if (killAura == null || !killAura.isEnabled()) return true; - return killAura.willAttackInTicks(JUMP_CRIT_LEAD_TICKS); - } - - private Mode getMode() { - return killAuraModeOverride != null ? killAuraModeOverride : mode.get(); - } - - private SelectionMode getSelectionMode() { - return killAuraSelectionOverride != null ? killAuraSelectionOverride : selectionMode.get(); - } - - private Entity getPreferredTarget() { - KillAura killAura = Modules.get(KillAura.class); - if (killAura != null && killAura.isEnabled() && killAura.getCurrentTarget() != null) { - return killAura.getCurrentTarget(); - } - return TargetManager.getTarget(); - } - - private void performPacketCritical(Minecraft mc, LocalPlayer player, Entity target) { - if (mc.getConnection() == null) return; - - switch (packetMode.get()) { - case VANILLA -> { - sendCriticalPacket(player, 0.2, false); - sendCriticalPacket(player, 0.01, false); - } - case NO_CHEAT_PLUS -> { - sendCriticalPacket(player, 0.11, false); - sendCriticalPacket(player, 0.1100013579, false); - sendCriticalPacket(player, 0.0000013579, false); - } - case FALLING -> { - sendCriticalPacket(player, 0.0625, false); - sendCriticalPacket(player, 0.0625013579, false); - sendCriticalPacket(player, 0.0000013579, false); - } - case LOW -> { - sendCriticalPacket(player, 1.0E-9, false); - sendCriticalPacket(player, 0.0, false); - } - case DOWN -> sendCriticalPacket(player, -1.0E-9, false); - case GRIM -> { - if (!player.onGround()) { - sendCriticalPacket(player, -1.0E-6, false); - } - } - case BLOCKSMC -> { - if (player.tickCount % 4 == 0) { - sendCriticalPacket(player, 0.0011, true); - sendCriticalPacket(player, 0.0, false); - } - } - } - } - - private void performVulcan297Critical(Minecraft mc, LocalPlayer player) { - if (mc.getConnection() == null) return; - - sendCriticalPacket(player, 0.021, false, PacketType.FULL); - sendCriticalPacket(player, 0.011, false, PacketType.FULL); - } - - private void updateVulcan297State(LocalPlayer player) { - if (getMode() != Mode.VULCAN_297) { - resetVulcan297State(); - return; - } - - if (vulcan297JumpRecoveryTicks > 0) { - vulcan297JumpRecoveryTicks--; - } - - if (player == null) { - resetVulcan297State(); - return; - } - - if (!player.onGround()) { - vulcan297WasAirborne = true; - vulcan297LandingRecoveryTicks = VULCAN_297_LANDING_RECOVERY_TICKS; - return; - } - - if (vulcan297WasAirborne && vulcan297LandingRecoveryTicks > 0) { - vulcan297LandingRecoveryTicks--; - return; - } - - vulcan297WasAirborne = false; - vulcan297LandingRecoveryTicks = 0; - } - - private boolean canPerformVulcan297Critical(LocalPlayer player) { - if (player == null || !player.onGround()) return false; - if (vulcan297JumpRecoveryTicks > 0) return false; - return vulcan297LandingRecoveryTicks <= 0; - } - - private void sendCriticalPacket(LocalPlayer player, double yOffset, boolean onGround) { - sendCriticalPacket(player, yOffset, onGround, packetType.get()); - } - - private void sendCriticalPacket(LocalPlayer player, double yOffset, boolean onGround, PacketType type) { - if (mc == null || mc.getConnection() == null || player == null) return; - - Packet packet = switch (type) { - case POSITION -> new ServerboundMovePlayerPacket.Pos( - player.getX(), - player.getY() + yOffset, - player.getZ(), - onGround, - player.horizontalCollision - ); - case FULL -> new ServerboundMovePlayerPacket.PosRot( - player.getX(), - player.getY() + yOffset, - player.getZ(), - player.getYRot(), - player.getXRot(), - onGround, - player.horizontalCollision - ); - }; - - mc.getConnection().send(packet); - } - - private boolean isAttackAlreadyPrepared(LocalPlayer player, Entity target) { - return player.tickCount == lastPreparedAttackAge && target.getId() == lastPreparedTargetId; - } - - private void markAttackPrepared(LocalPlayer player, Entity target) { - lastPreparedAttackAge = player.tickCount; - lastPreparedTargetId = target.getId(); - } - - private void resetPreparedAttack() { - lastPreparedAttackAge = -1; - lastPreparedTargetId = Integer.MIN_VALUE; - } - - private void resetVulcan297State() { - vulcan297JumpRecoveryTicks = 0; - vulcan297LandingRecoveryTicks = 0; - vulcan297WasAirborne = false; - } - - public enum Mode { - OFF, - JUMP, - PACKET, - NO_GROUND, - TIMER, - VULCAN_297 - } - - public enum SelectionMode { - SMART, - IGNORE, - ALWAYS - } - - public enum StopSprintingMode { - NONE, - LEGIT, - ON_NETWORK, - ON_ATTACK - } - - public enum PacketMode { - VANILLA, - NO_CHEAT_PLUS, - FALLING, - LOW, - DOWN, - GRIM, - BLOCKSMC - } - - public enum PacketType { - POSITION, - FULL - } - -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/ElytraTarget.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/ElytraTarget.java deleted file mode 100644 index 2ac5a53..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/ElytraTarget.java +++ /dev/null @@ -1,1711 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import dev.loki.lovisual.events.impl.*; -import dev.loki.lovisual.features.module.*; -import dev.loki.lovisual.features.module.Module; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.Direction; -import net.minecraft.core.Holder; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; -import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.boss.enderdragon.EndCrystal; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.item.enchantment.Enchantments; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.ModeValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.*; -import dev.loki.lovisual.features.module.*; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.player.ElytraRecastUtil; -import dev.loki.lovisual.util.player.inventory.FireworkUseController; -import dev.loki.lovisual.util.player.simulation.PlayerSimulationCache; -import dev.loki.lovisual.util.target.TargetManager; -import dev.loki.lovisual.util.world.ExplosionDamageUtil; - -import java.util.List; - -//todo Description -@ModuleInfo( - id = "elytratarget", - displayName = "ElytraTarget", - category = ModuleCategory.COMBAT -) -public final class ElytraTarget extends Module { - - private static final int PURSUIT_ROTATION_PRIORITY = 80; - private static final int CRYSTAL_FEAR_ROTATION_PRIORITY = 130; - private static final int BLOCK_DODGE_ROTATION_PRIORITY = 140; - private static final int FIREWORK_SYNC_PRIORITY = -1000; - private static final int FIREWORK_SPEED_FACTOR = 72; - private static final int FALL_FLYING_RESTART_DELAY_TICKS = 5; - private static final int HIT_STATUS_READY_TICKS = 5; - private static final int AUTO_TAKEOFF_COOLDOWN_TICKS = 12; - private static final double SIDE_RAYCAST_DISTANCE = 14.0; - private static final double BLOCK_DODGE_SWEEP_MARGIN = 0.08; - private static final double COLLISION_CLEARANCE_MARGIN = 1.25; - private static final double GROUND_TARGET_STILL_SPEED = 0.08; - private static final double ORBIT_MIN_RADIUS = 1.15; - private static final double ORBIT_MAX_RADIUS = 3.35; - private static final double ORBIT_ATTACK_RANGE_MARGIN = 0.22; - private static final double CRYSTAL_FEAR_SWEEP_MARGIN = 0.35; - private static final double CRYSTAL_FEAR_SAFE_DISTANCE = 7.25; - private static final double ORBIT_SIDE_SWITCH_DOT = 0.18; - private static final int TARGET_FOCUS_HOLD_TICKS = 45; - private static final double TARGET_FOCUS_RANGE_MULTIPLIER = 1.35; - private static final double[] BLOCK_DODGE_CANDIDATE_ANGLES = { - -65.0, 65.0, -105.0, 105.0, -35.0, 35.0, 180.0 - }; - private final Minecraft mc = Minecraft.getInstance(); - private final NumberValue speedThreshold = - numCommon( - "elytratargetSpeedThreshold", - "firework_speed", - CommonSettingSchemas.ELYTRA_FIREWORK_SPEED, - 30, - 0, - 100 - ); - private final BooleanValue swapBack = - boolCommon( - "elytratargetSwapBack", - "swap_back", - CommonSettingSchemas.INVENTORY_RESTORE_ITEM, - true - ); - private final BooleanValue silentSwap = - visibleWhen(boolCommon( - "elytratargetSilentSwap", - "silent_swap", - CommonSettingSchemas.ELYTRA_FIREWORK_SILENT_SWAP, - true - ), swapBack::get); - private final ModeValue targetMode = - modeSetting( - "elytratargetTargetMode", - "target_mode", - "both", - "both", - "flying", - "grounded" - ); - private final BooleanValue prepareRotations = - boolCommon( - "elytratargetPrepareRotations", - "prepare_rotations", - CommonSettingSchemas.ELYTRA_PREPARE_ROTATIONS, - true - ); - private final ModeValue pursuitMode = - modeSetting( - "elytratargetPursuitMode", - "pursuit_mode", - "auto", - "off", - "chase", - "high_pass", - "auto" - ); - private final NumberValue idealChaseDistance = - visibleWhen(num( - "elytratargetIdealChaseDistance", - "ideal_chase_distance", - 7.0f, - 2.0f, - 18.0f - ), this::isPursuitEnabled); - private final NumberValue overtakeHeight = - visibleWhen(num( - "elytratargetOvertakeHeight", - "overtake_height", - 7.0f, - 2.0f, - 18.0f - ), this::usesHighPassSettings); - private final NumberValue overtakeForward = - visibleWhen(num( - "elytratargetOvertakeForward", - "overtake_forward", - 4.0f, - 0.0f, - 16.0f - ), this::usesHighPassSettings); - private final NumberValue diveHorizontalDistance = - visibleWhen(num( - "elytratargetDiveHorizontalDistance", - "dive_horizontal_distance", - 5.0f, - 1.0f, - 12.0f - ), this::usesHighPassSettings); - private final NumberValue attackSetupSpeed = - visibleWhen(num( - "elytratargetAttackSetupSpeed", - "attack_setup_speed", - 0.75f, - 0.15f, - 3.0f - ), this::usesHighPassSettings); - private final ModeValue recastMode = - modeSetting( - "elytratargetRecastMode", - "recast_mode", - "grim", - "normal", - "grim" - ); - private final BooleanValue autoTakeoff = - bool( - "elytratargetAutoTakeoff", - "auto_takeoff", - false - ); - private final NumberValue targetRange = - visibleWhen(num( - "elytratargetTargetRange", - "target_range", - 42.0f, - 6.0f, - 96.0f - ), this::hasTargetingPurpose); - private final NumberValue targetFov = - visibleWhen(num( - "elytratargetTargetFov", - "target_fov", - 120.0f, - 10.0f, - 180.0f - ), this::hasTargetingPurpose); - private final NumberValue pursuitPredictionTicks = - visibleWhen(num( - "elytratargetPursuitPredictionTicks", - "pursuit_prediction_ticks", - 6, - 0, - 20 - ), this::hasTargetingPurpose); - private final BooleanValue solidBlockDodge = - bool( - "elytratargetSolidBlockDodge", - "solid_block_dodge", - false - ); - private final NumberValue blockDodgePredictionTicks = - visibleWhen(num( - "elytratargetBlockDodgePredictionTicks", - "block_dodge_prediction_ticks", - 10, - 3, - 30 - ), solidBlockDodge::get); - private final NumberValue blockDodgeMinDamage = - visibleWhen(num( - "elytratargetBlockDodgeMinDamage", - "block_dodge_min_damage", - 5.0f, - 1.0f, - 20.0f - ), solidBlockDodge::get); - private final NumberValue blockDodgeHealthBuffer = - visibleWhen(num( - "elytratargetBlockDodgeHealthBuffer", - "block_dodge_health_buffer", - 8.0f, - 0.0f, - 20.0f - ), solidBlockDodge::get); - private final BooleanValue crystalFear = - bool( - "elytratargetCrystalFear", - "crystal_fear", - true - ); - private final NumberValue crystalFearRange = - visibleWhen(num( - "elytratargetCrystalFearRange", - "crystal_fear_range", - 7.0f, - 3.0f, - 12.0f - ), crystalFear::get); - private final NumberValue crystalFearPredictionTicks = - visibleWhen(num( - "elytratargetCrystalFearPredictionTicks", - "crystal_fear_prediction_ticks", - 3, - 0, - 12 - ), crystalFear::get); - private final NumberValue crystalFearMinDamage = - visibleWhen(num( - "elytratargetCrystalFearMinDamage", - "crystal_fear_min_damage", - 6.0f, - 1.0f, - 20.0f - ), crystalFear::get); - private final NumberValue crystalFearHealthBuffer = - visibleWhen(num( - "elytratargetCrystalFearHealthBuffer", - "crystal_fear_health_buffer", - 7.0f, - 0.0f, - 20.0f - ), crystalFear::get); - private LivingEntity target; - private boolean preparingRotation; - private Rotation pendingRotation; - private Direction lastDirection; - private boolean attackWindowActive; - private PursuitPhase pursuitPhase = PursuitPhase.NONE; - private boolean pursuitRotationActive; - private int restartFallFlyingTicks; - private int hitStatusTicks = HIT_STATUS_READY_TICKS; - private boolean queuedFireworkUse; - private int orbitSide = 1; - private int focusedTargetId = -1; - private int targetFocusTicks; - private boolean autoTakeoffPending; - private boolean queuedAutoTakeoffJump; - private boolean queuedAutoTakeoffRelease; - private boolean queuedAutoTakeoffStartGlide; - private int autoTakeoffGlideDelayTicks; - private int autoTakeoffCooldownTicks; - - private static Vec3 horizontal(Vec3 vector) { - return new Vec3(vector.x, 0.0, vector.z); - } - - private static double horizontalDistance(Vec3 a, Vec3 b) { - return Math.hypot(a.x - b.x, a.z - b.z); - } - - private static Vec3 rotateHorizontal(Vec3 vector, double degrees) { - double radians = Math.toRadians(degrees); - double sin = Math.sin(radians); - double cos = Math.cos(radians); - return new Vec3( - vector.x * cos - vector.z * sin, - 0.0, - vector.x * sin + vector.z * cos - ); - } - - private static AABB union(AABB a, AABB b) { - return new AABB( - Math.min(a.minX, b.minX), - Math.min(a.minY, b.minY), - Math.min(a.minZ, b.minZ), - Math.max(a.maxX, b.maxX), - Math.max(a.maxY, b.maxY), - Math.max(a.maxZ, b.maxZ) - ); - } - - @Override - public void onEnable() { - resetState(); - } - - @Override - public void onDisable() { - RotationManager.INSTANCE.clear(this); - ElytraRecastUtil.INSTANCE.reset(this); - closeAttackWindow(); - resetState(); - } - - @Override - public WorldPhase getWorldPhase() { - return WorldPhase.END_MAIN; - } - - @EventHandler - private void onPostSync(EventPostSync event) { - if (!isEnabled()) return; - if (mc.player == null || mc.level == null) { - resetState(); - return; - } - - LocalPlayer player = mc.player; - if (isAttributeSwapElytraCycleActive()) { - target = null; - TargetManager.setElytraTarget(null); - clearPursuitState(); - clearAutoTakeoffState(); - queuedFireworkUse = false; - ElytraRecastUtil.INSTANCE.reset(this); - releaseRotationState(); - return; - } - - LivingEntity combatTarget = resolveCombatTarget(player); - boolean validSelf = isValidSelf(player); - boolean validTarget = isValidTarget(combatTarget); - - target = validSelf && validTarget ? combatTarget : null; - updateTargetFocus(target); - TargetManager.setElytraTarget(target); - boolean emergencyAvoidQueued = queueEmergencyAvoidanceRotation(player); - - if (!validSelf || !validTarget) { - clearPursuitState(); - queuedFireworkUse = false; - if (!emergencyAvoidQueued) { - releaseRotationState(); - } - } else { - updatePursuitPhase(player, target); - tickRestartFallFlying(player); - } - - if (emergencyAvoidQueued) { - clearPursuitState(); - queuedFireworkUse = false; - } - } - - @EventHandler(priority = -10) - private void onGameTick(GameTickEvent event) { - if (!isEnabled()) return; - LocalPlayer player = mc.player; - if (player == null || mc.level == null) { - resetState(); - return; - } - - if (hitStatusTicks < HIT_STATUS_READY_TICKS) { - hitStatusTicks++; - } - ElytraRecastUtil.INSTANCE.tick(this, player); - - if (isAttributeSwapElytraCycleActive()) { - queuedFireworkUse = false; - clearPursuitState(); - clearAutoTakeoffState(); - ElytraRecastUtil.INSTANCE.reset(this); - releaseRotationState(); - return; - } - - tickAutoTakeoff(player); - - boolean emergencyAvoidQueued = queueEmergencyAvoidanceRotation(player); - - if (!isRunning()) { - queuedFireworkUse = false; - clearPursuitState(); - if (!ElytraRecastUtil.INSTANCE.isActive(this)) { - ElytraRecastUtil.INSTANCE.reset(this); - } - if (!emergencyAvoidQueued) { - releaseRotationState(); - } - return; - } - - if (emergencyAvoidQueued) { - queuedFireworkUse = false; - clearPursuitState(); - return; - } - - updatePursuitPhase(player, target); - if (shouldUseFirework(player)) { - queuedFireworkUse = true; - } - } - - @EventHandler(priority = FIREWORK_SYNC_PRIORITY) - private void onSyncFirework(EventSync event) { - if (!queuedFireworkUse || !isEnabled()) return; - queuedFireworkUse = false; - - LocalPlayer player = mc.player; - if (player == null || !isRunning()) return; - if (!shouldUseFirework(player)) return; - - FireworkUseController.INSTANCE.use( - event.getYaw(), - event.getPitch(), - true, - swapBack.get(), - silentSwap.get(), - speedThreshold.get(), - true - ); - } - - @EventHandler(priority = FIREWORK_SYNC_PRIORITY - 20) - private void onMovementInput(MovementInputEvent event) { - if (!isEnabled()) return; - if (handleAutoTakeoffMovementInput(event)) return; - ElytraRecastUtil.INSTANCE.handleMovementInput(this, event); - } - - @EventHandler(priority = FIREWORK_SYNC_PRIORITY - 20) - private void onSyncRecast(EventSync event) { - if (!isEnabled()) return; - if (handleAutoTakeoffSync(event)) return; - ElytraRecastUtil.INSTANCE.handleSync(this, event); - } - - @EventHandler(priority = 0) - private void onRotationUpdate(RotationUpdateEvent event) { - if (!isEnabled() || event.getType() != RotationUpdateEvent.Type.PRE) return; - LocalPlayer player = mc.player; - if (player == null || mc.level == null) { - clearPursuitState(); - return; - } - - if (queueEmergencyAvoidanceRotation(player)) { - pursuitRotationActive = false; - return; - } - - if (!isRunning()) { - pursuitRotationActive = false; - return; - } - - updatePursuitPhase(player, target); - Rotation pursuitRotation = calculatePursuitRotation(player, target); - if (pursuitRotation == null) { - pursuitRotationActive = false; - return; - } - - pendingRotation = pursuitRotation; - pursuitRotationActive = true; - RotationTarget plan = new RotationTarget( - pursuitRotation.normalize(), - target, - List.of(), - 2, - 2.0f, - true, - MovementCorrection.SILENT, - true, - null - ); - RotationManager.INSTANCE.setRotationTarget(plan, PURSUIT_ROTATION_PRIORITY, this); - } - - @EventHandler - private void onPacketReceive(PacketEvent.Receive event) { - if (!isEnabled()) return; - if (!(event.getPacket() instanceof ClientboundEntityEventPacket packet)) return; - LivingEntity currentTarget = target; - if (currentTarget == null || mc.level == null) return; - - if (packet.getEntity(mc.level) == currentTarget - && (packet.getEventId() == 0 || packet.getEventId() == 3)) { - hitStatusTicks = 0; - } - } - - public LivingEntity getTarget() { - return target; - } - - public boolean isRunning() { - return isEnabled() - && mc.player != null - && mc.player.isFallFlying() - && target != null - && hasKillAuraGate() - && !isAttributeSwapElytraCycleActive(); - } - - public boolean canIgnoreKillAuraRotations() { - return isRunning() && (pursuitRotationActive || preparingRotation || attackWindowActive || pendingRotation != null); - } - - public boolean isManagingFireworks() { - return isRunning(); - } - - private void resetState() { - ElytraRecastUtil.INSTANCE.reset(this); - target = null; - TargetManager.setElytraTarget(null); - preparingRotation = false; - pendingRotation = null; - lastDirection = null; - attackWindowActive = false; - pursuitPhase = PursuitPhase.NONE; - pursuitRotationActive = false; - restartFallFlyingTicks = 0; - hitStatusTicks = HIT_STATUS_READY_TICKS; - queuedFireworkUse = false; - orbitSide = 1; - focusedTargetId = -1; - targetFocusTicks = 0; - autoTakeoffPending = false; - queuedAutoTakeoffJump = false; - queuedAutoTakeoffRelease = false; - queuedAutoTakeoffStartGlide = false; - autoTakeoffGlideDelayTicks = 0; - autoTakeoffCooldownTicks = 0; - } - - private LivingEntity resolveCombatTarget(LocalPlayer player) { - if (player == null || !hasKillAuraGate() || !hasTargetingPurpose()) { - return null; - } - - KillAura killAura = Modules.get(KillAura.class); - - TargetCandidate focused = evaluateFocusedTargetCandidate(player, target); - if (focused != null) { - return focused.entity(); - } - - TargetCandidate recentlyAttacked = evaluateFocusedTargetCandidate(player, resolveRecentAttackTarget()); - if (recentlyAttacked != null) { - return recentlyAttacked.entity(); - } - - LivingEntity auraTarget = killAura.getCurrentTarget(); - TargetCandidate current = evaluateTargetCandidate(player, auraTarget, true, false); - if (current != null) { - return current.entity(); - } - - LivingEntity best = null; - double bestScore = Double.POSITIVE_INFINITY; - for (LivingEntity candidate : killAura.findElytraTargetCandidates(targetRange.get(), targetFov.get())) { - TargetCandidate evaluated = evaluateTargetCandidate(player, candidate, false, false); - if (evaluated == null) continue; - if (evaluated.score() < bestScore) { - bestScore = evaluated.score(); - best = evaluated.entity(); - } - } - return best; - } - - private boolean hasKillAuraGate() { - KillAura killAura = Modules.get(KillAura.class); - return killAura != null && killAura.isEnabled(); - } - - private void updateTargetFocus(LivingEntity currentTarget) { - if (currentTarget != null) { - focusedTargetId = currentTarget.getId(); - targetFocusTicks = TARGET_FOCUS_HOLD_TICKS; - return; - } - - if (targetFocusTicks > 0) { - targetFocusTicks--; - if (targetFocusTicks <= 0) { - focusedTargetId = -1; - } - } else { - focusedTargetId = -1; - } - } - - private boolean isFocusedCandidate(LivingEntity candidate) { - return candidate != null - && targetFocusTicks > 0 - && focusedTargetId >= 0 - && candidate.getId() == focusedTargetId; - } - - private LivingEntity resolveRecentAttackTarget() { - if (TargetManager.getTargetSource() != TargetManager.Source.ATTACK) { - return null; - } - return TargetManager.getTarget(); - } - - private boolean isRecentAttackTarget(LivingEntity candidate) { - LivingEntity attacked = resolveRecentAttackTarget(); - return candidate != null && attacked != null && candidate.getId() == attacked.getId(); - } - - private TargetCandidate evaluateFocusedTargetCandidate(LocalPlayer player, LivingEntity candidate) { - if (candidate == null) return null; - if (!isFocusedCandidate(candidate) && !isRecentAttackTarget(candidate)) return null; - return evaluateTargetCandidate(player, candidate, true, true); - } - - private TargetCandidate evaluateTargetCandidate(LocalPlayer player, LivingEntity candidate, boolean currentAuraTarget, boolean focusBypass) { - if (player == null || !isValidTarget(candidate)) return null; - - boolean focused = focusBypass && (isFocusedCandidate(candidate) || isRecentAttackTarget(candidate)); - Vec3 predictedCenter = predictTargetCenter(candidate, pursuitPredictionTicks.get()); - double maxRange = Math.max(1.0, targetRange.get()); - if (focused) { - maxRange *= TARGET_FOCUS_RANGE_MULTIPLIER; - } - double distanceSq = player.getEyePosition().distanceToSqr(predictedCenter); - if (distanceSq > maxRange * maxRange) return null; - - float angle = angleToPredictedPoint(player, predictedCenter); - float maxFov = Mth.clamp(targetFov.get(), 1.0f, 180.0f); - if (!focused && maxFov < 180.0f && angle > maxFov * 0.5f) return null; - - Reachability reachability = evaluateReachability(player, candidate, predictedCenter); - if (reachability == null) return null; - - double score = distanceSq - + (focused ? 0.0 : angle * angle * 0.18) - + (reachability.raised() ? 36.0 : 0.0) - + (currentAuraTarget ? -64.0 : 0.0) - + (focused ? -192.0 : 0.0) - + (candidate == target ? -48.0 : 0.0); - return new TargetCandidate(candidate, predictedCenter, reachability.point(), score); - } - - private float angleToPredictedPoint(LocalPlayer player, Vec3 point) { - Rotation rotation = Rotation.lookingAt(point, player.getEyePosition()).normalize(); - return Math.abs(Mth.wrapDegrees(rotation.yaw() - player.getYRot())); - } - - private Reachability evaluateReachability(LocalPlayer player, LivingEntity candidate, Vec3 predictedCenter) { - if (player == null || candidate == null || mc.level == null) return null; - - if (isApproachCorridorClear(player, predictedCenter)) { - return new Reachability(predictedCenter, false); - } - - Vec3 playerPos = player.position(); - Vec3 horizontalToTarget = horizontal(predictedCenter.subtract(playerPos)); - Vec3 direction = horizontalToTarget.lengthSqr() > 1.0E-5 - ? horizontalToTarget.normalize() - : horizontal(player.getViewVector(1.0f)).normalize(); - if (direction.lengthSqr() < 1.0E-5) { - direction = new Vec3(0.0, 0.0, 1.0); - } - - double highPassHeight = usesHighPassSettings() - ? Math.max(2.0, overtakeHeight.get()) - : Math.max(3.0, candidate.getBoundingBox().getYsize() + 2.0); - double forward = usesHighPassSettings() - ? Math.max(0.0, overtakeForward.get()) - : 3.0; - Vec3 highApproach = predictedCenter - .add(direction.scale(forward)) - .add(0.0, highPassHeight, 0.0); - - if (isApproachCorridorClear(player, highApproach) && isRayClear(player, highApproach, predictedCenter)) { - return new Reachability(highApproach, true); - } - - return null; - } - - private boolean isAttributeSwapElytraCycleActive() { - AttributeSwap attributeSwap = Modules.get(AttributeSwap.class); - return attributeSwap != null && attributeSwap.isElytraCycleActive(); - } - - private boolean isValidSelf(LocalPlayer player) { - return player != null - && player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA) - && player.isFallFlying(); - } - - private boolean isValidTarget(LivingEntity entity) { - if (!(entity instanceof Player playerTarget)) return false; - if (!entity.isAlive() || entity.isRemoved()) return false; - - String mode = String.valueOf(targetMode.get()); - if ("flying".equals(mode)) { - return playerTarget.isFallFlying(); - } - if ("grounded".equals(mode)) { - return !playerTarget.isFallFlying(); - } - return true; - } - - private boolean isPursuitEnabled() { - return !"off".equals(pursuitMode.get()); - } - - private boolean isAutoTakeoffEnabled() { - return autoTakeoff.get(); - } - - private boolean hasTargetingPurpose() { - return isPursuitEnabled() || isAutoTakeoffEnabled(); - } - - private boolean usesHighPassSettings() { - String mode = pursuitMode.get(); - return "high_pass".equals(mode) || "auto".equals(mode); - } - - private void updatePursuitPhase(LocalPlayer player, LivingEntity currentTarget) { - if (!isPursuitEnabled() || player == null || currentTarget == null) { - clearPursuitState(); - return; - } - - boolean wantsHighPass = wantsHighPass(player, currentTarget); - if (!wantsHighPass) { - pursuitPhase = PursuitPhase.CHASE; - preparingRotation = false; - attackWindowActive = false; - return; - } - - Vec3 targetPoint = predictTargetCenter(currentTarget, pursuitPredictionTicks.get()); - Vec3 playerPos = player.position(); - double horizontalDistance = horizontalDistance(playerPos, targetPoint); - double heightAboveTarget = playerPos.y - targetPoint.y; - double horizontalSpeed = player.getDeltaMovement().horizontalDistance(); - double wantedHeight = Math.max(1.0, overtakeHeight.get()); - double diveDistance = Math.max(1.0, diveHorizontalDistance.get()); - - boolean highEnough = heightAboveTarget >= wantedHeight * 0.55; - boolean closeEnough = horizontalDistance <= diveDistance; - boolean fastEnough = horizontalSpeed >= attackSetupSpeed.get() || player.fallDistance >= 1.4f; - boolean descending = player.getDeltaMovement().y <= -0.03 || player.fallDistance >= 1.2f; - - if (highEnough && closeEnough && (fastEnough || descending)) { - pursuitPhase = PursuitPhase.DIVE; - preparingRotation = false; - attackWindowActive = true; - return; - } - - if (heightAboveTarget < wantedHeight * 0.35 || player.getDeltaMovement().y < -0.18) { - pursuitPhase = PursuitPhase.CLIMB; - } else { - pursuitPhase = PursuitPhase.OVERPASS; - } - preparingRotation = prepareRotations.get(); - attackWindowActive = false; - } - - private void clearPursuitState() { - preparingRotation = false; - pendingRotation = null; - attackWindowActive = false; - pursuitPhase = PursuitPhase.NONE; - pursuitRotationActive = false; - } - - private void closeAttackWindow() { - attackWindowActive = false; - } - - private Rotation calculatePursuitRotation(LocalPlayer player, LivingEntity currentTarget) { - if (!isPursuitEnabled() || player == null || currentTarget == null || pursuitPhase == PursuitPhase.NONE) { - return null; - } - - Vec3 point = calculatePursuitPoint(player, currentTarget); - if (point == null) return null; - - point = adjustPursuitPointForCrystalFear(player, point); - if (solidBlockDodge.get()) { - point = adjustPursuitPointForCollision(player, point); - } - - return Rotation.lookingAt(point, player.getEyePosition()).normalize(); - } - - private Vec3 calculatePursuitPoint(LocalPlayer player, LivingEntity currentTarget) { - Vec3 targetCenter = predictTargetCenter(currentTarget, pursuitPredictionTicks.get()); - Vec3 playerPos = player.position(); - Vec3 horizontalToTarget = horizontal(targetCenter.subtract(playerPos)); - double horizontalDistance = horizontalToTarget.length(); - Vec3 direction = horizontalDistance > 1.0E-4 - ? horizontalToTarget.scale(1.0 / horizontalDistance) - : horizontal(player.getViewVector(1.0f)); - if (direction.lengthSqr() < 1.0E-5) { - direction = new Vec3(0.0, 0.0, 1.0); - } else { - direction = direction.normalize(); - } - - return switch (pursuitPhase) { - case CLIMB -> targetCenter - .add(direction.scale(Math.max(1.0, overtakeForward.get() * 0.65))) - .add(0.0, Math.max(2.0, overtakeHeight.get()), 0.0); - case OVERPASS -> targetCenter - .add(direction.scale(Math.max(0.0, overtakeForward.get()))) - .add(0.0, Math.max(1.5, overtakeHeight.get() * 0.75), 0.0); - case DIVE -> targetCenter.add(0.0, currentTarget.getBoundingBox().getYsize() * -0.15, 0.0); - case CHASE -> calculateDirectChasePoint(player, currentTarget, targetCenter, direction, horizontalDistance); - case NONE -> null; - }; - } - - private Vec3 calculateDirectChasePoint(LocalPlayer player, - LivingEntity currentTarget, - Vec3 targetCenter, - Vec3 direction, - double horizontalDistance) { - if (shouldUseNoRotationOrbit(player, currentTarget, horizontalDistance)) { - return calculateNoRotationOrbitPoint(player, currentTarget, targetCenter, direction, horizontalDistance); - } - - double attackBand = getAuraAttackBand(currentTarget); - double configuredDistance = Math.max(2.0, idealChaseDistance.get()); - double idealDistance = Mth.clamp(configuredDistance, attackBand * 0.85, Math.max(attackBand * 1.55, attackBand + 1.0)); - double passThrough = horizontalDistance < idealDistance - ? Mth.clamp(idealDistance - horizontalDistance, 0.45, Math.max(1.2, attackBand * 0.7)) - : Math.min(Math.max(1.15, attackBand * 0.55), horizontalDistance * 0.16); - double lift = player.getDeltaMovement().y < -0.22 ? 1.5 : 0.0; - return targetCenter.add(direction.scale(passThrough)).add(0.0, lift, 0.0); - } - - private boolean shouldUseNoRotationOrbit(LocalPlayer player, LivingEntity currentTarget, double horizontalDistance) { - if (!shouldOwnAuraNoRotation()) return false; - if (player == null || currentTarget == null) return false; - if (currentTarget.isFallFlying()) return false; - - double attackBand = getAuraAttackBand(currentTarget); - boolean targetIsStill = currentTarget.getDeltaMovement().horizontalDistance() <= GROUND_TARGET_STILL_SPEED; - boolean targetIsGrounded = currentTarget.onGround() || currentTarget.fallDistance < 0.15f; - boolean alreadyInCombatBand = horizontalDistance <= attackBand * 2.35; - return (targetIsStill || targetIsGrounded) && alreadyInCombatBand; - } - - private Vec3 calculateNoRotationOrbitPoint(LocalPlayer player, - LivingEntity currentTarget, - Vec3 targetCenter, - Vec3 direction, - double horizontalDistance) { - updateOrbitSide(player, direction); - - double attackBand = getAuraAttackBand(currentTarget); - double attackRange = getAuraAttackRange(currentTarget); - double maxOrbitRadius = Math.max(ORBIT_MIN_RADIUS, Math.min(ORBIT_MAX_RADIUS, attackRange - ORBIT_ATTACK_RANGE_MARGIN)); - double orbitRadius = Mth.clamp(attackBand * 0.38, ORBIT_MIN_RADIUS, maxOrbitRadius); - if (horizontalDistance < attackBand * 0.78) { - orbitRadius = Math.min(maxOrbitRadius, orbitRadius + (attackBand * 0.78 - horizontalDistance) * 0.22); - } - if (horizontalDistance > attackBand * 1.45) { - orbitRadius *= 0.55; - } - - double forwardLead = Mth.clamp(horizontalDistance - attackBand * 0.72, 0.35, Math.max(1.15, attackBand * 0.78)); - if (currentTarget.getDeltaMovement().horizontalDistance() <= GROUND_TARGET_STILL_SPEED) { - forwardLead = Math.min(forwardLead, Math.max(0.75, attackRange * 0.55)); - } - - Vec3 tangent = new Vec3(-direction.z, 0.0, direction.x).normalize().scale(orbitSide * orbitRadius); - double targetHeight = currentTarget.getBoundingBox().getYsize(); - double verticalLead = Mth.clamp((targetCenter.y - player.getEyeY()) * 0.35, -0.65, 1.15); - if (player.getDeltaMovement().y < -0.18) { - verticalLead += 0.65; - } - - return targetCenter - .add(direction.scale(forwardLead)) - .add(tangent) - .add(0.0, Math.max(-0.35, targetHeight * 0.18 + verticalLead), 0.0); - } - - private void updateOrbitSide(LocalPlayer player, Vec3 direction) { - if (player == null || direction == null || direction.lengthSqr() < 1.0E-5) return; - - Vec3 tangent = new Vec3(-direction.z, 0.0, direction.x).normalize(); - Vec3 velocity = horizontal(player.getDeltaMovement()); - if (velocity.lengthSqr() > 0.015 * 0.015) { - double dot = velocity.normalize().dot(tangent); - if (Math.abs(dot) > ORBIT_SIDE_SWITCH_DOT) { - orbitSide = dot >= 0.0 ? 1 : -1; - return; - } - } - - Vec3 look = horizontal(player.getViewVector(1.0f)); - if (look.lengthSqr() > 1.0E-5) { - double dot = look.normalize().dot(tangent); - if (Math.abs(dot) > ORBIT_SIDE_SWITCH_DOT * 1.35) { - orbitSide = dot >= 0.0 ? 1 : -1; - } - } - } - - private boolean shouldOwnAuraNoRotation() { - KillAura killAura = Modules.get(KillAura.class); - return killAura != null && killAura.isNoRotationMode(); - } - - private double getAuraAttackRange(LivingEntity currentTarget) { - KillAura killAura = Modules.get(KillAura.class); - if (killAura == null || currentTarget == null) { - return 3.0; - } - return Mth.clamp(killAura.getEffectiveRange(currentTarget), 1.0, 6.0); - } - - private double getAuraAttackBand(LivingEntity currentTarget) { - double targetRadius = currentTarget == null - ? 0.3 - : Math.max(currentTarget.getBoundingBox().getXsize(), currentTarget.getBoundingBox().getZsize()) * 0.5; - return Math.max(1.4, getAuraAttackRange(currentTarget) + targetRadius - 0.18); - } - - private Vec3 adjustPursuitPointForCrystalFear(LocalPlayer player, Vec3 point) { - if (player == null || point == null || !crystalFear.get()) return point; - CrystalThreat threat = findCrystalThreat(player, point); - if (threat == null) return point; - - Vec3 away = horizontal(point.subtract(threat.pos())); - if (away.lengthSqr() < 1.0E-5) { - away = horizontal(player.getEyePosition().subtract(threat.pos())); - } - if (away.lengthSqr() < 1.0E-5) { - away = horizontal(player.getDeltaMovement()); - } - if (away.lengthSqr() < 1.0E-5) { - away = horizontal(player.getViewVector(1.0f)); - } - if (away.lengthSqr() < 1.0E-5) { - return point.add(0.0, 3.0, 0.0); - } - - Vec3 safeDirection = away.normalize(); - double lift = threat.damage() >= player.getHealth() + player.getAbsorptionAmount() * 0.5f ? 4.0 : 2.25; - return point - .add(safeDirection.scale(Math.max(2.0, CRYSTAL_FEAR_SAFE_DISTANCE - threat.distance()))) - .add(0.0, lift, 0.0); - } - - private Vec3 adjustPursuitPointForCollision(LocalPlayer player, Vec3 point) { - if (mc.level == null) return point; - if (isRayPathClear(player, point)) return point; - - double[] lifts = {2.0, 4.0, 7.0, 10.0}; - for (double lift : lifts) { - Vec3 lifted = point.add(0.0, lift, 0.0); - if (isRayPathClear(player, lifted)) { - return lifted; - } - } - - Rotation side = findFreeSideRotation(player); - Vec3 sideDirection = side.directionVector(); - return player.getEyePosition() - .add(sideDirection.scale(SIDE_RAYCAST_DISTANCE)) - .add(0.0, Math.max(2.0, overtakeHeight.get() * 0.5), 0.0); - } - - private boolean isRayPathClear(LocalPlayer player, Vec3 point) { - return isApproachCorridorClear(player, point); - } - - private boolean isApproachCorridorClear(LocalPlayer player, Vec3 point) { - if (player == null || mc.level == null || point == null) return false; - - Vec3 eye = player.getEyePosition(); - if (!isRayClear(player, eye, point)) return false; - - Vec3 direction = horizontal(point.subtract(eye)); - if (direction.lengthSqr() < 1.0E-5) return true; - direction = direction.normalize(); - Vec3 side = new Vec3(-direction.z, 0.0, direction.x).scale(0.42); - Vec3 body = player.getBoundingBox().getCenter(); - Vec3 low = new Vec3(body.x, player.getBoundingBox().minY + 0.35, body.z); - Vec3 high = new Vec3(body.x, player.getBoundingBox().minY + player.getBoundingBox().getYsize() * 0.85, body.z); - - return isRayClear(player, low.add(side), point.add(side)) - && isRayClear(player, low.subtract(side), point.subtract(side)) - && isRayClear(player, high, point.add(0.0, 0.35, 0.0)); - } - - private boolean isRayClear(LocalPlayer player, Vec3 from, Vec3 to) { - if (player == null || mc.level == null || from == null || to == null) return false; - HitResult hit = mc.level.clip(new ClipContext( - from, - to, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - if (hit.getType() == HitResult.Type.MISS) { - return true; - } - return hit.getLocation().distanceToSqr(from) + COLLISION_CLEARANCE_MARGIN * COLLISION_CLEARANCE_MARGIN - >= to.distanceToSqr(from); - } - - private boolean wantsHighPass(LocalPlayer player, LivingEntity currentTarget) { - String mode = pursuitMode.get(); - if ("high_pass".equals(mode)) return prepareRotations.get(); - if (!"auto".equals(mode) || !prepareRotations.get()) return false; - if (currentTarget instanceof Player targetPlayer && targetPlayer.isFallFlying()) { - return false; - } - return canSetupMaceDive(player); - } - - private boolean canSetupMaceDive(LocalPlayer player) { - AttributeSwap attributeSwap = Modules.get(AttributeSwap.class); - if (attributeSwap == null || !attributeSwap.isEnabled()) return false; - if (player == null || player.isUsingItem()) return false; - for (int i = 0; i < 36; i++) { - if (player.getInventory().getItem(i).is(Items.MACE)) { - return true; - } - } - return player.getMainHandItem().is(Items.MACE) || player.getOffhandItem().is(Items.MACE); - } - - private Vec3 predictTargetCenter(LivingEntity currentTarget, int ticks) { - int safeTicks = Mth.clamp(ticks, 0, 20); - Vec3 base = currentTarget.getBoundingBox().getCenter(); - if (safeTicks <= 0) { - return base; - } - - if (currentTarget instanceof Player playerTarget) { - PlayerSimulationCache.SimulatedPlayerCache simulation = PlayerSimulationCache.getSimulationForOtherPlayers(playerTarget); - PlayerSimulationCache.SimulatedPlayerSnapshot snapshot = simulation.getSnapshotAt(safeTicks); - Vec3 delta = snapshot.pos().subtract(playerTarget.position()); - return base.add(delta); - } - - return base.add(currentTarget.getDeltaMovement().scale(safeTicks)); - } - - private void tickAutoTakeoff(LocalPlayer player) { - if (autoTakeoffCooldownTicks > 0) { - autoTakeoffCooldownTicks--; - } - if (autoTakeoffGlideDelayTicks > 0) { - autoTakeoffGlideDelayTicks--; - } - - if (!isAutoTakeoffEnabled()) { - clearAutoTakeoffState(); - return; - } - - if (player == null || mc.level == null || isAttributeSwapElytraCycleActive()) { - clearAutoTakeoffState(); - return; - } - - if (player.isFallFlying()) { - if (autoTakeoffPending) { - autoTakeoffCooldownTicks = AUTO_TAKEOFF_COOLDOWN_TICKS; - } - clearAutoTakeoffState(); - return; - } - - if (!canAutoTakeoffSelf(player) || !hasAutoTakeoffTarget(player)) { - clearAutoTakeoffState(); - return; - } - - if (!autoTakeoffPending) { - if (autoTakeoffCooldownTicks > 0) return; - autoTakeoffPending = true; - if (canAutoTakeoffJumpNow(player)) { - queueAutoTakeoffJump(); - autoTakeoffGlideDelayTicks = player.onGround() ? 1 : 0; - } - } - - if (player.onGround() || player.isInWater() || player.isInLava()) { - queueAutoTakeoffJump(); - queuedAutoTakeoffStartGlide = false; - queuedAutoTakeoffRelease = false; - if (autoTakeoffGlideDelayTicks <= 0) { - autoTakeoffGlideDelayTicks = 1; - } - return; - } - - if (autoTakeoffGlideDelayTicks > 0) return; - if (player.getDeltaMovement().y > 0.0 && player.fallDistance <= 0.0f) return; - if (queuedAutoTakeoffStartGlide || queuedAutoTakeoffRelease) return; - - queuedAutoTakeoffRelease = true; - queuedAutoTakeoffStartGlide = true; - } - - private boolean canAutoTakeoffSelf(LocalPlayer player) { - if (player == null) return false; - if (player.isFallFlying()) return false; - if (player.isPassenger()) return false; - if (player.getAbilities().flying) return false; - if (player.onClimbable()) return false; - return player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA); - } - - private boolean hasAutoTakeoffTarget(LocalPlayer player) { - if (player == null || !hasKillAuraGate()) return false; - LivingEntity candidate = resolveCombatTarget(player); - return isValidTarget(candidate); - } - - private boolean canAutoTakeoffJumpNow(LocalPlayer player) { - return player != null - && !player.isPassenger() - && !player.getAbilities().flying - && (player.onGround() || player.isInWater() || player.isInLava()); - } - - private void queueAutoTakeoffJump() { - queuedAutoTakeoffJump = true; - } - - private void clearAutoTakeoffState() { - autoTakeoffPending = false; - queuedAutoTakeoffJump = false; - queuedAutoTakeoffRelease = false; - queuedAutoTakeoffStartGlide = false; - autoTakeoffGlideDelayTicks = 0; - } - - private boolean handleAutoTakeoffMovementInput(MovementInputEvent event) { - if (queuedAutoTakeoffRelease) { - event.setJump(false); - queuedAutoTakeoffRelease = false; - return true; - } - - if (queuedAutoTakeoffJump) { - event.setJump(true); - queuedAutoTakeoffJump = false; - return true; - } - - return false; - } - - private boolean handleAutoTakeoffSync(EventSync event) { - if (!queuedAutoTakeoffStartGlide) return false; - - LocalPlayer player = mc.player; - if (player == null) { - clearAutoTakeoffState(); - return false; - } - - if (player.isFallFlying()) { - clearAutoTakeoffState(); - autoTakeoffCooldownTicks = AUTO_TAKEOFF_COOLDOWN_TICKS; - return true; - } - - if (!canAutoTakeoffSelf(player)) { - clearAutoTakeoffState(); - return false; - } - - if (!player.onGround() - && !player.isInWater() - && !player.isInLava() - && player.getDeltaMovement().y <= 0.0) { - queuedAutoTakeoffStartGlide = false; - - if (player.tryToStartFallFlying()) { - queuedAutoTakeoffJump = true; - } - - if (player.isFallFlying() && mc.getConnection() != null) { - mc.getConnection().send( - new ServerboundPlayerCommandPacket(player, ServerboundPlayerCommandPacket.Action.START_FALL_FLYING) - ); - clearAutoTakeoffState(); - autoTakeoffCooldownTicks = AUTO_TAKEOFF_COOLDOWN_TICKS; - } else { - autoTakeoffGlideDelayTicks = 1; - } - return true; - } - - if (player.onGround() || player.isInWater() || player.isInLava()) { - queuedAutoTakeoffStartGlide = false; - queuedAutoTakeoffRelease = false; - } - - return false; - } - - private void releaseRotationState() { - RotationManager.INSTANCE.release(this, true); - } - - private void tickRestartFallFlying(LocalPlayer player) { - if (restartFallFlyingTicks > 0) { - restartFallFlyingTicks--; - return; - } - - if (player == null || player.onGround() || player.isFallFlying()) return; - if (!player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA)) return; - if (!hasFireworkRocket(player)) return; - if (ElytraRecastUtil.INSTANCE.isActive(this)) return; - - ElytraRecastUtil.INSTANCE.request( - this, - player, - ElytraRecastUtil.Mode.from(recastMode.get()), - false, - false, - false, - 0 - ); - ElytraRecastUtil.INSTANCE.tick(this, player); - restartFallFlyingTicks = FALL_FLYING_RESTART_DELAY_TICKS; - } - - private boolean shouldUseFirework(LocalPlayer player) { - if (player == null || !player.isFallFlying()) return false; - if (player.isUsingItem()) return false; - if (!hasFireworkRocket(player)) return false; - int threshold = speedThreshold.get(); - if (threshold <= 0) return false; - if (FireworkUseController.INSTANCE.isCooling(threshold)) return false; - - double currentSpeed = player.getDeltaMovement().horizontalDistance() * FIREWORK_SPEED_FACTOR; - if (currentSpeed < threshold) return true; - - if (pursuitPhase == PursuitPhase.CLIMB || pursuitPhase == PursuitPhase.OVERPASS) { - return currentSpeed < threshold * 1.25; - } - return false; - } - - private boolean hasFireworkRocket(LocalPlayer player) { - if (player == null) return false; - if (player.getOffhandItem().is(Items.FIREWORK_ROCKET)) return true; - for (int i = 0; i < 36; i++) { - if (player.getInventory().getItem(i).is(Items.FIREWORK_ROCKET)) return true; - } - return false; - } - - private Rotation findFreeSideRotation(LocalPlayer player) { - if (player == null || mc.level == null) { - return new Rotation(0.0f, -88.0f); - } - - Vec3 eye = player.getEyePosition(); - for (Direction direction : Direction.values()) { - if (direction == lastDirection) continue; - - Vec3 offset = Vec3.atLowerCornerOf(direction.getUnitVec3i()).scale(SIDE_RAYCAST_DISTANCE); - Vec3 lowEnd = eye.add(offset); - Vec3 highStart = eye.add(0.0, player.getBoundingBox().getYsize(), 0.0); - Vec3 highEnd = highStart.add(offset); - - HitResult lowRay = mc.level.clip(new ClipContext( - eye, - lowEnd, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - HitResult highRay = mc.level.clip(new ClipContext( - highStart, - highEnd, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - - if (lowRay.getType() == HitResult.Type.MISS && highRay.getType() == HitResult.Type.MISS) { - lastDirection = direction; - return Rotation.lookingAt(lowEnd, eye).normalize(); - } - } - - Rotation server = RotationManager.INSTANCE.getServerRotation(); - float yaw = server != null ? server.yaw() : player.getYRot(); - return new Rotation(yaw, -88.0f).normalize(); - } - - private boolean queueEmergencyAvoidanceRotation(LocalPlayer player) { - if (queueBlockDodgeRotation(player)) { - return true; - } - return queueCrystalFearRotation(player); - } - - private boolean queueCrystalFearRotation(LocalPlayer player) { - if (!crystalFear.get()) return false; - if (!isValidCrystalFearSelf(player)) return false; - - CrystalThreat threat = findCrystalThreat(player, null); - if (threat == null) return false; - - Rotation crystalFearRotation = findCrystalFearRotation(player, threat); - if (crystalFearRotation == null) return false; - - RotationTarget plan = new RotationTarget( - crystalFearRotation.normalize(), - null, - List.of(), - 2, - 2.0f, - true, - MovementCorrection.SILENT, - false, - null - ); - RotationManager.INSTANCE.setRotationTarget(plan, CRYSTAL_FEAR_ROTATION_PRIORITY, this); - return true; - } - - private boolean isValidCrystalFearSelf(LocalPlayer player) { - return player != null - && mc.level != null - && player.isFallFlying() - && !player.isPassenger() - && player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA); - } - - private CrystalThreat findCrystalThreat(LocalPlayer player, Vec3 plannedPoint) { - if (player == null || mc.level == null) return null; - - double range = Math.max(1.0, crystalFearRange.get()); - double rangeSq = range * range; - Vec3 eye = player.getEyePosition(); - Vec3 predictedSelf = predictSelfCrystalPosition(player); - Vec3 planned = plannedPoint != null ? plannedPoint : predictedSelf; - CrystalThreat best = null; - double bestScore = Double.NEGATIVE_INFINITY; - - for (var entity : mc.level.entitiesForRendering()) { - if (!(entity instanceof EndCrystal crystal)) continue; - if (!crystal.isAlive() || crystal.isRemoved()) continue; - - Vec3 crystalPos = crystal.position(); - double distanceSq = crystalPos.distanceToSqr(eye); - double plannedDistanceSq = crystalPos.distanceToSqr(planned); - if (distanceSq > rangeSq && plannedDistanceSq > rangeSq) continue; - - float damage = ExplosionDamageUtil.getCrystalDamage( - player, - crystalPos, - Mth.clamp(crystalFearPredictionTicks.get(), 0, 12), - true - ); - if (!isDangerousCrystalDamage(player, damage)) continue; - - double distance = Math.sqrt(Math.min(distanceSq, plannedDistanceSq)); - double score = damage * 100.0 + Math.max(0.0, range - distance) * 5.0; - if (plannedDistanceSq < distanceSq) { - score += 24.0; - } - if (score > bestScore) { - bestScore = score; - best = new CrystalThreat(crystal, crystalPos, damage, distance); - } - } - - return best; - } - - private Vec3 predictSelfCrystalPosition(LocalPlayer player) { - Vec3 predicted = player.getEyePosition(); - Vec3 velocity = player.getDeltaMovement(); - int ticks = Mth.clamp(crystalFearPredictionTicks.get(), 0, 12); - for (int i = 0; i < ticks; i++) { - predicted = predicted.add(velocity); - velocity = approximateNextElytraVelocity(velocity); - } - return predicted; - } - - private boolean isDangerousCrystalDamage(LocalPlayer player, float damage) { - if (damage < crystalFearMinDamage.get()) return false; - - float health = player.getHealth() + player.getAbsorptionAmount(); - double healthThreat = Math.max(crystalFearMinDamage.get(), health * 0.30); - return damage >= healthThreat || health - damage <= crystalFearHealthBuffer.get(); - } - - private Rotation findCrystalFearRotation(LocalPlayer player, CrystalThreat threat) { - Vec3 velocity = player.getDeltaMovement(); - Vec3 away = horizontal(player.getEyePosition().subtract(threat.pos())); - if (away.lengthSqr() < 1.0E-5) { - away = horizontal(velocity); - } - if (away.lengthSqr() < 1.0E-5) { - away = horizontal(player.getViewVector(1.0f)); - } - if (away.lengthSqr() < 1.0E-5) { - return findFreeSideRotation(player); - } - - Vec3 baseDirection = away.normalize(); - double horizontalSpeed = Math.max(0.24, horizontal(velocity).length()); - Vec3 bestDirection = null; - double bestScore = Double.NEGATIVE_INFINITY; - double[] candidateAngles = {0.0, -35.0, 35.0, -70.0, 70.0, -115.0, 115.0, 180.0}; - - for (double angle : candidateAngles) { - Vec3 candidateDirection = rotateHorizontal(baseDirection, angle).normalize(); - Vec3 candidateVelocity = new Vec3( - candidateDirection.x * horizontalSpeed, - Math.max(velocity.y, 0.02), - candidateDirection.z * horizontalSpeed - ); - double score = scoreCrystalFearDirection(player, threat, candidateVelocity, angle); - if (score > bestScore) { - bestScore = score; - bestDirection = candidateDirection; - } - } - - if (bestDirection == null) { - return findFreeSideRotation(player); - } - - Vec3 eye = player.getEyePosition(); - double lift = threat.damage() >= player.getHealth() + player.getAbsorptionAmount() * 0.5f ? 4.5 : 2.8; - Rotation rotation = Rotation.lookingAt( - eye.add(bestDirection.scale(20.0)).add(0.0, lift, 0.0), - eye - ).normalize(); - float pitch = Mth.clamp(rotation.pitch(), -48.0f, -4.0f); - return new Rotation(rotation.yaw(), pitch).normalize(); - } - - private double scoreCrystalFearDirection(LocalPlayer player, CrystalThreat threat, Vec3 initialVelocity, double angle) { - AABB baseBox = player.getBoundingBox(); - Vec3 offset = Vec3.ZERO; - Vec3 velocity = initialVelocity; - double minDistanceSq = Double.POSITIVE_INFINITY; - int ticks = Math.max(3, Mth.clamp(crystalFearPredictionTicks.get() + 3, 3, 14)); - - for (int tick = 1; tick <= ticks; tick++) { - Vec3 previousOffset = offset; - offset = offset.add(velocity); - Vec3 center = baseBox.move(offset).getCenter(); - minDistanceSq = Math.min(minDistanceSq, center.distanceToSqr(threat.pos())); - - AABB previousBox = baseBox.move(previousOffset); - AABB nextBox = baseBox.move(offset); - AABB swept = union(previousBox, nextBox).inflate(CRYSTAL_FEAR_SWEEP_MARGIN); - if (solidBlockDodge.get() && hasSolidCollision(player, swept)) { - return -10_000.0 - Math.abs(angle); - } - - velocity = approximateNextElytraVelocity(velocity); - } - - double minDistance = Math.sqrt(minDistanceSq); - double safeBonus = minDistance >= CRYSTAL_FEAR_SAFE_DISTANCE ? 120.0 : minDistance * 12.0; - return safeBonus - Math.abs(angle) * 0.35; - } - - private boolean queueBlockDodgeRotation(LocalPlayer player) { - if (!solidBlockDodge.get()) return false; - if (!isValidBlockDodgeSelf(player)) return false; - - Vec3 velocity = player.getDeltaMovement(); - if (velocity.horizontalDistance() < 0.18) return false; - - PredictedBlockImpact impact = predictBlockImpact(player, velocity, blockDodgePredictionTicks.get()); - if (impact == null) return false; - - double damage = estimateBlockImpactDamage(player, impact.velocity()); - if (!isDangerousBlockImpact(player, damage)) return false; - - Rotation dodgeRotation = findBlockDodgeRotation(player, impact); - if (dodgeRotation == null) return false; - - RotationTarget plan = new RotationTarget( - dodgeRotation.normalize(), - null, - List.of(), - 2, - 2.0f, - true, - MovementCorrection.SILENT, - false, - null - ); - RotationManager.INSTANCE.setRotationTarget(plan, BLOCK_DODGE_ROTATION_PRIORITY, this); - return true; - } - - private boolean isValidBlockDodgeSelf(LocalPlayer player) { - return player != null - && mc.level != null - && player.isFallFlying() - && !player.onGround() - && !player.isPassenger() - && player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA); - } - - private PredictedBlockImpact predictBlockImpact(LocalPlayer player, Vec3 initialVelocity, int ticks) { - if (player == null || mc.level == null) return null; - - AABB baseBox = player.getBoundingBox(); - Vec3 offset = Vec3.ZERO; - Vec3 velocity = initialVelocity; - int safeTicks = Math.max(1, ticks); - - for (int tick = 1; tick <= safeTicks; tick++) { - Vec3 previousOffset = offset; - offset = offset.add(velocity); - - AABB previousBox = baseBox.move(previousOffset); - AABB nextBox = baseBox.move(offset); - AABB swept = union(previousBox, nextBox).inflate(BLOCK_DODGE_SWEEP_MARGIN); - if (hasSolidCollision(player, swept)) { - return new PredictedBlockImpact(tick, velocity); - } - - velocity = approximateNextElytraVelocity(velocity); - } - - return null; - } - - private Vec3 approximateNextElytraVelocity(Vec3 velocity) { - return new Vec3( - velocity.x * 0.99, - velocity.y * 0.98, - velocity.z * 0.99 - ); - } - - private boolean hasSolidCollision(LocalPlayer player, AABB box) { - for (var shape : mc.level.getBlockCollisions(player, box)) { - if (!shape.isEmpty()) { - return true; - } - } - return false; - } - - private Rotation findBlockDodgeRotation(LocalPlayer player, PredictedBlockImpact impact) { - Vec3 velocity = player.getDeltaMovement(); - Vec3 horizontal = new Vec3(velocity.x, 0.0, velocity.z); - if (horizontal.lengthSqr() < 1.0E-5) { - Rotation movement = RotationManager.INSTANCE.getMovementRotation(); - Vec3 direction = movement != null ? movement.directionVector() : player.getViewVector(1.0f); - horizontal = new Vec3(direction.x, 0.0, direction.z); - } - if (horizontal.lengthSqr() < 1.0E-5) { - return findFreeSideRotation(player); - } - - Vec3 baseDirection = horizontal.normalize(); - double horizontalSpeed = Math.max(0.18, horizontal.length()); - Vec3 bestDirection = null; - double bestScore = Double.NEGATIVE_INFINITY; - - for (double angle : BLOCK_DODGE_CANDIDATE_ANGLES) { - Vec3 candidateDirection = rotateHorizontal(baseDirection, angle).normalize(); - Vec3 candidateVelocity = new Vec3( - candidateDirection.x * horizontalSpeed, - velocity.y, - candidateDirection.z * horizontalSpeed - ); - PredictedBlockImpact candidateImpact = predictBlockImpact(player, candidateVelocity, blockDodgePredictionTicks.get()); - double score = candidateImpact == null - ? 10_000.0 - Math.abs(angle) - : candidateImpact.ticks() * 100.0 - Math.abs(angle); - if (score > bestScore) { - bestScore = score; - bestDirection = candidateDirection; - } - } - - if (bestDirection == null) { - return findFreeSideRotation(player); - } - - Vec3 eye = player.getEyePosition(); - double lift = impact.ticks() <= 3 || velocity.y < -0.04 ? 4.0 : 2.0; - Rotation rotation = Rotation.lookingAt( - eye.add(bestDirection.scale(20.0)).add(0.0, lift, 0.0), - eye - ).normalize(); - float maxPitch = impact.ticks() <= 3 || velocity.y < -0.04 ? -28.0f : -10.0f; - float pitch = Mth.clamp(Math.min(rotation.pitch(), maxPitch), -55.0f, 5.0f); - return new Rotation(rotation.yaw(), pitch).normalize(); - } - - private double estimateBlockImpactDamage(LocalPlayer player, Vec3 impactVelocity) { - double raw = Math.max(0.0, impactVelocity.horizontalDistance() * 10.0 - 3.0); - if (raw <= 0.0) return 0.0; - - int featherLevel = getFeatherFallingLevel(player); - double reduction = Math.min(20.0, featherLevel * 3.0) / 25.0; - return raw * (1.0 - reduction); - } - - private boolean isDangerousBlockImpact(LocalPlayer player, double damage) { - if (damage < blockDodgeMinDamage.get()) return false; - - float health = player.getHealth() + player.getAbsorptionAmount(); - double healthThreat = Math.max(blockDodgeMinDamage.get(), health * 0.32); - return damage >= healthThreat || health - damage <= blockDodgeHealthBuffer.get(); - } - - private int getFeatherFallingLevel(LocalPlayer player) { - if (player == null || mc.level == null) return 0; - ItemStack boots = player.getItemBySlot(EquipmentSlot.FEET); - Holder feather = getFeatherFallingEnchant(); - return feather == null || boots == null || boots.isEmpty() - ? 0 - : EnchantmentHelper.getItemEnchantmentLevel(feather, boots); - } - - private Holder getFeatherFallingEnchant() { - if (mc.level == null) return null; - var registry = mc.level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT); - Enchantment enchantment = registry.getValue(Enchantments.FEATHER_FALLING); - return enchantment != null ? registry.wrapAsHolder(enchantment) : null; - } - - private enum PursuitPhase { - NONE, - CHASE, - CLIMB, - OVERPASS, - DIVE - } - - private record TargetCandidate(LivingEntity entity, Vec3 predictedCenter, Vec3 approachPoint, double score) { - } - - private record Reachability(Vec3 point, boolean raised) { - } - - private record CrystalThreat(EndCrystal crystal, Vec3 pos, float damage, double distance) { - } - - private record PredictedBlockImpact(int ticks, Vec3 velocity) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Hitbox.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Hitbox.java deleted file mode 100644 index 79af0c4..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Hitbox.java +++ /dev/null @@ -1,469 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.features.module.*; -import dev.loki.lovisual.features.module.Module; -import net.minecraft.client.Minecraft; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.joml.Matrix4f; -import org.joml.Quaternionf; -import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.features.module.*; -import dev.loki.lovisual.features.module.modules.visuals.ESP; -import dev.loki.lovisual.features.relations.CategoryRules; -import dev.loki.lovisual.features.relations.CategoryType; -import dev.loki.lovisual.features.relations.EntityFilters; -import dev.loki.lovisual.mixininterface.IEntity; -import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.depth.PreTranslucentDepth; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; -import dev.loki.lovisual.render.engine.renderer.MeshRenderer; -import dev.loki.lovisual.render.engine.renderer.Renderer3D; -import dev.loki.lovisual.render.engine.uniform.MeshBuilder; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - - -//todo Description -@ModuleInfo( - id = "hitbox", - displayName = "Hitbox", - category = ModuleCategory.COMBAT -) -public class Hitbox extends Module { - - private static final String ACTION_SUPPRESS_HITBOX = "suppress_hitbox"; - private static final long HIT_FLASH_DURATION_MS = 2000; - private static final MeshBuilder HITBOX_TRIS = new MeshBuilder(CombatantRenderPipelines.WORLD_COLORED_LIQUID_IGNORE); - private static final MeshBuilder HITBOX_LINES = new MeshBuilder(CombatantRenderPipelines.WORLD_COLORED_LINES_DEPTH); - private final Minecraft mc = Minecraft.getInstance(); - private final NumberValue padding = - num( - "hitboxPadding", - "padding", - 2.0f, - 0.2f, - 3.0f - ); - private final BooleanValue softDisable = - bool( - "hitboxSoftDisable", - "soft_disable_hold", - true - ); - private final BooleanValue renderEnabled = - bool( - "hitboxRenderEnabled", - "render_hitboxes", - true - ); - private final NumberValue renderDistance = - visibleWhen(num( - "hitboxRenderDistance", - "render_distance", - 48, - 8, - 160 - ), renderEnabled::get); - private final BooleanMapValue ignoreGroups = - visibleWhen(group( - "hitboxIgnoreGroups", - "ignore_categories", - ignoreCategoryDefaults() - ), renderEnabled::get); - private final RGBColorValue hitboxColor = - visibleWhen(colorNoAlpha( - "hitboxColor", - "hitbox_color", - "#78C8FF" - ), renderEnabled::get); - private final Map hitFlashMs = new ConcurrentHashMap<>(); - private final List precomputedBoxes = new ArrayList<>(); - private final List precomputedEntities = new ArrayList<>(); - - { - setDefaultBind("G"); // toggle padding/module - addAction(ACTION_SUPPRESS_HITBOX, "MOUSE3", BindMode.HOLD); - } - - private static Map ignoreCategoryDefaults() { - return Map.of( - "friends", false, - "staff", false, - "enemies", false, - "entities", false - ); - } - - // ====================================================== - // STATE - // ====================================================== - - private static PoseStack buildTransformStack() { - Matrix4f mv = new Matrix4f(RenderSystem.getModelViewMatrixCopy()); - Quaternionf camRot = new Quaternionf(RenderState.cameraRotation).conjugate(); - Matrix4f rotation = new Matrix4f().rotation(camRot); - Matrix4f transform = mv.invert().mul(rotation); - PoseStack stack = new PoseStack(); - stack.last().pose().set(transform); - return stack; - } - - private static void addFilledBox(MeshBuilder mesh, AABB box, int r, int g, int b, int a) { - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - quad(mesh, minX, minY, minZ, maxX, minY, minZ, maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - quad(mesh, minX, maxY, minZ, minX, maxY, maxZ, maxX, maxY, maxZ, maxX, maxY, minZ, r, g, b, a); - quad(mesh, minX, minY, maxZ, maxX, minY, maxZ, maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - quad(mesh, minX, minY, minZ, minX, maxY, minZ, maxX, maxY, minZ, maxX, minY, minZ, r, g, b, a); - quad(mesh, maxX, minY, minZ, maxX, maxY, minZ, maxX, maxY, maxZ, maxX, minY, maxZ, r, g, b, a); - quad(mesh, minX, minY, minZ, minX, minY, maxZ, minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - } - - private static void addOutlineBox(MeshBuilder mesh, AABB box, int r, int g, int b, int a) { - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - line(mesh, minX, minY, minZ, maxX, minY, minZ, r, g, b, a); - line(mesh, maxX, minY, minZ, maxX, minY, maxZ, r, g, b, a); - line(mesh, maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - line(mesh, minX, minY, maxZ, minX, minY, minZ, r, g, b, a); - - line(mesh, minX, maxY, minZ, maxX, maxY, minZ, r, g, b, a); - line(mesh, maxX, maxY, minZ, maxX, maxY, maxZ, r, g, b, a); - line(mesh, maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - line(mesh, minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - - line(mesh, minX, minY, minZ, minX, maxY, minZ, r, g, b, a); - line(mesh, maxX, minY, minZ, maxX, maxY, minZ, r, g, b, a); - line(mesh, maxX, minY, maxZ, maxX, maxY, maxZ, r, g, b, a); - line(mesh, minX, minY, maxZ, minX, maxY, maxZ, r, g, b, a); - } - - private static void quad(MeshBuilder mesh, - double x1, double y1, double z1, - double x2, double y2, double z2, - double x3, double y3, double z3, - double x4, double y4, double z4, - int r, int g, int b, int a) { - mesh.ensureQuadCapacity(); - int i1 = mesh.vec3(x1, y1, z1).color(r, g, b, a).next(); - int i2 = mesh.vec3(x2, y2, z2).color(r, g, b, a).next(); - int i3 = mesh.vec3(x3, y3, z3).color(r, g, b, a).next(); - int i4 = mesh.vec3(x4, y4, z4).color(r, g, b, a).next(); - mesh.quad(i1, i2, i3, i4); - } - - private static void line(MeshBuilder mesh, - double x1, double y1, double z1, - double x2, double y2, double z2, - int r, int g, int b, int a) { - mesh.ensureLineCapacity(); - int i1 = mesh.vec3(x1, y1, z1).color(r, g, b, a).next(); - int i2 = mesh.vec3(x2, y2, z2).color(r, g, b, a).next(); - mesh.line(i1, i2); - } - - // ====================================================== - // FILTERING - // ====================================================== - - public static double boxDistanceSq(AABB box, Vec3 p) { - double dx = 0.0; - if (p.x < box.minX) dx = box.minX - p.x; - else if (p.x > box.maxX) dx = p.x - box.maxX; - - double dy = 0.0; - if (p.y < box.minY) dy = box.minY - p.y; - else if (p.y > box.maxY) dy = p.y - box.maxY; - - double dz = 0.0; - if (p.z < box.minZ) dz = box.minZ - p.z; - else if (p.z > box.maxZ) dz = p.z - box.maxZ; - - return dx * dx + dy * dy + dz * dz; - } - - public boolean isSoftDisabledNow() { - return softDisable.get() && isActionHeld(ACTION_SUPPRESS_HITBOX); - } - - // ====================================================== - // RENDER - // ====================================================== - - public boolean isActiveForHitbox() { - return isEnabled() && !isSoftDisabledNow(); - } - - public double getPadding() { - return padding.get(); - } - - public boolean shouldRender() { - return isActiveForHitbox() && renderEnabled.get(); - } - - public int getRenderDistance() { - return renderDistance.get(); - } - - public boolean isAllowed(Entity e) { - if (e instanceof Player p) { - String name = p.getGameProfile().name(); - if (name != null) { - CategoryType type = CategoryRules.determine(name); - if (type == CategoryType.BEDWARS_SELF) return false; - if (ignoreGroups.get("friends") && type == CategoryType.FRIEND) return false; - if (ignoreGroups.get("staff") && type == CategoryType.STAFF) return false; - if (ignoreGroups.get("enemies") - && (type == CategoryType.ENEMY || type == CategoryType.BEDWARS_ENEMY)) return false; - } - } - - var id = BuiltInRegistries.ENTITY_TYPE.getKey(e.getType()); - return id == null || !ignoreGroups.get("entities") || !EntityFilters.get().isIgnoredEntity(id.toString()); - } - - /** - * True when the entity should be skipped entirely (raycast + render). - */ - public boolean shouldIgnore(Entity e) { - return !isAllowed(e); - } - - @Override - public WorldPhase getWorldPhase() { - return WorldPhase.END_MAIN; - } - - @Override - public void onRenderWorld(PoseStack matrices, net.minecraft.client.renderer.SubmitNodeCollector consumers, float tickDelta) { - // Legacy renderer path intentionally left empty. - } - - @Override - public void onRenderWorldEngine(Renderer3D renderer, Renderer3D depthRenderer, float tickDelta) { - if (!shouldRender() || mc.level == null || mc.player == null) return; - - Vec3 cam = mc.gameRenderer.mainCamera().position(); - precomputeBoxes(mc, tickDelta, cam); - - if (precomputedBoxes.isEmpty()) return; - - MeshBuilder tris = HITBOX_TRIS; - MeshBuilder lines = HITBOX_LINES; - lines.begin(); - tris.begin(); - - for (int i = 0; i < precomputedBoxes.size(); i++) { - AABB box = precomputedBoxes.get(i); - Entity e = precomputedEntities.get(i); - - float flash = getHitFlashFactor(e); - float[] rgba = resolveColor(e); - - float r = rgba[0], g = rgba[1], b = rgba[2]; - float fillA = Math.min(1.0f, (0.18f + 0.12f * flash) * 1.17f); //альфа тут - float lineA = Math.min(1.0f, 0.65f + 0.25f * flash); - - r = r * (1 - flash) + flash; - g = g * (1 - flash) + 0.5f * flash; - b = b * (1 - flash) + 0.0f * flash; - - int ri = (int) (r * 255f); - int gi = (int) (g * 255f); - int bi = (int) (b * 255f); - int fa = (int) (fillA * 255f); - int la = (int) (lineA * 255f); - - addOutlineBox(lines, box, ri, gi, bi, la); - addFilledBox(tris, box, ri, gi, bi, fa); - } - - tris.end(); - lines.end(); - - PoseStack transform = buildTransformStack(); - var fb = mc.gameRenderer.mainRenderTarget(); - var depthView = PreTranslucentDepth.getDepthView(); - var colorView = fb.getColorTextureView(); - if (depthView == null) { - return; - } - - if (tris.getIndicesCount() > 0) { - MeshRenderer.begin() - .attachments(colorView, depthView) - .pipeline(CombatantRenderPipelines.WORLD_COLORED_LIQUID_IGNORE) - .mesh(tris, transform) - .end(); - } - - if (lines.getIndicesCount() > 0) { - MeshRenderer.begin() - .attachments(colorView, depthView) - .pipeline(CombatantRenderPipelines.WORLD_COLORED_LINES_DEPTH) - .mesh(lines, transform) - .end(); - } - } - - private void precomputeBoxes(Minecraft mc, float tickDelta, Vec3 cam) { - precomputedBoxes.clear(); - precomputedEntities.clear(); - - double maxDist = getRenderDistance(); - double maxDistSq = maxDist * maxDist; - - AABB search = new AABB( - cam.x - maxDist, cam.y - maxDist, cam.z - maxDist, - cam.x + maxDist, cam.y + maxDist, cam.z + maxDist - ); - - List list = mc.level.getEntities(mc.player, search, - e -> e instanceof LivingEntity && e.isAlive() && isAllowed(e) && !isRenderedByEspReplacement(e)); - - for (Entity e : list) { - Vec3 pos = obtainEntityLerpedPos(e, tickDelta); - - double dx = pos.x - cam.x; - double dy = pos.y - cam.y; - double dz = pos.z - cam.z; - if (dx * dx + dy * dy + dz * dz > maxDistSq) continue; - - AABB box = e.getBoundingBox() - .move(pos.subtract(e.position())) - .inflate(getPadding()); - - precomputedBoxes.add(box); - precomputedEntities.add(e); - } - } - - private Vec3 obtainEntityLerpedPos(Entity e, float f) { - try { - return e.getPosition(f); - } catch (NoSuchMethodError ex) { - if (e instanceof IEntity access) { - Vec3 last = access.get$InstantRenderPos(); - return last.lerp(e.position(), f); - } - return e.position(); - } - } - - private boolean isRenderedByEspReplacement(Entity e) { - ESP esp = Modules.get(ESP.class); - return esp != null && esp.shouldRenderHitboxReplacement(e); - } - - private float[] resolveColor(Entity e) { - return argbToRgba(hitboxColor.getArgb()); - } - - // ====================================================== - // HIT FLASH SUPPORT - // ====================================================== - - private float[] argbToRgba(int argb) { - float a = ((argb >> 24) & 255) / 255f; - float r = ((argb >> 16) & 255) / 255f; - float g = ((argb >> 8) & 255) / 255f; - float b = (argb & 255) / 255f; - return new float[]{r, g, b, a}; - } - - public void markHit(Entity e) { - if (e != null) hitFlashMs.put(e.getId(), System.currentTimeMillis()); - - } - - // ====================================================== - // Utility for other components - // ====================================================== - - private float getHitFlashFactor(Entity e) { - Long t0 = hitFlashMs.get(e.getId()); - if (t0 == null) return 0f; - - long dt = System.currentTimeMillis() - t0; - if (dt >= HIT_FLASH_DURATION_MS) { - hitFlashMs.remove(e.getId()); - return 0f; - } - - float x = 1f - (float) dt / HIT_FLASH_DURATION_MS; - return x * x * (3f - 2f * x); - } - - /** - * Render/visual replacement predicate: active Hitbox + the same category/entity filters, - * but without the interaction distance check used by raycast expansion. - */ - public boolean isReplacementCandidate(Entity e) { - if (!(e instanceof LivingEntity living) || !living.isAlive()) { - return false; - } - return isActiveForHitbox() && isAllowed(e); - } - - public boolean shouldExpandFor(Entity e) { - if (!(e instanceof LivingEntity living) || !living.isAlive()) { - return false; - } - - return isEnabled() && !isSoftDisabledNow() && isAllowed(e) && withinMaxDistance(e); - } - - private boolean withinMaxDistance(Entity e) { - if (mc.player == null) return true; - Vec3 eye = mc.player.getEyePosition(1.0F); - return boxDistanceSq(e.getBoundingBox(), eye) <= 36.0; - } - - public void updateForLogic(float tickDelta) { - if (mc.player == null || mc.level == null) return; - - Vec3 eye = mc.player.getEyePosition(tickDelta); - precomputeBoxes(mc, tickDelta, eye); - } - - public int getPrecomputedCount() { - return precomputedBoxes.size(); - } - - public Entity getPrecomputedEntity(int i) { - return precomputedEntities.get(i); - } - - public AABB getPrecomputedBox(int i) { - return precomputedBoxes.get(i); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/KTLeave.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/KTLeave.java deleted file mode 100644 index fcf4e76..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/KTLeave.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.Connection; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.common.ServerboundPongPacket; -import net.minecraft.util.Util; -import net.minecraft.world.item.Items; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.values.BindMode; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Notifier; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.player.AutoTotem; -import dev.loki.lovisual.util.network.BlinkManager; -import dev.loki.lovisual.util.pvp.client.CooldownsState; - -//todo Description -@ModuleInfo( - id = "ktleave", - displayName = "KTLeave", - category = ModuleCategory.COMBAT -) -public final class KTLeave extends Module { - private static final String ACTION_LEAVE = "leave"; - - private final NumberValue hpThreshold = numCommon( - "ktLeaveHpThreshold", - "hp_threshold", - CommonSettingSchemas.PLAYER_HEALTH_THRESHOLD, - 6, - 1, - 20 - ); - private final BooleanValue includeAbsorption = bool("ktLeaveIncludeAbsorption", "include_absorption", true); - private final EnumValue mode = enumSetting("ktLeaveMode", "mode", Mode.LEGIT); - private final EnumValue totemMode = enumSetting("ktLeaveTotemMode", "totem_mode", TotemMode.AUTO_TOTEM); - private final NumberValue leaveDelayMs = num("ktLeaveDelayMs", "leave_delay_ms", 250, 0, 5000); - private final NumberValue packetFallbackMs = visibleWhen( - num("ktLeavePacketFallbackMs", "packet_fallback_ms", 1500, 0, 5000), - () -> mode.get() == Mode.PACKET_KICK - ); - private final NumberValue joinCooldownMs = - num("ktLeaveJoinCooldownMs", "join_cooldown_ms", 1500, 0, 60000); - - private final Minecraft mc = Minecraft.getInstance(); - private ClientLevel lastWorld; - private boolean pendingLowHealth; - private boolean leaveScheduled; - private boolean packetKickSent; - private boolean manualLeaveScheduled; - private long joinCooldownUntilMs; - private long leaveAtMs; - private long manualLeaveAtMs; - private long packetFallbackAtMs; - private boolean armedInPvp; - - public KTLeave() { - action(ACTION_LEAVE, "NONE", BindMode.PRESS); - } - - @Override - public void onDisable() { - resetState(); - } - - @Override - public void onTick() { - if (!isEnabled()) { - return; - } - if (mc == null || mc.player == null || mc.level == null || mc.getConnection() == null) { - resetState(); - return; - } - - long now = Util.getMillis(); - if (mc.level != lastWorld) { - resetState(); - lastWorld = mc.level; - joinCooldownUntilMs = now + joinCooldownMs.get(); - return; - } - - if (isActionPressedOnce(ACTION_LEAVE)) { - manualLeaveScheduled = true; - manualLeaveAtMs = now + leaveDelayMs.get(); - } - - if (packetKickSent) { - if (packetFallbackMs.get() > 0 && now >= packetFallbackAtMs) { - disconnectNormally(); - } - return; - } - - if (manualLeaveScheduled) { - if (now >= manualLeaveAtMs) { - executeConfiguredLeave(now); - } - return; - } - - if (now < joinCooldownUntilMs) { - return; - } - - if (currentHealth(mc.player) > hpThreshold.get()) { - clearLowHealthState(); - return; - } - - if (shouldHoldForTotem(mc.player)) { - clearLowHealthState(); - return; - } - - if (CooldownsState.MANAGER.isInPvp()) { - pendingLowHealth = true; - armedInPvp = true; - leaveScheduled = false; - return; - } - if (!armedInPvp) { - return; - } - - pendingLowHealth = true; - executeLeave(now); - } - - private void executeLeave(long now) { - if (!pendingLowHealth || mc.getConnection() == null) { - return; - } - - if (!leaveScheduled) { - leaveScheduled = true; - leaveAtMs = now + leaveDelayMs.get(); - return; - } - if (now < leaveAtMs) { - return; - } - - executeConfiguredLeave(now); - } - - private void executeConfiguredLeave(long now) { - if (mode.get() == Mode.PACKET_KICK && !mc.hasSingleplayerServer()) { - sendKickPackets(now); - return; - } - disconnectNormally(); - } - - private boolean shouldHoldForTotem(LocalPlayer player) { - TotemMode guardMode = totemMode.get(); - if (guardMode == TotemMode.OFF) { - return false; - } - if (player == null) { - return false; - } - - if (isTotemHeld(player)) { - return guardMode == TotemMode.AUTO_TOTEM - || guardMode == TotemMode.HELD - || guardMode == TotemMode.INVENTORY; - } - - return switch (guardMode) { - case AUTO_TOTEM -> canAutoTotemHandleNow(player); - case INVENTORY -> hasTotemInInventory(player); - case HELD, OFF -> false; - }; - } - - private boolean canAutoTotemHandleNow(LocalPlayer player) { - AutoTotem autoTotem = Modules.get(AutoTotem.class); - if (autoTotem == null || !autoTotem.isEnabled()) { - return false; - } - if (autoTotem.isTotemSwapPending()) { - return true; - } - return autoTotem.shouldHoldTotemNow(player) && autoTotem.canProvideTotemNow(player); - } - - private boolean isTotemHeld(LocalPlayer player) { - return player.getOffhandItem().is(Items.TOTEM_OF_UNDYING) - || player.getMainHandItem().is(Items.TOTEM_OF_UNDYING); - } - - private boolean hasTotemInInventory(LocalPlayer player) { - for (int i = 0; i < 36; i++) { - if (player.getInventory().getItem(i).is(Items.TOTEM_OF_UNDYING)) { - return true; - } - } - return false; - } - - private void clearLowHealthState() { - pendingLowHealth = false; - armedInPvp = false; - leaveScheduled = false; - } - - private int currentHealth(LocalPlayer player) { - float hp = player.getHealth(); - if (includeAbsorption.get()) { - hp += player.getAbsorptionAmount(); - } - return Math.round(hp); - } - - private void sendKickPackets(long now) { - Connection connection = mc.getConnection().getConnection(); - if (connection == null || !connection.isConnected()) { - return; - } - - int seed = (int) System.nanoTime(); - BlinkManager.INSTANCE.sendSilently(new ServerboundPongPacket(seed ^ 0x5A5A5A5A)); - BlinkManager.INSTANCE.sendSilently(new ServerboundPongPacket(Integer.MIN_VALUE + (seed & 0xFFFF))); - BlinkManager.INSTANCE.sendSilently(new ServerboundPongPacket(Integer.MAX_VALUE - (seed & 0xFFFF))); - - packetKickSent = true; - packetFallbackAtMs = now + packetFallbackMs.get(); - Notifier.info("KTLeave packet kick sent"); - } - - private void disconnectNormally() { - if (mc.getConnection() == null) { - return; - } - mc.getConnection().getConnection().disconnect(Component.empty()); - } - - private void resetState() { - pendingLowHealth = false; - armedInPvp = false; - leaveScheduled = false; - packetKickSent = false; - manualLeaveScheduled = false; - leaveAtMs = 0L; - manualLeaveAtMs = 0L; - packetFallbackAtMs = 0L; - } - - public enum Mode implements EnumValue.IdProvider { - LEGIT("legit"), - PACKET_KICK("packet_kick"); - - private final String id; - - Mode(String id) { - this.id = id; - } - - @Override - public String id() { - return id; - } - } - - public enum TotemMode implements EnumValue.IdProvider { - OFF("off"), - AUTO_TOTEM("auto_totem"), - HELD("held"), - INVENTORY("inventory"); - - private final String id; - - TotemMode(String id) { - this.id = id; - } - - @Override - public String id() { - return id; - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/KillAura.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/KillAura.java deleted file mode 100644 index 6fa789b..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/KillAura.java +++ /dev/null @@ -1,1241 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.util.combat.*; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.minecraft.client.Minecraft; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.common.impl.TargetFilters; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.RotationUpdateEvent; -import dev.loki.lovisual.events.impl.SprintControlEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.TargetStrafe; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.data.RotationWithVector; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.aiming.features.processors.LazyAimProcessor; -import dev.loki.lovisual.util.aiming.features.processors.RotationProcessor; -import dev.loki.lovisual.util.aiming.features.processors.ShakeAimProcessor; -import dev.loki.lovisual.util.aiming.features.processors.anglesmooth.AngleSmooth; -import dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.LinearAngleSmooth; -import dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.SigmoidAngleSmooth; -import dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.SmartAngleSmooth; -import dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.SpookyAngleSmooth; -import dev.loki.lovisual.util.aiming.point.PointInsideBox; -import dev.loki.lovisual.util.aiming.point.PointTracker; -import dev.loki.lovisual.util.aiming.preference.LeastDifferencePreference; -import dev.loki.lovisual.util.aiming.preference.RotationPreference; -import dev.loki.lovisual.util.aiming.raytrace.RotationRaytrace; -import dev.loki.lovisual.util.click.AttackPressing; -import dev.loki.lovisual.util.click.ClickScheduler; -import dev.loki.lovisual.util.combat.protocol.CombatProtocolHeuristics; -import dev.loki.lovisual.util.combat.protocol.ProtocolUtil; -import dev.loki.lovisual.util.raycast.RaycastUtil; -import dev.loki.lovisual.util.target.TargetManager; -import dev.loki.lovisual.util.target.TargetingUtil; -import dev.loki.lovisual.util.target.TargetingUtil.TargetingSettings; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; - -//todo Description -@ModuleInfo( - id = "killaura", - displayName = "KillAura", - category = ModuleCategory.COMBAT -) -public class KillAura extends Module { - - private static final int MAX_CPS = 100; - private static final String IGNORE_BOTS = "ignore_bots"; - private final Minecraft mc = Minecraft.getInstance(); - private final NumberValue range = - numCommon( - "killauraRange", - "range", - CommonSettingSchemas.COMBAT_RANGE, - 3.2, - 1.0, - 6.0 - ); - private final EnumValue reachMode = - enumCommon( - "killauraReachMode", - "reach_mode", - CommonSettingSchemas.COMBAT_REACH_MODE, - Reach.Mode.NORMAL, - Reach.Mode.values() - ); - private final NumberValue fov = - numCommon( - "killauraFov", - "fov", - CommonSettingSchemas.COMBAT_FOV, - 180f, - 30f, - 180f - ); - private final EnumValue priority = - enumCommon( - "killauraPriority", - "priority", - CommonSettingSchemas.COMBAT_PRIORITY, - TargetingUtil.TargetPriority.DISTANCE, - TargetingUtil.TargetPriority.values() - ); - private final EnumValue raycast = - enumCommon( - "killauraRaycast", - "raycast", - CommonSettingSchemas.COMBAT_RAYCAST, - RaycastMode.STRICT, - RaycastMode.values() - ); - private final ModeValue attackMode = modeCommon( - "killauraAttackMode", - "attack_mode", - CommonSettingSchemas.COMBAT_ATTACK_MODE, - CombatRotationModeUtil.MODE_ROTATIONS, - CombatRotationModeUtil.MODE_ROTATIONS, - CombatRotationModeUtil.MODE_NO_ROTATIONS - ); - private final NumberValue acquireRangeIncrement = - visibleWhen(numCommon( - "killauraAcquireRangeIncrement", - "range_increment", - CommonSettingSchemas.COMBAT_RANGE_INCREMENT, - 1.5, - 0.0, - 3.0 - ), this::usesRotationSettings); - private final NumberValue wallRange = - visibleWhen(numCommon( - "killauraWallRange", - "wall_range", - CommonSettingSchemas.COMBAT_WALL_RANGE, - 2.5, - 0.0, - 6.0 - ), this::usesRotationSettings); - private final NumberValue cpsMin = - numCommon( - "killauraCpsMin", - "cps_min", - CommonSettingSchemas.COMBAT_CPS_MIN, - 8, - 1, - MAX_CPS - ); - private final NumberValue cpsMax = - numCommon( - "killauraCpsMax", - "cps_max", - CommonSettingSchemas.COMBAT_CPS_MAX, - 12, - 1, - MAX_CPS - ); - private final BooleanValue breakShields = - boolCommon( - "killauraBreakShields", - "break_shields", - CommonSettingSchemas.COMBAT_BREAK_SHIELDS, - true - ); - private final EnumValue rotationTiming = - visibleWhen(enumCommon( - "killauraRotationTiming", - "rotation_timing", - CommonSettingSchemas.ROTATION_TIMING, - RotationTiming.NORMAL, - RotationTiming.values() - ), this::usesRotationSettings); - private final EnumValue correctionType = - visibleWhen(enumCommon( - "killauraCorrectionType", - "correction_type", - CommonSettingSchemas.COMBAT_CORRECTION_TYPE, - CorrectionType.FOCUSED, - CorrectionType.values() - ), this::usesRotationSettings); - private final EnumValue protocolMode = - enumCommon( - "killauraProtocolMode", - "protocol_mode", - CommonSettingSchemas.COMBAT_PROTOCOL, - ProtocolMode.AUTO, - ProtocolMode.values() - ); - private final BooleanMapValue protocolHeuristicSources = - visibleWhen(protocolHeuristics( - "killauraProtocolHeuristics", - "protocol_heuristics", - CommonSettingSchemas.COMBAT_PROTOCOL_HEURISTICS - ), () -> protocolMode.get() == ProtocolMode.AUTO); - private final EnumValue sprintResetMode = - enumCommon( - "killauraSprintResetMode", - "sprint_reset_mode", - CommonSettingSchemas.COMBAT_SPRINT_RESET, - SprintResetMode.DEFAULT, - SprintResetMode.values() - ); - private final EnumValue criticalsSelection = - visibleWhen(enumCommon( - "killauraCriticals", - "criticals", - CommonSettingSchemas.COMBAT_CRITICALS, - Criticals.SelectionMode.SMART, - Criticals.SelectionMode.values() - ), () -> !isLegacyAttackProtocol()); - private final EnumValue rotationMode = - visibleWhen(enumCommon( - "killauraRotationMode", - "rotation_mode", - CommonSettingSchemas.ROTATION_MODE, - AngleSmoothMode.SMART, - AngleSmoothMode.values() - ), this::usesRotationSettings); - // Linear smoothing - private final NumberValue linearHorMin = - visibleWhen(numCommon( - "linearHorizontalMin", - "linear_horizontal_min", - CommonSettingSchemas.ANGLESMOOTH_HORIZONTAL_MIN, - 180f, - 0f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.LINEAR); - private final NumberValue linearHorMax = - visibleWhen(numCommon( - "linearHorizontalMax", - "linear_horizontal_max", - CommonSettingSchemas.ANGLESMOOTH_HORIZONTAL_MAX, - 180f, - 0f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.LINEAR); - private final NumberValue linearVertMin = - visibleWhen(numCommon( - "linearVerticalMin", - "linear_vertical_min", - CommonSettingSchemas.ANGLESMOOTH_VERTICAL_MIN, - 180f, - 0f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.LINEAR); - private final NumberValue linearVertMax = - visibleWhen(numCommon( - "linearVerticalMax", - "linear_vertical_max", - CommonSettingSchemas.ANGLESMOOTH_VERTICAL_MAX, - 180f, - 0f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.LINEAR); - private final LinearAngleSmooth linearSmooth = new LinearAngleSmooth( - linearHorMin, linearHorMax, linearVertMin, linearVertMax - ); - // Sigmoid smoothing - private final NumberValue sigmoidHorMin = - visibleWhen(numCommon( - "sigmoidHorizontalMin", - "sigmoid_horizontal_min", - CommonSettingSchemas.ANGLESMOOTH_HORIZONTAL_MIN, - 180f, - 0f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SIGMOID); - private final NumberValue sigmoidHorMax = - visibleWhen(numCommon( - "sigmoidHorizontalMax", - "sigmoid_horizontal_max", - CommonSettingSchemas.ANGLESMOOTH_HORIZONTAL_MAX, - 180f, - 0f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SIGMOID); - private final NumberValue sigmoidVertMin = - visibleWhen(numCommon( - "sigmoidVerticalMin", - "sigmoid_vertical_min", - CommonSettingSchemas.ANGLESMOOTH_VERTICAL_MIN, - 180f, - 0f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SIGMOID); - private final NumberValue sigmoidVertMax = - visibleWhen(numCommon( - "sigmoidVerticalMax", - "sigmoid_vertical_max", - CommonSettingSchemas.ANGLESMOOTH_VERTICAL_MAX, - 180f, - 0f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SIGMOID); - private final NumberValue sigmoidSteepness = - visibleWhen(numCommon( - "sigmoidSteepness", - "sigmoid_steepness", - CommonSettingSchemas.ANGLESMOOTH_STEEPNESS, - 10f, - 0f, - 20f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SIGMOID); - private final NumberValue sigmoidMidpoint = - visibleWhen(numCommon( - "sigmoidMidpoint", - "sigmoid_midpoint", - CommonSettingSchemas.ANGLESMOOTH_MIDPOINT, - 0.3f, - 0f, - 1f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SIGMOID); - private final SigmoidAngleSmooth sigmoidSmooth = new SigmoidAngleSmooth( - sigmoidHorMin, sigmoidHorMax, sigmoidVertMin, sigmoidVertMax, - sigmoidSteepness, sigmoidMidpoint - ); - // Smart smoothing - private final NumberValue smartYawMin = - visibleWhen(numCommon( - "smartYawMin", - "smart_yaw_min", - CommonSettingSchemas.ANGLESMOOTH_YAW_MIN, - 70f, - 1f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SMART); - private final NumberValue smartYawMax = - visibleWhen(numCommon( - "smartYawMax", - "smart_yaw_max", - CommonSettingSchemas.ANGLESMOOTH_YAW_MAX, - 95f, - 1f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SMART); - private final NumberValue smartPitchMin = - visibleWhen(numCommon( - "smartPitchMin", - "smart_pitch_min", - CommonSettingSchemas.ANGLESMOOTH_PITCH_MIN, - 45f, - 1f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SMART); - private final NumberValue smartPitchMax = - visibleWhen(numCommon( - "smartPitchMax", - "smart_pitch_max", - CommonSettingSchemas.ANGLESMOOTH_PITCH_MAX, - 70f, - 1f, - 180f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SMART); - private final NumberValue smartSnapThreshold = - visibleWhen(numCommon( - "smartSnapThreshold", - "smart_snap_threshold", - CommonSettingSchemas.ANGLESMOOTH_SNAP_THRESHOLD, - 1.2f, - 0.05f, - 10.0f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SMART); - private final NumberValue smartJitterYaw = - visibleWhen(numCommon( - "smartJitterYaw", - "smart_jitter_yaw", - CommonSettingSchemas.ANGLESMOOTH_JITTER_YAW, - 0.8f, - 0.0f, - 6.0f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SMART); - private final NumberValue smartJitterPitch = - visibleWhen(numCommon( - "smartJitterPitch", - "smart_jitter_pitch", - CommonSettingSchemas.ANGLESMOOTH_JITTER_PITCH, - 0.4f, - 0.0f, - 4.0f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SMART); - private final BooleanValue smartDecelerateEnabled = - visibleWhen(boolCommon( - "smartDecelerateEnabled", - "smart_decelerate_enabled", - CommonSettingSchemas.ANGLESMOOTH_DECELERATE_ENABLED, - true - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SMART); - private final NumberValue smartDecelerateAngle = - visibleWhen(numCommon( - "smartDecelerateAngle", - "smart_decelerate_angle", - CommonSettingSchemas.ANGLESMOOTH_DECELERATE_ANGLE, - 35.0f, - 1.0f, - 120.0f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SMART && smartDecelerateEnabled.get()); - private final NumberValue smartDecelerateMinFactor = - visibleWhen(numCommon( - "smartDecelerateMinFactor", - "smart_decelerate_min_factor", - CommonSettingSchemas.ANGLESMOOTH_DECELERATE_MIN_FACTOR, - 0.22f, - 0.05f, - 1.0f - ), () -> usesRotationSettings() && rotationMode.get() == AngleSmoothMode.SMART && smartDecelerateEnabled.get()); - private final SmartAngleSmooth smartSmooth = new SmartAngleSmooth( - smartYawMin, smartYawMax, smartPitchMin, smartPitchMax, - smartSnapThreshold, smartJitterYaw, smartJitterPitch, - smartDecelerateEnabled, smartDecelerateAngle, smartDecelerateMinFactor - ); - private final NumberValue rotationResetTicks = - visibleWhen(numCommon( - "killauraRotationResetTicks", - "rotation_reset_ticks", - CommonSettingSchemas.ROTATION_RESET_TICKS, - 2, - 1, - 20 - ), this::usesRotationSettings); - private final NumberValue rotationResetThreshold = - visibleWhen(numCommon( - "killauraRotationResetThreshold", - "rotation_reset_threshold", - CommonSettingSchemas.ROTATION_RESET_THRESHOLD, - 2.0f, - 0.1f, - 15.0f - ), this::usesRotationSettings); - private final BooleanValue rotationThroughWalls = - visibleWhen(boolCommon( - "killauraRotationThroughWalls", - "rotation_through_walls", - CommonSettingSchemas.ROTATION_THROUGH_WALLS, - false - ), this::usesRotationSettings); - private final ClickScheduler clicker = new ClickScheduler(cpsMin.get(), cpsMax.get()); - private final PointTracker pointTracker = new PointTracker(); - // Optional aim processors - private final BooleanValue lazyAimEnabled = - visibleWhen(boolCommon( - "lazyAimEnabled", - "lazy_aim_enabled", - CommonSettingSchemas.LAZY_AIM_ENABLED, - false - ), this::usesRotationSettings); - private final NumberValue lazyAimThreshold = - visibleWhen(numCommon( - "lazyAimThreshold", - "lazy_aim_threshold", - CommonSettingSchemas.LAZY_AIM_THRESHOLD, - 1.8f, - 0.1f, - 10.0f - ), () -> usesRotationSettings() && lazyAimEnabled.get()); - private final NumberValue lazyAimFollowFactor = - visibleWhen(numCommon( - "lazyAimFollowFactor", - "lazy_aim_follow_factor", - CommonSettingSchemas.LAZY_AIM_FOLLOW_FACTOR, - 0.65f, - 0.1f, - 2.0f - ), () -> usesRotationSettings() && lazyAimEnabled.get()); - private final LazyAimProcessor lazyAimProcessor = new LazyAimProcessor(lazyAimThreshold, lazyAimFollowFactor); - private final BooleanValue shakeAimEnabled = - visibleWhen(boolCommon( - "shakeAimEnabled", - "shake_aim_enabled", - CommonSettingSchemas.SHAKE_AIM_ENABLED, - false - ), this::usesRotationSettings); - private final NumberValue shakeAimYawAmplitude = - visibleWhen(numCommon( - "shakeAimYawAmplitude", - "shake_aim_yaw_amplitude", - CommonSettingSchemas.SHAKE_AIM_YAW_AMPLITUDE, - 0.6f, - 0.0f, - 5.0f - ), () -> usesRotationSettings() && shakeAimEnabled.get()); - private final NumberValue shakeAimPitchAmplitude = - visibleWhen(numCommon( - "shakeAimPitchAmplitude", - "shake_aim_pitch_amplitude", - CommonSettingSchemas.SHAKE_AIM_PITCH_AMPLITUDE, - 0.3f, - 0.0f, - 3.0f - ), () -> usesRotationSettings() && shakeAimEnabled.get()); - private final NumberValue shakeAimSpeed = - visibleWhen(numCommon( - "shakeAimSpeed", - "shake_aim_speed", - CommonSettingSchemas.SHAKE_AIM_SPEED, - 0.25f, - 0.01f, - 2.0f - ), () -> usesRotationSettings() && shakeAimEnabled.get()); - private final ShakeAimProcessor shakeAimProcessor = new ShakeAimProcessor( - shakeAimYawAmplitude, shakeAimPitchAmplitude, shakeAimSpeed - ); - private final BooleanMapValue toggles = common( - group("killaura_toggles", "toggles", targetFilterDefaults()), - CommonSettingSchemas.TARGET_FILTERS.commonI18nKey() - ); - private final SpookyAngleSmooth spookySmooth = new SpookyAngleSmooth(); - private LivingEntity currentTarget; - private Vec3 lastAimPoint; - private int lastAimEntityId = -1; - private Rotation lastRotation; - private int lastRotationTick = -1; - private int lastAttackExecutionAge = -1; - - private static LinkedHashMap targetFilterDefaults() { - LinkedHashMap defaults = new LinkedHashMap<>(); - defaults.put(TargetFilters.PLAYERS_ONLY, false); - defaults.put(TargetFilters.IGNORE_FRIENDS, true); - defaults.put(TargetFilters.IGNORE_STAFF, true); - defaults.put(IGNORE_BOTS, true); - defaults.put(TargetFilters.IGNORE_ENEMIES, false); - defaults.put(TargetFilters.IGNORE_NAKED, false); - defaults.put(TargetFilters.IGNORE_ENTITIES, true); - return defaults; - } - - private boolean usesRotationSettings() { - return CombatRotationModeUtil.usesRotations(attackMode); - } - - @Override - public void onEnable() { - clicker.reset(); - currentTarget = null; - lastRotation = null; - lastRotationTick = -1; - SprintController.INSTANCE.clearSprintBlock(); - } - - @Override - public void onDisable() { - currentTarget = null; - TargetManager.setPredictionTarget(null); - TargetManager.setModuleTarget(null); - AttributeSwap.clearAuraControlIfActive(); - clearRotationState(false); - lastAttackExecutionAge = -1; - SprintController.INSTANCE.clearSprintBlock(); - } - - @EventHandler(priority = 10) - public void onRotationUpdate(RotationUpdateEvent event) { - if (!isEnabled()) return; - if (mc.player == null || mc.level == null) { - clearTargetImmediate(); - return; - } - - switch (event.getType()) { - case PRE -> { - if (isLegacyAttackProtocol()) { - clicker.setCps(cpsMin.get(), cpsMax.get()); - clicker.tick(); - } - - TargetingSettings settings = new TargetingSettings( - getAcquireRange(), - fov.get(), - toggles.get(TargetFilters.PLAYERS_ONLY), - toggles.get(TargetFilters.IGNORE_FRIENDS), - toggles.get(TargetFilters.IGNORE_STAFF), - toggles.get(TargetFilters.IGNORE_ENEMIES), - toggles.get(TargetFilters.IGNORE_NAKED), - toggles.get(TargetFilters.IGNORE_ENTITIES), - false, - priority.get() - ); - - List targets = filterDynamicReachTargets(filterAntiBotTargets(TargetingUtil.findTargets(mc, settings))); - syncPredictionTarget(targets); - boolean currentTargetCandidate = isCurrentTargetCandidate(targets); - if (CombatRotationModeUtil.isNoRotations(attackMode)) { - clearRotationState(true); - if (currentTargetCandidate && processLockedTargetNoRotations()) { - return; - } - for (LivingEntity target : targets) { - if (processTargetNoRotations(target)) { - setActiveTarget(target); - return; - } - } - - clearTargetRuntime(); - return; - } - - if (currentTargetCandidate && processLockedTarget()) { - return; - } - for (LivingEntity target : targets) { - if (processTarget(target)) { - setActiveTarget(target); - return; - } - } - - clearTargetRuntime(); - } - case POST -> tryAttackPost(); - } - } - - @Override - public void onTick() { - if (!isEnabled()) return; - if (mc.player == null || mc.level == null) { - clearTargetImmediate(); - return; - } - - syncModuleTargetState(); - } - - private void tryAttackPost() { - if (mc.player == null || mc.level == null) return; - if (mc.player.tickCount == lastAttackExecutionAge) return; - - LivingEntity target = currentTarget; - if (target == null) return; - - syncModuleTargetState(); - - if (!isInRange(target)) return; - boolean legacyProtocol = isLegacyAttackProtocol(); - - if (CombatRotationModeUtil.usesRotations(attackMode)) { - Rotation rotation = resolveAttackRotation(target); - if (rotation == null) return; - if (!passesRaycast(target, rotation.yaw(), rotation.pitch())) return; - } - - int clickCount = CombatStrikeController.INSTANCE.resolveClickCount(clicker, legacyProtocol); - if (clickCount <= 0) return; - - CombatStrikeController.SprintResetMode resetMode = resolveStrikeResetMode(); - - boolean attacked = CombatStrikeController.INSTANCE.tryAttack( - mc, - target, - legacyProtocol, - clickCount, - resetMode, - true, - () -> criticalHitAllowed(target) - ); - - if (!attacked) { - return; - } - - lastAttackExecutionAge = mc.player.tickCount; - - AttributeSwap.tryBreakShieldPostAttack( - target, - true, - breakShields.get() - ); - } - - public boolean willAttackInTicks(int ticks) { - if (!isEnabled()) { - return false; - } - - int safeTicks = Math.max(0, ticks); - if (isLegacyAttackProtocol()) { - return clicker.willClickAt(safeTicks); - } - - return AttackPressing.INSTANCE.willCooldownComplete(mc.player, currentTarget, false, safeTicks); - } - - public ClickScheduler getClickScheduler() { - return clicker; - } - - public LivingEntity getCurrentTarget() { - return currentTarget; - } - - public boolean isNoRotationMode() { - return isEnabled() && CombatRotationModeUtil.isNoRotations(attackMode); - } - - public List findElytraTargetCandidates(double range, float fov) { - if (!isEnabled() || mc.player == null || mc.level == null) { - return List.of(); - } - - double safeRange = Math.max(1.0, range); - float safeFov = Math.max(1.0f, Math.min(180.0f, fov)); - TargetingSettings settings = new TargetingSettings( - safeRange, - safeFov, - toggles.get(TargetFilters.PLAYERS_ONLY), - toggles.get(TargetFilters.IGNORE_FRIENDS), - toggles.get(TargetFilters.IGNORE_STAFF), - toggles.get(TargetFilters.IGNORE_ENEMIES), - toggles.get(TargetFilters.IGNORE_NAKED), - toggles.get(TargetFilters.IGNORE_ENTITIES), - false, - priority.get() - ); - - return filterAntiBotTargets(TargetingUtil.findTargets(mc, settings)); - } - - @EventHandler - private void onSprintControl(SprintControlEvent event) { - if (!isEnabled()) return; - if (event.getSource() != SprintControlEvent.Source.MOVEMENT_TICK - && event.getSource() != SprintControlEvent.Source.INPUT) { - return; - } - - if (shouldBlockSprinting(currentTarget)) { - event.setSprint(false); - } - } - - private void clearTargetImmediate() { - currentTarget = null; - TargetManager.setPredictionTarget(null); - TargetManager.setModuleTarget(null); - AttributeSwap.clearAuraControlIfActive(); - SprintController.INSTANCE.clearSprintBlock(); - clearRotationState(false); - lastAttackExecutionAge = -1; - } - - private void clearTargetRuntime() { - currentTarget = null; - TargetManager.setPredictionTarget(null); - TargetManager.setModuleTarget(null); - AttributeSwap.handleAuraTarget(null, false); - SprintController.INSTANCE.clearSprintBlock(); - lastAttackExecutionAge = -1; - clearRotationState(true); - } - - private boolean isCurrentTargetCandidate(List targets) { - LivingEntity target = currentTarget; - if (target == null || targets == null || targets.isEmpty()) { - return false; - } - int targetId = target.getId(); - for (LivingEntity candidate : targets) { - if (candidate != null && candidate.getId() == targetId) { - return true; - } - } - return false; - } - - private void syncModuleTargetState() { - LivingEntity target = currentTarget; - if (target == null || !target.isAlive() || target.isRemoved()) { - if (target != null) { - clearTargetRuntime(); - } else { - TargetManager.setModuleTarget(null); - } - return; - } - - TargetManager.setModuleTarget(target); - } - - private void syncPredictionTarget(List targets) { - if (targets == null || targets.isEmpty()) { - TargetManager.setPredictionTarget(null); - return; - } - - TargetManager.setPredictionTarget(targets.getFirst()); - } - - private List filterDynamicReachTargets(List targets) { - if (!usesDynamicReach() || targets == null || targets.isEmpty() || mc.player == null) { - return targets; - } - - Vec3 eyePos = mc.player.getEyePosition(); - List filtered = new ArrayList<>(targets.size()); - for (LivingEntity target : targets) { - double targetRange = getEffectiveAcquireRange(target); - double distSq = TargetingUtil.distanceToEntityBoxSq(eyePos, target); - if (distSq <= targetRange * targetRange) { - filtered.add(target); - } - } - return filtered; - } - - private List filterAntiBotTargets(List targets) { - if (!toggles.get(IGNORE_BOTS) || targets == null || targets.isEmpty()) { - return targets; - } - - List filtered = new ArrayList<>(targets.size()); - for (LivingEntity target : targets) { - if (target instanceof Player player && AntiBotTracker.INSTANCE.isBot(player)) { - continue; - } - filtered.add(target); - } - return filtered; - } - - private void clearRotationState(boolean smoothReturn) { - RotationManager.INSTANCE.release(this, smoothReturn); - pointTracker.reset(); - lastAimPoint = null; - lastAimEntityId = -1; - lastRotation = null; - lastRotationTick = -1; - } - - private void setActiveTarget(LivingEntity target) { - currentTarget = target; - TargetManager.setPredictionTarget(null); - TargetManager.setModuleTarget(target); - AttributeSwap.handleAuraTarget(target, breakShields.get()); - } - - private boolean processLockedTargetNoRotations() { - LivingEntity target = currentTarget; - if (mc.player == null || target == null) return false; - if (!target.isAlive() || target.isRemoved()) return false; - double lockRange = getEffectiveAcquireRange(target); - double distSq = TargetingUtil.distanceToEntityBoxSq(mc.player.getEyePosition(), target); - if (distSq > lockRange * lockRange) return false; - if (!processTargetNoRotations(target)) return false; - - setActiveTarget(target); - return true; - } - - private boolean processLockedTarget() { - LivingEntity target = currentTarget; - if (mc.player == null || target == null) return false; - if (!target.isAlive() || target.isRemoved()) return false; - double lockRange = getEffectiveAcquireRange(target); - double distSq = TargetingUtil.distanceToEntityBoxSq(mc.player.getEyePosition(), target); - if (distSq > lockRange * lockRange) return false; - if (processTarget(target)) { - setActiveTarget(target); - return true; - } - return false; - } - - private Rotation resolveAttackRotation(LivingEntity target) { - if (mc.player == null) return null; - - Rotation rotation; - RotationTiming timing = rotationTiming.get(); - if (timing == RotationTiming.ON_TICK) { - rotation = lastRotationTick == mc.player.tickCount ? lastRotation : null; - if (rotation == null) { - RotationWithVector rot = findAttackRotation(target); - if (rot == null) { - ElytraTarget elytraTarget = Modules.get(ElytraTarget.class); - if (elytraTarget != null && elytraTarget.canIgnoreKillAuraRotations()) { - Rotation current = RotationManager.INSTANCE.getCurrentRotation(); - rotation = current != null ? current : new Rotation(mc.player.getYRot(), mc.player.getXRot(), true); - } else { - return null; - } - } else { - rotation = rot.rotation(); - } - } - } else { - Rotation current = RotationManager.INSTANCE.getCurrentRotation(); - if (current != null) { - rotation = current; - } else if (lastRotation != null && lastAimEntityId == target.getId()) { - rotation = lastRotation; - } else { - RotationWithVector rot = findAttackRotation(target); - if (rot == null) { - ElytraTarget elytraTarget = Modules.get(ElytraTarget.class); - if (elytraTarget != null && elytraTarget.canIgnoreKillAuraRotations()) { - Rotation server = RotationManager.INSTANCE.getServerRotation(); - rotation = server; - } else { - return null; - } - } else { - lastRotation = rot.rotation(); - lastRotationTick = mc.player.tickCount; - rotation = rot.rotation(); - } - } - } - - return rotation != null ? rotation.normalize() : null; - } - - private boolean processTarget(LivingEntity target) { - double targetRange = getEffectiveAcquireRange(target); - double targetWallRange = getEffectiveWallRange(target, targetRange); - RotationWithVector rotation = findRotation(target, (float) targetRange, (float) targetWallRange); - if (rotation == null) return false; - - lastRotation = rotation.rotation(); - lastRotationTick = mc.player != null ? mc.player.tickCount : -1; - - RotationTarget plan = buildRotationTarget(rotation.rotation(), target); - RotationManager.INSTANCE.setRotationTarget(plan, 10, this); - return true; - } - - private RotationWithVector findAttackRotation(LivingEntity target) { - double targetRange = getEffectiveAttackRange(target); - double targetWallRange = getEffectiveWallRange(target, targetRange); - return findRotation(target, (float) targetRange, (float) targetWallRange); - } - - private boolean processTargetNoRotations(LivingEntity target) { - double attackRange = getEffectiveAttackRange(target); - boolean requireLineOfSight = raycast.get() == RaycastMode.STRICT; - return CombatRotationModeUtil.canAttackWithoutRotations(mc, target, attackRange, requireLineOfSight); - } - - private boolean isLegacyAttackProtocol() { - return switch (protocolMode.get()) { - case AUTO -> ProtocolUtil.isLegacyAttackProtocol(protocolHeuristicSources.getAll()); - case FORCE_1_8 -> true; - case FORCE_1_9 -> false; - }; - } - - private boolean isInRange(Entity target) { - double distSq = TargetingUtil.distanceToEntityBoxSq(mc.player.getEyePosition(), target); - double targetRange = getEffectiveAttackRange(target); - return distSq <= targetRange * targetRange; - } - - private boolean passesRaycast(Entity target, float yaw, float pitch) { - ElytraTarget elytraTarget = Modules.get(ElytraTarget.class); - if (elytraTarget != null && elytraTarget.canIgnoreKillAuraRotations()) { - return true; - } - - RaycastMode mode = raycast.get(); - if (mode == RaycastMode.NONE) return true; - - if (mc.player == null || target == null) { - return false; - } - - double attackRange = Math.max(0.0, getEffectiveAttackRange(target)); - double throughWallsRange = mode == RaycastMode.THROUGH_WALLS - ? getEffectiveWallRange(target, attackRange) - : 0.0; - - return RaycastUtil.isLookingAtEntity( - mc.player, - target, - yaw, - pitch, - attackRange, - throughWallsRange - ) != null; - } - - private boolean isLookingAtTargetBox(LivingEntity target, Rotation rotation) { - if (mc.player == null || target == null || rotation == null) { - return false; - } - - Vec3 eyePos = mc.player.getEyePosition(); - Vec3 lookVec = rotation.directionVector(); - AABB targetBox = target.getBoundingBox(); - Vec3 endVec = eyePos.add(lookVec.scale(getEffectiveAttackRange(target))); - return targetBox.contains(eyePos) || targetBox.clip(eyePos, endVec).isPresent(); - } - - private RotationWithVector findRotation(Entity target, float range, float wallsRange) { - if (mc.player == null) return null; - Vec3 eyes = mc.player.getEyePosition(); - pointTracker.setOptions( - false, - 0, - 0, - false, - 0.0, - 0.0, - false, - 0.0, - 0.0, - 0, - 0.15 - ); - Rotation initialRotation = RotationManager.INSTANCE.getCurrentRotation(); - if (initialRotation == null) { - initialRotation = new Rotation(mc.player.getYRot(), mc.player.getXRot(), true); - } - - RaycastMode pointMode = raycast.get(); - boolean ignoreWallsForPoint = pointMode == RaycastMode.NONE || pointMode == RaycastMode.THROUGH_WALLS; - PointInsideBox point = pointTracker.findPoint( - eyes, - target, - 0, - initialRotation, - range, - ignoreWallsForPoint - ); - AABB targetBox = point.box(); - - RotationPreference preference = LeastDifferencePreference.leastDifferenceToLastPoint(eyes, point.pos()); - - RotationWithVector rot = RotationRaytrace.raytraceBox( - eyes, - targetBox, - range, - wallsRange, - RotationRaytrace.OUTLINE_VISIBILITY, - preference, - true - ); - - if (rot == null && rotationThroughWalls.get()) { - rot = RotationRaytrace.raytraceBox( - eyes, - targetBox, - range, - range, - RotationRaytrace.OUTLINE_VISIBILITY, - preference, - true - ); - } - - if (rot == null) { - Rotation fallback = Rotation.lookingAt(point.pos(), eyes).normalize(); - rot = new RotationWithVector(fallback, point.pos()); - } - - if (rot != null) { - lastAimPoint = rot.vec(); - lastAimEntityId = target.getId(); - } - return rot; - } - - private RotationTarget buildRotationTarget(Rotation rotation, Entity target) { - List processors = new ArrayList<>(); - AngleSmooth smooth = selectAngleSmooth(); - if (smooth != null) { - processors.add(smooth); - } - boolean spookyMode = rotationMode.get() == AngleSmoothMode.SPOOKY; - if (!spookyMode && lazyAimEnabled.get()) { - processors.add(lazyAimProcessor); - } - if (!spookyMode && shakeAimEnabled.get()) { - processors.add(shakeAimProcessor); - } - boolean freeCorrection = correctionType.get() == CorrectionType.FREE; - MovementCorrection movementCorrection; - if (correctionType.get() == CorrectionType.NOT_VISIBLE) { - movementCorrection = MovementCorrection.OFF; - } else { - movementCorrection = MovementCorrection.SILENT; - } - - TargetStrafe targetStrafe = Modules.get(TargetStrafe.class); - if (freeCorrection && targetStrafe != null && targetStrafe.shouldDisableAuraFreeCorrection()) { - freeCorrection = false; - } - - return new RotationTarget( - rotation, - target, - processors, - rotationResetTicks.get(), - rotationResetThreshold.get(), - true, - movementCorrection, - freeCorrection, - null - ); - } - - private boolean shouldBlockSprinting(LivingEntity target) { - ElytraTarget elytraTarget = Modules.get(ElytraTarget.class); - if (elytraTarget != null && elytraTarget.isRunning()) { - return false; - } - return false; - } - - public double getRange() { - return range.get(); - } - - public double getAcquireRange() { - return range.get() + Math.max(0.0, acquireRangeIncrement.get()); - } - - public boolean usesDynamicReach() { - return reachMode.get() == Reach.Mode.VULCAN_297; - } - - public double getEffectiveRange(Entity target) { - return getEffectiveAttackRange(target); - } - - private double getEffectiveAttackRange(Entity target) { - return resolveDynamicReach(target, range.get()); - } - - private double getEffectiveAcquireRange(Entity target) { - return Math.max(0.0, getAcquireRange()); - } - - private double getEffectiveWallRange(Entity target, double effectiveRange) { - double requestedWallRange = Math.max(0.0, wallRange.get()); - return usesDynamicReach() && target instanceof Player - ? Math.min(requestedWallRange, Math.max(0.0, effectiveRange)) - : requestedWallRange; - } - - private double resolveDynamicReach(Entity target, double requestedReach) { - double safeReach = Math.max(0.0, requestedReach); - if (usesDynamicReach() && target instanceof Player) { - return VulcanReachController.INSTANCE.clampReach(target, safeReach); - } - return safeReach; - } - - private boolean criticalHitAllowed(LivingEntity target) { - if (target == null || mc.player == null) return true; - if (isLegacyAttackProtocol()) return true; - if (mc.player.isFallFlying()) return true; - - Criticals criticals = Modules.get(Criticals.class); - if (criticals == null) return true; - ClickScheduler gateClicker = isLegacyAttackProtocol() ? clicker : null; - CombatStrikeController.SprintResetMode resolvedSprintReset = - CombatStrikeController.INSTANCE.resolveSprintResetMode(resolveStrikeResetMode()); - boolean ignoreLocalSprintAfterReset = resolvedSprintReset != CombatStrikeController.SprintResetMode.NONE; - return criticals.shouldAttackForKillAura( - gateClicker, - target, - criticalsSelection.get(), - ignoreLocalSprintAfterReset - ); - } - - private int calculateTicks(Rotation rotation) { - AngleSmooth smooth = selectAngleSmooth(); - if (smooth == null) return 0; - Rotation base = RotationManager.INSTANCE.getServerRotation(); - if (base == null) return 0; - return smooth.calculateTicks(base, rotation); - } - - private CombatStrikeController.SprintResetMode resolveStrikeResetMode() { - return switch (sprintResetMode.get()) { - case DEFAULT -> CombatStrikeController.SprintResetMode.DEFAULT; - case LEGIT -> CombatStrikeController.SprintResetMode.LEGIT; - case PACKET -> CombatStrikeController.SprintResetMode.PACKET; - case NONE -> CombatStrikeController.SprintResetMode.NONE; - }; - } - - private AngleSmooth selectAngleSmooth() { - return switch (rotationMode.get()) { - case LINEAR -> linearSmooth; - case SIGMOID -> sigmoidSmooth; - case SMART -> smartSmooth; - case SPOOKY -> spookySmooth; - case NONE -> null; - }; - } - - public enum RaycastMode { - NONE, - STRICT, - THROUGH_WALLS - } - - public enum RotationTiming { - NORMAL, - SNAP, - ON_TICK - } - - @Getter - @RequiredArgsConstructor - public enum AngleSmoothMode implements EnumValue.IdProvider { - LINEAR("Linear"), - SIGMOID("Sigmoid"), - SMART("Smart"), - SPOOKY("Spooky"), - NONE("None"); - - private final String id; - } - - @Getter - @RequiredArgsConstructor - public enum ProtocolMode implements EnumValue.IdProvider { - AUTO("auto"), - FORCE_1_8("1.8"), - FORCE_1_9("1.9"); - - private final String id; - } - - public enum SprintResetMode { - DEFAULT, - LEGIT, - PACKET, - NONE - } - - public enum CorrectionType { - FREE, - FOCUSED, - NOT_VISIBLE - } - - // attack handled by AttackUtil -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/MaceKill.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/MaceKill.java deleted file mode 100644 index 8e598d1..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/MaceKill.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.features.module.modules.combat; - -import net.minecraft.client.Minecraft; -import net.minecraft.network.protocol.game.ServerboundInteractPacket; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.shapes.VoxelShape; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.PacketEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; - -//Такая хуйня на более менее ач работать не будет -// thx liquidbounce -//todo Description -@ModuleInfo( - id = "macekill", - displayName = "MaceKill", - category = ModuleCategory.COMBAT -) -public final class MaceKill extends Module { - public static boolean cancelCrit; - - private final Minecraft mc = Minecraft.getInstance(); - private final NumberValue fallHeight = - num("height", 22, 1, 170); - - @EventHandler - public void onPacketSend(PacketEvent.Send event) { - if (!isEnabled()) return; - if (!(event.getPacket() instanceof ServerboundInteractPacket packet)) return; - if (!isAttack(packet)) return; - - Entity ent = getEntity(packet); - if (ent == null || cancelCrit) return; - - if (!isHoldingMace()) return; - - doCrit(); - } - - private void doCrit() { - if (mc == null || mc.player == null || mc.level == null) return; - int height = determineHeight(); - if (height <= 0) return; - - // Paper/Spigot exploit: send multiple groundless packets for large heights - if (height > 10) { - int repeats = (int) Math.ceil(Math.abs(height / 10.0)); - for (int i = 0; i < repeats; i++) { - sendOnGroundOnly(false); - } - } else { - // Do it at least twice to neutralize horizontal distance - boolean onGround = mc.player.onGround(); - sendOnGroundOnly(onGround); - sendOnGroundOnly(onGround); - } - - // Teleport to the calculated height - sendPosition(mc.player.getX(), mc.player.getY() + height, mc.player.getZ(), false); - // Make sure we get back to the ground - sendPosition(mc.player.getX(), mc.player.getY(), mc.player.getZ(), false); - } - - private void sendOnGroundOnly(boolean onGround) { - if (mc == null || mc.player == null || mc.getConnection() == null) return; - mc.getConnection().send( - new ServerboundMovePlayerPacket.StatusOnly(onGround, mc.player.horizontalCollision) - ); - } - - private void sendPosition(double x, double y, double z, boolean onGround) { - if (mc == null || mc.player == null || mc.getConnection() == null) return; - mc.getConnection().send( - new ServerboundMovePlayerPacket.Pos( - x, y, z, onGround, mc.player.horizontalCollision - ) - ); - } - - private int determineHeight() { - if (mc == null || mc.player == null || mc.level == null) return 0; - - AABB bb = mc.player.getBoundingBox(); - int max = fallHeight.get(); - for (int i = max; i >= 1; i--) { - AABB shifted = bb.move(0.0, i, 0.0); - if (isBoxClear(shifted)) { - return i; - } - } - return 0; - } - - private boolean isBoxClear(AABB box) { - if (mc == null || mc.player == null || mc.level == null) return false; - for (VoxelShape shape : mc.level.getBlockCollisions(mc.player, box)) { - if (!shape.isEmpty()) return false; - } - return true; - } - - private boolean isHoldingMace() { - if (mc == null || mc.player == null) return false; - ItemStack mainHand = mc.player.getMainHandItem(); - return mainHand != null && mainHand.getItem() == Items.MACE; - } - - private Entity getEntity(ServerboundInteractPacket packet) { - if (mc == null || mc.level == null) return null; - int id = packet.entityId(); - return mc.level.getEntity(id); - } - - private boolean isAttack(ServerboundInteractPacket packet) { - return packet.hand() == null && packet.location() == null; - } - -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/ProjectilePuncher.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/ProjectilePuncher.java index 252c183..5ca534f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/ProjectilePuncher.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/ProjectilePuncher.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -55,6 +55,26 @@ import java.util.Map; ) public final class ProjectilePuncher extends Module { + public enum RaycastMode { + STRICT, + THROUGH_WALLS, + NONE + } + + public enum RotationTiming { + NORMAL, + SNAP, + ON_TICK + } + + public enum AngleSmoothMode { + LINEAR, + SIGMOID, + SMART, + SPOOKY, + NONE + } + private static final String PROJECTILE_FIREBALL = "fireball"; private static final String PROJECTILE_SHULKER_BULLET = "shulker_bullet"; private static final int ROTATION_PRIORITY = 10; @@ -93,21 +113,21 @@ public final class ProjectilePuncher extends Module { CommonSettingSchemas.INTERACTION_IGNORE_OPEN_INVENTORY, true ); - private final EnumValue raycast = + private final EnumValue raycast = enumCommon( "projectilePuncherRaycast", "raycast", CommonSettingSchemas.COMBAT_RAYCAST, - KillAura.RaycastMode.STRICT, - KillAura.RaycastMode.values() + RaycastMode.STRICT, + RaycastMode.values() ); - private final EnumValue rotationTiming = + private final EnumValue rotationTiming = enumCommon( "projectilePuncherRotationTiming", "rotation_timing", CommonSettingSchemas.ROTATION_TIMING, - KillAura.RotationTiming.NORMAL, - KillAura.RotationTiming.values() + RotationTiming.NORMAL, + RotationTiming.values() ); private final EnumValue movementCorrection = enumCommon( @@ -117,13 +137,13 @@ public final class ProjectilePuncher extends Module { MovementCorrection.STRICT, MovementCorrection.values() ); - private final EnumValue rotationMode = + private final EnumValue rotationMode = enumCommon( "projectilePuncherRotationMode", "rotation_mode", CommonSettingSchemas.ROTATION_MODE, - KillAura.AngleSmoothMode.SMART, - KillAura.AngleSmoothMode.values() + AngleSmoothMode.SMART, + AngleSmoothMode.values() ); private final NumberValue rotationResetTicks = numCommon( @@ -493,10 +513,10 @@ public final class ProjectilePuncher extends Module { lastRotationTick = mc.player != null ? mc.player.tickCount : -1; rotationReleased = false; - KillAura.RotationTiming timing = rotationTiming.get(); + RotationTiming timing = rotationTiming.get(); int rotTicks = calculateTicks(rotation.rotation()); - if (timing == KillAura.RotationTiming.SNAP && !clicker.willClickAt(Math.max(1, rotTicks))) { + if (timing == RotationTiming.SNAP && !clicker.willClickAt(Math.max(1, rotTicks))) { return true; } @@ -509,8 +529,8 @@ public final class ProjectilePuncher extends Module { if (mc.player == null) return null; Rotation rotation; - KillAura.RotationTiming timing = rotationTiming.get(); - if (timing == KillAura.RotationTiming.ON_TICK) { + RotationTiming timing = rotationTiming.get(); + if (timing == RotationTiming.ON_TICK) { rotation = lastRotationTick == mc.player.tickCount ? lastRotation : null; if (rotation == null) { RotationWithVector rot = findRotation(target, range.get().floatValue(), wallRange.get().floatValue()); @@ -528,11 +548,11 @@ public final class ProjectilePuncher extends Module { } private boolean passesRaycast(Entity target, float yaw, float pitch) { - KillAura.RaycastMode mode = raycast.get(); - if (mode == KillAura.RaycastMode.NONE) return true; + RaycastMode mode = raycast.get(); + if (mode == RaycastMode.NONE) return true; double maxRange = range.get(); - if (mode == KillAura.RaycastMode.THROUGH_WALLS) { + if (mode == RaycastMode.THROUGH_WALLS) { return RaycastUtil.isLookingAtEntity(mc.player, target, yaw, pitch, maxRange, wallRange.get()) != null; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/PvpCooldowns.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/PvpCooldowns.java index e1d66f4..059b850 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/PvpCooldowns.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/PvpCooldowns.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Reach.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Reach.java index b826426..ab4afd5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Reach.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/Reach.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,7 +20,6 @@ import dev.loki.lovisual.config.values.NumberValue; import dev.loki.lovisual.features.module.Module; import dev.loki.lovisual.features.module.ModuleCategory; import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.util.combat.VulcanReachController; import java.util.List; @@ -34,13 +33,19 @@ import java.util.Optional; ) public class Reach extends Module { - public final EnumValue raycast = + public enum RaycastMode { + STRICT, + THROUGH_WALLS, + NONE + } + + public final EnumValue raycast = enumCommon( "reachContext", "raycast", CommonSettingSchemas.COMBAT_RAYCAST, - KillAura.RaycastMode.STRICT, - KillAura.RaycastMode.values() + RaycastMode.STRICT, + RaycastMode.values() ); private final Minecraft mc = Minecraft.getInstance(); @@ -70,7 +75,7 @@ public class Reach extends Module { 3.0, 0.0, 6.0 - ), () -> raycast.get() == KillAura.RaycastMode.THROUGH_WALLS); + ), () -> raycast.get() == RaycastMode.THROUGH_WALLS); private static double boxDistanceSq(AABB box, Vec3 p) { double dx = 0.0; @@ -93,7 +98,7 @@ public class Reach extends Module { if (player == null || mc.level == null) return null; double visibleRange = distance.get(); - double throughWallsRange = raycast.get() == KillAura.RaycastMode.THROUGH_WALLS + double throughWallsRange = raycast.get() == RaycastMode.THROUGH_WALLS ? wallDistance.get() : 0.0; double searchRange = Math.max(visibleRange, throughWallsRange); @@ -120,7 +125,7 @@ public class Reach extends Module { if (player == null || mc.level == null) return null; double visibleRange = distance.get(); - double throughWallsRange = raycast.get() == KillAura.RaycastMode.THROUGH_WALLS + double throughWallsRange = raycast.get() == RaycastMode.THROUGH_WALLS ? wallDistance.get() : 0.0; double searchRange = Math.max(visibleRange, throughWallsRange); @@ -147,20 +152,13 @@ public class Reach extends Module { List candidates, double blockLimitSq, double requestedReach) { - Hitbox hb = Modules.get(Hitbox.class); - EntityHitResult bestHit = null; double bestBoxDistSq = Double.MAX_VALUE; double bestHitDistSq = Double.MAX_VALUE; for (Entity e : candidates) { - if (hb != null && hb.isEnabled() && hb.shouldIgnore(e)) continue; - AABB baseBox = e.getBoundingBox(); AABB bb = baseBox; - if (hb != null && hb.isEnabled() && hb.shouldExpandFor(e)) { - bb = bb.inflate(hb.getPadding()); - } Optional hit = bb.contains(start) ? Optional.of(start) @@ -169,7 +167,7 @@ public class Reach extends Module { if (hit.isEmpty()) continue; double boxDistSq = boxDistanceSq(baseBox, start); - double entityReach = resolveEntityReach(e, requestedReach, hb); + double entityReach = resolveEntityReach(e, requestedReach); double entityReachSq = entityReach * entityReach; if (boxDistSq > entityReachSq) continue; if (boxDistSq > blockLimitSq) continue; @@ -187,7 +185,7 @@ public class Reach extends Module { return bestHit; } - private double resolveEntityReach(Entity entity, double requestedReach, Hitbox hitbox) { + private double resolveEntityReach(Entity entity, double requestedReach) { if (mode.get() == Mode.VULCAN_297 && entity instanceof Player) { return VulcanReachController.INSTANCE.clampReach(entity, requestedReach); } @@ -207,17 +205,14 @@ public class Reach extends Module { Vec3 end, double visibleRange, double throughWallsRange) { - KillAura.RaycastMode mode = raycast.get(); + RaycastMode mode = raycast.get(); - if (mode == KillAura.RaycastMode.NONE) { + if (mode == RaycastMode.NONE) { double maxRange = Math.max(visibleRange, throughWallsRange); return maxRange * maxRange; } - Hitbox hitbox = Modules.get(Hitbox.class); - boolean forceThrough = hitbox != null && hitbox.isEnabled(); - - if (mode == KillAura.RaycastMode.THROUGH_WALLS || forceThrough) { + if (mode == RaycastMode.THROUGH_WALLS) { double maxAllowed = Math.max(visibleRange, throughWallsRange); HitResult blockHit = mc.level.clip(new ClipContext( diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/RubberHand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/RubberHand.java index e7297d8..202586d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/RubberHand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/RubberHand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/SpearAssist.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/SpearAssist.java index 0d57cff..85eb526 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/SpearAssist.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/SpearAssist.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/TPSSync.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/TPSSync.java index 62c071c..0e0f30a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/TPSSync.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/TPSSync.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorActionUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorActionUtil.java deleted file mode 100644 index f8a7ca4..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorActionUtil.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autoanchor; - -import dev.loki.lovisual.util.player.inventory.InventoryActionKind; -import dev.loki.lovisual.util.player.inventory.InventorySearchScope; -import dev.loki.lovisual.util.player.inventory.InventorySwap; -import dev.loki.lovisual.util.player.inventory.InventorySwapRequest; -import dev.loki.lovisual.util.player.inventory.InventorySwapVisibility; -import dev.loki.lovisual.util.combat.RubberHandUseUtil; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.RespawnAnchorBlock; -import net.minecraft.world.phys.BlockHitResult; - -import java.util.function.Predicate; - -public final class AutoAnchorActionUtil { - private AutoAnchorActionUtil() { - } - - public static boolean placeAnchor(Minecraft mc, - Object owner, - BlockHitResult hitResult, - InventorySearchScope scope, - InventorySwapVisibility visibility, - boolean restore) { - if (mc == null || owner == null || hitResult == null || mc.player == null || mc.gameMode == null) return false; - LocalPlayer player = mc.player; - InteractionHand held = AutoAnchorInteractionUtil.heldAnchorHand(player); - if (held != null) { - return useOn(mc, held, hitResult); - } - - return executeSwap(AutoAnchorInteractionUtil::isAnchor, scope, visibility, restore, - () -> useOn(mc, InteractionHand.MAIN_HAND, hitResult)); - } - - public static boolean explodeAnchor(Minecraft mc, - Object owner, - BlockHitResult hitResult, - InventorySearchScope scope, - InventorySwapVisibility visibility, - boolean restore) { - if (mc == null || owner == null || hitResult == null || mc.player == null || mc.level == null || mc.gameMode == null) return false; - - int charges = 0; - var state = mc.level.getBlockState(hitResult.getBlockPos()); - if (state.hasProperty(RespawnAnchorBlock.CHARGE)) { - charges = state.getValue(RespawnAnchorBlock.CHARGE); - } - - if (charges <= 0) { - return chargeAnchor(mc, hitResult, scope, visibility, restore); - } - - return detonateAnchor(mc, hitResult, scope, visibility, restore); - } - - public static boolean chargeAnchor(Minecraft mc, - BlockHitResult hitResult, - InventorySearchScope scope, - InventorySwapVisibility visibility, - boolean restore) { - if (mc == null || hitResult == null || mc.player == null || mc.gameMode == null) return false; - InteractionHand held = AutoAnchorInteractionUtil.heldGlowstoneHand(mc.player); - if (held != null) { - return useOn(mc, held, hitResult); - } - return executeSwap(AutoAnchorInteractionUtil::isGlowstone, scope, visibility, restore, - () -> useOn(mc, InteractionHand.MAIN_HAND, hitResult)); - } - - public static boolean detonateAnchor(Minecraft mc, - BlockHitResult hitResult, - InventorySearchScope scope, - InventorySwapVisibility visibility, - boolean restore) { - if (mc == null || hitResult == null || mc.player == null || mc.gameMode == null) return false; - InteractionHand held = AutoAnchorInteractionUtil.heldDetonatorHand(mc.player); - if (held != null) { - return useOn(mc, held, hitResult); - } - return executeSwap(AutoAnchorInteractionUtil::isDetonator, scope, visibility, restore, - () -> useOn(mc, InteractionHand.MAIN_HAND, hitResult)); - } - - public static boolean hasAnchor(Minecraft mc, InventorySearchScope scope) { - if (mc == null || mc.player == null) return false; - if (AutoAnchorInteractionUtil.heldAnchorHand(mc.player) != null) return true; - return InventorySwap.INSTANCE.findSlotForMode(AutoAnchorInteractionUtil::isAnchor, modeFor(scope, true)).found(); - } - - public static boolean hasGlowstone(Minecraft mc, InventorySearchScope scope) { - if (mc == null || mc.player == null) return false; - if (AutoAnchorInteractionUtil.heldGlowstoneHand(mc.player) != null) return true; - return InventorySwap.INSTANCE.findSlotForMode(AutoAnchorInteractionUtil::isGlowstone, modeFor(scope, true)).found(); - } - - private static boolean executeSwap(Predicate predicate, - InventorySearchScope scope, - InventorySwapVisibility visibility, - boolean restore, - Runnable action) { - return InventorySwap.INSTANCE.execute(InventorySwapRequest.builder(predicate, action) - .scope(scope != null ? scope : InventorySearchScope.FULL) - .visibility(visibility != null ? visibility : InventorySwapVisibility.SILENT) - .restore(restore) - .actionKind(InventoryActionKind.BLOCK_INTERACT) - .build()); - } - - private static dev.loki.lovisual.util.player.inventory.InventorySwapMode modeFor(InventorySearchScope scope, boolean silent) { - InventorySearchScope safeScope = scope != null ? scope : InventorySearchScope.FULL; - return switch (safeScope) { - case HOTBAR -> silent - ? dev.loki.lovisual.util.player.inventory.InventorySwapMode.SILENT - : dev.loki.lovisual.util.player.inventory.InventorySwapMode.NORMAL; - case INVENTORY -> silent - ? dev.loki.lovisual.util.player.inventory.InventorySwapMode.INVENTORY_SILENT - : dev.loki.lovisual.util.player.inventory.InventorySwapMode.INVENTORY_NORMAL; - case FULL -> silent - ? dev.loki.lovisual.util.player.inventory.InventorySwapMode.SILENT_FULL - : dev.loki.lovisual.util.player.inventory.InventorySwapMode.NORMAL_FULL; - }; - } - - private static boolean useOn(Minecraft mc, InteractionHand hand, BlockHitResult hitResult) { - if (mc.player == null || mc.gameMode == null || hand == null || hitResult == null) return false; - return RubberHandUseUtil.runBlockUse(mc, () -> { - InteractionResult result = mc.gameMode.useItemOn(mc.player, hand, hitResult); - mc.player.swing(hand); - return result != InteractionResult.FAIL; - }); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorDamageCandidate.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorDamageCandidate.java deleted file mode 100644 index e17a2ac..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorDamageCandidate.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autoanchor; - -public interface AutoAnchorDamageCandidate { - float damage(); - - float selfDamage(); - - boolean overrideDamage(); -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorDamageRules.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorDamageRules.java deleted file mode 100644 index 93f8141..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorDamageRules.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autoanchor; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; - -public final class AutoAnchorDamageRules { - private AutoAnchorDamageRules() { - } - - public static boolean shouldOverrideMinDamage(LivingEntity target, float damage, float faceplaceHealth) { - if (target == null) return false; - if (target.getHealth() + target.getAbsorptionAmount() <= faceplaceHealth) return true; - return damage >= target.getHealth() + target.getAbsorptionAmount() - 0.5f; - } - - public static boolean shouldOverrideMaxSelfDamage(Player player, - LivingEntity target, - float damage, - float selfDamage, - float maxSelfDamage) { - if (player == null || target == null) return false; - if (selfDamage <= maxSelfDamage) return false; - - boolean targetSafe = holdsTotem(target); - boolean playerSafe = holdsTotem(player); - float targetHp = target.getHealth() + target.getAbsorptionAmount() - 1.0f; - float playerHp = player.getHealth() + player.getAbsorptionAmount() - 1.0f; - - boolean canPop = damage > targetHp && targetSafe; - boolean canKill = damage > targetHp && !targetSafe; - boolean canPopSelf = selfDamage > playerHp && playerSafe; - boolean canKillSelf = selfDamage > playerHp && !playerSafe; - - if (canPopSelf && canKill) return true; - return (canPop || canKill) && !canKillSelf && !canPopSelf; - } - - public static boolean isSafe(Player player, float selfDamage, boolean overrideDamage) { - if (player == null) return false; - if (overrideDamage) return true; - return selfDamage + 0.5f <= player.getHealth() + player.getAbsorptionAmount(); - } - - public static T selectBest(Iterable candidates, - LivingEntity target, - float minDamage, - float faceplaceHealth) { - T best = null; - float bestDamage = 0.0f; - for (T data : candidates) { - if (data == null) continue; - if (!(shouldOverrideMinDamage(target, data.damage(), faceplaceHealth) || data.damage() > minDamage)) { - continue; - } - - if (best != null - && Math.abs(best.damage() - data.damage()) < 1.0f - && best.selfDamage() > data.selfDamage()) { - best = data; - bestDamage = data.damage(); - continue; - } - - if (data.damage() > bestDamage) { - best = data; - bestDamage = data.damage(); - } - } - return best; - } - - private static boolean holdsTotem(LivingEntity entity) { - if (entity == null) return false; - ItemStack main = entity.getMainHandItem(); - ItemStack off = entity.getOffhandItem(); - return (!main.isEmpty() && main.is(Items.TOTEM_OF_UNDYING)) - || (!off.isEmpty() && off.is(Items.TOTEM_OF_UNDYING)); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorData.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorData.java deleted file mode 100644 index 5c159a3..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorData.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autoanchor; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.BlockHitResult; - -public record AutoAnchorData( - BlockPos pos, - BlockHitResult hitResult, - float damage, - float selfDamage, - boolean overrideDamage, - boolean existingAnchor, - int charges -) implements AutoAnchorDamageCandidate { - public boolean charged() { - return existingAnchor && charges > 0; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorEntityBlocker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorEntityBlocker.java deleted file mode 100644 index 0bf1a0b..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorEntityBlocker.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autoanchor; - -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.ExperienceOrb; -import net.minecraft.world.phys.AABB; - -public final class AutoAnchorEntityBlocker { - public boolean isBlocked(ClientLevel level, BlockPos pos) { - if (level == null || pos == null) return true; - - AABB box = new AABB(pos); - for (Entity entity : level.entitiesForRendering()) { - if (entity == null || !entity.isAlive() || entity.isRemoved() || entity instanceof ExperienceOrb) { - continue; - } - if (entity.getBoundingBox().intersects(box)) { - return true; - } - } - return false; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorInteractionUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorInteractionUtil.java deleted file mode 100644 index e425808..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorInteractionUtil.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autoanchor; - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; - -public final class AutoAnchorInteractionUtil { - private AutoAnchorInteractionUtil() { - } - - public static Vec3 anchorVec(BlockPos pos) { - return Vec3.atCenterOf(pos); - } - - public static boolean hasSolidPlaceSupport(Level level, BlockPos placePos) { - if (level == null || placePos == null) return false; - for (Direction direction : Direction.values()) { - BlockPos support = placePos.relative(direction); - if (!level.isInWorldBounds(support)) continue; - - BlockState state = level.getBlockState(support); - if (!state.isAir() && !state.canBeReplaced() && !state.getCollisionShape(level, support).isEmpty()) { - return true; - } - } - return false; - } - - public static BlockHitResult getInteractResult( - Level level, - LocalPlayer player, - BlockPos pos, - boolean existingAnchor, - boolean allowAirPlace, - AutoAnchorPlacementMode mode, - float range, - float wallRange - ) { - if (existingAnchor || allowAirPlace) { - return getAnchorInteractResult(level, player, pos, mode, range, wallRange); - } - return getPlaceSupportInteract(level, player, pos, mode, range, wallRange); - } - - public static BlockHitResult getAnchorInteractResult( - Level level, - LocalPlayer player, - BlockPos pos, - AutoAnchorPlacementMode mode, - float range, - float wallRange - ) { - if (mode == AutoAnchorPlacementMode.STRICT) { - return getStrictAnchorInteract(level, player, pos, range, wallRange); - } - if (mode == AutoAnchorPlacementMode.LEGIT) { - return getLegitAnchorInteract(level, player, pos, range, wallRange); - } - return getDefaultAnchorInteract(level, player, pos, range, wallRange); - } - - public static BlockHitResult getDefaultAnchorInteract(Level level, - LocalPlayer player, - BlockPos pos, - float range, - float wallRange) { - if (level == null || player == null || pos == null) return null; - - Vec3 vec = Vec3.atCenterOf(pos); - Vec3 eyes = player.getEyePosition(); - double distanceSq = eyes.distanceToSqr(vec); - if (distanceSq > range * range) return null; - - if (!isVisibleOrWithinWallRange(level, player, eyes, vec, pos, distanceSq, wallRange)) { - return null; - } - - Direction side = player.getEyeY() >= pos.getY() + 0.5 ? Direction.UP : Direction.DOWN; - return new BlockHitResult(vec, side, pos, false); - } - - public static BlockHitResult getStrictAnchorInteract(Level level, - LocalPlayer player, - BlockPos pos, - float range, - float wallRange) { - if (level == null || player == null || pos == null) return null; - - Vec3 eyes = player.getEyePosition(); - double bestDistance = Double.MAX_VALUE; - BlockHitResult best = null; - - for (Direction direction : Direction.values()) { - Vec3 normal = Vec3.atLowerCornerOf(direction.getUnitVec3i()); - Vec3 sample = Vec3.atCenterOf(pos).add(normal.scale(0.5)); - double distanceSq = eyes.distanceToSqr(sample); - if (distanceSq > range * range) continue; - if (!isVisibleOrWithinWallRange(level, player, eyes, sample, pos, distanceSq, wallRange)) continue; - - if (distanceSq < bestDistance) { - bestDistance = distanceSq; - best = new BlockHitResult(sample, direction, pos, false); - } - } - - return best; - } - - public static BlockHitResult getLegitAnchorInteract(Level level, - LocalPlayer player, - BlockPos pos, - float range, - float wallRange) { - if (level == null || player == null || pos == null) return null; - - Vec3 eyes = player.getEyePosition(); - double bestDistance = Double.MAX_VALUE; - BlockHitResult best = null; - for (float x = 0.1f; x <= 0.9f; x += 0.2f) { - for (float y = 0.1f; y <= 0.9f; y += 0.2f) { - for (float z = 0.1f; z <= 0.9f; z += 0.2f) { - Vec3 point = new Vec3(pos.getX() + x, pos.getY() + y, pos.getZ() + z); - double distanceSq = eyes.distanceToSqr(point); - if (distanceSq > range * range) continue; - if (!isVisibleOrWithinWallRange(level, player, eyes, point, pos, distanceSq, wallRange)) continue; - - if (distanceSq < bestDistance) { - bestDistance = distanceSq; - best = new BlockHitResult(point, Direction.UP, pos, false); - } - } - } - } - return best; - } - - - public static BlockHitResult getSyntheticAnchorInteractResult(LocalPlayer player, - BlockPos pos, - float range) { - if (player == null || pos == null) return null; - Vec3 vec = Vec3.atCenterOf(pos); - if (player.getEyePosition().distanceToSqr(vec) > range * range) return null; - Direction side = player.getEyeY() >= pos.getY() + 0.5 ? Direction.UP : Direction.DOWN; - return new BlockHitResult(vec, side, pos, false); - } - - public static BlockHitResult getPlaceSupportInteract(Level level, - LocalPlayer player, - BlockPos placePos, - AutoAnchorPlacementMode mode, - float range, - float wallRange) { - if (level == null || player == null || placePos == null) return null; - - Vec3 eyes = player.getEyePosition(); - double bestDistance = Double.MAX_VALUE; - BlockHitResult best = null; - for (Direction direction : Direction.values()) { - BlockPos support = placePos.relative(direction); - if (!level.isInWorldBounds(support)) continue; - - BlockState state = level.getBlockState(support); - if (state.isAir() || state.canBeReplaced() || state.getCollisionShape(level, support).isEmpty()) { - continue; - } - - Direction face = direction.getOpposite(); - BlockHitResult candidate = mode == AutoAnchorPlacementMode.LEGIT - ? getBestSupportFacePoint(level, player, support, face, range, wallRange) - : getSupportFaceCenter(level, player, support, face, range, wallRange); - if (candidate == null) continue; - - double distanceSq = eyes.distanceToSqr(candidate.getLocation()); - if (distanceSq < bestDistance) { - bestDistance = distanceSq; - best = candidate; - } - } - return best; - } - - private static BlockHitResult getSupportFaceCenter(Level level, - LocalPlayer player, - BlockPos support, - Direction face, - float range, - float wallRange) { - Vec3 eyes = player.getEyePosition(); - Vec3 normal = Vec3.atLowerCornerOf(face.getUnitVec3i()); - Vec3 hitVec = Vec3.atCenterOf(support).add(normal.scale(0.5)); - double distanceSq = eyes.distanceToSqr(hitVec); - if (distanceSq > range * range) return null; - if (!isVisibleOrWithinWallRange(level, player, eyes, hitVec, support, distanceSq, wallRange)) return null; - return new BlockHitResult(hitVec, face, support, false); - } - - private static BlockHitResult getBestSupportFacePoint(Level level, - LocalPlayer player, - BlockPos support, - Direction face, - float range, - float wallRange) { - Vec3 eyes = player.getEyePosition(); - double bestDistance = Double.MAX_VALUE; - Vec3 bestPoint = null; - - for (float a = 0.2f; a <= 0.8f; a += 0.3f) { - for (float b = 0.2f; b <= 0.8f; b += 0.3f) { - Vec3 point = pointOnFace(support, face, a, b); - double distanceSq = eyes.distanceToSqr(point); - if (distanceSq > range * range) continue; - if (!isVisibleOrWithinWallRange(level, player, eyes, point, support, distanceSq, wallRange)) continue; - if (distanceSq < bestDistance) { - bestDistance = distanceSq; - bestPoint = point; - } - } - } - - return bestPoint == null ? null : new BlockHitResult(bestPoint, face, support, false); - } - - private static Vec3 pointOnFace(BlockPos pos, Direction face, float a, float b) { - double x = pos.getX(); - double y = pos.getY(); - double z = pos.getZ(); - return switch (face) { - case DOWN -> new Vec3(x + a, y, z + b); - case UP -> new Vec3(x + a, y + 1.0, z + b); - case NORTH -> new Vec3(x + a, y + b, z); - case SOUTH -> new Vec3(x + a, y + b, z + 1.0); - case WEST -> new Vec3(x, y + a, z + b); - case EAST -> new Vec3(x + 1.0, y + a, z + b); - }; - } - - private static boolean isVisibleOrWithinWallRange(Level level, - LocalPlayer player, - Vec3 eyes, - Vec3 point, - BlockPos expectedBlock, - double distanceSq, - float wallRange) { - BlockHitResult wall = level.clip(new ClipContext( - eyes, - point, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - if (wall == null || wall.getType() != HitResult.Type.BLOCK || expectedBlock.equals(wall.getBlockPos())) { - return true; - } - return distanceSq <= wallRange * wallRange; - } - - public static InteractionHand heldAnchorHand(LocalPlayer player) { - if (player == null) return null; - if (player.getOffhandItem().is(Items.RESPAWN_ANCHOR)) return InteractionHand.OFF_HAND; - if (player.getMainHandItem().is(Items.RESPAWN_ANCHOR)) return InteractionHand.MAIN_HAND; - return null; - } - - public static InteractionHand heldGlowstoneHand(LocalPlayer player) { - if (player == null) return null; - if (player.getOffhandItem().is(Items.GLOWSTONE)) return InteractionHand.OFF_HAND; - if (player.getMainHandItem().is(Items.GLOWSTONE)) return InteractionHand.MAIN_HAND; - return null; - } - - public static InteractionHand heldDetonatorHand(LocalPlayer player) { - if (player == null) return null; - if (!isGlowstone(player.getMainHandItem())) return InteractionHand.MAIN_HAND; - if (!isGlowstone(player.getOffhandItem())) return InteractionHand.OFF_HAND; - return null; - } - - public static boolean isAnchor(ItemStack stack) { - return stack != null && !stack.isEmpty() && stack.is(Items.RESPAWN_ANCHOR); - } - - public static boolean isGlowstone(ItemStack stack) { - return stack != null && !stack.isEmpty() && stack.is(Items.GLOWSTONE); - } - - public static boolean isDetonator(ItemStack stack) { - return stack == null || stack.isEmpty() || !stack.is(Items.GLOWSTONE); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorPlacementMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorPlacementMode.java deleted file mode 100644 index edae67f..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorPlacementMode.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autoanchor; - -public enum AutoAnchorPlacementMode { - DEFAULT, - STRICT, - LEGIT -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorPlanner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorPlanner.java deleted file mode 100644 index 1500b59..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorPlanner.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autoanchor; - -import dev.loki.lovisual.util.world.ExplosionDamageUtil; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.RespawnAnchorBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -public final class AutoAnchorPlanner { - private static final float ANCHOR_POWER = 5.0f; - private static final double TARGET_MAX_DISTANCE_SQ = 144.0; - private static final float MIN_RAW_DAMAGE = 1.5f; - private static final int MAX_PLACE_DAMAGE_EVALUATIONS = 64; - private static final int MAX_EXISTING_DAMAGE_EVALUATIONS = 32; - private static final double SUPPORT_RANGE_MARGIN = 0.95; - - private int lastScanned; - private int lastCandidates; - private int lastSafeCandidates; - private int lastSelfDamageRejects; - - public ScanResult scan(Context context, LivingEntity target, Vec3 center, int range) { - lastScanned = 0; - lastCandidates = 0; - lastSafeCandidates = 0; - lastSelfDamageRejects = 0; - - if (context == null || context.player() == null || context.level() == null || target == null || center == null) { - return new ScanResult(null, null, 0, 0, 0, 0); - } - - Vec3 predictedTarget = context.resolvePredictedPosition(target, context.predictTicks()); - Vec3 eyes = context.player().getEyePosition(); - BlockPos origin = BlockPos.containing(center); - int horizontalRange = Math.max(1, range); - int verticalRange = Math.min(horizontalRange, 3); - double radiusSq = (double) horizontalRange * horizontalRange; - - List placeShells = new ArrayList<>(); - List existingShells = new ArrayList<>(); - for (int x = origin.getX() - horizontalRange; x <= origin.getX() + horizontalRange; x++) { - for (int y = origin.getY() - verticalRange; y <= origin.getY() + verticalRange; y++) { - for (int z = origin.getZ() - horizontalRange; z <= origin.getZ() + horizontalRange; z++) { - BlockPos pos = new BlockPos(x, y, z); - Vec3 anchorVec = AutoAnchorInteractionUtil.anchorVec(pos); - if (anchorVec.distanceToSqr(center) > radiusSq) { - continue; - } - - lastScanned++; - CandidateShell shell = collectShell(context, pos, anchorVec, target, predictedTarget, eyes); - if (shell == null) continue; - if (shell.existingAnchor()) { - existingShells.add(shell); - } else { - placeShells.add(shell); - } - } - } - } - - Comparator byPotential = Comparator - .comparingDouble(CandidateShell::estimatedDamage) - .reversed() - .thenComparingDouble(CandidateShell::targetDistanceSq) - .thenComparingDouble(CandidateShell::eyeDistanceSq); - placeShells.sort(byPotential); - existingShells.sort(byPotential); - - List place = evaluateShells(context, target, placeShells, MAX_PLACE_DAMAGE_EVALUATIONS); - List explode = evaluateShells(context, target, existingShells, MAX_EXISTING_DAMAGE_EVALUATIONS); - - AutoAnchorData bestPlace = AutoAnchorDamageRules.selectBest( - place, - target, - context.minDamage(), - context.faceplaceHealth() - ); - AutoAnchorData bestExplode = AutoAnchorDamageRules.selectBest( - explode, - target, - context.minDamage(), - context.faceplaceHealth() - ); - return new ScanResult(bestPlace, bestExplode, lastScanned, lastCandidates, lastSafeCandidates, lastSelfDamageRejects); - } - - public AutoAnchorData evaluate(Context context, BlockPos pos, LivingEntity target) { - if (context == null || context.player() == null || context.level() == null || target == null || pos == null) { - return null; - } - - Vec3 predictedTarget = context.resolvePredictedPosition(target, context.predictTicks()); - CandidateShell shell = collectShell( - context, - pos, - AutoAnchorInteractionUtil.anchorVec(pos), - target, - predictedTarget, - context.player().getEyePosition() - ); - return evaluateShell(context, target, shell); - } - - private CandidateShell collectShell(Context context, - BlockPos pos, - Vec3 anchorVec, - LivingEntity target, - Vec3 predictedTarget, - Vec3 eyes) { - LocalPlayer player = context.player(); - ClientLevel level = context.level(); - if (player == null || level == null || target == null || pos == null || anchorVec == null || predictedTarget == null || eyes == null) { - return null; - } - if (!level.isInWorldBounds(pos)) { - return null; - } - - double targetDistanceSq = predictedTarget.distanceToSqr(anchorVec); - if (targetDistanceSq > TARGET_MAX_DISTANCE_SQ) { - return null; - } - - double quickRange = Math.max(0.0f, context.placeRange()) + SUPPORT_RANGE_MARGIN; - double eyeDistanceSq = eyes.distanceToSqr(anchorVec); - if (eyeDistanceSq > quickRange * quickRange) { - return null; - } - - float estimatedDamage = estimateMaxPreArmorDamage(predictedTarget, anchorVec); - if (estimatedDamage < MIN_RAW_DAMAGE) { - return null; - } - if (!(AutoAnchorDamageRules.shouldOverrideMinDamage(target, estimatedDamage, context.faceplaceHealth()) - || estimatedDamage > context.minDamage())) { - return null; - } - - BlockState state = level.getBlockState(pos); - boolean existingAnchor = state.is(Blocks.RESPAWN_ANCHOR); - int charges = existingAnchor && state.hasProperty(RespawnAnchorBlock.CHARGE) - ? state.getValue(RespawnAnchorBlock.CHARGE) - : 0; - - if (!existingAnchor) { - if (!state.canBeReplaced()) { - return null; - } - if (!context.allowAirPlace() && !AutoAnchorInteractionUtil.hasSolidPlaceSupport(level, pos)) { - return null; - } - } - - return new CandidateShell(pos, anchorVec, existingAnchor, charges, targetDistanceSq, eyeDistanceSq, estimatedDamage); - } - - private List evaluateShells(Context context, - LivingEntity target, - List shells, - int maxDamageEvaluations) { - List out = new ArrayList<>(); - if (shells == null || shells.isEmpty()) return out; - - int evaluated = 0; - int limit = Math.max(1, maxDamageEvaluations); - for (CandidateShell shell : shells) { - if (shell == null) continue; - if (evaluated++ >= limit) break; - - AutoAnchorData data = evaluateShell(context, target, shell); - if (data == null) continue; - out.add(data); - } - return out; - } - - private AutoAnchorData evaluateShell(Context context, LivingEntity target, CandidateShell shell) { - if (context == null || target == null || shell == null) { - return null; - } - LocalPlayer player = context.player(); - if (player == null) { - return null; - } - - float damage = ExplosionDamageUtil.getExplosionDamage( - target, - shell.anchorVec(), - ANCHOR_POWER, - context.predictTicks(), - false - ); - if (damage < MIN_RAW_DAMAGE) { - return null; - } - if (!(AutoAnchorDamageRules.shouldOverrideMinDamage(target, damage, context.faceplaceHealth()) - || damage > context.minDamage())) { - return null; - } - lastCandidates++; - - float selfDamage = ExplosionDamageUtil.getExplosionDamage( - player, - shell.anchorVec(), - ANCHOR_POWER, - context.selfPredictTicks(), - false - ); - boolean overrideDamage = context.shouldOverrideMaxSelfDamage(damage, selfDamage); - if (selfDamage > context.maxSelfDamage() && !overrideDamage) { - lastSelfDamageRejects++; - return null; - } - if (!context.isSafe(damage, selfDamage, overrideDamage)) { - return null; - } - - if (!shell.existingAnchor() && context.isBlockedByEntity(shell.pos())) { - return null; - } - - BlockHitResult interact = context.getInteractResult(shell.pos(), shell.existingAnchor()); - if (interact == null) { - return null; - } - - lastSafeCandidates++; - return new AutoAnchorData( - shell.pos(), - interact, - damage, - selfDamage, - overrideDamage, - shell.existingAnchor(), - shell.charges() - ); - } - - private static float estimateMaxPreArmorDamage(Vec3 entityPos, Vec3 anchorVec) { - if (entityPos == null || anchorVec == null) return 0.0f; - double explosionDiameter = ANCHOR_POWER * 2.0; - double distance = Math.max(0.0, Math.sqrt(entityPos.distanceToSqr(anchorVec)) - 1.5); - if (distance > explosionDiameter) return 0.0f; - - double distanceDecay = 1.0 - distance / explosionDiameter; - return (float) (((distanceDecay * distanceDecay + distanceDecay) / 2.0) * 7.0 * explosionDiameter + 1.0); - } - - public int lastScanned() { - return lastScanned; - } - - public int lastCandidates() { - return lastCandidates; - } - - public int lastSafeCandidates() { - return lastSafeCandidates; - } - - public int lastSelfDamageRejects() { - return lastSelfDamageRejects; - } - - public interface Context { - LocalPlayer player(); - - ClientLevel level(); - - Vec3 resolvePredictedPosition(LivingEntity entity, int ticks); - - BlockHitResult getInteractResult(BlockPos pos, boolean existingAnchor); - - boolean isBlockedByEntity(BlockPos pos); - - boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage); - - boolean isSafe(float damage, float selfDamage, boolean overrideDamage); - - boolean allowAirPlace(); - - float placeRange(); - - float minDamage(); - - float faceplaceHealth(); - - float maxSelfDamage(); - - int predictTicks(); - - int selfPredictTicks(); - } - - private record CandidateShell( - BlockPos pos, - Vec3 anchorVec, - boolean existingAnchor, - int charges, - double targetDistanceSq, - double eyeDistanceSq, - float estimatedDamage - ) { - } - - public record ScanResult( - AutoAnchorData bestPlace, - AutoAnchorData bestExplode, - int scanned, - int candidates, - int safeCandidates, - int selfDamageRejects - ) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorRenderUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorRenderUtil.java deleted file mode 100644 index 1bfb408..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autoanchor/AutoAnchorRenderUtil.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autoanchor; - -import dev.loki.lovisual.render.engine.renderer.Renderer3D; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.AABB; - -import java.util.Locale; - -public final class AutoAnchorRenderUtil { - private AutoAnchorRenderUtil() { - } - - public static String formatDamage(float value) { - if (value <= 0.0f) return ""; - String text = String.format(Locale.US, "%.2f", value); - int end = text.length(); - while (end > 0 && text.charAt(end - 1) == '0') end--; - if (end > 0 && text.charAt(end - 1) == '.') end--; - return text.substring(0, Math.max(end, 0)); - } - - public static double measureWidth(TextRenderer renderer, String text, double scale) { - if (renderer == null || text == null || text.isEmpty()) return 0.0; - renderer.begin(scale, true, false); - try { - return renderer.getWidth(text, false); - } finally { - renderer.end(); - } - } - - public static AABB lerpBox(AABB from, AABB to, float progress) { - float t = Mth.clamp(progress, 0.0f, 1.0f); - return new AABB( - Mth.lerp(t, from.minX, to.minX), - Mth.lerp(t, from.minY, to.minY), - Mth.lerp(t, from.minZ, to.minZ), - Mth.lerp(t, from.maxX, to.maxX), - Mth.lerp(t, from.maxY, to.maxY), - Mth.lerp(t, from.maxZ, to.maxZ) - ); - } - - public static int applyOpacity(int argb, float opacity) { - opacity = Math.max(0.0f, Math.min(1.0f, opacity)); - int alpha = (argb >>> 24) & 0xFF; - int outAlpha = Mth.clamp((int) (alpha * opacity), 0, 255); - return (outAlpha << 24) | (argb & 0x00FFFFFF); - } - - public static void addFilledBox(Renderer3D renderer, AABB box, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - renderer.quad(minX, minY, minZ, maxX, minY, minZ, maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - renderer.quad(minX, maxY, minZ, minX, maxY, maxZ, maxX, maxY, maxZ, maxX, maxY, minZ, r, g, b, a); - renderer.quad(minX, minY, maxZ, maxX, minY, maxZ, maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - renderer.quad(minX, minY, minZ, minX, maxY, minZ, maxX, maxY, minZ, maxX, minY, minZ, r, g, b, a); - renderer.quad(maxX, minY, minZ, maxX, maxY, minZ, maxX, maxY, maxZ, maxX, minY, maxZ, r, g, b, a); - renderer.quad(minX, minY, minZ, minX, minY, maxZ, minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - } - - public static void addOutlineBox(Renderer3D renderer, AABB box, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - renderer.line(minX, minY, minZ, maxX, minY, minZ, r, g, b, a); - renderer.line(maxX, minY, minZ, maxX, minY, maxZ, r, g, b, a); - renderer.line(maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - renderer.line(minX, minY, maxZ, minX, minY, minZ, r, g, b, a); - - renderer.line(minX, maxY, minZ, maxX, maxY, minZ, r, g, b, a); - renderer.line(maxX, maxY, minZ, maxX, maxY, maxZ, r, g, b, a); - renderer.line(maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - renderer.line(minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - - renderer.line(minX, minY, minZ, minX, maxY, minZ, r, g, b, a); - renderer.line(maxX, minY, minZ, maxX, maxY, minZ, r, g, b, a); - renderer.line(maxX, minY, maxZ, maxX, maxY, maxZ, r, g, b, a); - renderer.line(minX, minY, maxZ, minX, maxY, maxZ, r, g, b, a); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedActionUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedActionUtil.java deleted file mode 100644 index aeed70f..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedActionUtil.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autobed; - -import dev.loki.lovisual.util.player.inventory.InventoryActionKind; -import dev.loki.lovisual.util.player.inventory.InventorySearchScope; -import dev.loki.lovisual.util.player.inventory.InventorySwap; -import dev.loki.lovisual.util.player.inventory.InventorySwapRequest; -import dev.loki.lovisual.util.player.inventory.InventorySwapVisibility; -import dev.loki.lovisual.util.combat.RubberHandUseUtil; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.BlockHitResult; - -import java.util.function.Predicate; - -public final class AutoBedActionUtil { - private AutoBedActionUtil() { - } - - public static boolean placeBed(Minecraft mc, - Object owner, - BlockHitResult hitResult, - InventorySearchScope scope, - InventorySwapVisibility visibility, - boolean restore) { - if (mc == null || owner == null || hitResult == null || mc.player == null || mc.gameMode == null) return false; - LocalPlayer player = mc.player; - InteractionHand held = AutoBedInteractionUtil.heldBedHand(player); - if (held != null) { - return useOn(mc, held, hitResult); - } - - return executeSwap(AutoBedInteractionUtil::isBed, scope, visibility, restore, - () -> useOn(mc, InteractionHand.MAIN_HAND, hitResult)); - } - - public static boolean explodeBed(Minecraft mc, - Object owner, - BlockHitResult hitResult, - InventorySearchScope scope, - InventorySwapVisibility visibility, - boolean restore) { - if (mc == null || owner == null || hitResult == null || mc.player == null || mc.gameMode == null) return false; - InteractionHand held = AutoBedInteractionUtil.heldDetonatorHand(mc.player); - if (held != null) { - return useOn(mc, held, hitResult); - } - return executeSwap(AutoBedInteractionUtil::isDetonator, scope, visibility, restore, - () -> useOn(mc, InteractionHand.MAIN_HAND, hitResult)); - } - - public static boolean hasBed(Minecraft mc, InventorySearchScope scope) { - if (mc == null || mc.player == null) return false; - if (AutoBedInteractionUtil.heldBedHand(mc.player) != null) return true; - return InventorySwap.INSTANCE.findSlotForMode(AutoBedInteractionUtil::isBed, modeFor(scope, true)).found(); - } - - private static boolean executeSwap(Predicate predicate, - InventorySearchScope scope, - InventorySwapVisibility visibility, - boolean restore, - Runnable action) { - return InventorySwap.INSTANCE.execute(InventorySwapRequest.builder(predicate, action) - .scope(scope != null ? scope : InventorySearchScope.FULL) - .visibility(visibility != null ? visibility : InventorySwapVisibility.SILENT) - .restore(restore) - .actionKind(InventoryActionKind.BLOCK_INTERACT) - .build()); - } - - private static dev.loki.lovisual.util.player.inventory.InventorySwapMode modeFor(InventorySearchScope scope, boolean silent) { - InventorySearchScope safeScope = scope != null ? scope : InventorySearchScope.FULL; - return switch (safeScope) { - case HOTBAR -> silent - ? dev.loki.lovisual.util.player.inventory.InventorySwapMode.SILENT - : dev.loki.lovisual.util.player.inventory.InventorySwapMode.NORMAL; - case INVENTORY -> silent - ? dev.loki.lovisual.util.player.inventory.InventorySwapMode.INVENTORY_SILENT - : dev.loki.lovisual.util.player.inventory.InventorySwapMode.INVENTORY_NORMAL; - case FULL -> silent - ? dev.loki.lovisual.util.player.inventory.InventorySwapMode.SILENT_FULL - : dev.loki.lovisual.util.player.inventory.InventorySwapMode.NORMAL_FULL; - }; - } - - private static boolean useOn(Minecraft mc, InteractionHand hand, BlockHitResult hitResult) { - if (mc.player == null || mc.gameMode == null || hand == null || hitResult == null) return false; - return RubberHandUseUtil.runBlockUse(mc, () -> { - InteractionResult result = mc.gameMode.useItemOn(mc.player, hand, hitResult); - mc.player.swing(hand); - return result != InteractionResult.FAIL; - }); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedDamageCandidate.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedDamageCandidate.java deleted file mode 100644 index 58d6cc8..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedDamageCandidate.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autobed; - -public interface AutoBedDamageCandidate { - float damage(); - float selfDamage(); -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedDamageRules.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedDamageRules.java deleted file mode 100644 index 60c76ed..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedDamageRules.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autobed; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; - -public final class AutoBedDamageRules { - private AutoBedDamageRules() { - } - - public static boolean shouldOverrideMinDamage(LivingEntity target, float damage, float faceplaceHealth) { - if (target == null) return false; - if (target.getHealth() + target.getAbsorptionAmount() <= faceplaceHealth) return true; - return damage >= target.getHealth() + target.getAbsorptionAmount() - 0.5f; - } - - public static boolean shouldOverrideMaxSelfDamage(Player player, - LivingEntity target, - float damage, - float selfDamage, - float maxSelfDamage) { - if (player == null || target == null) return false; - if (selfDamage <= maxSelfDamage) return false; - - boolean targetSafe = holdsTotem(target); - boolean playerSafe = holdsTotem(player); - float targetHp = target.getHealth() + target.getAbsorptionAmount() - 1.0f; - float playerHp = player.getHealth() + player.getAbsorptionAmount() - 1.0f; - - boolean canPop = damage > targetHp && targetSafe; - boolean canKill = damage > targetHp && !targetSafe; - boolean canPopSelf = selfDamage > playerHp && playerSafe; - boolean canKillSelf = selfDamage > playerHp && !playerSafe; - - if (canPopSelf && canKill) return true; - return (canPop || canKill) && !canKillSelf && !canPopSelf; - } - - public static boolean isSafe(Player player, float selfDamage, boolean overrideDamage) { - if (player == null) return false; - if (overrideDamage) return true; - return selfDamage + 0.5f <= player.getHealth() + player.getAbsorptionAmount(); - } - - public static T selectBest(Iterable candidates, - LivingEntity target, - float minDamage, - float faceplaceHealth) { - T best = null; - float bestDamage = 0.0f; - for (T data : candidates) { - if (data == null) continue; - if (!(shouldOverrideMinDamage(target, data.damage(), faceplaceHealth) || data.damage() > minDamage)) { - continue; - } - - if (best != null - && Math.abs(best.damage() - data.damage()) < 1.0f - && best.selfDamage() > data.selfDamage()) { - best = data; - bestDamage = data.damage(); - continue; - } - - if (data.damage() > bestDamage) { - best = data; - bestDamage = data.damage(); - } - } - return best; - } - - private static boolean holdsTotem(LivingEntity entity) { - if (entity == null) return false; - ItemStack main = entity.getMainHandItem(); - ItemStack off = entity.getOffhandItem(); - return (!main.isEmpty() && main.is(Items.TOTEM_OF_UNDYING)) - || (!off.isEmpty() && off.is(Items.TOTEM_OF_UNDYING)); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedData.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedData.java deleted file mode 100644 index 864a907..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedData.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autobed; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; - -public record AutoBedData( - BlockPos footPos, - BlockPos headPos, - Direction facing, - BlockPos interactPos, - BlockHitResult placeHitResult, - BlockHitResult explodeHitResult, - Vec3 explosionVec, - float damage, - float selfDamage, - boolean overrideDamage, - boolean existingBed -) implements AutoBedDamageCandidate { - public BlockPos pos() { - return footPos; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedEntityBlocker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedEntityBlocker.java deleted file mode 100644 index 7b5b856..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedEntityBlocker.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autobed; - -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.ExperienceOrb; -import net.minecraft.world.phys.AABB; - -public final class AutoBedEntityBlocker { - public boolean isBlocked(ClientLevel level, BlockPos footPos, BlockPos headPos) { - if (level == null || footPos == null || headPos == null) return true; - - AABB box = new AABB(footPos).minmax(new AABB(headPos)); - for (Entity entity : level.entitiesForRendering()) { - if (entity == null || !entity.isAlive() || entity.isRemoved() || entity instanceof ExperienceOrb) { - continue; - } - if (entity.getBoundingBox().intersects(box)) { - return true; - } - } - return false; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedInteractionUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedInteractionUtil.java deleted file mode 100644 index fcc270a..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedInteractionUtil.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autobed; - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.tags.BlockTags; -import net.minecraft.tags.ItemTags; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.HorizontalDirectionalBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BedPart; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; - -public final class AutoBedInteractionUtil { - private AutoBedInteractionUtil() { - } - - public static Vec3 bedExplosionVec(BlockPos bedBlockPos) { - return Vec3.atCenterOf(bedBlockPos); - } - - public static Vec3 bedPairCenter(BlockPos footPos, BlockPos headPos) { - return Vec3.atCenterOf(footPos).add(Vec3.atCenterOf(headPos)).scale(0.5); - } - - public static boolean isBedBlock(BlockState state) { - return state != null && state.is(BlockTags.BEDS); - } - - public static boolean canPlaceBedAt(Level level, BlockPos footPos, BlockPos headPos) { - if (level == null || footPos == null || headPos == null) return false; - if (!level.isInWorldBounds(footPos) || !level.isInWorldBounds(headPos)) return false; - if (!level.getBlockState(footPos).canBeReplaced()) return false; - if (!level.getBlockState(headPos).canBeReplaced()) return false; - // Vanilla BedBlock placement only requires the second half to be replaceable/border-valid. - // The actual clicked support only has to resolve BlockPlaceContext#getClickedPos() to the foot block. - return hasPlaceSupport(level, footPos); - } - - public static boolean hasBedSupport(Level level, BlockPos pos) { - return hasPlaceSupport(level, pos); - } - - public static boolean hasPlaceSupport(Level level, BlockPos placePos) { - if (level == null || placePos == null) return false; - for (Direction face : Direction.values()) { - BlockPos support = placePos.relative(face.getOpposite()); - if (isSolidSupport(level, support)) { - return true; - } - } - return false; - } - - private static boolean isSolidSupport(Level level, BlockPos support) { - if (level == null || support == null || !level.isInWorldBounds(support)) return false; - BlockState state = level.getBlockState(support); - return !state.isAir() && !state.canBeReplaced() && !state.getCollisionShape(level, support).isEmpty(); - } - - public static BlockPos resolveOtherPart(BlockState state, BlockPos pos) { - if (state == null || pos == null || !isBedBlock(state)) return null; - Direction facing = bedFacing(state); - if (facing == null) return null; - BedPart part = bedPart(state); - if (part == BedPart.HEAD) { - return pos.relative(facing.getOpposite()); - } - return pos.relative(facing); - } - - public static BlockPos resolveFootPos(BlockState state, BlockPos pos) { - if (state == null || pos == null || !isBedBlock(state)) return null; - Direction facing = bedFacing(state); - if (facing == null) return null; - BedPart part = bedPart(state); - return part == BedPart.HEAD ? pos.relative(facing.getOpposite()) : pos; - } - - public static BlockPos resolveHeadPos(BlockState state, BlockPos pos) { - if (state == null || pos == null || !isBedBlock(state)) return null; - Direction facing = bedFacing(state); - if (facing == null) return null; - BedPart part = bedPart(state); - return part == BedPart.HEAD ? pos : pos.relative(facing); - } - - public static Direction bedFacing(BlockState state) { - if (state == null) return Direction.NORTH; - if (state.hasProperty(HorizontalDirectionalBlock.FACING)) return state.getValue(HorizontalDirectionalBlock.FACING); - return Direction.NORTH; - } - - public static BedPart bedPart(BlockState state) { - if (state != null && state.hasProperty(BedBlock.PART)) return state.getValue(BedBlock.PART); - return BedPart.FOOT; - } - - public static BlockHitResult getBedInteractResult(Level level, - LocalPlayer player, - BlockPos pos, - AutoBedPlacementMode mode, - float range, - float wallRange) { - if (mode == AutoBedPlacementMode.STRICT) { - return getStrictBlockInteract(level, player, pos, range, wallRange); - } - if (mode == AutoBedPlacementMode.LEGIT) { - return getLegitBlockInteract(level, player, pos, range, wallRange); - } - return getDefaultBlockInteract(level, player, pos, range, wallRange); - } - - public static BlockHitResult getPlaceSupportInteract(Level level, - LocalPlayer player, - BlockPos footPos, - BlockPos headPos, - AutoBedPlacementMode mode, - float range, - float wallRange) { - if (level == null || player == null || footPos == null || headPos == null) return null; - - // BedItem derives the bed FOOT from BlockPlaceContext#getClickedPos(). - // Clicking any solid neighbour face that points into footPos is valid, so beds can be placed from - // a single side/top support block. The head half only has to be replaceable and unobstructed. - return getBestFootPlacementInteract(level, player, footPos, mode, range, wallRange); - } - - private static BlockHitResult getBestFootPlacementInteract(Level level, - LocalPlayer player, - BlockPos placePos, - AutoBedPlacementMode mode, - float range, - float wallRange) { - Vec3 eyes = player.getEyePosition(); - double bestDistance = Double.MAX_VALUE; - BlockHitResult best = null; - for (Direction face : Direction.values()) { - BlockPos support = placePos.relative(face.getOpposite()); - if (!isSolidSupport(level, support)) continue; - BlockHitResult hit = mode == AutoBedPlacementMode.LEGIT - ? getBestSupportFacePoint(level, player, support, face, range, wallRange) - : getSupportFaceCenter(level, player, support, face, range, wallRange); - if (hit == null) continue; - double distanceSq = eyes.distanceToSqr(hit.getLocation()); - if (distanceSq < bestDistance) { - bestDistance = distanceSq; - best = hit; - } - } - return best; - } - - public static BlockHitResult getSyntheticBedInteractResult(LocalPlayer player, BlockPos pos, float range) { - if (player == null || pos == null) return null; - Vec3 vec = Vec3.atCenterOf(pos); - if (player.getEyePosition().distanceToSqr(vec) > range * range) return null; - Direction side = player.getEyeY() >= pos.getY() + 0.5 ? Direction.UP : Direction.DOWN; - return new BlockHitResult(vec, side, pos, false); - } - - public static float yawForFacing(Direction facing) { - if (facing == null) return 0.0f; - return switch (facing) { - case SOUTH -> 0.0f; - case WEST -> 90.0f; - case NORTH -> 180.0f; - case EAST -> -90.0f; - default -> 0.0f; - }; - } - - public static BlockHitResult getDefaultBlockInteract(Level level, - LocalPlayer player, - BlockPos pos, - float range, - float wallRange) { - if (level == null || player == null || pos == null) return null; - - Vec3 vec = Vec3.atCenterOf(pos); - Vec3 eyes = player.getEyePosition(); - double distanceSq = eyes.distanceToSqr(vec); - if (distanceSq > range * range) return null; - if (!isVisibleOrWithinWallRange(level, player, eyes, vec, pos, distanceSq, wallRange)) return null; - - Direction side = player.getEyeY() >= pos.getY() + 0.5 ? Direction.UP : Direction.DOWN; - return new BlockHitResult(vec, side, pos, false); - } - - public static BlockHitResult getStrictBlockInteract(Level level, - LocalPlayer player, - BlockPos pos, - float range, - float wallRange) { - if (level == null || player == null || pos == null) return null; - - Vec3 eyes = player.getEyePosition(); - double bestDistance = Double.MAX_VALUE; - BlockHitResult best = null; - for (Direction direction : Direction.values()) { - Vec3 normal = Vec3.atLowerCornerOf(direction.getUnitVec3i()); - Vec3 sample = Vec3.atCenterOf(pos).add(normal.scale(0.5)); - double distanceSq = eyes.distanceToSqr(sample); - if (distanceSq > range * range) continue; - if (!isVisibleOrWithinWallRange(level, player, eyes, sample, pos, distanceSq, wallRange)) continue; - if (distanceSq < bestDistance) { - bestDistance = distanceSq; - best = new BlockHitResult(sample, direction, pos, false); - } - } - return best; - } - - public static BlockHitResult getLegitBlockInteract(Level level, - LocalPlayer player, - BlockPos pos, - float range, - float wallRange) { - if (level == null || player == null || pos == null) return null; - - Vec3 eyes = player.getEyePosition(); - double bestDistance = Double.MAX_VALUE; - BlockHitResult best = null; - for (float x = 0.1f; x <= 0.9f; x += 0.2f) { - for (float y = 0.1f; y <= 0.9f; y += 0.2f) { - for (float z = 0.1f; z <= 0.9f; z += 0.2f) { - Vec3 point = new Vec3(pos.getX() + x, pos.getY() + y, pos.getZ() + z); - double distanceSq = eyes.distanceToSqr(point); - if (distanceSq > range * range) continue; - if (!isVisibleOrWithinWallRange(level, player, eyes, point, pos, distanceSq, wallRange)) continue; - if (distanceSq < bestDistance) { - bestDistance = distanceSq; - best = new BlockHitResult(point, Direction.UP, pos, false); - } - } - } - } - return best; - } - - private static BlockHitResult getSupportFaceCenter(Level level, - LocalPlayer player, - BlockPos support, - Direction face, - float range, - float wallRange) { - Vec3 eyes = player.getEyePosition(); - Vec3 normal = Vec3.atLowerCornerOf(face.getUnitVec3i()); - Vec3 hitVec = Vec3.atCenterOf(support).add(normal.scale(0.5)); - double distanceSq = eyes.distanceToSqr(hitVec); - if (distanceSq > range * range) return null; - if (!isVisibleOrWithinWallRange(level, player, eyes, hitVec, support, distanceSq, wallRange)) return null; - return new BlockHitResult(hitVec, face, support, false); - } - - private static BlockHitResult getBestSupportFacePoint(Level level, - LocalPlayer player, - BlockPos support, - Direction face, - float range, - float wallRange) { - Vec3 eyes = player.getEyePosition(); - double bestDistance = Double.MAX_VALUE; - Vec3 bestPoint = null; - for (float a = 0.2f; a <= 0.8f; a += 0.3f) { - for (float b = 0.2f; b <= 0.8f; b += 0.3f) { - Vec3 point = pointOnFace(support, face, a, b); - double distanceSq = eyes.distanceToSqr(point); - if (distanceSq > range * range) continue; - if (!isVisibleOrWithinWallRange(level, player, eyes, point, support, distanceSq, wallRange)) continue; - if (distanceSq < bestDistance) { - bestDistance = distanceSq; - bestPoint = point; - } - } - } - return bestPoint == null ? null : new BlockHitResult(bestPoint, face, support, false); - } - - private static Vec3 pointOnFace(BlockPos pos, Direction face, float a, float b) { - double x = pos.getX(); - double y = pos.getY(); - double z = pos.getZ(); - return switch (face) { - case DOWN -> new Vec3(x + a, y, z + b); - case UP -> new Vec3(x + a, y + 1.0, z + b); - case NORTH -> new Vec3(x + a, y + b, z); - case SOUTH -> new Vec3(x + a, y + b, z + 1.0); - case WEST -> new Vec3(x, y + a, z + b); - case EAST -> new Vec3(x + 1.0, y + a, z + b); - }; - } - - private static boolean isVisibleOrWithinWallRange(Level level, - LocalPlayer player, - Vec3 eyes, - Vec3 point, - BlockPos expectedBlock, - double distanceSq, - float wallRange) { - BlockHitResult wall = level.clip(new ClipContext( - eyes, - point, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - if (wall == null || wall.getType() != HitResult.Type.BLOCK || expectedBlock.equals(wall.getBlockPos())) { - return true; - } - return distanceSq <= wallRange * wallRange; - } - - public static InteractionHand heldBedHand(LocalPlayer player) { - if (player == null) return null; - if (isBed(player.getOffhandItem())) return InteractionHand.OFF_HAND; - if (isBed(player.getMainHandItem())) return InteractionHand.MAIN_HAND; - return null; - } - - public static InteractionHand heldDetonatorHand(LocalPlayer player) { - if (player == null) return null; - if (!isBed(player.getMainHandItem())) return InteractionHand.MAIN_HAND; - if (!isBed(player.getOffhandItem())) return InteractionHand.OFF_HAND; - return null; - } - - public static boolean isBed(ItemStack stack) { - return stack != null && !stack.isEmpty() && stack.is(ItemTags.BEDS); - } - - public static boolean isDetonator(ItemStack stack) { - return stack == null || stack.isEmpty() || !stack.is(ItemTags.BEDS); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedPlacementMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedPlacementMode.java deleted file mode 100644 index 795ca63..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedPlacementMode.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autobed; - -public enum AutoBedPlacementMode { - DEFAULT, - STRICT, - LEGIT -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedPlanner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedPlanner.java deleted file mode 100644 index 04a2495..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedPlanner.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autobed; - -import dev.loki.lovisual.util.world.ExplosionDamageUtil; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -public final class AutoBedPlanner { - private static final float BED_POWER = 5.0f; - private static final double TARGET_MAX_DISTANCE_SQ = 144.0; - private static final float MIN_RAW_DAMAGE = 1.5f; - private static final int MAX_PLACE_DAMAGE_EVALUATIONS = 64; - private static final int MAX_EXISTING_DAMAGE_EVALUATIONS = 32; - private static final double RANGE_MARGIN = 0.95; - private static final Direction[] HORIZONTAL = {Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST}; - - private int lastScanned; - private int lastCandidates; - private int lastSafeCandidates; - private int lastSelfDamageRejects; - - public ScanResult scan(Context context, LivingEntity target, Vec3 center, int range) { - lastScanned = 0; - lastCandidates = 0; - lastSafeCandidates = 0; - lastSelfDamageRejects = 0; - - if (context == null || context.player() == null || context.level() == null || target == null || center == null) { - return new ScanResult(null, null, 0, 0, 0, 0); - } - - Vec3 predictedTarget = context.resolvePredictedPosition(target, context.predictTicks()); - Vec3 eyes = context.player().getEyePosition(); - BlockPos origin = BlockPos.containing(center); - int horizontalRange = Math.max(1, range); - int verticalRange = Math.min(horizontalRange, 3); - double radiusSq = (double) horizontalRange * horizontalRange; - - List placeShells = new ArrayList<>(); - List existingShells = new ArrayList<>(); - for (int x = origin.getX() - horizontalRange; x <= origin.getX() + horizontalRange; x++) { - for (int y = origin.getY() - verticalRange; y <= origin.getY() + verticalRange; y++) { - for (int z = origin.getZ() - horizontalRange; z <= origin.getZ() + horizontalRange; z++) { - BlockPos pos = new BlockPos(x, y, z); - Vec3 posVec = Vec3.atCenterOf(pos); - if (posVec.distanceToSqr(center) > radiusSq) { - continue; - } - - lastScanned++; - collectExistingShell(context, pos, predictedTarget, eyes, existingShells); - collectPlaceShells(context, pos, predictedTarget, eyes, placeShells); - } - } - } - - Comparator byPotential = Comparator - .comparingDouble(CandidateShell::estimatedDamage) - .reversed() - .thenComparingDouble(CandidateShell::targetDistanceSq) - .thenComparingDouble(CandidateShell::eyeDistanceSq); - placeShells.sort(byPotential); - existingShells.sort(byPotential); - - List place = evaluateShells(context, target, placeShells, MAX_PLACE_DAMAGE_EVALUATIONS); - List explode = evaluateShells(context, target, existingShells, MAX_EXISTING_DAMAGE_EVALUATIONS); - - AutoBedData bestPlace = AutoBedDamageRules.selectBest( - place, - target, - context.minDamage(), - context.faceplaceHealth() - ); - AutoBedData bestExplode = AutoBedDamageRules.selectBest( - explode, - target, - context.minDamage(), - context.faceplaceHealth() - ); - return new ScanResult(bestPlace, bestExplode, lastScanned, lastCandidates, lastSafeCandidates, lastSelfDamageRejects); - } - - public AutoBedData evaluate(Context context, AutoBedData previous, LivingEntity target) { - if (previous == null) return null; - if (previous.existingBed()) { - CandidateShell existing = collectExistingShell(context, previous.interactPos(), target); - return evaluateShell(context, target, existing); - } - CandidateShell place = collectPlaceShell(context, previous.footPos(), previous.facing(), target); - return evaluateShell(context, target, place); - } - - private CandidateShell collectExistingShell(Context context, BlockPos pos, LivingEntity target) { - if (context == null || context.player() == null || context.level() == null || target == null || pos == null) return null; - Vec3 predictedTarget = context.resolvePredictedPosition(target, context.predictTicks()); - return collectExistingShell(context, pos, predictedTarget, context.player().getEyePosition()); - } - - private CandidateShell collectPlaceShell(Context context, BlockPos footPos, Direction facing, LivingEntity target) { - if (context == null || context.player() == null || context.level() == null || target == null || footPos == null || facing == null) return null; - Vec3 predictedTarget = context.resolvePredictedPosition(target, context.predictTicks()); - return collectPlaceShell(context, footPos, facing, predictedTarget, context.player().getEyePosition()); - } - - private void collectExistingShell(Context context, - BlockPos pos, - Vec3 predictedTarget, - Vec3 eyes, - List out) { - CandidateShell shell = collectExistingShell(context, pos, predictedTarget, eyes); - if (shell != null) out.add(shell); - } - - private CandidateShell collectExistingShell(Context context, - BlockPos pos, - Vec3 predictedTarget, - Vec3 eyes) { - LocalPlayer player = context.player(); - ClientLevel level = context.level(); - if (player == null || level == null || pos == null || predictedTarget == null || eyes == null) return null; - if (!level.isInWorldBounds(pos)) return null; - - BlockState state = level.getBlockState(pos); - if (!AutoBedInteractionUtil.isBedBlock(state)) return null; - - BlockPos footPos = AutoBedInteractionUtil.resolveFootPos(state, pos); - BlockPos headPos = AutoBedInteractionUtil.resolveHeadPos(state, pos); - Direction facing = AutoBedInteractionUtil.bedFacing(state); - if (footPos == null || headPos == null || facing == null) return null; - - Vec3 explosionVec = AutoBedInteractionUtil.bedExplosionVec(pos); - return collectShell(context, footPos, headPos, facing, pos, explosionVec, predictedTarget, eyes, true); - } - - private void collectPlaceShells(Context context, - BlockPos footPos, - Vec3 predictedTarget, - Vec3 eyes, - List out) { - for (Direction facing : HORIZONTAL) { - CandidateShell shell = collectPlaceShell(context, footPos, facing, predictedTarget, eyes); - if (shell != null) out.add(shell); - } - } - - private CandidateShell collectPlaceShell(Context context, - BlockPos footPos, - Direction facing, - Vec3 predictedTarget, - Vec3 eyes) { - if (context == null || context.level() == null || footPos == null || facing == null) return null; - BlockPos headPos = footPos.relative(facing); - if (!AutoBedInteractionUtil.canPlaceBedAt(context.level(), footPos, headPos)) { - return null; - } - - Vec3 footExplosion = AutoBedInteractionUtil.bedExplosionVec(footPos); - Vec3 headExplosion = AutoBedInteractionUtil.bedExplosionVec(headPos); - float footEstimate = estimateMaxPreArmorDamage(predictedTarget, footExplosion); - float headEstimate = estimateMaxPreArmorDamage(predictedTarget, headExplosion); - BlockPos interactPos = footEstimate >= headEstimate ? footPos : headPos; - Vec3 explosionVec = footEstimate >= headEstimate ? footExplosion : headExplosion; - return collectShell(context, footPos, headPos, facing, interactPos, explosionVec, predictedTarget, eyes, false); - } - - private CandidateShell collectShell(Context context, - BlockPos footPos, - BlockPos headPos, - Direction facing, - BlockPos interactPos, - Vec3 explosionVec, - Vec3 predictedTarget, - Vec3 eyes, - boolean existingBed) { - if (context == null || context.player() == null || context.level() == null || footPos == null || headPos == null - || facing == null || interactPos == null || explosionVec == null || predictedTarget == null || eyes == null) { - return null; - } - ClientLevel level = context.level(); - if (!level.isInWorldBounds(footPos) || !level.isInWorldBounds(headPos) || !level.isInWorldBounds(interactPos)) { - return null; - } - - double targetDistanceSq = predictedTarget.distanceToSqr(explosionVec); - if (targetDistanceSq > TARGET_MAX_DISTANCE_SQ) { - return null; - } - - double quickRange = Math.max(0.0f, context.placeRange()) + RANGE_MARGIN; - double eyeDistanceSq = eyes.distanceToSqr(existingBed ? explosionVec : AutoBedInteractionUtil.bedPairCenter(footPos, headPos)); - if (eyeDistanceSq > quickRange * quickRange) { - return null; - } - - float estimatedDamage = estimateMaxPreArmorDamage(predictedTarget, explosionVec); - if (estimatedDamage < MIN_RAW_DAMAGE) { - return null; - } - if (!(AutoBedDamageRules.shouldOverrideMinDamage(context.target(), estimatedDamage, context.faceplaceHealth()) - || estimatedDamage > context.minDamage())) { - return null; - } - - return new CandidateShell(footPos, headPos, facing, interactPos, explosionVec, existingBed, targetDistanceSq, eyeDistanceSq, estimatedDamage); - } - - private List evaluateShells(Context context, - LivingEntity target, - List shells, - int maxDamageEvaluations) { - List out = new ArrayList<>(); - if (shells == null || shells.isEmpty()) return out; - - int evaluated = 0; - int limit = Math.max(1, maxDamageEvaluations); - for (CandidateShell shell : shells) { - if (shell == null) continue; - if (evaluated++ >= limit) break; - AutoBedData data = evaluateShell(context, target, shell); - if (data == null) continue; - out.add(data); - } - return out; - } - - private AutoBedData evaluateShell(Context context, LivingEntity target, CandidateShell shell) { - if (context == null || target == null || shell == null) return null; - LocalPlayer player = context.player(); - if (player == null) return null; - - float damage = ExplosionDamageUtil.getExplosionDamage( - target, - shell.explosionVec(), - BED_POWER, - context.predictTicks(), - false - ); - if (damage < MIN_RAW_DAMAGE) return null; - if (!(AutoBedDamageRules.shouldOverrideMinDamage(target, damage, context.faceplaceHealth()) - || damage > context.minDamage())) { - return null; - } - lastCandidates++; - - float selfDamage = ExplosionDamageUtil.getExplosionDamage( - player, - shell.explosionVec(), - BED_POWER, - context.selfPredictTicks(), - false - ); - boolean overrideDamage = context.shouldOverrideMaxSelfDamage(damage, selfDamage); - if (selfDamage > context.maxSelfDamage() && !overrideDamage) { - lastSelfDamageRejects++; - return null; - } - if (!context.isSafe(damage, selfDamage, overrideDamage)) { - return null; - } - - if (!shell.existingBed() && context.isBlockedByEntity(shell.footPos(), shell.headPos())) { - return null; - } - - BlockHitResult placeInteract = null; - if (!shell.existingBed()) { - placeInteract = context.getPlaceInteractResult(shell.footPos(), shell.headPos()); - if (placeInteract == null) return null; - } - - BlockHitResult explodeInteract = context.getBedInteractResult(shell.interactPos()); - if (explodeInteract == null) { - return null; - } - - lastSafeCandidates++; - return new AutoBedData( - shell.footPos(), - shell.headPos(), - shell.facing(), - shell.interactPos(), - placeInteract, - explodeInteract, - shell.explosionVec(), - damage, - selfDamage, - overrideDamage, - shell.existingBed() - ); - } - - private static float estimateMaxPreArmorDamage(Vec3 entityPos, Vec3 explosionVec) { - if (entityPos == null || explosionVec == null) return 0.0f; - double explosionDiameter = BED_POWER * 2.0f; - double distance = Math.sqrt(entityPos.distanceToSqr(explosionVec)); - if (distance > explosionDiameter) return 0.0f; - double distanceDecay = 1.0 - distance / explosionDiameter; - double impact = Math.max(0.0, distanceDecay); - return (float) (((impact * impact + impact) / 2.0) * 7.0 * explosionDiameter + 1.0); - } - - public interface Context { - LocalPlayer player(); - ClientLevel level(); - LivingEntity target(); - Vec3 resolvePredictedPosition(LivingEntity entity, int ticks); - BlockHitResult getPlaceInteractResult(BlockPos footPos, BlockPos headPos); - BlockHitResult getBedInteractResult(BlockPos pos); - boolean isBlockedByEntity(BlockPos footPos, BlockPos headPos); - boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage); - boolean isSafe(float damage, float selfDamage, boolean overrideDamage); - float minDamage(); - float faceplaceHealth(); - float maxSelfDamage(); - int predictTicks(); - int selfPredictTicks(); - float placeRange(); - } - - private record CandidateShell( - BlockPos footPos, - BlockPos headPos, - Direction facing, - BlockPos interactPos, - Vec3 explosionVec, - boolean existingBed, - double targetDistanceSq, - double eyeDistanceSq, - float estimatedDamage - ) { - } - - public record ScanResult( - AutoBedData bestPlace, - AutoBedData bestExplode, - int scanned, - int candidates, - int safeCandidates, - int selfDamageRejects - ) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedRenderUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedRenderUtil.java deleted file mode 100644 index 15f0c6c..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autobed/AutoBedRenderUtil.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autobed; - -import dev.loki.lovisual.render.engine.renderer.Renderer3D; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.AABB; - -import java.util.Locale; - -public final class AutoBedRenderUtil { - private AutoBedRenderUtil() { - } - - public static String formatDamage(float value) { - if (value <= 0.0f) return ""; - String text = String.format(Locale.US, "%.2f", value); - int end = text.length(); - while (end > 0 && text.charAt(end - 1) == '0') end--; - if (end > 0 && text.charAt(end - 1) == '.') end--; - return text.substring(0, Math.max(end, 0)); - } - - public static double measureWidth(TextRenderer renderer, String text, double scale) { - if (renderer == null || text == null || text.isEmpty()) return 0.0; - renderer.begin(scale, true, false); - try { - return renderer.getWidth(text, false); - } finally { - renderer.end(); - } - } - - public static AABB lerpBox(AABB from, AABB to, float progress) { - float t = Mth.clamp(progress, 0.0f, 1.0f); - return new AABB( - Mth.lerp(t, from.minX, to.minX), - Mth.lerp(t, from.minY, to.minY), - Mth.lerp(t, from.minZ, to.minZ), - Mth.lerp(t, from.maxX, to.maxX), - Mth.lerp(t, from.maxY, to.maxY), - Mth.lerp(t, from.maxZ, to.maxZ) - ); - } - - public static int applyOpacity(int argb, float opacity) { - opacity = Math.max(0.0f, Math.min(1.0f, opacity)); - int alpha = (argb >>> 24) & 0xFF; - int outAlpha = Mth.clamp((int) (alpha * opacity), 0, 255); - return (outAlpha << 24) | (argb & 0x00FFFFFF); - } - - public static void addFilledBox(Renderer3D renderer, AABB box, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - renderer.quad(minX, minY, minZ, maxX, minY, minZ, maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - renderer.quad(minX, maxY, minZ, minX, maxY, maxZ, maxX, maxY, maxZ, maxX, maxY, minZ, r, g, b, a); - renderer.quad(minX, minY, maxZ, maxX, minY, maxZ, maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - renderer.quad(minX, minY, minZ, minX, maxY, minZ, maxX, maxY, minZ, maxX, minY, minZ, r, g, b, a); - renderer.quad(maxX, minY, minZ, maxX, maxY, minZ, maxX, maxY, maxZ, maxX, minY, maxZ, r, g, b, a); - renderer.quad(minX, minY, minZ, minX, minY, maxZ, minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - } - - public static void addOutlineBox(Renderer3D renderer, AABB box, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - renderer.line(minX, minY, minZ, maxX, minY, minZ, r, g, b, a); - renderer.line(maxX, minY, minZ, maxX, minY, maxZ, r, g, b, a); - renderer.line(maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - renderer.line(minX, minY, maxZ, minX, minY, minZ, r, g, b, a); - - renderer.line(minX, maxY, minZ, maxX, maxY, minZ, r, g, b, a); - renderer.line(maxX, maxY, minZ, maxX, maxY, maxZ, r, g, b, a); - renderer.line(maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - renderer.line(minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - - renderer.line(minX, minY, minZ, minX, maxY, minZ, r, g, b, a); - renderer.line(maxX, minY, minZ, maxX, maxY, minZ, r, g, b, a); - renderer.line(maxX, minY, maxZ, maxX, maxY, maxZ, r, g, b, a); - renderer.line(minX, minY, maxZ, minX, maxY, maxZ, r, g, b, a); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalAttempt.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalAttempt.java deleted file mode 100644 index 2e974b2..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalAttempt.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.world.phys.Vec3; - -public final class AutoCrystalAttempt { - private final long time; - private final int attempts; - private final float distanceSq; - private final Vec3 pos; - - public AutoCrystalAttempt(LocalPlayer player, long time, int attempts, Vec3 pos) { - this.time = time; - this.attempts = attempts; - this.pos = pos; - this.distanceSq = player != null && pos != null ? (float) player.distanceToSqr(pos) : 0.0f; - } - - public AutoCrystalAttempt incremented(LocalPlayer player) { - return new AutoCrystalAttempt(player, time, attempts + 1, pos); - } - - public boolean shouldRemove(LocalPlayer player) { - return player == null || pos == null || Math.abs(distanceSq - (float) player.distanceToSqr(pos)) >= 1.0f; - } - - public boolean canSetBlocked(int ping) { - return attempts >= Math.max(1.0f, ping / 25.0f); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalBaseEvaluator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalBaseEvaluator.java deleted file mode 100644 index d8c3fff..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalBaseEvaluator.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import dev.loki.lovisual.util.world.ExplosionDamageUtil; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.ExperienceOrb; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; - -public final class AutoCrystalBaseEvaluator { - private static final double CRYSTAL_MAX_DISTANCE_SQ = 144.0; - private static final float BASE_MIN_DAMAGE = 1.5f; - - private AutoCrystalBaseEvaluator() { - } - - public static boolean canEvaluateBaseAt(ClientLevel level, BlockPos pos) { - if (level == null || pos == null || !level.isInWorldBounds(pos)) { - return false; - } - - if (!level.isEmptyBlock(pos) || !level.isEmptyBlock(pos.above())) { - return false; - } - - AABB blockBox = new AABB(pos); - for (Entity entity : level.entitiesForRendering()) { - if (entity == null || !entity.isAlive() || entity.isRemoved() || entity instanceof ExperienceOrb) { - continue; - } - if (entity.getBoundingBox().intersects(blockBox)) { - return false; - } - } - - return true; - } - - public static AutoCrystalBasePlanner.BaseData getBaseData(Context context, BlockPos pos, LivingEntity currentTarget) { - LocalPlayer player = context.player(); - ClientLevel level = context.level(); - if (player == null || level == null || currentTarget == null || pos == null) { - return null; - } - - if (!canEvaluateBaseAt(level, pos)) { - return null; - } - - Vec3 crystalVec = AutoCrystalInteractionUtil.crystalVec(pos); - if (context.resolvePredictedPosition(currentTarget, context.predictTicks()).distanceToSqr(crystalVec) > CRYSTAL_MAX_DISTANCE_SQ) { - return null; - } - - BlockHitResult interactResult = AutoCrystalInteractionUtil.getObsidianInteractResult(level, player, pos, context.placeRange()); - if (interactResult == null) { - return null; - } - - float damage = ExplosionDamageUtil.getCrystalDamage(currentTarget, crystalVec, context.predictTicks(), context.ignoreTerrain(), pos); - float selfDamage = ExplosionDamageUtil.getCrystalDamage(player, crystalVec, context.selfPredictTicks(), context.ignoreTerrain(), pos); - boolean overrideDamage = context.shouldOverrideMaxSelfDamage(damage, selfDamage); - if (damage < BASE_MIN_DAMAGE) { - return null; - } - if (selfDamage > context.maxSelfDamage() && !overrideDamage) { - return null; - } - - return new AutoCrystalBasePlanner.BaseData(pos, interactResult, damage, selfDamage, overrideDamage); - } - - public interface Context { - LocalPlayer player(); - - ClientLevel level(); - - Vec3 resolvePredictedPosition(LivingEntity entity, int ticks); - - boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage); - - float placeRange(); - - float maxSelfDamage(); - - int predictTicks(); - - int selfPredictTicks(); - - boolean ignoreTerrain(); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalBasePlanner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalBasePlanner.java deleted file mode 100644 index 53c8b59..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalBasePlanner.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public final class AutoCrystalBasePlanner { - private int lastScanned; - private int lastCandidates; - private int lastSafeCandidates; - private int lastWorthCandidates; - private int lastDeltaCandidates; - - public BaseData findBest(Context context, LivingEntity target, List centers, int range, float minDamageDelta) { - if (context == null || target == null || centers == null || centers.isEmpty()) return null; - - lastScanned = 0; - lastCandidates = 0; - lastSafeCandidates = 0; - lastWorthCandidates = 0; - lastDeltaCandidates = 0; - - List candidates = new ArrayList<>(); - Set visited = new HashSet<>(); - for (Vec3 center : centers) { - if (center == null) continue; - BlockPos origin = BlockPos.containing(center); - for (int x = origin.getX() - range; x <= origin.getX() + range; x++) { - for (int y = origin.getY() - range; y <= origin.getY() + range; y++) { - for (int z = origin.getZ() - range; z <= origin.getZ() + range; z++) { - BlockPos pos = new BlockPos(x, y, z); - if (!visited.add(pos)) continue; - lastScanned++; - if (!context.canEvaluateBaseAt(pos)) continue; - - BaseData data = context.getBaseData(pos, target); - if (data == null) continue; - lastCandidates++; - if (!context.isSafe(data.damage(), data.selfDamage(), data.overrideDamage())) continue; - lastSafeCandidates++; - candidates.add(data); - } - } - } - } - - return filter(context, minDamageDelta, candidates); - } - - private BaseData filter(Context context, float minDamageDelta, List candidates) { - BaseData best = null; - float bestDamage = 0.0f; - - for (BaseData data : candidates) { - if (!context.isWorthBaseDamage(data.damage())) continue; - lastWorthCandidates++; - - if (!context.isEnoughBaseDamageDelta(data.damage(), minDamageDelta)) continue; - lastDeltaCandidates++; - - if (isBetter(data, best, bestDamage)) { - best = data; - bestDamage = data.damage(); - } - } - - return best; - } - - public int lastScanned() { - return lastScanned; - } - - public int lastCandidates() { - return lastCandidates; - } - - public int lastSafeCandidates() { - return lastSafeCandidates; - } - - public int lastWorthCandidates() { - return lastWorthCandidates; - } - - public int lastDeltaCandidates() { - return lastDeltaCandidates; - } - - private boolean isBetter(BaseData candidate, BaseData current, float currentDamage) { - if (candidate == null) return false; - if (current != null - && Math.abs(current.damage() - candidate.damage()) < 1.0f - && current.selfDamage() > candidate.selfDamage()) { - return true; - } - return candidate.damage() > currentDamage; - } - - public interface Context { - boolean canEvaluateBaseAt(BlockPos pos); - - BaseData getBaseData(BlockPos pos, LivingEntity target); - - boolean isSafe(float damage, float selfDamage, boolean overrideDamage); - - boolean hasCurrentCrystalPlan(); - - float currentCrystalDamage(); - - boolean isWorthBaseDamage(float damage); - - boolean isEnoughBaseDamageDelta(float damage, float minDamageDelta); - } - - public record BaseData( - BlockPos position, - BlockHitResult hitResult, - float damage, - float selfDamage, - boolean overrideDamage - ) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalCrystalData.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalCrystalData.java deleted file mode 100644 index 10178db..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalCrystalData.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import net.minecraft.world.entity.boss.enderdragon.EndCrystal; - -public record AutoCrystalCrystalData( - EndCrystal crystal, - float damage, - float selfDamage, - boolean overrideDamage -) implements AutoCrystalDamageCandidate { -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalDamageCandidate.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalDamageCandidate.java deleted file mode 100644 index e2f7f11..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalDamageCandidate.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -public interface AutoCrystalDamageCandidate { - float damage(); - - float selfDamage(); - - boolean overrideDamage(); -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalDamageRules.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalDamageRules.java deleted file mode 100644 index 708dfac..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalDamageRules.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Items; - -public final class AutoCrystalDamageRules { - private AutoCrystalDamageRules() { - } - - public static boolean shouldOverrideMinDamage(LivingEntity target, float damage, float faceplaceHealth) { - if (target == null) { - return false; - } - - float targetHealth = target.getHealth(); - if (target instanceof Player playerTarget) { - targetHealth += playerTarget.getAbsorptionAmount(); - } - - if (targetHealth - damage <= 0.0f) { - return true; - } - - return targetHealth <= faceplaceHealth; - } - - public static boolean shouldOverrideMaxSelfDamage( - LocalPlayer player, - LivingEntity target, - float damage, - float selfDamage, - float maxSelfDamage - ) { - if (target == null || player == null) { - return false; - } - - float targetHealth = target.getHealth(); - boolean targetHasTotem = false; - if (target instanceof Player playerTarget) { - targetHealth += playerTarget.getAbsorptionAmount(); - targetHasTotem = playerTarget.getOffhandItem().is(Items.TOTEM_OF_UNDYING) - || playerTarget.getMainHandItem().is(Items.TOTEM_OF_UNDYING); - } - - float playerHealth = player.getHealth() + player.getAbsorptionAmount(); - boolean playerHasTotem = player.getOffhandItem().is(Items.TOTEM_OF_UNDYING) - || player.getMainHandItem().is(Items.TOTEM_OF_UNDYING); - - boolean canPop = damage > targetHealth && targetHasTotem; - boolean canKill = damage > targetHealth && !targetHasTotem; - boolean canPopSelf = selfDamage > playerHealth && playerHasTotem; - boolean canKillSelf = selfDamage > playerHealth && !playerHasTotem; - - return selfDamage > maxSelfDamage && (canPop || canKill) && !canKillSelf && !canPopSelf; - } - - public static boolean isSafe(LocalPlayer player, float selfDamage, boolean overrideDamage) { - if (player == null) { - return false; - } - - if (overrideDamage) { - return true; - } - - return selfDamage + 0.5f <= player.getHealth() + player.getAbsorptionAmount(); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalEntityBlocker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalEntityBlocker.java deleted file mode 100644 index d6dc27f..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalEntityBlocker.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.ExperienceOrb; -import net.minecraft.world.entity.boss.enderdragon.EndCrystal; -import net.minecraft.world.phys.AABB; - -import java.util.function.IntPredicate; -import java.util.function.Predicate; - -public final class AutoCrystalEntityBlocker { - public Result check( - ClientLevel level, - LocalPlayer player, - BlockPos base, - boolean calcPhase, - IntPredicate deadCrystalPredicate, - IntPredicate blockedCrystalPredicate, - Predicate attackableCrystalPredicate - ) { - if (level == null || player == null || base == null) { - return Result.notBlocked(); - } - - AABB box = new AABB(base.above()).inflate(0.0, 1.0, 0.0); - EndCrystal secondaryCrystal = null; - - for (Entity entity : level.entitiesForRendering()) { - if (entity == null || !entity.isAlive() || entity.isRemoved()) { - continue; - } - - if (!entity.getBoundingBox().intersects(box)) { - continue; - } - - if (entity instanceof ExperienceOrb) { - continue; - } - - if (entity instanceof EndCrystal crystal) { - int id = crystal.getId(); - if (deadCrystalPredicate != null && deadCrystalPredicate.test(id)) { - continue; - } - - if (blockedCrystalPredicate != null && blockedCrystalPredicate.test(id)) { - return Result.blockedEntity(); - } - - if (calcPhase) { - if (attackableCrystalPredicate != null && attackableCrystalPredicate.test(crystal)) { - continue; - } - } else if (crystal.position().distanceToSqr(box.getCenter()) > 0.3) { - secondaryCrystal = crystal; - } - - return Result.blockedEntity(secondaryCrystal); - } - - return Result.blockedEntity(); - } - - return Result.notBlocked(); - } - - public record Result(boolean blocked, EndCrystal secondaryCrystal) { - public static Result notBlocked() { - return new Result(false, null); - } - - public static Result blockedEntity() { - return new Result(true, null); - } - - public static Result blockedEntity(EndCrystal secondaryCrystal) { - return new Result(true, secondaryCrystal); - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalHand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalHand.java deleted file mode 100644 index 350dc23..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalHand.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import net.minecraft.world.InteractionHand; - -public record AutoCrystalHand(InteractionHand hand, int hotbarSlot) { -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalInteractionUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalInteractionUtil.java deleted file mode 100644 index dd43b76..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalInteractionUtil.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; - -public final class AutoCrystalInteractionUtil { - private AutoCrystalInteractionUtil() { - } - - public static AABB predictedCrystalBox(BlockPos pos) { - return new AABB( - pos.getX(), - pos.getY() + 1.0, - pos.getZ(), - pos.getX() + 1.0, - pos.getY() + 3.0, - pos.getZ() + 1.0 - ); - } - - public static Vec3 crystalVec(BlockPos pos) { - return new Vec3(pos.getX() + 0.5, pos.getY() + 1.0, pos.getZ() + 0.5); - } - - public static BlockHitResult getCrystalInteractResult( - Level level, - LocalPlayer player, - BlockPos pos, - Vec3 crystalVec, - AutoCrystalPlacementMode mode, - float placeRange, - float wallRange - ) { - if (mode == AutoCrystalPlacementMode.STRICT) { - return getStrictInteract(level, player, pos, placeRange); - } - return getDefaultInteract(level, player, crystalVec, pos, placeRange, wallRange); - } - - public static BlockHitResult getStrictInteract(Level level, LocalPlayer player, BlockPos pos, float placeRange) { - if (player == null || level == null || pos == null) { - return null; - } - - Vec3 eyes = player.getEyePosition(); - Vec3[] samples = { - new Vec3(pos.getX() + 0.5, pos.getY() + 0.999, pos.getZ() + 0.5), - new Vec3(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.001), - new Vec3(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.999), - new Vec3(pos.getX() + 0.001, pos.getY() + 0.5, pos.getZ() + 0.5), - new Vec3(pos.getX() + 0.999, pos.getY() + 0.5, pos.getZ() + 0.5) - }; - Direction[] faces = { - Direction.UP, - Direction.NORTH, - Direction.SOUTH, - Direction.WEST, - Direction.EAST - }; - - double placeRangeSq = placeRange * placeRange; - for (int i = 0; i < samples.length; i++) { - Vec3 sample = samples[i]; - if (eyes.distanceToSqr(sample) > placeRangeSq) { - continue; - } - - BlockHitResult hit = level.clip(new ClipContext( - eyes, - sample, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - if (hit == null || hit.getType() != HitResult.Type.BLOCK) { - continue; - } - if (!pos.equals(hit.getBlockPos())) { - continue; - } - if (hit.getDirection() != faces[i]) { - continue; - } - - return new BlockHitResult(hit.getLocation(), hit.getDirection(), pos, false); - } - - return null; - } - - public static BlockHitResult getDefaultInteract( - Level level, - LocalPlayer player, - Vec3 crystalVec, - BlockPos pos, - float placeRange, - float wallRange - ) { - if (player == null || level == null || pos == null) { - return null; - } - - double distanceSq = player.getEyePosition().distanceToSqr(crystalVec); - double placeRangeSq = placeRange * placeRange; - if (distanceSq > placeRangeSq) { - return null; - } - - BlockHitResult wallCheck = level.clip(new ClipContext( - player.getEyePosition(), - crystalVec, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - if (wallCheck != null - && wallCheck.getType() == HitResult.Type.BLOCK - && !pos.equals(wallCheck.getBlockPos())) { - double wallRangeSq = wallRange * wallRange; - if (distanceSq > wallRangeSq) { - return null; - } - } - - return new BlockHitResult( - crystalVec, - level.isInWorldBounds(pos.above()) ? Direction.UP : Direction.DOWN, - pos, - false - ); - } - - public static BlockHitResult getObsidianInteractResult(Level level, LocalPlayer player, BlockPos pos, float placeRange) { - if (player == null || level == null || pos == null) { - return null; - } - - Vec3 eyes = player.getEyePosition(); - double rangeSq = placeRange * placeRange; - for (Direction direction : Direction.values()) { - BlockPos support = pos.relative(direction); - if (!level.isInWorldBounds(support)) continue; - var state = level.getBlockState(support); - if (state.isAir() || state.getCollisionShape(level, support).isEmpty()) continue; - - Direction face = direction.getOpposite(); - Vec3 normal = Vec3.atLowerCornerOf(face.getUnitVec3i()); - Vec3 hitVec = Vec3.atCenterOf(support).add(normal.scale(0.5)); - if (eyes.distanceToSqr(hitVec) > rangeSq) continue; - - BlockHitResult ray = level.clip(new ClipContext( - eyes, - hitVec, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - if (ray != null && ray.getType() == HitResult.Type.BLOCK && !support.equals(ray.getBlockPos())) { - continue; - } - - return new BlockHitResult(hitVec, face, support, false); - } - - return null; - } - - public static AutoCrystalHand findCrystalHand(LocalPlayer player) { - if (player == null) { - return null; - } - - if (player.getOffhandItem().is(Items.END_CRYSTAL)) { - return new AutoCrystalHand(InteractionHand.OFF_HAND, -1); - } - - for (int slot = 0; slot < 9; slot++) { - ItemStack stack = player.getInventory().getItem(slot); - if (stack.is(Items.END_CRYSTAL)) { - return new AutoCrystalHand(InteractionHand.MAIN_HAND, slot); - } - } - - return null; - } - - public static AutoCrystalHand findObsidianHand(LocalPlayer player) { - if (player == null) { - return null; - } - - if (player.getOffhandItem().is(Items.OBSIDIAN)) { - return new AutoCrystalHand(InteractionHand.OFF_HAND, -1); - } - - for (int slot = 0; slot < 9; slot++) { - ItemStack stack = player.getInventory().getItem(slot); - if (stack.is(Items.OBSIDIAN)) { - return new AutoCrystalHand(InteractionHand.MAIN_HAND, slot); - } - } - - return null; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceData.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceData.java deleted file mode 100644 index 34eab61..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceData.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.BlockHitResult; - -public record AutoCrystalPlaceData( - BlockPos pos, - BlockHitResult bhr, - float damage, - float selfDamage, - boolean overrideDamage -) implements AutoCrystalDamageCandidate { -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceScanDebug.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceScanDebug.java deleted file mode 100644 index 6c680a0..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceScanDebug.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import dev.loki.lovisual.util.world.ExplosionDamageUtil; -import net.minecraft.core.BlockPos; - -import java.util.Locale; - -public final class AutoCrystalPlaceScanDebug { - private int ok; - private int targetDistance; - private int canPlace; - private int invalidBase; - private int blockedAir; - private int blockedEntity; - private int interact; - private int damage; - private int selfDamage; - private float maxRawDamage; - private float maxRawSelfDamage; - private BlockPos maxRawDamagePos; - private ExplosionDamageUtil.DamageDebug maxRawDamageDebug; - - void recordOk() { - ok++; - } - - void recordTargetDistance() { - targetDistance++; - } - - void recordInteractFail() { - interact++; - } - - void recordDamageReject() { - damage++; - } - - void recordSelfDamageReject() { - selfDamage++; - } - - void recordPlaceValidation(AutoCrystalPlaceValidationResult result) { - canPlace++; - switch (result) { - case INVALID_BASE -> invalidBase++; - case BLOCKED_AIR -> blockedAir++; - case BLOCKED_ENTITY -> blockedEntity++; - default -> { - } - } - } - - void recordRawDamage(BlockPos pos, float damage, float selfDamage, ExplosionDamageUtil.DamageDebug damageDebug) { - if (damage >= maxRawDamage) { - maxRawDamage = damage; - maxRawSelfDamage = selfDamage; - maxRawDamagePos = pos; - maxRawDamageDebug = damageDebug; - } - } - - public int selfDamageRejects() { - return selfDamage; - } - - @Override - public String toString() { - return "ok=" + ok - + " targetDist=" + targetDistance - + " canPlace=" + canPlace - + " base=" + invalidBase - + " air=" + blockedAir - + " entity=" + blockedEntity - + " interact=" + interact - + " damage=" + damage - + " self=" + selfDamage - + " maxDmg=" + String.format(Locale.ROOT, "%.2f", maxRawDamage) - + " maxSelf=" + String.format(Locale.ROOT, "%.2f", maxRawSelfDamage) - + " maxPos=" + maxRawDamagePos - + " dmgDbg=" + (maxRawDamageDebug == null - ? "null" - : "reason=" + maxRawDamageDebug.reason() - + " exp=" + String.format(Locale.ROOT, "%.3f", maxRawDamageDebug.exposure()) - + " dist=" + String.format(Locale.ROOT, "%.3f", maxRawDamageDebug.distanceFactor()) - + " dSq=" + String.format(Locale.ROOT, "%.3f", maxRawDamageDebug.distanceSq()) - + " imp=" + String.format(Locale.ROOT, "%.3f", maxRawDamageDebug.impact()) - + " pre=" + String.format(Locale.ROOT, "%.2f", maxRawDamageDebug.preDamage()) - + " armor=" + String.format(Locale.ROOT, "%.2f", maxRawDamageDebug.postArmorDamage()) - + " resist=" + String.format(Locale.ROOT, "%.2f", maxRawDamageDebug.postResistanceDamage()) - + " final=" + String.format(Locale.ROOT, "%.2f", maxRawDamageDebug.finalDamage()) - + " box=" + maxRawDamageDebug.box() - + " rays=" + maxRawDamageDebug.clearRays() + "/" + maxRawDamageDebug.totalRays() - + " blockerPos=" + maxRawDamageDebug.blockerPos() - + " blockerBlock=" + maxRawDamageDebug.blockerBlock() - + " blockerSample=" + maxRawDamageDebug.blockerSample() - + " blockerAtSample=" + maxRawDamageDebug.blockerAtSampleCell() - + " blockerAtExplosion=" + maxRawDamageDebug.blockerAtExplosionCell()); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceValidationResult.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceValidationResult.java deleted file mode 100644 index 0d9ff4a..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlaceValidationResult.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -public enum AutoCrystalPlaceValidationResult { - OK, - INVALID_BASE, - BLOCKED_AIR, - BLOCKED_ENTITY -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlacementMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlacementMode.java deleted file mode 100644 index 4c61193..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlacementMode.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -public enum AutoCrystalPlacementMode { - DEFAULT, - STRICT -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlacementPlanner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlacementPlanner.java deleted file mode 100644 index 66e422d..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalPlacementPlanner.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import dev.loki.lovisual.util.world.ExplosionDamageUtil; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.boss.enderdragon.EndCrystal; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; - -import java.util.ArrayList; -import java.util.List; - -public final class AutoCrystalPlacementPlanner { - private static final double CRYSTAL_MAX_DISTANCE_SQ = 144.0; - - public PlaceScanResult findBestPlace(Context context, LivingEntity target, Vec3 center, int range) { - AutoCrystalPlaceScanDebug debug = new AutoCrystalPlaceScanDebug(); - List scannedCandidates = getPossibleBlocks(context, target, center, range, debug); - List candidates = scannedCandidates.stream() - .filter(data -> context.isSafe(data.damage(), data.selfDamage(), data.overrideDamage())) - .toList(); - AutoCrystalPlaceData best = candidates.isEmpty() - ? null - : AutoCrystalSelectionUtil.selectBest(candidates, target, context.minDamage(), context.faceplaceHealth()); - return new PlaceScanResult( - best, - scannedCandidates.size(), - candidates.size(), - debug.selfDamageRejects(), - debug - ); - } - - public BreakScanResult findBestCrystal(Context context, LivingEntity target) { - List scannedCandidates = getPossibleCrystals(context, target); - List candidates = scannedCandidates.stream() - .filter(data -> context.isSafe(data.damage(), data.selfDamage(), data.overrideDamage())) - .toList(); - AutoCrystalCrystalData best = candidates.isEmpty() - ? null - : AutoCrystalSelectionUtil.selectBest(candidates, target, context.minDamage(), context.faceplaceHealth()); - return new BreakScanResult(best, scannedCandidates.size(), candidates.size()); - } - - public AutoCrystalPlaceData getPlaceData(Context context, BlockPos pos, LivingEntity currentTarget) { - return getPlaceData(context, pos, currentTarget, new AutoCrystalPlaceScanDebug()); - } - - public AutoCrystalCrystalData evaluateCrystal(Context context, LivingEntity currentTarget, EndCrystal crystal) { - LocalPlayer player = context.player(); - if (player == null || currentTarget == null || crystal == null || !crystal.isAlive() || crystal.isRemoved()) { - return null; - } - - Vec3 crystalPos = crystal.position(); - float damage = ExplosionDamageUtil.getCrystalDamage(currentTarget, crystalPos, context.predictTicks(), context.ignoreTerrain()); - float selfDamage = ExplosionDamageUtil.getCrystalDamage(player, crystalPos, context.selfPredictTicks(), context.ignoreTerrain()); - boolean overrideDamage = context.shouldOverrideMaxSelfDamage(damage, selfDamage); - return new AutoCrystalCrystalData(crystal, damage, selfDamage, overrideDamage); - } - - public boolean canAttackCrystal(Context context, LivingEntity currentTarget, EndCrystal crystal) { - LocalPlayer player = context.player(); - if (player == null || crystal == null || !crystal.isAlive() || crystal.isRemoved() || currentTarget == null) { - return false; - } - - Vec3 crystalPos = crystal.position(); - double maxRangeSq = Math.max(context.breakRange(), context.breakWallRange()); - maxRangeSq *= maxRangeSq; - if (player.getEyePosition().distanceToSqr(crystalPos) > maxRangeSq) { - return false; - } - - AutoCrystalCrystalData data = evaluateCrystal(context, currentTarget, crystal); - if (data == null) { - return false; - } - if (!(context.shouldOverrideMinDamage(currentTarget, data.damage()) || data.damage() > context.minDamage())) { - return false; - } - return (data.selfDamage() <= context.maxSelfDamage() || data.overrideDamage()) - && context.isSafe(data.damage(), data.selfDamage(), data.overrideDamage()); - } - - private List getPossibleBlocks( - Context context, - LivingEntity currentTarget, - Vec3 center, - int range, - AutoCrystalPlaceScanDebug debug - ) { - List blocks = new ArrayList<>(); - if (context.player() == null || currentTarget == null || center == null) { - return blocks; - } - - for (int x = Mth.floor(center.x - range); x <= Mth.floor(center.x + range); x++) { - for (int y = Mth.floor(center.y - range); y <= Mth.floor(center.y + range); y++) { - for (int z = Mth.floor(center.z - range); z <= Mth.floor(center.z + range); z++) { - AutoCrystalPlaceData data = getPlaceData(context, new BlockPos(x, y, z), currentTarget, debug); - if (data != null) { - blocks.add(data); - debug.recordOk(); - } - } - } - } - - return blocks; - } - - private List getPossibleCrystals(Context context, LivingEntity currentTarget) { - List crystals = new ArrayList<>(); - LocalPlayer player = context.player(); - if (player == null || currentTarget == null) { - return crystals; - } - - double maxRangeSq = Math.max(context.breakRange(), context.breakWallRange()); - maxRangeSq *= maxRangeSq; - - for (Entity entity : context.entities()) { - if (!(entity instanceof EndCrystal crystal)) { - continue; - } - - if (!crystal.isAlive() || crystal.isRemoved()) { - continue; - } - - if (context.isDeadCrystal(crystal.getId()) || context.isCrystalBlocked(crystal.getId())) { - continue; - } - - Vec3 crystalPos = crystal.position(); - if (player.getEyePosition().distanceToSqr(crystalPos) > maxRangeSq) { - continue; - } - - AutoCrystalCrystalData data = evaluateCrystal(context, currentTarget, crystal); - if (data == null) { - continue; - } - if (data.selfDamage() > context.maxSelfDamage() && !data.overrideDamage()) { - continue; - } - - crystals.add(data); - } - - return crystals; - } - - private AutoCrystalPlaceData getPlaceData( - Context context, - BlockPos pos, - LivingEntity currentTarget, - AutoCrystalPlaceScanDebug debug - ) { - LocalPlayer player = context.player(); - if (player == null || currentTarget == null || pos == null) { - return null; - } - - Vec3 crystalVec = AutoCrystalInteractionUtil.crystalVec(pos); - if (context.resolvePredictedPosition(currentTarget, context.predictTicks()).distanceToSqr(crystalVec) > CRYSTAL_MAX_DISTANCE_SQ) { - debug.recordTargetDistance(); - return null; - } - - AutoCrystalPlaceValidationResult placeValidation = context.validatePlaceCrystal(pos, true); - if (placeValidation != AutoCrystalPlaceValidationResult.OK) { - debug.recordPlaceValidation(placeValidation); - return null; - } - - BlockHitResult interactResult = context.getInteractResult(pos, crystalVec); - if (interactResult == null) { - debug.recordInteractFail(); - return null; - } - - float damage = ExplosionDamageUtil.getCrystalDamage(currentTarget, crystalVec, context.predictTicks(), context.ignoreTerrain()); - float selfDamage = ExplosionDamageUtil.getCrystalDamage(player, crystalVec, context.selfPredictTicks(), context.ignoreTerrain()); - ExplosionDamageUtil.DamageDebug damageDebug = ExplosionDamageUtil.debugCrystalDamage( - currentTarget, - crystalVec, - context.predictTicks(), - context.ignoreTerrain() - ); - debug.recordRawDamage(pos, damage, selfDamage, damageDebug); - boolean overrideDamage = context.shouldOverrideMaxSelfDamage(damage, selfDamage); - if (!(context.shouldOverrideMinDamage(currentTarget, damage) || damage > context.minDamage())) { - debug.recordDamageReject(); - return null; - } - if (selfDamage > context.maxSelfDamage() && !overrideDamage) { - debug.recordSelfDamageReject(); - return null; - } - - return new AutoCrystalPlaceData(pos, interactResult, damage, selfDamage, overrideDamage); - } - - public interface Context { - LocalPlayer player(); - - Iterable entities(); - - Vec3 resolvePredictedPosition(LivingEntity entity, int ticks); - - AutoCrystalPlaceValidationResult validatePlaceCrystal(BlockPos pos, boolean calcPhase); - - BlockHitResult getInteractResult(BlockPos pos, Vec3 crystalVec); - - boolean isDeadCrystal(int id); - - boolean isCrystalBlocked(int id); - - boolean shouldOverrideMinDamage(LivingEntity target, float damage); - - boolean shouldOverrideMaxSelfDamage(float damage, float selfDamage); - - boolean isSafe(float damage, float selfDamage, boolean overrideDamage); - - float minDamage(); - - float faceplaceHealth(); - - float maxSelfDamage(); - - float breakRange(); - - float breakWallRange(); - - int predictTicks(); - - int selfPredictTicks(); - - boolean ignoreTerrain(); - } - - public record PlaceScanResult( - AutoCrystalPlaceData best, - int scannedCandidates, - int safeCandidates, - int selfDamageRejects, - AutoCrystalPlaceScanDebug debug - ) { - } - - public record BreakScanResult( - AutoCrystalCrystalData best, - int scannedCandidates, - int safeCandidates - ) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalRenderUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalRenderUtil.java deleted file mode 100644 index bd6a6e6..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalRenderUtil.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import dev.loki.lovisual.render.engine.renderer.Renderer3D; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.AABB; - -import java.util.Locale; - -public final class AutoCrystalRenderUtil { - private AutoCrystalRenderUtil() { - } - - public static String formatDamage(float value) { - if (value <= 0.0f) return ""; - String text = String.format(Locale.US, "%.2f", value); - int end = text.length(); - while (end > 0 && text.charAt(end - 1) == '0') end--; - if (end > 0 && text.charAt(end - 1) == '.') end--; - return text.substring(0, Math.max(end, 0)); - } - - public static double measureWidth(TextRenderer renderer, String text, double scale) { - if (renderer == null || text == null || text.isEmpty()) return 0.0; - renderer.begin(scale, true, false); - try { - return renderer.getWidth(text, false); - } finally { - renderer.end(); - } - } - - public static AABB lerpBox(AABB from, AABB to, float progress) { - float t = Mth.clamp(progress, 0.0f, 1.0f); - return new AABB( - Mth.lerp(t, from.minX, to.minX), - Mth.lerp(t, from.minY, to.minY), - Mth.lerp(t, from.minZ, to.minZ), - Mth.lerp(t, from.maxX, to.maxX), - Mth.lerp(t, from.maxY, to.maxY), - Mth.lerp(t, from.maxZ, to.maxZ) - ); - } - - public static int applyOpacity(int argb, float opacity) { - opacity = Math.max(0.0f, Math.min(1.0f, opacity)); - int alpha = (argb >>> 24) & 0xFF; - int outAlpha = Mth.clamp((int) (alpha * opacity), 0, 255); - return (outAlpha << 24) | (argb & 0x00FFFFFF); - } - - public static void addFilledBox(Renderer3D renderer, AABB box, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - renderer.quad(minX, minY, minZ, maxX, minY, minZ, maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - renderer.quad(minX, maxY, minZ, minX, maxY, maxZ, maxX, maxY, maxZ, maxX, maxY, minZ, r, g, b, a); - renderer.quad(minX, minY, maxZ, maxX, minY, maxZ, maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - renderer.quad(minX, minY, minZ, minX, maxY, minZ, maxX, maxY, minZ, maxX, minY, minZ, r, g, b, a); - renderer.quad(maxX, minY, minZ, maxX, maxY, minZ, maxX, maxY, maxZ, maxX, minY, maxZ, r, g, b, a); - renderer.quad(minX, minY, minZ, minX, minY, maxZ, minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - } - - public static void addOutlineBox(Renderer3D renderer, AABB box, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - renderer.line(minX, minY, minZ, maxX, minY, minZ, r, g, b, a); - renderer.line(maxX, minY, minZ, maxX, minY, maxZ, r, g, b, a); - renderer.line(maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - renderer.line(minX, minY, maxZ, minX, minY, minZ, r, g, b, a); - - renderer.line(minX, maxY, minZ, maxX, maxY, minZ, r, g, b, a); - renderer.line(maxX, maxY, minZ, maxX, maxY, maxZ, r, g, b, a); - renderer.line(maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - renderer.line(minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - - renderer.line(minX, minY, minZ, minX, maxY, minZ, r, g, b, a); - renderer.line(maxX, minY, minZ, maxX, maxY, minZ, r, g, b, a); - renderer.line(maxX, minY, maxZ, maxX, maxY, maxZ, r, g, b, a); - renderer.line(minX, minY, maxZ, minX, maxY, maxZ, r, g, b, a); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalSelectionUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalSelectionUtil.java deleted file mode 100644 index 6e335a5..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalSelectionUtil.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import net.minecraft.world.entity.LivingEntity; - -import java.util.List; - -public final class AutoCrystalSelectionUtil { - private AutoCrystalSelectionUtil() { - } - - public static T selectBest( - List candidates, - LivingEntity target, - float minDamage, - float faceplaceHealth - ) { - T bestData = null; - float bestVal = 0.0f; - - for (T data : candidates) { - if (!(AutoCrystalDamageRules.shouldOverrideMinDamage(target, data.damage(), faceplaceHealth) || data.damage() > minDamage)) { - continue; - } - - if (bestData != null - && data.overrideDamage() - && target != null - && target.getAbsorptionAmount() + target.getHealth() < bestData.damage() - && bestData.selfDamage() < data.selfDamage()) { - continue; - } - - boolean shouldStopOverride = bestData != null - && bestData.overrideDamage() - && target != null - && data.damage() > target.getHealth() + target.getAbsorptionAmount() - && data.selfDamage() < bestData.selfDamage(); - - float safetyComparatorDelta = shouldStopOverride ? 10.0f : 1.0f; - - if (bestData != null - && Math.abs(bestData.damage() - data.damage()) < safetyComparatorDelta - && Math.abs(bestData.selfDamage() - data.selfDamage()) > 1.0f) { - if (bestData.selfDamage() >= data.selfDamage()) { - bestData = data; - bestVal = data.damage(); - } - } else if (bestVal < data.damage()) { - bestData = data; - bestVal = data.damage(); - } - } - - return bestData; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalTracker.java deleted file mode 100644 index d05e8fc..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/combat/autocrystal/AutoCrystalTracker.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.combat.autocrystal; - -import dev.loki.lovisual.util.player.NetworkStatsUtil; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.boss.enderdragon.EndCrystal; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public final class AutoCrystalTracker { - private final Map deadCrystals = new ConcurrentHashMap<>(); - private final Map attackedCrystals = new ConcurrentHashMap<>(); - private final Map awaitingPositions = new ConcurrentHashMap<>(); - - public void tick(Minecraft mc) { - long now = System.currentTimeMillis(); - long deadTimeout = Math.max(50L, Math.max(0, NetworkStatsUtil.getPing(mc)) * 2L); - deadCrystals.entrySet().removeIf(entry -> now - entry.getValue() > deadTimeout); - attackedCrystals.entrySet().removeIf(entry -> entry.getValue().shouldRemove(mc.player)); - awaitingPositions.entrySet().removeIf(entry -> entry.getValue().shouldRemove(mc.player)); - } - - public void clear() { - deadCrystals.clear(); - attackedCrystals.clear(); - awaitingPositions.clear(); - } - - public void removeAwaitingPosition(BlockPos pos) { - if (pos != null) { - awaitingPositions.remove(pos); - } - } - - public void removeAwaitingPositionsNear(EndCrystal crystal) { - if (crystal == null) { - return; - } - awaitingPositions.entrySet().removeIf(entry -> crystal.distanceToSqr(Vec3.atCenterOf(entry.getKey())) < 0.3); - } - - public void onCrystalAttack(Minecraft mc, EndCrystal crystal) { - if (crystal == null) { - return; - } - setDeadCrystal(crystal.getId()); - attackedCrystals.compute(crystal.getId(), (id, attempt) -> - attempt == null - ? new AutoCrystalAttempt(mc.player, System.currentTimeMillis(), 1, crystal.position()) - : attempt.incremented(mc.player)); - } - - public void addAwaitingPosition(Minecraft mc, ClientLevel level, BlockPos pos) { - if (pos == null) { - return; - } - - boolean blocked = isPositionBlockedByCrystal(level, pos); - awaitingPositions.compute(pos, (blockPos, attempt) -> - attempt == null - ? new AutoCrystalAttempt(mc.player, System.currentTimeMillis(), 1, Vec3.atCenterOf(pos)) - : (!blocked ? attempt.incremented(mc.player) : attempt)); - } - - public boolean isAwaitingPositionBlocked(Minecraft mc, BlockPos pos) { - AutoCrystalAttempt attempt = awaitingPositions.get(pos); - return attempt != null && attempt.canSetBlocked(Math.max(0, NetworkStatsUtil.getPing(mc))); - } - - public boolean isCrystalBlocked(Minecraft mc, int id) { - AutoCrystalAttempt attempt = attackedCrystals.get(id); - return attempt != null && attempt.canSetBlocked(Math.max(0, NetworkStatsUtil.getPing(mc))); - } - - public boolean isDeadCrystal(int id) { - return deadCrystals.containsKey(id); - } - - public void setDeadCrystal(int id) { - deadCrystals.putIfAbsent(id, System.currentTimeMillis()); - } - - public void markNearbyCrystalsDead(ClientLevel level, EndCrystal sourceCrystal) { - if (level == null || sourceCrystal == null) { - return; - } - - double x = sourceCrystal.getX(); - double y = sourceCrystal.getY(); - double z = sourceCrystal.getZ(); - long now = System.currentTimeMillis(); - - for (Entity entity : level.entitiesForRendering()) { - if (!(entity instanceof EndCrystal crystal)) { - continue; - } - - if (!crystal.isAlive() || crystal.isRemoved() || isDeadCrystal(crystal.getId())) { - continue; - } - - if (crystal.distanceToSqr(x, y, z) <= 144.0) { - setDeadCrystal(crystal.getId()); - deadCrystals.put(crystal.getId(), now); - } - } - } - - public boolean isPositionBlockedByCrystal(ClientLevel level, BlockPos base) { - if (level == null || base == null) { - return false; - } - - AABB box = new AABB(base.above()).inflate(0.0, 1.0, 0.0); - for (Entity entity : level.entitiesForRendering()) { - if (entity instanceof EndCrystal crystal - && crystal.isAlive() - && !crystal.isRemoved() - && crystal.getBoundingBox().intersects(box)) { - return true; - } - } - - return false; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/BetterMinecraft.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/BetterMinecraft.java index 5f450de..6ff530a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/BetterMinecraft.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/BetterMinecraft.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,6 @@ import dev.loki.lovisual.config.values.BooleanValue; import dev.loki.lovisual.features.module.Module; import dev.loki.lovisual.features.module.ModuleCategory; import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.runtime.RuntimeGate; //todo Description @ModuleInfo( @@ -25,10 +24,10 @@ public final class BetterMinecraft extends Module { private final BooleanValue tablistRelations = bool("tablist_relations", true); public boolean isHideRecipeBookEnabled() { - return !RuntimeGate.isPanic() && isEnabled() && hideRecipeBook.get(); + return isEnabled() && hideRecipeBook.get(); } public boolean isTablistRelationsEnabled() { - return !RuntimeGate.isPanic() && isEnabled() && tablistRelations.get(); + return isEnabled() && tablistRelations.get(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/ClickGui.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/ClickGui.java index 1e91e11..d420387 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/ClickGui.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/ClickGui.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/DefineTarget.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/DefineTarget.java index d61da83..806b68d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/DefineTarget.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/DefineTarget.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/FakePlayer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/FakePlayer.java index 5a0aeb8..b018814 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/FakePlayer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/FakePlayer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/HitSounds.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/HitSounds.java index 1f6d328..94118f7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/HitSounds.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/HitSounds.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/MessageFilter.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/MessageFilter.java index 69a87f1..bd044a1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/MessageFilter.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/MessageFilter.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/NoSound.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/NoSound.java index 72a324e..4ccf851 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/NoSound.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/NoSound.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/Panic.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/Panic.java deleted file mode 100644 index 0676bae..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/misc/Panic.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.misc; - -import dev.loki.lovisual.config.values.BindMode; -import dev.loki.lovisual.features.command.CommandOutput; -import dev.loki.lovisual.features.gui.clickgui.settings.FunctionBindSetting; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.RuntimeControlModule; -import dev.loki.lovisual.runtime.ClientRuntime; -import dev.loki.lovisual.runtime.ClientRuntimeState; -import dev.loki.lovisual.runtime.RuntimeDiagnostics; - -@ModuleInfo( - id = "panic", - displayName = "Panic", aliases = {"selfdestruct"}, - category = ModuleCategory.MISC, - enabledByDefault = true -) -public final class Panic extends Module implements RuntimeControlModule { - private final FunctionBindSetting disableRestoreBind = - action("disable_restore", "Z+X+C", BindMode.PRESS); - private final FunctionBindSetting jarReplacementBind = - action("prepare_jar_replacement", "LEFT_CTRL+LEFT_SHIFT+J", BindMode.PRESS); - private final FunctionBindSetting diagnosticsBind = - action("runtime_diagnostics", "LEFT_CTRL+LEFT_SHIFT+D", BindMode.PRESS); - - { - setDefaultBind("NONE"); - } - - @Override - public void onRuntimeControlTick() { - if (disableRestoreBind.isPressed()) { - toggleSoftPanic("panic module disable/restore bind"); - } - if (diagnosticsBind.isPressed()) { - sendDiagnostics(); - } - if (jarReplacementBind.isPressed()) { - prepareJarReplacement("panic module jar replacement bind"); - } - } - - private void toggleSoftPanic(String reason) { - ClientRuntimeState state = ClientRuntime.state(); - if (state == ClientRuntimeState.JAR_REPLACEMENT_PANIC || state == ClientRuntimeState.DEAD) { - CommandOutput.send("Client is fully disabled for safe JAR replacement. Restart Minecraft to use the new JAR."); - return; - } - boolean changed = ClientRuntime.toggleSoftPanic(reason); - if (!changed) { - CommandOutput.send("Runtime state: " + ClientRuntime.state()); - return; - } - if (ClientRuntime.state() == ClientRuntimeState.SOFT_PANIC) { - CommandOutput.send("Panic Mode: ON"); - } else { - CommandOutput.send("Panic Mode: OFF"); - } - } - - private void prepareJarReplacement(String reason) { - if (ClientRuntime.prepareJarReplacement(reason)) { - CommandOutput.send("Client is fully disabled for safe JAR replacement. Restart Minecraft to use the new JAR."); - } - } - - private void sendDiagnostics() { - RuntimeDiagnostics diagnostics = ClientRuntime.diagnostics(); - for (String line : diagnostics.lines()) { - CommandOutput.send(line); - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/AirJump.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/AirJump.java deleted file mode 100644 index 8ac5d32..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/AirJump.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on, adapted from, or implemented - * with reference to Meteor Client - * (https://github.com/MeteorDevelopment/meteor-client). - * Copyright (c) Meteor Development. - * - * Licensed under the GNU General Public License v3.0. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import dev.loki.lovisual.util.screen.ClientScreen; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import org.lwjgl.glfw.GLFW; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.GameTickEvent; -import dev.loki.lovisual.events.impl.KeyInputEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.visuals.Freecam; - -//todo Description -@ModuleInfo( - id = "airjump", - displayName = "AirJump", - category = ModuleCategory.MOVEMENT -) -public class AirJump extends Module { - - private final EnumValue mode = - enumMode("mode", Mode.NORMAL, Mode.values()); - private int level; - private boolean maintainLevelReady; - - @Override - public void onEnable() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return; - level = mc.player.blockPosition().getY(); - maintainLevelReady = false; - } - - @EventHandler - private void onKeyInput(KeyInputEvent event) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || mc.options == null) return; - if (event.getAction() != GLFW.GLFW_PRESS) return; - if (ClientScreen.current() != null || mc.player.onGround() || isFreecamActive()) return; - - if (mc.options.keyJump.matches(event.getInput())) { - level = mc.player.blockPosition().getY(); - maintainLevelReady = false; - jumpVanillaClamped(mc.player); - } else if (mc.options.keyShift.matches(event.getInput())) { - level--; - maintainLevelReady = false; - } - } - - @EventHandler - private void onGameTick(GameTickEvent event) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || mc.options == null) return; - if (mc.player.onGround()) { - maintainLevelReady = false; - return; - } - if (isFreecamActive()) return; - - if (mc.player.getY() > level + 0.2) { - maintainLevelReady = true; - } - - if (mode.get() == Mode.MAINTAIN_LEVEL - && mc.options.keyJump.isDown() - && maintainLevelReady - && mc.player.getDeltaMovement().y <= 0.0 - && mc.player.blockPosition().getY() == level) { - maintainLevelReady = false; - jumpVanillaClamped(mc.player); - } - } - - private boolean isFreecamActive() { - return Modules.get(Freecam.class) != null && Modules.get(Freecam.class).isEnabled(); - } - - public boolean performNoFallJump() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || isFreecamActive()) return false; - - level = mc.player.blockPosition().getY(); - maintainLevelReady = false; - jumpVanillaClamped(mc.player); - return true; - } - - private void jumpVanillaClamped(LocalPlayer player) { - if (player == null) return; - - player.jumpFromGround(); - } - - public enum Mode { - NORMAL, - MAINTAIN_LEVEL - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/AutoDodge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/AutoDodge.java deleted file mode 100644 index 31e9023..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/AutoDodge.java +++ /dev/null @@ -1,941 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import dev.loki.lovisual.util.screen.ClientScreen; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.util.Mth; -import net.minecraft.world.damagesource.CombatRules; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.projectile.Projectile; -import net.minecraft.world.entity.projectile.ShulkerBullet; -import net.minecraft.world.entity.projectile.arrow.AbstractArrow; -import net.minecraft.world.entity.projectile.arrow.ThrownTrident; -import net.minecraft.world.entity.projectile.hurtingprojectile.Fireball; -import net.minecraft.world.entity.projectile.hurtingprojectile.windcharge.WindCharge; -import net.minecraft.world.entity.projectile.throwableitemprojectile.AbstractThrownPotion; -import net.minecraft.world.entity.projectile.throwableitemprojectile.Snowball; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.item.enchantment.Enchantments; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanMapValue; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.player.Scaffold; -import dev.loki.lovisual.mixins.accessors.PersistentProjectileEntityAccessor; -import dev.loki.lovisual.util.player.simulation.PlayerSimulationCache; -import dev.loki.lovisual.util.projectile.SimulatedArrow; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -//todo Description -@ModuleInfo( - id = "autododge", - displayName = "AutoDodge", - category = ModuleCategory.MOVEMENT -) -public final class AutoDodge extends Module { - - private static final String THREAT_ARROW = "arrow"; - private static final String THREAT_TRIDENT = "trident"; - private static final String THREAT_FIREBALL = "fireball"; - private static final String THREAT_WIND_CHARGE = "wind_charge"; - private static final String THREAT_SHULKER_BULLET = "shulker_bullet"; - private static final String THREAT_POTION = "potion"; - - private static final double SAFE_DISTANCE = 1.5 * 0.3 + 1.5 * 0.5; - private static final double DEFAULT_DANGER_PADDING = 1.5; - private static final double INPUT_DEAD_DOT = 0.25; - private static final double PLAYER_HALF_WIDTH = 0.3; - private static final double PATH_STEP_SPEED = 0.13; - private static final double COLLISION_MARGIN = 0.03; - private static final EquipmentSlot[] ARMOR_SLOTS = { - EquipmentSlot.HEAD, - EquipmentSlot.CHEST, - EquipmentSlot.LEGS, - EquipmentSlot.FEET - }; - - private final Minecraft mc = Minecraft.getInstance(); - - private final BooleanMapValue threats = group("autododgeThreats", defaultThreats()); - private final NumberValue range = num("autododgeRange", 24.0, 4.0, 96.0); - private final NumberValue maxTicks = num("autododgeMaxTicks", 80, 10, 120); - private final NumberValue maxThreats = num("autododgeMaxThreats", 24, 1, 96); - private final NumberValue dangerPadding = - num("autododgeDangerPadding", DEFAULT_DANGER_PADDING, 0.45, 3.0); - private final BooleanValue allowRotationChange = bool("autododgeAllowRotationChange", false); - private final BooleanValue allowJump = - visibleWhen(bool("autododgeAllowJump", true), allowRotationChange::get); - private final BooleanValue allowTimer = bool("autododgeAllowTimer", false); - private final NumberValue timerSpeed = - visibleWhen(num("autododgeTimerSpeed", 2.0f, 1.0f, 10.0f), allowTimer::get); - private final NumberValue pathCheckTicks = - num("autododgePathCheckTicks", 5, 1, 12); - private final BooleanValue fallFailsafe = bool("autododgeFallFailsafe", true); - private final BooleanValue edgeSafeWalk = - visibleWhen(bool("autododgeEdgeSafeWalk", true), fallFailsafe::get); - private final NumberValue maxPredictedFallDamage = - visibleWhen(num("autododgeMaxPredictedFallDamage", 4.0, 0.0, 20.0), fallFailsafe::get); - private final BooleanValue ignoreOpenInventory = bool("autododgeIgnoreOpenInventory", true); - private final BooleanValue ignoreUsingItem = bool("autododgeIgnoreUsingItem", true); - private final BooleanValue ignoreScaffold = bool("autododgeIgnoreScaffold", true); - - private boolean timerActive; - private boolean dodgedThisTick; - private int lastDodgeAge = -1; - - private static Map defaultThreats() { - Map defaults = new LinkedHashMap<>(); - defaults.put(THREAT_ARROW, true); - defaults.put(THREAT_TRIDENT, true); - defaults.put(THREAT_FIREBALL, true); - defaults.put(THREAT_WIND_CHARGE, true); - defaults.put(THREAT_SHULKER_BULLET, true); - defaults.put(THREAT_POTION, false); - return defaults; - } - - @Override - public void onDisable() { - clearTimer(); - dodgedThisTick = false; - } - - @Override - public void onTick() { - if (timerActive && !dodgedThisTick) { - clearTimer(); - } - dodgedThisTick = false; - } - - @EventHandler(priority = -100) - private void onMovementInput(MovementInputEvent event) { - LocalPlayer player = mc.player; - if (!canOperate(player)) { - return; - } - - List candidates = findThreats(player); - if (candidates.isEmpty()) { - return; - } - - HitInfo hit = getInflictedHit(candidates); - if (hit == null) { - return; - } - - DodgePlan plan = planEvasion(player, hit); - if (plan == null) { - return; - } - - applyInput(event, plan.input()); - - if (plan.yawChange() != null) { - player.setYRot(plan.yawChange()); - } - - if (plan.shouldJump() && allowJump.get() && player.onGround()) { - event.setJump(true); - } - - boolean edgeRecovered = applyEdgeSafeWalk(player, event); - - if (!edgeRecovered && allowTimer.get() && plan.useTimer()) { - Timer.setExternalTickTimer(timerSpeed.get()); - timerActive = true; - } - - dodgedThisTick = true; - lastDodgeAge = player.tickCount; - } - - public boolean hasDodgedRecently(LocalPlayer player, int ticks) { - if (!isEnabled() || player == null || lastDodgeAge < 0) { - return false; - } - - int delta = player.tickCount - lastDodgeAge; - return delta >= 0 && delta <= ticks; - } - - public boolean isTimerActive() { - return timerActive; - } - - private boolean canOperate(LocalPlayer player) { - if (!isEnabled() || player == null || mc.level == null) { - return false; - } - - if (!ignoreOpenInventory.get() - && (ClientScreen.current() instanceof AbstractContainerScreen)) { - return false; - } - - if (!ignoreUsingItem.get() && player.isUsingItem()) { - return false; - } - - Scaffold scaffold = Modules.get(Scaffold.class); - return ignoreScaffold.get() || scaffold == null || !scaffold.isEnabled(); - } - - private List findThreats(LocalPlayer player) { - List out = new ArrayList<>(); - double maxRangeSq = range.get() * range.get(); - - for (Entity entity : mc.level.entitiesForRendering()) { - if (entity == null || entity == player || !entity.isAlive()) { - continue; - } - if (entity.distanceToSqr(player) > maxRangeSq) { - continue; - } - if (entity instanceof Projectile projectile && projectile.getOwner() == player) { - continue; - } - if (!isEnabledThreat(entity)) { - continue; - } - if (entity.getDeltaMovement().lengthSqr() < 1.0E-7) { - continue; - } - - out.add(entity); - } - - out.sort((a, b) -> Double.compare(a.distanceToSqr(player), b.distanceToSqr(player))); - int limit = Math.max(1, maxThreats.get()); - if (out.size() > limit) { - return new ArrayList<>(out.subList(0, limit)); - } - return out; - } - - private boolean isEnabledThreat(Entity entity) { - if (entity instanceof ThrownTrident trident) { - return threats.get(THREAT_TRIDENT) && !trident.isNoPhysics() && !isInGround(trident); - } - - if (entity instanceof AbstractArrow projectile) { - return threats.get(THREAT_ARROW) && !projectile.isNoPhysics() && !isInGround(projectile); - } - - if (entity instanceof Fireball) { - return threats.get(THREAT_FIREBALL); - } - - if (entity instanceof WindCharge) { - return threats.get(THREAT_WIND_CHARGE); - } - - if (entity instanceof ShulkerBullet) { - return threats.get(THREAT_SHULKER_BULLET); - } - - if (entity instanceof AbstractThrownPotion || entity instanceof Snowball) { - return threats.get(THREAT_POTION); - } - - return false; - } - - private HitInfo getInflictedHit(List threats) { - PlayerSimulationCache.SimulatedPlayerCache playerSimulation = - PlayerSimulationCache.getSimulationForLocalPlayer(); - if (playerSimulation == null) { - return null; - } - - List simulations = new ArrayList<>(threats.size()); - for (Entity threat : threats) { - ThreatSimulation simulation = createSimulation(threat); - if (simulation != null) { - simulations.add(simulation); - } - } - - double expansion = Math.max(SAFE_DISTANCE, dangerPadding.get()); - int ticks = Math.max(1, maxTicks.get()); - for (int tick = 0; tick < ticks; tick++) { - PlayerSimulationCache.SimulatedPlayerSnapshot snapshot = - playerSimulation.getSnapshotAt(tick + 1); - if (snapshot == null) { - break; - } - - AABB playerBox = new AABB(-0.3, 0.0, -0.3, 0.3, 1.8, 0.3) - .inflate(expansion) - .move(snapshot.pos()); - - for (ThreatSimulation simulation : simulations) { - if (!simulation.tick()) { - continue; - } - - Vec3 hitPos = playerBox.clip(simulation.previousPos(), simulation.pos()).orElse(null); - if (hitPos != null) { - return new HitInfo( - tick, - simulation.entity(), - hitPos, - simulation.previousPos(), - simulation.velocity() - ); - } - } - } - - return null; - } - - private ThreatSimulation createSimulation(Entity entity) { - if (entity instanceof AbstractArrow - || entity instanceof ThrownTrident - || entity instanceof AbstractThrownPotion - || entity instanceof Snowball) { - return new ArrowLikeThreatSimulation(entity); - } - - return new LinearThreatSimulation(entity); - } - - private DodgePlan planEvasion(LocalPlayer player, HitInfo hit) { - Vec3 threatVelocity = horizontal(hit.velocity()); - if (threatVelocity.lengthSqr() < 1.0E-7) { - threatVelocity = horizontal(hit.hitPos().subtract(hit.previousThreatPos())); - } - if (threatVelocity.lengthSqr() < 1.0E-7) { - return null; - } - - Line threatLine = new Line(horizontal(hit.previousThreatPos()), threatVelocity.normalize()); - Vec3 playerPos2d = horizontal(player.position()); - Vec3 nearestPoint = threatLine.nearestPoint(playerPos2d); - double distanceToThreatLine = nearestPoint.distanceTo(playerPos2d); - double safeDistanceWithPadding = Math.max(SAFE_DISTANCE, dangerPadding.get()); - - if (distanceToThreatLine > safeDistanceWithPadding) { - return null; - } - - CandidatePlan candidate = findBestDodgeCandidate(player, hit, threatLine, safeDistanceWithPadding); - if (candidate == null) { - return null; - } - - Vec3 relativeDodge = candidate.relativeDodge(); - DodgePlan basePlan = new DodgePlan(candidate.input(), false, null, false); - if (distanceToThreatLine > SAFE_DISTANCE) { - return basePlan; - } - - DodgePlan escalated = escalateIfNeeded(player, hit, relativeDodge, basePlan); - return escalated != null ? escalated : basePlan; - } - - private DodgePlan escalateIfNeeded(LocalPlayer player, - HitInfo hit, - Vec3 relativeDodge, - DodgePlan basePlan) { - Vec3 actualDirection = inputDirection(player.getYRot(), basePlan.input()); - double effectiveness = similarity(actualDirection, relativeDodge); - if (effectiveness <= 0.05) { - effectiveness = 0.05; - } - - double safeDistanceWithPadding = Math.max(SAFE_DISTANCE, dangerPadding.get()); - double distanceToTravel = Math.max(0.0, relativeDodge.length() - (safeDistanceWithPadding - SAFE_DISTANCE)); - double travelTime = distanceToTravel / (effectiveness * 0.11); - int ticksToImpact = hit.tickDelta() + 1; - - if (ticksToImpact > travelTime) { - return null; - } - - boolean useTimer = shouldUseTimer(distanceToTravel, ticksToImpact); - if (!allowRotationChange.get()) { - return new DodgePlan(basePlan.input(), false, null, useTimer); - } - - float yaw = yawTowards(relativeDodge); - double effectiveVelocity = player.getDeltaMovement().horizontalDistance() - * Math.max(0.0, similarity(horizontal(player.getDeltaMovement()), relativeDodge)); - double travelTimeWithRotation = distanceToTravel / 0.13; - boolean shouldJump = ticksToImpact < travelTimeWithRotation && effectiveVelocity > 0.11; - - return new DodgePlan(InputPlan.FORWARD, shouldJump, yaw, useTimer); - } - - private boolean shouldUseTimer(double distanceToTravel, int ticksToImpact) { - if (!allowTimer.get()) { - return false; - } - - double baseSpeed = allowRotationChange.get() ? 0.155 : 0.11; - return (distanceToTravel / baseSpeed) / (ticksToImpact + 1.0) > 1.6; - } - - private CandidatePlan findBestDodgeCandidate(LocalPlayer player, - HitInfo hit, - Line threatLine, - double safeDistanceWithPadding) { - Vec3 playerPos2d = horizontal(player.position()); - Vec3 optimalDodgePosition = findOptimalDodgePosition(player, threatLine, safeDistanceWithPadding); - Vec3 preferredRelative = optimalDodgePosition.subtract(playerPos2d); - if (preferredRelative.lengthSqr() < 1.0E-7) { - return null; - } - - double currentDistance = threatLine.nearestPoint(playerPos2d).distanceTo(playerPos2d); - int horizon = Mth.clamp(Math.min(hit.tickDelta() + 1, pathCheckTicks.get()), 1, 12); - - CandidatePlan best = null; - double bestScore = -Double.MAX_VALUE; - for (InputPlan input : InputPlan.CANDIDATES) { - Vec3 direction = inputDirection(player.getYRot(), input); - if (direction.lengthSqr() < 1.0E-7) { - continue; - } - - double preference = similarity(direction, preferredRelative); - if (preference < -0.15) { - continue; - } - - CandidateSafety safety = evaluateCandidateSafety(player, direction, horizon); - if (safety.blocked()) { - continue; - } - if (fallFailsafe.get() && !safety.fallSafe()) { - continue; - } - - Vec3 projected = playerPos2d.add(direction.scale(PATH_STEP_SPEED * horizon)); - double distanceAfter = threatLine.nearestPoint(projected).distanceTo(projected); - if (distanceAfter <= currentDistance + 0.015) { - continue; - } - - double score = distanceAfter * 3.0 - + preference - - safety.predictedFallDamage() * 0.35 - - (safety.unsupported() ? 0.8 : 0.0); - if (score > bestScore) { - Vec3 relative = projected.subtract(playerPos2d); - bestScore = score; - best = new CandidatePlan(input, relative); - } - } - - if (best != null) { - return best; - } - - InputPlan fallback = chooseInputFor(player.getYRot(), preferredRelative); - if (fallback == null) { - return null; - } - - Vec3 direction = inputDirection(player.getYRot(), fallback); - CandidateSafety safety = evaluateCandidateSafety(player, direction, horizon); - if (safety.blocked() || (fallFailsafe.get() && !safety.fallSafe())) { - return null; - } - return new CandidatePlan(fallback, preferredRelative); - } - - private CandidateSafety evaluateCandidateSafety(LocalPlayer player, Vec3 direction, int horizon) { - AABB baseBox = player.getBoundingBox(); - Vec3 basePos = player.position(); - boolean unsupported = false; - double predictedFallDamage = 0.0; - - int safeHorizon = Math.max(1, horizon); - for (int tick = 1; tick <= safeHorizon; tick++) { - Vec3 offset = direction.scale(PATH_STEP_SPEED * tick); - AABB pathBox = baseBox.move(offset.x, 0.0, offset.z).deflate(COLLISION_MARGIN, 0.0, COLLISION_MARGIN); - if (!mc.level.noCollision(player, pathBox)) { - return new CandidateSafety(true, false, true, Double.POSITIVE_INFINITY); - } - - if (!hasGroundSupport(player, pathBox) && !player.isInWater() && !player.isFallFlying()) { - unsupported = true; - } - } - - if (unsupported && fallFailsafe.get()) { - Vec3 finalOffset = direction.scale(PATH_STEP_SPEED * safeHorizon); - Vec3 finalPos = basePos.add(finalOffset.x, 0.0, finalOffset.z); - predictedFallDamage = predictFallDamage(player, finalPos); - } - - boolean fallSafe = !unsupported - || !fallFailsafe.get() - || predictedFallDamage <= maxPredictedFallDamage.get() - && predictedFallDamage < player.getHealth() + player.getAbsorptionAmount() - 0.5f; - return new CandidateSafety(false, unsupported, fallSafe, predictedFallDamage); - } - - private boolean hasGroundSupport(LocalPlayer player, AABB box) { - AABB supportBox = new AABB( - box.minX + 0.05, - box.minY - 0.10, - box.minZ + 0.05, - box.maxX - 0.05, - box.minY - 0.01, - box.maxZ - 0.05 - ); - return !mc.level.noCollision(player, supportBox); - } - - private double predictFallDamage(LocalPlayer player, Vec3 horizontalLandingPos) { - if (mc.level == null) { - return Double.POSITIVE_INFINITY; - } - - double landingY = findLandingY(player, horizontalLandingPos); - if (!Double.isFinite(landingY)) { - return Double.POSITIVE_INFINITY; - } - - double fallDistance = Math.max(0.0, player.fallDistance + player.getY() - landingY); - if (fallDistance <= player.getAttributeValue(Attributes.SAFE_FALL_DISTANCE)) { - return 0.0; - } - - float raw = Mth.floor((fallDistance + 1.0E-6 - player.getAttributeValue(Attributes.SAFE_FALL_DISTANCE)) - * player.getAttributeValue(Attributes.FALL_DAMAGE_MULTIPLIER)); - if (raw <= 0.0f) { - return 0.0; - } - - return applyFallReductions(player, raw); - } - - private double findLandingY(LocalPlayer player, Vec3 horizontalLandingPos) { - double startY = player.getY() + 0.2; - double endY = mc.level.getMinY(); - double[][] samples = { - {0.0, 0.0}, - {PLAYER_HALF_WIDTH - 0.04, PLAYER_HALF_WIDTH - 0.04}, - {PLAYER_HALF_WIDTH - 0.04, -PLAYER_HALF_WIDTH + 0.04}, - {-PLAYER_HALF_WIDTH + 0.04, PLAYER_HALF_WIDTH - 0.04}, - {-PLAYER_HALF_WIDTH + 0.04, -PLAYER_HALF_WIDTH + 0.04} - }; - - double bestY = Double.NEGATIVE_INFINITY; - for (double[] sample : samples) { - Vec3 from = new Vec3(horizontalLandingPos.x + sample[0], startY, horizontalLandingPos.z + sample[1]); - Vec3 to = new Vec3(from.x, endY, from.z); - HitResult hit = mc.level.clip(new ClipContext( - from, - to, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.ANY, - player - )); - if (hit != null && hit.getType() != HitResult.Type.MISS) { - bestY = Math.max(bestY, hit.getLocation().y); - } - } - - return bestY; - } - - private float applyFallReductions(LocalPlayer player, float damage) { - DamageSource source = player.damageSources().fall(); - float armor = player.getArmorValue(); - float toughness = (float) player.getAttributeValue(Attributes.ARMOR_TOUGHNESS); - float out = CombatRules.getDamageAfterAbsorb(player, damage, source, armor, toughness); - - MobEffectInstance resistance = player.getEffect(MobEffects.RESISTANCE); - if (resistance != null) { - int reduced = 25 - (resistance.getAmplifier() + 1) * 5; - out = Math.max(out * reduced / 25.0f, 0.0f); - } - - float protection = getFallProtectionAmount(player); - return protection > 0.0f ? CombatRules.getDamageAfterMagicAbsorb(out, protection) : out; - } - - private float getFallProtectionAmount(LocalPlayer player) { - float total = 0.0f; - for (EquipmentSlot slot : ARMOR_SLOTS) { - ItemStack stack = player.getItemBySlot(slot); - total += getEnchantmentLevel(Enchantments.PROTECTION, stack); - if (slot == EquipmentSlot.FEET) { - total += getEnchantmentLevel(Enchantments.FEATHER_FALLING, stack) * 3.0f; - } - } - return total; - } - - private int getEnchantmentLevel(ResourceKey key, ItemStack stack) { - Holder entry = getEnchantmentEntry(key); - return entry != null ? EnchantmentHelper.getItemEnchantmentLevel(entry, stack) : 0; - } - - private Holder getEnchantmentEntry(ResourceKey key) { - if (mc.level == null || key == null) { - return null; - } - - Registry registry = mc.level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT); - Enchantment enchantment = registry.getValue(key); - return enchantment != null ? registry.wrapAsHolder(enchantment) : null; - } - - private Vec3 findOptimalDodgePosition(LocalPlayer player, Line threatLine, double safeDistanceWithPadding) { - Vec3 playerPos2d = horizontal(player.position()); - Vec3 velocity = horizontal(player.getDeltaMovement()); - Vec3 freeMovementPos = playerPos2d.add(velocity.scale(2.0)); - Vec3 nearestPosToLine = threatLine.nearestPoint(playerPos2d); - - Line[] borders = dangerZoneBorders(threatLine, safeDistanceWithPadding); - Vec3 first = borders[0].nearestPoint(freeMovementPos); - Vec3 second = borders[1].nearestPoint(freeMovementPos); - - if (walkableDistance(player, nearestPosToLine, first) < SAFE_DISTANCE) { - return second; - } - - if (walkableDistance(player, nearestPosToLine, second) < SAFE_DISTANCE) { - return first; - } - - return first.distanceTo(freeMovementPos) < second.distanceTo(freeMovementPos) - 0.05 ? first : second; - } - - private double walkableDistance(LocalPlayer player, Vec3 basePos, Vec3 dodgePos) { - double bestSq = Double.POSITIVE_INFINITY; - double[] rayHeights = {0.6, 1.6}; - for (double height : rayHeights) { - Vec3 from = new Vec3(basePos.x, player.getY() + height, basePos.z); - Vec3 to = new Vec3(dodgePos.x, player.getY() + height, dodgePos.z); - HitResult hit = mc.level.clip(new ClipContext( - from, - to, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - Vec3 realTo = hit != null && hit.getType() != HitResult.Type.MISS ? hit.getLocation() : to; - bestSq = Math.min(bestSq, from.distanceToSqr(realTo)); - } - - return Math.sqrt(bestSq); - } - - private Line[] dangerZoneBorders(Line baseLine, double distance) { - Vec3 ortho = new Vec3(-baseLine.direction().z, 0.0, baseLine.direction().x).normalize(); - Vec3 offset = ortho.scale(distance); - return new Line[]{ - new Line(baseLine.position().subtract(offset), baseLine.direction()), - new Line(baseLine.position().add(offset), baseLine.direction()) - }; - } - - private InputPlan chooseInputFor(float yaw, Vec3 desiredDirection) { - Vec3 desired = horizontal(desiredDirection); - if (desired.lengthSqr() < 1.0E-7) { - return null; - } - desired = desired.normalize(); - - InputPlan best = null; - double bestDot = -Double.MAX_VALUE; - for (InputPlan candidate : InputPlan.CANDIDATES) { - Vec3 direction = inputDirection(yaw, candidate); - double dot = direction.dot(desired); - if (dot > bestDot) { - bestDot = dot; - best = candidate; - } - } - - return bestDot >= INPUT_DEAD_DOT ? best : null; - } - - private Vec3 inputDirection(float yaw, InputPlan input) { - float forward = input.forward() == input.backward() ? 0.0f : (input.forward() ? 1.0f : -1.0f); - float sideways = input.left() == input.right() ? 0.0f : (input.left() ? 1.0f : -1.0f); - if (forward == 0.0f && sideways == 0.0f) { - return Vec3.ZERO; - } - - double sin = Math.sin(Math.toRadians(yaw + 90.0f)); - double cos = Math.cos(Math.toRadians(yaw + 90.0f)); - Vec3 direction = new Vec3( - forward * cos + sideways * sin, - 0.0, - forward * sin - sideways * cos - ); - - return direction.lengthSqr() > 1.0 ? direction.normalize() : direction; - } - - private void applyInput(MovementInputEvent event, InputPlan input) { - event.setForward(input.forward()); - event.setBackward(input.backward()); - event.setLeft(input.left()); - event.setRight(input.right()); - if (input.forward()) { - event.setSprint(true); - } - } - - private boolean applyEdgeSafeWalk(LocalPlayer player, MovementInputEvent event) { - if (!fallFailsafe.get() || !edgeSafeWalk.get()) { - return false; - } - - SafeWalk safeWalk = Modules.get(SafeWalk.class); - return safeWalk != null && safeWalk.handleExternalOnEdge(player, event); - } - - private float yawTowards(Vec3 direction) { - return Mth.wrapDegrees((float) Math.toDegrees(Math.atan2(direction.z, direction.x)) - 90.0f); - } - - private double similarity(Vec3 a, Vec3 b) { - Vec3 ah = horizontal(a); - Vec3 bh = horizontal(b); - double len = ah.length() * bh.length(); - if (len < 1.0E-7) { - return 0.0; - } - return ah.dot(bh) / len; - } - - private Vec3 horizontal(Vec3 vec) { - if (vec == null) { - return Vec3.ZERO; - } - return new Vec3(vec.x, 0.0, vec.z); - } - - private boolean isInGround(AbstractArrow projectile) { - try { - return ((PersistentProjectileEntityAccessor) projectile).combatant$isInGround(); - } catch (Throwable ignored) { - return false; - } - } - - private void clearTimer() { - if (timerActive) { - Timer.clearExternalTickTimer(); - timerActive = false; - } - } - - private interface ThreatSimulation { - Entity entity(); - - Vec3 previousPos(); - - Vec3 pos(); - - Vec3 velocity(); - - boolean tick(); - } - - private record HitInfo(int tickDelta, Entity threat, Vec3 hitPos, Vec3 previousThreatPos, Vec3 velocity) { - } - - private record DodgePlan(InputPlan input, boolean shouldJump, Float yawChange, boolean useTimer) { - } - - private record CandidatePlan(InputPlan input, Vec3 relativeDodge) { - } - - private record CandidateSafety(boolean blocked, - boolean unsupported, - boolean fallSafe, - double predictedFallDamage) { - } - - private record InputPlan(boolean forward, boolean backward, boolean left, boolean right) { - private static final InputPlan FORWARD = new InputPlan(true, false, false, false); - private static final InputPlan[] CANDIDATES = { - FORWARD, - new InputPlan(true, false, true, false), - new InputPlan(false, false, true, false), - new InputPlan(false, true, true, false), - new InputPlan(false, true, false, false), - new InputPlan(false, true, false, true), - new InputPlan(false, false, false, true), - new InputPlan(true, false, false, true) - }; - } - - private record Line(Vec3 position, Vec3 direction) { - private Vec3 nearestPoint(Vec3 point) { - double lengthSq = direction.lengthSqr(); - if (lengthSq < 1.0E-7) { - return position; - } - double t = point.subtract(position).dot(direction) / lengthSq; - return position.add(direction.scale(t)); - } - } - - private final class ArrowLikeThreatSimulation implements ThreatSimulation { - private final Entity entity; - private final SimulatedArrow arrow; - private Vec3 previousPos; - private Vec3 pos; - private Vec3 velocity; - private boolean done; - - private ArrowLikeThreatSimulation(Entity entity) { - this.entity = entity; - this.arrow = new SimulatedArrow(mc.level, entity.position(), entity.getDeltaMovement(), false); - this.previousPos = entity.position(); - this.pos = entity.position(); - this.velocity = entity.getDeltaMovement(); - } - - @Override - public Entity entity() { - return entity; - } - - @Override - public Vec3 previousPos() { - return previousPos; - } - - @Override - public Vec3 pos() { - return pos; - } - - @Override - public Vec3 velocity() { - return velocity; - } - - @Override - public boolean tick() { - if (done) { - return false; - } - - previousPos = arrow.getPos(); - HitResult hit = arrow.tick(); - pos = arrow.getPos(); - velocity = pos.subtract(previousPos); - if (hit != null) { - done = true; - } - - return velocity.lengthSqr() > 1.0E-9; - } - } - - private final class LinearThreatSimulation implements ThreatSimulation { - private final Entity entity; - private Vec3 previousPos; - private Vec3 pos; - private Vec3 velocity; - private boolean done; - - private LinearThreatSimulation(Entity entity) { - this.entity = entity; - this.previousPos = entity.position(); - this.pos = entity.position(); - this.velocity = entity.getDeltaMovement(); - } - - @Override - public Entity entity() { - return entity; - } - - @Override - public Vec3 previousPos() { - return previousPos; - } - - @Override - public Vec3 pos() { - return pos; - } - - @Override - public Vec3 velocity() { - return velocity; - } - - @Override - public boolean tick() { - if (done || velocity.lengthSqr() < 1.0E-9) { - return false; - } - - previousPos = pos; - Vec3 nextPos = pos.add(velocity); - HitResult hit = mc.level.clip(new ClipContext( - pos, - nextPos, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - entity - )); - - if (hit != null && hit.getType() != HitResult.Type.MISS) { - pos = hit.getLocation(); - velocity = pos.subtract(previousPos); - done = true; - return velocity.lengthSqr() > 1.0E-9; - } - - pos = nextPos; - velocity = entity instanceof ShulkerBullet ? velocity.scale(0.95) : velocity; - return true; - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ElytraFly.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ElytraFly.java deleted file mode 100644 index 2e219cd..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ElytraFly.java +++ /dev/null @@ -1,764 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import dev.loki.lovisual.events.impl.*; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; -import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket; -import net.minecraft.util.Mth; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.MoverType; -import net.minecraft.world.entity.player.Input; -import net.minecraft.world.entity.projectile.FireworkRocketEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.phys.Vec2; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.*; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.ElytraTarget; -import dev.loki.lovisual.mixins.accessors.InputAccessor; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.player.MovementUtil; -import dev.loki.lovisual.util.player.inventory.FireworkUseController; -import dev.loki.lovisual.util.player.inventory.InventorySwap; - -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; - -//todo Description -@ModuleInfo(id = "elytrafly", displayName = "ElytraFly", aliases = {"elytra", "efly", "elytraflight"}, category = ModuleCategory.MOVEMENT) -public class ElytraFly extends Module { - - private static final int FIREWORK_ROTATION_PRIORITY = 8; - private static final int ROTATION_EVENT_PRIORITY = 60; - - private static final double GRAVITY_COMPENSATION = 0.008; - private static final double NATURAL_LIFT_FACTOR = 0.005; - private static final float MAX_PITCH_ANGLE = 90.0f; - private static final float MAX_DIVE_SPEED_MULTIPLIER = 1.2f; - private static final float DIVE_SPEED_REDUCTION = 0.01f; - private static final float MIN_ACCELERATION_THRESHOLD = 0.01f; - private static final float DECELERATION_FACTOR = 0.98f; - private static final float SPEED_EFFECT_MULTIPLIER = 0.1f; - private static final double PITCH_REDUCTION_FACTOR = 0.3; - private static final double GROUND_PENALTY_FACTOR = 0.8; - private static final double NEAR_GROUND_HORIZONTAL_BOOST = 1.3; - private static final double NEAR_GROUND_VERTICAL_REDUCTION = 0.3; - private static final float DIVE_THRESHOLD_ANGLE = 15.0f; - private static final double DIVE_BOOST_MULTIPLIER = 2.0; - private static final double PACKET_START_COLLISION_XZ_CONTRACT = 0.25; - private static final double PACKET_START_COLLISION_Y_OFFSET = -0.3; - public final BooleanValue noCrash = bool("elytrafly_no_crash", true); - private final Minecraft mc = Minecraft.getInstance(); - private final EnumValue mode = enumMode("elytrafly_mode", Mode.BOOST, Mode.values()); - private final BooleanValue instantStart = bool("elytrafly_instant_start", false); - private final BooleanValue instantStop = bool("elytrafly_instant_stop", false); - private final BooleanValue speedEnabled = - visibleWhen(bool("elytrafly_speed", true), () -> mode.get() == Mode.STATIC); - private final NumberValue verticalSpeed = - visibleWhen(num("elytrafly_speed_vertical", 0.0f, 0.0f, 5.0f), () -> mode.get() == Mode.STATIC && speedEnabled.get()); - private final NumberValue horizontalSpeed = - visibleWhen(num("elytrafly_speed_horizontal", 0.0f, 0.0f, 8.0f), () -> mode.get() == Mode.STATIC && speedEnabled.get()); - private final BooleanValue notInFluid = bool("elytrafly_not_in_fluid", false); - private final BooleanValue durabilityExploit = bool("elytrafly_durability_exploit", false); - private final BooleanValue staticDurabilityExploitNotWhileNoMove = - visibleWhen(bool("elytrafly_static_durability_exploit_not_while_no_move", false), () -> mode.get() == Mode.STATIC); - private final BooleanValue staticGlide = - visibleWhen(bool("elytrafly_static_glide", false), () -> mode.get() == Mode.STATIC); - private final NumberValue staticVerticalGlide = - visibleWhen(num("elytrafly_static_glide_vertical", 0.01f, 0.0f, 1.0f), () -> mode.get() == Mode.STATIC && staticGlide.get()); - private final NumberValue staticHorizontalGlide = - visibleWhen(num("elytrafly_static_glide_horizontal", 0.0f, 0.0f, 1.0f), () -> mode.get() == Mode.STATIC && staticGlide.get()); - private final NumberValue vanillaDragPercent = - visibleWhen(num("elytrafly_vanilla_drag_percent", 99.0f, 90.0f, 100.0f), () -> mode.get() == Mode.VANILLA); - private final NumberValue vanillaForwardBoost = - visibleWhen(num("elytrafly_vanilla_forward_boost", 18.0f, 0.0f, 100.0f), () -> mode.get() == Mode.VANILLA); - private final NumberValue vanillaPitchLift = - visibleWhen(num("elytrafly_vanilla_pitch_lift", 4.5f, 0.0f, 30.0f), () -> mode.get() == Mode.VANILLA); - private final NumberValue boostSpeed = - visibleWhen(num("elytrafly_boost_speed", 0.018f, 0.0f, 2.0f), () -> mode.get() == Mode.BOOST); - private final NumberValue boostAcceleration = - visibleWhen(num("elytrafly_boost_acceleration", 0.018f, 0.001f, 0.1f), () -> mode.get() == Mode.BOOST); - private final BooleanValue boostAutoBoost = - visibleWhen(bool("elytrafly_boost_auto_boost", true), () -> mode.get() == Mode.BOOST); - private final NumberValue boostVerticalControl = - visibleWhen(num("elytrafly_boost_vertical_control", 0.0f, 0.0f, 1.0f), () -> mode.get() == Mode.BOOST); - private final BooleanValue boostSmartGround = - visibleWhen(bool("elytrafly_boost_smart_ground", true), () -> mode.get() == Mode.BOOST); - private final NumberValue boostGroundDistance = - visibleWhen(num("elytrafly_boost_ground_distance", 3.0f, 1.5f, 7.0f), () -> mode.get() == Mode.BOOST && boostSmartGround.get()); - private final BooleanValue boostDiveMechanics = - visibleWhen(bool("elytrafly_boost_dive_mechanics", false), () -> mode.get() == Mode.BOOST); - private final NumberValue boostDiveAcceleration = - visibleWhen(num("elytrafly_boost_dive_acceleration", 0.05f, 0.01f, 0.1f), () -> mode.get() == Mode.BOOST && boostDiveMechanics.get()); - private final NumberValue boostDiveEfficiency = - visibleWhen(num("elytrafly_boost_dive_efficiency", 0.8f, 0.4f, 1.5f), () -> mode.get() == Mode.BOOST && boostDiveMechanics.get()); - private final BooleanValue fireworkConsiderInventory = - visibleWhen(bool("elytrafly_firework_consider_inventory", false), () -> mode.get() == Mode.FIREWORK); - private final NumberValue fireworkCooldownMin = - visibleWhen(num("elytrafly_firework_cooldown_min", 20, 0, 300), () -> mode.get() == Mode.FIREWORK); - private final NumberValue fireworkCooldownMax = - visibleWhen(num("elytrafly_firework_cooldown_max", 20, 0, 300), () -> mode.get() == Mode.FIREWORK); - private final BooleanValue fireworkSilentRotation = - visibleWhen(bool("elytrafly_firework_silent_rotation", true), () -> mode.get() == Mode.FIREWORK); - private final NumberValue fireworkPitch = - visibleWhen(num("elytrafly_firework_pitch", 0.0f, -90.0f, 90.0f), () -> mode.get() == Mode.FIREWORK && fireworkSilentRotation.get()); - private final BooleanValue fireworkVelocityControl = - visibleWhen(bool("elytrafly_firework_velocity_control", true), () -> mode.get() == Mode.FIREWORK); - private final NumberValue fireworkVelocityFactor = - visibleWhen(num("elytrafly_firework_velocity_factor", 0.1f, 0.0f, 2.0f), () -> mode.get() == Mode.FIREWORK && fireworkVelocityControl.get()); - private final BooleanValue packetAutoStart = - visibleWhen(bool("elytrafly_packet_auto_start", true), () -> mode.get() == Mode.PACKET); - private final EnumValue packetSubMode = - visibleWhen(enumMode("elytrafly_packet_sub_mode", PacketSubMode.MOTION, PacketSubMode.values()), () -> mode.get() == Mode.PACKET); - private final BooleanValue packetCancelCorrections = - visibleWhen(bool("elytrafly_packet_cancel_corrections", true), () -> mode.get() == Mode.PACKET); - private boolean needsToRestart; - private Mode lastMode = mode.get(); - private float currentAcceleration; - private float currentDiveSpeed; - private boolean cachedGroundCheck; - private int groundCheckCooldown; - private int fireworkSkipTicks; - private boolean queuedFireworkUse; - - { - setDefaultBind("LEFT_ALT+L"); - } - - @Override - public void onEnable() { - resetRuntimeState(); - needsToRestart = false; - lastMode = mode.get(); - } - - @Override - public void onDisable() { - RotationManager.INSTANCE.clear(this); - InventorySwap.INSTANCE.releaseHotbar(this); - resetRuntimeState(); - needsToRestart = true; - } - - @Override - public void onTick() { - LocalPlayer player = mc.player; - if (player == null || mc.level == null) { - resetRuntimeState(); - return; - } - - syncModeChange(); - tickFireworkCooldown(); - - if (shouldNotOperate(player)) { - needsToRestart = false; - resetModeState(mode.get()); - return; - } - - boolean stop = shouldStopOperating(player); - if (stop && player.isFallFlying()) { - player.stopFallFlying(); - sendStartGlidingPacket(player); - needsToRestart = false; - return; - } - - if (player.isFallFlying()) { - applyTickMode(player); - - if (durabilityExploit.get() && shouldRunDurabilityExploit()) { - sendStartGlidingPacket(player); - needsToRestart = true; - } - } else if (shouldStartOperating(player)) { - suppressJumpInput(player); - player.startFallFlying(); - sendStartGlidingPacket(player); - } - } - - @EventHandler - private void onMove(PlayerMoveEvent event) { - LocalPlayer player = mc.player; - if (player == null || mc.level == null) return; - if (event.getType() != MoverType.SELF) return; - if (!isEnabled() || !player.isFallFlying()) return; - - switch (mode.get()) { - case STATIC -> applyStaticMove(event, player); - case BOOST -> applyBoostMove(event, player); - default -> { - } - } - } - - @EventHandler(priority = ROTATION_EVENT_PRIORITY) - private void onRotationUpdate(RotationUpdateEvent event) { - if (event.getType() != RotationUpdateEvent.Type.PRE) { - return; - } - - LocalPlayer player = mc.player; - if (player == null || mc.level == null) { - return; - } - - if (!isEnabled() || shouldNotOperate(player)) { - RotationManager.INSTANCE.clear(this); - return; - } - - if (mode.get() == Mode.FIREWORK && fireworkSilentRotation.get() && queuedFireworkUse && player.isFallFlying()) { - queueSilentRotation(player, fireworkPitch.get(), FIREWORK_ROTATION_PRIORITY, 3); - return; - } - - RotationManager.INSTANCE.clear(this); - } - - private void queueSilentRotation(LocalPlayer player, float pitch, int priority, int resetTicks) { - float yaw = player.getYRot(); - Rotation rotation = new Rotation(yaw, Mth.clamp(pitch, -90.0f, 90.0f), false); - RotationTarget plan = new RotationTarget( - rotation, - null, - List.of(), - Math.max(2, resetTicks), - 0.5f, - false, - MovementCorrection.SILENT, - null - ); - RotationManager.INSTANCE.setRotationTarget(plan, priority, this); - } - - public boolean shouldNotOperate() { - return mc.player == null || shouldNotOperate(mc.player); - } - - public boolean shouldApplyVanillaHook(LocalPlayer player) { - return isEnabled() - && mode.get() == Mode.VANILLA - && player != null - && player.isFallFlying(); - } - - public double getVanillaDragFactor() { - return vanillaDragPercent.get() / 100.0; - } - - public double getVanillaForwardBoostFactor() { - return vanillaForwardBoost.get() / 1000.0; - } - - public double getVanillaPitchLiftFactor() { - return vanillaPitchLift.get() / 1000.0; - } - - public Vec3 predictTargetingPos(LocalPlayer player) { - if (player == null) { - return Vec3.ZERO; - } - - Vec3 velocity = switch (mode.get()) { - case VANILLA -> predictVanillaVelocity(player); - default -> player.getDeltaMovement(); - }; - - return player.position().add(velocity); - } - - private boolean shouldNotOperate(LocalPlayer player) { - if (player == null) return true; - if (player.isPassenger()) return true; - if (player.getAbilities().instabuild || player.hasEffect(MobEffects.LEVITATION)) return true; - - ItemStack chest = player.getItemBySlot(EquipmentSlot.CHEST); - return !chest.is(Items.ELYTRA) || nextDamageWillBreak(chest); - } - - private Vec3 predictVanillaVelocity(LocalPlayer player) { - Vec3 velocity = player.getDeltaMovement(); - Vec3 look = player.getViewVector(1.0f); - float pitch = player.getXRot(); - - velocity = velocity.scale(getVanillaDragFactor()); - velocity = velocity.add(look.scale(getVanillaForwardBoostFactor())); - - double lift = -Math.sin(Math.toRadians(pitch)) * getVanillaPitchLiftFactor(); - return velocity.add(0.0, lift, 0.0); - } - - private boolean shouldStopOperating(LocalPlayer player) { - if (player == null) return false; - return instantStop.get() && mc.options.keyShift.isDown() && player.onGround() - || notInFluid.get() && isInLiquid(player); - } - - private boolean shouldStartOperating(LocalPlayer player) { - if (player == null) return false; - return (instantStart.get() && mc.options.keyJump.isDown() && player.getDeltaMovement().y != 0.0) - || needsToRestart; - } - - private boolean shouldRunDurabilityExploit() { - if (mode.get() == Mode.VANILLA) return false; - if (mode.get() != Mode.STATIC) return true; - return !staticDurabilityExploitNotWhileNoMove.get() || !MovementUtil.isMoving(); - } - - private void applyTickMode(LocalPlayer player) { - switch (mode.get()) { - case VANILLA -> { - } - case BOOST -> applyBoostTick(player); - case FIREWORK -> applyFireworkTick(player); - default -> { - } - } - } - - private void applyStaticMove(PlayerMoveEvent event, LocalPlayer player) { - Vec3 movement = event.getMovement(); - if (movement == null) return; - - boolean useSpeed = speedEnabled.get(); - if (useSpeed && MovementUtil.isMoving()) { - event.setMovement(applyStrafe(movement, player, horizontalSpeed.get(), 1.0)); - } else { - double glideX = 0.0; - double glideZ = 0.0; - if (staticGlide.get()) { - double len = Math.hypot(movement.x, movement.z); - if (len > 1.0E-6) { - glideX = movement.x / len * staticHorizontalGlide.get(); - glideZ = movement.z / len * staticHorizontalGlide.get(); - } - } - event.setMovement(new Vec3(glideX, movement.y, glideZ)); - } - - Vec3 updated = event.getMovement(); - if (updated == null) return; - - double newY; - if (mc.options.keyJump.isDown() && useSpeed) { - newY = verticalSpeed.get(); - } else if (mc.options.keyShift.isDown() && useSpeed) { - newY = -verticalSpeed.get(); - } else { - newY = staticGlide.get() ? -staticVerticalGlide.get() : 0.0; - } - - event.setMovement(new Vec3(updated.x, newY, updated.z)); - } - - private void applyBoostTick(LocalPlayer player) { - boolean nearGround = isNearGround(player); - float divePullUpBoost = handleDiveMechanics(player); - boolean shouldBoost = mc.options.keyJump.isDown() - || boostAutoBoost.get() - || divePullUpBoost > 0.0f; - - handleBoostAcceleration(shouldBoost); - - if (MovementUtil.isMoving()) { - double speed = calculateEffectiveBoostSpeed(player, nearGround); - player.setDeltaMovement(applyStrafe(player.getDeltaMovement(), player, speed, 1.0)); - } - } - - private void applyBoostMove(PlayerMoveEvent event, LocalPlayer player) { - Vec3 movement = event.getMovement(); - if (movement == null) return; - - boolean nearGround = isNearGround(player); - double divePullUpBoost = player.getXRot() < 0.0f && currentDiveSpeed > 0.0f - ? (-player.getXRot() / MAX_PITCH_ANGLE) * boostDiveEfficiency.get() * currentDiveSpeed * SPEED_EFFECT_MULTIPLIER - : 0.0; - - if (currentAcceleration > 0.0f || currentDiveSpeed > 0.0f) { - movement = movement.add(calculateBoostVector(player, nearGround, divePullUpBoost)); - } - - double newY = calculateBoostVerticalMovement(movement, divePullUpBoost); - event.setMovement(new Vec3(movement.x, newY, movement.z)); - } - - private void applyFireworkTick(LocalPlayer player) { - if (!shouldUseFirework(player)) { - return; - } - queuedFireworkUse = true; - } - - private boolean canPacketStartGliding(LocalPlayer player) { - if (player == null || mc.level == null) return false; - if (player.onGround() || player.isFallFlying() || player.isInWater() || player.isInLava()) return false; - if (player.getDeltaMovement().y > 0.0) return false; - - var collisionBox = player.getBoundingBox() - .inflate(-PACKET_START_COLLISION_XZ_CONTRACT, 0.0, -PACKET_START_COLLISION_XZ_CONTRACT) - .move(0.0, PACKET_START_COLLISION_Y_OFFSET, 0.0); - return !mc.level.getBlockCollisions(player, collisionBox).iterator().hasNext(); - } - - private boolean shouldUseFirework(LocalPlayer player) { - if (player == null || !player.isFallFlying() || player.isUsingItem()) return false; - if (fireworkSkipTicks > 0) return false; - if (!hasFireworkRocket(player)) return false; - - ElytraTarget elytraTarget = Modules.get(ElytraTarget.class); - if (elytraTarget != null && elytraTarget.isManagingFireworks()) { - return false; - } - - for (var entity : mc.level.entitiesForRendering()) { - if (entity instanceof FireworkRocketEntity firework && firework.getOwner() == player) { - return false; - } - } - - return true; - } - - private boolean hasFireworkRocket(LocalPlayer player) { - if (player == null) return false; - if (player.getOffhandItem().is(Items.FIREWORK_ROCKET) - || player.getMainHandItem().is(Items.FIREWORK_ROCKET)) { - return true; - } - - int max = fireworkConsiderInventory.get() ? player.getInventory().getContainerSize() : 9; - for (int i = 0; i < max; i++) { - if (player.getInventory().getItem(i).is(Items.FIREWORK_ROCKET)) { - return true; - } - } - return false; - } - - @EventHandler(priority = -1000) - private void onSyncFirework(EventSync event) { - if (!queuedFireworkUse || !isEnabled()) return; - - LocalPlayer player = mc.player; - queuedFireworkUse = false; - if (player == null || !player.isFallFlying()) return; - - if (FireworkUseController.INSTANCE.use( - event.getYaw(), - event.getPitch(), - fireworkConsiderInventory.get(), - true, - true, - 0, - true - )) { - fireworkSkipTicks = randomFireworkCooldown(); - } - } - - @EventHandler(priority = 20) - private void onSyncPacketMode(EventSync event) { - if (!isEnabled() || mode.get() != Mode.PACKET) return; - - LocalPlayer player = mc.player; - if (player == null || mc.level == null || shouldNotOperate(player)) return; - - boolean started = false; - if (packetAutoStart.get() && !player.isFallFlying() && canPacketStartGliding(player)) { - player.startFallFlying(); - sendStartGlidingPacket(player); - started = true; - } - - if (packetSubMode.get() == PacketSubMode.MOTION - && player.isFallFlying() - && !started - && player.tickCount % 3 != 0) { - event.cancel(); - } - } - - @EventHandler - private void onPacketReceive(PacketEvent.Receive event) { - if (!isEnabled() || mode.get() != Mode.PACKET || !packetCancelCorrections.get()) return; - - LocalPlayer player = mc.player; - if (player == null) return; - - if (event.getPacket() instanceof ClientboundSetEntityDataPacket( - int id, List> packedItems - ) - && id == player.getId() - && !packedItems.isEmpty()) { - event.cancel(); - } - } - - @EventHandler - private void onFirework(FireworkEvent event) { - if (!isEnabled() || mode.get() != Mode.FIREWORK || !fireworkVelocityControl.get()) return; - - LocalPlayer player = mc.player; - if (player == null || !player.isFallFlying()) return; - - ElytraTarget elytraTarget = Modules.get(ElytraTarget.class); - if (elytraTarget != null && elytraTarget.isManagingFireworks()) { - return; - } - - Vec3 currentVelocity = event.getVector(); - Rotation moveRotation = RotationManager.INSTANCE.getMovementRotation(); - Vec3 lookVector = moveRotation.directionVector(); - Vec3 wantedFireworkVelocity = lookVector.scale(1.5); - double factor = fireworkVelocityFactor.get(); - - event.setVector(currentVelocity.add( - lookVector.x * factor + (wantedFireworkVelocity.x - currentVelocity.x) * 0.5, - lookVector.y * factor + (wantedFireworkVelocity.y - currentVelocity.y) * 0.5, - lookVector.z * factor + (wantedFireworkVelocity.z - currentVelocity.z) * 0.5 - )); - } - - private void suppressJumpInput(LocalPlayer player) { - if (player == null || player.input == null) return; - - Input input = player.input.keyPresses; - ((InputAccessor) player.input).setPlayerInput(new Input( - input.forward(), - input.backward(), - input.left(), - input.right(), - false, - input.shift(), - input.sprint() - )); - } - - private void sendStartGlidingPacket(LocalPlayer player) { - if (player == null || mc.getConnection() == null) return; - mc.getConnection().send(new ServerboundPlayerCommandPacket( - player, - ServerboundPlayerCommandPacket.Action.START_FALL_FLYING - )); - } - - private Vec3 applyStrafe(Vec3 currentVelocity, LocalPlayer player, double speed, double strength) { - if (player == null || player.input == null) return currentVelocity; - - Vec2 input = player.input.getMoveVector(); - Vec3 movementInput = new Vec3(input.x, 0.0, input.y); - return MovementUtil.withStrafe(currentVelocity, movementInput, resolveMovementYaw(player), speed, strength); - } - - private float resolveMovementYaw(LocalPlayer player) { - Rotation rotation = RotationManager.INSTANCE.getCurrentRotation(); - var rotationTarget = RotationManager.INSTANCE.getActiveRotationTarget(); - if (rotation != null && rotationTarget != null && rotationTarget.movementCorrection != MovementCorrection.OFF) { - return rotation.yaw(); - } - return player.getYRot(); - } - - private Vec3 resolveDirectionVector(LocalPlayer player) { - Rotation rotation = RotationManager.INSTANCE.getCurrentRotation(); - var rotationTarget = RotationManager.INSTANCE.getActiveRotationTarget(); - if (rotation != null && rotationTarget != null && rotationTarget.movementCorrection != MovementCorrection.OFF) { - return rotation.directionVector(); - } - return player.getViewVector(1.0f); - } - - private boolean isNearGround(LocalPlayer player) { - if (!boostSmartGround.get()) return false; - - groundCheckCooldown--; - if (groundCheckCooldown <= 0) { - cachedGroundCheck = mc.level.getBlockCollisions( - player, - player.getBoundingBox().move(0.0, -boostGroundDistance.get(), 0.0) - ).iterator().hasNext(); - groundCheckCooldown = 3; - } - - return cachedGroundCheck; - } - - private float handleDiveMechanics(LocalPlayer player) { - if (!boostDiveMechanics.get()) { - currentDiveSpeed = Math.max(0.0f, currentDiveSpeed - DIVE_SPEED_REDUCTION); - return 0.0f; - } - - float oldDiveSpeed = currentDiveSpeed; - if (player.getXRot() > DIVE_THRESHOLD_ANGLE) { - float diveFactor = Math.min(player.getXRot() / MAX_PITCH_ANGLE, 1.0f); - currentDiveSpeed = Math.min( - currentDiveSpeed + boostDiveAcceleration.get() * diveFactor, - MAX_DIVE_SPEED_MULTIPLIER - ); - return 0.0f; - } - - currentDiveSpeed = Math.max(0.0f, currentDiveSpeed - DIVE_SPEED_REDUCTION); - - if (player.getXRot() < 0.0f && oldDiveSpeed > 0.0f) { - return oldDiveSpeed * (-player.getXRot() / MAX_PITCH_ANGLE) * boostDiveEfficiency.get(); - } - - return 0.0f; - } - - private void handleBoostAcceleration(boolean shouldBoost) { - if (shouldBoost && currentAcceleration < boostSpeed.get()) { - currentAcceleration = Math.min( - currentAcceleration + boostAcceleration.get() * (1.0f - currentAcceleration / boostSpeed.get()), - boostSpeed.get() - ); - return; - } - - if (!shouldBoost && currentAcceleration > 0.0f) { - float accelerated = currentAcceleration * (DECELERATION_FACTOR - boostAcceleration.get()); - currentAcceleration = accelerated >= MIN_ACCELERATION_THRESHOLD ? accelerated : 0.0f; - } - } - - private double calculateEffectiveBoostSpeed(LocalPlayer player, boolean nearGround) { - double baseSpeed = horizontalSpeed.get(); - double pitchReduction = player.getXRot() < 0.0f - ? Math.abs(player.getXRot() / MAX_PITCH_ANGLE) * PITCH_REDUCTION_FACTOR - : 0.0; - double speedBonus = currentDiveSpeed + getSpeedEffectAmplifier(player) * SPEED_EFFECT_MULTIPLIER; - double groundMultiplier = nearGround ? GROUND_PENALTY_FACTOR : 1.0; - return baseSpeed * (1.0 - pitchReduction + speedBonus) * groundMultiplier; - } - - private Vec3 calculateBoostVector(LocalPlayer player, boolean nearGround, double divePullUpBoost) { - Vec3 look = resolveDirectionVector(player); - double boostFactor = currentAcceleration - + (player.getXRot() > 0.0f ? currentDiveSpeed : divePullUpBoost * DIVE_BOOST_MULTIPLIER); - - if (nearGround) { - Vec3 scaled = new Vec3( - look.x * NEAR_GROUND_HORIZONTAL_BOOST, - look.y * NEAR_GROUND_VERTICAL_REDUCTION, - look.z * NEAR_GROUND_HORIZONTAL_BOOST - ); - double len = scaled.length(); - return len > 1.0E-6 ? scaled.scale(boostFactor / len) : Vec3.ZERO; - } - - return look.scale(boostFactor); - } - - private double calculateBoostVerticalMovement(Vec3 movement, double divePullUpBoost) { - double horizontal = Math.hypot(movement.x, movement.z); - double naturalLift = horizontal * NATURAL_LIFT_FACTOR; - double manualVertical = verticalSpeed.get() * boostVerticalControl.get(); - double baseY = movement.y - GRAVITY_COMPENSATION + naturalLift + divePullUpBoost; - - if (mc.options.keyJump.isDown() && !mc.options.keyShift.isDown()) { - return movement.y + manualVertical + divePullUpBoost; - } - if (mc.options.keyShift.isDown() && !mc.options.keyJump.isDown()) { - return movement.y - manualVertical; - } - return baseY; - } - - private double getSpeedEffectAmplifier(LocalPlayer player) { - var effect = player.getEffect(MobEffects.SPEED); - return effect == null ? 0.0 : effect.getAmplifier() + 1.0; - } - - private int randomFireworkCooldown() { - int min = Math.min(fireworkCooldownMin.get(), fireworkCooldownMax.get()); - int max = Math.max(fireworkCooldownMin.get(), fireworkCooldownMax.get()); - return ThreadLocalRandom.current().nextInt(min, max + 1); - } - - private boolean nextDamageWillBreak(ItemStack stack) { - return stack.isDamageableItem() && (stack.getMaxDamage() - stack.getDamageValue()) <= 1; - } - - private boolean isInLiquid(LocalPlayer player) { - return player != null && (player.isInWater() || player.isInLava()); - } - - private void tickFireworkCooldown() { - if (fireworkSkipTicks > 0) { - fireworkSkipTicks--; - } - } - - private void syncModeChange() { - Mode current = mode.get(); - if (current == lastMode) { - return; - } - - resetModeState(lastMode); - lastMode = current; - } - - private void resetRuntimeState() { - resetBoostState(); - fireworkSkipTicks = 0; - queuedFireworkUse = false; - } - - private void resetModeState(Mode currentMode) { - if (currentMode == Mode.BOOST) { - resetBoostState(); - } - if (currentMode == Mode.FIREWORK) { - fireworkSkipTicks = 0; - queuedFireworkUse = false; - } - } - - private void resetBoostState() { - currentAcceleration = 0.0f; - currentDiveSpeed = 0.0f; - cachedGroundCheck = false; - groundCheckCooldown = 0; - } - - public enum Mode { - STATIC, - VANILLA, - BOOST, - FIREWORK, - PACKET - } - - public enum PacketSubMode { - NORMAL, - MOTION - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ElytraHelper.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ElytraHelper.java deleted file mode 100644 index db50872..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ElytraHelper.java +++ /dev/null @@ -1,498 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.MultiPlayerGameMode; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.Holder; -import net.minecraft.core.component.DataComponents; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.item.enchantment.Enchantments; -import net.minecraft.world.item.equipment.Equippable; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.EventSync; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Notifier; -import dev.loki.lovisual.util.player.ElytraRecastUtil; -import dev.loki.lovisual.util.player.inventory.FireworkUseController; -import dev.loki.lovisual.util.player.inventory.InventorySwap; -import dev.loki.lovisual.util.pvp.client.CooldownsState; - -//todo Description -@ModuleInfo( - id = "elytrahelper", - displayName = "ElytraHelper", - category = ModuleCategory.MOVEMENT -) -public class ElytraHelper extends Module { - - private static final String SETTING_AUTO_TAKEOFF = "auto_takeoff"; - private static final String ACTION_SWAP_ELYTRA = "swap_elytra"; - private static final String ACTION_USE_FIREWORK = "use_firework"; - private static final String SETTING_RECAST_MODE = "recast_mode"; - private static final String SETTING_RECAST_AUTO_WALK = "recast_auto_walk"; - private static final String SETTING_RECAST_AUTO_JUMP = "recast_auto_jump"; - private static final String SETTING_RECAST_ALLOW_BROKEN = "recast_allow_broken"; - private static final String SETTING_RECAST_DELAY = "recast_delay"; - private static final int MANUAL_FIREWORK_COOLDOWN_TICKS = FireworkUseController.DEFAULT_MANUAL_COOLDOWN_TICKS; - private final Minecraft client = Minecraft.getInstance(); - private final BooleanValue autoTakeoff = - bool("auto_takeoff", SETTING_AUTO_TAKEOFF, true); - private final EnumValue recastMode = - enumSetting("recast_mode", SETTING_RECAST_MODE, ElytraRecastUtil.Mode.NORMAL, ElytraRecastUtil.Mode.values()); - private final BooleanValue recastAutoWalk = - bool("recast_auto_walk", SETTING_RECAST_AUTO_WALK, true); - private final BooleanValue recastAutoJump = - bool("recast_auto_jump", SETTING_RECAST_AUTO_JUMP, true); - private final BooleanValue recastAllowBroken = - bool("recast_allow_broken", SETTING_RECAST_ALLOW_BROKEN, true); - private final NumberValue recastDelay = - num("recast_delay", SETTING_RECAST_DELAY, 0, 0, 5); - private ItemStack previousChest = ItemStack.EMPTY; - private boolean swapLock = false; - private boolean pendingFirework = false; - private boolean queuedFireworkUse = false; - private boolean queuedJump = false; - private boolean queuedStartGlide = false; - private boolean pendingAutoTakeoff = false; - private boolean queuedAutoTakeoffRelease = false; - private int queuedAutoTakeoffJumpTicks = 0; - // Delay before START_FALL_FLYING during auto takeoff - private int glideDelayTicks = 0; - - { - setDefaultBind("LEFT_CTRL+R"); - addAction(ACTION_SWAP_ELYTRA, "R"); - addAction(ACTION_USE_FIREWORK, "F"); - } - - private boolean isRecastActive() { - if (!isEnabled()) return false; - return client != null && client.options != null && client.options.keyJump.isDown(); - } - - @Override - public void onTick() { - if (!isEnabled()) return; - if (client.player == null || client.gameMode == null) return; - - LocalPlayer player = client.player; - - // ===== SWAP ELYTRA ===== - if (isActionPressedOnce(ACTION_SWAP_ELYTRA) && !swapLock) { - swapLock = true; - swapChest(); - } - if (!isActionHeld(ACTION_SWAP_ELYTRA)) { - swapLock = false; - } - - if (glideDelayTicks > 0) { - glideDelayTicks--; - } - if (pendingFirework && player.isFallFlying()) { - pendingFirework = false; - queueFireworkUse(); - } - if (pendingAutoTakeoff) { - tickAutoTakeoff(player); - } - - // ===== FIREWORK / TAKEOFF ===== - if (isActionPressedOnce(ACTION_USE_FIREWORK)) { - handleFireworkOrTakeoff(player); - } else if (isActionHeld(ACTION_USE_FIREWORK) && player.isFallFlying() && canQueueManualFirework(player, false)) { - queueFireworkUse(); - } - if (isRecastActive()) { - handleRecast(player); - } else { - ElytraRecastUtil.INSTANCE.reset(this); - } - } - - @Override - public void onDisable() { - if (client == null) return; - InventorySwap.INSTANCE.releaseHotbar(this); - queuedJump = false; - queuedStartGlide = false; - pendingAutoTakeoff = false; - queuedAutoTakeoffRelease = false; - queuedAutoTakeoffJumpTicks = 0; - pendingFirework = false; - queuedFireworkUse = false; - glideDelayTicks = 0; - ElytraRecastUtil.INSTANCE.reset(this); - } - - private void handleRecast(LocalPlayer player) { - ElytraRecastUtil.INSTANCE.request( - this, - player, - recastMode.get(), - recastAllowBroken.get(), - !recastAutoJump.get(), - recastAutoWalk.get(), - recastDelay.get() - ); - ElytraRecastUtil.INSTANCE.tick(this, player); - } - - // ========================================================= - // FIREWORK + AUTO TAKEOFF - // ========================================================= - private void handleFireworkOrTakeoff(LocalPlayer player) { - - // Respect PVP firework cooldown first. - if (CooldownsState.MANAGER.isInPvp() - && CooldownsState.MANAGER.isCooling(Items.FIREWORK_ROCKET)) { - Notifier.warning("Firework is on cooldown"); - return; - } - - // Already gliding: queue the firework in sync phase. Holding the action keeps retrying, - // but FireworkUseController and KillAura sync gates decide the actual shot frame. - if (player.isFallFlying()) { - pendingAutoTakeoff = false; - queuedJump = false; - queuedStartGlide = false; - if (canQueueManualFirework(player, true)) { - queueFireworkUse(); - } - pendingFirework = false; - return; - } - - // AUTO TAKEOFF - if (!autoTakeoff.get()) return; - if (!player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA)) return; - if (player.isPassenger()) return; - if (pendingAutoTakeoff) { - pendingFirework = true; - return; - } - - // Queue jump for sync phase; water and lava are allowed. - pendingAutoTakeoff = true; - queuedStartGlide = false; - if (canJumpNow(player)) { - queueJump(); - glideDelayTicks = player.onGround() ? 1 : 0; - } - - // Firework will be used after glide starts. - pendingFirework = true; - } - - // ========================================================= - // DEFERRED FIREWORK USE - // ========================================================= - private void queueFireworkUse() { - queuedFireworkUse = true; - } - - private boolean canQueueManualFirework(LocalPlayer player, boolean notifyCooldown) { - if (player == null || !player.isFallFlying() || player.isUsingItem()) return false; - if (CooldownsState.MANAGER.isInPvp() - && CooldownsState.MANAGER.isCooling(Items.FIREWORK_ROCKET)) { - if (notifyCooldown) { - Notifier.warning("Firework is on cooldown"); - } - return false; - } - return FireworkUseController.INSTANCE.canPassCooldown(MANUAL_FIREWORK_COOLDOWN_TICKS); - } - - private void queueJump() { - queuedJump = true; - } - - private boolean canJumpNow(LocalPlayer player) { - return player != null - && !player.isPassenger() - && !player.getAbilities().flying - && (player.onGround() || player.isInWater() || player.isInLava()); - } - - private void clearAutoTakeoff() { - pendingAutoTakeoff = false; - queuedJump = false; - queuedStartGlide = false; - queuedAutoTakeoffRelease = false; - queuedAutoTakeoffJumpTicks = 0; - glideDelayTicks = 0; - } - - private void tickAutoTakeoff(LocalPlayer player) { - if (player == null) { - clearAutoTakeoff(); - return; - } - if (player.isFallFlying()) { - clearAutoTakeoff(); - return; - } - if (player.isPassenger() || !player.getItemBySlot(EquipmentSlot.CHEST).is(Items.ELYTRA)) { - clearAutoTakeoff(); - pendingFirework = false; - return; - } - - if (player.isInWater() || player.isInLava()) { - queueJump(); - queuedStartGlide = false; - queuedAutoTakeoffRelease = false; - glideDelayTicks = 0; - return; - } - - if (player.onGround()) { - queueJump(); - queuedStartGlide = false; - queuedAutoTakeoffRelease = false; - if (glideDelayTicks <= 0) { - glideDelayTicks = 1; - } - return; - } - - if (glideDelayTicks > 0) { - return; - } - - if (player.getDeltaMovement().y > 0.0) { - return; - } - - if (queuedStartGlide || queuedAutoTakeoffRelease) { - return; - } - - queuedAutoTakeoffRelease = true; - queuedStartGlide = true; - } - - @EventHandler(priority = -1000) - private void onMovementInput(MovementInputEvent event) { - if (!isEnabled()) return; - - if (ElytraRecastUtil.INSTANCE.handleMovementInput(this, event)) { - return; - } - - if (queuedAutoTakeoffRelease) { - event.setJump(false); - queuedAutoTakeoffRelease = false; - return; - } - - if (queuedAutoTakeoffJumpTicks > 0) { - event.setJump(true); - queuedAutoTakeoffJumpTicks--; - return; - } - - if (!queuedJump) return; - - LocalPlayer player = client.player; - if (player == null) { - queuedJump = false; - return; - } - - if (canJumpNow(player)) { - event.setJump(true); - } - queuedJump = false; - } - - @EventHandler(priority = -1000) - private void onSync(EventSync event) { - if (!isEnabled()) return; - - LocalPlayer player = client.player; - MultiPlayerGameMode manager = client.gameMode; - if (player == null || manager == null) return; - - if (queuedStartGlide) { - if (player.isFallFlying()) { - queuedStartGlide = false; - pendingAutoTakeoff = false; - } else if (!player.onGround() - && !player.isInWater() - && !player.isInLava() - && player.getDeltaMovement().y <= 0.0) { - queuedStartGlide = false; - if (player.tryToStartFallFlying()) { - pendingAutoTakeoff = false; - queuedAutoTakeoffJumpTicks = 1; - } - if (player.isFallFlying() && client.getConnection() != null) { - client.getConnection().send( - new ServerboundPlayerCommandPacket(player, ServerboundPlayerCommandPacket.Action.START_FALL_FLYING) - ); - } else { - glideDelayTicks = 1; - } - } else if (player.onGround() || player.isInWater() || player.isInLava()) { - queuedStartGlide = false; - queuedAutoTakeoffRelease = false; - } - } - - if (ElytraRecastUtil.INSTANCE.handleSync(this, event)) { - return; - } - - if (!queuedFireworkUse) return; - queuedFireworkUse = false; - FireworkUseController.INSTANCE.use( - event.getYaw(), - event.getPitch(), - true, - true, - true, - MANUAL_FIREWORK_COOLDOWN_TICKS, - true - ); - } - - // ========================================================= - // SWAP / UTILS - // ========================================================= - private void swapChest() { - LocalPlayer player = client.player; - if (player == null) return; - - ItemStack equipped = getChestStack(player); - - if (!isElytra(equipped)) { - int elytraSlot = findElytra(player); - if (elytraSlot == -1) return; - if (!equipped.isEmpty()) previousChest = equipped.copy(); - swapInventoryWithChest(player, elytraSlot); - return; - } - - int chestSlot = findPreviousOrAnyChest(player); - if (chestSlot == -1) return; - swapInventoryWithChest(player, chestSlot); - previousChest = ItemStack.EMPTY; - } - - private void swapInventoryWithChest(LocalPlayer player, int invSlot) { - var handler = player.inventoryMenu; - if (handler == null) return; - - int syncId = handler.containerId; - int chestScreenSlot = 6; - int invScreenSlot = InventorySwap.mapInventoryToScreenSlot(invSlot); - - client.execute(() -> InventorySwap.INSTANCE.swapScreenSlots(invScreenSlot, chestScreenSlot)); - } - - private ItemStack getChestStack(LocalPlayer player) { - return player.getInventory() - .getItem(EquipmentSlot.CHEST.getIndex(36)); - } - - private boolean isElytra(ItemStack stack) { - return !stack.isEmpty() && stack.is(Items.ELYTRA); - } - - private boolean isChestplate(ItemStack stack) { - if (stack.isEmpty() || stack.is(Items.ELYTRA)) return false; - Equippable eq = stack.get(DataComponents.EQUIPPABLE); - return eq != null && eq.slot() == EquipmentSlot.CHEST; - } - - private int findElytra(LocalPlayer player) { - for (int i = 0; i < 36; i++) { - if (player.getInventory().getItem(i).is(Items.ELYTRA)) return i; - } - return -1; - } - - private int findPreviousOrAnyChest(LocalPlayer player) { - if (!previousChest.isEmpty()) { - for (int i = 0; i < 36; i++) { - ItemStack s = player.getInventory().getItem(i); - if (!s.isEmpty() && ItemStack.isSameItem(s, previousChest)) { - return i; - } - } - } - - int best = findBestChestplate(player); - if (best != -1) return best; - - for (int i = 0; i < 36; i++) { - if (isChestplate(player.getInventory().getItem(i))) return i; - } - - return -1; - } - - private int findBestChestplate(LocalPlayer player) { - int bestSlot = -1; - int bestScore = -1; - - for (int i = 0; i < 36; i++) { - ItemStack s = player.getInventory().getItem(i); - int score = getChestDefenseScore(s); - if (score > bestScore) { - bestScore = score; - bestSlot = i; - } - } - return bestSlot; - } - - private int getChestDefenseScore(ItemStack stack) { - if (stack.isEmpty() || stack.is(Items.ELYTRA)) return 0; - - int base = - stack.is(Items.LEATHER_CHESTPLATE) ? 3 : - stack.is(Items.COPPER_CHESTPLATE) ? 4 : - stack.is(Items.CHAINMAIL_CHESTPLATE) ? 5 : - stack.is(Items.GOLDEN_CHESTPLATE) ? 5 : - stack.is(Items.IRON_CHESTPLATE) ? 6 : - stack.is(Items.DIAMOND_CHESTPLATE) ? 8 : - stack.is(Items.NETHERITE_CHESTPLATE) ? 9 : 0; - - if (base == 0) return 0; - return base * 10 + getProtectionLevel(stack) * 4; - } - - private int getProtectionLevel(ItemStack stack) { - Holder prot = getProtectionEnchant(); - return prot == null ? 0 : EnchantmentHelper.getItemEnchantmentLevel(prot, stack); - } - - private Holder getProtectionEnchant() { - if (client.level == null) return null; - var registry = client.level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT); - Enchantment ench = registry.getValue(Enchantments.PROTECTION); - return ench == null ? null : registry.wrapAsHolder(ench); - } - -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Flight.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Flight.java deleted file mode 100644 index a8610e2..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Flight.java +++ /dev/null @@ -1,459 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on, adapted from, or implemented - * with reference to Meteor Client - * (https://github.com/MeteorDevelopment/meteor-client). - * Copyright (c) Meteor Development. - * - * Licensed under the GNU General Public License v3.0. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import dev.loki.lovisual.events.impl.*; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket; -import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.*; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.mixins.accessors.LocalPlayerAccessor; -import dev.loki.lovisual.mixins.accessors.ServerboundMovePlayerPacketAccessor; -import dev.loki.lovisual.util.player.MovementUtil; - -//todo Description -@ModuleInfo( - id = "flight", - displayName = "Flight", - category = ModuleCategory.MOVEMENT -) -public class Flight extends Module { - - private final EnumValue mode = - enumMode("mode", Mode.ABILITIES, Mode.values()); - private final NumberValue speed = - visibleWhen(num("speed", 0.1, 0.0, 5.0), this::usesSpeed); - private final BooleanValue verticalSpeedMatch = - visibleWhen(bool("vertical_speed_match", false), () -> mode.get() == Mode.VELOCITY); - private final BooleanValue noSneak = - visibleWhen(bool("no_sneak", false), () -> mode.get() == Mode.VELOCITY); - private final EnumValue antiKickMode = - visibleWhen(enumMode("anti_kick_mode", AntiKickMode.PACKET, AntiKickMode.values()), this::supportsAntiKick); - private final NumberValue delay = - visibleWhen(num("anti_kick_delay", 20, 1, 200), this::supportsAntiKick); - private int delayLeft = delay.get(); - private final NumberValue offTime = - visibleWhen(num("anti_kick_off_time", 1, 1, 20), this::supportsAntiKick); - private int offLeft = offTime.get(); - private boolean flip; - private float lastYaw; - private double lastPacketY = Double.MAX_VALUE; - private Mode lastMode = mode.get(); - private int vulcanFlags; - private boolean vulcanWait; - private int grimTicks; - - @Override - public void onEnable() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return; - - resetModeState(); - - if (mode.get() == Mode.ABILITIES && !mc.player.isSpectator()) { - mc.player.getAbilities().flying = true; - if (!mc.player.getAbilities().instabuild) { - mc.player.getAbilities().mayfly = true; - } - } - - if (mode.get() == Mode.VULCAN_286_113) { - mc.player.connection.send(new ServerboundMovePlayerPacket.Pos( - mc.player.getX(), - mc.player.getY() - 0.1, - mc.player.getZ(), - mc.player.onGround(), - mc.player.horizontalCollision - )); - } - - lastMode = mode.get(); - } - - @Override - public void onDisable() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return; - if (mode.get() == Mode.ABILITIES && !mc.player.isSpectator()) { - abilitiesOff(); - } - resetModeState(); - } - - @EventHandler - private void onGameTick(GameTickEvent event) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return; - - syncModeChange(); - - if (isMeteorMode()) { - tickMeteorMode(mc); - return; - } - - LocalPlayer player = mc.player; - switch (mode.get()) { - case AIRWALK -> { - if (player.getDeltaMovement().y < 0.0 && !mc.options.keyJump.isDown() && !mc.options.keyShift.isDown()) { - player.setDeltaMovement(player.getDeltaMovement().x, 0.0, player.getDeltaMovement().z); - } - } - case VULCAN_277 -> { - if (player.fallDistance > 0.1f) { - Vec3 vel = player.getDeltaMovement(); - player.setDeltaMovement(vel.x, player.tickCount % 2 == 0 ? -0.155 : -0.1, vel.z); - } - } - case GRIM_2859_V -> { - if (grimTicks == 0 && player.onGround()) { - player.jumpFromGround(); - } - grimTicks++; - } - default -> { - } - } - } - - @EventHandler - private void onMove(PlayerMoveEvent event) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return; - if (event.getType() != net.minecraft.world.entity.MoverType.SELF) return; - - switch (mode.get()) { - case SPARTAN_524 -> { - double yaw = Math.toRadians(mc.player.getYRot()); - event.setMovement(new Vec3( - -Math.sin(yaw) * 0.28, - 0.0, - Math.cos(yaw) * 0.28 - )); - } - case AIRWALK -> { - Vec3 movement = event.getMovement(); - if (movement != null && movement.y < 0.0) { - event.setMovement(new Vec3(movement.x, 0.0, movement.z)); - } - } - default -> { - } - } - } - - @EventHandler - private void onCollision(EventCollision event) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return; - - BlockPos below = BlockPos.containing(mc.player.position()).below(); - boolean spoofBelow = event.getPos().equals(below) && !mc.options.keyShift.isDown(); - - switch (mode.get()) { - case AIRWALK, VULCAN_286_113, VULCAN_286_18 -> { - if (spoofBelow) { - event.setState(Blocks.BARRIER.defaultBlockState()); - } - } - default -> { - } - } - } - - @EventHandler - private void onPacketReceive(PacketEvent.Receive event) { - if (!(event.getPacket() instanceof ClientboundPlayerPositionPacket)) return; - - switch (mode.get()) { - case VULCAN_286_113, VULCAN_286_18 -> { - vulcanFlags++; - if (vulcanFlags == 1) { - vulcanWait = true; - event.cancel(); - } else { - setEnabled(false); - } - } - default -> { - } - } - } - - @EventHandler - private void onPacketSend(PacketEvent.Send event) { - if (!(event.getPacket() instanceof ServerboundMovePlayerPacket packet)) return; - - switch (mode.get()) { - case AIRWALK, VULCAN_286_18 -> ((ServerboundMovePlayerPacketAccessor) packet).combatant$setOnGround(true); - case VULCAN_286_113 -> { - if (vulcanWait) { - ((ServerboundMovePlayerPacketAccessor) packet).combatant$setOnGround(false); - } - } - default -> { - } - } - } - - @EventHandler - private void onSync(EventSync event) { - Minecraft mc = Minecraft.getInstance(); - LocalPlayer player = mc != null ? mc.player : null; - if (player == null) return; - - if (mode.get() == Mode.GRIM_2859_V && grimTicks >= 2) { - Vec3 original = player.position(); - player.setPos(original.x + 1152.0, original.y, original.z + 1152.0); - event.addPostAction(() -> player.setPos(original.x, original.y, original.z)); - } - } - - public ServerboundMovePlayerPacket onSendMovePacket(ServerboundMovePlayerPacket packet) { - if (packet == null) return null; - if (!isMeteorMode() || antiKickMode.get() != AntiKickMode.PACKET) return null; - - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return null; - - double currentY = packet.getY(Double.MAX_VALUE); - if (currentY != Double.MAX_VALUE) { - antiKickPacket(packet, currentY); - return null; - } - - ServerboundMovePlayerPacket fullPacket; - if (packet.hasRotation()) { - fullPacket = new ServerboundMovePlayerPacket.PosRot( - mc.player.getX(), - mc.player.getY(), - mc.player.getZ(), - packet.getYRot(0), - packet.getXRot(0), - packet.isOnGround(), - mc.player.horizontalCollision - ); - } else { - fullPacket = new ServerboundMovePlayerPacket.Pos( - mc.player.getX(), - mc.player.getY(), - mc.player.getZ(), - packet.isOnGround(), - mc.player.horizontalCollision - ); - } - - antiKickPacket(fullPacket, mc.player.getY()); - return fullPacket; - } - - public boolean onReceiveAbilities(ClientboundPlayerAbilitiesPacket packet) { - if (packet == null) return false; - if (mode.get() != Mode.ABILITIES) return false; - - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return false; - - mc.player.getAbilities().invulnerable = packet.isInvulnerable(); - mc.player.getAbilities().instabuild = packet.canInstabuild(); - mc.player.getAbilities().setWalkingSpeed(packet.getWalkingSpeed()); - return true; - } - - public float getOffGroundSpeed() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return -1; - if (!isEnabled() || mode.get() != Mode.VELOCITY) return -1; - return speed.get().floatValue() * (mc.player.isSprinting() ? 15f : 10f); - } - - public boolean noSneak() { - return isEnabled() && mode.get() == Mode.VELOCITY && noSneak.get(); - } - - private void tickMeteorMode(Minecraft mc) { - float currentYaw = mc.player.getYRot(); - if (mc.player.fallDistance >= 3f && currentYaw == lastYaw && mc.player.getDeltaMovement().length() < 0.003d) { - mc.player.setYRot(currentYaw + (flip ? 1 : -1)); - flip = !flip; - } - lastYaw = currentYaw; - - if (delayLeft > 0) delayLeft--; - - if (offLeft <= 0 && delayLeft <= 0) { - delayLeft = delay.get(); - offLeft = offTime.get(); - - if (antiKickMode.get() == AntiKickMode.PACKET) { - if (mc.player instanceof LocalPlayerAccessor accessor) { - accessor.combatant$setTicksSinceLastPositionPacketSent(20); - } - } - } else if (delayLeft <= 0) { - boolean shouldReturn = false; - - if (antiKickMode.get() == AntiKickMode.NORMAL) { - if (mode.get() == Mode.ABILITIES) { - abilitiesOff(); - shouldReturn = true; - } - } else if (antiKickMode.get() == AntiKickMode.PACKET && offLeft == offTime.get()) { - if (mc.player instanceof LocalPlayerAccessor accessor) { - accessor.combatant$setTicksSinceLastPositionPacketSent(20); - } - } - - offLeft--; - - if (shouldReturn) return; - } - - if (mc.player.getYRot() != lastYaw) mc.player.setYRot(lastYaw); - - switch (mode.get()) { - case VELOCITY -> { - mc.player.getAbilities().flying = false; - double horizontalSpeed = speed.get() * (mc.player.isSprinting() ? 15f : 10f); - double[] dir = MovementUtil.forward(horizontalSpeed); - Vec3 playerVelocity = new Vec3(dir[0], 0.0, dir[1]); - if (mc.options.keyJump.isDown()) { - playerVelocity = playerVelocity.add(0, speed.get() * (verticalSpeedMatch.get() ? 10f : 5f), 0); - } - if (mc.options.keyShift.isDown()) { - playerVelocity = playerVelocity.subtract(0, speed.get() * (verticalSpeedMatch.get() ? 10f : 5f), 0); - } - mc.player.setDeltaMovement(playerVelocity); - if (noSneak.get()) { - mc.player.setOnGround(false); - } - } - case ABILITIES -> { - if (mc.player.isSpectator()) return; - mc.player.getAbilities().setFlyingSpeed(speed.get().floatValue()); - mc.player.getAbilities().flying = true; - if (!mc.player.getAbilities().instabuild) { - mc.player.getAbilities().mayfly = true; - } - } - default -> { - } - } - } - - private void antiKickPacket(ServerboundMovePlayerPacket packet, double currentY) { - Minecraft mc = Minecraft.getInstance(); - LocalPlayer player = mc != null ? mc.player : null; - if (player == null) return; - - if (delayLeft <= 0 && lastPacketY != Double.MAX_VALUE - && shouldFlyDown(currentY, lastPacketY) && isOnAir(player)) { - ((ServerboundMovePlayerPacketAccessor) packet).combatant$setY(lastPacketY - 0.03130D); - } else { - lastPacketY = currentY; - } - } - - private boolean shouldFlyDown(double currentY, double lastY) { - if (currentY >= lastY) { - return true; - } - return lastY - currentY < 0.03130D; - } - - private boolean isOnAir(LocalPlayer player) { - return !player.onGround() - && !player.isInWater() - && !player.isInLava() - && !player.onClimbable(); - } - - private void abilitiesOff() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return; - mc.player.getAbilities().flying = false; - mc.player.getAbilities().setFlyingSpeed(0.05f); - if (!mc.player.getAbilities().instabuild) { - mc.player.getAbilities().mayfly = false; - } - } - - private void syncModeChange() { - Mode current = mode.get(); - if (current == lastMode) return; - lastMode = current; - if (!isEnabled() || !canUpdate()) return; - abilitiesOff(); - resetModeState(); - } - - private boolean canUpdate() { - Minecraft mc = Minecraft.getInstance(); - return mc != null && mc.player != null && mc.level != null; - } - - private boolean isMeteorMode() { - return mode.get() == Mode.ABILITIES || mode.get() == Mode.VELOCITY; - } - - private boolean supportsAntiKick() { - return mode.get() == Mode.ABILITIES || mode.get() == Mode.VELOCITY; - } - - private boolean usesSpeed() { - return switch (mode.get()) { - case ABILITIES, VELOCITY -> true; - default -> false; - }; - } - - private void resetModeState() { - delayLeft = delay.get(); - offLeft = offTime.get(); - flip = false; - lastPacketY = Double.MAX_VALUE; - vulcanFlags = 0; - vulcanWait = false; - grimTicks = 0; - } - - public enum Mode { - ABILITIES, - VELOCITY, - AIRWALK, - SPARTAN_524, - VULCAN_277, - VULCAN_286_113, - VULCAN_286_18, - GRIM_2859_V - } - - public enum AntiKickMode { - NORMAL, - PACKET, - NONE - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Freeze.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Freeze.java deleted file mode 100644 index df813d1..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Freeze.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; - -//todo Description -@ModuleInfo( - id = "freeze", - displayName = "Freeze", - category = ModuleCategory.MOVEMENT -) -public final class Freeze extends Module { - - public Freeze() { - setDefaultBind("COMMA"); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/InventoryMove.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/InventoryMove.java deleted file mode 100644 index 3bcabb7..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/InventoryMove.java +++ /dev/null @@ -1,500 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on InvMove - * (https://github.com/PieKing1215/InvMove). - * Copyright (c) PieKing1215 and contributors. - * - * Original portions remain under LGPLv3. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import com.mojang.blaze3d.platform.InputConstants; -import dev.loki.lovisual.util.screen.ClientScreen; -import net.minecraft.client.KeyMapping; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.EditBox; -import net.minecraft.client.gui.screens.PauseScreen; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.inventory.*; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientboundContainerClosePacket; -import net.minecraft.network.protocol.game.ServerboundContainerClickPacket; -import net.minecraft.network.protocol.game.ServerboundContainerClosePacket; -import net.minecraft.world.entity.player.Input; -import dev.loki.lovisual.config.values.BooleanMapValue; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.SetValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.events.impl.PacketEvent; -import dev.loki.lovisual.features.gui.clickgui.ClickGuiEditorScreen; -import dev.loki.lovisual.features.gui.clickgui.ClickGuiPickerScreen; -import dev.loki.lovisual.features.gui.clickgui.ClickGuiRenderer; -import dev.loki.lovisual.features.gui.clickgui.ClickGuiScreen; -import dev.loki.lovisual.features.gui.clickgui.settings.TextListSetting; -import dev.loki.lovisual.features.gui.clickgui.layout.screen.settings.implement.relations.RelationsComponent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.mixins.accessors.InputAccessor; -import dev.loki.lovisual.util.screen.ScreenCatalog; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -/** - * Inventory movement and per-screen policy system for Combatant. - *

- * Credit: - * Behavior design and feature scope were adapted from the InvMove mod by pieking1215. - */ -//todo Description -@ModuleInfo( - id = "inventorymove", - displayName = "InventoryMove", - category = ModuleCategory.MOVEMENT -) -public class InventoryMove extends Module { - - private static final long STOP_TIMEOUT_MS = 100L; - private static final long RESUME_DELAY_MS = 40L; - private static final double STOP_VELOCITY = 0.03; - private static final String TOGGLE_JUMP = "Jump"; - private static final String TOGGLE_SNEAK = "Sneak"; - private static final String TOGGLE_SPRINT = "Sprint"; - private final Minecraft mc = Minecraft.getInstance(); - private final EnumValue mode = enumSetting("mode", "mode", Mode.NORMAL, Mode.values()); - private final BooleanValue cancelServerClose = - visibleWhen(bool("cancel_server_close", true), () -> mode.get() == Mode.GRIM); - private final BooleanValue textFieldDisablesMovement = bool("text_fields_disable", true); - private final BooleanMapValue movementToggles = group("movement_toggles", defaultMovementToggles()); - private final SetValue allowedScreens = - textList("allowed_screens", "allowed_screens", TextListSetting.PickerMode.SCREENS, defaultAllowedScreens()); - private final SetValue blockedScreens = - textList("blocked_screens", "blocked_screens", TextListSetting.PickerMode.SCREENS, defaultBlockedScreens()); - private final List heldPackets = new ArrayList<>(); - private GrimPhase grimPhase = GrimPhase.IDLE; - private long phaseStartedAt = 0L; - private int pendingCloseSyncId = -1; - private boolean flushingPackets = false; - private boolean allowClosePacket = false; - private boolean movementBlocked = false; - - private static Set defaultAllowedScreens() { - LinkedHashSet screens = new LinkedHashSet<>(); - screens.add(AbstractContainerScreen.class.getName()); - screens.add(PauseScreen.class.getName()); - screens.add(ScreenCatalog.CLICK_GUI); - screens.add(ScreenCatalog.CLICK_GUI_EDITOR); - screens.add(ScreenCatalog.CLICK_GUI_PICKER); - screens.add("pivosos2007.gui.clickgui.ClickGuiScreen"); - screens.add("pivosos2007.gui.clickgui.ClickGuiPickerScreen"); - screens.add("pivosos2007.gui.clickgui.ClickGuiEditorScreen"); - screens.add("pivosos2007.features.gui.clickgui.ClickGuiScreen"); - screens.add("pivosos2007.features.gui.clickgui.ClickGuiEditorScreen"); - screens.add("pivosos2007.features.gui.clickgui.ClickGuiPickerScreen"); - screens.add(CreativeModeInventoryScreen.class.getName()); - screens.add(InventoryScreen.class.getName()); - screens.add(ContainerScreen.class.getName()); - return screens; - } - - private static java.util.Map defaultMovementToggles() { - java.util.LinkedHashMap toggles = new java.util.LinkedHashMap<>(); - toggles.put(TOGGLE_JUMP, true); - toggles.put(TOGGLE_SNEAK, true); - toggles.put(TOGGLE_SPRINT, true); - return toggles; - } - - private static Set defaultBlockedScreens() { - return new LinkedHashSet<>(Set.of( - AbstractSignEditScreen.class.getName(), - AbstractCommandBlockEditScreen.class.getName(), - StructureBlockEditScreen.class.getName(), - AnvilScreen.class.getName(), - BookEditScreen.class.getName(), - BookSignScreen.class.getName() - )); - } - - @Override - public void onEnable() { - resetGrimState(); - syncMovementKeysFromPhysical(); - } - - @Override - public void onDisable() { - resetGrimState(); - syncMovementKeysFromPhysical(); - } - - @Override - public void onTick() { - if (ClientScreen.current() != null) { - ScreenCatalog.registerSeen(ClientScreen.current()); - } - - if (mc.player == null) return; - - if (mode.get() == Mode.NORMAL) { - tickNormal(); - return; - } - - tickGrim(); - } - - @EventHandler - public void onMovementInput(MovementInputEvent event) { - if (mc.player == null || ClientScreen.current() == null) { - return; - } - - if (mode.get() == Mode.NORMAL) { - applyMovementToEvent(event, isMovementAllowed(ClientScreen.current())); - return; - } - - if (movementBlocked || isBlockingGrimPhase()) { - clearMovementEvent(event); - return; - } - - applyMovementToEvent(event, isMovementAllowed(ClientScreen.current())); - } - - private boolean isBlockingGrimPhase() { - return grimPhase == GrimPhase.STOPPING - || grimPhase == GrimPhase.FLUSHING - || grimPhase == GrimPhase.CLOSING; - } - - private void applyMovementToEvent(MovementInputEvent event, boolean canMove) { - if (!canMove || mc.getWindow() == null) { - clearMovementEvent(event); - return; - } - - event.setForward(isPhysicallyPressed(mc.options.keyUp)); - event.setBackward(isPhysicallyPressed(mc.options.keyDown)); - event.setLeft(isPhysicallyPressed(mc.options.keyLeft)); - event.setRight(isPhysicallyPressed(mc.options.keyRight)); - event.setJump(movementToggles.get(TOGGLE_JUMP) && isPhysicallyPressed(mc.options.keyJump)); - event.setSneak(movementToggles.get(TOGGLE_SNEAK) && isPhysicallyPressed(mc.options.keyShift)); - event.setSprint(movementToggles.get(TOGGLE_SPRINT) && isPhysicallyPressed(mc.options.keySprint)); - } - - private void clearMovementEvent(MovementInputEvent event) { - event.setForward(false); - event.setBackward(false); - event.setLeft(false); - event.setRight(false); - event.setJump(false); - event.setSprint(false); - event.setSneak(false); - - if (mc.player != null && mc.player.input != null) { - ((InputAccessor) mc.player.input).setPlayerInput(new Input(false, false, false, false, false, false, false)); - } - } - - @EventHandler - public void onPacketSend(PacketEvent.Send event) { - if (mode.get() != Mode.GRIM || mc.player == null) return; - - Packet packet = event.getPacket(); - if (packet instanceof ServerboundContainerClickPacket click) { - if (flushingPackets) return; - if (shouldBufferClickPacket(click)) { - heldPackets.add(click); - event.cancel(); - } - return; - } - - if (packet instanceof ServerboundContainerClosePacket close) { - if (allowClosePacket) return; - if (requestClose(close.getContainerId())) { - event.cancel(); - } - } - } - - @EventHandler - public void onPacketReceive(PacketEvent.Receive event) { - if (mode.get() != Mode.GRIM || !cancelServerClose.get()) return; - Packet packet = event.getPacket(); - if (packet instanceof ClientboundContainerClosePacket close && close.getContainerId() == 0) { - event.cancel(); - } - } - - public boolean shouldCancelHandledScreenClose(AbstractContainerScreen screen) { - return mode.get() == Mode.GRIM && requestClose(syncId(screen)); - } - - public boolean shouldCancelCloseHandledScreen() { - if (mode.get() != Mode.GRIM || mc.player == null) return false; - if (!(ClientScreen.current() instanceof AbstractContainerScreen)) return false; - return requestClose(mc.player.containerMenu.containerId); - } - - private void tickNormal() { - applyMovementForCurrentScreen(isMovementAllowed(ClientScreen.current())); - } - - private void tickGrim() { - boolean grimManaged = shouldManageCurrentHandledScreen(); - - if (grimManaged) { - if (grimPhase == GrimPhase.IDLE) { - grimPhase = GrimPhase.ACTIVE; - } - if (grimPhase == GrimPhase.ACTIVE) { - movementBlocked = false; - syncMovementKeysFromPhysical(); - } - } else if (grimPhase == GrimPhase.ACTIVE) { - resetGrimState(); - } - - if (!grimManaged && grimPhase == GrimPhase.IDLE) { - movementBlocked = false; - applyMovementForCurrentScreen(isMovementAllowed(ClientScreen.current())); - return; - } - - long elapsed = System.currentTimeMillis() - phaseStartedAt; - switch (grimPhase) { - case STOPPING -> { - movementBlocked = true; - releaseMovementKeys(); - if (isPlayerStopped() || elapsed >= STOP_TIMEOUT_MS) { - grimPhase = heldPackets.isEmpty() ? GrimPhase.CLOSING : GrimPhase.FLUSHING; - phaseStartedAt = System.currentTimeMillis(); - } - } - case FLUSHING -> { - movementBlocked = true; - releaseMovementKeys(); - flushHeldPackets(); - grimPhase = GrimPhase.CLOSING; - phaseStartedAt = System.currentTimeMillis(); - } - case CLOSING -> { - movementBlocked = true; - releaseMovementKeys(); - closeInventoryNow(); - grimPhase = GrimPhase.RESUMING; - phaseStartedAt = System.currentTimeMillis(); - } - case RESUMING -> { - movementBlocked = false; - syncMovementKeysFromPhysical(); - if (elapsed >= RESUME_DELAY_MS) { - resetGrimState(); - if (shouldManageCurrentHandledScreen()) { - grimPhase = GrimPhase.ACTIVE; - } else { - applyMovementForCurrentScreen(isMovementAllowed(ClientScreen.current())); - } - } - } - default -> { - } - } - } - - private boolean requestClose(int syncId) { - if (!shouldManageCurrentHandledScreen()) return false; - if (syncId < 0) return false; - if (heldPackets.isEmpty() && !hasGrimInventoryMovementRisk()) return false; - if (grimPhase != GrimPhase.ACTIVE && grimPhase != GrimPhase.IDLE) return true; - - pendingCloseSyncId = syncId; - movementBlocked = hasGrimInventoryMovementRisk(); - grimPhase = movementBlocked ? GrimPhase.STOPPING : (heldPackets.isEmpty() ? GrimPhase.CLOSING : GrimPhase.FLUSHING); - phaseStartedAt = System.currentTimeMillis(); - return true; - } - - private void flushHeldPackets() { - if (heldPackets.isEmpty() || mc.getConnection() == null) return; - flushingPackets = true; - try { - for (ServerboundContainerClickPacket packet : heldPackets) { - mc.getConnection().send(packet); - } - } finally { - heldPackets.clear(); - flushingPackets = false; - } - } - - private void closeInventoryNow() { - if (mc.player == null || mc.getConnection() == null) return; - if (pendingCloseSyncId >= 0) { - allowClosePacket = true; - try { - mc.getConnection().send(new ServerboundContainerClosePacket(pendingCloseSyncId)); - } finally { - allowClosePacket = false; - } - } - mc.player.clientSideCloseContainer(); - pendingCloseSyncId = -1; - } - - private boolean shouldBufferClickPacket(ServerboundContainerClickPacket packet) { - return shouldManageCurrentHandledScreen() - && packet.containerId() == syncId(ClientScreen.current()) - && (!heldPackets.isEmpty() || hasGrimInventoryMovementRisk() || grimPhase == GrimPhase.STOPPING); - } - - private boolean shouldManageCurrentHandledScreen() { - return syncId(ClientScreen.current()) >= 0 && isMovementAllowed(ClientScreen.current()); - } - - private boolean isMovementAllowed(Screen screen) { - if (screen == null || mc.player == null) return false; - if (isClickGuiTextInputActive(screen)) return false; - if (textFieldDisablesMovement.get() && hasActiveTextField(screen)) return false; - if (ScreenCatalog.matches(screen, blockedScreens.get())) return false; - if (isSafeVanillaNonInventoryScreen(screen)) return true; - return ScreenCatalog.matches(screen, allowedScreens.get()); - } - - private boolean isSafeVanillaNonInventoryScreen(Screen screen) { - if (screen == null || screen instanceof AbstractContainerScreen) return false; - - String name = screen.getClass().getName(); - return name.startsWith("net.minecraft.client.gui.screen."); - } - - private boolean isClickGuiTextInputActive(Screen screen) { - if (!(screen instanceof ClickGuiScreen - || screen instanceof ClickGuiEditorScreen - || screen instanceof ClickGuiPickerScreen)) { - return false; - } - return ClickGuiRenderer.isBlockingModuleKeybinds() || RelationsComponent.isMovementInputBlocked(); - } - - private boolean hasActiveTextField(Screen screen) { - if (screen == null) return false; - return screen.getFocused() instanceof EditBox field && field.canConsumeInput(); - } - - private int syncId(Screen screen) { - if (!(screen instanceof AbstractContainerScreen handled)) return -1; - return handled.getMenu().containerId; - } - - private boolean isPlayerStopped() { - if (mc.player == null) return true; - return Math.abs(mc.player.getDeltaMovement().x) < STOP_VELOCITY - && Math.abs(mc.player.getDeltaMovement().z) < STOP_VELOCITY; - } - - private void resetGrimState() { - heldPackets.clear(); - grimPhase = GrimPhase.IDLE; - phaseStartedAt = 0L; - pendingCloseSyncId = -1; - flushingPackets = false; - allowClosePacket = false; - movementBlocked = false; - } - - private void applyMovementForCurrentScreen(boolean canMove) { - if (ClientScreen.current() == null) return; - if (canMove) { - syncMovementKeysFromPhysical(); - } else { - releaseMovementKeys(); - } - } - - private void syncMovementKeysFromPhysical() { - if (mc.player == null || mc.getWindow() == null) return; - syncKey(mc.options.keyUp, true); - syncKey(mc.options.keyDown, true); - syncKey(mc.options.keyLeft, true); - syncKey(mc.options.keyRight, true); - syncKey(mc.options.keyJump, movementToggles.get(TOGGLE_JUMP)); - syncKey(mc.options.keyShift, movementToggles.get(TOGGLE_SNEAK)); - syncKey(mc.options.keySprint, movementToggles.get(TOGGLE_SPRINT)); - } - - private void releaseMovementKeys() { - mc.options.keyUp.setDown(false); - mc.options.keyDown.setDown(false); - mc.options.keyLeft.setDown(false); - mc.options.keyRight.setDown(false); - mc.options.keyJump.setDown(false); - mc.options.keyShift.setDown(false); - mc.options.keySprint.setDown(false); - } - - private void syncKey(KeyMapping key, boolean allowed) { - key.setDown(allowed && isPhysicallyPressed(key)); - } - - private boolean isPhysicallyPressed(KeyMapping key) { - InputConstants.Key boundKey = InputConstants.getKey(key.saveString()); - return InputConstants.isKeyDown(mc.getWindow(), boundKey.getValue()); - } - - private boolean hasPhysicalMovementInput() { - return mc.getWindow() != null - && (isPhysicallyPressed(mc.options.keyUp) - || isPhysicallyPressed(mc.options.keyDown) - || isPhysicallyPressed(mc.options.keyLeft) - || isPhysicallyPressed(mc.options.keyRight) - || (movementToggles.get(TOGGLE_JUMP) && isPhysicallyPressed(mc.options.keyJump)) - || (movementToggles.get(TOGGLE_SNEAK) && isPhysicallyPressed(mc.options.keyShift))); - } - - private boolean hasGrimInventoryMovementRisk() { - if (mc.player == null) return false; - if (mc.player.isSprinting() && (!mc.player.isSwimming() || mc.player.onGround())) return true; - if (hasPhysicalGrimMovingInput()) return true; - if (mc.player.input == null || mc.player.input.keyPresses == null) return false; - - Input input = mc.player.input.keyPresses; - return input.forward() || input.backward() || input.left() || input.right() || input.jump(); - } - - private boolean hasPhysicalGrimMovingInput() { - return mc.getWindow() != null - && (isPhysicallyPressed(mc.options.keyUp) - || isPhysicallyPressed(mc.options.keyDown) - || isPhysicallyPressed(mc.options.keyLeft) - || isPhysicallyPressed(mc.options.keyRight) - || (movementToggles.get(TOGGLE_JUMP) && isPhysicallyPressed(mc.options.keyJump))); - } - - public enum Mode { - NORMAL, - GRIM - } - - private enum GrimPhase { - IDLE, - ACTIVE, - STOPPING, - FLUSHING, - CLOSING, - RESUMING - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoFall.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoFall.java deleted file mode 100644 index 04e51c8..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoFall.java +++ /dev/null @@ -1,717 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; -import net.minecraft.network.protocol.game.ServerboundUseItemPacket; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.GameTickEvent; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.events.impl.PacketEvent; -import dev.loki.lovisual.events.impl.RotationUpdateEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.mixins.accessors.PlayerInventoryAccessor; -import dev.loki.lovisual.mixins.accessors.ServerboundMovePlayerPacketAccessor; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.block.scaffold.ScaffoldFacePositionFactory; -import dev.loki.lovisual.util.block.scaffold.ScaffoldPlacementTarget; -import dev.loki.lovisual.util.block.scaffold.ScaffoldTargetFinder; -import dev.loki.lovisual.util.player.InteractionUtil; -import dev.loki.lovisual.util.player.inventory.InventorySwap; -import dev.loki.lovisual.util.player.simulation.PlayerSimulationCache; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -//todo Description -@ModuleInfo( - id = "nofall", - displayName = "NoFall", - category = ModuleCategory.MOVEMENT -) -public class NoFall extends Module { - - private static final int MLG_COLLISION_PREDICTION_TICKS = 20; - private static final int MLG_SCAFFOLDING_SNEAK_TICKS = 3; - private static final int MLG_HOTBAR_RESET_TICKS = 1; - private static final long MLG_PICKUP_WATER_MIN_DELAY_MS = 200L; - private static final long MLG_PICKUP_WATER_MAX_DELAY_MS = 1000L; - private static final Set NETHER_MLG_ITEMS = Set.of( - Items.SCAFFOLDING, - Items.COBWEB, - Items.POWDER_SNOW_BUCKET, - Items.HAY_BLOCK, - Items.SLIME_BLOCK, - Items.HONEY_BLOCK, - Items.TWISTING_VINES - ); - private static final Set NORMAL_MLG_ITEMS; - - static { - java.util.LinkedHashSet items = new java.util.LinkedHashSet<>(NETHER_MLG_ITEMS); - items.add(Items.WATER_BUCKET); - NORMAL_MLG_ITEMS = Set.copyOf(items); - } - - private final EnumValue mode = - enumSetting("mode", "mode", Mode.GROUD_SPOOF, Mode.values()); - private final NumberValue packetJumpFallDistance = - visibleWhen(num("packet_jump_fall_distance", 3.0f, 0.0f, 20.0f), () -> mode.get() == Mode.PACKET_JUMP); - private final EnumValue packetJumpTiming = - visibleWhen(enumSetting("packet_jump_timing", "packet_jump_timing", PacketJumpTiming.LANDING, PacketJumpTiming.values()), - () -> mode.get() == Mode.PACKET_JUMP); - private final BooleanValue packetJumpResetFallDistance = - visibleWhen(bool("packet_jump_reset_fall_distance", true), - () -> mode.get() == Mode.PACKET_JUMP && packetJumpTiming.get() == PacketJumpTiming.FALLING); - private final NumberValue vulcanFallDistance = - visibleWhen(num("vulcan_fall_distance", 7.0f, 3.0f, 40.0f), () -> mode.get() == Mode.VULCAN); - private final NumberValue mlgMinFallDistance = - visibleWhen(num("mlg_min_fall_distance", 4.0f, 3.0f, 50.0f), () -> mode.get() == Mode.MLG); - private final BooleanValue mlgNoRotations = - visibleWhen(bool("mlg_no_rotations", false), () -> mode.get() == Mode.MLG); - private final List lastWaterPlacements = new ArrayList<>(); - private boolean packetJumpFalling; - private boolean packetJumpInternalSend; - private int lastPacketJumpTick = Integer.MIN_VALUE; - private double lastMoveX = Double.NaN; - private double lastMoveY = Double.NaN; - private double lastMoveZ = Double.NaN; - private MlgPlan currentMlgPlan; - private int mlgSneakTicks; - - { - setDefaultBind("GRAVE_ACCENT"); - } - - @Override - public void onEnable() { - resetState(); - } - - @Override - public void onDisable() { - resetState(); - } - - @EventHandler - private void onGameTick(GameTickEvent event) { - Minecraft client = Minecraft.getInstance(); - if (client == null || client.player == null || client.getConnection() == null) return; - - LocalPlayer player = client.player; - if (mode.get() == Mode.MLG) { - tickMlg(client, player); - return; - } - - if (player.onGround()) { - packetJumpFalling = false; - } - if (player.isShiftKeyDown()) return; - - switch (mode.get()) { - case GROUD_SPOOF -> { - if (isDangerousFall(player)) { - client.getConnection().send( - new ServerboundMovePlayerPacket.StatusOnly(true, player.horizontalCollision) - ); - } - } - case PACKET_JUMP -> { - packetJumpFalling = !player.onGround() && player.fallDistance > packetJumpFallDistance.get(); - if (packetJumpTiming.get() == PacketJumpTiming.FALLING - && packetJumpFalling - && player.tickCount != lastPacketJumpTick) { - sendPacketJumpSpoof(client, player, player.getX(), player.getY() + 1.0E-9, player.getZ()); - lastPacketJumpTick = player.tickCount; - if (packetJumpResetFallDistance.get()) { - player.fallDistance = 0.0f; - } - } - } - default -> { - } - } - } - - @EventHandler - private void onRotationUpdate(RotationUpdateEvent event) { - if (event.getType() != RotationUpdateEvent.Type.PRE) { - return; - } - - if (mode.get() != Mode.MLG) { - currentMlgPlan = null; - return; - } - - Minecraft client = Minecraft.getInstance(); - if (client == null || client.player == null || client.gameMode == null) { - currentMlgPlan = null; - return; - } - - currentMlgPlan = getCurrentGoal(client.player); - if (currentMlgPlan == null || mlgNoRotations.get()) { - return; - } - - RotationTarget target = new RotationTarget( - currentMlgPlan.rotation(), - client.player, - List.of(), - 1, - 4.0f, - false, - MovementCorrection.SILENT, - null - ); - RotationManager.INSTANCE.setRotationTarget(target, 100, this); - } - - @EventHandler - private void onMovementInput(MovementInputEvent event) { - if (mode.get() != Mode.MLG || mlgSneakTicks <= 0) { - return; - } - - mlgSneakTicks--; - event.setSneak(true); - } - - @EventHandler - private void onPacketSend(PacketEvent.Send event) { - if (packetJumpInternalSend) return; - if (!(event.getPacket() instanceof ServerboundMovePlayerPacket packet)) return; - - Minecraft client = Minecraft.getInstance(); - if (client == null || client.player == null) return; - - LocalPlayer player = client.player; - if (player.isShiftKeyDown()) { - rememberMovePacket(packet, player); - return; - } - - switch (mode.get()) { - case PACKET_JUMP -> { - packetJumpFalling = !player.onGround() && player.fallDistance > packetJumpFallDistance.get(); - if (packetJumpTiming.get() == PacketJumpTiming.LANDING - && packet.isOnGround() - && packetJumpFalling) { - packetJumpFalling = false; - sendPacketJumpSpoof( - client, - player, - resolveTracked(lastMoveX, player.getX()), - resolveTracked(lastMoveY, player.getY()) + 1.0E-9, - resolveTracked(lastMoveZ, player.getZ()) - ); - } - } - case VULCAN -> { - if (player.fallDistance > vulcanFallDistance.get()) { - ((ServerboundMovePlayerPacketAccessor) packet).combatant$setOnGround(true); - player.fallDistance = 0.0f; - player.setDeltaMovement(player.getDeltaMovement().x, 0.0, player.getDeltaMovement().z); - } - } - case NO_GROUND -> ((ServerboundMovePlayerPacketAccessor) packet).combatant$setOnGround(false); - default -> { - } - } - - rememberMovePacket(packet, player); - } - - private boolean isDangerousFall(LocalPlayer player) { - return player != null - && player.getDeltaMovement().y < -0.5 - && player.fallDistance > 2.0f; - } - - private void sendPacketJumpSpoof(Minecraft client, LocalPlayer player, double x, double y, double z) { - if (client.getConnection() == null || player == null) return; - - packetJumpInternalSend = true; - try { - client.getConnection().send(new ServerboundMovePlayerPacket.Pos( - x, - y, - z, - false, - player.horizontalCollision - )); - } finally { - packetJumpInternalSend = false; - } - } - - private void rememberMovePacket(ServerboundMovePlayerPacket packet, LocalPlayer player) { - lastMoveX = packet.getX(player.getX()); - lastMoveY = packet.getY(player.getY()); - lastMoveZ = packet.getZ(player.getZ()); - } - - private double resolveTracked(double value, double fallback) { - return Double.isNaN(value) ? fallback : value; - } - - private void resetState() { - packetJumpFalling = false; - packetJumpInternalSend = false; - lastPacketJumpTick = Integer.MIN_VALUE; - lastMoveX = Double.NaN; - lastMoveY = Double.NaN; - lastMoveZ = Double.NaN; - currentMlgPlan = null; - mlgSneakTicks = 0; - lastWaterPlacements.clear(); - InventorySwap.INSTANCE.releaseHotbar(this); - } - - private void tickMlg(Minecraft client, LocalPlayer player) { - if (player == null || client.gameMode == null) { - currentMlgPlan = null; - return; - } - - MlgPlan plan = currentMlgPlan; - if (plan == null) { - return; - } - - if (plan.type() == MlgPlanType.PLACE - && (player.onGround() - || player.isInWater() - || player.isInLava() - || player.onClimbable() - || player.getAbilities().flying)) { - currentMlgPlan = null; - return; - } - - BlockHitResult hitResult; - Rotation useRotation; - if (mlgNoRotations.get()) { - if (plan.type() == MlgPlanType.PICKUP_WATER) { - Rotation playerRotation = new Rotation(player.getYRot(), player.getXRot(), true).normalize(); - hitResult = traceTarget(player, playerRotation, ClipContext.Fluid.SOURCE_ONLY); - if (!plan.matches(hitResult)) { - return; - } - useRotation = playerRotation; - } else { - hitResult = plan.target().toHitResult(); - useRotation = plan.rotation(); - } - } else { - Rotation currentRotation = RotationManager.INSTANCE.getCurrentRotation(); - if (currentRotation == null) { - return; - } - - hitResult = traceTarget( - player, - currentRotation, - plan.type() == MlgPlanType.PICKUP_WATER ? ClipContext.Fluid.SOURCE_ONLY : ClipContext.Fluid.NONE - ); - if (!plan.matches(hitResult)) { - return; - } - useRotation = currentRotation; - } - - executeMlgPlacement(player, plan, hitResult, useRotation); - currentMlgPlan = null; - } - - private MlgPlan getCurrentGoal(LocalPlayer player) { - MlgPlan placement = getCurrentMlgPlacementPlan(player); - if (placement != null) { - return placement; - } - return getCurrentPickupPlan(player); - } - - private MlgPlan getCurrentMlgPlacementPlan(LocalPlayer player) { - if (player == null || player.fallDistance <= mlgMinFallDistance.get()) { - return null; - } - - MlgSource source = findClosestMlgSource(player); - if (source == null) { - return null; - } - - BlockPos collision = findMlgCollision(player); - if (collision == null || isFallDamageBlocking(collision)) { - return null; - } - - BlockPos targetPos = collision.above(); - ScaffoldPlacementTarget target = ScaffoldTargetFinder.findTarget( - player, - targetPos, - source.stack(), - List.of(BlockPos.ZERO), - null, - false, - new ScaffoldFacePositionFactory( - player, - player.getEyePosition(), - ScaffoldFacePositionFactory.Mode.CENTER, - null, - 0.0 - ), - player.getEyePosition() - ); - if (target == null) { - return null; - } - if (!isWithinMlgBlockRange(player, target.getHitVec())) { - return null; - } - - return new MlgPlan(MlgPlanType.PLACE, targetPos, target, target.getRotation(), source.hand(), source.hotbarSlot(), source.item()); - } - - private MlgPlan getCurrentPickupPlan(LocalPlayer player) { - if (player == null) { - return null; - } - - MlgSource source = findClosestSpecificItemSource(player, Items.BUCKET); - if (source == null) { - return null; - } - - Minecraft client = Minecraft.getInstance(); - if (client == null || client.level == null) { - return null; - } - - long now = System.currentTimeMillis(); - lastWaterPlacements.removeIf(placement -> - now - placement.timeMs() > MLG_PICKUP_WATER_MAX_DELAY_MS - || !client.level.getBlockState(placement.pos()).is(Blocks.WATER)); - - for (PlacedWater placement : lastWaterPlacements) { - if (now - placement.timeMs() < MLG_PICKUP_WATER_MIN_DELAY_MS) { - continue; - } - - Vec3 hitVec = Vec3.atCenterOf(placement.pos()).add(0.0, 0.45, 0.0); - Rotation rotation = Rotation.lookingAt(hitVec, player.getEyePosition()).normalize(); - if (!isWithinMlgBlockRange(player, hitVec)) { - continue; - } - - return new MlgPlan(MlgPlanType.PICKUP_WATER, placement.pos(), null, rotation, source.hand(), source.hotbarSlot(), source.item()); - } - - return null; - } - - private MlgSource findClosestMlgSource(LocalPlayer player) { - if (player == null) { - return null; - } - - Set allowedItems = player.level().dimension() == Level.NETHER - ? NETHER_MLG_ITEMS - : NORMAL_MLG_ITEMS; - ItemStack offhand = player.getOffhandItem(); - if (isAllowedMlgItem(offhand, allowedItems)) { - return new MlgSource(InteractionHand.OFF_HAND, -1, offhand, offhand.getItem()); - } - - int selectedSlot = ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); - int bestSlot = -1; - int bestDistance = Integer.MAX_VALUE; - ItemStack bestStack = ItemStack.EMPTY; - - for (int slot = 0; slot < 9; slot++) { - ItemStack stack = player.getInventory().getItem(slot); - if (!isAllowedMlgItem(stack, allowedItems)) { - continue; - } - - int distance = hotbarDistance(selectedSlot, slot); - if (distance < bestDistance) { - bestDistance = distance; - bestSlot = slot; - bestStack = stack; - } - } - - if (bestSlot == -1) { - return null; - } - - return new MlgSource(InteractionHand.MAIN_HAND, bestSlot, bestStack, bestStack.getItem()); - } - - private MlgSource findClosestSpecificItemSource(LocalPlayer player, Item item) { - if (player == null || item == null) { - return null; - } - - ItemStack offhand = player.getOffhandItem(); - if (!offhand.isEmpty() && offhand.is(item)) { - return new MlgSource(InteractionHand.OFF_HAND, -1, offhand, item); - } - - int selectedSlot = ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); - int bestSlot = -1; - int bestDistance = Integer.MAX_VALUE; - ItemStack bestStack = ItemStack.EMPTY; - - for (int slot = 0; slot < 9; slot++) { - ItemStack stack = player.getInventory().getItem(slot); - if (!stack.is(item)) { - continue; - } - - int distance = hotbarDistance(selectedSlot, slot); - if (distance < bestDistance) { - bestDistance = distance; - bestSlot = slot; - bestStack = stack; - } - } - - if (bestSlot == -1) { - return null; - } - - return new MlgSource(InteractionHand.MAIN_HAND, bestSlot, bestStack, item); - } - - private boolean isAllowedMlgItem(ItemStack stack, Set allowedItems) { - return stack != null && !stack.isEmpty() && allowedItems.contains(stack.getItem()); - } - - private int hotbarDistance(int from, int to) { - int diff = Math.abs(from - to); - return Math.min(diff, 9 - diff); - } - - private BlockPos findMlgCollision(LocalPlayer player) { - PlayerSimulationCache.SimulatedPlayerCache simulation = PlayerSimulationCache.getSimulationForLocalPlayer(); - if (simulation == null) { - return null; - } - - for (int tick = 1; tick <= MLG_COLLISION_PREDICTION_TICKS; tick++) { - PlayerSimulationCache.SimulatedPlayerSnapshot snapshot = simulation.getSnapshotAt(tick); - if (!snapshot.onGround()) { - continue; - } - - Vec3 pos = snapshot.pos(); - return BlockPos.containing(pos.x, pos.y - 0.2, pos.z); - } - - return null; - } - - private boolean isFallDamageBlocking(BlockPos pos) { - if (pos == null) { - return false; - } - - Minecraft client = Minecraft.getInstance(); - if (client == null || client.level == null) { - return false; - } - - var state = client.level.getBlockState(pos); - return state.is(Blocks.WATER) - || state.is(Blocks.COBWEB) - || state.is(Blocks.POWDER_SNOW) - || state.is(Blocks.HAY_BLOCK) - || state.is(Blocks.SLIME_BLOCK); - } - - private BlockHitResult traceTarget(LocalPlayer player, Rotation rotation, ClipContext.Fluid fluidHandling) { - if (player == null || rotation == null || player.level() == null) { - return null; - } - - double range = getMlgBlockRange(player); - Vec3 eyes = player.getEyePosition(); - Vec3 end = eyes.add(rotation.directionVector().scale(range)); - HitResult hitResult = player.level().clip(new ClipContext( - eyes, - end, - ClipContext.Block.OUTLINE, - fluidHandling, - player - )); - return hitResult instanceof BlockHitResult blockHitResult ? blockHitResult : null; - } - - private void executeMlgPlacement(LocalPlayer player, MlgPlan plan, BlockHitResult hitResult, Rotation useRotation) { - Minecraft client = Minecraft.getInstance(); - if (client == null || client.gameMode == null || player == null || plan == null || hitResult == null || useRotation == null) { - return; - } - if (!canReachMlgTarget(player, plan, hitResult)) { - return; - } - - if (plan.hotbarSlot() >= 0) { - InventorySwap.INSTANCE.leaseHotbar(this, plan.hotbarSlot(), MLG_HOTBAR_RESET_TICKS); - } - - boolean success; - if (plan.type() == MlgPlanType.PICKUP_WATER) { - InteractionResult useResult = interactItemWithRotation(player, plan.hand(), useRotation); - success = useResult != null && useResult.consumesAction(); - } else { - InteractionResult result = client.gameMode.useItemOn(player, plan.hand(), hitResult); - success = result != null && result.consumesAction(); - - if (!success && result == InteractionResult.PASS) { - InteractionResult useResult = interactItemWithRotation(player, plan.hand(), useRotation); - success = useResult != null && useResult.consumesAction(); - } - } - - if (success) { - player.swing(plan.hand()); - if (plan.item() == Items.SCAFFOLDING) { - mlgSneakTicks = MLG_SCAFFOLDING_SNEAK_TICKS; - } - if (plan.type() == MlgPlanType.PLACE && plan.item() == Items.WATER_BUCKET) { - lastWaterPlacements.add(new PlacedWater(plan.targetPos(), System.currentTimeMillis())); - } else if (plan.type() == MlgPlanType.PICKUP_WATER && plan.item() == Items.BUCKET) { - lastWaterPlacements.removeIf(placement -> placement.pos().equals(plan.targetPos())); - } - } - } - - private boolean canReachMlgTarget(LocalPlayer player, MlgPlan plan, BlockHitResult hitResult) { - if (player == null || plan == null || hitResult == null) { - return false; - } - if (!plan.matches(hitResult)) { - return false; - } - - return isWithinMlgBlockRange(player, hitResult.getLocation()); - } - - private boolean isWithinMlgBlockRange(LocalPlayer player, Vec3 point) { - if (player == null || point == null) { - return false; - } - double range = getMlgBlockRange(player); - return player.getEyePosition().distanceToSqr(point) <= range * range; - } - - private double getMlgBlockRange(LocalPlayer player) { - return player != null ? player.blockInteractionRange() : 0.0; - } - - private InteractionResult interactItemWithRotation(LocalPlayer player, InteractionHand hand, Rotation rotation) { - Minecraft client = Minecraft.getInstance(); - if (client == null || client.gameMode == null || player == null || rotation == null) { - return InteractionResult.FAIL; - } - Rotation normalized = rotation.normalize(); - ItemStack stack = player.getItemInHand(hand); - if (stack.isEmpty() || player.getCooldowns().isOnCooldown(stack)) { - return InteractionResult.PASS; - } - - final InteractionResult[] resultHolder = {InteractionResult.PASS}; - InteractionUtil.sendSequencedPacket(id -> - new ServerboundUseItemPacket(hand, id, normalized.yaw(), normalized.pitch())); - - InteractionResult result = stack.use(client.level, player, hand); - if (result instanceof InteractionResult.Success success) { - ItemStack newStack = Objects.requireNonNullElseGet(success.heldItemTransformedTo(), () -> player.getItemInHand(hand)); - if (newStack != stack) { - player.setItemInHand(hand, newStack); - } - } - resultHolder[0] = result; - return resultHolder[0]; - } - - public enum Mode { - GROUD_SPOOF, - PACKET_JUMP, - VULCAN, - NO_GROUND, - MLG - } - - public enum PacketJumpTiming { - LANDING, - FALLING - } - - private enum MlgPlanType { - PLACE, - PICKUP_WATER - } - - private record MlgSource(InteractionHand hand, int hotbarSlot, ItemStack stack, Item item) { - } - - private record MlgPlan( - MlgPlanType type, - BlockPos targetPos, - ScaffoldPlacementTarget target, - Rotation rotation, - InteractionHand hand, - int hotbarSlot, - Item item - ) { - private boolean matches(BlockHitResult hitResult) { - if (hitResult == null) { - return false; - } - - return switch (type) { - case PLACE -> target != null && target.matches(hitResult); - case PICKUP_WATER -> targetPos.equals(hitResult.getBlockPos()); - }; - } - } - - private record PlacedWater(BlockPos pos, long timeMs) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoPush.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoPush.java deleted file mode 100644 index fa707ab..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoPush.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; -import net.minecraft.world.entity.projectile.FishingHook; -import dev.loki.lovisual.config.values.BooleanMapValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.EventPushOutOfBlocks; -import dev.loki.lovisual.events.impl.PacketEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; - -import java.util.LinkedHashMap; - -//todo Description -@ModuleInfo( - id = "nopush", - displayName = "NoPush", - category = ModuleCategory.MOVEMENT -) -public class NoPush extends Module { - - private static final String SETTING_TOGGLES = "toggles"; - private final BooleanMapValue toggles = group( - "nopush_toggles", - SETTING_TOGGLES, - new LinkedHashMap<>() {{ - put("players", true); // толкание другими энтити - put("blocks", true); - put("liquids", true); - put("fishing_hook", true); // выталкивание из блоков - put("pearl_phase", true); // спуф позы после жемчуга - }} - ); - - public boolean off(String key) { - return isEnabled() && toggles.get(key); - } - - public boolean blocksEnabled() { - return off("blocks"); - } - - public boolean playersEnabled() { - return off("players"); - } - - public boolean liquidsEnabled() { - return off("liquids"); - } - - public boolean fishingHookEnabled() { - return off("fishing_hook"); - } - - @EventHandler - public void onPushOutOfBlocks(EventPushOutOfBlocks e) { - if (!blocksEnabled()) return; - e.cancel(); - } - - @EventHandler - public void onPacketReceive(PacketEvent.Receive e) { - if (!fishingHookEnabled()) return; - if (!(e.getPacket() instanceof ClientboundEntityEventPacket pac)) return; - if (pac.getEventId() != 31) return; - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.level == null || mc.player == null) return; - if (pac.getEntity(mc.level) instanceof FishingHook hook && hook.getHookedIn() == mc.player) { - e.cancel(); - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoStun.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoStun.java deleted file mode 100644 index cf9631f..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/NoStun.java +++ /dev/null @@ -1,570 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.resources.Identifier; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.ai.attributes.AttributeInstance; -import net.minecraft.world.entity.ai.attributes.AttributeModifier; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanMapValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.EventCollision; -import dev.loki.lovisual.events.impl.GameTickEvent; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.events.impl.PlayerJumpEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; - -import java.util.LinkedHashMap; -import java.util.Map; - -//todo Description -@ModuleInfo( - id = "nostun", - displayName = "NoStun", - category = ModuleCategory.MOVEMENT -) -public class NoStun extends Module { - - private static final float DEFAULT_SLIPPERINESS = 0.6F; - private static final float DEFAULT_VELOCITY_MULTIPLIER = 1.0F; - private static final double VULCAN_297_WEB_BUFFER_MAX = 7.0; - private static final double VULCAN_297_WEB_BUFFER_DECAY = 0.15; - private static final double VULCAN_297_WEB_FULL_COST = 1.0; - private static final double VULCAN_297_SPEED_E_BUFFER_MAX = 2.0; - private static final double VULCAN_297_SPEED_E_BUFFER_DECAY = 0.025; - private static final int VULCAN_297_SLOWNESS_JUMP_WINDOW_TICKS = 5; - private static final double VULCAN_297_SLOWNESS_EXEMPT_RATIO = 1.0; - private static final Identifier SLOWNESS_MOVEMENT_SPEED_MODIFIER_ID = Identifier.withDefaultNamespace("effect.slowness"); - private static final String SETTING_MODE = "mode"; - private static final String SETTING_FUNCTIONS = "functions"; - private static final String SETTING_ENV_BLOCKS = "env_blocks"; - private static final String SETTING_DEBUFFS = "debuffs"; - private static final String SETTING_EAT_SPEED = "eat_speed"; - private static final String SETTING_VULCAN_WEB_RATIO = "vulcan297_web_ratio"; - private static final String SETTING_VULCAN_SOUL_RATIO = "vulcan297_soul_sand_ratio"; - private static final String FN_USE_SPEED = "use_speed"; - private static final String FN_ENV_BLOCKS = "env_blocks"; - private static final String FN_NO_HURT_STUN = "no_hurt_stun"; - private static final String FN_DEBUFFS = "debuffs"; - private static final String ENV_WEB = "web"; - private static final String ENV_HONEY = "honey"; - private static final String ENV_SLIME = "slime"; - private static final String ENV_SOUL = "soul_sand"; - private static final String ENV_BERRY = "sweet_berry"; - private static final String DEBUFF_SLOWNESS = "slowness"; - private static final String DEBUFF_BLINDNESS = "blindness"; - private final Minecraft mc = Minecraft.getInstance(); - //todo ну хз на прыжках еще флагует блять так что хз хз - private final EnumValue mode = - enumSetting("noStunMode", SETTING_MODE, Mode.NORMAL, Mode.values()); - private final BooleanMapValue functions = - group("noStunFunctions", SETTING_FUNCTIONS, defaultFunctions()); - private final BooleanMapValue envBlocks = - visibleWhen(group("noStunEnvBlocks", SETTING_ENV_BLOCKS, defaultEnvBlocks()), () -> functions.get(FN_ENV_BLOCKS)); - private final NumberValue vulcan297WebRatio = - visibleWhen(num("noStunVulcan297WebRatio", SETTING_VULCAN_WEB_RATIO, 0.35, 0.0, 1.0), - () -> functions.get(FN_ENV_BLOCKS) && envBlocks.get(ENV_WEB) && isVulcan297()); - private final NumberValue vulcan297SoulSandRatio = - visibleWhen(num("noStunVulcan297SoulSandRatio", SETTING_VULCAN_SOUL_RATIO, 0.35, 0.0, 1.0), - () -> functions.get(FN_ENV_BLOCKS) && envBlocks.get(ENV_SOUL) && isVulcan297()); - private final BooleanMapValue debuffs = - visibleWhen(group("noStunDebuffs", SETTING_DEBUFFS, defaultDebuffs()), () -> functions.get(FN_DEBUFFS)); - private final NumberValue eatSpeed = - visibleWhen(num("noStunEatSpeed", SETTING_EAT_SPEED, 0.0, 0.0, 1.0), () -> functions.get(FN_USE_SPEED)); - private double vulcan297WebBudget; - private int vulcan297LastWebChargeAge = -1; - private int vulcan297LastWebDecayAge = -1; - private double vulcan297SlownessSpeedEBuffer; - private int vulcan297SlownessJumpTicks; - private int vulcan297LastSlownessDecisionAge = -1; - private double vulcan297LastSlownessRatio; - - private static double blend(double ratio, double vanilla, double normalized) { - return Mth.lerp(Mth.clamp(ratio, 0.0, 1.0), vanilla, normalized); - } - - public static String fnUseSpeed() { - return FN_USE_SPEED; - } - - public static String fnEnvBlocks() { - return FN_ENV_BLOCKS; - } - - public static String fnNoHurtStun() { - return FN_NO_HURT_STUN; - } - - public static String fnDebuffs() { - return FN_DEBUFFS; - } - - public static String envWeb() { - return ENV_WEB; - } - - public static String envHoney() { - return ENV_HONEY; - } - - public static String envSlime() { - return ENV_SLIME; - } - - public static String envSoulSand() { - return ENV_SOUL; - } - - public static String envBerry() { - return ENV_BERRY; - } - - private static Map defaultFunctions() { - Map m = new LinkedHashMap<>(); - m.put(FN_USE_SPEED, true); - m.put(FN_ENV_BLOCKS, true); - m.put(FN_NO_HURT_STUN, true); - m.put(FN_DEBUFFS, true); - return m; - } - - private static Map defaultEnvBlocks() { - Map m = new LinkedHashMap<>(); - m.put(ENV_WEB, true); - m.put(ENV_HONEY, true); - m.put(ENV_SLIME, true); - m.put(ENV_BERRY, true); - m.put(ENV_SOUL, true); - return m; - } - - private static Map defaultDebuffs() { - Map m = new LinkedHashMap<>(); - m.put(DEBUFF_SLOWNESS, true); - m.put(DEBUFF_BLINDNESS, true); - return m; - } - - @EventHandler - private void onMovementInput(MovementInputEvent event) { - if (shouldBlockWebJump() && event.isJump()) { - event.setJump(false); - } - } - - @EventHandler - private void onPlayerJump(PlayerJumpEvent event) { - if (shouldBlockWebJump()) { - event.cancel(); - return; - } - - if (shouldUseVulcan297SlownessLogic(mc.player)) { - vulcan297SlownessJumpTicks = VULCAN_297_SLOWNESS_JUMP_WINDOW_TICKS; - } - } - - @EventHandler - private void onGameTick(GameTickEvent event) { - if (!isEnabled() || !isVulcan297() || mc.player == null || mc.level == null) { - resetVulcan297WebBudget(); - resetVulcan297SlownessSpeedEBuffer(); - return; - } - - if (!isInsideWeb(mc.player)) { - decayVulcan297WebBudget(); - vulcan297LastWebChargeAge = -1; - } - - if (vulcan297SlownessJumpTicks > 0) { - vulcan297SlownessJumpTicks--; - } - if (!shouldUseVulcan297SlownessLogic(mc.player)) { - resetVulcan297SlownessSpeedEBuffer(); - } - } - - @EventHandler - private void onCollision(EventCollision event) { - if (shouldMakeWebSolidWhileGliding(event.getState(), event.getPos())) { - event.setState(Blocks.BARRIER.defaultBlockState()); - } - } - - @Override - public void onDisable() { - resetVulcan297WebBudget(); - resetVulcan297SlownessSpeedEBuffer(); - } - - public boolean isFunctionEnabled(String key) { - return functions.get(key); - } - - public boolean isEnvBlockEnabled(String key) { - return envBlocks.get(key); - } - - public boolean isEnvBlocksEnabled() { - return functions.get(FN_ENV_BLOCKS); - } - - public boolean isVulcan297() { - return mode.get() == Mode.VULCAN_297; - } - - public float getEatSpeed01() { - return (float) Mth.clamp(eatSpeed.get(), 0.0, 1.0); - } - - public boolean shouldIgnoreBlindness(Player player) { - return isEnabled() && isLocalPlayer(player) && functions.get(FN_DEBUFFS) && debuffs.get(DEBUFF_BLINDNESS); - } - - public double getMovementSpeedAttributeWithoutSlowness(Player player, double original) { - if (!isEnabled() || !isLocalPlayer(player) || !functions.get(FN_DEBUFFS) || !debuffs.get(DEBUFF_SLOWNESS)) { - return original; - } - - AttributeInstance movementSpeed = player.getAttribute(Attributes.MOVEMENT_SPEED); - if (movementSpeed == null || !movementSpeed.hasModifier(SLOWNESS_MOVEMENT_SPEED_MODIFIER_ID)) { - return original; - } - - double noSlowness = computeMovementSpeedWithoutSlownessModifier(movementSpeed); - if (!isVulcan297()) { - return noSlowness; - } - - double ratio = getVulcan297SlownessRatio(player, movementSpeed); - return blend(ratio, original, noSlowness); - } - - private double computeMovementSpeedWithoutSlownessModifier(AttributeInstance movementSpeed) { - double base = movementSpeed.getBaseValue(); - double value = base; - - for (AttributeModifier modifier : movementSpeed.getModifiers()) { - if (isMovementSpeedModifier(modifier, AttributeModifier.Operation.ADD_VALUE)) { - value += modifier.amount(); - } - } - - double multipliedBase = value; - for (AttributeModifier modifier : movementSpeed.getModifiers()) { - if (isMovementSpeedModifier(modifier, AttributeModifier.Operation.ADD_MULTIPLIED_BASE)) { - multipliedBase += base * modifier.amount(); - } - } - - for (AttributeModifier modifier : movementSpeed.getModifiers()) { - if (isMovementSpeedModifier(modifier, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)) { - multipliedBase *= 1.0 + modifier.amount(); - } - } - - return Attributes.MOVEMENT_SPEED.value().sanitizeValue(multipliedBase); - } - - private boolean isMovementSpeedModifier(AttributeModifier modifier, AttributeModifier.Operation operation) { - return modifier.operation() == operation && !modifier.is(SLOWNESS_MOVEMENT_SPEED_MODIFIER_ID); - } - - private double getVulcan297SlownessRatio(Player player, AttributeInstance movementSpeed) { - int age = player.tickCount; - if (age == vulcan297LastSlownessDecisionAge) { - return vulcan297LastSlownessRatio; - } - - int slownessLevel = getSlownessLevel(movementSpeed); - double ratio; - if (isVulcan297SpeedEPredictionExempt(player)) { - ratio = VULCAN_297_SLOWNESS_EXEMPT_RATIO; - decayVulcan297SlownessSpeedEBuffer(); - } else if (shouldUseVulcan297SlownessJumpRatio(player)) { - double cost = getVulcan297SlownessJumpCost(slownessLevel); - if (canChargeVulcan297SlownessSpeedEBuffer(cost)) { - ratio = getVulcan297SlownessJumpRatio(slownessLevel); - chargeVulcan297SlownessSpeedEBuffer(cost); - } else { - ratio = getVulcan297SlownessWalkRatio(slownessLevel); - decayVulcan297SlownessSpeedEBuffer(); - } - } else { - ratio = getVulcan297SlownessWalkRatio(slownessLevel); - decayVulcan297SlownessSpeedEBuffer(); - } - - vulcan297LastSlownessDecisionAge = age; - vulcan297LastSlownessRatio = ratio; - return ratio; - } - - private int getSlownessLevel(AttributeInstance movementSpeed) { - AttributeModifier modifier = movementSpeed.getModifier(SLOWNESS_MOVEMENT_SPEED_MODIFIER_ID); - if (modifier == null) { - return 0; - } - - return Math.max(1, (int) Math.round(Math.abs(modifier.amount()) / 0.15)); - } - - private double getVulcan297SlownessWalkRatio(int slownessLevel) { - if (slownessLevel >= 6) return 0.28; - if (slownessLevel >= 4) return 0.42; - if (slownessLevel >= 2) return 0.70; - return 1.0; - } - - private double getVulcan297SlownessJumpRatio(int slownessLevel) { - if (slownessLevel >= 6) return 0.58; - if (slownessLevel >= 4) return 0.78; - return 1.0; - } - - private double getVulcan297SlownessJumpCost(int slownessLevel) { - if (slownessLevel >= 6) return 0.70; - if (slownessLevel >= 4) return 0.50; - return 0.35; - } - - private boolean shouldUseVulcan297SlownessJumpRatio(Player player) { - return player != null - && vulcan297SlownessJumpTicks > 0 - && !player.onGround() - && !player.isFallFlying() - && player.getDeltaMovement().y > -0.08; - } - - private boolean shouldUseVulcan297SlownessLogic(Player player) { - if (player == null || !isEnabled() || !isVulcan297() || !functions.get(FN_DEBUFFS) || !debuffs.get(DEBUFF_SLOWNESS)) { - return false; - } - - AttributeInstance movementSpeed = player.getAttribute(Attributes.MOVEMENT_SPEED); - return movementSpeed != null && movementSpeed.hasModifier(SLOWNESS_MOVEMENT_SPEED_MODIFIER_ID); - } - - private boolean canChargeVulcan297SlownessSpeedEBuffer(double cost) { - return vulcan297SlownessSpeedEBuffer + cost <= VULCAN_297_SPEED_E_BUFFER_MAX; - } - - private void chargeVulcan297SlownessSpeedEBuffer(double cost) { - vulcan297SlownessSpeedEBuffer = Math.min(VULCAN_297_SPEED_E_BUFFER_MAX, vulcan297SlownessSpeedEBuffer + cost); - } - - private void decayVulcan297SlownessSpeedEBuffer() { - vulcan297SlownessSpeedEBuffer = Math.max(0.0, vulcan297SlownessSpeedEBuffer - VULCAN_297_SPEED_E_BUFFER_DECAY); - } - - private void resetVulcan297SlownessSpeedEBuffer() { - vulcan297SlownessSpeedEBuffer = 0.0; - vulcan297SlownessJumpTicks = 0; - vulcan297LastSlownessDecisionAge = -1; - vulcan297LastSlownessRatio = 0.0; - } - - private boolean isVulcan297SpeedEPredictionExempt(Player player) { - if (player == null || player.level() == null) return false; - if (player.getAbilities().instabuild || player.getAbilities().flying) return true; - if (player.isFallFlying() || player.isAutoSpinAttack() || player.isPassenger() || player.isSleeping()) - return true; - - BlockPos feetPos = player.blockPosition(); - Block feet = player.level().getBlockState(feetPos).getBlock(); - Block below = player.level().getBlockState(feetPos.below()).getBlock(); - - return isVulcan297SpeedEPredictionExemptBlock(feet) - || isVulcan297SpeedEPredictionExemptBlock(below); - } - - private boolean isVulcan297SpeedEPredictionExemptBlock(Block block) { - return block == Blocks.COBWEB || block == Blocks.HONEY_BLOCK; - } - - public Vec3 getSlowMovementOverride(BlockState state, Vec3 vanillaMultiplier) { - if (!isEnabled() || state == null || vanillaMultiplier == null || !functions.get(FN_ENV_BLOCKS)) { - return null; - } - - if (state.is(Blocks.COBWEB) && envBlocks.get(ENV_WEB) && isVulcan297()) { - if (shouldUseFullVulcan297WebBypass()) { - return null; - } - - decayVulcan297WebBudget(); - double horizontal = blend(vulcan297WebRatio.get(), vanillaMultiplier.x, 1.0); - return new Vec3(horizontal, vanillaMultiplier.y, horizontal); - } - - return null; - } - - public boolean shouldCancelSlowMovement(BlockState state) { - if (!isEnabled() || state == null || !functions.get(FN_ENV_BLOCKS)) { - return false; - } - if (state.is(Blocks.COBWEB) && envBlocks.get(ENV_WEB)) { - if (!isVulcan297()) { - return true; - } - if (shouldUseFullVulcan297WebBypass()) { - chargeVulcan297WebBudget(); - return true; - } - return false; - } - return state.is(Blocks.SWEET_BERRY_BUSH) && envBlocks.get(ENV_BERRY); - } - - public Float getSlipperinessOverride(Block block, float vanilla) { - if (!isEnabled() || block == null || !functions.get(FN_ENV_BLOCKS)) { - return null; - } - - if (block == Blocks.SLIME_BLOCK && envBlocks.get(ENV_SLIME) - || block == Blocks.HONEY_BLOCK && envBlocks.get(ENV_HONEY)) { - return isVulcan297() - ? (float) blend(vulcan297SoulSandRatio.get(), vanilla, DEFAULT_SLIPPERINESS) - : DEFAULT_SLIPPERINESS; - } - - return null; - } - - public Float getVelocityMultiplierOverride(Block block, float vanilla) { - if (!isEnabled() || block == null || !functions.get(FN_ENV_BLOCKS)) { - return null; - } - - if (block == Blocks.HONEY_BLOCK && envBlocks.get(ENV_HONEY)) { - return isVulcan297() - ? (float) blend(vulcan297SoulSandRatio.get(), vanilla, DEFAULT_VELOCITY_MULTIPLIER) - : DEFAULT_VELOCITY_MULTIPLIER; - } - - if (block == Blocks.SOUL_SAND && envBlocks.get(ENV_SOUL)) { - return getSoulSandVelocityMultiplier(vanilla); - } - - return null; - } - - public float getSoulSandVelocityMultiplier(float vanilla) { - if (!isEnabled() || !functions.get(FN_ENV_BLOCKS) || !envBlocks.get(ENV_SOUL)) { - return vanilla; - } - if (isVulcan297()) { - return (float) blend(vulcan297SoulSandRatio.get(), vanilla, DEFAULT_VELOCITY_MULTIPLIER); - } - return vanilla < 1.0F ? 1.0F : vanilla; - } - - private boolean shouldBlockWebJump() { - return isEnabled() - && functions.get(FN_ENV_BLOCKS) - && envBlocks.get(ENV_WEB) - && mc.player != null - && isInsideWeb(mc.player); - } - - private boolean shouldMakeWebSolidWhileGliding(BlockState state, BlockPos pos) { - if (state == null || pos == null || !state.is(Blocks.COBWEB)) return false; - if (!isEnabled() || !isVulcan297() || !functions.get(FN_ENV_BLOCKS) || !envBlocks.get(ENV_WEB)) return false; - if (mc.player == null || mc.level == null || !mc.player.isFallFlying() || mc.player.isSpectator()) return false; - - AABB movementBox = mc.player.getBoundingBox() - .expandTowards(mc.player.getDeltaMovement()) - .inflate(0.2); - return movementBox.intersects(new AABB(pos)); - } - - private boolean isInsideWeb(LocalPlayer player) { - if (mc.level == null) return false; - - AABB box = player.getBoundingBox().deflate(1.0E-4); - int minX = Mth.floor(box.minX); - int minY = Mth.floor(box.minY); - int minZ = Mth.floor(box.minZ); - int maxX = Mth.floor(box.maxX); - int maxY = Mth.floor(box.maxY); - int maxZ = Mth.floor(box.maxZ); - - for (int x = minX; x <= maxX; x++) { - for (int y = minY; y <= maxY; y++) { - for (int z = minZ; z <= maxZ; z++) { - if (mc.level.getBlockState(new BlockPos(x, y, z)).is(Blocks.COBWEB)) { - return true; - } - } - } - } - - return false; - } - - private boolean canUseVulcan297WebBurst() { - return vulcan297WebBudget + VULCAN_297_WEB_FULL_COST <= VULCAN_297_WEB_BUFFER_MAX; - } - - private boolean shouldUseFullVulcan297WebBypass() { - return canUseVulcan297WebBurst(); - } - - private void chargeVulcan297WebBudget() { - LocalPlayer player = mc.player; - int age = player != null ? player.tickCount : -1; - if (age == vulcan297LastWebChargeAge) { - return; - } - - vulcan297WebBudget = Math.min(VULCAN_297_WEB_BUFFER_MAX, vulcan297WebBudget + VULCAN_297_WEB_FULL_COST); - vulcan297LastWebChargeAge = age; - } - - private void decayVulcan297WebBudget() { - LocalPlayer player = mc.player; - int age = player != null ? player.tickCount : -1; - if (age == vulcan297LastWebDecayAge) { - return; - } - - vulcan297WebBudget = Math.max(0.0, vulcan297WebBudget - VULCAN_297_WEB_BUFFER_DECAY); - vulcan297LastWebDecayAge = age; - } - - private void resetVulcan297WebBudget() { - vulcan297WebBudget = 0.0; - vulcan297LastWebChargeAge = -1; - vulcan297LastWebDecayAge = -1; - } - - private boolean isLocalPlayer(Player player) { - return player != null && mc != null && player == mc.player; - } - - public enum Mode { - NORMAL, - VULCAN_297 - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Parkour.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Parkour.java deleted file mode 100644 index 9c78c9d..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Parkour.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; - -//todo Description -@ModuleInfo( - id = "parkour", - displayName = "Parkour", - category = ModuleCategory.MOVEMENT -) -public final class Parkour extends Module { - - private final Minecraft mc = Minecraft.getInstance(); - - private final NumberValue jumpFactor = num("jump_factor", 0.01f, 0.001f, 0.3f); - - @EventHandler - private void onMovementInput(MovementInputEvent event) { - if (!isEnabled() || mc.player == null || mc.level == null) { - return; - } - - if (!mc.player.onGround()) { - return; - } - if (event.isJump()) { - return; - } - if (event.isSneak()) { - return; - } - if (!event.isForward() && !event.isBackward() && !event.isLeft() && !event.isRight()) { - return; - } - - boolean hasGroundBelow = mc.level.getBlockCollisions( - mc.player, - mc.player.getBoundingBox() - .inflate(-jumpFactor.get(), 0.0, -jumpFactor.get()) - .move(0.0, -0.99, 0.0) - ).iterator().hasNext(); - - if (!hasGroundBelow && mc.player.getDeltaMovement().y <= 0.0) { - event.setJump(true); - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Phase.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Phase.java deleted file mode 100644 index 9bb5645..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Phase.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * Portions derived from ThunderHack Recode, copyright (c) 2023-2024 Pan4ur & 06ED. - * Upstream: https://github.com/Pan4ur/ThunderHack-Recode - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.*; -import net.minecraft.resources.ResourceKey; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.item.enchantment.Enchantments; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.EventBreakBlock; -import dev.loki.lovisual.events.impl.EventCollision; -import dev.loki.lovisual.events.impl.EventPostSync; -import dev.loki.lovisual.events.impl.EventSync; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.mixins.accessors.PlayerInventoryAccessor; -import dev.loki.lovisual.util.player.InteractionUtil; -import dev.loki.lovisual.util.player.MovementUtil; -import dev.loki.lovisual.util.player.inventory.InventorySwap; - -@Deprecated -//todo Description -//работает только на ванилах без ач -@ModuleInfo( - id = "phase", - displayName = "Phase", - category = ModuleCategory.MOVEMENT -) -public class Phase extends Module { - - private final EnumValue mode = - enumSetting("mode", "mode", Mode.VANILLA, Mode.values()); - private final BooleanValue silent = - visibleWhen(bool("silent", false), () -> mode.get() == Mode.BREAK_ASSIST); - private final BooleanValue waitBreak = - visibleWhen(bool("wait_break", true), () -> mode.get() == Mode.BREAK_ASSIST); - private final NumberValue afterBreak = - visibleWhen(num("break_timeout", 4, 1, 20), () -> mode.get() == Mode.BREAK_ASSIST && waitBreak.get()); - private final BooleanValue onlyOnGround = - visibleWhen(bool("only_on_ground", false), () -> mode.get() == Mode.PEARL); - private final BooleanValue autoDisable = - visibleWhen(bool("auto_disable", false), () -> mode.get() == Mode.PEARL); - private final NumberValue afterPearl = - visibleWhen(num("pearl_timeout", 0, 0, 60), () -> mode.get() == Mode.PEARL); - private final NumberValue pitch = - visibleWhen(num("pitch", 80f, 0f, 90f), () -> mode.get() == Mode.PEARL); - private final BooleanValue strict = - visibleWhen(bool("strict", false), () -> mode.get() == Mode.FORCE_MINE); - public int clipTimer; - public int afterPearlTime; - - @Override - public void onEnable() { - afterPearlTime = 0; - clipTimer = 0; - - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || mc.level == null) return; - - if (mc.player.onGround() && mode.get() == Mode.CC_CLIP) { - double[] diagonalOffset = MovementUtil.forwardWithoutStrafe(0.44); - boolean diagonal = mc.player.getYRot() % 90 > 35 && mc.player.getYRot() % 90 < 55; - - sendPacket(new ServerboundPlayerCommandPacket(mc.player, ServerboundPlayerCommandPacket.Action.START_SPRINTING)); - - if (diagonal) { - double[] directionVec = MovementUtil.forwardWithoutStrafe(0.51); - - int height = mc.level.clip( - new ClipContext( - mc.player.getEyePosition(), - mc.player.getEyePosition().add(diagonalOffset[0], 0, diagonalOffset[1]), - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - mc.player - ) - ).getType().equals(HitResult.Type.MISS) ? 1 : 2; - - mc.player.setPos(mc.player.getX() + directionVec[0], mc.player.getY() + height, mc.player.getZ() + directionVec[1]); - sendPacket(new ServerboundMovePlayerPacket.Pos(mc.player.getX(), mc.player.getY(), mc.player.getZ(), true, mc.player.horizontalCollision)); - - height = mc.level.isEmptyBlock(BlockPos.containing(mc.player.position().add(diagonalOffset[0], -2, diagonalOffset[1]))) ? 2 : 1; - - mc.player.setPos(mc.player.getX() + directionVec[0], mc.player.getY() - height, mc.player.getZ() + directionVec[1]); - sendPacket(new ServerboundMovePlayerPacket.Pos(mc.player.getX(), mc.player.getY(), mc.player.getZ(), true, mc.player.horizontalCollision)); - setEnabled(false); - } else { - double[] directionVec = MovementUtil.forwardWithoutStrafe(0.57); - - int height = mc.level.clip( - new ClipContext( - mc.player.getEyePosition(), - mc.player.getEyePosition().add(diagonalOffset[0], 0, diagonalOffset[1]), - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - mc.player - ) - ).getType().equals(HitResult.Type.MISS) ? 1 : 2; - - mc.player.setPos(mc.player.getX() + directionVec[0], mc.player.getY() + height, mc.player.getZ() + directionVec[1]); - sendPacket(new ServerboundMovePlayerPacket.Pos(mc.player.getX(), mc.player.getY(), mc.player.getZ(), true, mc.player.horizontalCollision)); - - mc.player.setPos(mc.player.getX() + directionVec[0], mc.player.getY(), mc.player.getZ() + directionVec[1]); - sendPacket(new ServerboundMovePlayerPacket.Pos(mc.player.getX(), mc.player.getY(), mc.player.getZ(), true, mc.player.horizontalCollision)); - - height = mc.level.isEmptyBlock(BlockPos.containing(mc.player.position().add(diagonalOffset[0], -2, diagonalOffset[1]))) ? 2 : 1; - - mc.player.setPos(mc.player.getX() + directionVec[0], mc.player.getY() - height, mc.player.getZ() + directionVec[1]); - sendPacket(new ServerboundMovePlayerPacket.Pos(mc.player.getX(), mc.player.getY(), mc.player.getZ(), true, mc.player.horizontalCollision)); - setEnabled(false); - } - } - } - - @EventHandler - public void onCollide(EventCollision e) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || mc.level == null) return; - - BlockPos playerPos = BlockPos.containing(mc.player.position()); - - if ((!isMode(Mode.CC_CLIP) && !isMode(Mode.PEARL) && !isMode(Mode.FORCE_MINE) && canNoClip()) || afterPearlTime > 0) { - if (!e.getPos().equals(playerPos.below()) || mc.options.keyShift.isDown()) { - e.setState(Blocks.AIR.defaultBlockState()); - } - } - - if (isMode(Mode.FORCE_MINE)) { - float xDelta = Math.abs(playerPos.getX() - e.getPos().getX()); - float zDelta = Math.abs(playerPos.getZ() - e.getPos().getZ()); - - if (xDelta != 0 && zDelta != 0 && strict.get()) { - return; - } - - if (!e.getPos().equals(playerPos.below()) || mc.options.keyShift.isDown()) { - e.setState(Blocks.AIR.defaultBlockState()); - } - } - } - - @EventHandler - public void onSync(EventSync e) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || mc.level == null) return; - - if (clipTimer > 0) clipTimer--; - if (afterPearlTime > 0) afterPearlTime--; - - if (isMode(Mode.BREAK_ASSIST) - && (mc.player.horizontalCollision || playerInsideBlock()) - && !mc.player.isUnderWater() - && !mc.player.isInLava() - && clipTimer <= 0) { - double[] dir = MovementUtil.forward(0.5); - - BlockPos blockToBreak = null; - - if (mc.options.keyJump.isDown()) { - blockToBreak = BlockPos.containing(mc.player.getX() + dir[0], mc.player.getY() + 2, mc.player.getZ() + dir[1]); - } else if (mc.options.keyShift.isDown()) { - blockToBreak = BlockPos.containing(mc.player.getX() + dir[0], mc.player.getY() - 1, mc.player.getZ() + dir[1]); - } else if (MovementUtil.isMoving()) { - blockToBreak = BlockPos.containing(mc.player.getX() + dir[0], mc.player.getY(), mc.player.getZ() + dir[1]); - } - - if (blockToBreak == null) return; - int bestTool = findBestTool(blockToBreak); - if (bestTool == -1) return; - - int prevItem = ((PlayerInventoryAccessor) mc.player.getInventory()).combatant$getSelectedSlot(); - InventorySwap.INSTANCE.selectHotbar(bestTool); - final BlockPos target = blockToBreak; - final Direction face = mc.player.getDirection(); - InteractionUtil.sendSequencedPacket(id -> - new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, target, face, id)); - InteractionUtil.sendSequencedPacket(id -> - new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK, target, face, id)); - mc.player.swing(InteractionHand.MAIN_HAND); - if (silent.get()) InventorySwap.INSTANCE.selectHotbar(prevItem); - } - - if (isMode(Mode.FORCE_MINE) - && (mc.player.horizontalCollision || playerInsideBlock()) - && !mc.player.isUnderWater() - && !mc.player.isInLava()) { - for (int x = -2; x < 2; x++) { - for (int y = -1; y < 3; y++) { - for (int z = -2; z < 2; z++) { - if (((x == 0 && y == 0 && z == 0) || (x == 0 && y == 1 && z == 0)) && !mc.options.keyShift.isDown()) { - continue; - } - - BlockPos bp = BlockPos.containing(mc.player.position()).offset(x, y, z); - if (mc.player.getBoundingBox().intersects(new AABB(bp)) && !mc.level.isEmptyBlock(bp)) { - sendPacket(new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK, bp, Direction.UP)); - } - } - } - } - } - - if (isMode(Mode.PEARL) && (mc.player.onGround() || !onlyOnGround.get())) { - if (mc.player.horizontalCollision && !playerInsideBlock() && clipTimer <= 0 && mc.player.tickCount > 60) { - double[] dir = MovementUtil.forward(0.5); - BlockPos block = BlockPos.containing(mc.player.getX() + dir[0], mc.player.getY(), mc.player.getZ() + dir[1]); - - if (mc.options.keyShift.isDown()) return; - - float[] angle = InteractionUtil.calculateAngle(Vec3.atCenterOf(block)); - int epSlot = findEPSlot(); - - if (epSlot != -1) { - mc.player.setYRot(angle[0]); - mc.player.setXRot(pitch.get()); - } - } - } - } - - @EventHandler - public void onPostSync(EventPostSync e) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || mc.level == null) return; - - if (isMode(Mode.PEARL) && (mc.player.onGround() || !onlyOnGround.get())) { - if (mc.player.horizontalCollision && !playerInsideBlock() && clipTimer <= 0 && mc.player.tickCount > 60) { - if (mc.options.keyShift.isDown()) return; - - int epSlot = findEPSlot(); - int prevItem = ((PlayerInventoryAccessor) mc.player.getInventory()).combatant$getSelectedSlot(); - - if (epSlot != -1) { - InventorySwap.INSTANCE.selectHotbar(epSlot); - InteractionUtil.sendSequencedPacket(id -> - new ServerboundUseItemPacket(InteractionHand.MAIN_HAND, id, mc.player.getYRot(), mc.player.getXRot())); - sendPacket(new ServerboundSwingPacket(InteractionHand.MAIN_HAND)); - InventorySwap.INSTANCE.selectHotbar(prevItem); - if (autoDisable.get()) { - setEnabled(false); - } - } - clipTimer = 20; - afterPearlTime = afterPearl.get(); - } - } - } - - @EventHandler - public void onBreakBlock(EventBreakBlock e) { - clipTimer = afterBreak.get(); - } - - public boolean canNoClip() { - if (isMode(Mode.VANILLA)) return true; - if (!waitBreak.get()) return true; - return clipTimer != 0; - } - - public boolean playerInsideBlock() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || mc.level == null) return false; - return !mc.level.isEmptyBlock(BlockPos.containing(mc.player.position())); - } - - private int findEPSlot() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return -1; - int epSlot = -1; - if (mc.player.getMainHandItem().getItem() == net.minecraft.world.item.Items.ENDER_PEARL) { - epSlot = ((PlayerInventoryAccessor) mc.player.getInventory()).combatant$getSelectedSlot(); - } - if (epSlot == -1) { - for (int i = 0; i < 9; ++i) { - if (mc.player.getInventory().getItem(i).getItem() == net.minecraft.world.item.Items.ENDER_PEARL) { - epSlot = i; - break; - } - } - } - return epSlot; - } - - private boolean isMode(Mode target) { - return mode.get() == target; - } - - private void sendPacket(Packet packet) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.getConnection() == null || packet == null) return; - mc.getConnection().send(packet); - } - - private int findBestTool(BlockPos pos) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || mc.level == null) return -1; - - BlockState state = mc.level.getBlockState(pos); - if (state.isAir()) return -1; - - int slot = -1; - float best = 1.0f; - for (int i = 0; i < 9; i++) { - ItemStack stack = mc.player.getInventory().getItem(i); - if (stack == null || stack.isEmpty()) continue; - - int level = 0; - Holder entry = entryOf(Enchantments.EFFICIENCY); - if (entry != null) { - level = EnchantmentHelper.getItemEnchantmentLevel(entry, stack); - } - float digSpeed = level; - float destroySpeed = stack.getDestroySpeed(state); - float score = digSpeed + destroySpeed; - if (score > best) { - best = score; - slot = i; - } - } - return slot; - } - - private Holder entryOf(ResourceKey key) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.level == null || key == null) return null; - Registry registry = - mc.level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT); - Enchantment value = registry.getValue(key); - if (value == null) return null; - return registry.wrapAsHolder(value); - } - - public enum Mode { - VANILLA, - PEARL, - BREAK_ASSIST, - FORCE_MINE, - CC_CLIP - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ReverseStep.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ReverseStep.java deleted file mode 100644 index 0e3871f..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/ReverseStep.java +++ /dev/null @@ -1,402 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanMapValue; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.GameTickEvent; -import dev.loki.lovisual.events.impl.PlayerJumpEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; - -//todo Description -@ModuleInfo( - id = "reversestep", - displayName = "ReverseStep", - category = ModuleCategory.MOVEMENT -) -public final class ReverseStep extends Module { - - private static final Set UNWANTED_BLOCKS = Set.of( - Blocks.WATER, - Blocks.COBWEB, - Blocks.POWDER_SNOW, - Blocks.HAY_BLOCK, - Blocks.SLIME_BLOCK - ); - private static final double[] VULCAN_297_STEP_C_MOTION = { - -0.5, - -0.07850000262260437, - -0.15530000627040863, - -0.2305999994277954, - -0.3043999969959259, - -0.376800000667572, - -0.44749999046325684, - -0.5170999765396118, - -0.5860000252723694, - -0.6520000100135803, - -0.7171000242233276, - -0.7811999917030334, - -0.843999981880188, - -0.9054999947547913, - -0.9657999873161316, - -1.024899959564209, - -1.082800030708313, - -1.1395000219345093, - -1.195099949836731, - -1.2496000528335571, - -1.3029999732971191, - -1.3559999465942383, - -1.406999945640564, - -1.4570000171661377, - -1.5069999694824219, - -1.5549999475479126 - }; - private static final double VULCAN_297_GROUND_SEARCH_DISTANCE = 50.0; - private static final double VULCAN_297_MIN_FALLING_MOTION = -0.01; - private static final double VULCAN_297_EXTERNAL_UPWARD_MOTION = 0.02; - private static final double VULCAN_297_SHORT_DROP_DISTANCE = 1.25; - private static final double VULCAN_297_SHORT_DROP_MOTION = -0.49; - private static final double VULCAN_297_FLIGHT_F_DECAY = 0.04; - private static final double VULCAN_297_FLIGHT_F_SHORT_DROP_COST = 1.0; - private static final double VULCAN_297_FLIGHT_F_AGGRESSIVE_LIMIT = 1.6; - private static final String STEP_C_EXEMPT_CREATIVE = "creative"; - private static final String STEP_C_EXEMPT_FLIGHT = "flight"; - private static final String STEP_C_EXEMPT_GLIDING = "gliding"; - private static final String STEP_C_EXEMPT_EXPLOSION = "explosion"; - private static final String STEP_C_EXEMPT_LIQUID = "liquid"; - private static final String STEP_C_EXEMPT_VEHICLE = "vehicle"; - private static final String STEP_C_EXEMPT_RIPTIDE = "riptide"; - private static final String STEP_C_EXEMPT_SLEEPING = "sleeping"; - private static final String STEP_C_EXEMPT_VELOCITY = "velocity"; - private static final String STEP_C_EXEMPT_SLIME = "slime"; - private static final String STEP_C_EXEMPT_ENDER_PEARL = "ender_pearl"; - private static final String STEP_C_EXEMPT_ANVIL = "anvil"; - private static final String STEP_C_EXEMPT_END_ROD = "end_rod"; - private static final String STEP_C_EXEMPT_CHAIN = "chain"; - private static final String STEP_C_EXEMPT_DRIPSTONE = "dripstone"; - private static final String STEP_C_EXEMPT_JUMP_BOOST = "jump_boost"; - private static final String STEP_C_EXEMPT_CLIMBABLE = "climbable"; - private static final String STEP_C_EXEMPT_SCAFFOLDING = "scaffolding"; - private static final String STEP_C_EXEMPT_POWDER_SNOW = "powder_snow"; - private static final String STEP_C_EXEMPT_SNOW = "snow"; - private final Minecraft mc = Minecraft.getInstance(); - private final EnumValue mode = enumSetting("reverseStepMode", "mode", Mode.INSTANT, Mode.values()); - private final NumberValue maximumFallDistance = - num("reverseStepMaximumFallDistance", "maximum_fall_distance", 1.0f, 1.0f, 50.0f); - private final NumberValue instantTicks = - visibleWhen(num("reverseStepInstantTicks", "ticks", 20, 1, 40), () -> mode.get() == Mode.INSTANT); - private final BooleanValue simulateFalling = - visibleWhen(bool("reverseStepSimulateFalling", "simulate_falling", false), () -> mode.get() == Mode.INSTANT); - private final NumberValue acceleratorFactor = - visibleWhen(num("reverseStepAcceleratorFactor", "factor", 1.0f, 0.1f, 5.0f), () -> mode.get() == Mode.ACCELERATOR); - private final NumberValue strictMotion = - visibleWhen(num("reverseStepStrictMotion", "motion", 1.0f, 0.1f, 5.0f), () -> mode.get() == Mode.STRICT); - private final NumberValue vulcan297Motion = - visibleWhen(num("reverseStepVulcan297Motion", "vulcan297_motion", 0.65f, 0.08f, 1.55f), () -> mode.get() == Mode.VULCAN_297); - private final NumberValue vulcan297ExemptMotion = - visibleWhen(num("reverseStepVulcan297ExemptMotion", "vulcan297_exempt_motion", 1.0f, 0.08f, 2.0f), () -> mode.get() == Mode.VULCAN_297); - private final NumberValue vulcan297StepCMargin = - visibleWhen(num("reverseStepVulcan297StepCMargin", "vulcan297_stepc_margin", 0.004f, 0.0f, 0.05f), () -> mode.get() == Mode.VULCAN_297); - private final BooleanMapValue vulcan297StepCExempts = - visibleWhen(group("reverseStepVulcan297StepCExempts", "vulcan297_stepc_exempts", vulcan297StepCExemptDefaults()), () -> mode.get() == Mode.VULCAN_297); - private boolean initiatedJump; - private int vulcan297FallTicks; - private boolean vulcan297Jumped; - private boolean vulcan297GroundSeen; - private boolean vulcan297ExternalAirState; - private int vulcan297AirTicks; - private double vulcan297FlightFRisk; - - private static Map vulcan297StepCExemptDefaults() { - Map defaults = new LinkedHashMap<>(); - defaults.put(STEP_C_EXEMPT_CREATIVE, true); - defaults.put(STEP_C_EXEMPT_FLIGHT, true); - defaults.put(STEP_C_EXEMPT_GLIDING, true); - defaults.put(STEP_C_EXEMPT_EXPLOSION, true); - defaults.put(STEP_C_EXEMPT_LIQUID, true); - defaults.put(STEP_C_EXEMPT_VEHICLE, true); - defaults.put(STEP_C_EXEMPT_RIPTIDE, true); - defaults.put(STEP_C_EXEMPT_SLEEPING, true); - defaults.put(STEP_C_EXEMPT_VELOCITY, true); - defaults.put(STEP_C_EXEMPT_SLIME, true); - defaults.put(STEP_C_EXEMPT_ENDER_PEARL, true); - defaults.put(STEP_C_EXEMPT_ANVIL, true); - defaults.put(STEP_C_EXEMPT_END_ROD, true); - defaults.put(STEP_C_EXEMPT_CHAIN, true); - defaults.put(STEP_C_EXEMPT_DRIPSTONE, true); - defaults.put(STEP_C_EXEMPT_JUMP_BOOST, true); - defaults.put(STEP_C_EXEMPT_CLIMBABLE, true); - defaults.put(STEP_C_EXEMPT_SCAFFOLDING, true); - defaults.put(STEP_C_EXEMPT_POWDER_SNOW, true); - defaults.put(STEP_C_EXEMPT_SNOW, true); - return defaults; - } - - @Override - public void onDisable() { - initiatedJump = false; - vulcan297FallTicks = 0; - vulcan297Jumped = false; - vulcan297GroundSeen = false; - vulcan297ExternalAirState = false; - vulcan297AirTicks = 0; - vulcan297FlightFRisk = 0.0; - } - - @EventHandler - private void onPlayerJump(PlayerJumpEvent event) { - if (!isEnabled()) { - return; - } - - if (mode.get() == Mode.VULCAN_297) { - vulcan297Jumped = true; - vulcan297FallTicks = 0; - } else { - initiatedJump = true; - } - } - - @EventHandler - private void onGameTick(GameTickEvent event) { - if (!isEnabled() || mc.player == null || mc.level == null) return; - - LocalPlayer player = mc.player; - decayVulcan297Risk(); - if (player.onGround()) { - initiatedJump = false; - vulcan297FallTicks = 0; - vulcan297Jumped = false; - vulcan297GroundSeen = mode.get() == Mode.VULCAN_297; - vulcan297ExternalAirState = false; - vulcan297AirTicks = 0; - return; - } - - if (mode.get() == Mode.VULCAN_297) { - if (vulcan297AirTicks == 0) { - vulcan297ExternalAirState = !vulcan297GroundSeen - || vulcan297Jumped - || player.hurtTime > 0 - || player.getDeltaMovement().y > VULCAN_297_EXTERNAL_UPWARD_MOTION; - } else if (player.hurtTime > 0 || player.getDeltaMovement().y > VULCAN_297_EXTERNAL_UPWARD_MOTION) { - vulcan297ExternalAirState = true; - } - - vulcan297AirTicks++; - - if (vulcan297ExternalAirState) { - vulcan297FallTicks = 0; - return; - } - } else { - vulcan297GroundSeen = false; - vulcan297ExternalAirState = false; - vulcan297AirTicks = 0; - - if (player.getDeltaMovement().y > 0.08) { - initiatedJump = true; - } - - if (initiatedJump) { - return; - } - if (isFallingTooFar(player) || unwantedBlocksBelow(player)) { - return; - } - } - - switch (mode.get()) { - case INSTANT -> handleInstant(player); - case STRICT -> { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(velocity.x, -strictMotion.get(), velocity.z); - } - case ACCELERATOR -> { - Vec3 velocity = player.getDeltaMovement(); - if (velocity.y < 0.0) { - player.setDeltaMovement(velocity.x, velocity.y * acceleratorFactor.get(), velocity.z); - } - } - case VULCAN_297 -> handleVulcan297(player); - } - } - - private void handleInstant(LocalPlayer player) { - BlockHitResult ground = raycastGround(player, maximumFallDistance.get()); - if (ground == null || ground.getType() != HitResult.Type.BLOCK) return; - - double targetY = ground.getLocation().y; - if (targetY >= player.getY()) return; - - if (simulateFalling.get() && mc.getConnection() != null) { - double startY = player.getY(); - int ticks = Math.max(1, instantTicks.get()); - for (int i = 1; i <= ticks; i++) { - double progress = i / (double) ticks; - double y = startY + (targetY - startY) * progress; - mc.getConnection().send(new ServerboundMovePlayerPacket.Pos( - player.getX(), - y, - player.getZ(), - i == ticks, - player.horizontalCollision - )); - } - } - - player.setPos(player.getX(), targetY, player.getZ()); - } - - private void handleVulcan297(LocalPlayer player) { - Vec3 velocity = player.getDeltaMovement(); - if (velocity.y >= VULCAN_297_MIN_FALLING_MOTION) { - vulcan297FallTicks = 0; - return; - } - - double searchDistance = Math.min(maximumFallDistance.get(), VULCAN_297_GROUND_SEARCH_DISTANCE); - BlockHitResult ground = raycastGround(player, searchDistance); - if (ground == null || ground.getType() != HitResult.Type.BLOCK) return; - - double targetY = ground.getLocation().y; - double distanceToGround = player.getY() - targetY; - if (distanceToGround <= 0.0 || distanceToGround > searchDistance) return; - - vulcan297FallTicks = Math.min(vulcan297FallTicks + 1, VULCAN_297_STEP_C_MOTION.length - 1); - - boolean exempt = isVulcan297StepCExempt(player, ground.getBlockPos()); - double totalDropDistance = player.fallDistance + distanceToGround; - boolean shortDrop = totalDropDistance <= VULCAN_297_SHORT_DROP_DISTANCE; - double targetMotion; - - if (exempt) { - targetMotion = -vulcan297ExemptMotion.get(); - } else if (shortDrop && vulcan297FallTicks == 1 && canUseVulcan297AggressiveShortDrop()) { - targetMotion = Math.max(-vulcan297Motion.get(), VULCAN_297_SHORT_DROP_MOTION); - vulcan297FlightFRisk += VULCAN_297_FLIGHT_F_SHORT_DROP_COST; - } else { - targetMotion = Math.max(-vulcan297Motion.get(), vulcan297SafeStepCMotion()); - } - - if (velocity.y > targetMotion) { - player.setDeltaMovement(velocity.x, targetMotion, velocity.z); - } - } - - private double vulcan297SafeStepCMotion() { - int index = Math.max(1, Math.min(vulcan297FallTicks, VULCAN_297_STEP_C_MOTION.length - 1)); - return VULCAN_297_STEP_C_MOTION[index] + vulcan297StepCMargin.get(); - } - - private boolean canUseVulcan297AggressiveShortDrop() { - return vulcan297FlightFRisk < VULCAN_297_FLIGHT_F_AGGRESSIVE_LIMIT; - } - - private void decayVulcan297Risk() { - if (vulcan297FlightFRisk > 0.0) { - vulcan297FlightFRisk = Math.max(0.0, vulcan297FlightFRisk - VULCAN_297_FLIGHT_F_DECAY); - } - } - - private boolean isVulcan297StepCExempt(LocalPlayer player, BlockPos groundPos) { - if (player == null || mc.level == null) return false; - - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_CREATIVE) && player.getAbilities().instabuild) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_FLIGHT) && player.getAbilities().flying) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_GLIDING) && player.isFallFlying()) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_EXPLOSION) && player.hurtTime > 0) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_LIQUID) && (player.isInWater() || player.isInLava())) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_VEHICLE) && player.isPassenger()) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_RIPTIDE) && player.isAutoSpinAttack()) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_SLEEPING) && player.isSleeping()) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_VELOCITY) && player.hurtTime > 0) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_ENDER_PEARL) && player.tickCount < 100) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_JUMP_BOOST) && player.hasEffect(MobEffects.JUMP_BOOST)) return true; - if (vulcan297StepCExempts.get(STEP_C_EXEMPT_CLIMBABLE) && player.onClimbable()) return true; - - BlockPos feet = player.blockPosition(); - return isVulcan297StepCExemptBlock(feet) - || isVulcan297StepCExemptBlock(feet.below()) - || isVulcan297StepCExemptBlock(groundPos); - } - - private boolean isVulcan297StepCExemptBlock(BlockPos pos) { - if (mc.level == null) return false; - - Block block = mc.level.getBlockState(pos).getBlock(); - return vulcan297StepCExempts.get(STEP_C_EXEMPT_SLIME) && block == Blocks.SLIME_BLOCK - || vulcan297StepCExempts.get(STEP_C_EXEMPT_ANVIL) && block == Blocks.ANVIL - || vulcan297StepCExempts.get(STEP_C_EXEMPT_END_ROD) && block == Blocks.END_ROD - || vulcan297StepCExempts.get(STEP_C_EXEMPT_CHAIN) && block == Blocks.IRON_CHAIN - || vulcan297StepCExempts.get(STEP_C_EXEMPT_DRIPSTONE) && block == Blocks.POINTED_DRIPSTONE - || vulcan297StepCExempts.get(STEP_C_EXEMPT_SCAFFOLDING) && block == Blocks.SCAFFOLDING - || vulcan297StepCExempts.get(STEP_C_EXEMPT_POWDER_SNOW) && block == Blocks.POWDER_SNOW - || vulcan297StepCExempts.get(STEP_C_EXEMPT_SNOW) && block == Blocks.SNOW; - } - - private boolean isFallingTooFar(LocalPlayer player) { - if (player.fallDistance > maximumFallDistance.get()) { - return true; - } - - AABB box = player.getBoundingBox().move(0.0, -maximumFallDistance.get(), 0.0); - return !mc.level.getBlockCollisions(player, box).iterator().hasNext(); - } - - private boolean unwantedBlocksBelow(LocalPlayer player) { - BlockHitResult hit = raycastGround(player, 20.0); - if (hit == null || hit.getType() != HitResult.Type.BLOCK) { - return false; - } - - BlockPos pos = hit.getBlockPos(); - Block block = mc.level.getBlockState(pos).getBlock(); - return UNWANTED_BLOCKS.contains(block); - } - - private BlockHitResult raycastGround(LocalPlayer player, double distance) { - HitResult result = mc.level.clip(new ClipContext( - player.position(), - player.position().add(0.0, -distance, 0.0), - ClipContext.Block.COLLIDER, - ClipContext.Fluid.ANY, - player - )); - - return result instanceof BlockHitResult blockHit ? blockHit : null; - } - - public enum Mode { - INSTANT, - STRICT, - ACCELERATOR, - VULCAN_297 - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/SafeWalk.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/SafeWalk.java deleted file mode 100644 index 03dbda4..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/SafeWalk.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import lombok.RequiredArgsConstructor; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.events.impl.PlayerSafeWalkEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.util.entity.EagleUtil; - -//todo Description -@ModuleInfo( - id = "safewalk", - displayName = "SafeWalk", - category = ModuleCategory.MOVEMENT -) -public final class SafeWalk extends Module { - - private final Minecraft mc = Minecraft.getInstance(); - private final EnumValue mode = enumMode("mode", Mode.ON_EDGE); - private final EnumValue onEdgeMode = - visibleWhen(enumMode("on_edge_mode", OnEdgeMode.STOP), this::isOnEdgeMode); - private final NumberValue edgeDistance = - visibleWhen(num("edge_distance", 0.1, 0.01, 0.5), this::isOnEdgeMode); - private final NumberValue keepTicks = - visibleWhen(num("keep_ticks", 2, 1, 20), this::isOnEdgeMode); - private final NumberValue sneakTicks = - visibleWhen(num("sneak_ticks", 0, 0, 20), this::isOnEdgeMode); - private final BooleanValue jump = - visibleWhen(bool("jump", false), this::isOnEdgeMode); - private final EagleUtil.EdgeRecovery edgeRecovery = new EagleUtil.EdgeRecovery(); - - private boolean isOnEdgeMode() { - return mode.get() == Mode.ON_EDGE; - } - - @Override - public void onDisable() { - edgeRecovery.reset(); - } - - public boolean handleExternalOnEdge(LocalPlayer player, MovementInputEvent event) { - if (player == null || event == null || player.getAbilities().flying) { - edgeRecovery.reset(); - return false; - } - - if (!player.onGround() && !event.isSneak()) { - edgeRecovery.reset(); - return false; - } - - return edgeRecovery.handleOnEdge( - player, - event, - edgeDistance.get(), - onEdgeMode.get().recoveryMode(), - keepTicks.get(), - sneakTicks.get(), - jump.get() - ); - } - - @EventHandler - private void onSafeWalk(PlayerSafeWalkEvent event) { - if (!isEnabled() || mode.get() != Mode.SAFE) { - return; - } - - LocalPlayer player = mc.player; - if (player == null || !player.onGround() || player.getAbilities().flying) { - return; - } - - event.setSafeWalk(true); - } - - @EventHandler - private void onMovementInput(MovementInputEvent event) { - if (!isEnabled() || mode.get() != Mode.ON_EDGE) { - edgeRecovery.reset(); - return; - } - - LocalPlayer player = mc.player; - if (player == null || player.getAbilities().flying) { - edgeRecovery.reset(); - return; - } - - if (!player.onGround() && !event.isSneak()) { - edgeRecovery.reset(); - return; - } - - handleExternalOnEdge(player, event); - } - - public enum Mode { - SAFE, - ON_EDGE - } - - @RequiredArgsConstructor - public enum OnEdgeMode { - STOP(EagleUtil.RecoveryMode.STOP), - INVERT(EagleUtil.RecoveryMode.INVERT), - CENTER(EagleUtil.RecoveryMode.CENTER); - - private final EagleUtil.RecoveryMode recoveryMode; - - public EagleUtil.RecoveryMode recoveryMode() { - return recoveryMode; - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Speed.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Speed.java deleted file mode 100644 index 66dd9d3..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Speed.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.MoverType; -import net.minecraft.world.phys.Vec2; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.GameTickEvent; -import dev.loki.lovisual.events.impl.PacketEvent; -import dev.loki.lovisual.events.impl.PlayerMoveEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.mixins.accessors.ServerboundMovePlayerPacketAccessor; -import dev.loki.lovisual.util.player.MovementUtil; - -//todo Description -@ModuleInfo( - id = "speed", - displayName = "Speed", - category = ModuleCategory.MOVEMENT -) -public final class Speed extends Module { - - public final NumberValue legitMultiplier = num("legit_multiplier", 1.20f, 1.15f, 1.50f); - public final NumberValue jumpAcceleration = num("jump_acceleration", 1.30f, 1.00f, 1.60f); - public final NumberValue entityBoostStrength = num("entity_boost_strength", 0.20f, 0.05f, 0.40f); - private final EnumValue mode = enumMode("mode", Mode.NCP); - private boolean lastOnGround = true; - private int airTicks; - - @Override - public void onEnable() { - resetState(); - } - - @Override - public void onDisable() { - resetState(); - } - - @EventHandler - private void onGameTick(GameTickEvent event) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null || mc.level == null) return; - - LocalPlayer player = mc.player; - updateAirTicks(player); - - switch (mode.get()) { - case NCP -> handleNcp(player); - case VULCAN_286 -> handleVulcan286(player); - case VULCAN_288 -> handleVulcan288(player); - case VULCAN_GROUND_286 -> handleVulcanGround286(player); - case MATRIX_7 -> handleMatrix7(player); - } - } - - @EventHandler - private void onMove(PlayerMoveEvent event) { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return; - if (event.getType() != MoverType.SELF) return; - if (mode.get() != Mode.NCP) return; - - LocalPlayer player = mc.player; - if (!canSpeed(player) || !MovementUtil.isMoving() || player.onGround()) return; - - double speedLevel = getSpeedAmplifier(player); - double airMin = 0.2 + 0.199999999 * speedLevel; - double useSpeed = Math.max(horizontalSpeed(player.getDeltaMovement()), airMin); - event.setMovement(withStrafe(event.getMovement(), player, useSpeed, 0.7)); - } - - @EventHandler - private void onPacketSend(PacketEvent.Send event) { - if (!(event.getPacket() instanceof ServerboundMovePlayerPacket packet)) return; - - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return; - - LocalPlayer player = mc.player; - if (!canSpeed(player)) return; - - switch (mode.get()) { - case VULCAN_288 -> { - if (player.getDeltaMovement().y < 0.0) { - ((ServerboundMovePlayerPacketAccessor) packet).combatant$setOnGround(true); - } - } - case VULCAN_GROUND_286 -> { - if (collidesBottomVertical(player) && !mc.options.keyJump.isDown() && MovementUtil.isMoving()) { - ((ServerboundMovePlayerPacketAccessor) packet).combatant$setY(packet.getY(player.getY()) + 0.005); - } - } - default -> { - } - } - } - - public boolean shouldBlockOmniSprintBoost() { - return isEnabled(); - } - - public boolean enabled(String key) { - return false; - } - - private void handleNcp(LocalPlayer player) { - if (!canSpeed(player)) return; - - if (player.onGround()) { - if (!MovementUtil.isMoving()) return; - - double groundMin = 0.281 + 0.199999999 * getSpeedAmplifier(player); - autoJump(player); - Vec3 velocity = withStrafe(player.getDeltaMovement(), player, groundMin, 1.0); - player.setDeltaMovement(velocity.x, 0.4, velocity.z); - return; - } - - if (airTicks == 5) { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(velocity.x, velocity.y - 0.1523351824467155, velocity.z); - } - - if (player.hurtTime >= 5 && player.getDeltaMovement().y >= 0.0) { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(velocity.x, velocity.y - 0.1, velocity.z); - } - } - - private void handleVulcan286(LocalPlayer player) { - if (!canSpeed(player)) return; - - if (player.onGround()) { - if (!MovementUtil.isMoving()) return; - autoJump(player); - return; - } - - double speedLevel = getSpeedAmplifier(player); - boolean goingSideways = player.input != null && player.input.getMoveVector().x != 0.0f; - - if (airTicks == 1) { - double speed = goingSideways ? 0.3345 : 0.3355 * (1.0 + speedLevel * 0.3819); - player.setDeltaMovement(withStrafe(player.getDeltaMovement(), player, speed, 1.0)); - } else if (airTicks == 2 && player.isSprinting()) { - double speed = goingSideways ? 0.3235 : 0.3284 * (1.0 + speedLevel * 0.355); - player.setDeltaMovement(withStrafe(player.getDeltaMovement(), player, speed, 1.0)); - } else if (airTicks == 4) { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(velocity.x, -0.376, velocity.z); - } else if (airTicks == 6) { - double horizontal = horizontalSpeed(player.getDeltaMovement()); - if (horizontal > 0.298) { - player.setDeltaMovement(withStrafe(player.getDeltaMovement(), player, 0.298, 1.0)); - } - } - } - - private void handleVulcan288(LocalPlayer player) { - if (!canSpeed(player)) return; - - boolean hasSpeed = getSpeedAmplifier(player) > 0.0; - - if (player.onGround()) { - if (!MovementUtil.isMoving()) return; - autoJump(player); - player.setDeltaMovement(withStrafe(player.getDeltaMovement(), player, hasSpeed ? 0.771 : 0.5, 1.0)); - return; - } - - if (airTicks == 1) { - player.setDeltaMovement(withStrafe(player.getDeltaMovement(), player, hasSpeed ? 0.605 : 0.31, 1.0)); - } else if (airTicks == 2) { - Vec3 velocity = withStrafe(player.getDeltaMovement(), player, hasSpeed ? 0.57 : 0.29, 1.0); - player.setDeltaMovement(velocity.x, hasSpeed ? -0.5 : -0.37, velocity.z); - } else if (airTicks == 3) { - player.setDeltaMovement(withStrafe(player.getDeltaMovement(), player, hasSpeed ? 0.595 : 0.27, 1.0)); - } else if (airTicks == 4) { - player.setDeltaMovement(withStrafe(player.getDeltaMovement(), player, hasSpeed ? 0.595 : 0.28, 1.0)); - } - - if (hasSpeed && player.fallDistance > 0.0f) { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(velocity.x * 1.055, velocity.y, velocity.z * 1.055); - } - } - - private void handleVulcanGround286(LocalPlayer player) { - if (!canSpeed(player)) return; - - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.options == null) return; - if (!MovementUtil.isMoving() || mc.options.keyJump.isDown()) return; - if (!collidesBottomVertical(player)) return; - - boolean hasSpeed = getSpeedAmplifier(player) > 0.0; - boolean movingSideways = player.input != null && player.input.getMoveVector().x != 0.0f; - double strafe = hasSpeed ? 0.59 : movingSideways ? 0.41 : 0.42; - - Vec3 velocity = withStrafe(player.getDeltaMovement(), player, strafe, 1.0); - player.setDeltaMovement(velocity.x, 0.005, velocity.z); - } - - private void handleMatrix7(LocalPlayer player) { - if (!canSpeed(player) || !MovementUtil.isMoving()) return; - - double baseSpeed = Math.max(horizontalSpeed(player.getDeltaMovement()), 0.28); - if (player.onGround()) { - Vec3 velocity = withStrafe(player.getDeltaMovement(), player, baseSpeed, 1.0); - player.setDeltaMovement(velocity.x, 0.419652, velocity.z); - return; - } - - if (player.getDeltaMovement().x * player.getDeltaMovement().x + player.getDeltaMovement().z * player.getDeltaMovement().z < 0.04) { - player.setDeltaMovement(withStrafe(player.getDeltaMovement(), player, baseSpeed, 1.0)); - } - } - - private void autoJump(LocalPlayer player) { - if (player == null || player.getDeltaMovement().y > 0.01) return; - player.jumpFromGround(); - } - - private boolean canSpeed(LocalPlayer player) { - return player != null - && !player.isShiftKeyDown() - && !player.isInWater() - && !player.isInLava() - && !player.onClimbable() - && !player.isPassenger() - && !player.isFallFlying(); - } - - private void updateAirTicks(LocalPlayer player) { - boolean onGround = player.onGround(); - if (onGround) { - airTicks = 0; - } else if (lastOnGround) { - airTicks = 1; - } else { - airTicks++; - } - - lastOnGround = onGround; - } - - private double getSpeedAmplifier(LocalPlayer player) { - if (player == null) return 0.0; - var effect = player.getEffect(MobEffects.SPEED); - return effect == null ? 0.0 : effect.getAmplifier(); - } - - private double horizontalSpeed(Vec3 velocity) { - return velocity == null ? 0.0 : Math.hypot(velocity.x, velocity.z); - } - - private Vec3 withStrafe(Vec3 currentVelocity, LocalPlayer player, double speed, double strength) { - if (player == null || player.input == null) return currentVelocity; - - Vec2 input = player.input.getMoveVector(); - Vec3 movementInput = new Vec3(input.x, 0.0, input.y); - return MovementUtil.withStrafe(currentVelocity, movementInput, player.getYRot(), speed, strength); - } - - private boolean collidesBottomVertical(LocalPlayer player) { - if (player == null || player.level() == null) return false; - - for (var shape : player.level().getBlockCollisions(player, player.getBoundingBox().move(0.0, -0.005, 0.0))) { - if (!shape.isEmpty()) { - return true; - } - } - - return false; - } - - private void resetState() { - lastOnGround = true; - airTicks = 0; - } - - public enum Mode { - NCP, - VULCAN_286, - VULCAN_288, - VULCAN_GROUND_286, - MATRIX_7 - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Sprint.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Sprint.java deleted file mode 100644 index 3cb9768..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Sprint.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientboundDamageEventPacket; -import net.minecraft.network.protocol.game.ClientboundExplodePacket; -import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.phys.Vec2; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.GameTickEvent; -import dev.loki.lovisual.events.impl.PacketEvent; -import dev.loki.lovisual.events.impl.PlayerJumpEvent; -import dev.loki.lovisual.events.impl.SprintControlEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.player.Scaffold; -import dev.loki.lovisual.features.module.modules.visuals.Freecam; -import dev.loki.lovisual.util.combat.CombatStrikeController; -import dev.loki.lovisual.util.combat.SprintController; -import dev.loki.lovisual.util.player.MovementUtil; - -//todo Description -@ModuleInfo( - id = "sprint", - displayName = "Sprint", - category = ModuleCategory.MOVEMENT -) -public final class Sprint extends Module { - - private static final double VULCAN_SPRINT_A_SPEED_GATE = 0.25; - private static final double VULCAN_SPRINT_A_BUFFER_DECAY = 0.4; - private static final int VULCAN_SPRINT_A_DIRECTION_GATE_TICKS = 10; - private static final int VULCAN_SPRINT_A_RESET_BEFORE_TICKS = 6; - private static final int VULCAN_SPRINT_A_RESET_TICKS = 3; - private static final int VULCAN_SPRINT_A_JUMP_GRACE_TICKS = 4; - private static final int VULCAN_EXTERNAL_SPRINT_SUPPRESS_TICKS = 30; - private final EnumValue defaultResetMode = - enumMode("default_reset_mode", ResetMode.LEGIT, ResetMode.values()); - private final BooleanValue omniDirectional = - bool("omni_directional", false); - private final BooleanValue vulcanBypass = - visibleWhen(bool("omni_directional_vulcan_bypass", true), omniDirectional::get); - private final BooleanValue avoidSwimStartForce = - bool("avoid_swim_start_force", true); - private final Minecraft mc = Minecraft.getInstance(); - private int vulcanSprintSuppressTicks; - private int vulcanSprintDirectionTicks; - private int vulcanSprintJumpGraceTicks; - private int vulcanExternalSprintSuppressTicks; - private double vulcanSprintABuffer; - - @Override - public void onEnable() { - resetVulcanSprintAGuard(); - } - - @Override - public void onDisable() { - resetVulcanSprintAGuard(); - } - - @EventHandler(priority = 2000) - private void onGameTick(GameTickEvent event) { - LocalPlayer player = mc.player; - if (player == null || mc.level == null) { - resetVulcanSprintAGuard(); - return; - } - - updateVulcanExternalSprintSuppress(player); - updateVulcanSprintAGuard(player); - } - - @EventHandler - private void onPacketReceive(PacketEvent.Receive event) { - LocalPlayer player = mc.player; - if (!isEnabled() || !omniDirectional.get() || !vulcanBypass.get() || player == null || mc.level == null) { - return; - } - - Packet packet = event.getPacket(); - if (packet instanceof ClientboundDamageEventPacket damage && damage.entityId() == player.getId()) { - armVulcanExternalSprintSuppress(); - } else if (packet instanceof ClientboundSetEntityMotionPacket velocity && velocity.id() == player.getId()) { - armVulcanExternalSprintSuppress(); - } else if (packet instanceof ClientboundExplodePacket explosion && explosion.playerKnockback().isPresent()) { - armVulcanExternalSprintSuppress(); - } - } - - @EventHandler - private void onPlayerJump(PlayerJumpEvent event) { - LocalPlayer player = mc.player; - if (!shouldUseOmniDirectional(player)) { - return; - } - - markVulcanSprintAJumpWindow(); - event.setYaw(getMovementYaw(player, event.getYaw())); - } - - @EventHandler - private void onSprintControl(SprintControlEvent event) { - LocalPlayer player = mc.player; - if (shouldHardSuppressSprint()) { - event.setSprint(false); - return; - } - - if (event.getSource() != SprintControlEvent.Source.MOVEMENT_TICK - && event.getSource() != SprintControlEvent.Source.INPUT) { - return; - } - - if (!event.isMoving() || !shouldUseOmniDirectional(player)) { - return; - } - - if (shouldAvoidForceSprintForSwimStart(player)) { - return; - } - - event.setSprint(true); - } - - public CombatStrikeController.SprintResetMode resolveCombatResetMode() { - return switch (defaultResetMode.get()) { - case LEGIT -> CombatStrikeController.SprintResetMode.LEGIT; - case PACKET -> CombatStrikeController.SprintResetMode.PACKET; - case FORCE -> CombatStrikeController.SprintResetMode.NONE; - }; - } - - public boolean isLegitResetMode() { - return defaultResetMode.get() == ResetMode.LEGIT; - } - - public boolean shouldAllowDirectionalSprint() { - LocalPlayer player = mc.player; - return shouldUseOmniDirectional(player); - } - - public boolean shouldSuppressExternalVulcanSprintForControl() { - return shouldSuppressExternalVulcanSprint(mc.player); - } - - public boolean shouldAvoidForceSprintForSwimStart(LocalPlayer player) { - return isEnabled() - && avoidSwimStartForce.get() - && isWaitingForManualSwimStart(player); - } - - public float getMovementYaw(LocalPlayer player, float fallbackYaw) { - return MovementUtil.getMovementDirectionYaw(player, fallbackYaw); - } - - private boolean shouldUseOmniDirectional(LocalPlayer player) { - return isEnabled() - && omniDirectional.get() - && canOperate(player) - && !shouldSuppressOmniDirectionalSprint(player) - && hasMovementInput(player); - } - - private boolean shouldHardSuppressSprint() { - return isEnabled() - && omniDirectional.get() - && vulcanBypass.get() - && (shouldSuppressScaffoldDirectionalSprint() - || vulcanSprintSuppressTicks > 0); - } - - private boolean shouldSuppressOmniDirectionalSprint(LocalPlayer player) { - return shouldHardSuppressSprint() || shouldSuppressExternalVulcanSprint(player); - } - - private boolean shouldSuppressScaffoldDirectionalSprint() { - Scaffold scaffold = Modules.get(Scaffold.class); - return scaffold != null && scaffold.shouldSuppressOmniDirectionalSprint(); - } - - private void updateVulcanSprintAGuard(LocalPlayer player) { - if (!isEnabled() || !omniDirectional.get() || !vulcanBypass.get() || !canOperate(player)) { - resetVulcanSprintAGuard(); - return; - } - - if (vulcanSprintJumpGraceTicks > 0) { - vulcanSprintJumpGraceTicks--; - } - - if (vulcanSprintSuppressTicks > 0) { - vulcanSprintSuppressTicks--; - vulcanSprintDirectionTicks = 0; - decayVulcanSprintABuffer(); - return; - } - - if (!isVulcanSprintARisky(player)) { - vulcanSprintDirectionTicks = 0; - decayVulcanSprintABuffer(); - return; - } - - vulcanSprintDirectionTicks++; - if (vulcanSprintDirectionTicks > VULCAN_SPRINT_A_DIRECTION_GATE_TICKS - && getHorizontalSpeed(player) > VULCAN_SPRINT_A_SPEED_GATE) { - vulcanSprintABuffer = Math.min(10000.0, vulcanSprintABuffer + 1.0); - } else { - decayVulcanSprintABuffer(); - } - - if (shouldResetBeforeVulcanSprintA()) { - vulcanSprintSuppressTicks = VULCAN_SPRINT_A_RESET_TICKS; - vulcanSprintDirectionTicks = 0; - decayVulcanSprintABuffer(); - SprintController.INSTANCE.requestLegitStop(mc, player, VULCAN_SPRINT_A_RESET_TICKS); - } - } - - private void updateVulcanExternalSprintSuppress(LocalPlayer player) { - if (!isEnabled() || !omniDirectional.get() || !vulcanBypass.get() || !canOperate(player)) { - vulcanExternalSprintSuppressTicks = 0; - return; - } - - if (player.hurtTime > 0) { - armVulcanExternalSprintSuppress(); - } - - if (vulcanExternalSprintSuppressTicks <= 0) { - return; - } - - if (player.onGround() && player.hurtTime <= 0) { - vulcanExternalSprintSuppressTicks = 0; - return; - } - - vulcanExternalSprintSuppressTicks--; - } - - private boolean shouldSuppressExternalVulcanSprint(LocalPlayer player) { - return player != null - && vulcanBypass.get() - && (vulcanExternalSprintSuppressTicks > 0 || player.hurtTime > 0); - } - - private void armVulcanExternalSprintSuppress() { - vulcanExternalSprintSuppressTicks = Math.max( - vulcanExternalSprintSuppressTicks, - VULCAN_EXTERNAL_SPRINT_SUPPRESS_TICKS - ); - } - - private boolean isVulcanSprintARisky(LocalPlayer player) { - if (player == null - || player.input == null - || !hasMovementInput(player) - || isVulcanSprintAExempt(player) - || isLowRiskVulcanSprintAJumpWindow(player) - || !isServerOrLocalSprinting(player)) { - return false; - } - - return hasRiskyOmniSprintDirection(player); - } - - private boolean shouldResetBeforeVulcanSprintA() { - return vulcanSprintDirectionTicks >= VULCAN_SPRINT_A_RESET_BEFORE_TICKS - || vulcanSprintABuffer >= 5.0; - } - - private boolean isServerOrLocalSprinting(LocalPlayer player) { - return player.isSprinting() || SprintController.INSTANCE.isServerSprinting(player); - } - - private boolean isLowRiskVulcanSprintAJumpWindow(LocalPlayer player) { - return !player.onGround() - || vulcanSprintJumpGraceTicks > 0 - || isJumpInputPressed(player); - } - - private boolean isJumpInputPressed(LocalPlayer player) { - return player.input != null - && player.input.keyPresses != null - && player.input.keyPresses.jump(); - } - - private void markVulcanSprintAJumpWindow() { - if (!isEnabled() || !omniDirectional.get() || !vulcanBypass.get()) { - return; - } - - vulcanSprintJumpGraceTicks = VULCAN_SPRINT_A_JUMP_GRACE_TICKS; - } - - private boolean hasRiskyOmniSprintDirection(LocalPlayer player) { - Vec2 movementInput = player.input.getMoveVector(); - float sideways = Math.abs(movementInput.x); - float forward = movementInput.y; - - return forward <= 0.0f || sideways > Math.abs(forward) + 0.001f; - } - - private boolean isVulcanSprintAExempt(LocalPlayer player) { - return player.isAutoSpinAttack() - || player.isInWater() - || player.isUnderWater() - || player.isInLava() - || player.isSwimming() - || player.isFallFlying() - || isOnIce(player); - } - - private boolean isWaitingForManualSwimStart(LocalPlayer player) { - return player != null - && player.input != null - && player.isUnderWater() - && !player.isSwimming() - && !player.isPassenger() - && !player.getAbilities().flying - && !player.isFallFlying() - && !player.isSpectator() - && mc.level != null - && mc.level.getFluidState(player.blockPosition()).is(FluidTags.WATER); - } - - private boolean isOnIce(LocalPlayer player) { - if (mc.level == null) { - return false; - } - - BlockPos pos = player.blockPosition().below(); - Block block = mc.level.getBlockState(pos).getBlock(); - return block == Blocks.ICE - || block == Blocks.PACKED_ICE - || block == Blocks.BLUE_ICE - || block == Blocks.FROSTED_ICE; - } - - private double getHorizontalSpeed(LocalPlayer player) { - Vec3 velocity = player.getDeltaMovement(); - return Math.hypot(velocity.x, velocity.z); - } - - private void decayVulcanSprintABuffer() { - vulcanSprintABuffer = Math.max(0.0, vulcanSprintABuffer - VULCAN_SPRINT_A_BUFFER_DECAY); - } - - private void resetVulcanSprintAGuard() { - vulcanSprintSuppressTicks = 0; - vulcanSprintDirectionTicks = 0; - vulcanSprintJumpGraceTicks = 0; - vulcanExternalSprintSuppressTicks = 0; - vulcanSprintABuffer = 0.0; - } - - private boolean hasMovementInput(LocalPlayer player) { - return player != null - && player.input != null - && (player.input.getMoveVector().x != 0.0f - || player.input.getMoveVector().y != 0.0f); - } - - private boolean canOperate(LocalPlayer player) { - return player != null && !isFreecamActive(); - } - - private boolean isFreecamActive() { - return Modules.get(Freecam.class) != null && Modules.get(Freecam.class).isEnabled(); - } - - public enum ResetMode { - LEGIT, - PACKET, - FORCE - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Step.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Step.java deleted file mode 100644 index 04375b0..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Step.java +++ /dev/null @@ -1,486 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; -import net.minecraft.stats.Stats; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec2; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanMapValue; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.GameTickEvent; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.events.impl.PlayerStepEvent; -import dev.loki.lovisual.events.impl.PlayerStepSuccessEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.util.player.MovementUtil; - -import java.util.LinkedHashMap; -import java.util.Map; - -//todo 297 vulcan step remove goofy ass shit -//todo Description -@ModuleInfo( - id = "step", - displayName = "Step", - category = ModuleCategory.MOVEMENT -) -public final class Step extends Module { - - private static final double[] JUMP_ORDER = { - 0.0, - 0.41999998688698, - 0.7531999805212, - 1.00133597911215, - 1.166109260938214, - 1.24918707874468, - 1.25220334025373, - 1.17675927506424, - 1.024424088213685 - }; - private static final String STEP_FLIGHT_EXEMPT_LIQUID = "liquid"; - private static final String STEP_FLIGHT_EXEMPT_WALL = "wall"; - private static final String STEP_FLIGHT_EXEMPT_CONDUIT = "conduit"; - private static final String STEP_FLIGHT_EXEMPT_FARMLAND = "farmland"; - private static final String STEP_FLIGHT_EXEMPT_SLOW_FALLING = "slow_falling"; - private static final String STEP_FLIGHT_EXEMPT_LEVITATION = "levitation"; - private static final String STEP_FLIGHT_EXEMPT_RIPTIDE = "riptide"; - private static final String STEP_FLIGHT_EXEMPT_WEB = "web"; - private static final String STEP_FLIGHT_EXEMPT_WATERLOGGED = "waterlogged"; - private static final String STEP_FLIGHT_EXEMPT_SHULKER_BOX = "shulker_box"; - private static final String STEP_FLIGHT_EXEMPT_SPECTATOR = "spectator"; - private static final String STEP_FLIGHT_EXEMPT_SLEEPING = "sleeping"; - private static final String STEP_FLIGHT_EXEMPT_SLIME = "slime"; - private static final String STEP_FLIGHT_EXEMPT_POWDER_SNOW = "powder_snow"; - private static final String STEP_FLIGHT_EXEMPT_SEAGRASS = "seagrass"; - private static final String STEP_FLIGHT_EXEMPT_SCAFFOLDING = "scaffolding"; - private static final String STEP_FLIGHT_EXEMPT_CLIMBABLE = "climbable"; - private static final String STEP_FLIGHT_EXEMPT_SWIMMING = "swimming"; - private static final String STEP_FLIGHT_EXEMPT_HONEY = "honey"; - private static final String STEP_FLIGHT_EXEMPT_SEA_PICKLE = "sea_pickle"; - private static final String STEP_FLIGHT_EXEMPT_BUBBLE_COLUMN = "bubble_column"; - private static final String STEP_FLIGHT_EXEMPT_VEHICLE = "vehicle"; - private static final String STEP_FLIGHT_EXEMPT_KELP = "kelp"; - private static final String STEP_FLIGHT_EXEMPT_GLIDING = "gliding"; - private static final String STEP_FLIGHT_EXEMPT_CHUNK = "chunk"; - private static final double VULCAN_297_FLIGHT_F_DECAY = 0.04; - private static final double VULCAN_297_JUMP_A_DECAY = 0.15; - private static final double VULCAN_297_STEP_JUMP_COST = 0.65; - private static final double VULCAN_297_VERTICAL_RECOVERY_COST = 1.0; - private static final double VULCAN_297_FLIGHT_F_LIMIT = 1.6; - private static final double VULCAN_297_JUMP_A_LIMIT = 1.7; - private final Minecraft mc = Minecraft.getInstance(); - private final EnumValue mode = enumSetting("stepMode", "mode", Mode.INSTANT, Mode.values()); - private final NumberValue height = visibleWhen(num("stepHeight", "height", 1.0f, 0.6f, 5.0f), () -> mode.get() == Mode.INSTANT); - private final BooleanValue trim = visibleWhen(bool("stepTrim", "trim", false), () -> mode.get() == Mode.INSTANT); - private final NumberValue simulateJumpOrderStart = - visibleWhen(num("stepSimulateJumpOrderStart", "simulate_jump_order_start", 0, 0, JUMP_ORDER.length - 1), () -> mode.get() == Mode.INSTANT); - private final NumberValue simulateJumpOrderEnd = - visibleWhen(num("stepSimulateJumpOrderEnd", "simulate_jump_order_end", 2, 0, JUMP_ORDER.length - 1), () -> mode.get() == Mode.INSTANT); - private final NumberValue waitTicks = visibleWhen(num("stepWaitTicks", "wait_ticks", 0, 0, 60), () -> mode.get() == Mode.INSTANT); - private final EnumValue packetMode = - visibleWhen(enumSetting("stepPacketMode", "packet_mode", PacketMode.FULL, PacketMode.values()), () -> mode.get() == Mode.INSTANT); - private final BooleanMapValue vulcan297FlightExempts = - visibleWhen(group("stepVulcan297FlightExempts", "vulcan297_flight_exempts", vulcan297FlightExemptDefaults()), () -> mode.get() == Mode.VULCAN_297); - private int ticksWait; - private int vulcanStepCounter; - private int vulcanSequenceTicks; - private boolean vulcanStepping; - private boolean vulcanEvenStep; - private boolean vulcan297Aggressive; - private double vulcan297FlightFRisk; - private double vulcan297JumpARisk; - - private static Map vulcan297FlightExemptDefaults() { - Map defaults = new LinkedHashMap<>(); - defaults.put(STEP_FLIGHT_EXEMPT_LIQUID, true); - defaults.put(STEP_FLIGHT_EXEMPT_WALL, true); - defaults.put(STEP_FLIGHT_EXEMPT_CONDUIT, true); - defaults.put(STEP_FLIGHT_EXEMPT_FARMLAND, true); - defaults.put(STEP_FLIGHT_EXEMPT_SLOW_FALLING, true); - defaults.put(STEP_FLIGHT_EXEMPT_LEVITATION, true); - defaults.put(STEP_FLIGHT_EXEMPT_RIPTIDE, true); - defaults.put(STEP_FLIGHT_EXEMPT_WEB, true); - defaults.put(STEP_FLIGHT_EXEMPT_WATERLOGGED, true); - defaults.put(STEP_FLIGHT_EXEMPT_SHULKER_BOX, true); - defaults.put(STEP_FLIGHT_EXEMPT_SPECTATOR, true); - defaults.put(STEP_FLIGHT_EXEMPT_SLEEPING, true); - defaults.put(STEP_FLIGHT_EXEMPT_SLIME, true); - defaults.put(STEP_FLIGHT_EXEMPT_POWDER_SNOW, true); - defaults.put(STEP_FLIGHT_EXEMPT_SEAGRASS, true); - defaults.put(STEP_FLIGHT_EXEMPT_SCAFFOLDING, true); - defaults.put(STEP_FLIGHT_EXEMPT_CLIMBABLE, true); - defaults.put(STEP_FLIGHT_EXEMPT_SWIMMING, true); - defaults.put(STEP_FLIGHT_EXEMPT_HONEY, true); - defaults.put(STEP_FLIGHT_EXEMPT_SEA_PICKLE, true); - defaults.put(STEP_FLIGHT_EXEMPT_BUBBLE_COLUMN, true); - defaults.put(STEP_FLIGHT_EXEMPT_VEHICLE, true); - defaults.put(STEP_FLIGHT_EXEMPT_KELP, true); - defaults.put(STEP_FLIGHT_EXEMPT_GLIDING, true); - defaults.put(STEP_FLIGHT_EXEMPT_CHUNK, true); - return defaults; - } - - @Override - public void onDisable() { - ticksWait = 0; - resetVulcan(); - vulcan297FlightFRisk = 0.0; - vulcan297JumpARisk = 0.0; - } - - @EventHandler - private void onGameTick(GameTickEvent event) { - if (!isEnabled()) return; - - if (ticksWait > 0) { - ticksWait--; - } - decayVulcan297Risk(); - - if (mode.get() == Mode.VULCAN_286) { - tickVulcan286(); - } else if (mode.get() == Mode.VULCAN_297) { - tickVulcan297(); - } - } - - @EventHandler - private void onMovementInput(MovementInputEvent event) { - if (!isEnabled() || mc.player == null || mc.level == null) return; - - LocalPlayer player = mc.player; - boolean manualJump = isManualJump(event, player); - if (mode.get() == Mode.LEGIT) { - if (canStep(player, 1.0) && !manualJump) { - event.setJump(true); - } - return; - } - - if ((mode.get() != Mode.VULCAN_286 && mode.get() != Mode.VULCAN_297) || vulcanStepping) return; - if (mode.get() == Mode.VULCAN_297 && manualJump) return; - if (mode.get() == Mode.VULCAN_297 && isVulcan297PredictionRiskHigh()) return; - if (!canStep(player, 1.0)) return; - - event.setJump(true); - if (mode.get() == Mode.VULCAN_297) { - vulcan297JumpARisk += VULCAN_297_STEP_JUMP_COST; - vulcan297FlightFRisk += VULCAN_297_STEP_JUMP_COST * 0.5; - } - vulcanStepCounter++; - vulcan297Aggressive = mode.get() == Mode.VULCAN_297 && isVulcan297FlightExempt(player); - vulcanEvenStep = vulcanStepCounter % 2 == 0; - vulcanSequenceTicks = 0; - vulcanStepping = true; - } - - @EventHandler - private void onPlayerStep(PlayerStepEvent event) { - if (!isEnabled() || mode.get() != Mode.INSTANT || ticksWait > 0) return; - event.setHeight(height.get()); - } - - @EventHandler - private void onPlayerStepSuccess(PlayerStepSuccessEvent event) { - if (!isEnabled() || mode.get() != Mode.INSTANT) return; - if (ticksWait > 0 || mc.player == null || mc.getConnection() == null) return; - - LocalPlayer player = mc.player; - double stepHeight = event.getAdjustedVec().y; - if (stepHeight <= 0.5) return; - - int start = Math.min(simulateJumpOrderStart.get(), simulateJumpOrderEnd.get()); - int end = Math.max(simulateJumpOrderStart.get(), simulateJumpOrderEnd.get()); - if (start == 0 && end == 0) { - ticksWait = waitTicks.get(); - return; - } - - player.awardStat(Stats.JUMP); - - double maxY = player.getY(); - double baseY = player.getY() - stepHeight; - for (int i = start; i <= end && i < JUMP_ORDER.length; i++) { - double additionalY = JUMP_ORDER[i]; - if (additionalY == 0.0) continue; - - double y = baseY + additionalY; - if (trim.get()) { - y = Math.min(y, maxY); - } - mc.getConnection().send(movePacket(player, y)); - } - - ticksWait = waitTicks.get(); - } - - private void tickVulcan286() { - if (!vulcanStepping || mc.player == null) return; - - vulcanSequenceTicks++; - LocalPlayer player = mc.player; - tickVulcan286Sequence(player); - } - - private void tickVulcan286Sequence(LocalPlayer player) { - - if (vulcanSequenceTicks == 2) { - if (vulcanEvenStep) { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(withStrafe(new Vec3(velocity.x, 0.24680001947880004, velocity.z), player, 0.2)); - vulcan297FlightFRisk += VULCAN_297_VERTICAL_RECOVERY_COST; - } - return; - } - - if (vulcanSequenceTicks == 3) { - if (vulcanEvenStep) { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(velocity.x, 0.0, velocity.z); - vulcan297FlightFRisk += VULCAN_297_VERTICAL_RECOVERY_COST * 0.5; - } - return; - } - - if (vulcanSequenceTicks >= 4) { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(velocity.x, -0.17, velocity.z); - resetVulcan(); - } - } - - private void tickVulcan297AggressiveSequence(LocalPlayer player) { - if (isVulcan297StepCExempt(player)) { - tickVulcan286Sequence(player); - return; - } - - if (vulcanSequenceTicks == 2) { - if (vulcanEvenStep) { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(withStrafe(new Vec3(velocity.x, 0.24680001947880004, velocity.z), player, 0.2)); - } - return; - } - - if (vulcanSequenceTicks == 3) { - if (vulcanEvenStep) { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(velocity.x, 0.0, velocity.z); - } - return; - } - - if (vulcanSequenceTicks >= 4) { - resetVulcan(); - } - } - - private void tickVulcan297() { - if (!vulcanStepping || mc.player == null) return; - - vulcanSequenceTicks++; - LocalPlayer player = mc.player; - - if (vulcan297Aggressive && isVulcan297FlightExempt(player)) { - tickVulcan297AggressiveSequence(player); - return; - } - - if (player.onGround() && vulcanSequenceTicks > 1 || vulcanSequenceTicks >= 10) { - resetVulcan(); - } - } - - private Packet movePacket(LocalPlayer player, double y) { - return switch (packetMode.get()) { - case FULL -> new ServerboundMovePlayerPacket.PosRot( - player.getX(), - y, - player.getZ(), - player.getYRot(), - player.getXRot(), - false, - player.horizontalCollision - ); - case POSITION_AND_ON_GROUND -> new ServerboundMovePlayerPacket.Pos( - player.getX(), - y, - player.getZ(), - false, - player.horizontalCollision - ); - }; - } - - private boolean canStep(LocalPlayer player, double stepHeight) { - if (player == null || mc.level == null) return false; - if (!player.onGround() || player.isShiftKeyDown() || player.isSpectator()) return false; - if (player.isInWater() || player.isInLava() || player.onClimbable() || player.isPassenger()) return false; - if (!MovementUtil.isMoving()) return false; - - Vec3 offset = horizontalInputOffset(player, 0.36); - if (offset.horizontalDistanceSqr() < 1.0E-7) return false; - - AABB box = player.getBoundingBox(); - AABB forwardBox = box.move(offset.x, 0.0, offset.z); - if (mc.level.noCollision(player, forwardBox)) return false; - - AABB steppedBox = box.move(offset.x, stepHeight, offset.z); - return mc.level.noCollision(player, steppedBox); - } - - private boolean isManualJump(MovementInputEvent event, LocalPlayer player) { - return event.isJump() - || mc.options != null && mc.options.keyJump.isDown() - || player.input != null && player.input.keyPresses.jump(); - } - - private boolean isVulcan297FlightExempt(LocalPlayer player) { - if (player == null || mc.level == null) return false; - - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_LIQUID) && (player.isInWater() || player.isInLava())) - return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_WALL) && player.horizontalCollision) return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_CONDUIT) && player.hasEffect(MobEffects.CONDUIT_POWER)) - return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_SLOW_FALLING) && player.hasEffect(MobEffects.SLOW_FALLING)) - return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_LEVITATION) && player.hasEffect(MobEffects.LEVITATION)) - return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_RIPTIDE) && player.isAutoSpinAttack()) return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_SPECTATOR) && player.isSpectator()) return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_SLEEPING) && player.isSleeping()) return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_CLIMBABLE) && player.onClimbable()) return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_SWIMMING) && player.isSwimming()) return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_VEHICLE) && player.isPassenger()) return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_GLIDING) && player.isFallFlying()) return true; - if (vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_CHUNK) && player.tickCount < 100) return true; - - BlockPos feet = player.blockPosition(); - return isVulcan297FlightExemptBlock(feet) - || isVulcan297FlightExemptBlock(feet.below()) - || isVulcan297FlightExemptBlock(feet.above()); - } - - private boolean isVulcan297FlightExemptBlock(BlockPos pos) { - if (mc.level == null) return false; - - Block block = mc.level.getBlockState(pos).getBlock(); - return vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_FARMLAND) && block == Blocks.FARMLAND - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_WEB) && block == Blocks.COBWEB - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_WATERLOGGED) && mc.level.getBlockState(pos).getFluidState().isSource() - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_SHULKER_BOX) && block == Blocks.SHULKER_BOX - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_SLIME) && block == Blocks.SLIME_BLOCK - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_POWDER_SNOW) && block == Blocks.POWDER_SNOW - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_SEAGRASS) && (block == Blocks.SEAGRASS || block == Blocks.TALL_SEAGRASS) - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_SCAFFOLDING) && block == Blocks.SCAFFOLDING - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_HONEY) && block == Blocks.HONEY_BLOCK - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_SEA_PICKLE) && block == Blocks.SEA_PICKLE - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_BUBBLE_COLUMN) && block == Blocks.BUBBLE_COLUMN - || vulcan297FlightExempts.get(STEP_FLIGHT_EXEMPT_KELP) && (block == Blocks.KELP || block == Blocks.KELP_PLANT); - } - - private boolean isVulcan297StepCExempt(LocalPlayer player) { - if (player == null || mc.level == null) return false; - - if (player.getAbilities().instabuild || player.getAbilities().flying) return true; - if (player.isFallFlying() || player.isInWater() || player.isInLava()) return true; - if (player.isPassenger() || player.isAutoSpinAttack() || player.isSleeping()) return true; - if (player.hurtTime > 0 || player.hasEffect(MobEffects.JUMP_BOOST) || player.onClimbable()) return true; - - BlockPos feet = player.blockPosition(); - return isVulcan297StepCExemptBlock(feet) - || isVulcan297StepCExemptBlock(feet.below()) - || isVulcan297StepCExemptBlock(feet.above()); - } - - private boolean isVulcan297StepCExemptBlock(BlockPos pos) { - if (mc.level == null) return false; - - Block block = mc.level.getBlockState(pos).getBlock(); - return block == Blocks.SLIME_BLOCK - || block == Blocks.ANVIL - || block == Blocks.END_ROD - || block == Blocks.IRON_CHAIN - || block == Blocks.POINTED_DRIPSTONE - || block == Blocks.SCAFFOLDING - || block == Blocks.POWDER_SNOW - || block == Blocks.SNOW; - } - - private boolean isVulcan297PredictionRiskHigh() { - return vulcan297FlightFRisk >= VULCAN_297_FLIGHT_F_LIMIT - || vulcan297JumpARisk >= VULCAN_297_JUMP_A_LIMIT; - } - - private void decayVulcan297Risk() { - if (vulcan297FlightFRisk > 0.0) { - vulcan297FlightFRisk = Math.max(0.0, vulcan297FlightFRisk - VULCAN_297_FLIGHT_F_DECAY); - } - if (vulcan297JumpARisk > 0.0) { - vulcan297JumpARisk = Math.max(0.0, vulcan297JumpARisk - VULCAN_297_JUMP_A_DECAY); - } - } - - private Vec3 horizontalInputOffset(LocalPlayer player, double length) { - if (player.input == null) return Vec3.ZERO; - - Vec2 input = player.input.getMoveVector(); - if (input.lengthSquared() <= 1.0E-7f) return Vec3.ZERO; - - float yaw = player.getYRot(); - double rad = Math.toRadians(yaw); - double sin = Math.sin(rad); - double cos = Math.cos(rad); - double x = input.x * cos - input.y * sin; - double z = input.y * cos + input.x * sin; - Vec3 out = new Vec3(x, 0.0, z); - return out.lengthSqr() > 1.0 ? out.normalize().scale(length) : out.scale(length); - } - - private Vec3 withStrafe(Vec3 velocity, LocalPlayer player, double speed) { - if (player.input == null) return velocity; - Vec2 input = player.input.getMoveVector(); - Vec3 movementInput = new Vec3(input.x, 0.0, input.y); - return MovementUtil.withStrafe(velocity, movementInput, player.getYRot(), speed, 1.0); - } - - private void resetVulcan() { - vulcanStepping = false; - vulcanSequenceTicks = 0; - vulcanEvenStep = false; - vulcan297Aggressive = false; - } - - public enum Mode { - INSTANT, - LEGIT, - VULCAN_286, - VULCAN_297 - } - - public enum PacketMode { - FULL, - POSITION_AND_ON_GROUND - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Strafe.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Strafe.java deleted file mode 100644 index e37dbc4..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Strafe.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntitySelector; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.projectile.ProjectileUtil; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.CrosshairTargetUpdateEvent; -import dev.loki.lovisual.events.impl.GameTickEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.KillAura; -import dev.loki.lovisual.features.module.modules.visuals.Freecam; -import dev.loki.lovisual.util.OmniItemUtils; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.player.MovementUtil; - -import java.util.List; - -//todo Description -@ModuleInfo( - id = "strafe", - displayName = "Strafe", - category = ModuleCategory.MOVEMENT -) -public final class Strafe extends Module { - - private static final int ROTATION_PRIORITY = 15; - - private final Minecraft mc = Minecraft.getInstance(); - private final EnumValue mode = enumMode("mode", Mode.MATRIX); - private final NumberValue speed = - visibleWhen(num("speed", 0.42f, 0.0f, 1.0f), this::isMatrixMode); - private final NumberValue grimEffectiveDegrees = - visibleWhen(num("grim_effective_degrees", 45.0f, 0.0f, 90.0f), this::isGrimMode); - private final BooleanValue grimOverrideCrosshairTarget = - visibleWhen(bool("grim_override_crosshair_target", false), this::isGrimMode); - private float lastYaw; - private float lastPitch; - - private static float resolveMatrixYaw(LocalPlayer player, float fallbackYaw) { - if (player == null) { - return fallbackYaw; - } - return Mth.wrapDegrees(MovementUtil.getMovementDirectionYaw(player, fallbackYaw)); - } - - private static void setHorizontalVelocity(LocalPlayer player, float yaw, double speed) { - double x = Math.cos(Math.toRadians(yaw + 90.0f)) * speed; - double z = Math.sin(Math.toRadians(yaw + 90.0f)) * speed; - player.setDeltaMovement(x, player.getDeltaMovement().y, z); - } - - @EventHandler(priority = 2000) - private void onGameTick(GameTickEvent event) { - LocalPlayer player = mc.player; - if (player == null || mc.level == null) { - return; - } - - boolean moving = MovementUtil.isMoving(); - float yaw = player.getYRot(); - - if (isMatrixMode()) { - handleMatrixMode(player, moving, yaw); - lastYaw = yaw; - lastPitch = 0.0f; - } else if (isGrimMode()) { - handleGrimMode(player, moving, yaw); - lastYaw = yaw; - lastPitch = 0.0f; - } - } - - @EventHandler(priority = 2000) - private void onCrosshairTargetUpdate(CrosshairTargetUpdateEvent event) { - LocalPlayer player = mc.player; - if (!shouldOverrideGrimCrosshair(player)) { - return; - } - - float yaw = resolveGrimYaw(player, player.getYRot()); - float pitch = player.getXRot(); - HitResult hitResult = raycastRotationPoint(player, event.getTickDelta(), yaw, pitch); - event.setHitResult(hitResult); - event.setTargetedEntity(hitResult instanceof EntityHitResult entityHit ? entityHit.getEntity() : null); - } - - @Override - public void onEnable() { - LocalPlayer player = mc.player; - lastYaw = player != null ? player.getYRot() : 0.0f; - lastPitch = player != null ? player.getXRot() : 0.0f; - } - - @Override - public void onDisable() { - RotationManager.INSTANCE.clear(this); - } - - private void handleMatrixMode(LocalPlayer player, boolean moving, float yaw) { - if (moving) { - yaw = resolveMatrixYaw(player, yaw); - double motion = speed.get() * 1.5f; - setHorizontalVelocity(player, yaw, motion); - } else { - setHorizontalVelocity(player, yaw, 0.0); - } - - player.setDeltaMovement(player.getDeltaMovement().x, player.getDeltaMovement().y, player.getDeltaMovement().z); - } - - private void handleGrimMode(LocalPlayer player, boolean moving, float yaw) { - if (!moving) { - return; - } - if (OmniItemUtils.isProjectileWeaponInHand(player)) { - return; - } - - yaw = resolveGrimYaw(player, yaw); - KillAura killAura = Modules.get(KillAura.class); - if (killAura != null && killAura.getCurrentTarget() != null) { - return; - } - - RotationTarget target = new RotationTarget( - new Rotation(yaw, player.getXRot(), true), - player, - List.of(), - 1, - 1.0f, - false, - MovementCorrection.SILENT, - null - ); - RotationManager.INSTANCE.setRotationTarget(target, ROTATION_PRIORITY, this); - } - - private boolean shouldOverrideGrimCrosshair(LocalPlayer player) { - if (!isEnabled() - || !isGrimMode() - || !grimOverrideCrosshairTarget.get() - || !canOperate(player) - || !MovementUtil.isMoving()) { - return false; - } - if (OmniItemUtils.isProjectileWeaponInHand(player)) { - return false; - } - KillAura killAura = Modules.get(KillAura.class); - return killAura == null || killAura.getCurrentTarget() == null; - } - - private HitResult raycastRotationPoint(LocalPlayer player, float tickDelta, float yaw, float pitch) { - Vec3 start = player.getEyePosition(tickDelta); - Vec3 direction = Vec3.directionFromRotation(pitch, yaw).normalize(); - - double entityRange = player.entityInteractionRange(); - double blockRange = player.blockInteractionRange(); - Vec3 blockEnd = start.add(direction.scale(blockRange)); - - HitResult blockHit = mc.level.clip(new ClipContext( - start, - blockEnd, - ClipContext.Block.OUTLINE, - ClipContext.Fluid.NONE, - player - )); - - double entityRangeSq = entityRange * entityRange; - if (blockHit.getType() != HitResult.Type.MISS) { - entityRangeSq = Math.min(entityRangeSq, start.distanceToSqr(blockHit.getLocation())); - } - - Vec3 entityEnd = start.add(direction.scale(entityRange)); - EntityHitResult entityHit = ProjectileUtil.getEntityHitResult( - player, - start, - entityEnd, - player.getBoundingBox().expandTowards(direction.scale(entityRange)).inflate(1.0), - this::isCrosshairCandidate, - entityRangeSq - ); - - return entityHit != null ? entityHit : blockHit; - } - - private boolean isCrosshairCandidate(Entity entity) { - if (!EntitySelector.CAN_BE_PICKED.test(entity)) { - return false; - } - return entity instanceof LivingEntity living && living.isAlive(); - } - - private float resolveGrimYaw(LocalPlayer player, float yaw) { - if (player == null || mc.options == null) { - return yaw; - } - - boolean left = mc.options.keyLeft.isDown(); - boolean right = mc.options.keyRight.isDown(); - if (left == right) { - return yaw; - } - - float delta = left ? -grimEffectiveDegrees.get() : grimEffectiveDegrees.get(); - return yaw + delta; - } - - private boolean isMatrixMode() { - return mode.get() == Mode.MATRIX; - } - - private boolean isGrimMode() { - return mode.get() == Mode.GRIM; - } - - private boolean canOperate(LocalPlayer player) { - return player != null && !isFreecamActive(); - } - - private boolean isFreecamActive() { - return Modules.get(Freecam.class) != null && Modules.get(Freecam.class).isEnabled(); - } - - private enum Mode { - MATRIX, - GRIM - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/SuperFirework.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/SuperFirework.java deleted file mode 100644 index 2803d04..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/SuperFirework.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.FireworkEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.data.Rotation; - -//todo Description -@ModuleInfo( - id = "superfirework", - displayName = "SuperFirework", - category = ModuleCategory.MOVEMENT -) -public class SuperFirework extends Module { - - private final EnumValue mode = - enumSetting("superfirework_mode", "mode", FireworkMode.GRIM, FireworkMode.GRIM, FireworkMode.CUSTOM); - private final NumberValue speed = - visibleWhen(num("superfirework_speed", "speed", 20.0f, 1.0f, 100.0f), this::isCustomMode); - - private static Rotation resolveRotation(LocalPlayer player) { - Rotation rotation = RotationManager.INSTANCE.getCurrentRotation(); - if (rotation != null) { - return rotation; - } - return new Rotation(player.getYRot(), player.getXRot(), true); - } - - private static Rotation resolveMoveRotation(LocalPlayer player) { - return RotationManager.INSTANCE.getMovementRotation(); - } - - @EventHandler - public void onFirework(FireworkEvent event) { - LocalPlayer player = Minecraft.getInstance().player; - if (player == null) { - return; - } - - Rotation rotation = resolveRotation(player); - Rotation moveRotation = resolveMoveRotation(player); - float yaw = rotation.yaw(); - float movePitch = moveRotation.pitch(); - - if (mode.get() == FireworkMode.GRIM) { - int ff = yaw > 0.0f ? 45 : -45; - double acceleration = Math.abs((yaw + ff) % 90.0 - ff) / 45.0; - double boost = 1.0 + (0.3 * acceleration * acceleration); - boolean yAcceleration = Math.abs(movePitch) > 60.0f; - - Vec3 vector = event.getVector(); - event.setVector(new Vec3( - vector.x * boost, - yAcceleration ? vector.y * boost : vector.y, - vector.z * boost - )); - return; - } - - if (mode.get() == FireworkMode.CUSTOM) { - int ff = yaw > 0.0f ? 45 : -45; - double acceleration = Math.abs((yaw + ff) % 90.0 - ff) / 45.0; - double rotationBoost = 1.0 + (0.3 * acceleration * acceleration); - boolean yAcceleration = Math.abs(movePitch) > 60.0f; - - Vec3 direction = moveRotation.directionVector(); - float customSpeed = speed.get() / 20.0f; - double finalSpeed = customSpeed * rotationBoost; - - event.setVector(new Vec3( - direction.x * finalSpeed, - yAcceleration ? direction.y * finalSpeed : direction.y * customSpeed, - direction.z * finalSpeed - )); - } - } - - private boolean isCustomMode() { - return mode.get() == FireworkMode.CUSTOM; - } - - @Getter - @RequiredArgsConstructor - private enum FireworkMode implements EnumValue.IdProvider { - GRIM("Grim"), - CUSTOM("Custom"); - - private final String id; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/TargetStrafe.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/TargetStrafe.java deleted file mode 100644 index de00b35..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/TargetStrafe.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.GameTickEvent; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.KillAura; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.combat.SprintController; - -//todo Description -@ModuleInfo( - id = "targetstrafe", - displayName = "TargetStrafe", - category = ModuleCategory.MOVEMENT -) -public final class TargetStrafe extends Module { - - private final Minecraft mc = Minecraft.getInstance(); - private final EnumValue mode = - enumMode("mode", StrafeMode.MATRIX, StrafeMode.MATRIX, StrafeMode.GRIM); - private final EnumValue grimPointType = - visibleWhen(enumMode("grim_point_type", PointType.CUBE, PointType.CUBE, PointType.CENTER, PointType.CIRCLE), this::isGrimMode); - private final NumberValue grimRadius = - visibleWhen(num("grim_radius", 0.87f, 0.1f, 1.5f), this::usesGrimRadius); - private final EnumValue matrixPointType = - visibleWhen(enumMode("matrix_point_type", PointType.CIRCLE, PointType.CUBE, PointType.CIRCLE), this::isMatrixMode); - private final NumberValue radius = - visibleWhen(num("radius", 2.5f, 0.1f, 7.0f), this::isMatrixMode); - private final NumberValue speed = - visibleWhen(num("speed", 0.3f, 0.1f, 1.0f), this::isMatrixMode); - private final BooleanValue autoJump = - bool("auto_jump", true); - private final BooleanValue onlyKeyPressed = - bool("only_key_pressed", false); - private final BooleanValue inFrontOfTarget = - bool("in_front_of_target", false); - private final EnumValue directionMode = - enumMode("direction_mode", DirectionMode.CLOCKWISE, - DirectionMode.CLOCKWISE, DirectionMode.COUNTERCLOCKWISE, DirectionMode.RANDOM); - private int pointIndex; - - private static float resolveControlYaw() { - var rotation = RotationManager.INSTANCE.getCurrentRotation(); - if (rotation != null) { - return rotation.yaw(); - } - - LocalPlayer player = Minecraft.getInstance().player; - return player != null ? player.getYRot() : 0.0f; - } - - private static void setHorizontalVelocity(LocalPlayer player, float yaw, double speed) { - player.setDeltaMovement( - -Math.sin(Math.toRadians(yaw)) * speed, - player.getDeltaMovement().y, - Math.cos(Math.toRadians(yaw)) * speed - ); - } - - private static boolean hasForwardMovement(float angleDiff) { - return angleDiff > -67.5f && angleDiff < 67.5f; - } - - @Override - public void onEnable() { - pointIndex = 0; - } - - @EventHandler - private void onMovementInput(MovementInputEvent event) { - if (!isEnabled() || !isGrimMode()) return; - - LocalPlayer player = mc.player; - LivingEntity target = currentTarget(); - if (player == null || mc.level == null || target == null || !target.isAlive()) return; - if (onlyKeyPressed.get() && !isAnyMovementKeyPressed()) return; - - Vec3 playerPos = player.position(); - Vec3 targetPos = target.position(); - double r = grimRadius.get(); - int directionMultiplier = resolveDirectionMultiplier(); - - Vec3 nextPoint; - if (inFrontOfTarget.get()) { - float targetYaw = target.getYRot(); - if (grimPointType.get() == PointType.CENTER) { - nextPoint = targetPos.add( - -Math.sin(Math.toRadians(targetYaw)) * r * directionMultiplier, - 0.0, - Math.cos(Math.toRadians(targetYaw)) * r * directionMultiplier - ); - } else { - double offset = Math.cos(System.currentTimeMillis() / 500.0) * r * directionMultiplier; - nextPoint = targetPos.add( - -Math.sin(Math.toRadians(targetYaw)) * r + Math.cos(Math.toRadians(targetYaw)) * offset, - 0.0, - Math.cos(Math.toRadians(targetYaw)) * r + Math.sin(Math.toRadians(targetYaw)) * offset - ); - } - } else { - nextPoint = switch (grimPointType.get()) { - case CUBE -> nextCubePoint(playerPos, targetPos, r, directionMultiplier); - case CIRCLE -> nextCirclePoint(playerPos, targetPos, r, directionMultiplier); - case CENTER -> new Vec3(targetPos.x, playerPos.y, targetPos.z); - }; - } - - Vec3 direction = nextPoint.subtract(playerPos); - if (direction.lengthSqr() < 1.0E-6) return; - direction = direction.normalize(); - - float yaw = resolveControlYaw(); - float movementAngle = (float) Math.toDegrees(Math.atan2(direction.z, direction.x)) - 90.0f; - float angleDiff = Mth.wrapDegrees(movementAngle - yaw); - - boolean forward = false; - boolean backward = false; - boolean left = false; - boolean right = false; - - if (angleDiff >= -22.5f && angleDiff < 22.5f) { - forward = true; - } else if (angleDiff >= 22.5f && angleDiff < 67.5f) { - forward = true; - right = true; - } else if (angleDiff >= 67.5f && angleDiff < 112.5f) { - right = true; - } else if (angleDiff >= 112.5f && angleDiff < 157.5f) { - backward = true; - right = true; - } else if (angleDiff >= -67.5f && angleDiff < -22.5f) { - forward = true; - left = true; - } else if (angleDiff >= -112.5f && angleDiff < -67.5f) { - left = true; - } else if (angleDiff >= -157.5f && angleDiff < -112.5f) { - backward = true; - left = true; - } else { - backward = true; - } - - event.setForward(forward); - event.setBackward(backward); - event.setLeft(left); - event.setRight(right); - event.setSprint(SprintController.INSTANCE.canStartSprinting(player) - && hasForwardMovement(angleDiff)); - - if (autoJump.get() && player.onGround()) { - event.setJump(true); - } - } - - @EventHandler - private void onTick(GameTickEvent event) { - if (!isEnabled() || !isMatrixMode()) return; - - LocalPlayer player = mc.player; - LivingEntity target = currentTarget(); - if (player == null || mc.level == null || target == null || !target.isAlive()) return; - if (onlyKeyPressed.get() && !isAnyMovementKeyPressed()) return; - - Vec3 playerPos = player.position(); - Vec3 targetPos = target.position(); - double r = radius.get(); - - if (autoJump.get() && player.onGround()) { - player.jumpFromGround(); - } - - int directionMultiplier = resolveDirectionMultiplier(); - - if (inFrontOfTarget.get()) { - float targetYaw = target.getYRot(); - double x = targetPos.x - Math.sin(Math.toRadians(targetYaw)) * r * directionMultiplier; - double z = targetPos.z + Math.cos(Math.toRadians(targetYaw)) * r * directionMultiplier; - - float yaw = (float) Math.toDegrees(Math.atan2(z - playerPos.z, x - playerPos.x)) - 90.0f; - setHorizontalVelocity(player, yaw, speed.get()); - requestSprintForMovementYaw(player, yaw); - return; - } - - if (matrixPointType.get() == PointType.CUBE) { - Vec3 nextPoint = nextCubePoint(playerPos, targetPos, r, directionMultiplier); - Vec3 dirVec = nextPoint.subtract(playerPos); - if (dirVec.lengthSqr() < 1.0E-6) return; - dirVec = dirVec.normalize(); - - float yaw = (float) Math.toDegrees(Math.atan2(dirVec.z, dirVec.x)) - 90.0f; - setHorizontalVelocity(player, yaw, speed.get()); - requestSprintForMovementYaw(player, yaw); - return; - } - - double angle = Math.atan2(playerPos.z - targetPos.z, playerPos.x - targetPos.x); - angle += directionMultiplier * speed.get() / Math.max(playerPos.distanceTo(targetPos), r); - - double x = targetPos.x + r * Math.cos(angle); - double z = targetPos.z + r * Math.sin(angle); - float yaw = (float) Math.toDegrees(Math.atan2(z - playerPos.z, x - playerPos.x)) - 90.0f; - setHorizontalVelocity(player, yaw, speed.get()); - requestSprintForMovementYaw(player, yaw); - } - - private LivingEntity currentTarget() { - KillAura killAura = Modules.get(KillAura.class); - if (killAura == null || !killAura.isEnabled()) { - return null; - } - return killAura.getCurrentTarget(); - } - - public boolean shouldDisableAuraFreeCorrection() { - return isEnabled() && isGrimMode() && currentTarget() != null; - } - - private int resolveDirectionMultiplier() { - return switch (directionMode.get()) { - case COUNTERCLOCKWISE -> -1; - case RANDOM -> ((System.currentTimeMillis() / 3000L) % 2L == 0L) ? 1 : -1; - case CLOCKWISE -> 1; - }; - } - - private Vec3 nextCubePoint(Vec3 playerPos, Vec3 targetPos, double radius, int directionMultiplier) { - Vec3[] points = new Vec3[]{ - new Vec3(targetPos.x - radius, playerPos.y, targetPos.z - radius), - new Vec3(targetPos.x - radius, playerPos.y, targetPos.z + radius), - new Vec3(targetPos.x + radius, playerPos.y, targetPos.z + radius), - new Vec3(targetPos.x + radius, playerPos.y, targetPos.z - radius) - }; - - if (playerPos.distanceTo(points[pointIndex]) < 0.5) { - pointIndex = (pointIndex + directionMultiplier + points.length) % points.length; - } - - return points[pointIndex]; - } - - private Vec3 nextCirclePoint(Vec3 playerPos, Vec3 targetPos, double radius, int directionMultiplier) { - double baseAngle = (System.currentTimeMillis() % 3600L) / 3600.0 * 4.0 * Math.PI; - double angle = directionMultiplier > 0 ? baseAngle : (2.0 * Math.PI - baseAngle); - return new Vec3( - targetPos.x + Math.cos(angle) * radius, - playerPos.y, - targetPos.z + Math.sin(angle) * radius - ); - } - - private boolean isAnyMovementKeyPressed() { - return mc.options != null - && (mc.options.keyUp.isDown() - || mc.options.keyDown.isDown() - || mc.options.keyLeft.isDown() - || mc.options.keyRight.isDown()); - } - - private void requestSprintForMovementYaw(LocalPlayer player, float movementYaw) { - float controlYaw = resolveControlYaw(); - float angleDiff = Mth.wrapDegrees(movementYaw - controlYaw); - SprintController.INSTANCE.requestStartSprinting(mc, player, hasForwardMovement(angleDiff)); - } - - private boolean isMatrixMode() { - return mode.get() == StrafeMode.MATRIX; - } - - private boolean isGrimMode() { - return mode.get() == StrafeMode.GRIM; - } - - private boolean usesGrimRadius() { - return isGrimMode() && (grimPointType.get() == PointType.CUBE || grimPointType.get() == PointType.CIRCLE); - } - - @Getter - @RequiredArgsConstructor - private enum StrafeMode implements EnumValue.IdProvider { - MATRIX("Matrix"), - GRIM("Grim"); - - private final String id; - } - - @Getter - @RequiredArgsConstructor - private enum PointType implements EnumValue.IdProvider { - CUBE("Cube"), - CENTER("Center"), - CIRCLE("Circle"); - - private final String id; - } - - @Getter - @RequiredArgsConstructor - private enum DirectionMode implements EnumValue.IdProvider { - CLOCKWISE("Clockwise"), - COUNTERCLOCKWISE("Counterclockwise"), - RANDOM("Random"); - - private final String id; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Timer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Timer.java deleted file mode 100644 index 975399b..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Timer.java +++ /dev/null @@ -1,429 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.util.time.TimerController; -import net.minecraft.client.Minecraft; -import net.minecraft.network.protocol.common.ClientboundPingPacket; -import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket; -import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; -import net.minecraft.util.Mth; -import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.EventSync; -import dev.loki.lovisual.events.impl.PacketEvent; -import dev.loki.lovisual.events.impl.PostPlayerUpdateEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.util.input.KeyManager; -import dev.loki.lovisual.util.player.MovementUtil; - -//todo Description -@ModuleInfo( - id = "timer", - displayName = "Timer", - category = ModuleCategory.MOVEMENT -) -public class Timer extends Module { - - // ── Vulcan TimerA sliding-window model ─────────────────────────────────────── - // - // TimerA uses a 50-sample sliding FIFO window (EvictingQueue). - // Each add() evicts the OLDEST entry. The oldest entries are the SLOW packets - // from BEFORE the boost, not the fast packets we just added. This is the key: - // - // After N fast packets, window = [S×(50-N), F×N] (old slow | new fast) - // When we send slow: evict oldest (OLD SLOW), not the fast ones. - // Fast packets only leave after (50-N) slow packets flush the old slow first. - // REAL tail = 50 slow packets (not N or 14 as the broken counter model said). - // - // Correct approach: track the exact window state with a circular boolean buffer. - // canBoost = fastCount < kMax where kMax = floor(2.5S / (1.05*(S-1))) - // - // For S=2.64: kMax=3. With fastCount ≤ 2 (boost condition fastCount < kMax): - // avgDelay = (2×18.9 + 48×50)/50 = 48.76ms → speed = 1.025 << 1.05. SAFE. - // For S=2.0: kMax=4, fastCount ≤ 3. speed ≈ 1.031. SAFE. - // - // Energy bar = 1 - fastCount/kMax. Full = all window slots slow. Empty = at kMax. - private static final int VULCAN_WINDOW_SIZE = 50; - private static final boolean[] vulcanWindow = new boolean[VULCAN_WINDOW_SIZE]; // true=fast - // legacy fields kept so onDisable compiles without changing other code paths - @SuppressWarnings("unused") - private static final float timerABuffer = 0f; - @SuppressWarnings("unused") - private static final float fastInWindow = 0f; - @SuppressWarnings("unused") - private static final boolean vulcanBoostPhase = false; - public static float energy = 0f; - public static float yaw; - public static float pitch; - private static int vulcanWindowHead = 0; // next write position (circular) - private static int vulcanWindowCount = 0; // filled slots 0..50 - private static int vulcanFastCount = 0; // # fast entries currently in window - private static double prevPosX; - private static double prevPosY; - private static double prevPosZ; - private static float tickTimer = 1f; - private static float externalTickTimer = 1f; - private final EnumValue mode = - enumMode("mode", Mode.NORMAL, Mode.values()); - private final BooleanValue old = - visibleWhen(bool("old", false), () -> mode.get() == Mode.MATRIX); - private final NumberValue speed = - visibleWhen(num("speed", 2.0, 0.1, 10.0), () -> mode.get() != Mode.SHIFT); - private final NumberValue shiftTicks = - visibleWhen(num("shift_ticks", 10, 1, 40), () -> mode.get() == Mode.SHIFT); - private final KeyBindValue boostKey = - visibleWhen(bind("boost_key", "NONE", BindMode.HOLD), - () -> mode.get() == Mode.GRIM || mode.get() == Mode.GRIM_CONCEPT || mode.get() == Mode.VULCAN); - private final NumberValue grimFillTime = - visibleWhen(num("grim_fill_time", 20.0, 1.0, 120.0), () -> mode.get() == Mode.GRIM_CONCEPT); - private final NumberValue grimConsumeMult = - visibleWhen(num("grim_consume_mult", 10.0, 1.0, 20.0), () -> mode.get() == Mode.GRIM_CONCEPT); - private final EnumValue onFlag = - enumMode("on_flag", OnFlag.RESET, OnFlag.values()); - private long cancelTime; - private long lastSetbackTime = 0L; - private String lastBoostCombo = "NONE"; - private long lastPingTime = 0L; - - public static float getEnergy01() { - return Mth.clamp(energy, 0f, 1f); - } - - public static float getTickTimer() { - float controllerTimer = TimerController.getTimerSpeed(); - if (tickTimer != 1f) return tickTimer; - return externalTickTimer == 1f ? controllerTimer : externalTickTimer; - } - - public static void setExternalTickTimer(float timer) { - if (Float.isNaN(timer) || Float.isInfinite(timer)) { - clearExternalTickTimer(); - return; - } - externalTickTimer = Mth.clamp(timer, 0.1f, 10.0f); - TimerController.requestTimerSpeed( - externalTickTimer, - TimerController.IMPORTANT_FOR_USAGE_1, - Timer.class - ); - } - - public static void clearExternalTickTimer() { - externalTickTimer = 1f; - TimerController.clear(Timer.class); - } - - @Override - public void onEnable() { - tickTimer = 1f; - externalTickTimer = 1f; - if (mode.get() == Mode.VULCAN) { - vulcanWindowHead = 0; - vulcanWindowCount = 0; - vulcanFastCount = 0; - java.util.Arrays.fill(vulcanWindow, false); - energy = 1f; - } else if (mode.get() != Mode.MATRIX) { - energy = 0f; - } - if (mode.get() == Mode.GRIM || mode.get() == Mode.GRIM_CONCEPT) { - cancelTime = System.currentTimeMillis(); - lastPingTime = 0L; - } - ensureBoostBind(); - } - - @Override - public void onDisable() { - tickTimer = 1f; - externalTickTimer = 1f; - vulcanWindowHead = 0; - vulcanWindowCount = 0; - vulcanFastCount = 0; - java.util.Arrays.fill(vulcanWindow, false); - } - - @Override - public void onTick() { - ensureBoostBind(); - - switch (mode.get()) { - case NORMAL -> tickTimer = speed.get().floatValue(); - case MATRIX -> { - if (!MovementUtil.isMoving()) { - tickTimer = 1f; - return; - } - - tickTimer = Math.max(speed.get().floatValue(), 1f); - - if (energy > 0f) { - float drain = (float) ((0.1f * speed.get()) - 0.1f); - energy = Mth.clamp(energy - drain, 0f, 1f); - } else { - setEnabled(false); - } - } - case GRIM -> { - if (energy <= 0f || !isBoostHeld() || getSetbackAge() < 2000L) { - tickTimer = 1f; - return; - } - - tickTimer = Math.max(speed.get().floatValue(), 1f); - float drain = (float) ((0.0025f * speed.get()) - 0.0025f); - energy = Mth.clamp(energy - drain, 0f, 1f); - } - case GRIM_CONCEPT -> { - if (energy <= 0f || !isBoostHeld() || getSetbackAge() < 2000L) { - tickTimer = 1f; - return; - } - - tickTimer = Math.max(speed.get().floatValue(), 1f); - float drain = (float) ((0.0025f * speed.get()) - 0.0025f); - float mult = grimConsumeMult.get().floatValue(); - if (mult < 0f) mult = 0f; - energy = Mth.clamp(energy - drain * mult, 0f, 1f); - } - case SHIFT -> tickTimer = 1f; - case VULCAN -> { - // Correct model: circular buffer tracks exactly which of the last 50 - // packets were fast. Vulcan's EvictingQueue evicts the OLDEST entry — - // after N fast packets the window is [S×(50-N), F×N], so slow packets - // evict old SLOW first; fast packets only leave after (50-N) slow packets. - // - // Safe k_max = floor(2.5*S / (1.05*(S-1))): - // S=2.64 → kMax=3, avgDelay at k=2: 48.76ms, speed=1.025 < 1.05 ✓ - // S=2.0 → kMax=4, avgDelay at k=3: 48.5ms, speed=1.031 < 1.05 ✓ - // - // We boost when fastCount < kMax (strictly). After boost, fastCount rises - // to kMax and we stop. Fast entries leave the window only after (50-kMax) - // subsequent slow packets flush the initial slow buffer out. - - boolean held = isBoostHeld(); - boolean setbackRecent = getSetbackAge() < 500L; - float s = speed.get().floatValue(); - - // kMax: max fast packets allowed in 50-sample window at speed S - int kMax = (s <= 1.001f) ? 0 : (int) (2.5f * s / (1.05f * (s - 1f))); - if (kMax <= 0) kMax = 0; - - boolean canBoost = held && !setbackRecent && kMax > 0 && vulcanFastCount < kMax; - - if (canBoost) { - tickTimer = Math.max(s, 1f); - vulcanEvalWindow(true); - } else { - tickTimer = 1f; - vulcanEvalWindow(false); - } - - // Energy: 1.0 = window clean (fastCount=0), 0.0 = budget used (fastCount=kMax) - energy = (kMax > 0) - ? Mth.clamp(1f - (float) vulcanFastCount / kMax, 0f, 1f) - : 0f; - } - } - } - - @EventHandler - public void onPacketReceive(PacketEvent.Receive e) { - if (mode.get() == Mode.GRIM) { - if (e.getPacket() instanceof ClientboundPingPacket && getSetbackAge() > 2000L) { - if (System.currentTimeMillis() - cancelTime > 25000L) { - cancelTime = System.currentTimeMillis(); - energy = 0f; - return; - } - - if (!MovementUtil.isMoving()) { - energy = Mth.clamp(energy + 0.005f, 0f, 1f); - } - - e.cancel(); - } - } - if (mode.get() == Mode.GRIM_CONCEPT) { - if (e.getPacket() instanceof ClientboundPingPacket && getSetbackAge() > 2000L) { - long now = System.currentTimeMillis(); - if (now - cancelTime > 25000L) { - cancelTime = now; - energy = 0f; - lastPingTime = now; - return; - } - - if (lastPingTime <= 0L) { - lastPingTime = now; - } - - if (!MovementUtil.isMoving()) { - double fillSeconds = grimFillTime.get(); - if (fillSeconds < 1.0) fillSeconds = 1.0; - double delta = (now - lastPingTime) / (fillSeconds * 1000.0); - if (delta > 0.0) { - energy = Mth.clamp(energy + (float) delta, 0f, 1f); - } - } - - lastPingTime = now; - e.cancel(); - } - } - - if (e.getPacket() instanceof ClientboundPlayerPositionPacket) { - lastSetbackTime = System.currentTimeMillis(); - if (mode.get() == Mode.VULCAN) { - // Server correction inserts a 150ms sample into Vulcan's window — helps. - // Reset our circular buffer: assume server state is now clean. - tickTimer = 1f; - vulcanWindowHead = 0; - vulcanWindowCount = 0; - vulcanFastCount = 0; - java.util.Arrays.fill(vulcanWindow, false); - energy = 1f; - if (onFlag.get() == OnFlag.DISABLE) { - setEnabled(false); - } - } else { - switch (onFlag.get()) { - case RESET -> { - tickTimer = 1f; - energy = 0f; - } - case DISABLE -> { - energy = 0f; - setEnabled(false); - } - case NONE -> { - } - } - } - } - - if (e.getPacket() instanceof ClientboundSetEntityMotionPacket velo - && (mode.get() == Mode.GRIM || mode.get() == Mode.GRIM_CONCEPT)) { - Minecraft mc = Minecraft.getInstance(); - if (mc != null && mc.player != null && velo.id() == mc.player.getId()) { - tickTimer = 1f; - energy = 0f; - lastSetbackTime = System.currentTimeMillis(); - } - } - } - - @EventHandler - public void onPostPlayerUpdate(PostPlayerUpdateEvent event) { - if (mode.get() != Mode.SHIFT) return; - - if (energy < 0.9f) { - setEnabled(false); - return; - } - - event.cancel(); - event.setIterations(shiftTicks.get()); - setEnabled(false); - } - - @EventHandler - public void onSync(EventSync e) { - if (mode.get() == Mode.MATRIX) { - float delta = notMoving() ? 0.025f : (old.get() ? -0.005f : 0f); - energy = Mth.clamp(energy + delta, 0f, 1f); - } - - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return; - - prevPosX = mc.player.getX(); - prevPosY = mc.player.getY(); - prevPosZ = mc.player.getZ(); - yaw = mc.player.getYRot(); - pitch = mc.player.getXRot(); - } - - /** - * Update the circular window buffer with one packet (fast or slow). - * Evicts the OLDEST entry, exactly mirroring Vulcan's EvictingQueue.add(). - * fastCount stays accurate: only changes when a fast entry is evicted or added. - */ - private void vulcanEvalWindow(boolean fast) { - if (vulcanWindowCount == VULCAN_WINDOW_SIZE) { - // evict oldest - if (vulcanWindow[vulcanWindowHead]) vulcanFastCount--; - } else { - vulcanWindowCount++; - } - vulcanWindow[vulcanWindowHead] = fast; - if (fast) vulcanFastCount++; - vulcanWindowHead = (vulcanWindowHead + 1) % VULCAN_WINDOW_SIZE; - } - - public Mode getMode() { - return mode.get(); - } - - private long getSetbackAge() { - if (lastSetbackTime <= 0L) return Long.MAX_VALUE; - return System.currentTimeMillis() - lastSetbackTime; - } - - private boolean notMoving() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.player == null) return false; - return prevPosX == mc.player.getX() - && prevPosY == mc.player.getY() - && prevPosZ == mc.player.getZ() - && yaw == mc.player.getYRot() - && pitch == mc.player.getXRot(); - } - - private String boostBindingName() { - return name() + ":" + boostKey.getName(); - } - - private void ensureBoostBind() { - String combo = boostKey.get(); - if (combo == null) combo = "NONE"; - if (combo.equalsIgnoreCase(lastBoostCombo)) return; - - String name = boostBindingName(); - KeyManager.unregisterAll(name); - if (!boostKey.isNone()) { - KeyManager.registerCombo(name, combo); - } - lastBoostCombo = combo; - } - - private boolean isBoostHeld() { - String combo = boostKey.get(); - if (combo == null || combo.equalsIgnoreCase("NONE")) return false; - return KeyManager.isHeld(boostBindingName()); - } - - public enum Mode { - NORMAL, - MATRIX, - SHIFT, - GRIM, - GRIM_CONCEPT, - VULCAN - } - - public enum OnFlag { - DISABLE, - NONE, - RESET - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Velocity.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Velocity.java deleted file mode 100644 index d5e6d40..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/Velocity.java +++ /dev/null @@ -1,1079 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import dev.loki.lovisual.events.impl.*; -import dev.loki.lovisual.util.screen.ClientScreen; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.inventory.InventoryScreen; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.Connection; -import net.minecraft.network.PacketListener; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.common.ClientboundPingPacket; -import net.minecraft.network.protocol.common.ServerboundPongPacket; -import net.minecraft.network.protocol.game.*; -import net.minecraft.resources.ResourceKey; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.player.Input; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.item.enchantment.Enchantments; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.block.*; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.values.BooleanMapValue; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.Events; -import dev.loki.lovisual.events.impl.*; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.mixins.accessors.ClientboundExplodePacketAccessor; -import dev.loki.lovisual.mixins.accessors.ClientboundSetEntityMotionPacketAccessor; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.network.BlinkManager; -import dev.loki.lovisual.util.network.TransferOrigin; -import dev.loki.lovisual.util.player.MovementUtil; - -import java.util.*; -import java.util.concurrent.ThreadLocalRandom; - -/** - * Velocity modes ported from LiquidBounce's ModuleVelocity. - */ -//todo Description -@ModuleInfo( - id = "velocity", - displayName = "Velocity", - category = ModuleCategory.MOVEMENT -) -public final class Velocity extends Module { - - private static final double VULCAN_297_SAFE_HORIZONTAL_RATIO = 0.25; - private static final double VULCAN_297_TINY_HORIZONTAL = 0.01; - private static final double VULCAN_297_JUMP_LIKE_VERTICAL = 0.41999998688697815; - private static final double VULCAN_297_PROTECTED_VERTICAL = 0.6; - private static final int VULCAN_297_WIND_BURST_PENDING_TICKS = 8; - private static final int VULCAN_297_WIND_BURST_PROTECT_TICKS = 12; - private static final String VULCAN_EXEMPT_LIQUID = "liquid"; - private static final String VULCAN_EXEMPT_FROZEN = "frozen"; - private static final String VULCAN_EXEMPT_FALL_DAMAGE = "fall_damage"; - private static final String VULCAN_EXEMPT_WEB = "web"; - private static final String VULCAN_EXEMPT_VOID = "void"; - private static final String VULCAN_EXEMPT_SLOW_FALLING = "slow_falling"; - private static final String VULCAN_EXEMPT_TRAPDOOR = "trapdoor"; - private static final String VULCAN_EXEMPT_SOUL_SAND = "soul_sand"; - private static final String VULCAN_EXEMPT_SLIME = "slime"; - private static final String VULCAN_EXEMPT_FLIGHT = "flight"; - private static final String VULCAN_EXEMPT_VEHICLE = "vehicle"; - private static final String VULCAN_EXEMPT_ELYTRA = "elytra"; - private static final String VULCAN_EXEMPT_FENCE = "fence"; - private static final String VULCAN_EXEMPT_WALL = "wall"; - private static final String VULCAN_EXEMPT_SWEET_BERRIES = "sweet_berries"; - private static final String VULCAN_EXEMPT_NETHERITE_ARMOR = "netherite_armor"; - private final Minecraft mc = Minecraft.getInstance(); - private final EnumValue mode = - enumCommon("velocityMode", "velocity_mode", CommonSettingSchemas.ANTICHEAT_MODE, Mode.MODIFY, Mode.values()); - private final NumberValue delay = visibleWhen(num("velocityDelay", "delay", 0, 0, 40), this::supportsIncomingVelocity); - private final NumberValue pauseOnFlag = num("velocityPauseOnFlag", "pause_on_flag", 0, 0, 20); - private final NumberValue modifyHorizontal = visibleWhen(num("velocityModifyHorizontal", "modify_horizontal", 0.0f, -1.0f, 1.0f), () -> mode.get() == Mode.MODIFY); - private final NumberValue modifyVertical = visibleWhen(num("velocityModifyVertical", "modify_vertical", 0.0f, -1.0f, 1.0f), () -> mode.get() == Mode.MODIFY); - private final NumberValue modifyMotionHorizontal = visibleWhen(num("velocityModifyMotionHorizontal", "modify_motion_horizontal", 0.0f, 0.0f, 1.0f), () -> mode.get() == Mode.MODIFY); - private final NumberValue modifyMotionVertical = visibleWhen(num("velocityModifyMotionVertical", "modify_motion_vertical", 0.0f, 0.0f, 1.0f), () -> mode.get() == Mode.MODIFY); - private final NumberValue modifyChance = visibleWhen(num("velocityModifyChance", "modify_chance", 100, 0, 100), () -> mode.get() == Mode.MODIFY); - private final EnumValue modifyFilter = visibleWhen(enumSetting("velocityModifyFilter", "modify_filter", Filter.ALWAYS, Filter.values()), () -> mode.get() == Mode.MODIFY); - private final BooleanValue modifyOnlyMove = visibleWhen(bool("velocityModifyOnlyMove", "modify_only_move", false), () -> mode.get() == Mode.MODIFY); - private final NumberValue modifyTransactionBuffer = visibleWhen(num("velocityModifyTransactionBuffer", "modify_transaction_buffer", 0, 0, 3), () -> mode.get() == Mode.MODIFY); - private final NumberValue reversalDelay = visibleWhen(num("velocityReversalDelay", "reversal_delay", 2, 1, 5), () -> mode.get() == Mode.REVERSAL); - private final NumberValue reversalXModifier = visibleWhen(num("velocityReversalXModifier", "reversal_x_modifier", 0.5f, 0.0f, 1.0f), () -> mode.get() == Mode.REVERSAL); - private final NumberValue reversalZModifier = visibleWhen(num("velocityReversalZModifier", "reversal_z_modifier", 0.5f, 0.0f, 1.0f), () -> mode.get() == Mode.REVERSAL); - private final BooleanValue reversalOnlyMoving = visibleWhen(bool("velocityReversalOnlyMoving", "reversal_only_moving", false), () -> mode.get() == Mode.REVERSAL); - private final NumberValue strafeDelay = visibleWhen(num("velocityStrafeDelay", "strafe_delay", 2, 0, 10), () -> mode.get() == Mode.STRAFE); - private final NumberValue strafeStrength = visibleWhen(num("velocityStrafeStrength", "strafe_strength", 1.0f, 0.1f, 2.0f), () -> mode.get() == Mode.STRAFE); - private final BooleanValue strafeUntilGround = visibleWhen(bool("velocityStrafeUntilGround", "strafe_until_ground", false), () -> mode.get() == Mode.STRAFE); - private final NumberValue jumpResetChance = visibleWhen(num("velocityJumpResetChance", "jump_reset_chance", 100.0f, 0.0f, 100.0f), () -> mode.get() == Mode.JUMP_RESET); - private final BooleanValue jumpResetByHits = visibleWhen(bool("velocityJumpResetByHits", "jump_reset_by_hits", false), () -> mode.get() == Mode.JUMP_RESET); - private final NumberValue jumpResetHits = visibleWhen(num("velocityJumpResetHits", "jump_reset_hits", 2, 0, 10), () -> mode.get() == Mode.JUMP_RESET); - private final BooleanValue jumpResetByDelay = visibleWhen(bool("velocityJumpResetByDelay", "jump_reset_by_delay", true), () -> mode.get() == Mode.JUMP_RESET); - private final NumberValue jumpResetTicks = visibleWhen(num("velocityJumpResetTicks", "jump_reset_ticks", 2, 0, 20), () -> mode.get() == Mode.JUMP_RESET); - private final NumberValue lagTime = visibleWhen(num("velocityLagTime", "lag_time", 5, 1, 20), () -> mode.get() == Mode.LAG); - private final BooleanValue lagJumpReset = visibleWhen(bool("velocityLagJumpReset", "lag_jump_reset", false), () -> mode.get() == Mode.LAG); - private final NumberValue dexlandHReduce = visibleWhen(num("velocityDexlandHReduce", "dexland_h_reduce", 0.3f, 0.0f, 1.0f), () -> mode.get() == Mode.DEXLAND); - private final NumberValue dexlandAttacksToWork = visibleWhen(num("velocityDexlandAttacksToWork", "dexland_attacks_to_work", 4, 1, 10), () -> mode.get() == Mode.DEXLAND); - private final BooleanValue grim2344AlternativeBypass = visibleWhen(bool("velocityGrim2344AlternativeBypass", "grim2344_alternative_bypass", true), () -> mode.get() == Mode.GRIM_2344); - private final NumberValue aacReduce = visibleWhen(num("velocityAACReduce", "aac_reduce", 0.62f, 0.0f, 1.0f), () -> mode.get() == Mode.AAC_442); - private final BooleanValue intaveReduceOnAttack = visibleWhen(bool("velocityIntaveReduceOnAttack", "intave_reduce_on_attack", true), () -> mode.get() == Mode.INTAVE); - private final NumberValue intaveReduceFactor = visibleWhen(num("velocityIntaveReduceFactor", "intave_reduce_factor", 0.6f, 0.6f, 1.0f), () -> mode.get() == Mode.INTAVE); - private final NumberValue intaveHurtTimeMin = visibleWhen(num("velocityIntaveHurtTimeMin", "intave_hurt_time_min", 5, 1, 10), () -> mode.get() == Mode.INTAVE); - private final NumberValue intaveHurtTimeMax = visibleWhen(num("velocityIntaveHurtTimeMax", "intave_hurt_time_max", 7, 1, 10), () -> mode.get() == Mode.INTAVE); - private final NumberValue intaveLastAttackTime = visibleWhen(num("velocityIntaveLastAttackTime", "intave_last_attack_time", 2000, 1, 10000), () -> mode.get() == Mode.INTAVE); - private final BooleanValue intaveJumpReset = visibleWhen(bool("velocityIntaveJumpReset", "intave_jump_reset", true), () -> mode.get() == Mode.INTAVE); - private final NumberValue intaveJumpChance = visibleWhen(num("velocityIntaveJumpChance", "intave_jump_chance", 50.0f, 0.0f, 100.0f), () -> mode.get() == Mode.INTAVE); - private final BooleanValue intaveRandomize = visibleWhen(bool("velocityIntaveRandomize", "intave_randomize", false), () -> mode.get() == Mode.INTAVE); - private final NumberValue intaveRandomDelayTicks = visibleWhen(num("velocityIntaveRandomDelayTicks", "intave_random_delay_ticks", 5, 0, 10), () -> mode.get() == Mode.INTAVE); - private final NumberValue vulcan297ExemptRatio = visibleWhen(num("velocityVulcan297ExemptRatio", "vulcan297_exempt_ratio", 0.0f, 0.0f, 1.0f), this::isVulcan297Mode); - private final BooleanMapValue vulcan297Exempts = visibleWhen(group("velocityVulcan297Exempts", "vulcan297_exempts", vulcan297ExemptDefaults()), this::isVulcan297Mode); - private final Queue delayedPackets = new ArrayDeque<>(); - private int pause; - private int transactionBuffer; - private boolean reversalHandlingVelocity; - private int reversalVelocityTicks; - private int strafeTicks = -1; - private boolean strafeApplyUntilGround; - private int jumpLimitUntilJump; - private boolean jumpResetFallDamage; - private boolean lagShouldLag; - private int lagTicks; - private int lagShouldJumpTicks; - private boolean hypixelAbsorbedVelocity; - private long dexlandLastAttackTime; - private int dexlandCount; - private boolean grim2371CancelNextVelocity; - private boolean grim2371Delay; - private boolean grim2371NeedClick; - private boolean grim2371WaitForPing; - private boolean grim2371WaitForUpdate; - private boolean grim2371ShouldSkip; - private BlockHitResult grim2371HitResult; - private int grim2371FreezeTicks; - private boolean grim2344CanCancel; - private long intaveLastAttack; - private boolean intaveFallDamage; - private int intaveCurrentDelay; - private int intaveDelayCounter; - private int vulcan297WindBurstPendingTicks; - private int vulcan297WindBurstProtectTicks; - - private static Map vulcan297ExemptDefaults() { - Map defaults = new LinkedHashMap<>(); - defaults.put(VULCAN_EXEMPT_LIQUID, true); - defaults.put(VULCAN_EXEMPT_FROZEN, true); - defaults.put(VULCAN_EXEMPT_FALL_DAMAGE, true); - defaults.put(VULCAN_EXEMPT_WEB, true); - defaults.put(VULCAN_EXEMPT_VOID, true); - defaults.put(VULCAN_EXEMPT_SLOW_FALLING, true); - defaults.put(VULCAN_EXEMPT_TRAPDOOR, true); - defaults.put(VULCAN_EXEMPT_SOUL_SAND, true); - defaults.put(VULCAN_EXEMPT_SLIME, true); - defaults.put(VULCAN_EXEMPT_FLIGHT, true); - defaults.put(VULCAN_EXEMPT_VEHICLE, true); - defaults.put(VULCAN_EXEMPT_ELYTRA, true); - defaults.put(VULCAN_EXEMPT_FENCE, true); - defaults.put(VULCAN_EXEMPT_WALL, true); - defaults.put(VULCAN_EXEMPT_SWEET_BERRIES, true); - defaults.put(VULCAN_EXEMPT_NETHERITE_ARMOR, true); - return defaults; - } - - @Override - public void onEnable() { - resetState(); - } - - @Override - public void onDisable() { - BlinkManager.INSTANCE.flush(TransferOrigin.INCOMING); - resetState(); - } - - @EventHandler(priority = 2) - private void onPacket(PacketEvent event) { - if (!isEnabled() || player() == null) return; - - Packet packet = event.getPacket(); - if (event.isOriginal()) { - if (packet instanceof ClientboundPlayerPositionPacket) { - pause = pauseOnFlag.get(); - return; - } - if (pause > 0) return; - if (event.getOrigin() == TransferOrigin.INCOMING - && supportsIncomingVelocity() - && isLocalPlayerVelocity(packet) - && delay.get() > 0) { - event.cancel(); - delayedPackets.add(new DelayedPacket(packet, delay.get())); - return; - } - } - - switch (mode.get()) { - case MODIFY -> handleModify(event, packet); - case REVERSAL -> handleReversal(event, packet); - case STRAFE -> handleStrafePacket(event, packet); - case JUMP_RESET -> handleJumpResetPacket(packet); - case LAG -> handleLagPacket(packet); - case HYPIXEL -> handleHypixel(event, packet); - case BLOCKSMC -> handleBlocksMc(event, packet); - case GRIM_2371 -> handleGrim2371Packet(event, packet); - case GRIM_2344 -> handleGrim2344(event, packet); - case INTAVE -> handleIntavePacket(packet); - case VULCAN_297 -> handleVulcan297(event, packet); - default -> { - } - } - - } - - @EventHandler - private void onBlinkPacket(BlinkPacketEvent event) { - if (!isEnabled() || player() == null) return; - - if (mode.get() == Mode.LAG - && lagShouldLag - && event.getOrigin() == TransferOrigin.INCOMING - && !(event.getPacket() instanceof ClientboundPingPacket)) { - event.setAction(BlinkManager.Action.QUEUE); - return; - } - - if (mode.get() == Mode.GRIM_2371 - && !grim2371WaitForUpdate - && grim2371Delay - && event.getOrigin() == TransferOrigin.INCOMING) { - event.setAction(BlinkManager.Action.QUEUE); - } - } - - @EventHandler - private void onTick(GameTickEvent event) { - if (!isEnabled()) return; - - if (pause > 0) pause--; - processDelayedPackets(); - - LocalPlayer player = player(); - if (player == null) return; - - switch (mode.get()) { - case REVERSAL -> tickReversal(player); - case STRAFE -> tickStrafe(player); - case LAG -> tickLag(player); - case HYPIXEL -> { - if (player.onGround()) hypixelAbsorbedVelocity = false; - } - case HYLEX -> tickHylex(player); - case GRIM_2371 -> tickGrim2371(player); - case AAC_442 -> { - if (player.hurtTime > 0 && !player.onGround()) { - multiplyHorizontal(player, aacReduce.get()); - } - } - default -> { - } - } - - if (vulcan297WindBurstProtectTicks > 0) { - vulcan297WindBurstProtectTicks--; - } - if (vulcan297WindBurstPendingTicks > 0) { - vulcan297WindBurstPendingTicks--; - } - } - - @EventHandler - private void onMovementInput(MovementInputEvent event) { - if (!isEnabled() || player() == null) return; - - if (mode.get() == Mode.JUMP_RESET) { - handleJumpResetInput(event, player()); - } else if (mode.get() == Mode.LAG) { - if (lagJumpReset.get() && lagShouldJumpTicks > 0 && player().onGround() && player().isSprinting()) { - event.setJump(true); - lagShouldJumpTicks = 0; - } - } else if (mode.get() == Mode.INTAVE) { - handleIntaveJumpReset(event, player()); - } - } - - @EventHandler - private void onMove(PlayerMoveEvent event) { - if (!isEnabled() || mode.get() != Mode.STRAFE || !strafeApplyUntilGround || player() == null) return; - - if (player().onGround()) { - strafeApplyUntilGround = false; - return; - } - - event.setMovement(withStrafe(event.getMovement(), strafeStrength.get())); - } - - @EventHandler - private void onAttack(AttackEntityEvent event) { - if (!isEnabled() || player() == null) return; - - if (mode.get() == Mode.DEXLAND) { - long now = System.currentTimeMillis(); - if (player().hurtTime > 0 - && ++dexlandCount % dexlandAttacksToWork.get() == 0 - && now - dexlandLastAttackTime <= 8000L) { - multiplyHorizontal(player(), dexlandHReduce.get()); - } - dexlandLastAttackTime = now; - } else if (mode.get() == Mode.HYLEX) { - handleHylexAttack(player()); - } else if (mode.get() == Mode.INTAVE && intaveReduceOnAttack.get()) { - long now = System.currentTimeMillis(); - int min = Math.min(intaveHurtTimeMin.get(), intaveHurtTimeMax.get()); - int max = Math.max(intaveHurtTimeMin.get(), intaveHurtTimeMax.get()); - if (player().hurtTime >= min && player().hurtTime <= max && now - intaveLastAttack <= intaveLastAttackTime.get()) { - multiplyHorizontal(player(), intaveReduceFactor.get()); - } - intaveLastAttack = now; - } else if (mode.get() == Mode.VULCAN_297 && isVulcan297WindBurstMaceAttack(event, player())) { - armVulcan297MaceVelocityWindow(); - } - } - - private void handleModify(PacketEvent event, Packet packet) { - if (packet instanceof ClientboundSetEntityMotionPacket velocity && velocity.id() == player().getId()) { - if (!shouldModifyVelocity()) return; - - if (modifyHorizontal.get() == 0.0f && modifyVertical.get() == 0.0f) { - event.cancel(); - return; - } - - Vec3 packetVelocity = velocity.movement(); - Vec3 currentVelocity = player().getDeltaMovement(); - double x = modifyHorizontal.get() != 0.0f - ? packetVelocity.x * modifyHorizontal.get() - : currentVelocity.x * modifyMotionHorizontal.get(); - double y = modifyVertical.get() != 0.0f - ? packetVelocity.y * modifyVertical.get() - : currentVelocity.y * modifyMotionVertical.get(); - double z = modifyHorizontal.get() != 0.0f - ? packetVelocity.z * modifyHorizontal.get() - : currentVelocity.z * modifyMotionHorizontal.get(); - ((ClientboundSetEntityMotionPacketAccessor) (Object) velocity).combatant$setVelocity(new Vec3(x, y, z)); - transactionBuffer += modifyTransactionBuffer.get(); - return; - } - - if (packet instanceof ClientboundExplodePacket explosion && explosion.playerKnockback().isPresent()) { - if (!shouldModifyVelocity()) return; - - Vec3 knockback = explosion.playerKnockback().get(); - ((ClientboundExplodePacketAccessor) (Object) explosion).combatant$setPlayerKnockback(Optional.of(new Vec3( - knockback.x * modifyHorizontal.get(), - knockback.y * modifyVertical.get(), - knockback.z * modifyHorizontal.get() - ))); - transactionBuffer += modifyTransactionBuffer.get(); - return; - } - - if (packet instanceof ServerboundPongPacket && transactionBuffer > 0) { - event.cancel(); - transactionBuffer--; - } - } - - private boolean shouldModifyVelocity() { - if (modifyChance.get() != 100 && ThreadLocalRandom.current().nextInt(100) > modifyChance.get()) return false; - if (modifyOnlyMove.get() && !isMoving()) return false; - - return switch (modifyFilter.get()) { - case ALWAYS -> true; - case ON_GROUND -> player().onGround(); - case IN_AIR -> !player().onGround(); - }; - } - - private void handleReversal(PacketEvent event, Packet packet) { - if (!isLocalPlayerVelocity(packet)) return; - if (reversalOnlyMoving.get() && !isMoving()) return; - - reversalVelocityTicks = 0; - reversalHandlingVelocity = true; - } - - private void tickReversal(LocalPlayer player) { - if (!reversalHandlingVelocity) return; - - Vec3 velocity = player.getDeltaMovement(); - if (velocity.lengthSqr() == 0.0) { - reversalHandlingVelocity = false; - reversalVelocityTicks = 0; - return; - } - - if (reversalVelocityTicks++ >= reversalDelay.get()) { - player.setDeltaMovement( - velocity.x * -reversalXModifier.get(), - velocity.y, - velocity.z * -reversalZModifier.get() - ); - reversalHandlingVelocity = false; - reversalVelocityTicks = 0; - } - } - - private void handleStrafePacket(PacketEvent event, Packet packet) { - if (!isLocalPlayerVelocity(packet)) return; - - strafeTicks = strafeDelay.get(); - if (strafeTicks <= 0) { - applyStrafe(player()); - } - } - - private void tickStrafe(LocalPlayer player) { - if (strafeTicks < 0) return; - - if (strafeTicks-- <= 0) { - applyStrafe(player); - strafeTicks = -1; - } - } - - private void applyStrafe(LocalPlayer player) { - if (player == null) return; - - player.setDeltaMovement(withStrafe(player.getDeltaMovement(), strafeStrength.get())); - if (strafeUntilGround.get()) { - strafeApplyUntilGround = true; - } - } - - private Vec3 withStrafe(Vec3 currentVelocity, double strength) { - return MovementUtil.withStrafe( - currentVelocity, - movementInput(), - movementYaw(), - horizontalSpeed(currentVelocity) * strength, - 1.0 - ); - } - - private void handleJumpResetPacket(Packet packet) { - if (packet instanceof ClientboundSetEntityMotionPacket(int id, Vec3 v) && id == player().getId()) { - jumpResetFallDamage = v.x == 0.0 && v.z == 0.0 && v.y < 0.0; - } - } - - private void handleJumpResetInput(MovementInputEvent event, LocalPlayer player) { - if (player.hurtTime != 9 - || !player.onGround() - || !player.isSprinting() - || jumpResetFallDamage - || !jumpResetCooldownOver() - || !rollChance(jumpResetChance.get())) { - updateJumpResetLimit(player); - return; - } - - event.setJump(true); - jumpLimitUntilJump = 0; - } - - private boolean jumpResetCooldownOver() { - if (jumpResetByHits.get()) return jumpLimitUntilJump >= jumpResetHits.get(); - if (jumpResetByDelay.get()) return jumpLimitUntilJump >= jumpResetTicks.get(); - return true; - } - - private void updateJumpResetLimit(LocalPlayer player) { - if (jumpResetByHits.get()) { - if (player.hurtTime == 9) jumpLimitUntilJump++; - } else { - jumpLimitUntilJump++; - } - } - - private void handleLagPacket(Packet packet) { - if (packet instanceof ClientboundSetEntityMotionPacket velocity && velocity.id() == player().getId()) { - lagShouldLag = true; - lagTicks = lagTime.get(); - } - } - - private void tickLag(LocalPlayer player) { - if (lagShouldLag && --lagTicks <= 0) { - lagShouldLag = false; - lagTicks = 0; - BlinkManager.INSTANCE.flush(TransferOrigin.INCOMING); - lagShouldJumpTicks = 2; - } - if (lagShouldJumpTicks > 0) { - lagShouldJumpTicks--; - } - } - - private void handleHypixel(PacketEvent event, Packet packet) { - if (!(packet instanceof ClientboundSetEntityMotionPacket velocity) || velocity.id() != player().getId()) return; - - if (!player().onGround() && !hypixelAbsorbedVelocity) { - event.cancel(); - hypixelAbsorbedVelocity = true; - return; - } - - Vec3 current = player().getDeltaMovement(); - Vec3 packetVelocity = velocity.movement(); - ((ClientboundSetEntityMotionPacketAccessor) (Object) velocity).combatant$setVelocity(new Vec3(current.x, packetVelocity.y, current.z)); - } - - private void handleBlocksMc(PacketEvent event, Packet packet) { - if (!(packet instanceof ClientboundSetEntityMotionPacket velocity) || velocity.id() != player().getId()) return; - - event.cancel(); - sendSneaking(true); - sendSneaking(false); - } - - private void handleHylexAttack(LocalPlayer player) { - if (!isMoving() || !player.isSprinting()) return; - - switch (player.hurtTime) { - case 9 -> multiplyHorizontal(player, 0.8); - case 8 -> multiplyHorizontal(player, 0.11); - case 7 -> multiplyHorizontal(player, 0.4); - case 4 -> multiplyHorizontal(player, 0.37); - default -> { - } - } - } - - private void tickHylex(LocalPlayer player) { - if (player.hurtTime > 5 && player.onGround()) { - player.jumpFromGround(); - } - } - - private void handleGrim2371Packet(PacketEvent event, Packet packet) { - if (packet instanceof ServerboundInteractPacket || packet instanceof ServerboundUseItemOnPacket) { - grim2371ShouldSkip = true; - } else if (packet instanceof ServerboundMovePlayerPacket move && move.hasPosition() && grim2371WaitForUpdate) { - event.cancel(); - return; - } else if (packet instanceof ServerboundPongPacket && grim2371WaitForPing) { - grim2371WaitForUpdate = false; - grim2371WaitForPing = false; - } - - if (packet instanceof ClientboundBlockUpdatePacket block - && grim2371WaitForUpdate - && block.getPos().equals(player().blockPosition())) { - grim2371WaitForPing = true; - grim2371NeedClick = false; - } - - if (event.isCancelled() || grim2371WaitForUpdate || grim2371Delay) return; - - if (isLocalPlayerDamage(packet)) { - grim2371CancelNextVelocity = true; - } else if (grim2371CancelNextVelocity && isLocalPlayerVelocity(packet)) { - event.cancel(); - grim2371Delay = true; - grim2371CancelNextVelocity = false; - grim2371NeedClick = true; - } - } - - private void tickGrim2371(LocalPlayer player) { - if (grim2371NeedClick && !grim2371ShouldSkip && !player.isUsingItem()) { - grim2371HitResult = traceDownToPlayerBlock(player); - } - - if (grim2371HitResult != null) { - grim2371Delay = false; - BlinkManager.INSTANCE.flush(TransferOrigin.INCOMING); - - if (mc.gameMode != null) { - InteractionResult result = mc.gameMode.useItemOn(player, InteractionHand.MAIN_HAND, grim2371HitResult); - if (result.consumesAction()) { - player.swing(InteractionHand.MAIN_HAND); - } - } - - sendGrim2371Rotation(player); - grim2371FreezeTicks = 0; - grim2371WaitForUpdate = true; - grim2371HitResult = null; - grim2371NeedClick = false; - } - - if (grim2371WaitForUpdate && ++grim2371FreezeTicks > 20) { - grim2371WaitForUpdate = false; - grim2371WaitForPing = false; - grim2371NeedClick = false; - } - - grim2371ShouldSkip = false; - } - - private void handleGrim2344(PacketEvent event, Packet packet) { - if (isLocalPlayerDamage(packet)) { - grim2344CanCancel = true; - } - - if (isLocalPlayerVelocity(packet) && grim2344CanCancel) { - event.cancel(); - int repeats = grim2344AlternativeBypass.get() ? 4 : 1; - for (int i = 0; i < repeats; i++) { - sendFullMovePacket(player()); - } - sendStopDestroyBlock(player()); - grim2344CanCancel = false; - } - } - - private void handleIntavePacket(Packet packet) { - if (packet instanceof ClientboundSetEntityMotionPacket(int id, Vec3 v) && id == player().getId()) { - intaveFallDamage = v.x == 0.0 && v.z == 0.0 && v.y < 0.0; - } - } - - private void handleIntaveJumpReset(MovementInputEvent event, LocalPlayer player) { - if (!intaveJumpReset.get()) return; - - boolean shouldJump = rollChance(intaveJumpChance.get()) && player.hurtTime > 5 && !intaveFallDamage; - boolean canJump = player.onGround() && !(ClientScreen.current() instanceof InventoryScreen); - - if (intaveRandomize.get()) { - intaveDelayCounter++; - if (intaveDelayCounter >= intaveCurrentDelay) { - if (shouldJump && canJump) event.setJump(true); - intaveDelayCounter = 0; - intaveCurrentDelay = ThreadLocalRandom.current().nextInt(intaveRandomDelayTicks.get() + 1); - } - } else if (shouldJump && canJump) { - event.setJump(true); - } - } - - private void handleVulcan297(PacketEvent event, Packet packet) { - LocalPlayer player = player(); - if (player == null) return; - - if (event.getOrigin() == TransferOrigin.OUTGOING - && packet instanceof ServerboundSwingPacket swing - && isVulcan297MaceSwing(swing, player)) { - armVulcan297MaceVelocityWindow(); - return; - } - - if (packet instanceof ClientboundSetEntityMotionPacket velocity && velocity.id() == player.getId()) { - if (vulcan297WindBurstProtectTicks > 0) { - return; - } - - Vec3 modified = getVulcan297Velocity(player, velocity.movement()); - if (isZeroVelocity(modified)) { - event.cancel(); - return; - } - - ((ClientboundSetEntityMotionPacketAccessor) (Object) velocity).combatant$setVelocity(modified); - return; - } - - if (packet instanceof ClientboundExplodePacket explosion && explosion.playerKnockback().isPresent()) { - if (vulcan297WindBurstPendingTicks > 0) { - vulcan297WindBurstPendingTicks = 0; - vulcan297WindBurstProtectTicks = VULCAN_297_WIND_BURST_PROTECT_TICKS; - } - } - } - - private void armVulcan297MaceVelocityWindow() { - vulcan297WindBurstPendingTicks = Math.max(vulcan297WindBurstPendingTicks, VULCAN_297_WIND_BURST_PENDING_TICKS); - vulcan297WindBurstProtectTicks = Math.max(vulcan297WindBurstProtectTicks, VULCAN_297_WIND_BURST_PROTECT_TICKS); - } - - private boolean isVulcan297MaceSwing(ServerboundSwingPacket packet, LocalPlayer player) { - return packet.getHand() == InteractionHand.MAIN_HAND && player.getMainHandItem().is(Items.MACE); - } - - private boolean isVulcan297WindBurstMaceAttack(AttackEntityEvent event, LocalPlayer player) { - if (event.getPlayer() != player || player.isFallFlying() || player.fallDistance < 1.5f) { - return false; - } - - ItemStack stack = player.getMainHandItem(); - return stack.is(Items.MACE) && getEnchantmentLevel(Enchantments.WIND_BURST, stack) > 0; - } - - private int getEnchantmentLevel(ResourceKey key, ItemStack stack) { - Holder entry = getEnchantmentEntry(key); - return entry == null ? 0 : EnchantmentHelper.getItemEnchantmentLevel(entry, stack); - } - - private Holder getEnchantmentEntry(ResourceKey key) { - if (mc.level == null) return null; - Registry registry = mc.level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT); - Enchantment enchantment = registry.getValue(key); - return enchantment != null ? registry.wrapAsHolder(enchantment) : null; - } - - private Vec3 getVulcan297Velocity(LocalPlayer player, Vec3 velocity) { - double horizontal = horizontalSpeed(velocity); - boolean typeAExempt = isVulcan297TypeAExempt(player); - boolean typeBExempt = isVulcan297TypeBExempt(player); - - if (!typeAExempt && shouldPreserveVulcan297EntityImpulse(velocity)) { - return velocity; - } - - double exemptRatio = vulcan297ExemptRatio.get(); - double horizontalFactor = typeBExempt ? exemptRatio : VULCAN_297_SAFE_HORIZONTAL_RATIO; - double verticalFactor = typeAExempt ? exemptRatio : velocity.y > 0.0 ? 1.0 : 0.0; - - if (!typeBExempt && horizontal < VULCAN_297_TINY_HORIZONTAL && velocity.y <= VULCAN_297_JUMP_LIKE_VERTICAL) { - horizontalFactor = 0.0; - } - - return applyVulcan297Budget(velocity, horizontalFactor, verticalFactor); - } - - private Vec3 applyVulcan297Budget(Vec3 velocity, double horizontalFactor, double verticalFactor) { - return new Vec3( - velocity.x * horizontalFactor, - velocity.y * verticalFactor, - velocity.z * horizontalFactor - ); - } - - private boolean shouldPreserveVulcan297EntityImpulse(Vec3 velocity) { - double horizontal = horizontalSpeed(velocity); - - if (velocity.y >= VULCAN_297_PROTECTED_VERTICAL) { - return true; - } - - return velocity.y > VULCAN_297_JUMP_LIKE_VERTICAL && horizontal >= VULCAN_297_SAFE_HORIZONTAL_RATIO; - } - - private boolean isVulcan297TypeAExempt(LocalPlayer player) { - return isVulcan297SharedExempt(player) - || getVulcan297BlockExempt(player); - } - - private boolean isVulcan297TypeBExempt(LocalPlayer player) { - return isVulcan297SharedExempt(player) - || getVulcan297BlockExempt(player) - || vulcan297Exempts.get(VULCAN_EXEMPT_NETHERITE_ARMOR) && hasVulcan297NetheriteArmor(player); - } - - private boolean isVulcan297SharedExempt(LocalPlayer player) { - if (vulcan297Exempts.get(VULCAN_EXEMPT_VEHICLE) && player.isPassenger()) return true; - if (vulcan297Exempts.get(VULCAN_EXEMPT_ELYTRA) && player.isFallFlying()) return true; - if (vulcan297Exempts.get(VULCAN_EXEMPT_LIQUID) && (player.isInWater() - || player.isUnderWater() - || player.isInLava() - || player.isSwimming())) { - return true; - } - if (vulcan297Exempts.get(VULCAN_EXEMPT_FROZEN) && player.isFullyFrozen()) return true; - if (vulcan297Exempts.get(VULCAN_EXEMPT_FLIGHT) && player.getAbilities().flying) return true; - if (vulcan297Exempts.get(VULCAN_EXEMPT_FALL_DAMAGE) && player.fallDistance > 3.0f) return true; - if (vulcan297Exempts.get(VULCAN_EXEMPT_VOID) && isBelowWorld(player)) return true; - return vulcan297Exempts.get(VULCAN_EXEMPT_SLOW_FALLING) && player.hasEffect(MobEffects.SLOW_FALLING); - } - - private boolean isBelowWorld(LocalPlayer player) { - return mc.level != null && player.getY() < mc.level.getMinY(); - } - - private boolean getVulcan297BlockExempt(LocalPlayer player) { - if (mc.level == null) { - return false; - } - - BlockPos feet = player.blockPosition(); - return isVulcan297ExemptBlock(mc.level.getBlockState(feet).getBlock()) - || isVulcan297ExemptBlock(mc.level.getBlockState(feet.below()).getBlock()); - } - - private boolean isVulcan297ExemptBlock(Block block) { - return vulcan297Exempts.get(VULCAN_EXEMPT_WEB) && (block == Blocks.COBWEB || block == Blocks.POWDER_SNOW) - || vulcan297Exempts.get(VULCAN_EXEMPT_SOUL_SAND) && block == Blocks.SOUL_SAND - || vulcan297Exempts.get(VULCAN_EXEMPT_SLIME) && block == Blocks.SLIME_BLOCK - || vulcan297Exempts.get(VULCAN_EXEMPT_SWEET_BERRIES) && block == Blocks.SWEET_BERRY_BUSH - || vulcan297Exempts.get(VULCAN_EXEMPT_TRAPDOOR) && block instanceof TrapDoorBlock - || vulcan297Exempts.get(VULCAN_EXEMPT_FENCE) && block instanceof FenceBlock - || vulcan297Exempts.get(VULCAN_EXEMPT_WALL) && block instanceof WallBlock; - } - - private boolean hasVulcan297NetheriteArmor(LocalPlayer player) { - return isNetheriteArmor(player.getItemBySlot(EquipmentSlot.HEAD)) - || isNetheriteArmor(player.getItemBySlot(EquipmentSlot.CHEST)) - || isNetheriteArmor(player.getItemBySlot(EquipmentSlot.LEGS)) - || isNetheriteArmor(player.getItemBySlot(EquipmentSlot.FEET)); - } - - private boolean isNetheriteArmor(ItemStack stack) { - return stack.is(Items.NETHERITE_HELMET) - || stack.is(Items.NETHERITE_CHESTPLATE) - || stack.is(Items.NETHERITE_LEGGINGS) - || stack.is(Items.NETHERITE_BOOTS); - } - - private boolean isZeroVelocity(Vec3 velocity) { - return velocity.x == 0.0 && velocity.y == 0.0 && velocity.z == 0.0; - } - - private void processDelayedPackets() { - int size = delayedPackets.size(); - for (int i = 0; i < size; i++) { - DelayedPacket delayed = delayedPackets.poll(); - if (delayed == null) continue; - - delayed.ticks--; - if (delayed.ticks > 0) { - delayedPackets.add(delayed); - continue; - } - - PacketEvent.Receive packetEvent = new PacketEvent.Receive(delayed.packet, false); - Events.BUS.post(packetEvent); - if (!packetEvent.isCancelled()) { - handleIncomingPacket(delayed.packet); - } - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private void handleIncomingPacket(Packet packet) { - Connection connection = mc.getConnection() != null ? mc.getConnection().getConnection() : null; - PacketListener listener = connection != null ? connection.getPacketListener() : null; - if (listener != null) { - ((Packet) packet).handle(listener); - } - } - - private boolean supportsIncomingVelocity() { - return mode.get() != Mode.DEXLAND - && mode.get() != Mode.HYLEX - && mode.get() != Mode.AAC_442 - && mode.get() != Mode.INTAVE - && mode.get() != Mode.VULCAN_297; - } - - private boolean isVulcan297Mode() { - return mode.get() == Mode.VULCAN_297; - } - - private boolean isLocalPlayerVelocity(Packet packet) { - LocalPlayer player = player(); - if (player == null) return false; - if (packet instanceof ClientboundSetEntityMotionPacket velocity) { - return velocity.id() == player.getId(); - } - return packet instanceof ClientboundExplodePacket explosion && explosion.playerKnockback().isPresent(); - } - - private boolean isLocalPlayerDamage(Packet packet) { - return packet instanceof ClientboundDamageEventPacket damage && player() != null && damage.entityId() == player().getId(); - } - - private LocalPlayer player() { - return mc.player; - } - - private boolean isMoving() { - return MovementUtil.isMoving(); - } - - private Vec3 movementInput() { - if (player() == null || player().input == null) return Vec3.ZERO; - var input = player().input.getMoveVector(); - return new Vec3(input.x, 0.0, input.y); - } - - private float movementYaw() { - Rotation rotation = RotationManager.INSTANCE.getMovementRotation(); - return rotation != null ? rotation.yaw() : player().getYRot(); - } - - private double horizontalSpeed(Vec3 velocity) { - return Math.hypot(velocity.x, velocity.z); - } - - private void multiplyHorizontal(LocalPlayer player, double factor) { - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement(velocity.x * factor, velocity.y, velocity.z * factor); - } - - private boolean rollChance(float chance) { - return chance >= 100.0f || ThreadLocalRandom.current().nextDouble(100.0) < chance; - } - - private void sendSneaking(boolean sneaking) { - if (mc.getConnection() == null) return; - Input input = player() != null && player().input != null - ? player().input.keyPresses - : new Input(false, false, false, false, false, false, false); - mc.getConnection().send(new ServerboundPlayerInputPacket(new Input( - input.forward(), - input.backward(), - input.left(), - input.right(), - input.jump(), - sneaking, - input.sprint() - ))); - } - - private BlockHitResult traceDownToPlayerBlock(LocalPlayer player) { - Rotation server = RotationManager.INSTANCE.getServerRotation(); - float yaw = server != null ? server.yaw() : player.getYRot(); - Vec3 start = player.getEyePosition(); - Vec3 end = start.add(Vec3.directionFromRotation(90.0f, yaw).scale(4.5)); - HitResult hit = player.level().clip(new ClipContext( - start, - end, - ClipContext.Block.OUTLINE, - ClipContext.Fluid.NONE, - player - )); - if (!(hit instanceof BlockHitResult blockHit) || blockHit.getType() == HitResult.Type.MISS) return null; - - BlockPos playerBlock = player.blockPosition(); - return blockHit.getBlockPos().relative(blockHit.getDirection()).equals(playerBlock) ? blockHit : null; - } - - private void sendGrim2371Rotation(LocalPlayer player) { - if (mc.getConnection() == null) return; - Rotation server = RotationManager.INSTANCE.getServerRotation(); - if (server == null || Mth.abs(server.pitch() - 90.0f) > 0.001f) { - mc.getConnection().send(new ServerboundMovePlayerPacket.Rot( - player.getYRot(), - 90.0f, - player.onGround(), - player.horizontalCollision - )); - } else { - mc.getConnection().send(new ServerboundMovePlayerPacket.StatusOnly( - player.onGround(), - player.horizontalCollision - )); - } - } - - private void sendFullMovePacket(LocalPlayer player) { - if (mc.getConnection() == null || player == null) return; - mc.getConnection().send(new ServerboundMovePlayerPacket.PosRot( - player.getX(), - player.getY(), - player.getZ(), - player.getYRot(), - player.getXRot(), - player.onGround(), - player.horizontalCollision - )); - } - - private void sendStopDestroyBlock(LocalPlayer player) { - if (mc.getConnection() == null || player == null) return; - mc.getConnection().send(new ServerboundPlayerActionPacket( - ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK, - player.blockPosition(), - Direction.DOWN - )); - } - - private void resetState() { - delayedPackets.clear(); - pause = 0; - transactionBuffer = 0; - reversalHandlingVelocity = false; - reversalVelocityTicks = 0; - strafeTicks = -1; - strafeApplyUntilGround = false; - jumpLimitUntilJump = 0; - jumpResetFallDamage = false; - lagShouldLag = false; - lagTicks = 0; - lagShouldJumpTicks = 0; - hypixelAbsorbedVelocity = false; - dexlandLastAttackTime = 0L; - dexlandCount = 0; - grim2371CancelNextVelocity = false; - grim2371Delay = false; - grim2371NeedClick = false; - grim2371WaitForPing = false; - grim2371WaitForUpdate = false; - grim2371ShouldSkip = false; - grim2371HitResult = null; - grim2371FreezeTicks = 0; - grim2344CanCancel = false; - intaveLastAttack = 0L; - intaveFallDamage = false; - intaveCurrentDelay = 0; - intaveDelayCounter = 0; - vulcan297WindBurstPendingTicks = 0; - vulcan297WindBurstProtectTicks = 0; - } - - @Getter - @RequiredArgsConstructor - public enum Mode implements EnumValue.IdProvider { - MODIFY("modify"), - REVERSAL("reversal"), - STRAFE("strafe"), - JUMP_RESET("jump_reset"), - LAG("lag"), - HYPIXEL("hypixel"), - DEXLAND("dexland"), - HYLEX("hylex"), - BLOCKSMC("blocksmc"), - GRIM_2371("grim_2371"), - GRIM_2344("grim_2344_117"), - AAC_442("aac_4_4_2"), - INTAVE("intave"), - VULCAN_297("vulcan_297"); - - private final String id; - } - - private enum Filter { - ALWAYS, - ON_GROUND, - IN_AIR - } - - private static final class DelayedPacket { - final Packet packet; - int ticks; - - DelayedPacket(Packet packet, int ticks) { - this.packet = packet; - this.ticks = ticks; - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/WindJump.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/WindJump.java deleted file mode 100644 index 33f4735..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/movement/WindJump.java +++ /dev/null @@ -1,675 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.movement; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.MultiPlayerGameMode; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.EventSync; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.events.impl.PlayerJumpEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.TPSSync; -import dev.loki.lovisual.mixins.accessors.PlayerInventoryAccessor; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.player.MovementUtil; -import dev.loki.lovisual.util.player.inventory.InventorySwap; -import dev.loki.lovisual.util.player.simulation.PlayerSimulationCache; - -//todo Description -@ModuleInfo( - id = "windjump", - displayName = "WindJump", - category = ModuleCategory.MOVEMENT -) -public class WindJump extends Module { - - private static final String SETTING_ITEM_USAGE_MODE = "item_usage_mode"; - private static final String ACTION_WINDJUMP = "windjump"; - private static final String ACTION_WINDTHROW = "windthrow"; - - private static final float MIN_DOWN_PITCH = 60f; - private static final double MAX_BLOCK_DISTANCE = 1.5; - private static final double MIN_BLOCK_DISTANCE = 0.3; - private static final double FALL_TRIGGER_DISTANCE = 1.0; - private static final double FALL_TRIGGER_VERTICAL_SPEED = -0.05; // must be falling - private static final double WINDTHROW_TRIGGER_VERTICAL_SPEED = -0.12; - private static final double MAX_FALL_RAYCAST = 6.0; // extend ray when falling fast - private static final double WIND_CHARGE_SPEED = 1.5; - private static final double IMPACT_POINT_Y_OFFSET = 0.25; - private static final double MAX_THROW_PREDICTION_TICKS = 3.0; - private static final int USE_EXPIRE_TICKS = 2; - private static final int WIND_CHARGE_COOLDOWN_TICKS = 10; - private static final int HOTBAR_RESET_TICKS = 0; - private static final double MOTION_YAW_EPSILON = 0.08; - private static final int PREDICTION_TICKS = 7; - private static final double HORIZONTAL_LEAD_FACTOR = 0.32; - private static final double VERTICAL_LEAD_FACTOR = 0.85; - private static final double JUMP_VERTICAL_BONUS = 0.16; - private static final double MAX_HORIZONTAL_LEAD = 0.65; - private static final double IMPACT_BACKTRACK_FACTOR = 0.55; - private static final double MAX_IMPACT_BACKTRACK = 0.55; - private static final double JUMP_START_HORIZONTAL_LEAD_FACTOR = 0.08; - private static final double JUMP_START_VERTICAL_LEAD_FACTOR = 0.18; - private static final double JUMP_START_MAX_HORIZONTAL_LEAD = 0.12; - private static final double JUMP_START_IMPACT_BACKTRACK_FACTOR = 0.85; - private static final double JUMP_START_MAX_IMPACT_BACKTRACK = 0.80; - private static final double JUMP_THROW_INPUT_DELAY_TICKS = 0.08; - private static final double JUMP_START_MIN_LEAD_TICKS = 0.08; - private static final double JUMP_START_MAX_LEAD_TICKS = 0.28; - - private static final float THROW_PITCH = 90.0f; // straight down - private final EnumValue windThrowMode = - enumSetting("windThrowMode", SETTING_ITEM_USAGE_MODE, WindThrowMode.UNLOCKED, WindThrowMode.UNLOCKED, WindThrowMode.LEGIT); - private PendingUse pendingUse = null; - private int nextAllowedUseTick = 0; - private int lastJumpAge = Integer.MIN_VALUE; - - { - addAction(ACTION_WINDJUMP, "LEFT_ALT"); - addAction(ACTION_WINDTHROW, "LEFT_ALT+X"); - } - - @Override - public void onDisable() { - pendingUse = null; - nextAllowedUseTick = 0; - lastJumpAge = Integer.MIN_VALUE; - } - - @Override - public void onTick() { - if (!isEnabled()) return; - - Minecraft mc = Minecraft.getInstance(); - if (mc.player == null || mc.gameMode == null) return; - - LocalPlayer player = mc.player; - boolean windthrowHeld = isActionHeld(ACTION_WINDTHROW); - - if (processHeldWindJump(player)) { - return; - } - - // WindThrow on press - if (isActionPressedOnce(ACTION_WINDTHROW)) { - performWindThrow(player, false, 0.0); - } - - // Auto-trigger windthrow when key held and ground is approaching - if (windthrowHeld) { - double vy = player.getDeltaMovement().y; - if (vy <= WINDTHROW_TRIGGER_VERTICAL_SPEED && !player.onGround()) { - double rayDist = fallRayDistance(vy); - double dist = distanceToGround(player, rayDist); - - boolean withinImmediate = dist >= MIN_BLOCK_DISTANCE && dist <= FALL_TRIGGER_DISTANCE; - boolean willReachNextTick = dist > FALL_TRIGGER_DISTANCE - && dist <= rayDist - && (dist + vy) <= FALL_TRIGGER_DISTANCE; - - if (withinImmediate || willReachNextTick) { - if (!queueBestWindChargeUse(player, false, false, false)) { - performWindThrow(player, true, rayDist); - } - } - } - } - } - - @Override - public void onFrame(float tickDelta) { - if (!isEnabled()) return; - - Minecraft mc = Minecraft.getInstance(); - if (mc.player == null || mc.gameMode == null) return; - - LocalPlayer player = mc.player; - if (!player.isFallFlying() || !isActionHeld(ACTION_WINDJUMP)) return; - - if (getWindChargeHand(player) == null) return; - - double previewTicks = Math.max(0.0, tickDelta); - Vec3 predictedPos = predictSelfPosition(player, previewTicks, true, false); - - HitResult hit = player.level().clip(new ClipContext( - predictedPos.add(0.0, 0.2, 0.0), - predictedPos.add(0.0, -MAX_BLOCK_DISTANCE, 0.0), - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - - if (hit == null || hit.getType() != HitResult.Type.BLOCK) return; - - double distance = predictedPos.y - hit.getLocation().y(); - if (distance < MIN_BLOCK_DISTANCE || distance > MAX_BLOCK_DISTANCE) return; - - queueBestWindChargeUse(player, false, true, false); - } - - private boolean performWindThrow(LocalPlayer player, boolean allowNearGround, double nearGroundRange) { - if (player == null) return false; - if (player.inventoryMenu == null) return false; - if (!hasWindCharge(player)) return false; - - double vy = player.getDeltaMovement().y; - double range = allowNearGround ? Math.max(FALL_TRIGGER_DISTANCE, Math.min(MAX_FALL_RAYCAST, Math.max(FALL_TRIGGER_DISTANCE, nearGroundRange))) : 0.0; - boolean nearGround = allowNearGround && vy <= WINDTHROW_TRIGGER_VERTICAL_SPEED && isNearGround(player, range); - boolean onGround = player.onGround(); - boolean groundOk = onGround || nearGround; - if (!groundOk) return false; // only from ground / near-ground - - return queueBestWindChargeUse(player, onGround, false, false); - } - - private boolean processHeldWindJump(LocalPlayer player) { - if (player == null || !isActionHeld(ACTION_WINDJUMP)) { - return false; - } - - if (player.isFallFlying() - || player.isSwimming() - || player.isInWater() - || player.isInLava()) { - return false; - } - - if (!findCollision(player)) { - return false; - } - - return queueHeldWindJumpUse(player); - } - - private boolean canJumpNow(LocalPlayer player) { - return player != null - && !player.isPassenger() - && !player.getAbilities().flying - && (player.onGround() || player.isInWater() || player.isInLava()); - } - - @EventHandler(priority = -1000) - private void onMovementInput(MovementInputEvent event) { - if (!isEnabled() || !isActionHeld(ACTION_WINDJUMP)) return; - - LocalPlayer player = Minecraft.getInstance().player; - if (canStartHeldWindJump(player)) { - event.setJump(true); - } - } - - @EventHandler(priority = -1000) - private void onPlayerJump(PlayerJumpEvent event) { - if (!isEnabled()) return; - LocalPlayer player = Minecraft.getInstance().player; - if (player == null) return; - lastJumpAge = player.tickCount; - } - - @EventHandler(priority = -1000) - private void onSync(EventSync event) { - if (!isEnabled()) return; - - LocalPlayer player = Minecraft.getInstance().player; - MultiPlayerGameMode manager = Minecraft.getInstance().gameMode; - if (player == null || manager == null || pendingUse == null) return; - - PendingUse use = pendingUse; - if (player.tickCount > use.expireAge()) { - pendingUse = null; - return; - } - if (player.tickCount < nextAllowedUseTick) { - pendingUse = null; - return; - } - if (player.getCooldowns().isOnCooldown(Items.WIND_CHARGE.getDefaultInstance())) { - pendingUse = null; - return; - } - - pendingUse = null; - - event.setRotation(use.yaw(), use.pitch(), true); - executePendingUse(use); - } - - private void executePendingUse(PendingUse use) { - LocalPlayer player = Minecraft.getInstance().player; - MultiPlayerGameMode manager = Minecraft.getInstance().gameMode; - if (player == null || manager == null || use == null) return; - - float yaw = use.yaw(); - float pitch = use.pitch(); - int syncId = player.inventoryMenu != null ? player.inventoryMenu.containerId : -1; - boolean swapped = use.sourceScreenSlot() >= 0 && use.targetScreenSlot() >= 0 && syncId >= 0; - - float prevYaw = player.getYRot(); - float prevPitch = player.getXRot(); - try { - if (use.hotbarSlot() >= 0) { - InventorySwap.INSTANCE.leaseHotbar(this, use.hotbarSlot(), HOTBAR_RESET_TICKS); - } - if (swapped) { - InventorySwap.INSTANCE.swapScreenSlots(use.sourceScreenSlot(), use.targetScreenSlot()); - } - player.setYRot(yaw); - player.setXRot(pitch); - InteractionResult result = manager.useItem(player, use.hand()); - if (!result.consumesAction()) return; - player.swing(use.hand()); - nextAllowedUseTick = player.tickCount + WIND_CHARGE_COOLDOWN_TICKS; - } finally { - player.setYRot(prevYaw); - player.setXRot(prevPitch); - if (swapped) { - InventorySwap.INSTANCE.swapScreenSlots(use.sourceScreenSlot(), use.targetScreenSlot()); - } - } - } - - private int findWindChargeSlot(LocalPlayer player, int originalSlot) { - // prefer hotbar (excluding current slot), then rest of inventory - for (int i = 0; i < 9; i++) { - if (i == originalSlot) continue; - if (player.getInventory().getItem(i).is(Items.WIND_CHARGE)) return i; - } - for (int i = 9; i < 36; i++) { - if (player.getInventory().getItem(i).is(Items.WIND_CHARGE)) return i; - } - return -1; - } - - private InteractionHand getWindChargeHand(LocalPlayer player) { - ItemStack main = player.getMainHandItem(); - ItemStack off = player.getOffhandItem(); - if (isWindCharge(main)) return InteractionHand.MAIN_HAND; - if (isWindCharge(off)) return InteractionHand.OFF_HAND; - return null; - } - - private boolean isWindCharge(ItemStack stack) { - return stack != null && stack.getItem() == Items.WIND_CHARGE; - } - - private boolean hasWindCharge(LocalPlayer player) { - if (isWindCharge(player.getMainHandItem()) || isWindCharge(player.getOffhandItem())) { - return true; - } - return findWindChargeSlot(player, ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot()) != -1; - } - - private int findWindChargeHotbarSlot(LocalPlayer player) { - if (player == null) return -1; - for (int i = 0; i < 9; i++) { - if (player.getInventory().getItem(i).is(Items.WIND_CHARGE)) { - return i; - } - } - return -1; - } - - private boolean queueHeldWindJumpUse(LocalPlayer player) { - if (player == null || pendingUse != null || player.tickCount < nextAllowedUseTick) { - return false; - } - - UseSource source = resolveHeldWindJumpSource(player); - if (source == null) { - return false; - } - - Rotation rotation = buildJumpStartRotation(player); - pendingUse = new PendingUse( - source.hand(), - rotation.yaw(), - rotation.pitch(), - source.sourceScreenSlot(), - source.targetScreenSlot(), - source.hotbarSlot(), - player.tickCount + USE_EXPIRE_TICKS - ); - return true; - } - - private boolean canStartHeldWindJump(LocalPlayer player) { - if (!canJumpNow(player)) { - return false; - } - if (player == null || player.inventoryMenu == null) { - return false; - } - if (player.getCooldowns().isOnCooldown(Items.WIND_CHARGE.getDefaultInstance())) { - return false; - } - return resolveHeldWindJumpSource(player) != null; - } - - private UseSource resolveHeldWindJumpSource(LocalPlayer player) { - if (player == null) return null; - if (isWindCharge(player.getOffhandItem())) { - return new UseSource(InteractionHand.OFF_HAND, -1, -1, -1); - } - if (isWindCharge(player.getMainHandItem())) { - return new UseSource(InteractionHand.MAIN_HAND, -1, -1, -1); - } - - int hotbarSlot = findWindChargeHotbarSlot(player); - if (hotbarSlot == -1) { - return null; - } - - return new UseSource(InteractionHand.MAIN_HAND, -1, -1, hotbarSlot); - } - - private boolean queueBestWindChargeUse(LocalPlayer player, - boolean allowInventorySwap, - boolean preferJumpPrediction, - boolean jumpStartThrow) { - if (player == null) return false; - if (pendingUse != null) return false; - if (player.tickCount < nextAllowedUseTick) return false; - - UseSource source = resolveUseSource(player, allowInventorySwap); - if (source == null) return false; - - Rotation rotation = computeThrowRotation(player, preferJumpPrediction, jumpStartThrow); - if (rotation == null) return false; - - int expireAge = player.tickCount + USE_EXPIRE_TICKS; - pendingUse = new PendingUse( - source.hand(), - rotation.yaw(), - rotation.pitch(), - source.sourceScreenSlot(), - source.targetScreenSlot(), - source.hotbarSlot(), - expireAge - ); - return true; - } - - private UseSource resolveUseSource(LocalPlayer player, boolean allowInventorySwap) { - if (player == null) return null; - if (isWindCharge(player.getMainHandItem())) { - return new UseSource(InteractionHand.MAIN_HAND, -1, -1, -1); - } - if (isWindCharge(player.getOffhandItem())) { - return new UseSource(InteractionHand.OFF_HAND, -1, -1, -1); - } - if (!allowInventorySwap) { - return null; - } - - int selectedSlot = ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); - int windSlot = findWindChargeSlot(player, selectedSlot); - if (windSlot == -1) { - return null; - } - - return new UseSource( - InteractionHand.MAIN_HAND, - InventorySwap.mapInventoryToScreenSlot(windSlot), - InventorySwap.mapHotbarToScreenSlot(selectedSlot), - -1 - ); - } - - private Rotation computeThrowRotation(LocalPlayer player, - boolean preferJumpPrediction, - boolean jumpStartThrow) { - if (player == null) return null; - if (jumpStartThrow) { - return buildJumpStartRotation(player); - } - - Vec3 eyePos = player.getEyePosition(); - double leadTicks = Mth.clamp( - initialLeadTicks(player, preferJumpPrediction, jumpStartThrow), - jumpStartThrow ? 0.02 : 0.15, - MAX_THROW_PREDICTION_TICKS - ); - Vec3 impactPoint = null; - - for (int i = 0; i < 3; i++) { - Vec3 predictedSelf = predictSelfPosition(player, leadTicks, preferJumpPrediction, jumpStartThrow); - impactPoint = findGroundImpactPoint(player, predictedSelf, jumpStartThrow); - if (impactPoint == null) { - break; - } - - double flightTicks = Mth.clamp( - eyePos.distanceTo(impactPoint) / effectiveWindChargeSpeed(), - jumpStartThrow ? 0.02 : 0.15, - MAX_THROW_PREDICTION_TICKS - ); - if (Math.abs(flightTicks - leadTicks) < 0.1) { - break; - } - leadTicks = flightTicks; - } - - if (impactPoint == null) { - return fallbackRotation(player); - } - - Vec3 diff = impactPoint.subtract(eyePos); - double horizontalSq = diff.x * diff.x + diff.z * diff.z; - if (horizontalSq < 0.0025) { - return fallbackRotation(player); - } - - Rotation rotation = Rotation.lookingAt(impactPoint, eyePos); - float yaw = horizontalSq < 0.01 ? resolveMotionYaw(player, rotation.yaw()) : rotation.yaw(); - float pitch = Mth.clamp(Math.max(rotation.pitch(), MIN_DOWN_PITCH), MIN_DOWN_PITCH, THROW_PITCH); - return new Rotation(yaw, pitch, false).normalize(); - } - - private Rotation buildJumpStartRotation(LocalPlayer player) { - float directionYaw = MovementUtil.getMovementDirectionYaw(player, player.getYRot()) - 180.0f; - return new Rotation(directionYaw, 80.0f, false).normalize(); - } - - private Vec3 predictSelfPosition(LocalPlayer player, - double leadTicks, - boolean preferJumpPrediction, - boolean jumpStartThrow) { - double totalTicks = leadTicks; - if (jumpStartThrow) { - totalTicks += JUMP_THROW_INPUT_DELAY_TICKS; - } else if (preferJumpPrediction && isRecentJump(player)) { - totalTicks += 0.18; - } - totalTicks = Mth.clamp(totalTicks, 0.0, MAX_THROW_PREDICTION_TICKS); - - Vec3 position = player.position(); - Vec3 velocity = resolvePredictionVelocity(player, jumpStartThrow); - Vec3 horizontalVelocity = new Vec3(velocity.x, 0.0, velocity.z); - - double horizontalTicks = totalTicks * (jumpStartThrow ? JUMP_START_HORIZONTAL_LEAD_FACTOR : HORIZONTAL_LEAD_FACTOR); - Vec3 horizontalLead = horizontalVelocity.scale(horizontalTicks); - double horizontalLength = horizontalLead.horizontalDistance(); - double maxHorizontalLead = jumpStartThrow ? JUMP_START_MAX_HORIZONTAL_LEAD : MAX_HORIZONTAL_LEAD; - if (horizontalLength > maxHorizontalLead && horizontalLength > 1.0E-6) { - horizontalLead = horizontalLead.scale(maxHorizontalLead / horizontalLength); - } - - double verticalLead = velocity.y * totalTicks * (jumpStartThrow ? JUMP_START_VERTICAL_LEAD_FACTOR : VERTICAL_LEAD_FACTOR); - if (preferJumpPrediction && isRecentJump(player) && velocity.y > 0.0) { - double bonusScale = jumpStartThrow ? 0.12 : 0.35; - double bonusCap = jumpStartThrow ? JUMP_VERTICAL_BONUS * 0.4 : JUMP_VERTICAL_BONUS; - verticalLead += Math.min(bonusCap, velocity.y * bonusScale); - } - - return position.add(horizontalLead.x, verticalLead, horizontalLead.z); - } - - private Vec3 findGroundImpactPoint(LocalPlayer player, Vec3 predictedSelf, boolean jumpStartThrow) { - if (player == null || predictedSelf == null || player.level() == null) return null; - - double verticalRoom = Math.max(0.0, predictedSelf.y - player.getY()); - double rayDistance = Mth.clamp( - 2.2 + verticalRoom + Math.max(0.0, player.getDeltaMovement().y) * 5.0, - MAX_BLOCK_DISTANCE, - MAX_FALL_RAYCAST - ); - Vec3 start = new Vec3(predictedSelf.x, predictedSelf.y + 0.25, predictedSelf.z); - Vec3 end = start.add(0.0, -rayDistance, 0.0); - HitResult hit = player.level().clip(new ClipContext( - start, - end, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - if (hit != null && hit.getType() == HitResult.Type.BLOCK) { - Vec3 impact = hit.getLocation().add(0.0, IMPACT_POINT_Y_OFFSET, 0.0); - Vec3 horizontalVelocity = new Vec3(player.getDeltaMovement().x, 0.0, player.getDeltaMovement().z); - double speed = horizontalVelocity.horizontalDistance(); - if (speed > 1.0E-6) { - double factor = jumpStartThrow ? JUMP_START_IMPACT_BACKTRACK_FACTOR : IMPACT_BACKTRACK_FACTOR; - double maxBacktrack = jumpStartThrow ? JUMP_START_MAX_IMPACT_BACKTRACK : MAX_IMPACT_BACKTRACK; - double backtrack = Math.min(maxBacktrack, speed * factor); - impact = impact.subtract(horizontalVelocity.normalize().scale(backtrack)); - } - return impact; - } - return null; - } - - private Rotation fallbackRotation(LocalPlayer player) { - return new Rotation(resolveMotionYaw(player, player.getYRot()), THROW_PITCH, false).normalize(); - } - - private double initialLeadTicks(LocalPlayer player, boolean preferJumpPrediction, boolean jumpStartThrow) { - Vec3 velocity = resolvePredictionVelocity(player, jumpStartThrow); - if (jumpStartThrow) { - double lead = JUMP_THROW_INPUT_DELAY_TICKS - + Math.min(0.03, velocity.horizontalDistance() * 0.04) - + Math.min(0.04, Math.max(0.0, velocity.y) * 0.08); - if (preferJumpPrediction && isRecentJump(player)) { - lead += 0.01; - } - return Mth.clamp(lead, JUMP_START_MIN_LEAD_TICKS, JUMP_START_MAX_LEAD_TICKS); - } - - double lead = 0.35 - + Math.min(0.85, velocity.horizontalDistance() * 1.15) - + Math.min(0.65, Math.max(0.0, velocity.y) * 1.35); - if (preferJumpPrediction && isRecentJump(player)) { - lead += 0.45; - } - return Math.min(MAX_THROW_PREDICTION_TICKS, lead); - } - - private boolean isRecentJump(LocalPlayer player) { - if (player == null || lastJumpAge == Integer.MIN_VALUE) return false; - return player.tickCount - lastJumpAge <= 2; - } - - private boolean findCollision(LocalPlayer player) { - if (player == null || player.isFallFlying() || player.isSwimming() || player.isInWater() || player.isInLava()) { - return false; - } - - PlayerSimulationCache.SimulatedPlayerCache simulation = PlayerSimulationCache.getSimulationForLocalPlayer(); - if (simulation == null) { - return false; - } - - return simulation.getSnapshotAt(PREDICTION_TICKS).onGround(); - } - - private Vec3 resolvePredictionVelocity(LocalPlayer player, boolean jumpStartThrow) { - Vec3 velocity = player.getDeltaMovement(); - return velocity; - } - - private float resolveMotionYaw(LocalPlayer player, float fallbackYaw) { - if (player == null) return fallbackYaw; - - Vec3 velocity = player.getDeltaMovement(); - if (velocity.horizontalDistanceSqr() > MOTION_YAW_EPSILON * MOTION_YAW_EPSILON) { - return Mth.wrapDegrees((float) Math.toDegrees(Math.atan2(velocity.z, velocity.x)) - 90.0f); - } - - return Mth.wrapDegrees(MovementUtil.getMovementDirectionYaw(player, fallbackYaw)); - } - - private boolean isNearGround(LocalPlayer player, double maxDist) { - if (player == null || player.level() == null) return false; - double dist = distanceToGround(player, maxDist); - return dist >= 0 && dist <= maxDist; - } - - private double distanceToGround(LocalPlayer player, double maxDist) { - if (player == null || player.level() == null) return Double.POSITIVE_INFINITY; - Vec3 start = player.position(); - Vec3 end = start.add(0, -maxDist, 0); - HitResult hit = player.level().clip(new ClipContext( - start, - end, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - if (hit != null && hit.getType() == HitResult.Type.BLOCK) { - return start.y - hit.getLocation().y(); - } - return Double.POSITIVE_INFINITY; - } - - private double fallRayDistance(double vy) { - return Math.max(FALL_TRIGGER_DISTANCE, Math.min(MAX_FALL_RAYCAST, Math.abs(vy) * 2.0)); - } - - private double serverTickDelta() { - double delta = 1.0; - TPSSync tpsSync = Modules.get(TPSSync.class); - if (tpsSync != null && tpsSync.isEnabled()) { - delta = tpsSync.getServerTickDelta(); - } - return Math.max(0.05, delta); - } - - private double effectiveWindChargeSpeed() { - return WIND_CHARGE_SPEED * serverTickDelta(); - } - - @Getter - @RequiredArgsConstructor - private enum WindThrowMode implements EnumValue.IdProvider { - UNLOCKED("UNLOCKED"), - LEGIT("LEGIT"); - - private final String id; - } - - private record UseSource(InteractionHand hand, int sourceScreenSlot, int targetScreenSlot, int hotbarSlot) { - } - - private record PendingUse(InteractionHand hand, float yaw, float pitch, int sourceScreenSlot, int targetScreenSlot, - int hotbarSlot, int expireAge) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AirPlace.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AirPlace.java deleted file mode 100644 index fa52882..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AirPlace.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.player; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.protocol.game.ServerboundUseItemOnPacket; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.BindMode; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.config.values.RGBAColorValue; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.WorldPhase; -import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.renderer.Renderer3D; - -//todo Description -@ModuleInfo( - id = "airplace", - displayName = "AirPlace", - category = ModuleCategory.PLAYER -) -public class AirPlace extends Module { - - private static final String SETTING_DISTANCE = "distance"; - private static final String SETTING_FILL_COLOR = "fill_color"; - private static final String SETTING_LINE_COLOR = "line_color"; - private static final String SETTING_LINE_WIDTH = "line_width"; - private final Minecraft mc = Minecraft.getInstance(); - private final NumberValue distanceValue = - num("airplace_distance", SETTING_DISTANCE, 5f, 3f, 6f); - private final RGBAColorValue fillColor = - color("airplace_fill_color", SETTING_FILL_COLOR, "#326432FF"); - private final RGBAColorValue lineColor = - color("airplace_line_color", SETTING_LINE_COLOR, "#966432FF"); - private final NumberValue lineWidth = - num("airplace_line_width", SETTING_LINE_WIDTH, 2, 1, 5); - private BlockPos lastPos; - private boolean lastRayMiss = false; - private int sequence = 0; - private boolean prevUsePressed = false; - - { - addAction("increase_distance", "KP_ADD", BindMode.PRESS); - addAction("decrease_distance", "KP_SUBTRACT", BindMode.PRESS); - } - - private static void addFilledBox(Renderer3D renderer, AABB box, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - renderer.quad(minX, minY, minZ, maxX, minY, minZ, maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - renderer.quad(minX, maxY, minZ, minX, maxY, maxZ, maxX, maxY, maxZ, maxX, maxY, minZ, r, g, b, a); - renderer.quad(minX, minY, maxZ, maxX, minY, maxZ, maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - renderer.quad(minX, minY, minZ, minX, maxY, minZ, maxX, maxY, minZ, maxX, minY, minZ, r, g, b, a); - renderer.quad(maxX, minY, minZ, maxX, maxY, minZ, maxX, maxY, maxZ, maxX, minY, maxZ, r, g, b, a); - renderer.quad(minX, minY, minZ, minX, minY, maxZ, minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - } - - private static void addOutlineBox(Renderer3D renderer, AABB box, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - renderer.line(minX, minY, minZ, maxX, minY, minZ, r, g, b, a); - renderer.line(maxX, minY, minZ, maxX, minY, maxZ, r, g, b, a); - renderer.line(maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - renderer.line(minX, minY, maxZ, minX, minY, minZ, r, g, b, a); - - renderer.line(minX, maxY, minZ, maxX, maxY, minZ, r, g, b, a); - renderer.line(maxX, maxY, minZ, maxX, maxY, maxZ, r, g, b, a); - renderer.line(maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - renderer.line(minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - - renderer.line(minX, minY, minZ, minX, maxY, minZ, r, g, b, a); - renderer.line(maxX, minY, minZ, maxX, maxY, minZ, r, g, b, a); - renderer.line(maxX, minY, maxZ, maxX, maxY, maxZ, r, g, b, a); - renderer.line(minX, minY, maxZ, minX, maxY, maxZ, r, g, b, a); - } - - @Override - public void onTick() { - if (!isEnabled() || mc == null || mc.player == null) return; - - LocalPlayer player = mc.player; - boolean usePressed = mc.options.keyUse.isDown(); - - handleDistanceBinds(); - handleTick(player, usePressed); - - prevUsePressed = usePressed; - } - - private void handleTick(LocalPlayer player, boolean useKeyPressed) { - ItemStack stack = player.getMainHandItem(); - if (!(stack.getItem() instanceof BlockItem)) { - lastPos = null; - lastRayMiss = false; - return; - } - - updateTarget(player, distanceValue.get()); - - if (useKeyPressed && !prevUsePressed) { - if (lastRayMiss && lastPos != null) tryPlaceBlock(player); - } - } - - @Override - public WorldPhase getWorldPhase() { - return WorldPhase.END_MAIN; - } - - @Override - public void onRenderWorldEngine(Renderer3D renderer, Renderer3D depthRenderer, float tickDelta) { - if (!isEnabled() || mc.level == null || mc.player == null) return; - boolean main = mc.player.getMainHandItem().getItem() instanceof BlockItem; - boolean off = mc.player.getOffhandItem().getItem() instanceof BlockItem; - if (!main && !off) return; - if (!lastRayMiss || lastPos == null) return; - if (!isPlaceableTarget(lastPos)) return; - - AABB box = new AABB(lastPos); - int fill = fillColor.getArgb(); - int line = lineColor.getArgb(); - - float prevWidth = RenderState.lineWidth; - RenderState.lineWidth = Math.max(1.0f, lineWidth.get()); - try { - addFilledBox(renderer, box, fill); - addOutlineBox(renderer, box, line); - } finally { - RenderState.lineWidth = prevWidth; - } - } - - private void updateTarget(LocalPlayer player, double distance) { - Vec3 eye = player.getEyePosition(); - Vec3 end = eye.add(player.getViewVector(1f).normalize().scale(distance)); - - BlockHitResult hit = player.level().clip(new ClipContext( - eye, end, - ClipContext.Block.COLLIDER, - ClipContext.Fluid.NONE, - player - )); - - BlockPos pos; - if (hit.getType() == BlockHitResult.Type.MISS) { - pos = new BlockPos( - Mth.floor(end.x), - Mth.floor(end.y), - Mth.floor(end.z) - ); - lastRayMiss = true; - } else { - pos = hit.getBlockPos().relative(hit.getDirection()); - lastRayMiss = false; - } - - lastPos = isPlaceableTarget(pos) ? pos : null; - } - - private void tryPlaceBlock(LocalPlayer player) { - if (lastPos == null) return; - - ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); - if (!(stack.getItem() instanceof BlockItem)) return; - - if (mc.player.connection == null) return; - - Vec3 hitVec = new Vec3( - lastPos.getX() + 0.5, - lastPos.getY() + 0.5, - lastPos.getZ() + 0.5 - ); - - BlockHitResult hit = new BlockHitResult( - hitVec, Direction.UP, lastPos, false - ); - - mc.player.connection.send( - new ServerboundUseItemOnPacket(InteractionHand.MAIN_HAND, hit, sequence++) - ); - - player.swing(InteractionHand.MAIN_HAND); - - } - - private boolean isPlaceableTarget(BlockPos pos) { - if (pos == null || mc.level == null) return false; - - var state = mc.level.getBlockState(pos); - return state.isAir() || state.canBeReplaced() || !state.getFluidState().isEmpty(); - } - - private void handleDistanceBinds() { - double step = 1.0; - boolean changed = false; - - if (isActionPressedOnce("increase_distance")) { - distanceValue.set(distanceValue.castToType(Math.min(6.0, distanceValue.get() + step))); - changed = true; - } - if (isActionPressedOnce("decrease_distance")) { - distanceValue.set(distanceValue.castToType(Math.max(3.0, distanceValue.get() - step))); - changed = true; - } - - if (changed) { - saveConfig(); - } - } -} - diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoArmor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoArmor.java deleted file mode 100644 index c9db68c..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoArmor.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.player; - -import dev.loki.lovisual.util.screen.ClientScreen; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.inventory.InventoryScreen; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.component.DataComponents; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.Identifier; -import net.minecraft.resources.ResourceKey; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.inventory.ContainerInput; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.item.enchantment.Enchantments; -import net.minecraft.world.item.equipment.Equippable; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.ItemIdSetValue; -import dev.loki.lovisual.features.gui.clickgui.settings.TextListSetting; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.util.player.inventory.InventorySwap; - -import java.util.Set; - -//todo Description -@ModuleInfo( - id = "autoarmor", - displayName = "AutoArmor", - category = ModuleCategory.PLAYER -) -public class AutoArmor extends Module { - - private static final String SETTING_MODE = "mode"; - private static final String SETTING_ARMOR_ITEMS = "armor_items"; - private final EnumValue mode = - enumSetting("autoArmorMode", SETTING_MODE, Mode.AUTO, Mode.values()); - private final ItemIdSetValue armorItems = - visibleWhen(itemList("armor_items", SETTING_ARMOR_ITEMS, TextListSetting.PickerMode.EQUIPPABLE_ARMOR), - () -> mode.get() == Mode.WHITELIST); - private final Minecraft mc = Minecraft.getInstance(); - - @Override - public void onTick() { - if (!isEnabled() || mc.player == null || mc.gameMode == null || mc.level == null) return; - if (ClientScreen.current() != null && !(ClientScreen.current() instanceof InventoryScreen)) - return; - if (mc.player.inventoryMenu == null) return; - - int syncId = mc.player.inventoryMenu.containerId; - for (EquipmentSlot slot : EquipmentSlot.values()) { - if (slot.getType() != EquipmentSlot.Type.HUMANOID_ARMOR) continue; - - ItemStack equipped = mc.player.getItemBySlot(slot); - if (slot == EquipmentSlot.CHEST && equipped.is(Items.ELYTRA)) continue; - - Candidate best = findBestCandidate(slot); - if (best != null && isBetter(best.stack, equipped, slot)) { - int from = InventorySwap.mapInventoryToScreenSlot(best.invSlot); - int to = armorScreenSlot(slot); - InventorySwap.INSTANCE.swapScreenSlots(from, to); - return; - } - - if (isBroken(equipped)) { - if (best != null) { - int from = InventorySwap.mapInventoryToScreenSlot(best.invSlot); - int to = armorScreenSlot(slot); - InventorySwap.INSTANCE.swapScreenSlots(from, to); - return; - } - int armorSlot = armorScreenSlot(slot); - if (hasInventorySpace()) { - mc.gameMode.handleContainerInput(syncId, armorSlot, 0, ContainerInput.QUICK_MOVE, mc.player); - return; - } - } - } - } - - private Candidate findBestCandidate(EquipmentSlot slot) { - if (mc.player == null) return null; - Set whitelist = armorItems.get(); - int bestSlot = -1; - double bestScore = Double.NEGATIVE_INFINITY; - - for (int i = 0; i < 36; i++) { - ItemStack stack = mc.player.getInventory().getItem(i); - if (stack == null || stack.isEmpty()) continue; - if (!isEquippableForSlot(stack, slot)) continue; - if (isBroken(stack)) continue; - if (hasCurseOfBinding(stack)) continue; - if (mode.get() == Mode.WHITELIST && !isWhitelisted(stack, whitelist)) continue; - - double score = scoreArmor(stack, slot); - if (score > bestScore) { - bestScore = score; - bestSlot = i; - } - } - - return bestSlot >= 0 ? new Candidate(bestSlot, mc.player.getInventory().getItem(bestSlot).copy()) : null; - } - - private boolean isWhitelisted(ItemStack stack, Set ids) { - if (ids == null || ids.isEmpty()) return false; - Identifier id = BuiltInRegistries.ITEM.getKey(stack.getItem()); - return id != null && ids.contains(id.toString()); - } - - private boolean isEquippableForSlot(ItemStack stack, EquipmentSlot slot) { - Equippable eq = stack.get(DataComponents.EQUIPPABLE); - return eq != null && eq.slot() == slot; - } - - private boolean isBetter(ItemStack candidate, ItemStack current, EquipmentSlot slot) { - if (candidate == null || candidate.isEmpty()) return false; - if (current == null || current.isEmpty()) return true; - if (hasCurseOfBinding(current)) return false; - return scoreArmor(candidate, slot) > scoreArmor(current, slot); - } - - private double scoreArmor(ItemStack stack, EquipmentSlot slot) { - if (stack == null || stack.isEmpty()) return Double.NEGATIVE_INFINITY; - - double[] armor = new double[]{0.0}; - double[] toughness = new double[]{0.0}; - double[] kbResist = new double[]{0.0}; - stack.forEachModifier(slot, (attribute, modifier) -> { - if (attribute.is(Attributes.ARMOR)) { - armor[0] += modifier.amount(); - } else if (attribute.is(Attributes.ARMOR_TOUGHNESS)) { - toughness[0] += modifier.amount(); - } else if (attribute.is(Attributes.KNOCKBACK_RESISTANCE)) { - kbResist[0] += modifier.amount(); - } - }); - - int protection = getEnchantmentLevel(Enchantments.PROTECTION, stack); - int blast = getEnchantmentLevel(Enchantments.BLAST_PROTECTION, stack); - int projectile = getEnchantmentLevel(Enchantments.PROJECTILE_PROTECTION, stack); - int fire = getEnchantmentLevel(Enchantments.FIRE_PROTECTION, stack); - int unbreaking = getEnchantmentLevel(Enchantments.UNBREAKING, stack); - int mending = getEnchantmentLevel(Enchantments.MENDING, stack); - - return armor[0] * 10.0 - + toughness[0] * 4.0 - + kbResist[0] * 2.0 - + protection * 1.4 - + blast * 0.6 - + projectile * 0.4 - + fire * 0.3 - + unbreaking * 0.1 - + mending * 0.2; - } - - private boolean hasCurseOfBinding(ItemStack stack) { - Holder curse = getEnchantmentEntry(Enchantments.BINDING_CURSE); - return curse != null && EnchantmentHelper.getItemEnchantmentLevel(curse, stack) > 0; - } - - private int getEnchantmentLevel(ResourceKey key, ItemStack stack) { - Holder entry = getEnchantmentEntry(key); - return entry == null ? 0 : EnchantmentHelper.getItemEnchantmentLevel(entry, stack); - } - - private Holder getEnchantmentEntry(ResourceKey key) { - if (mc.level == null) return null; - Registry registry = mc.level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT); - Enchantment enchantment = registry.getValue(key); - return enchantment != null ? registry.wrapAsHolder(enchantment) : null; - } - - private boolean isBroken(ItemStack stack) { - if (stack == null || stack.isEmpty()) return false; - int max = stack.getMaxDamage(); - if (max <= 0) return false; - return (double) stack.getDamageValue() / max > 0.98; - } - - private boolean hasInventorySpace() { - if (mc.player == null) return false; - for (int i = 0; i < 36; i++) { - if (mc.player.getInventory().getItem(i).isEmpty()) { - return true; - } - } - return false; - } - - private int armorScreenSlot(EquipmentSlot slot) { - return switch (slot) { - case HEAD -> 5; - case CHEST -> 6; - case LEGS -> 7; - case FEET -> 8; - default -> -1; - }; - } - - public enum Mode { - AUTO, - WHITELIST - } - - private record Candidate(int invSlot, ItemStack stack) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoEat.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoEat.java deleted file mode 100644 index 822f224..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoEat.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.player; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.Identifier; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import dev.loki.lovisual.config.values.BooleanMapValue; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.features.gui.hud.draggable.impl.Itemizer; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.mixins.accessors.PlayerInventoryAccessor; -import dev.loki.lovisual.util.item.FoodUtil; -import dev.loki.lovisual.util.player.inventory.InventorySwap; - -//todo Description -@ModuleInfo( - id = "autoeat", - displayName = "AutoEat", - category = ModuleCategory.PLAYER -) -public class AutoEat extends Module { - - private static final String SETTING_EAT_MODE = "eat_mode"; - private static final String SETTING_HAND_MODE = "hand_mode"; - private static final String SETTING_AVOID_FOODS = "avoid_foods"; - private static final String SETTING_HP_THRESHOLD = "hp_threshold"; - - private final Minecraft mc = Minecraft.getInstance(); - private final EnumValue eatMode = - enumSetting("autoEatMode", SETTING_EAT_MODE, EatMode.INSTANT, EatMode.INSTANT, EatMode.EXACT); - private final EnumValue handMode = - enumSetting("autoEatHand", SETTING_HAND_MODE, HandMode.MAINHAND, HandMode.MAINHAND, HandMode.OFFHAND); - private final NumberValue hpThreshold = - num("autoEatHpThreshold", SETTING_HP_THRESHOLD, 8, 1, 20); - private final BooleanMapValue avoidFoods = group( - "autoEatAvoidFoods", - SETTING_AVOID_FOODS, - new java.util.LinkedHashMap<>() {{ - put("golden_apple", true); - put("enchanted_golden_apple", true); - }} - ); - private boolean forcingUse = false; - private boolean useKeyWasPressed = false; - private int prevSelectedSlot = -1; - private boolean restoreSelected = false; - private int restoreInvSlot = -1; - private int restoreHotbarSlot = -1; - private boolean restoreMainPending = false; - private int restoreOffhandSlot = -1; - private boolean restoreOffhandPending = false; - - @Override - public void onDisable() { - if (mc != null && mc.player != null) { - stopAutoUse(mc.player); - } - } - - @Override - public void onTick() { - if (!isEnabled()) return; - if (mc == null || mc.player == null || mc.gameMode == null) return; - - LocalPlayer player = mc.player; - - if (player.isSpectator() || player.getAbilities().instabuild) { - stopAutoUse(player); - return; - } - - if (player.isUsingItem()) { - if (FoodUtil.isFood(player.getUseItem())) { - if (forcingUse && !mc.options.keyUse.isDown()) { - mc.options.keyUse.setDown(true); - } - return; - } - stopAutoUse(player); - return; - } - - int hunger = player.getFoodData().getFoodLevel(); - int missing = 20 - hunger; - int hp = Math.round(player.getHealth() + player.getAbsorptionAmount()); - boolean emergency = hp <= hpThreshold.get(); - if (missing <= 0 && !emergency) { - stopAutoUse(player); - return; - } - - boolean exact = isExactMode(); - InteractionHand desiredHand = resolveDesiredHand(player); - - ItemStack offhand = player.getOffhandItem(); - ItemStack mainhand = player.getMainHandItem(); - boolean offhandCandidate = desiredHand == InteractionHand.OFF_HAND - && shouldEatWith(offhand, missing, exact, emergency); - boolean mainhandCandidate = desiredHand == InteractionHand.MAIN_HAND - && shouldEatWith(mainhand, missing, exact, emergency); - float offhandScore = offhandCandidate ? FoodUtil.scoreFood(offhand) : Float.NEGATIVE_INFINITY; - float mainhandScore = mainhandCandidate ? FoodUtil.scoreFood(mainhand) : Float.NEGATIVE_INFINITY; - - int bestSlot = handMode.get() == HandMode.OFFHAND - ? findBestFoodSlotPreferInventory(player, missing, exact, emergency) - : findBestFoodSlot(player, missing, exact, emergency); - if (bestSlot == -1 && (offhandCandidate || mainhandCandidate)) { - startUse(player, offhandCandidate ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND); - return; - } - if (bestSlot == -1) { - stopAutoUse(player); - return; - } - - float bestScore = FoodUtil.scoreFood(player.getInventory().getItem(bestSlot)); - if (offhandCandidate && offhandScore >= bestScore) { - startUse(player, InteractionHand.OFF_HAND); - return; - } - if (mainhandCandidate && mainhandScore >= bestScore) { - startUse(player, InteractionHand.MAIN_HAND); - return; - } - - boolean handReady = desiredHand == InteractionHand.OFF_HAND - ? ensureFoodInOffhand(player, bestSlot, bestScore) - : ensureFoodInMainhand(player, bestSlot, bestScore); - - if (!handReady) { - stopAutoUse(player); - return; - } - - ItemStack active = desiredHand == InteractionHand.OFF_HAND - ? player.getOffhandItem() - : player.getMainHandItem(); - - if (!shouldEatWith(active, missing, exact, emergency)) { - stopAutoUse(player); - return; - } - - startUse(player, desiredHand); - } - - private boolean isExactMode() { - return eatMode.get() == EatMode.EXACT; - } - - private InteractionHand resolveDesiredHand(LocalPlayer player) { - boolean offhandBlocked = player.getOffhandItem().is(Items.TOTEM_OF_UNDYING); - if (handMode.get() == HandMode.OFFHAND && !offhandBlocked) { - return InteractionHand.OFF_HAND; - } - return InteractionHand.MAIN_HAND; - } - - private boolean shouldEatWith(ItemStack stack, int missing, boolean exact, boolean emergency) { - if (!FoodUtil.isFood(stack)) return false; - if (!isFoodAllowed(stack)) return false; - if (!exact || emergency) { - if (missing > 0) return true; - return emergency && FoodUtil.canAlwaysEat(stack); - } - return FoodUtil.getNutrition(stack) <= missing; - } - - private int findBestFoodSlot(LocalPlayer player, int missing, boolean exact, boolean emergency) { - int bestSlot = -1; - float bestScore = Float.NEGATIVE_INFINITY; - - for (int i = 0; i < 36; i++) { - ItemStack stack = player.getInventory().getItem(i); - if (!FoodUtil.isFood(stack)) continue; - if (!isFoodAllowed(stack)) continue; - if (exact && !emergency && FoodUtil.getNutrition(stack) > missing) continue; - if (emergency && missing <= 0 && !FoodUtil.canAlwaysEat(stack)) continue; - - float score = FoodUtil.scoreFood(stack); - if (score > bestScore) { - bestScore = score; - bestSlot = i; - } - } - - return bestSlot; - } - - private int findBestFoodSlotPreferInventory(LocalPlayer player, int missing, boolean exact, boolean emergency) { - int bestSlot = -1; - float bestScore = Float.NEGATIVE_INFINITY; - - for (int i = 9; i < 36; i++) { - ItemStack stack = player.getInventory().getItem(i); - if (!FoodUtil.isFood(stack)) continue; - if (!isFoodAllowed(stack)) continue; - if (exact && !emergency && FoodUtil.getNutrition(stack) > missing) continue; - if (emergency && missing <= 0 && !FoodUtil.canAlwaysEat(stack)) continue; - float score = FoodUtil.scoreFood(stack); - if (score > bestScore) { - bestScore = score; - bestSlot = i; - } - } - - if (bestSlot != -1) return bestSlot; - return findBestFoodSlot(player, missing, exact, emergency); - } - - private boolean ensureFoodInMainhand(LocalPlayer player, int bestSlot, float bestScore) { - PlayerInventoryAccessor inv = (PlayerInventoryAccessor) player.getInventory(); - - if (restoreMainPending) { - inv.combatant$setSelectedSlot(restoreHotbarSlot); - return true; - } - - ItemStack main = player.getMainHandItem(); - float mainScore = FoodUtil.scoreFood(main); - if (FoodUtil.isFood(main) && mainScore >= bestScore) return true; - - if (bestSlot < 0) return false; - - if (bestSlot < 9) { - int selected = inv.combatant$getSelectedSlot(); - if (selected != bestSlot) { - prevSelectedSlot = selected; - restoreSelected = true; - inv.combatant$setSelectedSlot(bestSlot); - } - return true; - } - - int targetHotbar = findEmptyHotbarSlot(player); - int selected = inv.combatant$getSelectedSlot(); - if (targetHotbar == -1) targetHotbar = selected; - - if (targetHotbar != selected) { - prevSelectedSlot = selected; - restoreSelected = true; - } - inv.combatant$setSelectedSlot(targetHotbar); - - if (player.inventoryMenu == null) return false; - - restoreInvSlot = bestSlot; - restoreHotbarSlot = targetHotbar; - restoreMainPending = true; - - InventorySwap.INSTANCE.swapScreenSlots(InventorySwap.mapInventoryToScreenSlot(bestSlot), InventorySwap.mapHotbarToScreenSlot(targetHotbar)); - return true; - } - - private boolean ensureFoodInOffhand(LocalPlayer player, int bestSlot, float bestScore) { - if (restoreOffhandPending) return true; - - ItemStack off = player.getOffhandItem(); - float offScore = FoodUtil.scoreFood(off); - if (FoodUtil.isFood(off) && offScore >= bestScore) return true; - - if (bestSlot < 0) return false; - if (player.inventoryMenu == null) return false; - - restoreOffhandSlot = bestSlot; - restoreOffhandPending = true; - - InventorySwap.INSTANCE.swapInventoryToOffhand(bestSlot); - return true; - } - - private int findEmptyHotbarSlot(LocalPlayer player) { - for (int i = 0; i < 9; i++) { - if (player.getInventory().getItem(i).isEmpty()) return i; - } - return -1; - } - - private boolean isFoodAllowed(ItemStack stack) { - if (stack == null || stack.isEmpty()) return false; - Identifier id = BuiltInRegistries.ITEM.getKey(stack.getItem()); - if (id == null) return true; - String key = id.getPath(); - if (!avoidFoods.getAll().containsKey(key)) return true; - return !avoidFoods.get(key); - } - - private void startUse(LocalPlayer player, InteractionHand hand) { - if (!forcingUse) { - useKeyWasPressed = mc.options.keyUse.isDown(); - } - - if (!mc.options.keyUse.isDown()) { - mc.options.keyUse.setDown(true); - } - forcingUse = true; - - ItemStack used = hand == InteractionHand.OFF_HAND - ? player.getOffhandItem().copy() - : player.getMainHandItem().copy(); - InteractionResult r = mc.gameMode.useItem(player, hand); - if (r.consumesAction()) { - player.swing(hand); - Itemizer.showAutoEat(used); - } - } - - private void stopAutoUse(LocalPlayer player) { - if (forcingUse && !useKeyWasPressed) { - mc.options.keyUse.setDown(false); - } - forcingUse = false; - - if (restoreMainPending) { - restoreMainPending = false; - restoreMainSwap(player); - } - - if (restoreOffhandPending) { - restoreOffhandPending = false; - restoreOffhandSwap(player); - } - - if (restoreSelected) { - restoreSelected = false; - if (prevSelectedSlot >= 0) { - ((PlayerInventoryAccessor) player.getInventory()).combatant$setSelectedSlot(prevSelectedSlot); - } - prevSelectedSlot = -1; - } - } - - private void restoreMainSwap(LocalPlayer player) { - if (restoreInvSlot < 0 || restoreHotbarSlot < 0) return; - if (player.inventoryMenu == null) return; - - InventorySwap.INSTANCE.swapScreenSlots(InventorySwap.mapInventoryToScreenSlot(restoreInvSlot), InventorySwap.mapHotbarToScreenSlot(restoreHotbarSlot)); - - restoreInvSlot = -1; - restoreHotbarSlot = -1; - } - - private void restoreOffhandSwap(LocalPlayer player) { - if (restoreOffhandSlot < 0) return; - if (player.inventoryMenu == null) return; - - InventorySwap.INSTANCE.swapInventoryToOffhand(restoreOffhandSlot); - restoreOffhandSlot = -1; - } - - @Getter - @RequiredArgsConstructor - private enum EatMode implements EnumValue.IdProvider { - INSTANT("INSTANT"), - EXACT("EXACT"); - - private final String id; - } - - @Getter - @RequiredArgsConstructor - private enum HandMode implements EnumValue.IdProvider { - MAINHAND("MAINHAND"), - OFFHAND("OFFHAND"); - - private final String id; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoTool.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoTool.java index 67943b2..95f4a81 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoTool.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoTool.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -56,10 +56,10 @@ public class AutoTool extends Module { boolean breakingNow = mc.options.keyAttack.isDown() && mc.gameMode.isDestroying(); if (breakingNow && mc.gameMode instanceof MultiPlayerGameModeAccessor accessor) { - BlockPos pos = accessor.combatant$getCurrentBreakingPos(); + BlockPos pos = accessor.lovisual$getCurrentBreakingPos(); if (pos != null) { int bestSlot = findBestHotbarTool(pos); - int selected = ((PlayerInventoryAccessor) mc.player.getInventory()).combatant$getSelectedSlot(); + int selected = ((PlayerInventoryAccessor) mc.player.getInventory()).lovisual$getSelectedSlot(); if (bestSlot >= 0 && bestSlot != selected) { if (originalSlot < 0) { originalSlot = selected; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoTotem.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoTotem.java deleted file mode 100644 index 4719046..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/AutoTotem.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.player; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.world.entity.boss.enderdragon.EndCrystal; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.values.BooleanValue; -import dev.loki.lovisual.config.values.NumberValue; -import dev.loki.lovisual.features.gui.hud.draggable.impl.Itemizer; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.util.player.inventory.InventorySwap; - -import java.util.function.Predicate; - -//todo Description -@ModuleInfo( - id = "autototem", - displayName = "AutoTotem", - category = ModuleCategory.PLAYER -) -public class AutoTotem extends Module { - private final Minecraft mc = Minecraft.getInstance(); - - private final NumberValue healthThreshold = - numCommon( - "autototem_threshold", - "health_threshold", - CommonSettingSchemas.PLAYER_HEALTH_THRESHOLD, - 10.0f, - 1.0f, - 40.0f - ); - - private final NumberValue elytraHealth = - numCommon( - "autototem_elytra_health", - "elytra_health", - CommonSettingSchemas.PLAYER_ELYTRA_HEALTH, - 8.5f, - 1.0f, - 40.0f - ); - - private final NumberValue crystalDistance = - numCommon( - "autototem_crystal_distance", - "crystal_distance", - CommonSettingSchemas.COMBAT_CRYSTAL_DISTANCE, - 4.0f, - 1.0f, - 6.0f - ); - - private final BooleanValue fallCheck = - boolCommon( - "autototem_fall_check", - "fall_check", - CommonSettingSchemas.PLAYER_FALL_CHECK, - true - ); - - private final BooleanValue saveTaliks = - boolCommon( - "autototem_save_taliks", - "save_taliks", - CommonSettingSchemas.ITEMS_SAVE_UNENCHANTED, - true - ); - - private final BooleanValue returnItem = - boolCommon( - "autototem_return_item", - "return_item", - CommonSettingSchemas.INVENTORY_RESTORE_ITEM, - true - ); - - private ItemStack previousOffhand = ItemStack.EMPTY; - private int previousOffhandSlot = -1; - private boolean usingTotem = false; - private boolean offhandSwapPending = false; - - @Override - public void onTick() { - if (!isEnabled()) return; - - if (mc.player == null || mc.level == null || mc.isPaused()) { - offhandSwapPending = false; - return; - } - - if (offhandSwapPending) { - return; - } - - LocalPlayer player = mc.player; - - float health = player.getHealth() + player.getAbsorptionAmount(); - - boolean shouldHoldTotem = shouldHoldTotem(player, health); - if (shouldHoldTotem) { - equipTotem(player); - return; - } - - if (usingTotem && returnItem.get()) { - restorePrevious(player); - } - } - - @Override - public void onDisable() { - offhandSwapPending = false; - clearRestoreState(); - } - - private boolean shouldHoldTotem(LocalPlayer player, float health) { - if (player.isFallFlying() && health <= elytraHealth.get()) { - return true; - } - - if (health <= healthThreshold.get()) { - return true; - } - - if (fallCheck.get() && player.fallDistance > 10.0f) { - return true; - } - - return getClosestCrystalDistance(player) <= crystalDistance.get(); - } - - public boolean shouldHoldTotemNow(LocalPlayer player) { - if (!isEnabled() || player == null) return false; - return shouldHoldTotem(player, player.getHealth() + player.getAbsorptionAmount()); - } - - public boolean canProvideTotemNow(LocalPlayer player) { - if (!isEnabled()) return false; - if (player == null || mc.gameMode == null) return false; - if (isTotemInOffhand(player)) return true; - if (offhandSwapPending) return false; - return findTotemSlot(player) != -1; - } - - public boolean ensureTotemForDanger(LocalPlayer player) { - if (!canProvideTotemNow(player)) return false; - if (isTotemInOffhand(player)) return true; - - int slot = findTotemSlot(player); - if (slot == -1) return false; - - rememberPreviousOffhand(player, slot); - return swapTotemToOffhand(player, slot); - } - - - public boolean isTotemSwapPending() { - return offhandSwapPending; - } - - private void equipTotem(LocalPlayer player) { - if (player == null || mc.gameMode == null) return; - if (isTotemInOffhand(player)) return; - int slot = findTotemSlot(player); - if (slot == -1) return; - - rememberPreviousOffhand(player, slot); - swapTotemToOffhand(player, slot); - } - - private boolean swapTotemToOffhand(LocalPlayer player, int slot) { - if (player == null || mc.gameMode == null || offhandSwapPending) return false; - - offhandSwapPending = true; - ItemStack displayStack = player.getInventory().getItem(slot).copy(); - boolean accepted = InventorySwap.INSTANCE.swapInventoryToOffhand(slot, () -> { - usingTotem = true; - offhandSwapPending = false; - Itemizer.showAutoTotem(displayStack); - }); - if (!accepted) { - offhandSwapPending = false; - } - return accepted; - } - - private void restorePrevious(LocalPlayer player) { - if (player == null || mc.gameMode == null) return; - - if (previousOffhand.isEmpty()) { - clearRestoreState(); - return; - } - - if (!player.getOffhandItem().is(Items.TOTEM_OF_UNDYING)) { - clearRestoreState(); - return; - } - - int restoreSlot = resolveRestoreSlot(player); - if (restoreSlot == -1) { - clearRestoreState(); - return; - } - - requestOffhandSwap(restoreSlot, this::clearRestoreState); - } - - private void rememberPreviousOffhand(LocalPlayer player, int totemSlot) { - if (player == null) return; - if (usingTotem) return; - - ItemStack offhand = player.getOffhandItem(); - if (offhand.isEmpty()) { - previousOffhand = ItemStack.EMPTY; - previousOffhandSlot = -1; - return; - } - - previousOffhand = offhand.copy(); - previousOffhandSlot = totemSlot; - } - - private boolean requestOffhandSwap(int slot, Runnable afterSwap) { - if (offhandSwapPending) return false; - - offhandSwapPending = true; - boolean accepted = InventorySwap.INSTANCE.swapInventoryToOffhand(slot, () -> { - if (afterSwap != null) { - afterSwap.run(); - } - offhandSwapPending = false; - }); - if (!accepted) { - offhandSwapPending = false; - } - return accepted; - } - - private int findTotemSlot(LocalPlayer player) { - if (saveTaliks.get()) { - int nonEnchanted = find(player, stack -> - stack.is(Items.TOTEM_OF_UNDYING) && !stack.isEnchanted() - ); - - if (nonEnchanted != -1) { - return nonEnchanted; - } - } - - return find(player, Items.TOTEM_OF_UNDYING); - } - - private int find(LocalPlayer player, Item item) { - return find(player, stack -> stack.is(item)); - } - - private int find(LocalPlayer player, Predicate predicate) { - if (player == null || predicate == null) return -1; - - for (int i = 0; i < 36; i++) { - ItemStack stack = player.getInventory().getItem(i); - if (!stack.isEmpty() && predicate.test(stack)) { - return i; - } - } - - return -1; - } - - private int findItem(LocalPlayer player, ItemStack target) { - if (player == null || target == null || target.isEmpty()) return -1; - - for (int i = 0; i < 36; i++) { - ItemStack stack = player.getInventory().getItem(i); - if (!stack.isEmpty() && ItemStack.isSameItemSameComponents(stack, target)) { - return i; - } - } - - return -1; - } - - private int resolveRestoreSlot(LocalPlayer player) { - if (previousOffhandSlot >= 0 && previousOffhandSlot < 36) { - ItemStack stack = player.getInventory().getItem(previousOffhandSlot); - if (!stack.isEmpty() && ItemStack.isSameItemSameComponents(stack, previousOffhand)) { - return previousOffhandSlot; - } - } - - return findItem(player, previousOffhand); - } - - private double getClosestCrystalDistance(LocalPlayer player) { - if (player == null || mc.level == null) { - return Double.MAX_VALUE; - } - - double minDist = Double.MAX_VALUE; - double range = crystalDistance.get(); - - for (EndCrystal crystal : mc.level.getEntitiesOfClass( - EndCrystal.class, - player.getBoundingBox().inflate(range), - crystal -> crystal != null && !crystal.isRemoved() - )) { - double dist = player.position().distanceTo(crystal.position()); - if (dist < minDist) { - minDist = dist; - } - } - - return minDist; - } - - private boolean isTotemInOffhand(LocalPlayer player) { - return player != null && player.getOffhandItem().is(Items.TOTEM_OF_UNDYING); - } - - private void clearRestoreState() { - previousOffhand = ItemStack.EMPTY; - previousOffhandSlot = -1; - usingTotem = false; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/ClickPearl.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/ClickPearl.java index 8401382..da481de 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/ClickPearl.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/ClickPearl.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -60,7 +60,7 @@ public class ClickPearl extends Module { if (player.getCooldowns().isOnCooldown(new ItemStack(Items.ENDER_PEARL))) return; PlayerInventoryAccessor inv = (PlayerInventoryAccessor) player.getInventory(); - int originalSlot = inv.combatant$getSelectedSlot(); + int originalSlot = inv.lovisual$getSelectedSlot(); ItemStack off = player.getOffhandItem(); if (isPearl(off)) { @@ -71,10 +71,10 @@ public class ClickPearl extends Module { int hotbarPearl = findPearlInHotbar(player); if (hotbarPearl != -1) { - inv.combatant$setSelectedSlot(hotbarPearl); + inv.lovisual$setSelectedSlot(hotbarPearl); manager.useItem(player, InteractionHand.MAIN_HAND); player.swing(InteractionHand.MAIN_HAND); - inv.combatant$setSelectedSlot(originalSlot); + inv.lovisual$setSelectedSlot(originalSlot); return; } @@ -93,10 +93,10 @@ public class ClickPearl extends Module { InventorySwap.INSTANCE.swapScreenSlots(pearlScreen, targetScreen); - inv.combatant$setSelectedSlot(emptyHotbar); + inv.lovisual$setSelectedSlot(emptyHotbar); manager.useItem(player, InteractionHand.MAIN_HAND); player.swing(InteractionHand.MAIN_HAND); - inv.combatant$setSelectedSlot(originalSlot); + inv.lovisual$setSelectedSlot(originalSlot); } else { int targetScreen = InventorySwap.mapHotbarToScreenSlot(originalSlot); int pearlScreen = InventorySwap.mapInventoryToScreenSlot(invPearl); @@ -118,7 +118,7 @@ public class ClickPearl extends Module { } } - inv.combatant$setSelectedSlot(originalSlot); + inv.lovisual$setSelectedSlot(originalSlot); } }); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/FakeLag.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/FakeLag.java index 7a48733..f1e1073 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/FakeLag.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/FakeLag.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/NoDelay.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/NoDelay.java index 3da5c48..cf357e6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/NoDelay.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/NoDelay.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -126,13 +126,13 @@ public final class NoDelay extends Module { } if (types.get(TYPE_RIGHT_CLICK)) { - ((MinecraftAccessor) mc).combatant$setItemUseCooldown(0); + ((MinecraftAccessor) mc).lovisual$setItemUseCooldown(0); } else if (types.get(TYPE_BLOCK_PLACE)) { applyBlockPlaceCooldown(); } if (types.get(TYPE_BREAK_COOLDOWN) && mc.gameMode instanceof MultiPlayerGameModeAccessor accessor) { - accessor.combatant$setBlockBreakingCooldown(0); + accessor.lovisual$setBlockBreakingCooldown(0); } if (types.get(TYPE_FAST_BREAK)) { @@ -142,7 +142,7 @@ public final class NoDelay extends Module { } if (types.get(TYPE_JUMP)) { - ((LivingEntityAccessor) mc.player).combatant$setJumpingCooldown(0); + ((LivingEntityAccessor) mc.player).lovisual$setJumpingCooldown(0); } } @@ -217,10 +217,10 @@ public final class NoDelay extends Module { if (!isBlockPlaceCandidate(mc.player, mc.hitResult)) return; MinecraftAccessor accessor = (MinecraftAccessor) mc; - int current = accessor.combatant$getItemUseCooldown(); + int current = accessor.lovisual$getItemUseCooldown(); int maxCooldown = blockPlaceCooldownTicks.get(); if (current > maxCooldown) { - accessor.combatant$setItemUseCooldown(maxCooldown); + accessor.lovisual$setItemUseCooldown(maxCooldown); } } @@ -244,10 +244,10 @@ public final class NoDelay extends Module { return; } - BlockPos pos = accessor.combatant$getCurrentBreakingPos(); + BlockPos pos = accessor.lovisual$getCurrentBreakingPos(); if (pos == null) return; - float progress = accessor.combatant$getCurrentBreakingProgress(); + float progress = accessor.lovisual$getCurrentBreakingProgress(); float requiredProgress = fastBreakMode.get() == FastBreakMode.VULCAN_297 ? Math.max(fastBreakProgress.get(), VULCAN_297_MIN_SERVER_ACCEPT_PROGRESS) : fastBreakProgress.get(); @@ -260,7 +260,7 @@ public final class NoDelay extends Module { // Let vanilla finish the break during handleKeybinds on the next tick. Its STOP packet // is then sent before LocalPlayer emits movement, outside Vulcan 2.9.7 BadPackets N's // "movement -> <5 ms dig -> 40..100 ms movement" timing window. - accessor.combatant$setCurrentBreakingProgress(1.0f); + accessor.lovisual$setCurrentBreakingProgress(1.0f); lastBoostedBreakPos = pos.immutable(); return; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/NoInteract.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/NoInteract.java index e8718a9..11a655b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/NoInteract.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/NoInteract.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,9 +11,6 @@ import dev.loki.lovisual.config.values.BooleanValue; import dev.loki.lovisual.features.module.Module; import dev.loki.lovisual.features.module.ModuleCategory; import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.KillAura; - //todo Description @ModuleInfo( id = "nointeract", @@ -24,11 +21,10 @@ public final class NoInteract extends Module { private final BooleanValue onlyKillAura = bool("only_kill_aura", true); public boolean shouldBlockBlockInteraction() { - KillAura killAura = Modules.get(KillAura.class); return shouldBlockBlockInteraction( isEnabled(), onlyKillAura.get(), - killAura != null && killAura.isEnabled() + false ); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/Scaffold.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/Scaffold.java deleted file mode 100644 index 0d88b2f..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/Scaffold.java +++ /dev/null @@ -1,2416 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.features.module.modules.player; - -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.events.impl.*; -import dev.loki.lovisual.features.module.*; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.util.block.scaffold.*; -import dev.loki.lovisual.util.screen.ClientScreen; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Input; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.SettingDef; -import dev.loki.lovisual.config.values.*; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.impl.*; -import dev.loki.lovisual.features.gui.hud.nondraggable.impl.BetterTooltips; -import dev.loki.lovisual.features.module.*; -import dev.loki.lovisual.mixins.accessors.ServerboundMovePlayerPacketAccessor; -import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.core.ViewportContext; -import dev.loki.lovisual.render.engine.math.HudScale; -import dev.loki.lovisual.render.engine.renderer.Renderer2D; -import dev.loki.lovisual.render.engine.renderer.Renderer3D; -import dev.loki.lovisual.render.engine.text.FontInfo; -import dev.loki.lovisual.render.engine.text.Fonts; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.render.helpers.TickDelta; -import dev.loki.lovisual.util.aiming.RestrictedSingleUseAction; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.RotationUtil; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.aiming.features.processors.RotationProcessor; -import dev.loki.lovisual.util.aiming.features.processors.anglesmooth.AngleSmooth; -import dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.AccelerationAngleSmooth; -import dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.InterpolationAngleSmooth; -import dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.LinearAngleSmooth; -import dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.SigmoidAngleSmooth; -import dev.loki.lovisual.util.block.scaffold.*; -import dev.loki.lovisual.util.entity.EagleUtil; -import dev.loki.lovisual.util.player.MovementUtil; -import dev.loki.lovisual.util.player.inventory.InventorySwap; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -//todo Description -@ModuleInfo(id = "scaffold", displayName = "Scaffold", aliases = {"bridge", "autobridge"}, category = ModuleCategory.PLAYER) -public class Scaffold extends Module { - private static final boolean DEBUG_LOGS = true; - private static final List NORMAL_OFFSETS = commonOffsets(0, -1, 1); - private static final List DOWN_OFFSETS = commonOffsets(0, -1, 1, -2, 2); - private final EnumValue rotationTiming = - new EnumValue<>("rotation_timing", RotationTiming.NORMAL, RotationTiming.values()); - private final EnumValue technique = - new EnumValue<>("technique", Technique.NORMAL, Technique.values()); - private final EnumValue sameY = - new EnumValue<>("same_y", SameYMode.OFF, SameYMode.values()); - private final EnumValue movementCorrection = - new EnumValue<>("movement_correction", MovementCorrection.SILENT, MovementCorrection.values()); - private final EnumValue angleSmoothMode = - new EnumValue<>("angle_smooth_mode", AngleSmoothMode.INTERPOLATION, AngleSmoothMode.values()); - private final EnumValue clientSprintMode = - new EnumValue<>("client_sprint_mode", SprintMode.DO_NOT_CHANGE, SprintMode.values()); - private final EnumValue serverSprintMode = - new EnumValue<>("server_sprint_mode", SprintMode.DO_NOT_CHANGE, SprintMode.values()); - private final EnumValue towerMode = - new EnumValue<>("tower_mode", TowerMode.NONE, TowerMode.values()); - private final EnumValue tellyResetMode = - new EnumValue<>("telly_reset_mode", TellyResetMode.RESET, TellyResetMode.values()); - private final EnumValue aimMode = - new EnumValue<>("aim_mode", ScaffoldFacePositionFactory.Mode.STABILIZED, ScaffoldFacePositionFactory.Mode.values()); - private final EnumValue placementIndicatorSide = - new EnumValue<>("placement_indicator_side", IndicatorSide.LEFT, IndicatorSide.values()); - private final EnumValue placementIndicatorStyle = - new EnumValue<>("placement_indicator_style", IndicatorStyle.PILL, IndicatorStyle.values()); - private final EnumValue placementIndicatorCountMode = - new EnumValue<>("placement_indicator_count_mode", IndicatorCountMode.CURRENT_STACK, IndicatorCountMode.values()); - private final BooleanValue autoBlock = - new BooleanValue("auto_block", true); - private final BooleanValue renderPlacement = - new BooleanValue("render_placement", true); - private final BooleanValue placementIndicator = - new BooleanValue("placement_indicator", true); - private final BooleanValue placementIndicatorBackground = - new BooleanValue("placement_indicator_background", true); - private final BooleanValue autoBlockAlways = - new BooleanValue("auto_block_always", false); - private final BooleanValue prediction = - new BooleanValue("prediction", true); - private final BooleanValue considerInventory = - new BooleanValue("consider_inventory", false); - private final BooleanValue down = - new BooleanValue("down", false); - private final BooleanValue eagle = - new BooleanValue("eagle", false); - private final BooleanValue eagleOnlyOnGround = - new BooleanValue("eagle_only_on_ground", true); - private final NumberValue placementSpeed = - new NumberValue<>("placement_speed", 6.0, 1.0, 20.0); - private final NumberValue delay = - new NumberValue<>("delay", 0, 0, 20); - private final NumberValue autoBlockSlotResetDelay = - new NumberValue<>("auto_block_slot_reset_delay", 5, 0, 40); - private final NumberValue autoBlockDoNotUseBelowCount = - new NumberValue<>("auto_block_do_not_use_below_count", 1, 0, 64); - private final NumberValue blocksToEagle = - new NumberValue<>("blocks_to_eagle", 0, 0, 10); - private final NumberValue expandLength = - new NumberValue<>("expand_length", 4, 1, 10); - private final NumberValue eagleEdgeDistance = - new NumberValue<>("eagle_edge_distance", 0.01, 0.01, 1.3); - private final NumberValue minDist = - new NumberValue<>("min_dist", 0.0, 0.0, 0.25); - private final BooleanValue acceleration = - new BooleanValue("acceleration", false); - private final NumberValue accelerationMultiplier = - new NumberValue<>("acceleration_multiplier", 0.6, 0.1, 3.0); - private final BooleanValue accelerationOnlyOnGround = - new BooleanValue("acceleration_only_on_ground", false); - private final BooleanValue strafe = - new BooleanValue("strafe", false); - private final NumberValue strafeSpeed = - new NumberValue<>("strafe_speed", 0.247, 0.0, 5.0); - private final BooleanValue strafeHypixel = - new BooleanValue("strafe_hypixel", false); - private final BooleanValue strafeOnlyOnGround = - new BooleanValue("strafe_only_on_ground", false); - private final BooleanValue jumpStrafe = - new BooleanValue("jump_strafe", false); - private final NumberValue jumpStrafeStraightMin = - new NumberValue<>("jump_strafe_straight_min", 0.48, 0.1, 1.0); - private final NumberValue jumpStrafeStraightMax = - new NumberValue<>("jump_strafe_straight_max", 0.49, 0.1, 1.0); - private final NumberValue jumpStrafeDiagonalMin = - new NumberValue<>("jump_strafe_diagonal_min", 0.48, 0.1, 1.0); - private final NumberValue jumpStrafeDiagonalMax = - new NumberValue<>("jump_strafe_diagonal_max", 0.49, 0.1, 1.0); - private final BooleanValue speedLimiter = - new BooleanValue("speed_limiter", false); - private final BooleanValue stabilizeMovement = - new BooleanValue("stabilize_movement", false); - private final BooleanValue telly = - new BooleanValue("telly", false); - private final BooleanValue tellyAimOnTower = - new BooleanValue("telly_aim_on_tower", true); - private final BooleanValue ceiling = - new BooleanValue("ceiling", false); - private final BooleanValue headHitter = - new BooleanValue("head_hitter", false); - private final NumberValue speedLimit = - new NumberValue<>("speed_limit", 0.11, 0.01, 0.4); - private final NumberValue tellyStraightTicks = - new NumberValue<>("telly_straight_ticks", 0, 0, 5); - private final NumberValue tellyJumpTicksMin = - new NumberValue<>("telly_jump_ticks_min", 0, 0, 10); - private final NumberValue tellyJumpTicksMax = - new NumberValue<>("telly_jump_ticks_max", 0, 0, 10); - private final NumberValue towerMotion = - new NumberValue<>("tower_motion", 0.42, 0.0, 1.0); - private final NumberValue towerTriggerHeight = - new NumberValue<>("tower_trigger_height", 0.78, 0.76, 1.0); - private final NumberValue towerSlow = - new NumberValue<>("tower_slow", 1.0, 0.0, 3.0); - private final RGBAColorValue renderFillColor = - new RGBAColorValue("render_fill_color", "#3264A0A0"); - private final RGBAColorValue renderLineColor = - new RGBAColorValue("render_line_color", "#96A0FFFF"); - private final NumberValue renderLineWidth = - new NumberValue<>("render_line_width", 2, 1, 5); - private final NumberValue renderBobAmplitude = - new NumberValue<>("render_bob_amplitude", 0.08, 0.0, 0.3); - private final NumberValue renderBobSpeed = - new NumberValue<>("render_bob_speed", 2.2, 0.2, 8.0); - private final NumberValue renderPlaceAnimTime = - new NumberValue<>("render_place_anim_time", 0.22, 0.05, 1.0); - private final NumberValue placementIndicatorScale = - new NumberValue<>("placement_indicator_scale", 1.0, 0.5, 3.0); - private final NumberValue placementIndicatorOffsetX = - new NumberValue<>("placement_indicator_offset_x", 26.0, -120.0, 120.0); - private final NumberValue placementIndicatorOffsetY = - new NumberValue<>("placement_indicator_offset_y", 0.0, -120.0, 120.0); - private final NumberValue linearHorMin = - new NumberValue<>("linear_horizontal_min", 180f, 0f, 180f); - private final NumberValue linearHorMax = - new NumberValue<>("linear_horizontal_max", 180f, 0f, 180f); - private final NumberValue linearVertMin = - new NumberValue<>("linear_vertical_min", 180f, 0f, 180f); - private final NumberValue linearVertMax = - new NumberValue<>("linear_vertical_max", 180f, 0f, 180f); - private final NumberValue sigmoidHorMin = - new NumberValue<>("sigmoid_horizontal_min", 180f, 0f, 180f); - private final NumberValue sigmoidHorMax = - new NumberValue<>("sigmoid_horizontal_max", 180f, 0f, 180f); - private final NumberValue sigmoidVertMin = - new NumberValue<>("sigmoid_vertical_min", 180f, 0f, 180f); - private final NumberValue sigmoidVertMax = - new NumberValue<>("sigmoid_vertical_max", 180f, 0f, 180f); - private final NumberValue sigmoidSteepness = - new NumberValue<>("sigmoid_steepness", 10f, 0f, 20f); - private final NumberValue sigmoidMidpoint = - new NumberValue<>("sigmoid_midpoint", 0.3f, 0f, 1f); - private final NumberValue interpHorMin = - new NumberValue<>("interp_horizontal_min", 80, 1, 100); - private final NumberValue interpHorMax = - new NumberValue<>("interp_horizontal_max", 85, 1, 100); - private final NumberValue interpVertMin = - new NumberValue<>("interp_vertical_min", 20, 1, 100); - private final NumberValue interpVertMax = - new NumberValue<>("interp_vertical_max", 25, 1, 100); - private final NumberValue interpDirMin = - new NumberValue<>("interp_direction_change_min", 95, 0, 100); - private final NumberValue interpDirMax = - new NumberValue<>("interp_direction_change_max", 100, 0, 100); - private final NumberValue interpMidpoint = - new NumberValue<>("interp_midpoint", 0.35f, 0.0f, 1.0f); - private final NumberValue accelYawMin = - new NumberValue<>("accel_yaw_min", 20f, 1f, 180f); - private final NumberValue accelYawMax = - new NumberValue<>("accel_yaw_max", 25f, 1f, 180f); - private final NumberValue accelPitchMin = - new NumberValue<>("accel_pitch_min", 20f, 1f, 180f); - private final NumberValue accelPitchMax = - new NumberValue<>("accel_pitch_max", 25f, 1f, 180f); - private final BooleanValue accelDynamicEnabled = - new BooleanValue("accel_dynamic_enabled", false); - private final NumberValue accelCoefDistance = - new NumberValue<>("accel_coef_distance", -1.393f, -2f, 2f); - private final NumberValue accelYawCrossMin = - new NumberValue<>("accel_yaw_cross_min", 17f, 1f, 180f); - private final NumberValue accelYawCrossMax = - new NumberValue<>("accel_yaw_cross_max", 20f, 1f, 180f); - private final NumberValue accelPitchCrossMin = - new NumberValue<>("accel_pitch_cross_min", 17f, 1f, 180f); - private final NumberValue accelPitchCrossMax = - new NumberValue<>("accel_pitch_cross_max", 20f, 1f, 180f); - private final BooleanValue accelErrorEnabled = - new BooleanValue("accel_error_enabled", true); - private final NumberValue accelYawError = - new NumberValue<>("accel_yaw_error", 0.1f, 0.01f, 1f); - private final NumberValue accelPitchError = - new NumberValue<>("accel_pitch_error", 0.1f, 0.01f, 1f); - private final BooleanValue constantErrorEnabled = - new BooleanValue("constant_error_enabled", true); - private final NumberValue constantYawError = - new NumberValue<>("constant_yaw_error", 0.1f, 0.01f, 1f); - private final NumberValue constantPitchError = - new NumberValue<>("constant_pitch_error", 0.1f, 0.01f, 1f); - private final BooleanValue sigmoidDecelEnabled = - new BooleanValue("sigmoid_decel_enabled", false); - private final NumberValue sigmoidDecelSteepness = - new NumberValue<>("sigmoid_decel_steepness", 10f, 0.0f, 20f); - private final NumberValue sigmoidDecelMidpoint = - new NumberValue<>("sigmoid_decel_midpoint", 0.3f, 0.0f, 1.0f); - private final ScaffoldMovementPlanner movementPlanner = new ScaffoldMovementPlanner(); - private final ScaffoldMovementPrediction movementPrediction = new ScaffoldMovementPrediction(); - private final ScaffoldPlacementGate placementGate = new ScaffoldPlacementGate(); - private final InterpolationAngleSmooth interpolationSmooth = new InterpolationAngleSmooth( - interpHorMin, interpHorMax, interpVertMin, interpVertMax, interpDirMin, interpDirMax, interpMidpoint - ); - private final LinearAngleSmooth linearSmooth = new LinearAngleSmooth( - linearHorMin, linearHorMax, linearVertMin, linearVertMax - ); - private final SigmoidAngleSmooth sigmoidSmooth = new SigmoidAngleSmooth( - sigmoidHorMin, sigmoidHorMax, sigmoidVertMin, sigmoidVertMax, - sigmoidSteepness, sigmoidMidpoint - ); - private final AccelerationAngleSmooth accelerationSmooth = new AccelerationAngleSmooth( - accelYawMin, accelYawMax, accelPitchMin, accelPitchMax, - accelDynamicEnabled, accelCoefDistance, - accelYawCrossMin, accelYawCrossMax, accelPitchCrossMin, accelPitchCrossMax, - accelErrorEnabled, accelYawError, accelPitchError, - constantErrorEnabled, constantYawError, constantPitchError, - sigmoidDecelEnabled, sigmoidDecelSteepness, sigmoidDecelMidpoint - ); - private ScaffoldPlacementTarget currentTarget; - private int placementY; - private int delayLeft; - private boolean wasPlaced; - private int towerAirTicks; - private double towerJumpBaseY = Double.NaN; - private boolean rawForward; - private boolean rawBackward; - private boolean rawLeft; - private boolean rawRight; - private int strafeMoveTicks; - private int ticksUntilTellyJump; - private int tellyJumpTicks; - private ItemStack indicatorStack = ItemStack.EMPTY; - private boolean indicatorVisible; - private float indicatorX; - private float indicatorY; - private float indicatorSize; - private float indicatorScaleFactor; - private String indicatorCountText = ""; - private float indicatorCountX; - private float indicatorCountY; - private float indicatorTextScale; - private int indicatorCountValue; - private boolean indicatorRenderItem; - private BlockPos lastPlacedRenderPos; - private long lastPlacedRenderMillis; - private long debugAttemptCounter; - private BlockPos debugLastTargetPos; - private BlockPos debugPendingPlacedPos; - private int debugPendingPlacedTicks; - private long debugPendingPlacedAttempt; - private boolean debugPendingPlacedSeenSolid; - private ScaffoldLine currentOptimalLine; - - { - declareSettings(); - } - - private static List commonOffsets(int... xzOffsets) { - List list = new ArrayList<>(xzOffsets.length * xzOffsets.length * 2); - for (int x : xzOffsets) { - for (int z : xzOffsets) { - list.add(new BlockPos(x, 0, z)); - list.add(new BlockPos(x, -1, z)); - } - } - return List.copyOf(list); - } - - private static int withAlphaScale(int argb, float scale) { - int alpha = (argb >>> 24) & 0xFF; - int scaledAlpha = Mth.clamp((int) (alpha * scale), 0, 255); - return (argb & 0x00FFFFFF) | (scaledAlpha << 24); - } - - private static int getPillCountColor(int count) { - int low = 0xFFFF5C5C; - int mid = 0xFFDCE61E; - int high = 0xFF63F27D; - - if (count <= 64) { - float t = Mth.clamp(count / 64.0f, 0.0f, 1.0f); - return lerpColor(low, mid, t); - } - - float t = Mth.clamp((count - 64) / 64.0f, 0.0f, 1.0f); - return lerpColor(mid, high, t); - } - - private static int lerpColor(int from, int to, float t) { - int a1 = (from >>> 24) & 0xFF; - int r1 = (from >>> 16) & 0xFF; - int g1 = (from >>> 8) & 0xFF; - int b1 = from & 0xFF; - - int a2 = (to >>> 24) & 0xFF; - int r2 = (to >>> 16) & 0xFF; - int g2 = (to >>> 8) & 0xFF; - int b2 = to & 0xFF; - - int a = Mth.lerpInt(t, a1, a2); - int r = Mth.lerpInt(t, r1, r2); - int g = Mth.lerpInt(t, g1, g2); - int b = Mth.lerpInt(t, b1, b2); - return (a << 24) | (r << 16) | (g << 8) | b; - } - - private static int colorWithAlpha(int rgb, int alpha) { - return (alpha << 24) | (rgb & 0x00FFFFFF); - } - - private static void addFilledBox(Renderer3D renderer, AABB box, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - renderer.quad(minX, minY, minZ, maxX, minY, minZ, maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - renderer.quad(minX, maxY, minZ, minX, maxY, maxZ, maxX, maxY, maxZ, maxX, maxY, minZ, r, g, b, a); - renderer.quad(minX, minY, maxZ, maxX, minY, maxZ, maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - renderer.quad(minX, minY, minZ, minX, maxY, minZ, maxX, maxY, minZ, maxX, minY, minZ, r, g, b, a); - renderer.quad(maxX, minY, minZ, maxX, maxY, minZ, maxX, maxY, maxZ, maxX, minY, maxZ, r, g, b, a); - renderer.quad(minX, minY, minZ, minX, minY, maxZ, minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - } - - private static void addOutlineBox(Renderer3D renderer, AABB box, int argb) { - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - renderer.line(minX, minY, minZ, maxX, minY, minZ, r, g, b, a); - renderer.line(maxX, minY, minZ, maxX, minY, maxZ, r, g, b, a); - renderer.line(maxX, minY, maxZ, minX, minY, maxZ, r, g, b, a); - renderer.line(minX, minY, maxZ, minX, minY, minZ, r, g, b, a); - - renderer.line(minX, maxY, minZ, maxX, maxY, minZ, r, g, b, a); - renderer.line(maxX, maxY, minZ, maxX, maxY, maxZ, r, g, b, a); - renderer.line(maxX, maxY, maxZ, minX, maxY, maxZ, r, g, b, a); - renderer.line(minX, maxY, maxZ, minX, maxY, minZ, r, g, b, a); - - renderer.line(minX, minY, minZ, minX, maxY, minZ, r, g, b, a); - renderer.line(maxX, minY, minZ, maxX, maxY, minZ, r, g, b, a); - renderer.line(maxX, minY, maxZ, maxX, maxY, maxZ, r, g, b, a); - renderer.line(minX, minY, maxZ, minX, maxY, maxZ, r, g, b, a); - } - - private static void debugLog(String pattern, Object... args) { - if (!DEBUG_LOGS) { - } - // DebugLog.info("[ScaffoldDebug] " + pattern, args); - } - - private static String describeTarget(ScaffoldPlacementTarget target) { - if (target == null) return "null"; - return "placed=" + target.getPlacedBlockPos() - + " interact=" + target.getInteractedBlockPos() - + " side=" + target.getDirection() - + " rot=" + describeRotation(target.getRotation()); - } - - private static String describeHit(BlockHitResult hit) { - if (hit == null) return "null"; - return "block=" + hit.getBlockPos() - + " side=" + hit.getDirection() - + " pos=" + formatVec(hit.getLocation()); - } - - private static String describeRotation(Rotation rotation) { - if (rotation == null) return "null"; - return String.format(java.util.Locale.ROOT, "(yaw=%.2f,pitch=%.2f)", rotation.yaw(), rotation.pitch()); - } - - private static String formatVec(Vec3 vec) { - if (vec == null) return "null"; - return String.format(java.util.Locale.ROOT, "(%.3f,%.3f,%.3f)", vec.x, vec.y, vec.z); - } - - @Override - public HudPhase getHudPhase() { - return HudPhase.LAST; - } - - @Override - public WorldPhase getWorldPhase() { - return WorldPhase.END_MAIN; - } - - private void declareSettings() { - List defs = new ArrayList<>(); - defs.add(SettingDef.mode(rotationTiming)); - defs.add(SettingDef.mode(technique)); - defs.add(SettingDef.mode(sameY)); - defs.add(SettingDef.mode(movementCorrection).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL)); - defs.add(SettingDef.mode(angleSmoothMode).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL)); - defs.add(SettingDef.number(linearHorMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.LINEAR)); - defs.add(SettingDef.number(linearHorMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.LINEAR)); - defs.add(SettingDef.number(linearVertMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.LINEAR)); - defs.add(SettingDef.number(linearVertMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.LINEAR)); - defs.add(SettingDef.number(sigmoidHorMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.SIGMOID)); - defs.add(SettingDef.number(sigmoidHorMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.SIGMOID)); - defs.add(SettingDef.number(sigmoidVertMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.SIGMOID)); - defs.add(SettingDef.number(sigmoidVertMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.SIGMOID)); - defs.add(SettingDef.number(sigmoidSteepness).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.SIGMOID)); - defs.add(SettingDef.number(sigmoidMidpoint).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.SIGMOID)); - defs.add(SettingDef.number(interpHorMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.INTERPOLATION)); - defs.add(SettingDef.number(interpHorMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.INTERPOLATION)); - defs.add(SettingDef.number(interpVertMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.INTERPOLATION)); - defs.add(SettingDef.number(interpVertMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.INTERPOLATION)); - defs.add(SettingDef.number(interpDirMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.INTERPOLATION)); - defs.add(SettingDef.number(interpDirMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.INTERPOLATION)); - defs.add(SettingDef.number(interpMidpoint).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.INTERPOLATION)); - defs.add(SettingDef.number(accelYawMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION)); - defs.add(SettingDef.number(accelYawMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION)); - defs.add(SettingDef.number(accelPitchMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION)); - defs.add(SettingDef.number(accelPitchMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION)); - defs.add(SettingDef.bool(accelDynamicEnabled).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION)); - defs.add(SettingDef.number(accelCoefDistance).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && accelDynamicEnabled.get())); - defs.add(SettingDef.number(accelYawCrossMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && accelDynamicEnabled.get())); - defs.add(SettingDef.number(accelYawCrossMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && accelDynamicEnabled.get())); - defs.add(SettingDef.number(accelPitchCrossMin).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && accelDynamicEnabled.get())); - defs.add(SettingDef.number(accelPitchCrossMax).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && accelDynamicEnabled.get())); - defs.add(SettingDef.bool(accelErrorEnabled).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION)); - defs.add(SettingDef.number(accelYawError).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && accelErrorEnabled.get())); - defs.add(SettingDef.number(accelPitchError).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && accelErrorEnabled.get())); - defs.add(SettingDef.bool(constantErrorEnabled).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION)); - defs.add(SettingDef.number(constantYawError).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && constantErrorEnabled.get())); - defs.add(SettingDef.number(constantPitchError).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && constantErrorEnabled.get())); - defs.add(SettingDef.bool(sigmoidDecelEnabled).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION)); - defs.add(SettingDef.number(sigmoidDecelSteepness).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && sigmoidDecelEnabled.get())); - defs.add(SettingDef.number(sigmoidDecelMidpoint).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL && angleSmoothMode.get() == AngleSmoothMode.ACCELERATION && sigmoidDecelEnabled.get())); - defs.add(SettingDef.bool(autoBlock)); - defs.add(SettingDef.bool(renderPlacement)); - defs.add(SettingDef.color(renderFillColor).visibleWhen(renderPlacement::get)); - defs.add(SettingDef.color(renderLineColor).visibleWhen(renderPlacement::get)); - defs.add(SettingDef.number(renderLineWidth).visibleWhen(renderPlacement::get)); - defs.add(SettingDef.number(renderBobAmplitude).visibleWhen(renderPlacement::get)); - defs.add(SettingDef.number(renderBobSpeed).visibleWhen(renderPlacement::get)); - defs.add(SettingDef.number(renderPlaceAnimTime).visibleWhen(renderPlacement::get)); - defs.add(SettingDef.bool(placementIndicator)); - defs.add(SettingDef.mode(placementIndicatorStyle).visibleWhen(placementIndicator::get)); - defs.add(SettingDef.mode(placementIndicatorSide).visibleWhen(placementIndicator::get)); - defs.add(SettingDef.mode(placementIndicatorCountMode).visibleWhen(placementIndicator::get)); - defs.add(SettingDef.number(placementIndicatorScale).visibleWhen(placementIndicator::get)); - defs.add(SettingDef.number(placementIndicatorOffsetX).visibleWhen(placementIndicator::get)); - defs.add(SettingDef.number(placementIndicatorOffsetY).visibleWhen(placementIndicator::get)); - defs.add(SettingDef.bool(placementIndicatorBackground).visibleWhen(placementIndicator::get)); - defs.add(SettingDef.bool(autoBlockAlways).visibleWhen(autoBlock::get)); - defs.add(SettingDef.number(autoBlockSlotResetDelay).visibleWhen(autoBlock::get)); - defs.add(SettingDef.number(autoBlockDoNotUseBelowCount).visibleWhen(autoBlock::get)); - defs.add(SettingDef.bool(prediction)); - defs.add(SettingDef.bool(considerInventory).visibleWhen(() -> rotationTiming.get() == RotationTiming.NORMAL)); - defs.add(SettingDef.number(placementSpeed).common(CommonSettingSchemas.PLACEMENT_SPEED)); - defs.add(SettingDef.number(delay)); - defs.add(SettingDef.bool(down)); - defs.add(SettingDef.bool(eagle)); - defs.add(SettingDef.number(blocksToEagle).visibleWhen(eagle::get)); - defs.add(SettingDef.number(eagleEdgeDistance).visibleWhen(eagle::get)); - defs.add(SettingDef.bool(eagleOnlyOnGround).visibleWhen(eagle::get)); - defs.add(SettingDef.number(expandLength).visibleWhen(() -> technique.get() == Technique.EXPAND)); - defs.add(SettingDef.bool(acceleration)); - defs.add(SettingDef.number(accelerationMultiplier).visibleWhen(acceleration::get)); - defs.add(SettingDef.bool(accelerationOnlyOnGround).visibleWhen(acceleration::get)); - defs.add(SettingDef.bool(strafe)); - defs.add(SettingDef.number(strafeSpeed).visibleWhen(strafe::get)); - defs.add(SettingDef.bool(strafeHypixel).visibleWhen(strafe::get)); - defs.add(SettingDef.bool(strafeOnlyOnGround).visibleWhen(strafe::get)); - defs.add(SettingDef.bool(jumpStrafe)); - defs.add(SettingDef.number(jumpStrafeStraightMin).visibleWhen(jumpStrafe::get)); - defs.add(SettingDef.number(jumpStrafeStraightMax).visibleWhen(jumpStrafe::get)); - defs.add(SettingDef.number(jumpStrafeDiagonalMin).visibleWhen(jumpStrafe::get)); - defs.add(SettingDef.number(jumpStrafeDiagonalMax).visibleWhen(jumpStrafe::get)); - defs.add(SettingDef.bool(speedLimiter)); - defs.add(SettingDef.number(speedLimit).visibleWhen(speedLimiter::get)); - defs.add(SettingDef.bool(stabilizeMovement).visibleWhen(() -> technique.get() == Technique.NORMAL)); - defs.add(SettingDef.bool(telly).visibleWhen(() -> technique.get() == Technique.NORMAL)); - defs.add(SettingDef.mode(aimMode).visibleWhen(() -> technique.get() == Technique.NORMAL)); - defs.add(SettingDef.mode(tellyResetMode).visibleWhen(() -> technique.get() == Technique.NORMAL && telly.get())); - defs.add(SettingDef.number(tellyStraightTicks).visibleWhen(() -> technique.get() == Technique.NORMAL && telly.get())); - defs.add(SettingDef.number(tellyJumpTicksMin).visibleWhen(() -> technique.get() == Technique.NORMAL && telly.get())); - defs.add(SettingDef.number(tellyJumpTicksMax).visibleWhen(() -> technique.get() == Technique.NORMAL && telly.get())); - defs.add(SettingDef.bool(tellyAimOnTower).visibleWhen(() -> technique.get() == Technique.NORMAL && telly.get())); - defs.add(SettingDef.bool(ceiling).visibleWhen(() -> technique.get() == Technique.NORMAL)); - defs.add(SettingDef.bool(headHitter).visibleWhen(() -> technique.get() == Technique.NORMAL)); - defs.add(SettingDef.mode(towerMode)); - defs.add(SettingDef.number(towerMotion).visibleWhen(() -> towerMode.get() == TowerMode.MOTION)); - defs.add(SettingDef.number(towerTriggerHeight).visibleWhen(() -> towerMode.get() == TowerMode.MOTION)); - defs.add(SettingDef.number(towerSlow).visibleWhen(() -> towerMode.get() == TowerMode.MOTION)); - defs.add(SettingDef.mode(clientSprintMode)); - defs.add(SettingDef.mode(serverSprintMode)); - defs.forEach(this::setting); - } - - @Override - public void onEnable() { - LocalPlayer player = player(); - if (player == null) return; - placementY = player.getBlockY() - 1; - delayLeft = 0; - placementGate.reset(); - wasPlaced = false; - currentTarget = null; - towerAirTicks = 0; - towerJumpBaseY = Double.NaN; - strafeMoveTicks = 0; - ticksUntilTellyJump = 0; - tellyJumpTicks = randomTellyJumpTicks(); - currentOptimalLine = null; - indicatorStack = ItemStack.EMPTY; - indicatorVisible = false; - indicatorCountText = ""; - indicatorCountValue = 0; - indicatorRenderItem = false; - lastPlacedRenderPos = null; - lastPlacedRenderMillis = 0L; - debugPendingPlacedPos = null; - debugPendingPlacedTicks = 0; - debugPendingPlacedAttempt = 0L; - debugPendingPlacedSeenSolid = false; - movementPlanner.reset(); - movementPrediction.reset(); - } - - @Override - public void onDisable() { - InventorySwap.INSTANCE.releaseHotbar(this); - currentTarget = null; - wasPlaced = false; - delayLeft = 0; - placementGate.reset(); - towerAirTicks = 0; - towerJumpBaseY = Double.NaN; - strafeMoveTicks = 0; - ticksUntilTellyJump = 0; - tellyJumpTicks = 0; - currentOptimalLine = null; - indicatorStack = ItemStack.EMPTY; - indicatorVisible = false; - indicatorCountText = ""; - indicatorCountValue = 0; - indicatorRenderItem = false; - lastPlacedRenderPos = null; - lastPlacedRenderMillis = 0L; - debugPendingPlacedPos = null; - debugPendingPlacedTicks = 0; - debugPendingPlacedAttempt = 0L; - debugPendingPlacedSeenSolid = false; - movementPlanner.reset(); - movementPrediction.reset(); - RotationManager.INSTANCE.release(this); - } - - public boolean shouldSuppressOmniDirectionalSprint() { - return isEnabled() && (currentTarget != null || wasPlaced); - } - - @Override - public void onRenderWorldEngine(Renderer3D renderer, Renderer3D depthRenderer, float tickDelta) { - if (!renderPlacement.get()) return; - - LocalPlayer player = player(); - Minecraft mc = Minecraft.getInstance(); - if (player == null || mc.level == null) return; - - RenderPreview preview = getRenderPreview(tickDelta); - if (preview == null) return; - - AABB box = animatedRenderBox(preview.pos, preview.progress, tickDelta); - int fill = withAlphaScale(renderFillColor.getArgb(), preview.progress); - int line = withAlphaScale(renderLineColor.getArgb(), preview.progress); - - float prevWidth = RenderState.lineWidth; - RenderState.lineWidth = Math.max(1.0f, renderLineWidth.get()); - try { - addFilledBox(renderer, box, fill); - addOutlineBox(renderer, box, line); - } finally { - RenderState.lineWidth = prevWidth; - } - } - - @EventHandler - private void onGameTick(GameTickEvent event) { - LocalPlayer player = player(); - if (player == null) return; - - if (debugPendingPlacedPos != null) { - BlockState state = player.level().getBlockState(debugPendingPlacedPos); - boolean solid = !state.isAir(); - if (solid) { - debugPendingPlacedSeenSolid = true; - } else if (debugPendingPlacedSeenSolid) { - debugLog( - "post-place-rollback attempt#%d pos=%s playerPos=%s vel=%s current=%s server=%s", - debugPendingPlacedAttempt, - debugPendingPlacedPos, - formatVec(player.position()), - formatVec(player.getDeltaMovement()), - describeRotation(RotationManager.INSTANCE.getCurrentRotation()), - describeRotation(RotationManager.INSTANCE.getServerRotation()) - ); - debugPendingPlacedPos = null; - debugPendingPlacedTicks = 0; - debugPendingPlacedAttempt = 0L; - debugPendingPlacedSeenSolid = false; - } else if (debugPendingPlacedTicks == 2) { - debugLog( - "post-place-missing attempt#%d pos=%s playerPos=%s vel=%s current=%s server=%s", - debugPendingPlacedAttempt, - debugPendingPlacedPos, - formatVec(player.position()), - formatVec(player.getDeltaMovement()), - describeRotation(RotationManager.INSTANCE.getCurrentRotation()), - describeRotation(RotationManager.INSTANCE.getServerRotation()) - ); - } - - if (debugPendingPlacedPos != null) { - debugPendingPlacedTicks--; - if (debugPendingPlacedTicks <= 0) { - debugPendingPlacedPos = null; - debugPendingPlacedAttempt = 0L; - debugPendingPlacedSeenSolid = false; - } - } - } - - if (delayLeft > 0) delayLeft--; - InventorySwap.INSTANCE.tick(); - if (player.onGround()) { - placementY = player.getBlockY() - 1; - towerAirTicks = 0; - ticksUntilTellyJump++; - } else { - towerAirTicks++; - } - if (wasPlaced) { - wasPlaced = false; - } - - handleTower(player); - handleHeadHitter(player); - handleAcceleration(player); - handleStrafe(player); - updateStrafeMoveTicks(player); - } - - @Override - public void onRenderHudEngine(Renderer2D renderer, TextRenderer textRenderer, GuiGraphicsExtractor ctx, float tickDelta) { - indicatorVisible = false; - indicatorCountText = ""; - indicatorCountValue = 0; - indicatorRenderItem = false; - if (!placementIndicator.get() || ctx == null || !isEnabled()) return; - - LocalPlayer player = player(); - if (player == null) return; - - PlacementIndicatorData data = getPlacementIndicatorData(player); - if (data == null || data.stack().isEmpty()) return; - - Minecraft client = Minecraft.getInstance(); - int fbw = client.getWindow().getWidth(); - int fbh = client.getWindow().getHeight(); - - ViewportContext.beginUnscaledLogical(ctx); - try { - float centerX = HudScale.virtualWidth(fbw, fbh) * 0.5f; - float centerY = HudScale.virtualHeight(fbw, fbh) * 0.5f; - BetterTooltips tooltips = BetterTooltips.get(); - float userScale = placementIndicatorScale.get().floatValue(); - float renderScale = userScale * 3.0f; - float slotSize = (tooltips != null ? tooltips.shulkerPreviewSlotSize() : 18.0f) * renderScale; - float slotRadius = (tooltips != null ? tooltips.shulkerPreviewSlotRadius() : 5.0f) * renderScale; - float slotSoftness = (tooltips != null ? tooltips.shulkerPreviewSlotSoftness() : 1.0f) * renderScale; - float stroke = 0.35f * renderScale; - float offsetX = placementIndicatorOffsetX.get().floatValue(); - float offsetY = placementIndicatorOffsetY.get().floatValue(); - boolean pill = placementIndicatorStyle.get() == IndicatorStyle.PILL; - float textScale = pill ? 1.08f * renderScale : 0.86f * renderScale; - TextRenderer countRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); - float countWidth = data.countText().isEmpty() ? 0.0f : (float) countRenderer.getWidth(data.countText(), false) * textScale; - float textHeight = (float) countRenderer.getHeight(false) * textScale; - float pillPadX = 3.0f * renderScale; - float pillPadY = renderScale; - float bodyWidth = pill - ? Math.max(10.0f * renderScale, countWidth + pillPadX * 2.0f) - : slotSize; - float bodyHeight = pill - ? textHeight + pillPadY * 2.0f - : slotSize; - float bodyRadius = placementIndicatorStyle.get() == IndicatorStyle.PILL - ? bodyHeight * 0.5f - : slotRadius; - - float x; - float y; - switch (placementIndicatorSide.get()) { - case RIGHT -> { - x = centerX + offsetX; - y = centerY - bodyHeight * 0.5f + offsetY; - } - case TOP -> { - x = centerX - bodyWidth * 0.5f + offsetX; - y = centerY - bodyHeight + offsetY; - } - case BOTTOM -> { - x = centerX - bodyWidth * 0.5f + offsetX; - y = centerY + offsetY; - } - case LEFT -> { - x = centerX - bodyWidth - offsetX; - y = centerY - bodyHeight * 0.5f + offsetY; - } - default -> { - x = centerX - bodyWidth - offsetX; - y = centerY - bodyHeight * 0.5f + offsetY; - } - } - - if (placementIndicatorBackground.get()) { - if (pill) { - renderer.roundedRect(x, y, bodyWidth, bodyHeight, bodyRadius, 0.0f, 0xD0101010); - } else { - int slotRgb = tooltips != null ? tooltips.shulkerPreviewSlotBgRgb() : 0x202020; - int borderRgb = tooltips != null ? tooltips.shulkerPreviewSlotBorderRgb() : 0x2F2F2F; - int borderAlpha = tooltips != null ? tooltips.shulkerPreviewSlotBorderAlpha() : 160; - renderer.roundedRect(x, y, bodyWidth, bodyHeight, bodyRadius, slotSoftness, colorWithAlpha(slotRgb, 0xFF)); - renderer.roundedRectStroke(x, y, bodyWidth, bodyHeight, bodyRadius, slotSoftness, stroke, colorWithAlpha(borderRgb, borderAlpha)); - } - } - - indicatorStack = data.stack().copy(); - indicatorVisible = true; - indicatorRenderItem = !pill; - indicatorX = x; - indicatorY = y; - indicatorSize = bodyHeight; - indicatorScaleFactor = renderScale; - indicatorCountText = data.countText(); - indicatorCountValue = data.count(); - indicatorTextScale = textScale; - if (pill && !indicatorCountText.isEmpty()) { - indicatorCountX = x + (bodyWidth - countWidth) * 0.5f; - indicatorCountY = y + (bodyHeight - textHeight) * 0.5f; - countRenderer.begin(indicatorTextScale, false, false); - countRenderer.render(indicatorCountText, indicatorCountX, indicatorCountY, new RenderColor(getPillCountColor(indicatorCountValue)), false); - countRenderer.end(); - } else { - indicatorCountX = x + bodyWidth - 3.0f * renderScale; - indicatorCountY = y + bodyHeight - 2.0f * renderScale; - } - } finally { - ViewportContext.beginUnscaled(ctx); - } - } - - @Override - public void onRenderHudEngineForeground(Renderer2D renderer, TextRenderer textRenderer, GuiGraphicsExtractor ctx, float tickDelta) { - if (!indicatorVisible || ctx == null) return; - - ViewportContext.beginUnscaledLogical(ctx); - try { - if (indicatorRenderItem && !indicatorStack.isEmpty()) { - float iconSize = 16.0f * indicatorScaleFactor; - float offset = (indicatorSize - iconSize) * 0.5f; - renderer.item( - indicatorStack, - indicatorX + offset, - indicatorY + offset, - indicatorScaleFactor, - 0, - Renderer2D.ITEM_OVERLAY_ALL, - null - ); - } - - if (!indicatorCountText.isEmpty() && indicatorRenderItem) { - float ratio = Renderer2D.getUnscaledItemRatio(); - TextRenderer countRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, textRenderer); - countRenderer.begin(indicatorTextScale * ratio); - double textX = indicatorCountX * ratio; - double textY = indicatorCountY * ratio; - double width = countRenderer.getWidth(indicatorCountText, false); - textX -= width; - textY -= countRenderer.getHeight(false); - countRenderer.render(indicatorCountText, textX, textY, new RenderColor(0xFFFFFFFF), false); - countRenderer.end(); - } - } finally { - ViewportContext.beginUnscaled(ctx); - } - } - - @EventHandler - private void onRotationUpdate(RotationUpdateEvent event) { - if (event.getType() != RotationUpdateEvent.Type.PRE) { - return; - } - - LocalPlayer player = player(); - boolean hasTarget = refreshCurrentTarget(player); - if (rotationTiming.get() != RotationTiming.NORMAL) return; - - if (!hasTarget) { - requestNormalStrictMoonwalkRotation(player); - return; - } - - List processors = buildRotationProcessors(); - ScaffoldPlacementTarget targetSnapshot = currentTarget; - RotationTarget target = new RotationTarget( - targetSnapshot.getRotation(), - null, - processors, - 2, - 4.0f, - considerInventory.get(), - movementCorrection.get(), - new RestrictedSingleUseAction(() -> executeScheduledNormalPlacement( - targetSnapshot, - RotationManager.INSTANCE.getCurrentRotation() != null - ? RotationManager.INSTANCE.getCurrentRotation() - : targetSnapshot.getRotation(), - preparePlacementHand(player()), - resolveNormalScheduledHit(player(), targetSnapshot) - )) - ); - RotationManager.INSTANCE.setRotationTarget(target, 100, this); - } - - private void requestNormalStrictMoonwalkRotation(LocalPlayer player) { - if (player == null || technique.get() != Technique.NORMAL) return; - if (movementCorrection.get() != MovementCorrection.STRICT) return; - if (!hasRawInput() || blockCount(player) <= 0) return; - - float movementYaw = getRawMovementDirectionYaw(player, player.getYRot()); - Rotation moonwalkRotation = new Rotation(movementYaw + 180.0f, 75.0f, false).normalize(); - RotationTarget target = new RotationTarget( - moonwalkRotation, - null, - buildRotationProcessors(), - 2, - 4.0f, - considerInventory.get(), - movementCorrection.get(), - null - ); - RotationManager.INSTANCE.setRotationTarget(target, 100, this); - } - - @EventHandler - private void onMovementInput(MovementInputEvent event) { - LocalPlayer player = player(); - if (!canOperate(player)) return; - - rawForward = event.isForward(); - rawBackward = event.isBackward(); - rawLeft = event.isLeft(); - rawRight = event.isRight(); - currentOptimalLine = hasRawInput() - ? movementPlanner.getOptimalMovementLine(player, getRawMovementDirectionYaw(player, player.getYRot())) - : null; - - refreshCurrentTarget(player); - - if (handleNormalOnTickPlacement(player, event)) { - return; - } - - if (speedLimiter.get() && horizontalSpeed(player.getDeltaMovement()) > speedLimit.get()) { - event.setForward(false); - event.setBackward(false); - event.setLeft(false); - event.setRight(false); - return; - } - - handleStabilizeMovement(player, event); - handleTelly(player, event); - - if (shouldGoDown(player)) { - event.setSneak(false); - return; - } - - handleNormalStrictMoonwalkInput(player, event); - - if (shouldEagle(player, event) && !event.isSneak()) { - event.setSneak(true); - } - } - - @EventHandler - private void onSafeWalk(PlayerSafeWalkEvent event) { - LocalPlayer player = player(); - boolean canOperate = canOperate(player); - if (!ScaffoldPlacementGate.shouldSafeWalk( - isEnabled(), - eagle.get(), - canOperate, - canOperate && player.onGround(), - canOperate && player.getAbilities().flying, - canOperate && shouldGoDown(player), - canOperate && blockCount(player) > 0 - )) return; - - // Eagle must never depend on rotation smoothing or placement cadence. Vanilla edge - // clipping keeps the player on the current block while the one-tick Eagle pulse ends. - event.setSafeWalk(true); - } - - @EventHandler - private void onSync(EventSync event) { - } - - @EventHandler - private void onPostPlayerUpdate(PostPlayerUpdateEvent event) { - LocalPlayer player = player(); - if (!canOperate(player) || rotationTiming.get() != RotationTiming.ON_TICK) return; - executeOnTickPlacement(player); - } - - private boolean handleNormalOnTickPlacement(LocalPlayer player, MovementInputEvent event) { - if (player == null || event == null) return false; - if (technique.get() != Technique.NORMAL || rotationTiming.get() != RotationTiming.ON_TICK) return false; - if (shouldGoDown(player) || player.getAbilities().flying) return false; - if (!normalOnTickPlacementRequired(player)) return false; - - boolean placed = executeOnTickPlacement(player); - if (placed) { - return false; - } - - stopHorizontalInput(event); - return true; - } - - private boolean normalOnTickPlacementRequired(LocalPlayer player) { - if (player == null || player.level() == null) return false; - if (!hasRawInput()) return false; - - BlockPos targetPos = getTargetedPosition(player); - if (targetPos == null || !player.level().isInWorldBounds(targetPos)) { - return false; - } - - return player.level().getBlockState(targetPos).canBeReplaced(); - } - - private void stopHorizontalInput(MovementInputEvent event) { - if (event == null) return; - event.setForward(false); - event.setBackward(false); - event.setLeft(false); - event.setRight(false); - event.setSprint(false); - } - - private boolean executeOnTickPlacement(LocalPlayer player) { - if (!canOperate(player) || currentTarget == null || !isPlacementCadenceReady()) return false; - if (isTargetStaleForPlayer(player, currentTarget)) { - debugLog( - "target-cleared reason=stale-window target=%s playerPos=%s vel=%s onGround=%s", - describeTarget(currentTarget), - formatVec(player.position()), - formatVec(player.getDeltaMovement()), - player.onGround() - ); - currentTarget = null; - return false; - } - - InteractionHand hand = preparePlacementHand(player); - if (hand == null) return false; - - debugLog( - "attempt#%d timing=%s tech=%s target=%s server=%s current=%s hand=%s delay=%d pos=%s vel=%s", - ++debugAttemptCounter, - EnumIds.defaultId(rotationTiming.get()), - EnumIds.defaultId(technique.get()), - describeTarget(currentTarget), - describeRotation(RotationManager.INSTANCE.getServerRotation()), - describeRotation(RotationManager.INSTANCE.getCurrentRotation()), - hand, - delayLeft, - formatVec(player.position()), - formatVec(player.getDeltaMovement()) - ); - - Rotation currentRotation = currentTarget.getRotation(); - if (currentRotation == null) { - return false; - } - - Rotation serverRotation = RotationManager.INSTANCE.getServerRotation(); - if (serverRotation == null || !serverRotation.approximatelyEquals(currentRotation, 0.01f)) { - debugLog( - "attempt#%d on-tick-pre-look server=%s targetRot=%s", - debugAttemptCounter, - describeRotation(serverRotation), - describeRotation(currentRotation) - ); - sendLookPacket(player, currentRotation); - } - - BlockHitResult hitResult = resolvePlacementHit(player, currentTarget, currentRotation); - if (!currentTarget.matches(hitResult) || !isValidCrosshairTarget(player, hitResult)) { - return false; - } - - boolean placed = tryPlace(player, hand, hitResult); - if (!placed) { - return false; - } - - restoreOnTickPlayerRotation(player, currentRotation); - return true; - } - - private void restoreOnTickPlayerRotation(LocalPlayer player, Rotation scaffoldRotation) { - if (player == null || scaffoldRotation == null) return; - - Rotation playerRotation = new Rotation(player.getYRot(), player.getXRot(), true); - Rotation updatedServerRotation = RotationManager.INSTANCE.getServerRotation(); - if (updatedServerRotation == null || !updatedServerRotation.approximatelyEquals(playerRotation, 0.01f)) { - debugLog( - "attempt#%d on-tick-post-restore server=%s player=%s", - debugAttemptCounter, - describeRotation(updatedServerRotation), - describeRotation(playerRotation) - ); - sendLookPacket(player, new Rotation( - RotationUtil.withFixedYaw(player.getYRot(), scaffoldRotation.yaw()), - player.getXRot(), - true - )); - } - } - - private void executeScheduledNormalPlacement( - ScaffoldPlacementTarget target, - Rotation rotation, - InteractionHand hand, - BlockHitResult hitResult - ) { - LocalPlayer player = player(); - if (!isEnabled() || player == null || target == null || hitResult == null || hand == null - || !isPlacementCadenceReady()) { - return; - } - if (currentTarget != target) { - if (!samePlacementTarget(currentTarget, target)) { - currentTarget = target; - } - } - if (isTargetStaleForPlayer(player, target)) { - currentTarget = null; - return; - } - - long attemptId = ++debugAttemptCounter; - debugLog( - "attempt#%d timing=%s tech=%s target=%s server=%s current=%s hand=%s delay=%d pos=%s vel=%s", - attemptId, - EnumIds.defaultId(rotationTiming.get()), - EnumIds.defaultId(technique.get()), - describeTarget(target), - describeRotation(RotationManager.INSTANCE.getServerRotation()), - describeRotation(rotation), - hand, - delayLeft, - formatVec(player.position()), - formatVec(player.getDeltaMovement()) - ); - - tryPlace(player, hand, hitResult); - } - - private boolean samePlacementTarget(ScaffoldPlacementTarget a, ScaffoldPlacementTarget b) { - if (a == null || b == null) { - return false; - } - return a.getPlacedBlockPos().equals(b.getPlacedBlockPos()) - && a.getInteractedBlockPos().equals(b.getInteractedBlockPos()) - && a.getDirection() == b.getDirection(); - } - - private BlockHitResult resolveNormalScheduledHit(LocalPlayer player, ScaffoldPlacementTarget target) { - if (player == null || target == null) { - return null; - } - - Rotation currentRotation = RotationManager.INSTANCE.getCurrentRotation(); - if (currentRotation == null) { - currentRotation = target.getRotation(); - } - if (currentRotation == null) { - currentRotation = new Rotation(player.getYRot(), player.getXRot(), true); - } - - return switch (technique.get()) { - case NORMAL -> getNormalCrosshairTarget(player, target, currentRotation); - default -> getTechniqueCrosshairTarget(player, target, currentRotation); - }; - } - - private BlockHitResult resolvePlacementHit( - LocalPlayer player, - ScaffoldPlacementTarget target, - Rotation currentRotation - ) { - if (player == null || target == null || currentRotation == null) { - return null; - } - - BlockHitResult hitResult = switch (technique.get()) { - case NORMAL -> getNormalCrosshairTarget(player, target, currentRotation); - default -> getTechniqueCrosshairTarget(player, target, currentRotation); - }; - - if (hitResult != null) { - return hitResult; - } - - if (technique.get() != Technique.NORMAL) { - return null; - } - - RotationTiming timing = rotationTiming.get(); - if (timing != RotationTiming.ON_TICK) { - return null; - } - - return getOnTickHorizontalFallbackHit(player, target); - } - - @EventHandler - private void onPacketSend(PacketEvent.Send event) { - LocalPlayer player = player(); - if (!isEnabled() || player == null || towerMode.get() != TowerMode.VULCAN || !isTowering(player)) return; - if (!(event.getPacket() instanceof ServerboundMovePlayerPacket packet)) return; - if (isMoving(player)) return; - - ServerboundMovePlayerPacketAccessor accessor = (ServerboundMovePlayerPacketAccessor) packet; - if (player.tickCount % 2 == 0) { - accessor.combatant$setX(packet.getX(player.getX()) + 0.1); - accessor.combatant$setZ(packet.getZ(player.getZ()) + 0.1); - } - } - - @EventHandler - private void onPacketReceive(PacketEvent.Receive event) { - LocalPlayer player = player(); - if (!isEnabled() || player == null) return; - if (!(event.getPacket() instanceof ClientboundPlayerPositionPacket packet)) return; - - debugLog( - "server-correct packetRot=%s playerPos=%s vel=%s target=%s current=%s server=%s", - describeRotation(new Rotation(packet.change().yRot(), packet.change().xRot(), true)), - formatVec(player.position()), - formatVec(player.getDeltaMovement()), - describeTarget(currentTarget), - describeRotation(RotationManager.INSTANCE.getCurrentRotation()), - describeRotation(RotationManager.INSTANCE.getServerRotation()) - ); - } - - @EventHandler - private void onSprintControl(SprintControlEvent event) { - if (!isEnabled()) return; - - SprintMode mode = switch (event.getSource()) { - case INPUT, MOVEMENT_TICK -> clientSprintMode.get(); - case NETWORK -> serverSprintMode.get(); - default -> SprintMode.DO_NOT_CHANGE; - }; - - if (mode == SprintMode.DO_NOT_CHANGE) return; - - switch (mode) { - case FORCE_SPRINT -> { - if (event.isMoving()) { - event.setSprint(true); - } - } - case FORCE_NO_SPRINT -> event.setSprint(false); - case NO_SPRINT_ON_PLACE -> { - if (wasPlaced) { - event.setSprint(false); - } - } - case NO_SPRINT_ON_GROUND -> { - LocalPlayer player = player(); - if (player != null) { - event.setSprint(!player.onGround()); - } - } - default -> { - } - } - } - - private boolean tryPlace(LocalPlayer player, InteractionHand hand, BlockHitResult hitResult) { - if (player == null || currentTarget == null || hitResult == null || !isPlacementCadenceReady()) return false; - - Vec3 previousFallOffPos = currentOptimalLine != null - ? movementPrediction.getFallOffPositionOnLine(player, currentOptimalLine) - : null; - - InteractionResult result = Minecraft.getInstance().gameMode.useItemOn( - player, - hand, - hitResult - ); - if (result == null || !result.consumesAction()) { - debugLog( - "attempt#%d place-fail result=%s hit=%s target=%s playerPos=%s vel=%s onGround=%s current=%s server=%s", - debugAttemptCounter, - result, - describeHit(hitResult), - describeTarget(currentTarget), - formatVec(player.position()), - formatVec(player.getDeltaMovement()), - player.onGround(), - describeRotation(RotationManager.INSTANCE.getCurrentRotation()), - describeRotation(RotationManager.INSTANCE.getServerRotation()) - ); - return false; - } - - player.swing(hand); - debugLog( - "attempt#%d place-ok hit=%s target=%s", - debugAttemptCounter, - describeHit(hitResult), - describeTarget(currentTarget) - ); - wasPlaced = true; - debugPendingPlacedPos = currentTarget.getPlacedBlockPos(); - debugPendingPlacedTicks = 3; - debugPendingPlacedAttempt = debugAttemptCounter; - debugPendingPlacedSeenSolid = false; - movementPlanner.trackPlacedBlock(currentTarget.getPlacedBlockPos()); - movementPrediction.onPlace(currentOptimalLine, previousFallOffPos, player.position()); - lastPlacedRenderPos = currentTarget.getPlacedBlockPos(); - lastPlacedRenderMillis = System.currentTimeMillis(); - placementGate.recordSuccessfulPlacement(System.nanoTime(), blocksToEagle.get()); - delayLeft = delay.get(); - currentTarget = null; - return true; - } - - private BlockHitResult getNormalCrosshairTarget( - LocalPlayer player, - ScaffoldPlacementTarget target, - Rotation currentRotation - ) { - if (player == null || target == null || currentRotation == null) return null; - - BlockHitResult crosshairTarget = traceScaffoldTarget(player, currentRotation); - if (target.matches(crosshairTarget)) { - return crosshairTarget; - } - - return shouldGoDown(player) ? target.toHitResult() : null; - } - - private BlockHitResult getTechniqueCrosshairTarget( - LocalPlayer player, - ScaffoldPlacementTarget target, - Rotation currentRotation - ) { - if (player == null || target == null || currentRotation == null) return null; - - BlockHitResult crosshairTarget = traceScaffoldTarget(player, currentRotation); - if (target.matches(crosshairTarget)) { - return crosshairTarget; - } - - return switch (technique.get()) { - case EXPAND -> target.toHitResult(); - case NORMAL -> shouldGoDown(player) ? target.toHitResult() : null; - default -> null; - }; - } - - private boolean isValidCrosshairTarget(LocalPlayer player, BlockHitResult hitResult) { - return player != null && isValidCrosshairTarget(player.getEyePosition(), hitResult); - } - - private boolean isValidCrosshairTarget(Vec3 eyePos, BlockHitResult hitResult) { - if (eyePos == null || hitResult == null) return false; - - Vec3 diff = hitResult.getLocation().subtract(eyePos); - Direction side = hitResult.getDirection(); - - if (side.getAxis() != Direction.Axis.Y) { - double dist = (side == Direction.NORTH || side == Direction.SOUTH) ? diff.z : diff.x; - return !(Math.abs(dist) < minDist.get()); - } - - return true; - } - - private boolean isTargetStaleForPlayer(LocalPlayer player, ScaffoldPlacementTarget target) { - if (player == null || target == null) return false; - if (player.onGround()) return false; - if (player.getDeltaMovement().y >= 0.0) return false; - - Direction side = target.getDirection(); - if (side.getAxis() == Direction.Axis.Y) { - return false; - } - - double staleY = target.getInteractedBlockPos().getY() + 1.0; - return player.getY() < staleY; - } - - private BlockHitResult traceScaffoldTarget(LocalPlayer player, Rotation rotation) { - if (player == null || rotation == null) return null; - return traceScaffoldTarget(player, player.getEyePosition(), rotation); - } - - private BlockHitResult getOnTickHorizontalFallbackHit( - LocalPlayer player, - ScaffoldPlacementTarget target - ) { - if (player == null || target == null) { - return null; - } - if (target.getDirection().getAxis() == Direction.Axis.Y) { - return null; - } - - BlockHitResult fallbackHit = target.toHitResult(); - return isWithinBlockInteractionRange(player, fallbackHit.getLocation()) ? fallbackHit : null; - } - - private boolean isWithinBlockInteractionRange(LocalPlayer player, Vec3 point) { - if (player == null || point == null) { - return false; - } - double range = player.blockInteractionRange(); - return player.getEyePosition().distanceToSqr(point) <= range * range; - } - - private BlockHitResult traceScaffoldTarget(LocalPlayer player, Vec3 eyes, Rotation rotation) { - if (player == null || eyes == null || rotation == null || player.level() == null) return null; - - double range = Math.max(player.blockInteractionRange(), player.entityInteractionRange()); - Vec3 end = eyes.add(rotation.directionVector().scale(range)); - HitResult hitResult = player.level().clip(new ClipContext( - eyes, - end, - ClipContext.Block.OUTLINE, - ClipContext.Fluid.NONE, - player - )); - - return hitResult instanceof BlockHitResult blockHitResult ? blockHitResult : null; - } - - @EventHandler - private void onPlayerJump(PlayerJumpEvent event) { - LocalPlayer player = player(); - if (!isEnabled() || player == null) return; - - ticksUntilTellyJump = 0; - tellyJumpTicks = randomTellyJumpTicks(); - if (!jumpStrafe.get()) return; - - float direction = getRawMovementDirectionYaw(player, player.getYRot()); - boolean straight = Math.round(direction / 45.0f) * 45 % 90 == 0; - double min = straight ? jumpStrafeStraightMin.get() : jumpStrafeDiagonalMin.get(); - double max = straight ? jumpStrafeStraightMax.get() : jumpStrafeDiagonalMax.get(); - double speed = randomRange(min, max); - Vec3 strafeVelocity = MovementUtil.withStrafe(player.getDeltaMovement(), new Vec3(0.0, 0.0, 1.0), direction, speed, 1.0); - player.setDeltaMovement(strafeVelocity.x, player.getDeltaMovement().y, strafeVelocity.z); - } - - private InteractionHand preparePlacementHand(LocalPlayer player) { - if (player == null) return null; - if (ScaffoldBlockItemSelection.isValidBlock(player.getMainHandItem())) return InteractionHand.MAIN_HAND; - if (ScaffoldBlockItemSelection.isValidBlock(player.getOffhandItem())) return InteractionHand.OFF_HAND; - if (!autoBlock.get()) return null; - - int bestSlot = ScaffoldBlockItemSelection.findBestHotbarSlot( - player, - autoBlockDoNotUseBelowCount.get(), - InventorySwap.INSTANCE.serverSelectedSlot() - ); - if (bestSlot < 0) return null; - InventorySwap.INSTANCE.leaseHotbar(this, bestSlot, autoBlockSlotResetDelay.get()); - - return ScaffoldBlockItemSelection.isValidBlock(player.getMainHandItem()) ? InteractionHand.MAIN_HAND : null; - } - - private void restoreSelectedSlot() { - InventorySwap.INSTANCE.releaseHotbar(this); - } - - private ItemStack getPreferredPlacementStack(LocalPlayer player) { - if (player == null) return ItemStack.EMPTY; - if (ScaffoldBlockItemSelection.isValidBlock(player.getMainHandItem())) return player.getMainHandItem(); - if (ScaffoldBlockItemSelection.isValidBlock(player.getOffhandItem())) return player.getOffhandItem(); - if (!autoBlock.get()) return ItemStack.EMPTY; - - int bestSlot = ScaffoldBlockItemSelection.findBestHotbarSlot( - player, - autoBlockDoNotUseBelowCount.get(), - InventorySwap.INSTANCE.serverSelectedSlot() - ); - if (bestSlot < 0) return ItemStack.EMPTY; - - if (autoBlockAlways.get()) { - InventorySwap.INSTANCE.leaseHotbar(this, bestSlot, autoBlockSlotResetDelay.get()); - if (ScaffoldBlockItemSelection.isValidBlock(player.getMainHandItem())) { - return player.getMainHandItem(); - } - } - - return player.getInventory().getItem(bestSlot); - } - - private ItemStack peekPlacementIndicatorStack(LocalPlayer player) { - if (player == null) return ItemStack.EMPTY; - if (ScaffoldBlockItemSelection.isValidBlock(player.getMainHandItem())) return player.getMainHandItem(); - if (ScaffoldBlockItemSelection.isValidBlock(player.getOffhandItem())) return player.getOffhandItem(); - if (!autoBlock.get()) return ItemStack.EMPTY; - - int silentSlot = InventorySwap.INSTANCE.isHotbarLeasedBy(this) ? InventorySwap.INSTANCE.serverSelectedSlot() : -1; - if (silentSlot >= 0 && silentSlot <= 8) { - ItemStack stack = player.getInventory().getItem(silentSlot); - if (ScaffoldBlockItemSelection.isValidBlock(stack)) { - return stack; - } - } - - int bestSlot = ScaffoldBlockItemSelection.findBestHotbarSlot( - player, - autoBlockDoNotUseBelowCount.get(), - InventorySwap.INSTANCE.serverSelectedSlot() - ); - return bestSlot >= 0 ? player.getInventory().getItem(bestSlot) : ItemStack.EMPTY; - } - - private PlacementIndicatorData getPlacementIndicatorData(LocalPlayer player) { - ItemStack stack = peekPlacementIndicatorStack(player); - if (stack.isEmpty()) return null; - - int count = getPlacementIndicatorCount(player, stack); - return new PlacementIndicatorData(stack, Math.max(count, 0), String.valueOf(Math.max(count, 0))); - } - - private int getPlacementIndicatorCount(LocalPlayer player, ItemStack stack) { - if (player == null || stack.isEmpty()) return 0; - - return switch (placementIndicatorCountMode.get()) { - case CURRENT_STACK -> stack.getCount(); - case SAME_ITEM -> countAvailableScaffoldBlocks(player, candidate -> - ItemStack.isSameItemSameComponents(candidate, stack)); - case ALL_PLACEABLE -> countAvailableScaffoldBlocks(player, ScaffoldBlockItemSelection::isValidBlock); - }; - } - - private int countAvailableScaffoldBlocks(LocalPlayer player, java.util.function.Predicate predicate) { - int count = 0; - - ItemStack offhand = player.getOffhandItem(); - if (predicate.test(offhand)) { - count += offhand.getCount(); - } - - for (int slot = 0; slot < 36; slot++) { - ItemStack stack = player.getInventory().getItem(slot); - if (predicate.test(stack)) { - count += stack.getCount(); - } - } - - return count; - } - - private RenderPreview getRenderPreview(float tickDelta) { - Minecraft mc = Minecraft.getInstance(); - if (mc.level == null) return null; - - if (currentTarget != null) { - BlockPos pos = currentTarget.getPlacedBlockPos(); - if (mc.level.getBlockState(pos).canBeReplaced()) { - return new RenderPreview(pos, 1.0f); - } - } - - if (lastPlacedRenderPos == null) return null; - - double elapsed = (System.currentTimeMillis() - lastPlacedRenderMillis) / 1000.0; - double duration = renderPlaceAnimTime.get(); - if (elapsed >= duration) { - lastPlacedRenderPos = null; - return null; - } - - float progress = (float) (1.0 - (elapsed / duration)); - return new RenderPreview(lastPlacedRenderPos, Mth.clamp(progress, 0.0f, 1.0f)); - } - - private AABB animatedRenderBox(BlockPos pos, float progress, float tickDelta) { - double time = (System.currentTimeMillis() / 1000.0) * renderBobSpeed.get(); - double bob = Math.sin((time + tickDelta) * Math.PI) * renderBobAmplitude.get() * progress; - double inset = 0.06 * (1.0 - progress); - - return new AABB( - pos.getX() + inset, - pos.getY() + inset + bob, - pos.getZ() + inset, - pos.getX() + 1.0 - inset, - pos.getY() + 1.0 - inset + bob, - pos.getZ() + 1.0 - inset - ); - } - - private BlockPos getTargetedPosition(LocalPlayer player) { - Vec3 predictedPos = getPlacementBasePosition(player); - BlockPos basePos = BlockPos.containing(predictedPos); - if (shouldGoDown(player)) { - return basePos.below(2); - } - if (canConstructCeiling(player)) { - return basePos.above(3); - } - if (Minecraft.getInstance().options.keyJump.isDown() - && (!isMoving(player) || player.horizontalCollision)) { - return basePos.below(); - } - - return switch (sameY.get()) { - case ON -> new BlockPos(basePos.getX(), placementY, basePos.getZ()); - case FALLING -> player.getDeltaMovement().y < 0.2 - ? new BlockPos(basePos.getX(), placementY, basePos.getZ()) - : basePos.below(); - case OFF -> basePos.below(); - }; - } - - private ScaffoldPlacementTarget findPlacementTarget(LocalPlayer player, ItemStack stack) { - return switch (technique.get()) { - case EXPAND -> findExpandPlacementTarget(player, stack); - case NORMAL -> findNormalPlacementTarget(player, stack); - }; - } - - private boolean refreshCurrentTarget(LocalPlayer player) { - if (!canOperate(player)) { - currentTarget = null; - if (debugLastTargetPos != null) { - debugLog("target-cleared reason=canOperate-false"); - debugLastTargetPos = null; - } - return false; - } - - ItemStack stack = getPreferredPlacementStack(player); - if (!ScaffoldBlockItemSelection.isValidBlock(stack)) { - currentTarget = null; - if (debugLastTargetPos != null) { - debugLog("target-cleared reason=no-valid-stack"); - debugLastTargetPos = null; - } - return false; - } - - currentTarget = findPlacementTarget(player, stack); - BlockPos currentPos = currentTarget != null ? currentTarget.getPlacedBlockPos() : null; - if (currentPos == null) { - if (debugLastTargetPos != null) { - debugLog("target-cleared reason=findPlacementTarget-null"); - debugLastTargetPos = null; - } - } else if (!currentPos.equals(debugLastTargetPos)) { - debugLog( - "target-acquired tech=%s timing=%s target=%s playerPos=%s vel=%s", - EnumIds.defaultId(technique.get()), - EnumIds.defaultId(rotationTiming.get()), - describeTarget(currentTarget), - formatVec(player.position()), - formatVec(player.getDeltaMovement()) - ); - debugLastTargetPos = currentPos; - } - return currentTarget != null; - } - - private boolean shouldKeepPreviousTarget( - LocalPlayer player, - ScaffoldPlacementTarget previousTarget, - ScaffoldPlacementTarget nextTarget - ) { - if (player == null || previousTarget == null || nextTarget == null) { - return false; - } - if (isTargetStaleForPlayer(player, previousTarget)) { - return false; - } - if (!isNearbyPlacementTransition(previousTarget, nextTarget)) { - return false; - } - if (!isPreviousTargetStillActionable(player, previousTarget)) { - return false; - } - - Rotation previousRotation = previousTarget.getRotation(); - Rotation nextRotation = nextTarget.getRotation(); - if (previousRotation == null || nextRotation == null) { - return false; - } - - return previousRotation.angleTo(nextRotation) > 90.0f; - } - - private boolean isNearbyPlacementTransition(ScaffoldPlacementTarget previousTarget, ScaffoldPlacementTarget nextTarget) { - if (previousTarget == null || nextTarget == null) { - return false; - } - - BlockPos previousPlaced = previousTarget.getPlacedBlockPos(); - BlockPos nextPlaced = nextTarget.getPlacedBlockPos(); - if (previousPlaced.equals(nextPlaced)) { - return true; - } - - int dx = Math.abs(previousPlaced.getX() - nextPlaced.getX()); - int dy = Math.abs(previousPlaced.getY() - nextPlaced.getY()); - int dz = Math.abs(previousPlaced.getZ() - nextPlaced.getZ()); - return dy == 0 && dx + dz <= 1; - } - - private boolean isPreviousTargetStillActionable(LocalPlayer player, ScaffoldPlacementTarget target) { - if (player == null || target == null || player.level() == null) { - return false; - } - - BlockState supportState = player.level().getBlockState(target.getInteractedBlockPos()); - if (supportState == null || supportState.canBeReplaced()) { - return false; - } - - BlockState placedState = player.level().getBlockState(target.getPlacedBlockPos()); - if (placedState == null || !placedState.canBeReplaced()) { - return false; - } - - return isWithinBlockInteractionRange(player, target.getHitVec()); - } - - private ScaffoldPlacementTarget findNormalPlacementTarget(LocalPlayer player, ItemStack stack) { - Vec3 placementEyePos = getPlacementEyePos(player); - Comparator comparator = getNormalTargetComparator(player, placementEyePos); - List offsets = shouldGoDown(player) ? DOWN_OFFSETS : NORMAL_OFFSETS; - ScaffoldFacePositionFactory facePositionFactory = createPlacementFacePositionFactory(player, aimMode.get(), placementEyePos); - BlockPos targetedPos = getTargetedPosition(player); - List movementOffsets = movementAlignedNormalOffsets(player, targetedPos, offsets); - if (movementOffsets.isEmpty()) { - return null; - } - - return findNormalPlacementTargetAt( - player, - stack, - targetedPos, - movementOffsets, - comparator, - facePositionFactory, - placementEyePos - ); - } - - private List movementAlignedNormalOffsets(LocalPlayer player, BlockPos targetedPos, List offsets) { - if (player == null || targetedPos == null || offsets == null || offsets.isEmpty()) { - return offsets; - } - if (currentOptimalLine == null || !hasRawInput() || shouldGoDown(player)) { - return offsets; - } - - Vec3 reference = currentOptimalLine.getNearestPointTo(player.position()); - Vec3 direction = currentOptimalLine.direction(); - List aligned = new ArrayList<>(offsets.size()); - - for (BlockPos offset : offsets) { - BlockPos candidate = targetedPos.offset(offset); - double progress = Vec3.atCenterOf(candidate).subtract(reference).dot(direction); - if (progress >= -0.15) { - aligned.add(offset); - } - } - - return aligned; - } - - private ScaffoldPlacementTarget findNormalPlacementTargetAt( - LocalPlayer player, - ItemStack stack, - BlockPos targetedPos, - List offsets, - Comparator comparator, - ScaffoldFacePositionFactory facePositionFactory, - Vec3 placementEyePos - ) { - return ScaffoldTargetFinder.findTarget( - player, - targetedPos, - stack, - offsets, - comparator, - shouldGoDown(player), - facePositionFactory, - placementEyePos - ); - } - - private ScaffoldPlacementTarget findExpandPlacementTarget(LocalPlayer player, ItemStack stack) { - Vec3 placementEyePos = getPlacementEyePos(player); - for (int i = 0; i <= expandLength.get(); i++) { - BlockPos position = getExpandTargetedPosition(player, i); - ScaffoldPlacementTarget target = ScaffoldTargetFinder.findTarget( - player, - position, - stack, - List.of(BlockPos.ZERO), - Comparator.comparingDouble((BlockPos pos) -> Vec3.atCenterOf(pos).distanceToSqr(placementEyePos)).reversed(), - true, - new ScaffoldFacePositionFactory( - player, - placementEyePos, - ScaffoldFacePositionFactory.Mode.CENTER, - currentOptimalLine, - randomRange(-1.0, 1.0) - ), - placementEyePos - ); - if (target == null) continue; - Vec3 blockCenter = Vec3.atCenterOf(target.getPlacedBlockPos()); - Rotation rotation = Rotation.lookingAt(blockCenter, placementEyePos); - return target.withRotation(rotation); - } - return null; - } - - private ScaffoldPlacementTarget findCenterPlacementTarget(LocalPlayer player, ItemStack stack) { - Vec3 placementEyePos = getPlacementEyePos(player); - return ScaffoldTargetFinder.findTarget( - player, - getTargetedPosition(player), - stack, - NORMAL_OFFSETS, - Comparator.comparingDouble((BlockPos pos) -> Vec3.atCenterOf(pos).distanceToSqr(placementEyePos)).reversed(), - false, - new ScaffoldFacePositionFactory( - player, - placementEyePos, - ScaffoldFacePositionFactory.Mode.CENTER, - currentOptimalLine, - randomRange(-1.0, 1.0) - ), - placementEyePos - ); - } - - private BlockPos getExpandTargetedPosition(LocalPlayer player, int expand) { - Vec3 position = player.position(); - float yaw = player.getYRot(); - int x = (int) (-Math.sin(Math.toRadians(yaw)) * expand); - int z = (int) (Math.cos(Math.toRadians(yaw)) * expand); - BlockPos expanded = BlockPos.containing(position).offset(x, 0, z); - return getTargetedPositionFromBase(player, expanded); - } - - private BlockPos getTargetedPositionFromBase(LocalPlayer player, BlockPos basePos) { - if (shouldGoDown(player)) { - return basePos.below(2); - } - if (Minecraft.getInstance().options.keyJump.isDown() - && (!isMoving(player) || player.horizontalCollision)) { - return basePos.below(); - } - return switch (sameY.get()) { - case ON -> new BlockPos(basePos.getX(), placementY, basePos.getZ()); - case FALLING -> player.getDeltaMovement().y < 0.2 - ? new BlockPos(basePos.getX(), placementY, basePos.getZ()) - : basePos.below(); - case OFF -> basePos.below(); - }; - } - - private void sendLookPacket(LocalPlayer player, Rotation rotation) { - if (player == null || player.connection == null || rotation == null) return; - Rotation normalized = rotation.normalize(); - debugLog( - "send-look pos=%s rot=%s onGround=%s horiz=%s", - formatVec(player.position()), - describeRotation(normalized), - player.onGround(), - player.horizontalCollision - ); - player.connection.send(new ServerboundMovePlayerPacket.PosRot( - player.getX(), - player.getY(), - player.getZ(), - normalized.yaw(), - normalized.pitch(), - player.onGround(), - player.horizontalCollision - )); - } - - private boolean canOperate(LocalPlayer player) { - Minecraft mc = Minecraft.getInstance(); - return player != null - && mc.level != null - && mc.gameMode != null - && ClientScreen.current() == null; - } - - private boolean isMoving(LocalPlayer player) { - if (player == null || player.input == null) return false; - return Math.abs(player.input.getMoveVector().x) > 1.0E-5f - || Math.abs(player.input.getMoveVector().y) > 1.0E-5f; - } - - private boolean shouldGoDown(LocalPlayer player) { - Minecraft mc = Minecraft.getInstance(); - return down.get() - && player != null - && mc.options.keyShift.isDown() - && canStandOn(player.blockPosition().below(2)); - } - - private boolean shouldEagle(LocalPlayer player, MovementInputEvent event) { - if (player == null || event == null) return false; - - EagleUtil.EdgeCheck edgeCheck = EagleUtil.checkEdge(player, event, eagleEdgeDistance.get()); - return placementGate.consumeEaglePulse( - eagle.get(), - edgeCheck.closeToEdge(), - eagleOnlyOnGround.get(), - player.onGround(), - player.getAbilities().flying, - shouldGoDown(player) - ); - } - - private boolean isPlacementCadenceReady() { - return placementGate.isPlacementReady(System.nanoTime(), placementSpeed.get(), delayLeft); - } - - private void handleTower(LocalPlayer player) { - if (!isEnabled() || player == null) return; - if (!isTowering(player)) { - towerJumpBaseY = Double.NaN; - return; - } - - switch (towerMode.get()) { - case MOTION -> handleMotionTower(player); - case VULCAN -> handleVulcanTower(player); - case HYPIXEL -> handleHypixelTower(player); - default -> { - } - } - } - - private void handleAcceleration(LocalPlayer player) { - if (!acceleration.get() || player == null) return; - if (accelerationOnlyOnGround.get() && !player.onGround()) return; - - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement( - velocity.x * accelerationMultiplier.get(), - velocity.y, - velocity.z * accelerationMultiplier.get() - ); - } - - private void updateStrafeMoveTicks(LocalPlayer player) { - if (player == null) return; - if (isMoving(player)) { - strafeMoveTicks++; - } else { - strafeMoveTicks = 0; - } - } - - private void handleHeadHitter(LocalPlayer player) { - if (!headHitter.get() || technique.get() != Technique.NORMAL || player == null) return; - if (!player.onGround() || !isMoving(player)) return; - BlockPos above = player.blockPosition().above(2); - if (player.level().getBlockState(above).isAir()) return; - player.jumpFromGround(); - } - - private void handleStabilizeMovement(LocalPlayer player, MovementInputEvent event) { - if (!stabilizeMovement.get() || technique.get() != Technique.NORMAL || player == null) return; - if (rotationTiming.get() != RotationTiming.NORMAL) return; - if (event.isJump() && player.onGround()) return; - - ScaffoldLine optimalLine = currentOptimalLine; - if (optimalLine == null) return; - - Vec3 nearestPoint = optimalLine.getNearestPointTo(player.position()); - Vec3 toLine = nearestPoint.subtract(player.position()); - Vec3 lineDirection = new Vec3(optimalLine.direction().x, 0.0, optimalLine.direction().z); - if (lineDirection.lengthSqr() < 1.0E-7) return; - - Vec3 desiredWorld = lineDirection.normalize(); - double correctionLength = Math.hypot(toLine.x, toLine.z); - if (correctionLength > 1.0E-7) { - Vec3 correction = new Vec3(toLine.x / correctionLength, 0.0, toLine.z / correctionLength); - double correctionStrength = Mth.clamp(0.35 + correctionLength * 3.0, 0.35, 1.0); - desiredWorld = desiredWorld.add(correction.scale(correctionStrength)).normalize(); - } - - applyLineHoldInput(event, desiredWorld, player.getYRot()); - } - - private void applyLineHoldInput(MovementInputEvent event, Vec3 desiredWorld, float yaw) { - double rad = Math.toRadians(yaw); - double sin = Math.sin(rad); - double cos = Math.cos(rad); - double localForward = desiredWorld.z * cos - desiredWorld.x * sin; - double localSideways = desiredWorld.x * cos + desiredWorld.z * sin; - - event.setForward(localForward > 1.0E-4); - event.setBackward(localForward < -1.0E-4); - event.setLeft(localSideways < -1.0E-4); - event.setRight(localSideways > 1.0E-4); - } - - private void handleNormalStrictMoonwalkInput(LocalPlayer player, MovementInputEvent event) { - if (player == null || event == null) return; - if (technique.get() != Technique.NORMAL) return; - if (rotationTiming.get() != RotationTiming.NORMAL) return; - if (movementCorrection.get() != MovementCorrection.STRICT) return; - if (!hasRawInput() || blockCount(player) <= 0) return; - - Rotation movementRotation = RotationManager.INSTANCE.getCurrentRotation(); - if (movementRotation == null && currentTarget != null) { - movementRotation = currentTarget.getRotation(); - } - if (movementRotation == null) { - movementRotation = new Rotation(getRawMovementDirectionYaw(player, player.getYRot()) + 180.0f, 75.0f, false).normalize(); - } - - Input corrected = RotationUtil.correctMovementInput( - event.toPlayerInput(), - player.getYRot(), - movementRotation.yaw() - ); - if (corrected == null) return; - - event.setForward(corrected.forward()); - event.setBackward(corrected.backward()); - event.setLeft(corrected.left()); - event.setRight(corrected.right()); - event.setJump(corrected.jump()); - event.setSprint(corrected.sprint() && corrected.forward() && !corrected.backward()); - } - - private void handleTelly(LocalPlayer player, MovementInputEvent event) { - if (!telly.get() || technique.get() != Technique.NORMAL || player == null) return; - if (!isMoving(player) || blockCount(player) <= 0 || !player.onGround()) return; - - switch (tellyResetMode.get()) { - case REVERSE -> event.setJump(true); - case RESET -> { - if (shouldTellyJumpNow(player)) { - event.setJump(true); - } - } - } - } - - private void handleStrafe(LocalPlayer player) { - if (!strafe.get() || player == null) return; - if (strafeOnlyOnGround.get() && !player.onGround()) return; - - if (strafeHypixel.get()) { - double speedValue = player.hasEffect(net.minecraft.world.effect.MobEffects.SPEED) ? 0.295 : 0.207; - if (player.tickCount % 20 == 0 || strafeMoveTicks <= 7) { - speedValue = 0.09800000190734863; - } - Vec3 velocity = MovementUtil.withStrafe(player.getDeltaMovement(), movementInputVector(player), player.getYRot(), speedValue, 1.0); - player.setDeltaMovement(velocity); - return; - } - - Vec3 velocity = MovementUtil.withStrafe(player.getDeltaMovement(), movementInputVector(player), player.getYRot(), strafeSpeed.get(), 1.0); - player.setDeltaMovement(velocity); - } - - private void handleMotionTower(LocalPlayer player) { - if (player.onGround()) { - player.jumpFromGround(); - towerJumpBaseY = player.getY(); - return; - } - - if (Double.isNaN(towerJumpBaseY)) return; - if (player.getY() <= towerJumpBaseY + towerTriggerHeight.get()) return; - - player.absSnapTo(player.getX(), Math.floor(player.getY()), player.getZ()); - Vec3 velocity = player.getDeltaMovement(); - player.setDeltaMovement( - velocity.x * towerSlow.get(), - towerMotion.get(), - velocity.z * towerSlow.get() - ); - towerJumpBaseY = player.getY(); - } - - private void handleVulcanTower(LocalPlayer player) { - if (player.tickCount % 2 == 0) { - player.setDeltaMovement(player.getDeltaMovement().x, 0.7, player.getDeltaMovement().z); - } else { - player.setDeltaMovement(player.getDeltaMovement().x, isMoving(player) ? 0.42 : 0.6, player.getDeltaMovement().z); - } - } - - private void handleHypixelTower(LocalPlayer player) { - Vec3 velocity = player.getDeltaMovement(); - - if (Math.abs(player.getX() % 1.0) > 1.0E-4 && !isMoving(player)) { - double adjust = Math.round(player.getX()) - player.getX(); - player.setDeltaMovement(Math.copySign(Math.min(Math.abs(adjust), 0.281), adjust), velocity.y, velocity.z); - velocity = player.getDeltaMovement(); - } - - if (towerAirTicks > 14) { - player.setDeltaMovement(velocity.x * 0.6, velocity.y - 0.09, velocity.z * 0.6); - return; - } - - int mod = Math.floorMod(towerAirTicks, 3); - if (mod == 0) { - Vec3 strafe = MovementUtil.withStrafe(player.getDeltaMovement(), new Vec3(0.0, 0.0, 1.0), player.getYRot(), 0.247, 1.0); - player.setDeltaMovement(strafe.x, 0.42, strafe.z); - } else if (mod == 2) { - player.setDeltaMovement(velocity.x, 1.0 - (player.getY() % 1.0), velocity.z); - } - } - - private boolean isTowering(LocalPlayer player) { - Minecraft mc = Minecraft.getInstance(); - return towerMode.get() != TowerMode.NONE - && player != null - && mc.options.keyJump.isDown() - && !shouldGoDown(player) - && blockCount(player) > 0 - && isBlockBelow(player); - } - - - private float getRawMovementDirectionYaw(LocalPlayer player, float fallbackYaw) { - if (player == null) return fallbackYaw; - boolean forwards = rawForward && !rawBackward; - boolean backwards = rawBackward && !rawForward; - boolean left = rawLeft && !rawRight; - boolean right = rawRight && !rawLeft; - - if (!forwards && !backwards && !left && !right) return fallbackYaw; - - float actualYaw = fallbackYaw; - float forward = 1.0f; - - if (backwards) { - actualYaw += 180.0f; - forward = -0.5f; - } else if (forwards) { - forward = 0.5f; - } - - if (left) { - actualYaw -= 90.0f * forward; - } - if (right) { - actualYaw += 90.0f * forward; - } - - return actualYaw; - } - - private boolean hasRawInput() { - return rawForward || rawBackward || rawLeft || rawRight; - } - - private boolean isRawDiagonal() { - return rawForward != rawBackward && rawLeft != rawRight; - } - - private Vec3 movementInputVector(LocalPlayer player) { - if (player == null || player.input == null) return Vec3.ZERO; - return new Vec3(player.input.getMoveVector().x, 0.0, player.input.getMoveVector().y); - } - - private double horizontalSpeed(Vec3 velocity) { - return velocity == null ? 0.0 : Math.hypot(velocity.x, velocity.z); - } - - private double randomRange(double min, double max) { - double low = Math.min(min, max); - double high = Math.max(min, max); - return low + Math.random() * (high - low); - } - - - private Comparator getNormalTargetComparator(LocalPlayer player, Vec3 placementEyePos) { - if (currentOptimalLine != null) { - return Comparator.comparingDouble((BlockPos pos) -> currentOptimalLine.squaredDistanceTo(Vec3.atCenterOf(pos))).reversed(); - } - Vec3 referenceEyePos = placementEyePos != null - ? placementEyePos - : (player != null ? player.getEyePosition() : Vec3.ZERO); - return Comparator.comparingDouble((BlockPos pos) -> Vec3.atCenterOf(pos).distanceToSqr(referenceEyePos)).reversed(); - } - - private ScaffoldFacePositionFactory createPlacementFacePositionFactory( - LocalPlayer player, - ScaffoldFacePositionFactory.Mode mode, - Vec3 placementEyePos - ) { - return new ScaffoldFacePositionFactory( - player, - placementEyePos, - mode, - currentOptimalLine, - randomRange(-1.0, 1.0) - ); - } - - private Vec3 getPlacementEyePos(LocalPlayer player) { - if (player == null) { - return Vec3.ZERO; - } - - Vec3 placementPos = getPlacementBasePosition(player); - return placementPos.add(0.0, player.getEyeHeight(player.getPose()), 0.0); - } - - private boolean canConstructCeiling(LocalPlayer player) { - return ceiling.get() - && technique.get() == Technique.NORMAL - && player != null - && !player.level().getBlockState(player.blockPosition().below()).isAir(); - } - - private boolean shouldTellyJumpNow(LocalPlayer player) { - if (ticksUntilTellyJump < tellyJumpTicks) return false; - if (isTowering(player) && !tellyAimOnTower.get()) return false; - return RotationManager.INSTANCE.getCurrentRotation() == null || tellyStraightTicks.get() == 0; - } - - private int randomTellyJumpTicks() { - int min = Math.min(tellyJumpTicksMin.get(), tellyJumpTicksMax.get()); - int max = Math.max(tellyJumpTicksMin.get(), tellyJumpTicksMax.get()); - return min + (int) Math.floor(Math.random() * (max - min + 1)); - } - - - private Vec3 getPlacementBasePosition(LocalPlayer player) { - if (player == null) return Vec3.ZERO; - if (prediction.get()) { - Vec3 predicted = movementPrediction.getPredictedPlacementPos(player, currentOptimalLine); - if (predicted != null) { - return predicted; - } - } - if (technique.get() == Technique.NORMAL && isRawDiagonal() && currentOptimalLine != null) { - return getTickDeltaDiagonalPlacementPos(player); - } - return player.position(); - } - - private Vec3 getTickDeltaDiagonalPlacementPos(LocalPlayer player) { - Vec3 velocity = new Vec3(player.getDeltaMovement().x, 0.0, player.getDeltaMovement().z); - double tickDelta = TickDelta.get(); - double lead = Math.max(0.35, Math.min(1.35, tickDelta + 0.45)); - Vec3 projected = player.position().add(velocity.scale(lead)); - - if (velocity.horizontalDistanceSqr() < 0.02 * 0.02) { - Vec3 direction = currentOptimalLine.direction().normalize(); - projected = projected.add(direction.scale(0.18 + tickDelta * 0.12)); - } - - return currentOptimalLine.getNearestPointTo(projected); - } - - private boolean isBlockBelow(LocalPlayer player) { - return player != null && player.level().getBlockCollisions( - player, - player.getBoundingBox().inflate(0.5, 0.0, 0.5).move(0.0, -1.05, 0.0) - ).iterator().hasNext(); - } - - private boolean canStandOn(BlockPos pos) { - Minecraft mc = Minecraft.getInstance(); - return mc.level != null - && mc.level.getBlockState(pos).isFaceSturdy(mc.level, pos, net.minecraft.core.Direction.UP); - } - - private int blockCount(LocalPlayer player) { - if (player == null) return 0; - int count = ScaffoldBlockItemSelection.isValidBlock(player.getOffhandItem()) ? player.getOffhandItem().getCount() : 0; - for (int i = 0; i < 9; i++) { - ItemStack stack = player.getInventory().getItem(i); - if (ScaffoldBlockItemSelection.isValidBlock(stack)) { - count += stack.getCount(); - } - } - return count; - } - - private LocalPlayer player() { - Minecraft mc = Minecraft.getInstance(); - return mc != null ? mc.player : null; - } - - private List buildRotationProcessors() { - List processors = new ArrayList<>(); - AngleSmooth smooth = selectAngleSmooth(); - if (smooth != null) { - processors.add(smooth); - } - return processors; - } - - private AngleSmooth selectAngleSmooth() { - return switch (angleSmoothMode.get()) { - case LINEAR -> linearSmooth; - case SIGMOID -> sigmoidSmooth; - case INTERPOLATION -> interpolationSmooth; - case ACCELERATION -> accelerationSmooth; - case NONE -> null; - }; - } - - public enum RotationTiming { - NORMAL, - ON_TICK - } - - public enum AngleSmoothMode { - LINEAR, - SIGMOID, - INTERPOLATION, - ACCELERATION, - NONE - } - - public enum SameYMode { - OFF, - ON, - FALLING - } - - public enum SprintMode { - DO_NOT_CHANGE, - FORCE_SPRINT, - FORCE_NO_SPRINT, - NO_SPRINT_ON_PLACE, - NO_SPRINT_ON_GROUND - } - - public enum TowerMode { - NONE, - MOTION, - VULCAN, - HYPIXEL - } - - public enum Technique { - NORMAL, - EXPAND - } - - public enum TellyResetMode { - REVERSE, - RESET - } - - public enum IndicatorSide { - LEFT, - RIGHT, - TOP, - BOTTOM - } - - public enum IndicatorStyle { - SLOT, - PILL - } - - public enum IndicatorCountMode { - CURRENT_STACK, - SAME_ITEM, - ALL_PLACEABLE - } - - private record RenderPreview(BlockPos pos, float progress) { - } - - private record PlacementIndicatorData(ItemStack stack, int count, String countText) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/ShitDropper.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/ShitDropper.java index 04a7ef3..424eb64 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/ShitDropper.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/ShitDropper.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/XCarry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/XCarry.java deleted file mode 100644 index 2cbc74c..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/player/XCarry.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.features.module.modules.player; - -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.features.module.ModuleCategory; -import dev.loki.lovisual.features.module.ModuleInfo; - -/** - * Keeps items in the 2x2 crafting grid or cursor when closing inventory (no drops). - */ -//todo Description -@ModuleInfo( - id = "xcarry", - displayName = "XCarry", - category = ModuleCategory.PLAYER -) -public class XCarry extends Module { -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/AspectRatio.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/AspectRatio.java index ddef613..6af0d96 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/AspectRatio.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/AspectRatio.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BedwarsESP.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BedwarsESP.java index 367560d..3e29831 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BedwarsESP.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BedwarsESP.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BlockESP.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BlockESP.java index 79341a8..f47e964 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BlockESP.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BlockESP.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BlockHighlight.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BlockHighlight.java index 8be2e12..bcd4164 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BlockHighlight.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/BlockHighlight.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -31,7 +31,7 @@ import dev.loki.lovisual.features.module.WorldPhase; import dev.loki.lovisual.mixins.accessors.MultiPlayerGameModeAccessor; import dev.loki.lovisual.render.engine.RenderState; import dev.loki.lovisual.render.engine.animation.AnimatedRenderColors; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; @@ -281,8 +281,8 @@ public class BlockHighlight extends Module { private void renderShapeLines(Renderer3D renderer, VoxelShape worldShape) { MeshBuilder mesh = renderer.batch( outlineDepthTest.get() - ? CombatantRenderPipelines.WORLD_COLORED_DEPTH - : CombatantRenderPipelines.WORLD_COLORED, + ? LoVisualRenderPipelines.WORLD_COLORED_DEPTH + : LoVisualRenderPipelines.WORLD_COLORED, outlineDepthTest.get() ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.NONE @@ -376,8 +376,8 @@ public class BlockHighlight extends Module { private void renderShapeBoxes(Renderer3D renderer, VoxelShape worldShape) { MeshBuilder mesh = renderer.batch( outlineDepthTest.get() - ? CombatantRenderPipelines.WORLD_COLORED_DEPTH - : CombatantRenderPipelines.WORLD_COLORED, + ? LoVisualRenderPipelines.WORLD_COLORED_DEPTH + : LoVisualRenderPipelines.WORLD_COLORED, outlineDepthTest.get() ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.NONE @@ -446,10 +446,10 @@ public class BlockHighlight extends Module { if (interactionManager == null || !interactionManager.isDestroying()) return; if (!(interactionManager instanceof MultiPlayerGameModeAccessor accessor)) return; - BlockPos pos = accessor.combatant$getCurrentBreakingPos(); + BlockPos pos = accessor.lovisual$getCurrentBreakingPos(); if (pos == null) return; - float progress = Mth.clamp(accessor.combatant$getCurrentBreakingProgress(), 0.0f, 1.0f); + float progress = Mth.clamp(accessor.lovisual$getCurrentBreakingProgress(), 0.0f, 1.0f); renderBreakingInfo(renderer, pos, progress); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/CameraClip.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/CameraClip.java index 25bffe3..d9a2677 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/CameraClip.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/CameraClip.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Chams.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Chams.java index 6e5abbb..3195694 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Chams.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Chams.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -35,7 +35,7 @@ import dev.loki.lovisual.features.module.ModuleInfo; import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.mixins.accessors.GameRendererAccessor; import dev.loki.lovisual.mixins.iris.IrisHandRendererAccessor; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; @@ -363,7 +363,7 @@ public class Chams extends Module { renderIrisHandMaskPhase(renderer, cameraRenderState, positionMatrix, dispatcher, tickDelta, true); renderIrisHandMaskPhase(renderer, cameraRenderState, positionMatrix, dispatcher, tickDelta, false); } finally { - ((IrisHandRendererAccessor) HandRenderer.INSTANCE).combatant$setRenderingSolid(false); + ((IrisHandRendererAccessor) HandRenderer.INSTANCE).lovisual$setRenderingSolid(false); RenderSystem.restoreProjectionMatrix(); RenderState.rendering3D = prevRendering3D; RenderSystem.outputColorTextureOverride = prevColor; @@ -381,9 +381,9 @@ public class Chams extends Module { float tickDelta, boolean solidPhase) { IrisHandRendererAccessor irisHand = (IrisHandRendererAccessor) HandRenderer.INSTANCE; - irisHand.combatant$setRenderingSolid(solidPhase); + irisHand.lovisual$setRenderingSolid(solidPhase); - PoseStack handMatrices = irisHand.combatant$invokeSetupGlState(renderer, cameraRenderState, positionMatrix, tickDelta); + PoseStack handMatrices = irisHand.lovisual$invokeSetupGlState(renderer, cameraRenderState, positionMatrix, tickDelta); handMatrices.pushPose(); var modelView = RenderSystem.getModelViewStack(); modelView.pushMatrix(); @@ -420,7 +420,7 @@ public class Chams extends Module { if (w <= 0 || h <= 0) return; if (handMask == null) { - handMask = new TextureTarget("combatant-hand-mask", w, h, true, GpuFormat.RGBA8_UNORM); + handMask = new TextureTarget("lovisual-hand-mask", w, h, true, GpuFormat.RGBA8_UNORM); bufferW = w; bufferH = h; } else if (w != bufferW || h != bufferH) { @@ -564,7 +564,7 @@ public class Chams extends Module { FullScreenRenderer.begin("LoVisual Fullscreen Pass") .attachment(dst) - .pipeline(CombatantRenderPipelines.HAND_GLASS) + .pipeline(LoVisualRenderPipelines.HAND_GLASS) .uniform("HandGlass", HandGlassUniforms.get()) .sampler("u_Src", src, PostProcessManager.getSampler()) .sampler("u_Mask", maskView, getHandMaskSampler()) @@ -592,7 +592,7 @@ public class Chams extends Module { FullScreenRenderer.begin("LoVisual Fullscreen Pass") .attachment(dst) - .pipeline(CombatantRenderPipelines.HAND_METALLIC) + .pipeline(LoVisualRenderPipelines.HAND_METALLIC) .uniform("HandMetallic", HandMetallicUniforms.get()) .sampler("u_Src", src, PostProcessManager.getSampler()) .sampler("u_Mask", maskView, getHandMaskSampler()) @@ -621,7 +621,7 @@ public class Chams extends Module { FullScreenRenderer.begin("LoVisual Fullscreen Pass") .attachment(dst) - .pipeline(CombatantRenderPipelines.HAND_SMOKE) + .pipeline(LoVisualRenderPipelines.HAND_SMOKE) .uniform("HandSmoke", HandSmokeUniforms.get()) .sampler("u_Src", src, PostProcessManager.getSampler()) .sampler("u_Mask", maskView, getHandMaskSampler()) diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Crosshair.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Crosshair.java index f38e645..4ac384e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Crosshair.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Crosshair.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -41,7 +41,7 @@ import dev.loki.lovisual.events.impl.PacketEvent; import dev.loki.lovisual.features.gui.hud.HudRenderUtil; import dev.loki.lovisual.features.gui.hud.draggable.impl.Itemizer; import dev.loki.lovisual.features.module.*; -import dev.loki.lovisual.features.module.modules.combat.KillAura; +import dev.loki.lovisual.features.module.Module; import dev.loki.lovisual.features.module.modules.combat.Reach; import dev.loki.lovisual.features.relations.CategoryService; import dev.loki.lovisual.features.relations.EntityFilters; @@ -392,7 +392,7 @@ public class Crosshair extends Module { private float getAttackCooldownProgress() { if (mc.player instanceof IPlayerAttackCooldown cooldown) { - return cooldown.combatant$getAttackCooldownProgress(0.0f); + return cooldown.lovisual$getAttackCooldownProgress(0.0f); } return mc.player.getAttackStrengthScale(0.0f); } @@ -586,12 +586,7 @@ public class Crosshair extends Module { private boolean isVulcanReachActive() { Reach reach = Modules.get(Reach.class); - if (reach != null && reach.isEnabled() && reach.isVulcan297Mode()) { - return true; - } - - KillAura killAura = Modules.get(KillAura.class); - return killAura != null && killAura.isEnabled() && killAura.usesDynamicReach(); + return reach != null && reach.isEnabled() && reach.isVulcan297Mode(); } private double resolveVulcanRequestedReach(Player target) { @@ -600,11 +595,6 @@ public class Crosshair extends Module { return reach.getConfiguredDistance(); } - KillAura killAura = Modules.get(KillAura.class); - if (killAura != null && killAura.isEnabled() && killAura.usesDynamicReach()) { - return killAura.getRange(); - } - return 3.0; } @@ -619,16 +609,6 @@ public class Crosshair extends Module { return player; } - KillAura killAura = Modules.get(KillAura.class); - if (killAura != null - && killAura.isEnabled() - && killAura.usesDynamicReach() - && killAura.getCurrentTarget() instanceof Player auraTarget - && auraTarget.isAlive()) { - lastVulcanReachTarget = auraTarget; - return auraTarget; - } - if (lastVulcanReachTarget != null && !lastVulcanReachTarget.isAlive()) { lastVulcanReachTarget = null; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/DamageTint.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/DamageTint.java index 5c548e3..666b966 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/DamageTint.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/DamageTint.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,7 +15,7 @@ import dev.loki.lovisual.config.values.NumberValue; import dev.loki.lovisual.features.module.Module; import dev.loki.lovisual.features.module.ModuleCategory; import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; @@ -125,7 +125,7 @@ public class DamageTint extends Module implements PostProcessPass { FullScreenRenderer.begin("LoVisual Fullscreen Pass") .attachment(dst) - .pipeline(CombatantRenderPipelines.DAMAGE_TINT) + .pipeline(LoVisualRenderPipelines.DAMAGE_TINT) .uniform("PostProcess", PostProcessUniforms.get()) .sampler("u_Texture", src, PostProcessManager.getSampler()) .end(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/DropESP.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/DropESP.java index ff60fb2..090eaa2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/DropESP.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/DropESP.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ESP.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ESP.java index 7588667..e27f38f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ESP.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ESP.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,72 +8,25 @@ package dev.loki.lovisual.features.module.modules.visuals; -import dev.loki.lovisual.features.theme.Theme; -import com.mojang.blaze3d.GpuFormat; -import com.mojang.blaze3d.ProjectionType; -import com.mojang.blaze3d.buffers.GpuBufferSlice; -import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.pipeline.TextureTarget; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.textures.AddressMode; -import com.mojang.blaze3d.textures.FilterMode; -import com.mojang.blaze3d.textures.GpuSampler; import com.mojang.blaze3d.textures.GpuTextureView; -import com.mojang.blaze3d.vertex.PoseStack; +import dev.loki.lovisual.config.common.CommonSettingSchemas; import dev.loki.lovisual.config.values.*; +import dev.loki.lovisual.features.gui.clickgui.settings.TextListSetting; import dev.loki.lovisual.features.module.*; import dev.loki.lovisual.features.module.Module; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.ProjectionMatrixBuffer; -import net.minecraft.client.renderer.RenderBuffers; -import net.minecraft.client.renderer.SubmitNodeStorage; -import net.minecraft.client.renderer.entity.EntityRenderDispatcher; -import net.minecraft.client.renderer.entity.EntityRenderer; -import net.minecraft.client.renderer.entity.state.EntityRenderState; -import net.minecraft.client.renderer.feature.FeatureRenderDispatcher; -import net.minecraft.client.renderer.state.level.LevelRenderState; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.Identifier; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.joml.Matrix4f; -import org.joml.Quaternionf; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.features.gui.clickgui.settings.TextListSetting; -import dev.loki.lovisual.features.module.modules.combat.Hitbox; -import dev.loki.lovisual.features.relations.CategoryService; -import dev.loki.lovisual.mixins.accessors.EntityRenderManagerAccessor; -import dev.loki.lovisual.mixins.accessors.EntityRendererAccessor; -import dev.loki.lovisual.mixins.accessors.LevelRendererAccessor; -import dev.loki.lovisual.render.ShaderEspRenderContext; -import dev.loki.lovisual.render.compat.EntityCullingCompat; -import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.animation.AnimationUtility; -import dev.loki.lovisual.render.engine.core.CombatantWorldMatrices; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; import dev.loki.lovisual.render.engine.msaa.MsaaFramebuffer; -import dev.loki.lovisual.render.engine.msaa.MsaaWorldTarget; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; -import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; -import dev.loki.lovisual.render.engine.renderer.MeshRenderer; 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.render.engine.uniform.MeshBuilder; -import dev.loki.lovisual.render.engine.uniform.impl.ShaderEspBlurUniforms; -import dev.loki.lovisual.render.engine.uniform.impl.ShaderEspGradientUniforms; -import dev.loki.lovisual.render.engine.uniform.impl.ShaderEspSmokeUniforms; -import dev.loki.lovisual.render.iris.IrisCombatantFrameHooks; -import dev.loki.lovisual.render.helpers.MatteHudStyle; -import dev.loki.lovisual.render.helpers.ScreenProjection; -import dev.loki.lovisual.render.helpers.ScreenSpaceOverlay2D; -import dev.loki.lovisual.util.player.PlayerHealthResolver; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderBuffers; +import net.minecraft.client.renderer.SubmitNodeStorage; +import net.minecraft.client.renderer.feature.FeatureRenderDispatcher; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; import java.util.*; @@ -81,414 +34,146 @@ import java.util.*; @ModuleInfo(id = "esp", displayName = "ESP", aliases = {"wallhack", "wh", "outline"}, category = ModuleCategory.VISUALS) public class ESP extends Module { - private static final String MODE_FULL = "Full"; - private static final String MODE_CHAMFERED = "Chamfered"; - private static final String MODE_CORNERS = "Corners"; - private static final String MODE_3D = "3D"; - private static final String MODE_SHADER = "Шейдер"; - private static final String SHADER_FILL_SOLID = "Solid"; - private static final String SHADER_FILL_SMOKE = "Smoke"; - private static final String SHADER_COLOR_ENTITY = "Entity"; - private static final String SHADER_COLOR_THEME = "Theme"; - private static final String SHADER_COLOR_CUSTOM = "Custom"; - private static final int OUTLINE_ALPHA = 145; - private static final int COLOR_ALPHA = 210; - private static final int HEALTH_ALPHA = 220; - private static final int ABSORB_RGB = 0x3AA7FF; - private static final float OUTLINE_EXPAND = 1.5f; - private static final float OUTLINE_THICKNESS = 1.5f; - private static final float COLOR_THICKNESS = 2.0f; - private static final float GRAD_LIGHTEN = 0.30f; - private static final float GRAD_DARKEN = 0.42f; - private static final float HEALTH_BAR_WIDTH = 5.0f; - private static final float HEALTH_BAR_GAP = 8.0f; - private static final float HEALTH_BAR_INSET = 1.0f; - private static final double AABB_TOP_OFFSET = 0.18; - private static final float CORNER_SEGMENT_FRACTION = 0.27f; - private static final float CHAMFER_FRACTION = 0.16f; - private static final boolean PIXEL_SNAP = true; - private static final double SHADER_MAX_DISTANCE = 128.0; - private static final float BOX_3D_GRADIENT_SPEED = 0.00115f; - private static ProjectionMatrixBuffer shaderEspProjection; - private static GpuSampler shaderEspSampler; - private final Minecraft mc = Minecraft.getInstance(); - private final BooleanValue renderEntities = + static final String MODE_FULL = "Full"; + static final String MODE_CHAMFERED = "Chamfered"; + static final String MODE_CORNERS = "Corners"; + static final String MODE_3D = "3D"; + static final String MODE_SHADER = "Шейдер"; + static final String SHADER_FILL_SOLID = "Solid"; + static final String SHADER_FILL_SMOKE = "Smoke"; + static final String SHADER_COLOR_ENTITY = "Entity"; + static final String SHADER_COLOR_THEME = "Theme"; + static final String SHADER_COLOR_CUSTOM = "Custom"; + static final int OUTLINE_ALPHA = 145; + static final int COLOR_ALPHA = 210; + static final int HEALTH_ALPHA = 220; + static final int ABSORB_RGB = 0x3AA7FF; + static final float OUTLINE_EXPAND = 1.5f; + static final float OUTLINE_THICKNESS = 1.5f; + static final float COLOR_THICKNESS = 2.0f; + static final float GRAD_LIGHTEN = 0.30f; + static final float GRAD_DARKEN = 0.42f; + static final float HEALTH_BAR_WIDTH = 5.0f; + static final float HEALTH_BAR_GAP = 8.0f; + static final float HEALTH_BAR_INSET = 1.0f; + static final double AABB_TOP_OFFSET = 0.18; + static final float CORNER_SEGMENT_FRACTION = 0.27f; + static final float CHAMFER_FRACTION = 0.16f; + static final boolean PIXEL_SNAP = true; + static final double SHADER_MAX_DISTANCE = 128.0; + static final float BOX_3D_GRADIENT_SPEED = 0.00115f; + + final Minecraft mc = Minecraft.getInstance(); + final BooleanValue renderEntities = bool("espRenderEntities", "render_entities", false); - private final RGBColorValue entityColor = + final RGBColorValue entityColor = visibleWhen(colorNoAlpha("espEntityColor", "entity_color", "#78C8FF"), renderEntities::get); - private final ItemIdSetValue searchEntities = + final ItemIdSetValue searchEntities = visibleWhen(itemList("espSearchEntities", "search_entities", TextListSetting.PickerMode.ENTITIES), renderEntities::get); - private final BooleanValue renderSelf = + final BooleanValue renderSelf = bool("espRenderSelf", "render_self", false); - private final ModeValue boxMode = + final BooleanValue onlyVisible = + bool("espOnlyVisible", "only_visible", true); + final BooleanValue skipInvisible = + bool("espSkipInvisible", "skip_invisible", true); + final BooleanValue onlyArmored = + bool("espOnlyArmor", "only_armor", true); + final ModeValue boxMode = modeCommon("espBoxMode", "box_mode", CommonSettingSchemas.ESP_BOX_MODE, MODE_FULL, MODE_FULL, MODE_CORNERS, MODE_3D, MODE_CHAMFERED, MODE_SHADER); - private final SetValue shaderChamsEntities = + final SetValue shaderChamsEntities = visibleWhen(textList("espShaderChamsEntities", "shader_chams_entities", TextListSetting.PickerMode.ENTITIES, Set.of("minecraft:end_crystal")), this::isShaderBox); - private final RGBColorValue shaderChamsEntityColor = + final RGBColorValue shaderChamsEntityColor = visibleWhen(colorNoAlpha("espShaderChamsEntityColor", "shader_chams_entity_color", "#B064FF"), this::isShaderBox); - private final BooleanValue healthBar = + final BooleanValue healthBar = visibleWhen(boolCommon("espHealthBar", "health_bar_left", CommonSettingSchemas.ESP_HEALTH_BAR, true), () -> !is3DBox() && !isShaderBox()); - private final BooleanValue healthBarGradient = + final BooleanValue healthBarGradient = visibleWhen(boolCommon("espHealthBarGradient", "health_bar_gradient", CommonSettingSchemas.ESP_HEALTH_BAR_GRADIENT, true), () -> healthBar.get() && !is3DBox() && !isShaderBox()); - private final NumberValue healthBarDistance = + final NumberValue healthBarDistance = visibleWhen(numCommon("espHealthBarDistance", "health_bar_distance", CommonSettingSchemas.ESP_HEALTH_BAR_DISTANCE, 80, 5, 256), () -> healthBar.get() && !is3DBox() && !isShaderBox()); - private final NumberValue box3dLineWidth = + final NumberValue box3dLineWidth = visibleWhen(numCommon("esp3dLineWidth", "line_width", CommonSettingSchemas.ESP_LINE_WIDTH, 1.5f, 0.5f, 6.0f), this::is3DBox); - private final NumberValue box3dGradientStrength = + final NumberValue box3dGradientStrength = visibleWhen(num("esp3dGradientStrength", "gradient_strength", 1.35f, 0.0f, 2.5f), this::is3DBox); - private final NumberValue box3dFillAlpha = + final NumberValue box3dFillAlpha = visibleWhen(num("esp3dFillAlpha", "fill_alpha", 0.30f, 0.0f, 1.0f), this::is3DBox); - private final NumberValue box3dOutlineAlpha = + final NumberValue box3dOutlineAlpha = visibleWhen(num("esp3dOutlineAlpha", "outline_alpha", 1.0f, 0.0f, 1.0f), this::is3DBox); - private final BooleanValue shaderGlow = + final BooleanValue shaderGlow = visibleWhen(bool("espShaderGlowEnabled", "shader_glow_enabled", true), this::isShaderBox); - private final NumberValue shaderGlowStrength = + final NumberValue shaderGlowStrength = visibleWhen(num("espShaderGlowStrength", "shader_glow_strength", 8.0f, 1.0f, 48.0f), () -> isShaderBox() && shaderGlow.get()); - private final NumberValue shaderGlowAlpha = + final NumberValue shaderGlowAlpha = visibleWhen(num("espShaderGlowAlpha", "shader_glow_alpha", 0.72f, 0.0f, 1.0f), () -> isShaderBox() && shaderGlow.get()); - private final NumberValue shaderGlowIntensity = + final NumberValue shaderGlowIntensity = visibleWhen(num("espShaderGlowIntensity", "shader_glow_intensity", 1.25f, 0.10f, 4.0f), () -> isShaderBox() && shaderGlow.get()); - private final ModeValue shaderGlowColorMode = + final ModeValue shaderGlowColorMode = visibleWhen(mode("espShaderGlowColorMode", "shader_glow_color_mode", SHADER_COLOR_ENTITY, SHADER_COLOR_ENTITY, SHADER_COLOR_THEME, SHADER_COLOR_CUSTOM), () -> isShaderBox() && shaderGlow.get()); - private final RGBColorValue shaderGlowColor = + final RGBColorValue shaderGlowColor = visibleWhen(colorNoAlpha("espShaderGlowColor", "shader_glow_color", "#78C8FF"), () -> isShaderBox() && shaderGlow.get() && isCustomShaderColor(shaderGlowColorMode)); - private final BooleanValue shaderOutline = + final BooleanValue shaderOutline = visibleWhen(bool("espShaderOutlineEnabled", "shader_outline_enabled", true), this::isShaderBox); - private final NumberValue shaderOutlineWidth = + final NumberValue shaderOutlineWidth = visibleWhen(num("espShaderOutlineWidth", "shader_outline_width", 2.0f, 0.5f, 18.0f), () -> isShaderBox() && shaderOutline.get()); - private final NumberValue shaderOutlineAlpha = + final NumberValue shaderOutlineAlpha = visibleWhen(num("espShaderOutlineAlpha", "shader_outline_alpha", 0.92f, 0.0f, 1.0f), () -> isShaderBox() && shaderOutline.get()); - private final NumberValue shaderOutlineIntensity = + final NumberValue shaderOutlineIntensity = visibleWhen(num("espShaderOutlineIntensity", "shader_outline_intensity", 1.15f, 0.10f, 4.0f), () -> isShaderBox() && shaderOutline.get()); - private final ModeValue shaderShadowColorMode = + final ModeValue shaderShadowColorMode = visibleWhen(mode("espShaderShadowColorMode", "shader_shadow_color_mode", SHADER_COLOR_ENTITY, SHADER_COLOR_ENTITY, SHADER_COLOR_THEME, SHADER_COLOR_CUSTOM), () -> isShaderBox() && shaderOutline.get()); - private final RGBColorValue shaderShadowColor = + final RGBColorValue shaderShadowColor = visibleWhen(colorNoAlpha("espShaderShadowColor", "shader_shadow_color", "#78C8FF"), () -> isShaderBox() && shaderOutline.get() && isCustomShaderColor(shaderShadowColorMode)); - private final BooleanValue shaderFill = + final BooleanValue shaderFill = visibleWhen(bool("espShaderFillEnabled", "shader_fill_enabled", true), this::isShaderBox); - private final ModeValue shaderFillStyle = + final ModeValue shaderFillStyle = visibleWhen(mode("espShaderFillStyle", "shader_fill_style", SHADER_FILL_SOLID, SHADER_FILL_SOLID, SHADER_FILL_SMOKE), () -> isShaderBox() && shaderFill.get()); - private final NumberValue shaderSmokeScale = + final NumberValue shaderSmokeScale = visibleWhen(num("espShaderSmokeScale", "shader_smoke_scale", 2.60f, 0.35f, 8.0f), () -> isShaderBox() && shaderFill.get() && isShaderSmokeFill()); - private final NumberValue shaderSmokeSpeed = + final NumberValue shaderSmokeSpeed = visibleWhen(num("espShaderSmokeSpeed", "shader_smoke_speed", 0.55f, 0.0f, 3.0f), () -> isShaderBox() && shaderFill.get() && isShaderSmokeFill()); - private final NumberValue shaderSmokeOctaves = + final NumberValue shaderSmokeOctaves = visibleWhen(num("espShaderSmokeOctaves", "shader_smoke_octaves", 4, 1, 6), () -> isShaderBox() && shaderFill.get() && isShaderSmokeFill()); - private final NumberValue shaderSmokeContrast = + final NumberValue shaderSmokeContrast = visibleWhen(num("espShaderSmokeContrast", "shader_smoke_contrast", 1.20f, 0.35f, 3.0f), () -> isShaderBox() && shaderFill.get() && isShaderSmokeFill()); - private final NumberValue shaderFillAlpha = + final NumberValue shaderFillAlpha = visibleWhen(num("espShaderFillAlpha", "shader_fill_alpha", 0.41f, 0.0f, 1.0f), () -> isShaderBox() && shaderFill.get()); - private final ModeValue shaderFillColorMode = + final ModeValue shaderFillColorMode = visibleWhen(mode("espShaderFillColorMode", "shader_fill_color_mode", SHADER_COLOR_ENTITY, SHADER_COLOR_ENTITY, SHADER_COLOR_THEME, SHADER_COLOR_CUSTOM), () -> isShaderBox() && shaderFill.get()); - private final RGBColorValue shaderFillColor = + final RGBColorValue shaderFillColor = visibleWhen(colorNoAlpha("espShaderFillColor", "shader_fill_color", "#78C8FF"), () -> isShaderBox() && shaderFill.get() && isCustomShaderColor(shaderFillColorMode)); - private final NumberValue shaderDarkMultiplier = + final NumberValue shaderDarkMultiplier = visibleWhen(num("espShaderDarkMultiplier", "shader_dark_multiplier", 0.55f, 0.0f, 1.5f), this::isShaderBox); private final PostProcessPass shaderEspPass = new ShaderEspPass(); - private final SubmitNodeStorage shaderEspCommandQueue = new SubmitNodeStorage(); - private TextureTarget shaderMask; - private TextureTarget shaderBlurBuffer; - private TextureTarget shaderEffectBuffer; - private MsaaFramebuffer shaderMaskMsaa; - private FeatureRenderDispatcher shaderEspRenderDispatcher; - private RenderBuffers shaderEspRenderBuffers; - private int shaderBufferW = -1; - private int shaderBufferH = -1; - private int shaderMaskSamples; + final SubmitNodeStorage shaderEspCommandQueue = new SubmitNodeStorage(); + TextureTarget shaderMask; + TextureTarget shaderBlurBuffer; + TextureTarget shaderEffectBuffer; + MsaaFramebuffer shaderMaskMsaa; + FeatureRenderDispatcher shaderEspRenderDispatcher; + RenderBuffers shaderEspRenderBuffers; + int shaderBufferW = -1; + int shaderBufferH = -1; + int shaderMaskSamples; { PostProcessManager.register(shaderEspPass); } - private static boolean containsEntityId(Set selected, Identifier id) { - String full = id.toString(); - String path = id.getPath(); - for (String raw : selected) { - if (raw == null || raw.isBlank()) { - continue; - } - String normalized = raw.trim().toLowerCase(Locale.ROOT); - if (full.equals(normalized) || path.equals(normalized)) { - return true; - } - if (!normalized.contains(":") && full.equals("minecraft:" + normalized)) { - return true; - } - } - return false; - } - - private static GpuSampler getShaderEspSampler() { - if (shaderEspSampler != null) { - return shaderEspSampler; - } - shaderEspSampler = RenderSystem.getDevice().createSampler( - AddressMode.CLAMP_TO_EDGE, - AddressMode.CLAMP_TO_EDGE, - FilterMode.LINEAR, - FilterMode.LINEAR, - 1, - OptionalDouble.empty() - ); - return shaderEspSampler; - } - - private static void clearFramebuffer(RenderTarget framebuffer) { - if (framebuffer == null || framebuffer.getColorTexture() == null) { - return; - } - RenderSystem.getDevice().createCommandEncoder().clearColorTexture(framebuffer.getColorTexture(), new org.joml.Vector4f(0.0f, 0.0f, 0.0f, 0.0f)); - } - - private static String formatHealth(float health) { - if (Math.abs(health - Math.round(health)) < 0.05f) { - return Math.round(health) + " HP"; - } - return String.format(Locale.ROOT, "%.1f HP", health); - } - - private static void addFilledBox(MeshBuilder mesh, - AABB box, - int c000, int c001, int c010, int c011, - int c100, int c101, int c110, int c111) { - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - quad(mesh, minX, minY, minZ, c000, maxX, minY, minZ, c100, maxX, minY, maxZ, c101, minX, minY, maxZ, c001); - quad(mesh, minX, maxY, minZ, c010, minX, maxY, maxZ, c011, maxX, maxY, maxZ, c111, maxX, maxY, minZ, c110); - quad(mesh, minX, minY, maxZ, c001, maxX, minY, maxZ, c101, maxX, maxY, maxZ, c111, minX, maxY, maxZ, c011); - quad(mesh, minX, minY, minZ, c000, minX, maxY, minZ, c010, maxX, maxY, minZ, c110, maxX, minY, minZ, c100); - quad(mesh, maxX, minY, minZ, c100, maxX, maxY, minZ, c110, maxX, maxY, maxZ, c111, maxX, minY, maxZ, c101); - quad(mesh, minX, minY, minZ, c000, minX, minY, maxZ, c001, minX, maxY, maxZ, c011, minX, maxY, minZ, c010); - } - - private static void addOutlineBox(MeshBuilder mesh, - AABB box, - int c000, int c001, int c010, int c011, - int c100, int c101, int c110, int c111) { - double minX = box.minX; - double minY = box.minY; - double minZ = box.minZ; - double maxX = box.maxX; - double maxY = box.maxY; - double maxZ = box.maxZ; - - line(mesh, minX, minY, minZ, c000, maxX, minY, minZ, c100); - line(mesh, maxX, minY, minZ, c100, maxX, minY, maxZ, c101); - line(mesh, maxX, minY, maxZ, c101, minX, minY, maxZ, c001); - line(mesh, minX, minY, maxZ, c001, minX, minY, minZ, c000); - - line(mesh, minX, maxY, minZ, c010, maxX, maxY, minZ, c110); - line(mesh, maxX, maxY, minZ, c110, maxX, maxY, maxZ, c111); - line(mesh, maxX, maxY, maxZ, c111, minX, maxY, maxZ, c011); - line(mesh, minX, maxY, maxZ, c011, minX, maxY, minZ, c010); - - line(mesh, minX, minY, minZ, c000, minX, maxY, minZ, c010); - line(mesh, maxX, minY, minZ, c100, maxX, maxY, minZ, c110); - line(mesh, maxX, minY, maxZ, c101, maxX, maxY, maxZ, c111); - line(mesh, minX, minY, maxZ, c001, minX, maxY, maxZ, c011); - } - - private static void quad(MeshBuilder mesh, - double x1, double y1, double z1, int c1, - double x2, double y2, double z2, int c2, - double x3, double y3, double z3, int c3, - double x4, double y4, double z4, int c4) { - mesh.ensureQuadCapacity(); - putVertex(mesh, x1, y1, z1, c1); - int i1 = mesh.next(); - putVertex(mesh, x2, y2, z2, c2); - int i2 = mesh.next(); - putVertex(mesh, x3, y3, z3, c3); - int i3 = mesh.next(); - putVertex(mesh, x4, y4, z4, c4); - int i4 = mesh.next(); - mesh.quad(i1, i2, i3, i4); - } - - private static void quad(MeshBuilder mesh, - double x1, double y1, double z1, - double x2, double y2, double z2, - double x3, double y3, double z3, - double x4, double y4, double z4, - int r, int g, int b, int a) { - mesh.ensureQuadCapacity(); - int i1 = mesh.vec3(x1, y1, z1).color(r, g, b, a).next(); - int i2 = mesh.vec3(x2, y2, z2).color(r, g, b, a).next(); - int i3 = mesh.vec3(x3, y3, z3).color(r, g, b, a).next(); - int i4 = mesh.vec3(x4, y4, z4).color(r, g, b, a).next(); - mesh.quad(i1, i2, i3, i4); - } - - private static void line(MeshBuilder mesh, - double x1, double y1, double z1, int c1, - double x2, double y2, double z2, int c2) { - mesh.ensureLineCapacity(); - putVertex(mesh, x1, y1, z1, c1); - int i1 = mesh.next(); - putVertex(mesh, x2, y2, z2, c2); - int i2 = mesh.next(); - mesh.line(i1, i2); - } - - private static void line(MeshBuilder mesh, - double x1, double y1, double z1, - double x2, double y2, double z2, - int r, int g, int b, int a) { - mesh.ensureLineCapacity(); - int i1 = mesh.vec3(x1, y1, z1).color(r, g, b, a).next(); - int i2 = mesh.vec3(x2, y2, z2).color(r, g, b, a).next(); - mesh.line(i1, i2); - } - - private static void putVertex(MeshBuilder mesh, double x, double y, double z, int argb) { - mesh.vec3(x, y, z).color( - (argb >>> 16) & 0xFF, - (argb >>> 8) & 0xFF, - argb & 0xFF, - (argb >>> 24) & 0xFF - ); - } - - private static int boxGradientColor(int baseRgb, AABB box, double x, double y, double z, int alpha, float strength) { - double nx = safeRatio(x - box.minX, box.maxX - box.minX); - double ny = safeRatio(y - box.minY, box.maxY - box.minY); - double nz = safeRatio(z - box.minZ, box.maxZ - box.minZ); - double phase = AnimationUtility.time(BOX_3D_GRADIENT_SPEED) - + (box.minX + box.minY * 0.7 + box.minZ * 1.3) * 0.18; - double waveA = 0.5 + 0.5 * Math.sin(phase + nx * 2.65 + ny * 5.30 - nz * 1.75); - double waveB = 0.5 + 0.5 * Math.sin(phase * 0.72 - nx * 3.10 + ny * 1.35 + nz * 4.40); - float t = clamp01((float) (ny * 0.44 + nz * 0.18 + (1.0 - nx) * 0.16 + waveA * 0.16 + waveB * 0.12)); - - int darkRgb = mixRgb(baseRgb, 0x000000, clamp01(0.18f + 0.36f * strength)); - int lightRgb = mixRgb(baseRgb, 0xFFFFFF, clamp01(0.16f + 0.40f * strength)); - int gradientRgb = mixRgb(darkRgb, lightRgb, t); - int preservedRgb = mixRgb(baseRgb, gradientRgb, clamp01(strength)); - return withAlpha(preservedRgb, alpha); - } - - private static double safeRatio(double value, double length) { - if (length <= 0.0001) return 0.0; - if (value <= 0.0) return 0.0; - if (value >= length) return 1.0; - return value / length; - } - - private static boolean isCustomShaderColor(ModeValue mode) { - return mode != null && SHADER_COLOR_CUSTOM.equalsIgnoreCase(mode.get()); - } - - private static boolean usesShaderOverrideColor(ModeValue mode) { - if (mode == null) return false; - String value = mode.get(); - return SHADER_COLOR_THEME.equalsIgnoreCase(value) || SHADER_COLOR_CUSTOM.equalsIgnoreCase(value); - } - - private static float shaderSmokeTime() { - return (System.currentTimeMillis() % 600_000L) / 1000.0f; - } - - private static int deriveSmokeColor(int rgb, int layer) { - int base = rgb & 0x00FFFFFF; - return switch (layer) { - case 0 -> mixRgb(base, 0xFFFFFF, 0.18f); - case 1 -> base; - default -> mixRgb(base, 0x05070C, 0.48f); - }; - } - - private static int withAlpha(int rgb, int alpha) { - int a = clamp(alpha); - return (a << 24) | (rgb & 0x00FFFFFF); - } - - private static int alpha255(float alpha) { - return clamp(Math.round(clamp01(alpha) * 255.0f)); - } - - private static int mixRgb(int rgbA, int rgbB, float t) { - float clamped = Math.max(0f, Math.min(1f, t)); - int ar = (rgbA >>> 16) & 0xFF; - int ag = (rgbA >>> 8) & 0xFF; - int ab = rgbA & 0xFF; - int br = (rgbB >>> 16) & 0xFF; - int bg = (rgbB >>> 8) & 0xFF; - int bb = rgbB & 0xFF; - - int r = Math.round(ar + (br - ar) * clamped); - int g = Math.round(ag + (bg - ag) * clamped); - int b = Math.round(ab + (bb - ab) * clamped); - return (clamp(r) << 16) | (clamp(g) << 8) | clamp(b); - } - - private static int scaleRgb(int rgb, float multiplier) { - float m = Math.max(0.0f, Math.min(2.0f, multiplier)); - int r = Math.round(((rgb >>> 16) & 0xFF) * m); - int g = Math.round(((rgb >>> 8) & 0xFF) * m); - int b = Math.round((rgb & 0xFF) * m); - return (clamp(r) << 16) | (clamp(g) << 8) | clamp(b); - } - - private static float clamp01(float v) { - if (v < 0f) return 0f; - if (v > 1f) return 1f; - return v; - } - - private static int healthRgb(float ratio) { - float t = clamp01(ratio); - if (t >= 0.5f) { - float k = (t - 0.5f) / 0.5f; - return mixRgb(0xFFFF00, 0x00FF00, k); - } - float k = t / 0.5f; - return mixRgb(0xFF0000, 0xFFFF00, k); - } - - private static int clamp(int v) { - if (v < 0) return 0; - if (v > 255) return 255; - return v; - } - - private static int mixArgb(int a, int b, float t) { - float clamped = clamp01(t); - int aa = (a >>> 24) & 0xFF; - int ar = (a >>> 16) & 0xFF; - int ag = (a >>> 8) & 0xFF; - int ab = a & 0xFF; - int ba = (b >>> 24) & 0xFF; - int br = (b >>> 16) & 0xFF; - int bg = (b >>> 8) & 0xFF; - int bb = b & 0xFF; - - int oa = Math.round(aa + (ba - aa) * clamped); - int or = Math.round(ar + (br - ar) * clamped); - int og = Math.round(ag + (bg - ag) * clamped); - int ob = Math.round(ab + (bb - ab) * clamped); - return (clamp(oa) << 24) | (clamp(or) << 16) | (clamp(og) << 8) | clamp(ob); - } - @Override public HudPhase getHudPhase() { return HudPhase.BEFORE_MISC_OVERLAYS; @@ -506,43 +191,16 @@ public class ESP extends Module { Vec3 camPos = mc.gameRenderer.mainCamera().position(); if (!is3DBox() && !isShaderBox()) { - List playerEntries = collectPlayerEntries(camPos); - playerEntries.sort(Comparator.comparingDouble(RenderEntry::distSq).reversed()); - - for (RenderEntry entry : playerEntries) { - draw2DESP(renderer, entry.entity(), tickDelta, entry.color(), entry.distSq()); - } + List playerEntries = EspEntityCollector.collectPlayerEntries(this, camPos); + Esp2DRenderer.renderPlayerEntries(this, renderer, tickDelta, playerEntries); } - renderSearchEntityOverlay(renderer, textRenderer, tickDelta, camPos); + EspSearchOverlay.render(this, renderer, textRenderer, tickDelta, camPos); } @Override public void onRenderWorldEngine(Renderer3D renderer, Renderer3D depthRenderer, float tickDelta) { - if (!isEnabled() || !is3DBox() || mc.level == null || mc.player == null) return; - - Vec3 camPos = mc.gameRenderer.mainCamera().position(); - List entries = collectPlayerEntries(camPos); - if (entries.isEmpty()) return; - - float previousLineWidth = RenderState.lineWidth; - MeshBuilder lines; - MeshBuilder tris; - try { - RenderState.lineWidth = box3dLineWidth.get(); - lines = renderer.batch(CombatantRenderPipelines.WORLD_COLORED_LINES, Renderer3D.DepthMode.NONE); - tris = renderer.batch(CombatantRenderPipelines.WORLD_COLORED, Renderer3D.DepthMode.NONE); - } finally { - RenderState.lineWidth = previousLineWidth; - } - - entries.sort(Comparator.comparingDouble(RenderEntry::distSq).reversed()); - for (RenderEntry entry : entries) { - Entity entity = entry.entity(); - AABB box = resolveWorldBox(entity, tickDelta, shouldUseHitboxExpansion(entity)); - int color = resolve3DColor(entity, entry.color()); - add3DBox(tris, lines, box, color); - } + Esp3DRenderer.render(this, renderer, tickDelta); } @Override @@ -551,867 +209,12 @@ public class ESP extends Module { shaderMaskMsaa.destroyBuffers(); shaderMaskMsaa = null; } - closeShaderEspRenderDispatcher(); + EspShaderRenderer.closeDispatcher(this); shaderMaskSamples = 0; } - private void closeShaderEspRenderDispatcher() { - if (shaderEspRenderDispatcher != null) { - shaderEspRenderDispatcher.close(); - shaderEspRenderDispatcher = null; - } - if (shaderEspRenderBuffers != null) { - shaderEspRenderBuffers.close(); - shaderEspRenderBuffers = null; - } - } - - private List collectPlayerEntries(Vec3 camPos) { - List entries = new ArrayList<>(); - - for (Player player : mc.level.players()) { - if (!shouldRenderPlayer(player)) continue; - int color = resolvePlayerColor(player); - double distSq = player.distanceToSqr(camPos); - entries.add(new RenderEntry(player, color, distSq)); - } - - return entries; - } - - private List collectSearchEntityEntries(Vec3 camPos) { - List entries = new ArrayList<>(); - if (!renderEntities.get()) return entries; - - int color = entityColor.getArgb(); - for (Entity entity : mc.level.entitiesForRendering()) { - if (!shouldRenderEntity(entity)) continue; - double distSq = entity.distanceToSqr(camPos); - entries.add(new RenderEntry(entity, color, distSq)); - } - - return entries; - } - - private boolean shouldRenderPlayer(Player p) { - if (p == null) return false; - if (p == mc.player) { - if (mc.options.getCameraType().isFirstPerson()) return false; - return renderSelf.get(); - } - return true; - } - - private boolean shouldRenderEntity(Entity e) { - if (e == null) return false; - if (e instanceof Player) return false; - if (e == mc.player) return false; - Identifier id = BuiltInRegistries.ENTITY_TYPE.getKey(e.getType()); - if (id == null) return false; - return searchEntities.get().contains(id.toString()); - } - - private int resolvePlayerColor(Player p) { - return CategoryService.getColor(p); - } - - private int resolve3DColor(Entity entity, int fallbackColor) { - if (entity instanceof Player player) { - return CategoryService.getColor(player); - } - return fallbackColor; - } - - private boolean renderShaderEsp(GpuTextureView src, GpuTextureView dst, float tickDelta) { - if (!isEnabled() || !isShaderBox() || mc.level == null || mc.player == null) { - return false; - } - if (!shaderGlow.get() && !shaderOutline.get() && !shaderFill.get()) { - return false; - } - - Vec3 camPos = mc.gameRenderer.mainCamera().position(); - List entries = collectShaderEntries(camPos); - if (entries.isEmpty()) { - return false; - } - - ensureShaderBuffers(); - if (shaderMask == null || shaderBlurBuffer == null || shaderEffectBuffer == null) { - return false; - } - - if (!renderShaderEntityMask(entries, tickDelta)) { - return false; - } - - PostProcessManager.copy(src, dst); - - int width = mc.getWindow().getWidth(); - int height = mc.getWindow().getHeight(); - return renderShaderColorPass(dst, width, height); - } - - private List collectShaderEntries(Vec3 camPos) { - List entries = new ArrayList<>(); - double maxDistSq = SHADER_MAX_DISTANCE * SHADER_MAX_DISTANCE; - - for (RenderEntry entry : collectPlayerEntries(camPos)) { - if (entry.distSq() > maxDistSq) { - continue; - } - entries.add(entry); - } - - for (RenderEntry entry : collectShaderChamsEntityEntries(camPos, maxDistSq)) { - entries.add(entry); - } - - entries.sort(Comparator.comparingDouble(RenderEntry::distSq).reversed()); - return entries; - } - - private List collectShaderChamsEntityEntries(Vec3 camPos, double maxDistSq) { - List entries = new ArrayList<>(); - Set selected = shaderChamsEntities.get(); - if (selected == null || selected.isEmpty()) { - return entries; - } - - int color = shaderChamsEntityColor.getArgb(); - for (Entity entity : mc.level.entitiesForRendering()) { - if (!shouldRenderShaderChamsEntity(entity, selected)) { - continue; - } - double distSq = entity.distanceToSqr(camPos); - if (distSq > maxDistSq) { - continue; - } - entries.add(new RenderEntry(entity, color, distSq)); - } - return entries; - } - - private boolean shouldRenderShaderChamsEntity(Entity entity, Set selected) { - if (entity == null) return false; - if (entity instanceof Player) return false; - if (entity == mc.player) return false; - - Identifier id = BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()); - if (id == null) return false; - return containsEntityId(selected, id); - } - - private boolean renderShaderColorPass(GpuTextureView dst, int width, int height) { - if (shaderMask.getColorTextureView() == null) { - return false; - } - - float darkMultiplier = shaderDarkMultiplier.get(); - boolean rendered = false; - - if (shaderGlow.get()) { - float glowRadius = Math.max(1.0f, shaderGlowStrength.get()); - blurShaderMask(shaderMask, shaderEffectBuffer, glowRadius, width, height); - drawShaderGradient(shaderEffectBuffer, dst, width, height, - alpha255(shaderGlowAlpha.get()), - darkMultiplier, - shaderGlowColorMode, - shaderGlowColor, - shaderGlowIntensity.get()); - rendered = true; - } - - if (shaderFill.get()) { - if (isShaderSmokeFill()) { - drawShaderSmoke(shaderMask, dst, width, height); - } else { - drawShaderGradient(shaderMask, dst, width, height, - alpha255(shaderFillAlpha.get()), - darkMultiplier, - shaderFillColorMode, - shaderFillColor, - 1.0f); - } - rendered = true; - } - - if (shaderOutline.get()) { - float outlineRadius = Math.max(0.5f, shaderOutlineWidth.get()); - blurShaderMask(shaderMask, shaderEffectBuffer, outlineRadius, width, height); - drawShaderGradient(shaderEffectBuffer, dst, width, height, - alpha255(shaderOutlineAlpha.get()), - darkMultiplier, - shaderShadowColorMode, - shaderShadowColor, - shaderOutlineIntensity.get()); - rendered = true; - } - - return rendered; - } - - private void blurShaderMask(RenderTarget input, RenderTarget output, float radius, int width, int height) { - - clearFramebuffer(shaderBlurBuffer); - ShaderEspBlurUniforms.update(width, height, Math.min(radius, 63.0f), 1.0f, 0.0f); - FullScreenRenderer.begin("LoVisual Fullscreen Pass") - .attachment(shaderBlurBuffer.getColorTextureView()) - .pipeline(CombatantRenderPipelines.SHADER_ESP_SHADOW) - .uniform("ShaderEspBlur", ShaderEspBlurUniforms.get()) - .sampler("u_Texture", input.getColorTextureView(), getShaderEspSampler()) - .sampler("u_Mask", input.getColorTextureView(), getShaderEspSampler()) - .end(); - - clearFramebuffer(output); - ShaderEspBlurUniforms.update(width, height, Math.min(radius, 63.0f), 0.0f, 1.0f); - FullScreenRenderer.begin("LoVisual Fullscreen Pass") - .attachment(output.getColorTextureView()) - .pipeline(CombatantRenderPipelines.SHADER_ESP_SHADOW) - .uniform("ShaderEspBlur", ShaderEspBlurUniforms.get()) - .sampler("u_Texture", shaderBlurBuffer.getColorTextureView(), getShaderEspSampler()) - .sampler("u_Mask", input.getColorTextureView(), getShaderEspSampler()) - .end(); - } - - private void drawShaderGradient(RenderTarget input, GpuTextureView dst, int width, int height, int alpha, - float darkMultiplier, ModeValue colorMode, RGBColorValue customColor, - float intensity) { - int rgb = resolveShaderColor(colorMode, customColor); - boolean overrideColor = usesShaderOverrideColor(colorMode); - int passColor = withAlpha(rgb, alpha); - ShaderEspGradientUniforms.update( - 0.0f, - 0.0f, - width, - height, - passColor, - darkMultiplier, - overrideColor ? 1.0f : 0.0f, - Math.max(0.0f, Math.min(4.0f, intensity)) - ); - FullScreenRenderer.begin("LoVisual Fullscreen Pass") - .attachment(dst) - .pipeline(CombatantRenderPipelines.SHADER_ESP_GRADIENT) - .uniform("ShaderEspGradient", ShaderEspGradientUniforms.get()) - .sampler("u_Texture", input.getColorTextureView(), getShaderEspSampler()) - .end(); - } - - private void drawShaderSmoke(RenderTarget input, GpuTextureView dst, int width, int height) { - int rgb = resolveShaderColor(shaderFillColorMode, shaderFillColor); - boolean overrideColor = usesShaderOverrideColor(shaderFillColorMode); - ShaderEspSmokeUniforms.update( - 0.0f, - 0.0f, - width, - height, - shaderSmokeTime(), - shaderSmokeScale.get(), - shaderSmokeSpeed.get(), - clamp01(shaderFillAlpha.get()), - shaderSmokeOctaves.get(), - shaderSmokeContrast.get(), - overrideColor ? 1.0f : 0.0f, - 1.0f, - deriveSmokeColor(rgb, 0), - deriveSmokeColor(rgb, 1), - deriveSmokeColor(rgb, 2) - ); - FullScreenRenderer.begin("LoVisual Fullscreen Pass") - .attachment(dst) - .pipeline(CombatantRenderPipelines.SHADER_ESP_SMOKE) - .uniform("ShaderEspSmoke", ShaderEspSmokeUniforms.get()) - .sampler("u_Texture", input.getColorTextureView(), getShaderEspSampler()) - .end(); - } - - private void ensureShaderBuffers() { - int width = mc.getWindow().getWidth(); - int height = mc.getWindow().getHeight(); - if (width <= 0 || height <= 0) { - return; - } - - boolean sizeChanged = width != shaderBufferW || height != shaderBufferH; - if (shaderMask == null) { - shaderMask = new TextureTarget("combatant-shader-esp-mask", width, height, true, GpuFormat.RGBA8_UNORM); - shaderBlurBuffer = new TextureTarget("combatant-shader-esp-blur", width, height, false, GpuFormat.RGBA8_UNORM); - shaderEffectBuffer = new TextureTarget("combatant-shader-esp-effect", width, height, false, GpuFormat.RGBA8_UNORM); - shaderBufferW = width; - shaderBufferH = height; - } else if (sizeChanged) { - shaderMask.resize(width, height); - shaderBlurBuffer.resize(width, height); - shaderEffectBuffer.resize(width, height); - shaderBufferW = width; - shaderBufferH = height; - } - - int samples = MsaaWorldTarget.getSamples(); - if (samples > 1) { - if (shaderMaskMsaa == null || shaderMaskSamples != samples) { - if (shaderMaskMsaa != null) { - shaderMaskMsaa.destroyBuffers(); - } - shaderMaskMsaa = new MsaaFramebuffer("combatant-shader-esp-mask-msaa", width, height, true, samples); - shaderMaskSamples = samples; - } else if (sizeChanged) { - shaderMaskMsaa.resize(width, height); - } - } else if (shaderMaskMsaa != null) { - shaderMaskMsaa.destroyBuffers(); - shaderMaskMsaa = null; - shaderMaskSamples = 0; - } - } - - private boolean renderShaderEntityMask(List entries, float tickDelta) { - if (entries.isEmpty() || shaderMask == null) { - return false; - } - - LevelRenderer worldRenderer = mc.levelRenderer; - if (worldRenderer == null) { - return false; - } - - MsaaFramebuffer worldMsaa = MsaaWorldTarget.getMsaaFramebuffer(); - boolean useMsaaMask = worldMsaa != null - && worldMsaa.getSamples() > 1 - && shaderMaskMsaa != null; - RenderTarget target = useMsaaMask ? shaderMaskMsaa : shaderMask; - - var colorTex = target.getColorTexture(); - if (colorTex == null) { - return false; - } - - var encoder = RenderSystem.getDevice().createCommandEncoder(); - encoder.clearColorTexture(colorTex, new org.joml.Vector4f(0.0f, 0.0f, 0.0f, 0.0f)); - - var depthTex = target.getDepthTexture(); - if (depthTex != null) { - encoder.clearDepthTexture(depthTex, 1.0); - } - - GpuTextureView prevColor = RenderSystem.outputColorTextureOverride; - GpuTextureView prevDepth = RenderSystem.outputDepthTextureOverride; - GpuBufferSlice prevProjection = RenderSystem.getProjectionMatrixBuffer(); - ProjectionType prevProjectionType = RenderSystem.getProjectionType(); - Matrix4f prevMeshProjection = MeshRenderer.projection(); - Matrix4f prevWorldProjection = new Matrix4f(RenderState.worldProjection); - boolean prevRendering3D = RenderState.rendering3D; - - RenderSystem.outputColorTextureOverride = target.getColorTextureView(); - RenderSystem.outputDepthTextureOverride = target.getDepthTextureView(); - - if (shaderEspProjection == null) { - shaderEspProjection = new ProjectionMatrixBuffer("combatant-shader-esp-projection"); - } - Matrix4f espProjection = CombatantWorldMatrices.renderProjectionMatrix(); - if (espProjection == null) { - espProjection = new Matrix4f(RenderState.worldProjection); - } - RenderSystem.setProjectionMatrix(shaderEspProjection.getBuffer(espProjection), ProjectionType.PERSPECTIVE); - MeshRenderer.setProjection(espProjection); - RenderState.worldProjection.set(espProjection); - RenderState.rendering3D = true; - - var modelView = RenderSystem.getModelViewStack(); - modelView.pushMatrix(); - modelView.identity(); - Matrix4f capturedPosition = CombatantWorldMatrices.positionMatrix(); - if (capturedPosition != null) { - modelView.mul(capturedPosition); - } else if (mc.gameRenderer != null && mc.gameRenderer.mainCamera() != null) { - modelView.mul(new Matrix4f().rotation(mc.gameRenderer.mainCamera().rotation().conjugate(new Quaternionf()))); - } - - PoseStack matrices = new PoseStack(); - boolean pushed = false; - - try (ShaderEspRenderContext.Scope ignored = ShaderEspRenderContext.enter()) { - LevelRendererAccessor accessor = (LevelRendererAccessor) worldRenderer; - LevelRenderState base = accessor.combatant$getWorldRenderState(); - if (base == null || base.cameraRenderState == null) { - return false; - } - - LevelRenderState temp = new LevelRenderState(); - temp.cameraRenderState = base.cameraRenderState; - temp.shouldShowEntityOutlines = true; - - shaderEspCommandQueue.getSubmitsPerOrder().clear(); - - EntityRenderDispatcher entityRenderManager = mc.getEntityRenderDispatcher(); - for (RenderEntry entry : entries) { - Entity entity = entry.entity(); - EntityCullingCompat.forceVisibleForShaderEsp(entity); - EntityRenderer entityRenderer = - ((EntityRenderManagerAccessor) entityRenderManager).combatant$invokeGetRenderer(entity); - if (entityRenderer == null) { - continue; - } - - EntityRenderState state = ((EntityRendererAccessor) entityRenderer).combatant$invokeCreateRenderState(); - ((EntityRendererAccessor) entityRenderer).combatant$invokeUpdateRenderState(entity, state, tickDelta); - if (state == null) { - continue; - } - - state.outlineColor = 0xFF000000 | (entry.color() & 0x00FFFFFF); - state.shadowRadius = 0.0f; - state.shadowPieces.clear(); - state.nameTag = null; - state.nameTagAttachment = null; - temp.entityRenderStates.add(state); - } - - if (temp.entityRenderStates.isEmpty()) { - return false; - } - - FeatureRenderDispatcher dispatcher = getShaderEspRenderDispatcher(); - if (dispatcher == null) { - return false; - } - - boolean standaloneDispatcher = dispatcher == shaderEspRenderDispatcher && shaderEspRenderBuffers != null; - accessor.combatant$invokeSubmitEntities(matrices, temp, shaderEspCommandQueue); - pushed = true; - try { - try (FeatureRenderDispatcher.PreparedFrame prepared = dispatcher.prepareFrame(shaderEspCommandQueue)) { - if (!prepared.hasAnyOutline()) { - return false; - } - prepared.executeOutline(); - } - } finally { - if (standaloneDispatcher) { - shaderEspRenderBuffers.endFrame(); - } - } - } finally { - modelView.popMatrix(); - MeshRenderer.setProjection(prevMeshProjection); - RenderState.worldProjection.set(prevWorldProjection); - RenderState.rendering3D = prevRendering3D; - if (prevProjection != null && prevProjectionType != null) { - RenderSystem.setProjectionMatrix(prevProjection, prevProjectionType); - } - RenderSystem.outputColorTextureOverride = prevColor; - RenderSystem.outputDepthTextureOverride = prevDepth; - shaderEspCommandQueue.getSubmitsPerOrder().clear(); - } - - return !useMsaaMask || CombatantRenderSystem.rhi().msaa().resolve(shaderMaskMsaa, shaderMask, true, false); - } - - private FeatureRenderDispatcher getShaderEspRenderDispatcher() { - if (IrisCombatantFrameHooks.isRenderingAfterIrisFinalization()) { - return getStandaloneShaderEspRenderDispatcher(); - } - if (mc != null && mc.levelRenderer instanceof LevelRendererAccessor accessor) { - FeatureRenderDispatcher dispatcher = accessor.combatant$getEntityRenderDispatcher(); - if (dispatcher != null) { - return dispatcher; - } - } - return getStandaloneShaderEspRenderDispatcher(); - } - - private FeatureRenderDispatcher getStandaloneShaderEspRenderDispatcher() { - if (shaderEspRenderDispatcher != null) { - return shaderEspRenderDispatcher; - } - if (mc.gameRenderer == null || mc.getModelManager() == null || mc.getAtlasManager() == null || mc.font == null) { - return null; - } - shaderEspRenderBuffers = new RenderBuffers(1); - shaderEspRenderDispatcher = new FeatureRenderDispatcher( - shaderEspRenderBuffers, - mc.getModelManager(), - mc.getAtlasManager(), - mc.font, - mc.gameRenderer.gameRenderState() - ); - return shaderEspRenderDispatcher; - } - - private void renderSearchEntityOverlay(Renderer2D renderer, TextRenderer fallbackTextRenderer, float tickDelta, Vec3 camPos) { - List entries = collectSearchEntityEntries(camPos); - if (entries.isEmpty()) return; - - entries.sort(Comparator.comparingDouble(RenderEntry::distSq).reversed()); - - TextRenderer labelRenderer = ScreenSpaceOverlay2D.labelRenderer(fallbackTextRenderer); - List labels = new ArrayList<>(); - boolean measureStarted = false; - if (!labelRenderer.isBuilding()) { - labelRenderer.begin(ScreenSpaceOverlay2D.TEXT_SCALE, true, false); - measureStarted = true; - } - - for (RenderEntry entry : entries) { - Entity entity = entry.entity(); - AABB box = resolveWorldBox(entity, tickDelta, false); - ScreenSpaceOverlay2D.ScreenRect rect = ScreenSpaceOverlay2D.projectBox(box, tickDelta); - if (rect == null) continue; - - ScreenSpaceOverlay2D.LabelEntry label = createSearchEntityLabel(labelRenderer, entity, entry.color(), rect); - labels.add(new SearchLabelEntry(entry.distSq(), rect, entry.color(), label)); - } - - if (measureStarted) { - labelRenderer.end(); - } - if (labels.isEmpty()) return; - - labels.sort(Comparator.comparingDouble(SearchLabelEntry::distSq).reversed()); - for (SearchLabelEntry entry : labels) { - renderSearchEntityLabelPass(renderer, labelRenderer, entry); - } - } - - private void renderSearchEntityLabelPass(Renderer2D renderer, - TextRenderer labelRenderer, - SearchLabelEntry entry) { - ScreenSpaceOverlay2D.ScreenRect rect = entry.rect(); - ScreenSpaceOverlay2D.LabelEntry label = entry.label(); - MatteHudStyle.drawFrame(renderer, rect.minX(), rect.minY(), rect.width(), rect.height(), entry.color(), 1.0f); - MatteHudStyle.drawLabelPlate(renderer, label.x(), label.y(), label.totalWidth(), label.height(), 1.0f); - - boolean renderStarted = false; - if (!labelRenderer.isBuilding()) { - labelRenderer.begin(ScreenSpaceOverlay2D.TEXT_SCALE); - renderStarted = true; - } - try { - ScreenSpaceOverlay2D.renderLabels(labelRenderer, List.of(label), false); - } finally { - if (renderStarted) { - labelRenderer.end(); - } - } - Renderer2D.flushBatch(Renderer2D.FlushReason.EXPLICIT); - } - - private ScreenSpaceOverlay2D.LabelEntry createSearchEntityLabel(TextRenderer labelRenderer, Entity entity, - int baseColor, - ScreenSpaceOverlay2D.ScreenRect rect) { - String name = entity.getDisplayName() != null ? entity.getDisplayName().getString() : entity.getName().getString(); - if (entity instanceof LivingEntity living) { - PlayerHealthResolver.HealthSnapshot health = PlayerHealthResolver.resolve(living); - float max = health.maxHealth(); - if (max > 0.0f) { - float ratio = clamp01(health.totalHealth() / max); - String hpText = formatHealth(health.totalHealth()); - return ScreenSpaceOverlay2D.createCenteredLabel( - labelRenderer, - name, - hpText, - baseColor, - withAlpha(healthRgb(ratio), 235), - rect - ); - } - } - return ScreenSpaceOverlay2D.createCenteredLabel(labelRenderer, name, baseColor, rect); - } - - private void draw2DESP(Renderer2D renderer, Entity entity, float tickDelta, int baseColor, double distSq) { - AABB box = resolveWorldBox(entity, tickDelta, false); - ScreenBox screen = project(box, tickDelta); - if (screen == null) return; - - drawBoxESP(renderer, screen.minX(), screen.minY(), screen.maxX(), screen.maxY(), baseColor); - if (healthBar.get()) { - double maxDist = healthBarDistance.get(); - if (distSq <= maxDist * maxDist) { - drawHealthBar(renderer, screen.minX(), screen.minY(), screen.maxX(), screen.maxY(), entity); - } - } - } - - private AABB resolveWorldBox(Entity entity, float tickDelta, boolean hitboxExpanded) { - Vec3 pos = entity.getPosition(tickDelta); - AABB box = entity.getBoundingBox().move( - pos.x - entity.getX(), - pos.y - entity.getY(), - pos.z - entity.getZ() - ); - - Hitbox hitbox = Modules.get(Hitbox.class); - if (hitboxExpanded && hitbox != null) { - box = box.inflate(hitbox.getPadding()); - } - - return new AABB(box.minX, box.minY, box.minZ, box.maxX, box.maxY + AABB_TOP_OFFSET, box.maxZ); - } - - private ScreenBox project(AABB box, float tickDelta) { - Vec3[] pts = new Vec3[]{ - new Vec3(box.minX, box.minY, box.minZ), - new Vec3(box.minX, box.minY, box.maxZ), - new Vec3(box.minX, box.maxY, box.minZ), - new Vec3(box.minX, box.maxY, box.maxZ), - new Vec3(box.maxX, box.minY, box.minZ), - new Vec3(box.maxX, box.minY, box.maxZ), - new Vec3(box.maxX, box.maxY, box.minZ), - new Vec3(box.maxX, box.maxY, box.maxZ) - }; - - double minX = Double.POSITIVE_INFINITY; - double minY = Double.POSITIVE_INFINITY; - double maxX = Double.NEGATIVE_INFINITY; - double maxY = Double.NEGATIVE_INFINITY; - - for (Vec3 p : pts) { - Vec3 screen = ScreenProjection.worldToScreen(p, tickDelta); - if (screen == null) continue; - minX = Math.min(minX, screen.x); - minY = Math.min(minY, screen.y); - maxX = Math.max(maxX, screen.x); - maxY = Math.max(maxY, screen.y); - } - - if (minX == Double.POSITIVE_INFINITY) return null; - if (maxX <= minX || maxY <= minY) return null; - - if (PIXEL_SNAP) { - minX = Math.floor(minX); - minY = Math.floor(minY); - maxX = Math.ceil(maxX); - maxY = Math.ceil(maxY); - } - - return new ScreenBox(minX, minY, maxX, maxY); - } - - private void drawBoxESP(Renderer2D renderer, double minX, double minY, double maxX, double maxY, int baseColor) { - int baseRgb = baseColor & 0x00FFFFFF; - int darkRgb = mixRgb(baseRgb, 0x000000, GRAD_DARKEN); - int lightRgb = mixRgb(baseRgb, 0xFFFFFF, GRAD_LIGHTEN); - - Gradient gradient = new Gradient( - withAlpha(lightRgb, COLOR_ALPHA), - withAlpha(baseRgb, COLOR_ALPHA), - withAlpha(lightRgb, COLOR_ALPHA), - withAlpha(darkRgb, COLOR_ALPHA) - ); - int outline = withAlpha(0x000000, OUTLINE_ALPHA); - - drawOutline(renderer, - minX - OUTLINE_EXPAND, minY - OUTLINE_EXPAND, - maxX + OUTLINE_EXPAND, maxY + OUTLINE_EXPAND, - OUTLINE_THICKNESS, SolidColor.of(outline)); - - drawOutline(renderer, minX, minY, maxX, maxY, COLOR_THICKNESS, gradient); - - double innerInset = COLOR_THICKNESS; - drawOutline(renderer, - minX + innerInset, minY + innerInset, - maxX - innerInset, maxY - innerInset, - OUTLINE_THICKNESS, SolidColor.of(outline)); - } - - private void drawHealthBar(Renderer2D renderer, double x1, double y1, double x2, double y2, Entity entity) { - if (!(entity instanceof LivingEntity living)) return; - double height = y2 - y1; - if (height <= 0.0) return; - - PlayerHealthResolver.HealthSnapshot health = PlayerHealthResolver.resolve(living); - float max = health.maxHealth(); - if (max <= 0f) return; - float current = health.totalHealth(); - float ratio = clamp01(current / max); - float absorption = Math.max(0f, health.absorption()); - float absorptionRatio = clamp01(absorption / max); - - double barX = x1 - HEALTH_BAR_GAP - HEALTH_BAR_WIDTH; - double barY = y1; - - renderer.quad(barX, barY, HEALTH_BAR_WIDTH, height, 0xFF000000); - - double inset = Math.min(HEALTH_BAR_INSET, Math.min(HEALTH_BAR_WIDTH * 0.45, height * 0.1)); - double innerX = barX + inset; - double innerY = barY + inset; - double innerW = Math.max(0.0, HEALTH_BAR_WIDTH - inset * 2.0); - double innerH = Math.max(0.0, height - inset * 2.0); - - double fillH = innerH * ratio; - if (fillH <= 0.0) return; - double fillY = innerY + (innerH - fillH); - if (healthBarGradient.get()) { - float topT = clamp01((float) (fillH / Math.max(0.0001, innerH))); - int topRgb = mixRgb(0xFF0000, 0x00FF00, topT); - int bottomRgb = 0xFF0000; - renderer.quad( - innerX, fillY, innerW, fillH, - withAlpha(topRgb, HEALTH_ALPHA), - withAlpha(topRgb, HEALTH_ALPHA), - withAlpha(bottomRgb, HEALTH_ALPHA), - withAlpha(bottomRgb, HEALTH_ALPHA) - ); - } else { - int rgb = healthRgb(ratio); - renderer.quad(innerX, fillY, innerW, fillH, withAlpha(rgb, HEALTH_ALPHA)); - } - - if (absorptionRatio > 0f) { - float totalRatio = clamp01(current / max); - double absorbH = innerH * Math.min(absorptionRatio, totalRatio); - if (absorbH > 0.0) { - double absorbY = innerY + (innerH - absorbH); - renderer.quad(innerX, absorbY, innerW, absorbH, withAlpha(ABSORB_RGB, HEALTH_ALPHA)); - } - } - } - - private void drawOutline(Renderer2D renderer, double x1, double y1, double x2, double y2, - double thickness, ColorResolver colors) { - double width = x2 - x1; - double height = y2 - y1; - if (width <= 0 || height <= 0 || thickness <= 0.0) return; - - if (isCornerBox()) { - drawOutlineCorners(renderer, x1, y1, x2, y2, thickness, colors); - return; - } - - if (isChamferedBox()) { - drawOutlineChamfered(renderer, x1, y1, x2, y2, thickness, colors); - return; - } - - drawGradientQuad(renderer, x1, y1, x2, y1 + thickness, x1, y1, x2, y2, colors); - drawGradientQuad(renderer, x1, y2 - thickness, x2, y2, x1, y1, x2, y2, colors); - drawGradientQuad(renderer, x1, y1, x1 + thickness, y2, x1, y1, x2, y2, colors); - drawGradientQuad(renderer, x2 - thickness, y1, x2, y2, x1, y1, x2, y2, colors); - } - - private void drawOutlineChamfered(Renderer2D renderer, double x1, double y1, double x2, double y2, - double thickness, ColorResolver colors) { - double width = x2 - x1; - double height = y2 - y1; - if (width <= 0.0 || height <= 0.0) return; - - double chamfer = Math.min(width, height) * CHAMFER_FRACTION; - chamfer = Math.max(chamfer, thickness * 3.0); - chamfer = Math.min(chamfer, Math.min(width, height) * 0.32); - if (chamfer <= thickness) { - drawGradientQuad(renderer, x1, y1, x2, y1 + thickness, x1, y1, x2, y2, colors); - drawGradientQuad(renderer, x1, y2 - thickness, x2, y2, x1, y1, x2, y2, colors); - drawGradientQuad(renderer, x1, y1, x1 + thickness, y2, x1, y1, x2, y2, colors); - drawGradientQuad(renderer, x2 - thickness, y1, x2, y2, x1, y1, x2, y2, colors); - return; - } - - renderer.chamferedRectStrokeQuad( - x1, - y1, - width, - height, - chamfer, - chamfer, - chamfer, - chamfer, - thickness, - colors.colorAt(x1, y1, x1, y1, x2, y2), - colors.colorAt(x2, y1, x1, y1, x2, y2), - colors.colorAt(x2, y2, x1, y1, x2, y2), - colors.colorAt(x1, y2, x1, y1, x2, y2) - ); - } - - private void drawOutlineCorners(Renderer2D renderer, double x1, double y1, double x2, double y2, - double thickness, ColorResolver colors) { - double width = x2 - x1; - double height = y2 - y1; - if (width <= 0 || height <= 0) return; - - double seg = Math.min(width, height) * CORNER_SEGMENT_FRACTION; - double minSeg = thickness * 2.0; - double segX = Math.min(width * 0.5, Math.max(seg, minSeg)); - double segY = Math.min(height * 0.5, Math.max(seg, minSeg)); - - drawCornerSegment(renderer, x1, y1, x1 + segX, y1 + thickness, x1, y1, x2, y2, colors); - drawCornerSegment(renderer, x1, y1, x1 + thickness, y1 + segY, x1, y1, x2, y2, colors); - - drawCornerSegment(renderer, x2 - segX, y1, x2, y1 + thickness, x1, y1, x2, y2, colors); - drawCornerSegment(renderer, x2 - thickness, y1, x2, y1 + segY, x1, y1, x2, y2, colors); - - drawCornerSegment(renderer, x1, y2 - thickness, x1 + segX, y2, x1, y1, x2, y2, colors); - drawCornerSegment(renderer, x1, y2 - segY, x1 + thickness, y2, x1, y1, x2, y2, colors); - - drawCornerSegment(renderer, x2 - segX, y2 - thickness, x2, y2, x1, y1, x2, y2, colors); - drawCornerSegment(renderer, x2 - thickness, y2 - segY, x2, y2, x1, y1, x2, y2, colors); - } - - private void drawCornerSegment(Renderer2D renderer, - double sx1, double sy1, double sx2, double sy2, - double boxX1, double boxY1, double boxX2, double boxY2, - ColorResolver colors) { - drawGradientQuad(renderer, sx1, sy1, sx2, sy2, boxX1, boxY1, boxX2, boxY2, colors); - } - - private void drawGradientQuad(Renderer2D renderer, - double sx1, double sy1, double sx2, double sy2, - double boxX1, double boxY1, double boxX2, double boxY2, - ColorResolver colors) { - renderer.quad( - sx1, sy1, sx2 - sx1, sy2 - sy1, - colors.colorAt(sx1, sy1, boxX1, boxY1, boxX2, boxY2), - colors.colorAt(sx2, sy1, boxX1, boxY1, boxX2, boxY2), - colors.colorAt(sx2, sy2, boxX1, boxY1, boxX2, boxY2), - colors.colorAt(sx1, sy2, boxX1, boxY1, boxX2, boxY2) - ); - } - - private void add3DBox(MeshBuilder tris, MeshBuilder lines, AABB box, int argb) { - int rgb = argb & 0x00FFFFFF; - int fillAlpha = alpha255(box3dFillAlpha.get()); - int outlineAlpha = alpha255(box3dOutlineAlpha.get()); - float gradientStrength = Math.max(0.0f, Math.min(2.5f, box3dGradientStrength.get())); - - int c000 = boxGradientColor(rgb, box, box.minX, box.minY, box.minZ, fillAlpha, gradientStrength); - int c001 = boxGradientColor(rgb, box, box.minX, box.minY, box.maxZ, fillAlpha, gradientStrength); - int c010 = boxGradientColor(rgb, box, box.minX, box.maxY, box.minZ, fillAlpha, gradientStrength); - int c011 = boxGradientColor(rgb, box, box.minX, box.maxY, box.maxZ, fillAlpha, gradientStrength); - int c100 = boxGradientColor(rgb, box, box.maxX, box.minY, box.minZ, fillAlpha, gradientStrength); - int c101 = boxGradientColor(rgb, box, box.maxX, box.minY, box.maxZ, fillAlpha, gradientStrength); - int c110 = boxGradientColor(rgb, box, box.maxX, box.maxY, box.minZ, fillAlpha, gradientStrength); - int c111 = boxGradientColor(rgb, box, box.maxX, box.maxY, box.maxZ, fillAlpha, gradientStrength); - - addFilledBox(tris, box, c000, c001, c010, c011, c100, c101, c110, c111); - addOutlineBox(lines, box, - withAlpha(c000, outlineAlpha), - withAlpha(c001, outlineAlpha), - withAlpha(c010, outlineAlpha), - withAlpha(c011, outlineAlpha), - withAlpha(c100, outlineAlpha), - withAlpha(c101, outlineAlpha), - withAlpha(c110, outlineAlpha), - withAlpha(c111, outlineAlpha)); - } - - public boolean shouldRenderHitboxReplacement(Entity entity) { - if (!isEnabled() || !is3DBox()) return false; - if (entity == null) return false; - if (entity instanceof Player player) { - return shouldRenderPlayer(player) && shouldUseHitboxExpansion(entity); - } - return false; - } - - private boolean shouldUseHitboxExpansion(Entity entity) { - Hitbox hitbox = Modules.get(Hitbox.class); - return hitbox != null && hitbox.isReplacementCandidate(entity); - } - public boolean shouldLiftNameTagsSection(Player player) { - return isEnabled() && isNameTagsLiftBoxMode() && shouldRenderPlayer(player); + return isEnabled() && isNameTagsLiftBoxMode() && EspEntityCollector.shouldRenderPlayer(this, player); } private boolean isNameTagsLiftBoxMode() { @@ -1420,84 +223,30 @@ public class ESP extends Module { || MODE_CHAMFERED.equalsIgnoreCase(boxMode.get()); } - private boolean isShaderSmokeFill() { + boolean isShaderSmokeFill() { return SHADER_FILL_SMOKE.equalsIgnoreCase(shaderFillStyle.get()); } - private int resolveShaderColor(ModeValue mode, RGBColorValue customColor) { - if (mode != null) { - String value = mode.get(); - if (SHADER_COLOR_THEME.equalsIgnoreCase(value)) { - return Theme.theme().accent() & 0x00FFFFFF; - } - if (SHADER_COLOR_CUSTOM.equalsIgnoreCase(value) && customColor != null) { - return customColor.getArgb() & 0x00FFFFFF; - } - } - return 0xFFFFFF; + private boolean isCustomShaderColor(ModeValue mode) { + return mode != null && SHADER_COLOR_CUSTOM.equalsIgnoreCase(mode.get()); } - private boolean isCornerBox() { + boolean isCornerBox() { return MODE_CORNERS.equalsIgnoreCase(boxMode.get()); } - private boolean isChamferedBox() { + boolean isChamferedBox() { return MODE_CHAMFERED.equalsIgnoreCase(boxMode.get()); } - private boolean is3DBox() { + boolean is3DBox() { return MODE_3D.equalsIgnoreCase(boxMode.get()); } - private boolean isShaderBox() { + boolean isShaderBox() { return MODE_SHADER.equalsIgnoreCase(boxMode.get()); } - @FunctionalInterface - private interface ColorResolver { - int colorAt(double x, double y, double boxX1, double boxY1, double boxX2, double boxY2); - } - - private record RenderEntry(Entity entity, int color, double distSq) { - } - - private record SearchLabelEntry(double distSq, ScreenSpaceOverlay2D.ScreenRect rect, int color, - ScreenSpaceOverlay2D.LabelEntry label) { - } - - private record ScreenBox(double minX, double minY, double maxX, double maxY) { - } - - private record SolidColor(int color) implements ColorResolver { - static SolidColor of(int color) { - return new SolidColor(color); - } - - @Override - public int colorAt(double x, double y, double boxX1, double boxY1, double boxX2, double boxY2) { - return color; - } - } - - private record Gradient(int topLeft, int topRight, int bottomRight, int bottomLeft) implements ColorResolver { - private static double safeRatio(double value, double length) { - if (length <= 0.0001) return 0.0; - if (value <= 0.0) return 0.0; - if (value >= length) return 1.0; - return value / length; - } - - @Override - public int colorAt(double x, double y, double boxX1, double boxY1, double boxX2, double boxY2) { - double tx = safeRatio(x - boxX1, boxX2 - boxX1); - double ty = safeRatio(y - boxY1, boxY2 - boxY1); - - int top = mixArgb(topLeft, topRight, (float) tx); - int bottom = mixArgb(bottomLeft, bottomRight, (float) tx); - return mixArgb(top, bottom, (float) ty); - } - } - private final class ShaderEspPass implements PostProcessPass { @Override public boolean isActive() { @@ -1514,7 +263,7 @@ public class ESP extends Module { @Override public boolean render(GpuTextureView src, GpuTextureView dst, float tickDelta) { - return ESP.this.renderShaderEsp(src, dst, tickDelta); + return EspShaderRenderer.render(ESP.this, src, dst, tickDelta); } } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Esp2DRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Esp2DRenderer.java new file mode 100644 index 0000000..c167786 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Esp2DRenderer.java @@ -0,0 +1,176 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.helpers.ScreenProjection; +import dev.loki.lovisual.util.player.PlayerHealthResolver; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +import java.util.Comparator; +import java.util.List; + +final class Esp2DRenderer { + + private Esp2DRenderer() { + } + + static void renderPlayerEntries(ESP esp, Renderer2D renderer, float tickDelta, List entries) { + entries.sort(Comparator.comparingDouble(EspModel.RenderEntry::distSq).reversed()); + for (EspModel.RenderEntry entry : entries) { + draw2DESP(esp, renderer, entry.entity(), tickDelta, entry.color(), entry.distSq()); + } + } + + static void draw2DESP(ESP esp, Renderer2D renderer, Entity entity, float tickDelta, int baseColor, double distSq) { + AABB box = resolveWorldBox(entity, tickDelta); + EspModel.ScreenBox screen = project(box, tickDelta); + if (screen == null) return; + + drawBoxESP(esp, renderer, screen.minX(), screen.minY(), screen.maxX(), screen.maxY(), baseColor); + if (esp.healthBar.get()) { + double maxDist = esp.healthBarDistance.get(); + if (distSq <= maxDist * maxDist) { + drawHealthBar(esp, renderer, screen.minX(), screen.minY(), screen.maxX(), screen.maxY(), entity); + } + } + } + + static AABB resolveWorldBox(Entity entity, float tickDelta) { + Vec3 pos = entity.getPosition(tickDelta); + AABB box = entity.getBoundingBox().move( + pos.x - entity.getX(), + pos.y - entity.getY(), + pos.z - entity.getZ() + ); + + return new AABB(box.minX, box.minY, box.minZ, box.maxX, box.maxY + ESP.AABB_TOP_OFFSET, box.maxZ); + } + + static EspModel.ScreenBox project(AABB box, float tickDelta) { + Vec3[] pts = new Vec3[]{ + new Vec3(box.minX, box.minY, box.minZ), + new Vec3(box.minX, box.minY, box.maxZ), + new Vec3(box.minX, box.maxY, box.minZ), + new Vec3(box.minX, box.maxY, box.maxZ), + new Vec3(box.maxX, box.minY, box.minZ), + new Vec3(box.maxX, box.minY, box.maxZ), + new Vec3(box.maxX, box.maxY, box.minZ), + new Vec3(box.maxX, box.maxY, box.maxZ) + }; + + double minX = Double.POSITIVE_INFINITY; + double minY = Double.POSITIVE_INFINITY; + double maxX = Double.NEGATIVE_INFINITY; + double maxY = Double.NEGATIVE_INFINITY; + + for (Vec3 p : pts) { + Vec3 screen = ScreenProjection.worldToScreen(p, tickDelta); + if (screen == null) continue; + minX = Math.min(minX, screen.x); + minY = Math.min(minY, screen.y); + maxX = Math.max(maxX, screen.x); + maxY = Math.max(maxY, screen.y); + } + + if (minX == Double.POSITIVE_INFINITY) return null; + if (maxX <= minX || maxY <= minY) return null; + + if (ESP.PIXEL_SNAP) { + minX = Math.floor(minX); + minY = Math.floor(minY); + maxX = Math.ceil(maxX); + maxY = Math.ceil(maxY); + } + + return new EspModel.ScreenBox(minX, minY, maxX, maxY); + } + + static void drawBoxESP(ESP esp, Renderer2D renderer, double minX, double minY, double maxX, double maxY, int baseColor) { + int baseRgb = baseColor & 0x00FFFFFF; + int darkRgb = EspColorUtil.mixRgb(baseRgb, 0x000000, ESP.GRAD_DARKEN); + int lightRgb = EspColorUtil.mixRgb(baseRgb, 0xFFFFFF, ESP.GRAD_LIGHTEN); + + EspModel.Gradient gradient = new EspModel.Gradient( + EspColorUtil.withAlpha(lightRgb, ESP.COLOR_ALPHA), + EspColorUtil.withAlpha(baseRgb, ESP.COLOR_ALPHA), + EspColorUtil.withAlpha(lightRgb, ESP.COLOR_ALPHA), + EspColorUtil.withAlpha(darkRgb, ESP.COLOR_ALPHA) + ); + int outline = EspColorUtil.withAlpha(0x000000, ESP.OUTLINE_ALPHA); + + EspOutlineRenderer.drawOutline(esp, renderer, + minX - ESP.OUTLINE_EXPAND, minY - ESP.OUTLINE_EXPAND, + maxX + ESP.OUTLINE_EXPAND, maxY + ESP.OUTLINE_EXPAND, + ESP.OUTLINE_THICKNESS, EspModel.SolidColor.of(outline)); + + EspOutlineRenderer.drawOutline(esp, renderer, minX, minY, maxX, maxY, ESP.COLOR_THICKNESS, gradient); + + double innerInset = ESP.COLOR_THICKNESS; + EspOutlineRenderer.drawOutline(esp, renderer, + minX + innerInset, minY + innerInset, + maxX - innerInset, maxY - innerInset, + ESP.OUTLINE_THICKNESS, EspModel.SolidColor.of(outline)); + } + + static void drawHealthBar(ESP esp, Renderer2D renderer, double x1, double y1, double x2, double y2, Entity entity) { + if (!(entity instanceof LivingEntity living)) return; + double height = y2 - y1; + if (height <= 0.0) return; + + PlayerHealthResolver.HealthSnapshot health = PlayerHealthResolver.resolve(living); + float max = health.maxHealth(); + if (max <= 0f) return; + float current = health.totalHealth(); + float ratio = EspColorUtil.clamp01(current / max); + float absorption = Math.max(0f, health.absorption()); + float absorptionRatio = EspColorUtil.clamp01(absorption / max); + + double barX = x1 - ESP.HEALTH_BAR_GAP - ESP.HEALTH_BAR_WIDTH; + double barY = y1; + + renderer.quad(barX, barY, ESP.HEALTH_BAR_WIDTH, height, 0xFF000000); + + double inset = Math.min(ESP.HEALTH_BAR_INSET, Math.min(ESP.HEALTH_BAR_WIDTH * 0.45, height * 0.1)); + double innerX = barX + inset; + double innerY = barY + inset; + double innerW = Math.max(0.0, ESP.HEALTH_BAR_WIDTH - inset * 2.0); + double innerH = Math.max(0.0, height - inset * 2.0); + + double fillH = innerH * ratio; + if (fillH <= 0.0) return; + double fillY = innerY + (innerH - fillH); + if (esp.healthBarGradient.get()) { + float topT = EspColorUtil.clamp01((float) (fillH / Math.max(0.0001, innerH))); + int topRgb = EspColorUtil.mixRgb(0xFF0000, 0x00FF00, topT); + int bottomRgb = 0xFF0000; + renderer.quad( + innerX, fillY, innerW, fillH, + EspColorUtil.withAlpha(topRgb, ESP.HEALTH_ALPHA), + EspColorUtil.withAlpha(topRgb, ESP.HEALTH_ALPHA), + EspColorUtil.withAlpha(bottomRgb, ESP.HEALTH_ALPHA), + EspColorUtil.withAlpha(bottomRgb, ESP.HEALTH_ALPHA) + ); + } else { + int rgb = EspColorUtil.healthRgb(ratio); + renderer.quad(innerX, fillY, innerW, fillH, EspColorUtil.withAlpha(rgb, ESP.HEALTH_ALPHA)); + } + + if (absorptionRatio > 0f) { + float totalRatio = EspColorUtil.clamp01(current / max); + double absorbH = innerH * Math.min(absorptionRatio, totalRatio); + if (absorbH > 0.0) { + double absorbY = innerY + (innerH - absorbH); + renderer.quad(innerX, absorbY, innerW, absorbH, EspColorUtil.withAlpha(ESP.ABSORB_RGB, ESP.HEALTH_ALPHA)); + } + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Esp3DRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Esp3DRenderer.java new file mode 100644 index 0000000..b5aeaed --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Esp3DRenderer.java @@ -0,0 +1,79 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.engine.RenderState; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; +import dev.loki.lovisual.render.engine.renderer.Renderer3D; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +import java.util.Comparator; +import java.util.List; + +final class Esp3DRenderer { + + private Esp3DRenderer() { + } + + static void render(ESP esp, Renderer3D renderer, float tickDelta) { + if (!esp.isEnabled() || !esp.is3DBox() || esp.mc.level == null || esp.mc.player == null) return; + + Vec3 camPos = esp.mc.gameRenderer.mainCamera().position(); + List entries = EspEntityCollector.collectPlayerEntries(esp, camPos); + if (entries.isEmpty()) return; + + float previousLineWidth = RenderState.lineWidth; + MeshBuilder lines; + MeshBuilder tris; + try { + RenderState.lineWidth = esp.box3dLineWidth.get(); + lines = renderer.batch(LoVisualRenderPipelines.WORLD_COLORED_LINES, Renderer3D.DepthMode.NONE); + tris = renderer.batch(LoVisualRenderPipelines.WORLD_COLORED, Renderer3D.DepthMode.NONE); + } finally { + RenderState.lineWidth = previousLineWidth; + } + + entries.sort(Comparator.comparingDouble(EspModel.RenderEntry::distSq).reversed()); + for (EspModel.RenderEntry entry : entries) { + Entity entity = entry.entity(); + AABB box = Esp2DRenderer.resolveWorldBox(entity, tickDelta); + int color = EspEntityCollector.resolve3DColor(entity, entry.color()); + add3DBox(esp, tris, lines, box, color); + } + } + + static void add3DBox(ESP esp, MeshBuilder tris, MeshBuilder lines, AABB box, int argb) { + int rgb = argb & 0x00FFFFFF; + int fillAlpha = EspColorUtil.alpha255(esp.box3dFillAlpha.get()); + int outlineAlpha = EspColorUtil.alpha255(esp.box3dOutlineAlpha.get()); + float gradientStrength = Math.max(0.0f, Math.min(2.5f, esp.box3dGradientStrength.get())); + + int c000 = EspColorUtil.boxGradientColor(rgb, box, box.minX, box.minY, box.minZ, fillAlpha, gradientStrength); + int c001 = EspColorUtil.boxGradientColor(rgb, box, box.minX, box.minY, box.maxZ, fillAlpha, gradientStrength); + int c010 = EspColorUtil.boxGradientColor(rgb, box, box.minX, box.maxY, box.minZ, fillAlpha, gradientStrength); + int c011 = EspColorUtil.boxGradientColor(rgb, box, box.minX, box.maxY, box.maxZ, fillAlpha, gradientStrength); + int c100 = EspColorUtil.boxGradientColor(rgb, box, box.maxX, box.minY, box.minZ, fillAlpha, gradientStrength); + int c101 = EspColorUtil.boxGradientColor(rgb, box, box.maxX, box.minY, box.maxZ, fillAlpha, gradientStrength); + int c110 = EspColorUtil.boxGradientColor(rgb, box, box.maxX, box.maxY, box.minZ, fillAlpha, gradientStrength); + int c111 = EspColorUtil.boxGradientColor(rgb, box, box.maxX, box.maxY, box.maxZ, fillAlpha, gradientStrength); + + EspMeshBuilder.addFilledBox(tris, box, c000, c001, c010, c011, c100, c101, c110, c111); + EspMeshBuilder.addOutlineBox(lines, box, + EspColorUtil.withAlpha(c000, outlineAlpha), + EspColorUtil.withAlpha(c001, outlineAlpha), + EspColorUtil.withAlpha(c010, outlineAlpha), + EspColorUtil.withAlpha(c011, outlineAlpha), + EspColorUtil.withAlpha(c100, outlineAlpha), + EspColorUtil.withAlpha(c101, outlineAlpha), + EspColorUtil.withAlpha(c110, outlineAlpha), + EspColorUtil.withAlpha(c111, outlineAlpha)); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspColorUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspColorUtil.java new file mode 100644 index 0000000..60e2690 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspColorUtil.java @@ -0,0 +1,135 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import net.minecraft.world.phys.AABB; + +import java.util.Locale; + +final class EspColorUtil { + + private EspColorUtil() { + } + + static int boxGradientColor(int baseRgb, AABB box, double x, double y, double z, int alpha, float strength) { + double nx = safeRatio(x - box.minX, box.maxX - box.minX); + double ny = safeRatio(y - box.minY, box.maxY - box.minY); + double nz = safeRatio(z - box.minZ, box.maxZ - box.minZ); + double phase = AnimationUtility.time(ESP.BOX_3D_GRADIENT_SPEED) + + (box.minX + box.minY * 0.7 + box.minZ * 1.3) * 0.18; + double waveA = 0.5 + 0.5 * Math.sin(phase + nx * 2.65 + ny * 5.30 - nz * 1.75); + double waveB = 0.5 + 0.5 * Math.sin(phase * 0.72 - nx * 3.10 + ny * 1.35 + nz * 4.40); + float t = clamp01((float) (ny * 0.44 + nz * 0.18 + (1.0 - nx) * 0.16 + waveA * 0.16 + waveB * 0.12)); + + int darkRgb = mixRgb(baseRgb, 0x000000, clamp01(0.18f + 0.36f * strength)); + int lightRgb = mixRgb(baseRgb, 0xFFFFFF, clamp01(0.16f + 0.40f * strength)); + int gradientRgb = mixRgb(darkRgb, lightRgb, t); + int preservedRgb = mixRgb(baseRgb, gradientRgb, clamp01(strength)); + return withAlpha(preservedRgb, alpha); + } + + static double safeRatio(double value, double length) { + if (length <= 0.0001) return 0.0; + if (value <= 0.0) return 0.0; + if (value >= length) return 1.0; + return value / length; + } + + static String formatHealth(float health) { + if (Math.abs(health - Math.round(health)) < 0.05f) { + return Math.round(health) + " HP"; + } + return String.format(Locale.ROOT, "%.1f HP", health); + } + + static float shaderSmokeTime() { + return (System.currentTimeMillis() % 600_000L) / 1000.0f; + } + + static int deriveSmokeColor(int rgb, int layer) { + int base = rgb & 0x00FFFFFF; + return switch (layer) { + case 0 -> mixRgb(base, 0xFFFFFF, 0.18f); + case 1 -> base; + default -> mixRgb(base, 0x05070C, 0.48f); + }; + } + + static int withAlpha(int rgb, int alpha) { + int a = clamp(alpha); + return (a << 24) | (rgb & 0x00FFFFFF); + } + + static int alpha255(float alpha) { + return clamp(Math.round(clamp01(alpha) * 255.0f)); + } + + static int mixRgb(int rgbA, int rgbB, float t) { + float clamped = Math.max(0f, Math.min(1f, t)); + int ar = (rgbA >>> 16) & 0xFF; + int ag = (rgbA >>> 8) & 0xFF; + int ab = rgbA & 0xFF; + int br = (rgbB >>> 16) & 0xFF; + int bg = (rgbB >>> 8) & 0xFF; + int bb = rgbB & 0xFF; + + int r = Math.round(ar + (br - ar) * clamped); + int g = Math.round(ag + (bg - ag) * clamped); + int b = Math.round(ab + (bb - ab) * clamped); + return (clamp(r) << 16) | (clamp(g) << 8) | clamp(b); + } + + static int scaleRgb(int rgb, float multiplier) { + float m = Math.max(0.0f, Math.min(2.0f, multiplier)); + int r = Math.round(((rgb >>> 16) & 0xFF) * m); + int g = Math.round(((rgb >>> 8) & 0xFF) * m); + int b = Math.round((rgb & 0xFF) * m); + return (clamp(r) << 16) | (clamp(g) << 8) | clamp(b); + } + + static float clamp01(float v) { + if (v < 0f) return 0f; + if (v > 1f) return 1f; + return v; + } + + static int healthRgb(float ratio) { + float t = clamp01(ratio); + if (t >= 0.5f) { + float k = (t - 0.5f) / 0.5f; + return mixRgb(0xFFFF00, 0x00FF00, k); + } + float k = t / 0.5f; + return mixRgb(0xFF0000, 0xFFFF00, k); + } + + static int clamp(int v) { + if (v < 0) return 0; + if (v > 255) return 255; + return v; + } + + static int mixArgb(int a, int b, float t) { + float clamped = clamp01(t); + int aa = (a >>> 24) & 0xFF; + int ar = (a >>> 16) & 0xFF; + int ag = (a >>> 8) & 0xFF; + int ab = a & 0xFF; + int ba = (b >>> 24) & 0xFF; + int br = (b >>> 16) & 0xFF; + int bg = (b >>> 8) & 0xFF; + int bb = b & 0xFF; + + int oa = Math.round(aa + (ba - aa) * clamped); + int or = Math.round(ar + (br - ar) * clamped); + int og = Math.round(ag + (bg - ag) * clamped); + int ob = Math.round(ab + (bb - ab) * clamped); + return (clamp(oa) << 24) | (clamp(or) << 16) | (clamp(og) << 8) | clamp(ob); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspEntityCollector.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspEntityCollector.java new file mode 100644 index 0000000..0fc1e7b --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspEntityCollector.java @@ -0,0 +1,182 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.features.relations.CategoryService; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.Identifier; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +final class EspEntityCollector { + + private EspEntityCollector() { + } + + static boolean containsEntityId(Set selected, Identifier id) { + String full = id.toString(); + String path = id.getPath(); + for (String raw : selected) { + if (raw == null || raw.isBlank()) { + continue; + } + String normalized = raw.trim().toLowerCase(Locale.ROOT); + if (full.equals(normalized) || path.equals(normalized)) { + return true; + } + if (!normalized.contains(":") && full.equals("minecraft:" + normalized)) { + return true; + } + } + return false; + } + + static List collectPlayerEntries(ESP esp, Vec3 camPos) { + List entries = new ArrayList<>(); + + for (Player player : esp.mc.level.players()) { + if (!shouldRenderPlayer(esp, player)) continue; + int color = resolvePlayerColor(player); + double distSq = player.distanceToSqr(camPos); + entries.add(new EspModel.RenderEntry(player, color, distSq)); + } + + return entries; + } + + static List collectSearchEntityEntries(ESP esp, Vec3 camPos) { + List entries = new ArrayList<>(); + if (!esp.renderEntities.get()) return entries; + + int color = esp.entityColor.getArgb(); + for (Entity entity : esp.mc.level.entitiesForRendering()) { + if (!shouldRenderEntity(esp, entity)) continue; + double distSq = entity.distanceToSqr(camPos); + entries.add(new EspModel.RenderEntry(entity, color, distSq)); + } + + return entries; + } + + static List collectShaderEntries(ESP esp, Vec3 camPos) { + List entries = new ArrayList<>(); + double maxDistSq = ESP.SHADER_MAX_DISTANCE * ESP.SHADER_MAX_DISTANCE; + + for (EspModel.RenderEntry entry : collectPlayerEntries(esp, camPos)) { + if (entry.distSq() > maxDistSq) { + continue; + } + entries.add(entry); + } + + for (EspModel.RenderEntry entry : collectShaderChamsEntityEntries(esp, camPos, maxDistSq)) { + entries.add(entry); + } + + entries.sort(java.util.Comparator.comparingDouble(EspModel.RenderEntry::distSq).reversed()); + return entries; + } + + static List collectShaderChamsEntityEntries(ESP esp, Vec3 camPos, double maxDistSq) { + List entries = new ArrayList<>(); + Set selected = esp.shaderChamsEntities.get(); + if (selected == null || selected.isEmpty()) { + return entries; + } + + int color = esp.shaderChamsEntityColor.getArgb(); + for (Entity entity : esp.mc.level.entitiesForRendering()) { + if (!shouldRenderShaderChamsEntity(esp, entity, selected)) { + continue; + } + double distSq = entity.distanceToSqr(camPos); + if (distSq > maxDistSq) { + continue; + } + entries.add(new EspModel.RenderEntry(entity, color, distSq)); + } + return entries; + } + + static boolean shouldRenderPlayer(ESP esp, Player p) { + if (p == null) return false; + if (p == esp.mc.player) { + if (esp.mc.options.getCameraType().isFirstPerson()) return false; + return esp.renderSelf.get(); + } + if (esp.skipInvisible.get() && (p.isInvisible() || p.hasEffect(net.minecraft.world.effect.MobEffects.INVISIBILITY))) { + return false; + } + if (esp.onlyArmored.get() && !hasAnyArmor(p)) { + return false; + } + if (esp.onlyVisible.get() && !hasLineOfSight(esp, p)) { + return false; + } + return true; + } + + static boolean hasAnyArmor(Player p) { + return !p.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.HEAD).isEmpty() + || !p.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.CHEST).isEmpty() + || !p.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.LEGS).isEmpty() + || !p.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.FEET).isEmpty(); + } + + static boolean hasLineOfSight(ESP esp, Player p) { + if (esp.mc.level == null) return false; + Vec3 start = esp.mc.gameRenderer.mainCamera().position(); + Vec3 end = p.getBoundingBox().getCenter(); + HitResult result = esp.mc.level.clip(new ClipContext( + start, + end, + ClipContext.Block.COLLIDER, + ClipContext.Fluid.NONE, + esp.mc.player + )); + return result.getType() == HitResult.Type.MISS; + } + + static boolean shouldRenderEntity(ESP esp, Entity e) { + if (e == null) return false; + if (e instanceof Player) return false; + if (e == esp.mc.player) return false; + Identifier id = BuiltInRegistries.ENTITY_TYPE.getKey(e.getType()); + if (id == null) return false; + return esp.searchEntities.get().contains(id.toString()); + } + + static boolean shouldRenderShaderChamsEntity(ESP esp, Entity entity, Set selected) { + if (entity == null) return false; + if (entity instanceof Player) return false; + if (entity == esp.mc.player) return false; + + Identifier id = BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()); + if (id == null) return false; + return containsEntityId(selected, id); + } + + static int resolvePlayerColor(Player p) { + return CategoryService.getColor(p); + } + + static int resolve3DColor(Entity entity, int fallbackColor) { + if (entity instanceof Player player) { + return CategoryService.getColor(player); + } + return fallbackColor; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspMeshBuilder.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspMeshBuilder.java new file mode 100644 index 0000000..2ff669f --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspMeshBuilder.java @@ -0,0 +1,124 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; +import net.minecraft.world.phys.AABB; + +final class EspMeshBuilder { + + private EspMeshBuilder() { + } + + static void addFilledBox(MeshBuilder mesh, + AABB box, + int c000, int c001, int c010, int c011, + int c100, int c101, int c110, int c111) { + double minX = box.minX; + double minY = box.minY; + double minZ = box.minZ; + double maxX = box.maxX; + double maxY = box.maxY; + double maxZ = box.maxZ; + + quad(mesh, minX, minY, minZ, c000, maxX, minY, minZ, c100, maxX, minY, maxZ, c101, minX, minY, maxZ, c001); + quad(mesh, minX, maxY, minZ, c010, minX, maxY, maxZ, c011, maxX, maxY, maxZ, c111, maxX, maxY, minZ, c110); + quad(mesh, minX, minY, maxZ, c001, maxX, minY, maxZ, c101, maxX, maxY, maxZ, c111, minX, maxY, maxZ, c011); + quad(mesh, minX, minY, minZ, c000, minX, maxY, minZ, c010, maxX, maxY, minZ, c110, maxX, minY, minZ, c100); + quad(mesh, maxX, minY, minZ, c100, maxX, maxY, minZ, c110, maxX, maxY, maxZ, c111, maxX, minY, maxZ, c101); + quad(mesh, minX, minY, minZ, c000, minX, minY, maxZ, c001, minX, maxY, maxZ, c011, minX, maxY, minZ, c010); + } + + static void addOutlineBox(MeshBuilder mesh, + AABB box, + int c000, int c001, int c010, int c011, + int c100, int c101, int c110, int c111) { + double minX = box.minX; + double minY = box.minY; + double minZ = box.minZ; + double maxX = box.maxX; + double maxY = box.maxY; + double maxZ = box.maxZ; + + line(mesh, minX, minY, minZ, c000, maxX, minY, minZ, c100); + line(mesh, maxX, minY, minZ, c100, maxX, minY, maxZ, c101); + line(mesh, maxX, minY, maxZ, c101, minX, minY, maxZ, c001); + line(mesh, minX, minY, maxZ, c001, minX, minY, minZ, c000); + + line(mesh, minX, maxY, minZ, c010, maxX, maxY, minZ, c110); + line(mesh, maxX, maxY, minZ, c110, maxX, maxY, maxZ, c111); + line(mesh, maxX, maxY, maxZ, c111, minX, maxY, maxZ, c011); + line(mesh, minX, maxY, maxZ, c011, minX, maxY, minZ, c010); + + line(mesh, minX, minY, minZ, c000, minX, maxY, minZ, c010); + line(mesh, maxX, minY, minZ, c100, maxX, maxY, minZ, c110); + line(mesh, maxX, minY, maxZ, c101, maxX, maxY, maxZ, c111); + line(mesh, minX, minY, maxZ, c001, minX, maxY, maxZ, c011); + } + + static void quad(MeshBuilder mesh, + double x1, double y1, double z1, int c1, + double x2, double y2, double z2, int c2, + double x3, double y3, double z3, int c3, + double x4, double y4, double z4, int c4) { + mesh.ensureQuadCapacity(); + putVertex(mesh, x1, y1, z1, c1); + int i1 = mesh.next(); + putVertex(mesh, x2, y2, z2, c2); + int i2 = mesh.next(); + putVertex(mesh, x3, y3, z3, c3); + int i3 = mesh.next(); + putVertex(mesh, x4, y4, z4, c4); + int i4 = mesh.next(); + mesh.quad(i1, i2, i3, i4); + } + + static void quad(MeshBuilder mesh, + double x1, double y1, double z1, + double x2, double y2, double z2, + double x3, double y3, double z3, + double x4, double y4, double z4, + int r, int g, int b, int a) { + mesh.ensureQuadCapacity(); + int i1 = mesh.vec3(x1, y1, z1).color(r, g, b, a).next(); + int i2 = mesh.vec3(x2, y2, z2).color(r, g, b, a).next(); + int i3 = mesh.vec3(x3, y3, z3).color(r, g, b, a).next(); + int i4 = mesh.vec3(x4, y4, z4).color(r, g, b, a).next(); + mesh.quad(i1, i2, i3, i4); + } + + static void line(MeshBuilder mesh, + double x1, double y1, double z1, int c1, + double x2, double y2, double z2, int c2) { + mesh.ensureLineCapacity(); + putVertex(mesh, x1, y1, z1, c1); + int i1 = mesh.next(); + putVertex(mesh, x2, y2, z2, c2); + int i2 = mesh.next(); + mesh.line(i1, i2); + } + + static void line(MeshBuilder mesh, + double x1, double y1, double z1, + double x2, double y2, double z2, + int r, int g, int b, int a) { + mesh.ensureLineCapacity(); + int i1 = mesh.vec3(x1, y1, z1).color(r, g, b, a).next(); + int i2 = mesh.vec3(x2, y2, z2).color(r, g, b, a).next(); + mesh.line(i1, i2); + } + + static void putVertex(MeshBuilder mesh, double x, double y, double z, int argb) { + mesh.vec3(x, y, z).color( + (argb >>> 16) & 0xFF, + (argb >>> 8) & 0xFF, + argb & 0xFF, + (argb >>> 24) & 0xFF + ); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspModel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspModel.java new file mode 100644 index 0000000..9bc1a30 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspModel.java @@ -0,0 +1,62 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.helpers.ScreenSpaceOverlay2D; +import net.minecraft.world.entity.Entity; + +final class EspModel { + + private EspModel() { + } + + @FunctionalInterface + interface ColorResolver { + int colorAt(double x, double y, double boxX1, double boxY1, double boxX2, double boxY2); + } + + record RenderEntry(Entity entity, int color, double distSq) { + } + + record SearchLabelEntry(double distSq, ScreenSpaceOverlay2D.ScreenRect rect, int color, + ScreenSpaceOverlay2D.LabelEntry label) { + } + + record ScreenBox(double minX, double minY, double maxX, double maxY) { + } + + record SolidColor(int color) implements ColorResolver { + static SolidColor of(int color) { + return new SolidColor(color); + } + + @Override + public int colorAt(double x, double y, double boxX1, double boxY1, double boxX2, double boxY2) { + return color; + } + } + + record Gradient(int topLeft, int topRight, int bottomRight, int bottomLeft) implements ColorResolver { + private static double safeRatio(double value, double length) { + if (length <= 0.0001) return 0.0; + if (value <= 0.0) return 0.0; + if (value >= length) return 1.0; + return value / length; + } + + @Override + public int colorAt(double x, double y, double boxX1, double boxY1, double boxX2, double boxY2) { + double tx = safeRatio(x - boxX1, boxX2 - boxX1); + double ty = safeRatio(y - boxY1, boxY2 - boxY1); + + int top = EspColorUtil.mixArgb(topLeft, topRight, (float) tx); + int bottom = EspColorUtil.mixArgb(bottomLeft, bottomRight, (float) tx); + return EspColorUtil.mixArgb(top, bottom, (float) ty); + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspOutlineRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspOutlineRenderer.java new file mode 100644 index 0000000..ebdc157 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspOutlineRenderer.java @@ -0,0 +1,116 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.engine.renderer.Renderer2D; + +final class EspOutlineRenderer { + + private EspOutlineRenderer() { + } + + static void drawOutline(ESP esp, Renderer2D renderer, double x1, double y1, double x2, double y2, + double thickness, EspModel.ColorResolver colors) { + double width = x2 - x1; + double height = y2 - y1; + if (width <= 0 || height <= 0 || thickness <= 0.0) return; + + if (esp.isCornerBox()) { + drawOutlineCorners(esp, renderer, x1, y1, x2, y2, thickness, colors); + return; + } + + if (esp.isChamferedBox()) { + drawOutlineChamfered(esp, renderer, x1, y1, x2, y2, thickness, colors); + return; + } + + drawGradientQuad(renderer, x1, y1, x2, y1 + thickness, x1, y1, x2, y2, colors); + drawGradientQuad(renderer, x1, y2 - thickness, x2, y2, x1, y1, x2, y2, colors); + drawGradientQuad(renderer, x1, y1, x1 + thickness, y2, x1, y1, x2, y2, colors); + drawGradientQuad(renderer, x2 - thickness, y1, x2, y2, x1, y1, x2, y2, colors); + } + + private static void drawOutlineChamfered(ESP esp, Renderer2D renderer, double x1, double y1, double x2, double y2, + double thickness, EspModel.ColorResolver colors) { + double width = x2 - x1; + double height = y2 - y1; + if (width <= 0.0 || height <= 0.0) return; + + double chamfer = Math.min(width, height) * ESP.CHAMFER_FRACTION; + chamfer = Math.max(chamfer, thickness * 3.0); + chamfer = Math.min(chamfer, Math.min(width, height) * 0.32); + if (chamfer <= thickness) { + drawGradientQuad(renderer, x1, y1, x2, y1 + thickness, x1, y1, x2, y2, colors); + drawGradientQuad(renderer, x1, y2 - thickness, x2, y2, x1, y1, x2, y2, colors); + drawGradientQuad(renderer, x1, y1, x1 + thickness, y2, x1, y1, x2, y2, colors); + drawGradientQuad(renderer, x2 - thickness, y1, x2, y2, x1, y1, x2, y2, colors); + return; + } + + renderer.chamferedRectStrokeQuad( + x1, + y1, + width, + height, + chamfer, + chamfer, + chamfer, + chamfer, + thickness, + colors.colorAt(x1, y1, x1, y1, x2, y2), + colors.colorAt(x2, y1, x1, y1, x2, y2), + colors.colorAt(x2, y2, x1, y1, x2, y2), + colors.colorAt(x1, y2, x1, y1, x2, y2) + ); + } + + private static void drawOutlineCorners(ESP esp, Renderer2D renderer, double x1, double y1, double x2, double y2, + double thickness, EspModel.ColorResolver colors) { + double width = x2 - x1; + double height = y2 - y1; + if (width <= 0 || height <= 0) return; + + double seg = Math.min(width, height) * ESP.CORNER_SEGMENT_FRACTION; + double minSeg = thickness * 2.0; + double segX = Math.min(width * 0.5, Math.max(seg, minSeg)); + double segY = Math.min(height * 0.5, Math.max(seg, minSeg)); + + drawCornerSegment(renderer, x1, y1, x1 + segX, y1 + thickness, x1, y1, x2, y2, colors); + drawCornerSegment(renderer, x1, y1, x1 + thickness, y1 + segY, x1, y1, x2, y2, colors); + + drawCornerSegment(renderer, x2 - segX, y1, x2, y1 + thickness, x1, y1, x2, y2, colors); + drawCornerSegment(renderer, x2 - thickness, y1, x2, y1 + segY, x1, y1, x2, y2, colors); + + drawCornerSegment(renderer, x1, y2 - thickness, x1 + segX, y2, x1, y1, x2, y2, colors); + drawCornerSegment(renderer, x1, y2 - segY, x1 + thickness, y2, x1, y1, x2, y2, colors); + + drawCornerSegment(renderer, x2 - segX, y2 - thickness, x2, y2, x1, y1, x2, y2, colors); + drawCornerSegment(renderer, x2 - thickness, y2 - segY, x2, y2, x1, y1, x2, y2, colors); + } + + private static void drawCornerSegment(Renderer2D renderer, + double sx1, double sy1, double sx2, double sy2, + double boxX1, double boxY1, double boxX2, double boxY2, + EspModel.ColorResolver colors) { + drawGradientQuad(renderer, sx1, sy1, sx2, sy2, boxX1, boxY1, boxX2, boxY2, colors); + } + + private static void drawGradientQuad(Renderer2D renderer, + double sx1, double sy1, double sx2, double sy2, + double boxX1, double boxY1, double boxX2, double boxY2, + EspModel.ColorResolver colors) { + renderer.quad( + sx1, sy1, sx2 - sx1, sy2 - sy1, + colors.colorAt(sx1, sy1, boxX1, boxY1, boxX2, boxY2), + colors.colorAt(sx2, sy1, boxX1, boxY1, boxX2, boxY2), + colors.colorAt(sx2, sy2, boxX1, boxY1, boxX2, boxY2), + colors.colorAt(sx1, sy2, boxX1, boxY1, boxX2, boxY2) + ); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspSearchOverlay.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspSearchOverlay.java new file mode 100644 index 0000000..e994918 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspSearchOverlay.java @@ -0,0 +1,109 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.MatteHudStyle; +import dev.loki.lovisual.render.helpers.ScreenSpaceOverlay2D; +import dev.loki.lovisual.util.player.PlayerHealthResolver; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +final class EspSearchOverlay { + + private EspSearchOverlay() { + } + + static void render(ESP esp, Renderer2D renderer, TextRenderer fallbackTextRenderer, float tickDelta, Vec3 camPos) { + List entries = EspEntityCollector.collectSearchEntityEntries(esp, camPos); + if (entries.isEmpty()) return; + + entries.sort(Comparator.comparingDouble(EspModel.RenderEntry::distSq).reversed()); + + TextRenderer labelRenderer = ScreenSpaceOverlay2D.labelRenderer(fallbackTextRenderer); + List labels = new ArrayList<>(); + boolean measureStarted = false; + if (!labelRenderer.isBuilding()) { + labelRenderer.begin(ScreenSpaceOverlay2D.TEXT_SCALE, true, false); + measureStarted = true; + } + + for (EspModel.RenderEntry entry : entries) { + Entity entity = entry.entity(); + AABB box = Esp2DRenderer.resolveWorldBox(entity, tickDelta); + ScreenSpaceOverlay2D.ScreenRect rect = ScreenSpaceOverlay2D.projectBox(box, tickDelta); + if (rect == null) continue; + + ScreenSpaceOverlay2D.LabelEntry label = createSearchEntityLabel(labelRenderer, entity, entry.color(), rect); + labels.add(new EspModel.SearchLabelEntry(entry.distSq(), rect, entry.color(), label)); + } + + if (measureStarted) { + labelRenderer.end(); + } + if (labels.isEmpty()) return; + + labels.sort(Comparator.comparingDouble(EspModel.SearchLabelEntry::distSq).reversed()); + for (EspModel.SearchLabelEntry entry : labels) { + renderSearchEntityLabelPass(renderer, labelRenderer, entry); + } + } + + private static void renderSearchEntityLabelPass(Renderer2D renderer, + TextRenderer labelRenderer, + EspModel.SearchLabelEntry entry) { + ScreenSpaceOverlay2D.ScreenRect rect = entry.rect(); + ScreenSpaceOverlay2D.LabelEntry label = entry.label(); + MatteHudStyle.drawFrame(renderer, rect.minX(), rect.minY(), rect.width(), rect.height(), entry.color(), 1.0f); + MatteHudStyle.drawLabelPlate(renderer, label.x(), label.y(), label.totalWidth(), label.height(), 1.0f); + + boolean renderStarted = false; + if (!labelRenderer.isBuilding()) { + labelRenderer.begin(ScreenSpaceOverlay2D.TEXT_SCALE); + renderStarted = true; + } + try { + ScreenSpaceOverlay2D.renderLabels(labelRenderer, List.of(label), false); + } finally { + if (renderStarted) { + labelRenderer.end(); + } + } + Renderer2D.flushBatch(Renderer2D.FlushReason.EXPLICIT); + } + + private static ScreenSpaceOverlay2D.LabelEntry createSearchEntityLabel(TextRenderer labelRenderer, Entity entity, + int baseColor, + ScreenSpaceOverlay2D.ScreenRect rect) { + String name = entity.getDisplayName() != null ? entity.getDisplayName().getString() : entity.getName().getString(); + if (entity instanceof LivingEntity living) { + PlayerHealthResolver.HealthSnapshot health = PlayerHealthResolver.resolve(living); + float max = health.maxHealth(); + if (max > 0.0f) { + float ratio = EspColorUtil.clamp01(health.totalHealth() / max); + String hpText = EspColorUtil.formatHealth(health.totalHealth()); + return ScreenSpaceOverlay2D.createCenteredLabel( + labelRenderer, + name, + hpText, + baseColor, + EspColorUtil.withAlpha(EspColorUtil.healthRgb(ratio), 235), + rect + ); + } + } + return ScreenSpaceOverlay2D.createCenteredLabel(labelRenderer, name, baseColor, rect); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderColor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderColor.java new file mode 100644 index 0000000..81b5232 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderColor.java @@ -0,0 +1,198 @@ +/* + * 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.features.module.modules.visuals; + +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.AddressMode; +import com.mojang.blaze3d.textures.FilterMode; +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTextureView; +import dev.loki.lovisual.config.values.ModeValue; +import dev.loki.lovisual.config.values.RGBColorValue; +import dev.loki.lovisual.features.theme.Theme; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; +import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; +import dev.loki.lovisual.render.engine.uniform.impl.ShaderEspBlurUniforms; +import dev.loki.lovisual.render.engine.uniform.impl.ShaderEspGradientUniforms; +import dev.loki.lovisual.render.engine.uniform.impl.ShaderEspSmokeUniforms; + +import java.util.OptionalDouble; + +final class EspShaderColor { + + private static GpuSampler shaderEspSampler; + + private EspShaderColor() { + } + + static boolean renderColorPass(ESP esp, GpuTextureView dst, int width, int height) { + if (esp.shaderMask.getColorTextureView() == null) { + return false; + } + + float darkMultiplier = esp.shaderDarkMultiplier.get(); + boolean rendered = false; + + if (esp.shaderGlow.get()) { + float glowRadius = Math.max(1.0f, esp.shaderGlowStrength.get()); + blurShaderMask(esp, esp.shaderMask, esp.shaderEffectBuffer, glowRadius, width, height); + drawShaderGradient(esp, esp.shaderEffectBuffer, dst, width, height, + EspColorUtil.alpha255(esp.shaderGlowAlpha.get()), + darkMultiplier, + esp.shaderGlowColorMode, + esp.shaderGlowColor, + esp.shaderGlowIntensity.get()); + rendered = true; + } + + if (esp.shaderFill.get()) { + if (esp.isShaderSmokeFill()) { + drawShaderSmoke(esp, esp.shaderMask, dst, width, height); + } else { + drawShaderGradient(esp, esp.shaderMask, dst, width, height, + EspColorUtil.alpha255(esp.shaderFillAlpha.get()), + darkMultiplier, + esp.shaderFillColorMode, + esp.shaderFillColor, + 1.0f); + } + rendered = true; + } + + if (esp.shaderOutline.get()) { + float outlineRadius = Math.max(0.5f, esp.shaderOutlineWidth.get()); + blurShaderMask(esp, esp.shaderMask, esp.shaderEffectBuffer, outlineRadius, width, height); + drawShaderGradient(esp, esp.shaderEffectBuffer, dst, width, height, + EspColorUtil.alpha255(esp.shaderOutlineAlpha.get()), + darkMultiplier, + esp.shaderShadowColorMode, + esp.shaderShadowColor, + esp.shaderOutlineIntensity.get()); + rendered = true; + } + + return rendered; + } + + private static void blurShaderMask(ESP esp, RenderTarget input, RenderTarget output, float radius, int width, int height) { + + clearFramebuffer(esp.shaderBlurBuffer); + ShaderEspBlurUniforms.update(width, height, Math.min(radius, 63.0f), 1.0f, 0.0f); + FullScreenRenderer.begin("LoVisual Fullscreen Pass") + .attachment(esp.shaderBlurBuffer.getColorTextureView()) + .pipeline(LoVisualRenderPipelines.SHADER_ESP_SHADOW) + .uniform("ShaderEspBlur", ShaderEspBlurUniforms.get()) + .sampler("u_Texture", input.getColorTextureView(), getShaderEspSampler()) + .sampler("u_Mask", input.getColorTextureView(), getShaderEspSampler()) + .end(); + + clearFramebuffer(output); + ShaderEspBlurUniforms.update(width, height, Math.min(radius, 63.0f), 0.0f, 1.0f); + FullScreenRenderer.begin("LoVisual Fullscreen Pass") + .attachment(output.getColorTextureView()) + .pipeline(LoVisualRenderPipelines.SHADER_ESP_SHADOW) + .uniform("ShaderEspBlur", ShaderEspBlurUniforms.get()) + .sampler("u_Texture", esp.shaderBlurBuffer.getColorTextureView(), getShaderEspSampler()) + .sampler("u_Mask", input.getColorTextureView(), getShaderEspSampler()) + .end(); + } + + private static void drawShaderGradient(ESP esp, RenderTarget input, GpuTextureView dst, int width, int height, int alpha, + float darkMultiplier, ModeValue colorMode, RGBColorValue customColor, + float intensity) { + int rgb = resolveShaderColor(colorMode, customColor); + boolean overrideColor = usesShaderOverrideColor(colorMode); + int passColor = EspColorUtil.withAlpha(rgb, alpha); + ShaderEspGradientUniforms.update( + 0.0f, + 0.0f, + width, + height, + passColor, + darkMultiplier, + overrideColor ? 1.0f : 0.0f, + Math.max(0.0f, Math.min(4.0f, intensity)) + ); + FullScreenRenderer.begin("LoVisual Fullscreen Pass") + .attachment(dst) + .pipeline(LoVisualRenderPipelines.SHADER_ESP_GRADIENT) + .uniform("ShaderEspGradient", ShaderEspGradientUniforms.get()) + .sampler("u_Texture", input.getColorTextureView(), getShaderEspSampler()) + .end(); + } + + private static void drawShaderSmoke(ESP esp, RenderTarget input, GpuTextureView dst, int width, int height) { + int rgb = resolveShaderColor(esp.shaderFillColorMode, esp.shaderFillColor); + boolean overrideColor = usesShaderOverrideColor(esp.shaderFillColorMode); + ShaderEspSmokeUniforms.update( + 0.0f, + 0.0f, + width, + height, + EspColorUtil.shaderSmokeTime(), + esp.shaderSmokeScale.get(), + esp.shaderSmokeSpeed.get(), + EspColorUtil.clamp01(esp.shaderFillAlpha.get()), + esp.shaderSmokeOctaves.get(), + esp.shaderSmokeContrast.get(), + overrideColor ? 1.0f : 0.0f, + 1.0f, + EspColorUtil.deriveSmokeColor(rgb, 0), + EspColorUtil.deriveSmokeColor(rgb, 1), + EspColorUtil.deriveSmokeColor(rgb, 2) + ); + FullScreenRenderer.begin("LoVisual Fullscreen Pass") + .attachment(dst) + .pipeline(LoVisualRenderPipelines.SHADER_ESP_SMOKE) + .uniform("ShaderEspSmoke", ShaderEspSmokeUniforms.get()) + .sampler("u_Texture", input.getColorTextureView(), getShaderEspSampler()) + .end(); + } + + private static GpuSampler getShaderEspSampler() { + if (shaderEspSampler != null) { + return shaderEspSampler; + } + shaderEspSampler = RenderSystem.getDevice().createSampler( + AddressMode.CLAMP_TO_EDGE, + AddressMode.CLAMP_TO_EDGE, + FilterMode.LINEAR, + FilterMode.LINEAR, + 1, + OptionalDouble.empty() + ); + return shaderEspSampler; + } + + private static void clearFramebuffer(RenderTarget framebuffer) { + if (framebuffer == null || framebuffer.getColorTexture() == null) { + return; + } + RenderSystem.getDevice().createCommandEncoder().clearColorTexture(framebuffer.getColorTexture(), new org.joml.Vector4f(0.0f, 0.0f, 0.0f, 0.0f)); + } + + private static int resolveShaderColor(ModeValue mode, RGBColorValue customColor) { + if (mode != null) { + String value = mode.get(); + if (ESP.SHADER_COLOR_THEME.equalsIgnoreCase(value)) { + return Theme.theme().accent() & 0x00FFFFFF; + } + if (ESP.SHADER_COLOR_CUSTOM.equalsIgnoreCase(value) && customColor != null) { + return customColor.getArgb() & 0x00FFFFFF; + } + } + return 0xFFFFFF; + } + + private static boolean usesShaderOverrideColor(ModeValue mode) { + if (mode == null) return false; + String value = mode.get(); + return ESP.SHADER_COLOR_THEME.equalsIgnoreCase(value) || ESP.SHADER_COLOR_CUSTOM.equalsIgnoreCase(value); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderMask.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderMask.java new file mode 100644 index 0000000..a8852ac --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderMask.java @@ -0,0 +1,187 @@ +/* + * 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.features.module.modules.visuals; + +import com.mojang.blaze3d.ProjectionType; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.GpuTextureView; +import com.mojang.blaze3d.vertex.PoseStack; +import dev.loki.lovisual.mixins.accessors.EntityRenderManagerAccessor; +import dev.loki.lovisual.mixins.accessors.EntityRendererAccessor; +import dev.loki.lovisual.mixins.accessors.LevelRendererAccessor; +import dev.loki.lovisual.render.ShaderEspRenderContext; +import dev.loki.lovisual.render.compat.EntityCullingCompat; +import dev.loki.lovisual.render.engine.RenderState; +import dev.loki.lovisual.render.engine.core.LoVisualWorldMatrices; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; +import dev.loki.lovisual.render.engine.msaa.MsaaFramebuffer; +import dev.loki.lovisual.render.engine.msaa.MsaaWorldTarget; +import dev.loki.lovisual.render.engine.renderer.MeshRenderer; +import net.minecraft.client.renderer.feature.FeatureRenderDispatcher; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.ProjectionMatrixBuffer; +import net.minecraft.client.renderer.SubmitNodeStorage; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.state.EntityRenderState; +import net.minecraft.client.renderer.state.level.LevelRenderState; +import net.minecraft.world.entity.Entity; +import org.joml.Matrix4f; +import org.joml.Quaternionf; + +import java.util.List; + +final class EspShaderMask { + + private static ProjectionMatrixBuffer shaderEspProjection; + + private EspShaderMask() { + } + + static boolean renderEntityMask(ESP esp, List entries, float tickDelta) { + if (entries.isEmpty() || esp.shaderMask == null) { + return false; + } + + LevelRenderer worldRenderer = esp.mc.levelRenderer; + if (worldRenderer == null) { + return false; + } + + MsaaFramebuffer worldMsaa = MsaaWorldTarget.getMsaaFramebuffer(); + boolean useMsaaMask = worldMsaa != null + && worldMsaa.getSamples() > 1 + && esp.shaderMaskMsaa != null; + RenderTarget target = useMsaaMask ? esp.shaderMaskMsaa : esp.shaderMask; + + var colorTex = target.getColorTexture(); + if (colorTex == null) { + return false; + } + + var encoder = RenderSystem.getDevice().createCommandEncoder(); + encoder.clearColorTexture(colorTex, new org.joml.Vector4f(0.0f, 0.0f, 0.0f, 0.0f)); + + var depthTex = target.getDepthTexture(); + if (depthTex != null) { + encoder.clearDepthTexture(depthTex, 1.0); + } + + GpuTextureView prevColor = RenderSystem.outputColorTextureOverride; + GpuTextureView prevDepth = RenderSystem.outputDepthTextureOverride; + GpuBufferSlice prevProjection = RenderSystem.getProjectionMatrixBuffer(); + ProjectionType prevProjectionType = RenderSystem.getProjectionType(); + Matrix4f prevMeshProjection = MeshRenderer.projection(); + Matrix4f prevWorldProjection = new Matrix4f(RenderState.worldProjection); + boolean prevRendering3D = RenderState.rendering3D; + + RenderSystem.outputColorTextureOverride = target.getColorTextureView(); + RenderSystem.outputDepthTextureOverride = target.getDepthTextureView(); + + if (shaderEspProjection == null) { + shaderEspProjection = new ProjectionMatrixBuffer("lovisual-shader-esp-projection"); + } + Matrix4f espProjection = LoVisualWorldMatrices.renderProjectionMatrix(); + if (espProjection == null) { + espProjection = new Matrix4f(RenderState.worldProjection); + } + RenderSystem.setProjectionMatrix(shaderEspProjection.getBuffer(espProjection), ProjectionType.PERSPECTIVE); + MeshRenderer.setProjection(espProjection); + RenderState.worldProjection.set(espProjection); + RenderState.rendering3D = true; + + var modelView = RenderSystem.getModelViewStack(); + modelView.pushMatrix(); + modelView.identity(); + Matrix4f capturedPosition = LoVisualWorldMatrices.positionMatrix(); + if (capturedPosition != null) { + modelView.mul(capturedPosition); + } else if (esp.mc.gameRenderer != null && esp.mc.gameRenderer.mainCamera() != null) { + modelView.mul(new Matrix4f().rotation(esp.mc.gameRenderer.mainCamera().rotation().conjugate(new Quaternionf()))); + } + + PoseStack matrices = new PoseStack(); + + try (ShaderEspRenderContext.Scope ignored = ShaderEspRenderContext.enter()) { + LevelRendererAccessor accessor = (LevelRendererAccessor) worldRenderer; + LevelRenderState base = accessor.lovisual$getWorldRenderState(); + if (base == null || base.cameraRenderState == null) { + return false; + } + + LevelRenderState temp = new LevelRenderState(); + temp.cameraRenderState = base.cameraRenderState; + temp.shouldShowEntityOutlines = true; + + esp.shaderEspCommandQueue.getSubmitsPerOrder().clear(); + + EntityRenderDispatcher entityRenderManager = esp.mc.getEntityRenderDispatcher(); + for (EspModel.RenderEntry entry : entries) { + Entity entity = entry.entity(); + EntityCullingCompat.forceVisibleForShaderEsp(entity); + EntityRenderer entityRenderer = + ((EntityRenderManagerAccessor) entityRenderManager).lovisual$invokeGetRenderer(entity); + if (entityRenderer == null) { + continue; + } + + EntityRenderState state = ((EntityRendererAccessor) entityRenderer).lovisual$invokeCreateRenderState(); + ((EntityRendererAccessor) entityRenderer).lovisual$invokeUpdateRenderState(entity, state, tickDelta); + if (state == null) { + continue; + } + + state.outlineColor = 0xFF000000 | (entry.color() & 0x00FFFFFF); + state.shadowRadius = 0.0f; + state.shadowPieces.clear(); + state.nameTag = null; + state.nameTagAttachment = null; + temp.entityRenderStates.add(state); + } + + if (temp.entityRenderStates.isEmpty()) { + return false; + } + + FeatureRenderDispatcher dispatcher = EspShaderRenderer.getShaderEspRenderDispatcher(esp); + if (dispatcher == null) { + return false; + } + + boolean standaloneDispatcher = dispatcher == esp.shaderEspRenderDispatcher && esp.shaderEspRenderBuffers != null; + accessor.lovisual$invokeSubmitEntities(matrices, temp, esp.shaderEspCommandQueue); + try { + try (FeatureRenderDispatcher.PreparedFrame prepared = dispatcher.prepareFrame(esp.shaderEspCommandQueue)) { + if (!prepared.hasAnyOutline()) { + return false; + } + prepared.executeOutline(); + } + } finally { + if (standaloneDispatcher) { + esp.shaderEspRenderBuffers.endFrame(); + } + } + } finally { + modelView.popMatrix(); + MeshRenderer.setProjection(prevMeshProjection); + RenderState.worldProjection.set(prevWorldProjection); + RenderState.rendering3D = prevRendering3D; + if (prevProjection != null && prevProjectionType != null) { + RenderSystem.setProjectionMatrix(prevProjection, prevProjectionType); + } + RenderSystem.outputColorTextureOverride = prevColor; + RenderSystem.outputDepthTextureOverride = prevDepth; + esp.shaderEspCommandQueue.getSubmitsPerOrder().clear(); + } + + return !useMsaaMask || LoVisualRenderSystem.rhi().msaa().resolve(esp.shaderMaskMsaa, esp.shaderMask, true, false); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderRenderer.java new file mode 100644 index 0000000..c6fdb16 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/EspShaderRenderer.java @@ -0,0 +1,139 @@ +/* + * 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.features.module.modules.visuals; + +import com.mojang.blaze3d.GpuFormat; +import com.mojang.blaze3d.pipeline.TextureTarget; +import com.mojang.blaze3d.textures.GpuTextureView; +import dev.loki.lovisual.render.engine.msaa.MsaaFramebuffer; +import dev.loki.lovisual.render.engine.msaa.MsaaWorldTarget; +import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; +import dev.loki.lovisual.render.iris.IrisLoVisualFrameHooks; +import net.minecraft.client.renderer.RenderBuffers; +import net.minecraft.client.renderer.feature.FeatureRenderDispatcher; +import net.minecraft.world.phys.Vec3; + +import java.util.List; + +final class EspShaderRenderer { + + private EspShaderRenderer() { + } + + static boolean render(ESP esp, GpuTextureView src, GpuTextureView dst, float tickDelta) { + if (!esp.isEnabled() || !esp.isShaderBox() || esp.mc.level == null || esp.mc.player == null) { + return false; + } + if (!esp.shaderGlow.get() && !esp.shaderOutline.get() && !esp.shaderFill.get()) { + return false; + } + + Vec3 camPos = esp.mc.gameRenderer.mainCamera().position(); + List entries = EspEntityCollector.collectShaderEntries(esp, camPos); + if (entries.isEmpty()) { + return false; + } + + ensureShaderBuffers(esp); + if (esp.shaderMask == null || esp.shaderBlurBuffer == null || esp.shaderEffectBuffer == null) { + return false; + } + + if (!EspShaderMask.renderEntityMask(esp, entries, tickDelta)) { + return false; + } + + PostProcessManager.copy(src, dst); + + int width = esp.mc.getWindow().getWidth(); + int height = esp.mc.getWindow().getHeight(); + return EspShaderColor.renderColorPass(esp, dst, width, height); + } + + static void ensureShaderBuffers(ESP esp) { + int width = esp.mc.getWindow().getWidth(); + int height = esp.mc.getWindow().getHeight(); + if (width <= 0 || height <= 0) { + return; + } + + boolean sizeChanged = width != esp.shaderBufferW || height != esp.shaderBufferH; + if (esp.shaderMask == null) { + esp.shaderMask = new TextureTarget("lovisual-shader-esp-mask", width, height, true, GpuFormat.RGBA8_UNORM); + esp.shaderBlurBuffer = new TextureTarget("lovisual-shader-esp-blur", width, height, false, GpuFormat.RGBA8_UNORM); + esp.shaderEffectBuffer = new TextureTarget("lovisual-shader-esp-effect", width, height, false, GpuFormat.RGBA8_UNORM); + esp.shaderBufferW = width; + esp.shaderBufferH = height; + } else if (sizeChanged) { + esp.shaderMask.resize(width, height); + esp.shaderBlurBuffer.resize(width, height); + esp.shaderEffectBuffer.resize(width, height); + esp.shaderBufferW = width; + esp.shaderBufferH = height; + } + + int samples = MsaaWorldTarget.getSamples(); + if (samples > 1) { + if (esp.shaderMaskMsaa == null || esp.shaderMaskSamples != samples) { + if (esp.shaderMaskMsaa != null) { + esp.shaderMaskMsaa.destroyBuffers(); + } + esp.shaderMaskMsaa = new MsaaFramebuffer("lovisual-shader-esp-mask-msaa", width, height, true, samples); + esp.shaderMaskSamples = samples; + } else if (sizeChanged) { + esp.shaderMaskMsaa.resize(width, height); + } + } else if (esp.shaderMaskMsaa != null) { + esp.shaderMaskMsaa.destroyBuffers(); + esp.shaderMaskMsaa = null; + esp.shaderMaskSamples = 0; + } + } + + static FeatureRenderDispatcher getShaderEspRenderDispatcher(ESP esp) { + if (IrisLoVisualFrameHooks.isRenderingAfterIrisFinalization()) { + return getStandaloneShaderEspRenderDispatcher(esp); + } + if (esp.mc != null && esp.mc.levelRenderer instanceof dev.loki.lovisual.mixins.accessors.LevelRendererAccessor accessor) { + FeatureRenderDispatcher dispatcher = accessor.lovisual$getEntityRenderDispatcher(); + if (dispatcher != null) { + return dispatcher; + } + } + return getStandaloneShaderEspRenderDispatcher(esp); + } + + static FeatureRenderDispatcher getStandaloneShaderEspRenderDispatcher(ESP esp) { + if (esp.shaderEspRenderDispatcher != null) { + return esp.shaderEspRenderDispatcher; + } + if (esp.mc.gameRenderer == null || esp.mc.getModelManager() == null || esp.mc.getAtlasManager() == null || esp.mc.font == null) { + return null; + } + esp.shaderEspRenderBuffers = new RenderBuffers(1); + esp.shaderEspRenderDispatcher = new FeatureRenderDispatcher( + esp.shaderEspRenderBuffers, + esp.mc.getModelManager(), + esp.mc.getAtlasManager(), + esp.mc.font, + esp.mc.gameRenderer.gameRenderState() + ); + return esp.shaderEspRenderDispatcher; + } + + static void closeDispatcher(ESP esp) { + if (esp.shaderEspRenderDispatcher != null) { + esp.shaderEspRenderDispatcher.close(); + esp.shaderEspRenderDispatcher = null; + } + if (esp.shaderEspRenderBuffers != null) { + esp.shaderEspRenderBuffers.close(); + esp.shaderEspRenderBuffers = null; + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/FovControl.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/FovControl.java index b28eaab..748653f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/FovControl.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/FovControl.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Freecam.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Freecam.java index 3ea5fb6..4eae6aa 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Freecam.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Freecam.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/FullBright.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/FullBright.java index d8676bd..75223b4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/FullBright.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/FullBright.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/HitEffect.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/HitEffect.java index bcbaabc..f2c40cb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/HitEffect.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/HitEffect.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -35,7 +35,7 @@ import dev.loki.lovisual.render.engine.RenderState; import dev.loki.lovisual.render.engine.TextureStorage; import dev.loki.lovisual.render.engine.animation.AnimatedRenderColors; import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import dev.loki.lovisual.render.helpers.Particle3D; @@ -285,8 +285,8 @@ public class HitEffect extends Module { addWave(basePos); } else { ILocalPlayer access = (ILocalPlayer) mc.player; - float yaw = access.combatant$getLastYaw(); - float pitch = access.combatant$getLastPitch(); + float yaw = access.lovisual$getLastYaw(); + float pitch = access.lovisual$getLastPitch(); double distance = mc.player.distanceTo(target) + 1.0; Vec3 point = getRtxPoint(target, yaw, pitch, distance); @@ -295,7 +295,7 @@ public class HitEffect extends Module { bubbles.add(new HitBubble(point, -yaw, pitch, new Timer())); if (starsEnabled.get() && mc.player instanceof IPlayerAttackCooldown cooldownAccess) { - float cooldown = cooldownAccess.combatant$getAttackCooldownProgress(0.0f); + float cooldown = cooldownAccess.lovisual$getAttackCooldownProgress(0.0f); if (cooldown >= CHARGED_THRESHOLD) { boolean crit = isCritical(mc.player, cooldown); spawnStars(point, crit); @@ -342,8 +342,8 @@ public class HitEffect extends Module { private void renderBubbleEffect(Renderer3D renderer, float tickDelta) { boolean useDepth = depthTest.get(); RenderPipeline pipeline = useDepth - ? CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE; + ? LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE; Renderer3D.DepthMode depthMode = useDepth ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.MAIN; if (!bubbles.isEmpty()) { @@ -485,8 +485,8 @@ public class HitEffect extends Module { private void renderHitParticles(Renderer3D renderer, float tickDelta) { boolean useDepth = depthTest.get(); RenderPipeline pipeline = useDepth - ? CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE; + ? LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE; Renderer3D.DepthMode depthMode = useDepth ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.MAIN; Quaternionf camRot = RenderState.cameraRotation; @@ -707,8 +707,8 @@ public class HitEffect extends Module { try { boolean useDepth = depthTest.get(); RenderPipeline pipeline = useDepth - ? CombatantRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_COLORED_LINES; + ? LoVisualRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_COLORED_LINES; Renderer3D.DepthMode depthMode = useDepth ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.MAIN; MeshBuilder mesh = renderer.batch(pipeline, depthMode); if (mesh == null) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/HoleESP.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/HoleESP.java index 892113e..2359e98 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/HoleESP.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/HoleESP.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,7 +15,7 @@ import dev.loki.lovisual.features.module.ModuleCategory; import dev.loki.lovisual.features.module.ModuleInfo; import dev.loki.lovisual.features.module.WorldPhase; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import dev.loki.lovisual.util.block.BlockSearchUtil; @@ -393,7 +393,7 @@ public final class HoleESP extends Module { } private static void addVerticalFadeBox(Renderer3D renderer, AABB box, int bottomArgb, int topArgb) { - MeshBuilder mesh = renderer.batch(CombatantRenderPipelines.WORLD_COLORED, Renderer3D.DepthMode.MAIN); + MeshBuilder mesh = renderer.batch(LoVisualRenderPipelines.WORLD_COLORED, Renderer3D.DepthMode.MAIN); if (mesh == null) { return; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/JumpCircles.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/JumpCircles.java index f687479..3c71983 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/JumpCircles.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/JumpCircles.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,7 +25,7 @@ import dev.loki.lovisual.render.engine.TextureStorage; import dev.loki.lovisual.render.engine.animation.AnimatedRenderColors; import dev.loki.lovisual.render.engine.color.RenderColor; import dev.loki.lovisual.render.engine.math.ColorMath; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import dev.loki.lovisual.util.time.Timer; @@ -122,8 +122,8 @@ public class JumpCircles extends Module { boolean useDepth = depthTest.get(); RenderPipeline pipeline = useDepth - ? CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE; + ? LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE; Renderer3D.DepthMode depthMode = useDepth ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.MAIN; MeshBuilder mesh = renderer.batchTextured(pipeline, resolveTexture(), depthMode); if (mesh == null) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/KillEffect.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/KillEffect.java index 1a43a87..df5c69d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/KillEffect.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/KillEffect.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -29,7 +29,7 @@ import dev.loki.lovisual.render.engine.RenderState; import dev.loki.lovisual.render.engine.TextureStorage; import dev.loki.lovisual.render.engine.color.ColorUtils; import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import dev.loki.lovisual.util.time.Timer; @@ -247,7 +247,7 @@ public class KillEffect extends Module { if (embers.isEmpty()) return; MeshBuilder mesh = renderer.batchTextured( - CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE, + LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE, TextureStorage.FIRE_FLY, Renderer3D.DepthMode.MAIN ); @@ -279,7 +279,7 @@ public class KillEffect extends Module { if (flashes.isEmpty()) return; MeshBuilder mesh = renderer.batchTextured( - CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE, + LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE, TextureStorage.DEFAULT_CIRCLE, Renderer3D.DepthMode.MAIN ); @@ -305,7 +305,7 @@ public class KillEffect extends Module { if (lightningStrikes.isEmpty()) return; MeshBuilder mesh = renderer.batchTextured( - CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE, + LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE, TextureStorage.FIRE_FLY, Renderer3D.DepthMode.MAIN ); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/MotionBlur.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/MotionBlur.java index 052fc00..a32efd3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/MotionBlur.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/MotionBlur.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -18,7 +18,7 @@ import dev.loki.lovisual.features.module.Module; import dev.loki.lovisual.features.module.ModuleCategory; import dev.loki.lovisual.features.module.ModuleInfo; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.*; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; import dev.loki.lovisual.render.engine.uniform.impl.MotionBlurUniforms; @@ -157,9 +157,9 @@ public final class MotionBlur extends Module implements PostProcessPass { try { FullScreenRenderer.ensureInit(); - FullScreenRenderer.begin("Combatant Temporal Camera MotionBlur") + FullScreenRenderer.begin("LoVisual Temporal Camera MotionBlur") .attachment(dst) - .pipeline(CombatantRenderPipelines.MOTION_BLUR) + .pipeline(LoVisualRenderPipelines.MOTION_BLUR) .uniform("MotionBlur", MotionBlurUniforms.get()) .sampler("u_Texture", src, PostProcessManager.getSampler()) .sampler("u_PreviousColor", previousColor, PostProcessManager.getSampler()) @@ -168,7 +168,7 @@ public final class MotionBlur extends Module implements PostProcessPass { return true; } catch (Throwable t) { resources.invalidate(); - DebugLog.error("[Combatant] MotionBlur render failed", t); + DebugLog.error("[LoVisual] MotionBlur render failed", t); return false; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagCache.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagCache.java new file mode 100644 index 0000000..f191c0d --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagCache.java @@ -0,0 +1,143 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.util.player.effect.StatusEffectView; +import dev.loki.lovisual.util.pvp.opponents.TotemPopSnapshot; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +import java.util.List; +import java.util.UUID; + +final class NameTagCache { + + private static final int EFFECT_CACHE_TICKS = 4; + private static final int ENCHANT_CACHE_TICKS = 2; + private static final float TOTEM_BADGE_ANIM_SPEED = 10.0f; + + private NameTagCache() { + } + + static ItemStack[] getCachedEquipmentSlots(NameTags self, Player player) { + UUID id = player.getUUID(); + ItemStack[] slots = self.slotCache.computeIfAbsent(id, key -> new ItemStack[6]); + slots[0] = player.getMainHandItem(); + slots[1] = player.getItemBySlot(EquipmentSlot.FEET); + slots[2] = player.getItemBySlot(EquipmentSlot.LEGS); + slots[3] = player.getItemBySlot(EquipmentSlot.CHEST); + slots[4] = player.getItemBySlot(EquipmentSlot.HEAD); + slots[5] = player.getOffhandItem(); + return slots; + } + + static List resolveEffects(NameTags self, Player player) { + UUID id = player.getUUID(); + NameTagModel.EffectCache cache = self.effectCache.computeIfAbsent(id, key -> new NameTagModel.EffectCache()); + int tick = player.tickCount; + if (tick - cache.lastTick >= EFFECT_CACHE_TICKS || cache.effects.isEmpty()) { + cache.effects = StatusEffectView.collectHudEffects(player); + cache.lastTick = tick; + } + return cache.effects; + } + + static NameTagModel.EnchantCache resolveEnchantCache(NameTags self, Player player, ItemStack[] slots) { + UUID id = player.getUUID(); + NameTagModel.EnchantCache cache = self.enchantCache.computeIfAbsent(id, key -> new NameTagModel.EnchantCache()); + int tick = player.tickCount; + int signature = equipmentSignature(slots); + if (signature != cache.signature + || tick - cache.lastTick >= ENCHANT_CACHE_TICKS + || cache.lines.isEmpty()) { + List> lines = NameTagEnchantFormatter.buildEnchantLines(self, slots); + cache.lines = lines; + cache.maxLines = NameTagEnchantFormatter.maxEnchantLines(lines); + cache.lastTick = tick; + cache.signature = signature; + } + return cache; + } + + static float updateTotemPopAnimation(NameTags self, Player player, TotemPopSnapshot snapshot, float dt) { + if (player == null) return 0.0f; + UUID id = player.getUUID(); + boolean visible = snapshot != null && snapshot.visible(); + if (visible) { + self.totemPopLastCounts.put(id, snapshot.count()); + } + + float current = self.totemPopAnimations.getOrDefault(id, 0.0f); + float target = visible ? 1.0f : 0.0f; + float next = AnimationUtility.approach(current, target, dt, TOTEM_BADGE_ANIM_SPEED); + next = AnimationUtility.snap(next, target, 0.001f); + + if (next <= 0.001f && !visible) { + self.totemPopAnimations.remove(id); + self.totemPopLastCounts.remove(id); + return 0.0f; + } + + self.totemPopAnimations.put(id, next); + return next; + } + + static int resolveTotemPopCount(NameTags self, Player player, TotemPopSnapshot snapshot, float animation) { + if (player == null) return 0; + if (snapshot != null && snapshot.visible()) { + return snapshot.count(); + } + if (animation > 0.001f) { + return Math.max(0, self.totemPopLastCounts.getOrDefault(player.getUUID(), 0)); + } + return 0; + } + + static void pruneCaches(NameTags self) { + if (self.seenIds.isEmpty()) { + self.slotCache.clear(); + self.effectCache.clear(); + self.enchantCache.clear(); + self.totemPopAnimations.clear(); + self.totemPopLastCounts.clear(); + return; + } + self.slotCache.keySet().removeIf(id -> !self.seenIds.contains(id)); + self.effectCache.keySet().removeIf(id -> !self.seenIds.contains(id)); + self.enchantCache.keySet().removeIf(id -> !self.seenIds.contains(id)); + self.totemPopAnimations.keySet().removeIf(id -> !self.seenIds.contains(id)); + self.totemPopLastCounts.keySet().removeIf(id -> !self.seenIds.contains(id)); + } + + static void clearCaches(NameTags self) { + self.enchantCache.clear(); + } + + private static int equipmentSignature(ItemStack[] slots) { + if (slots == null || slots.length == 0) return 1; + int hash = 1; + for (ItemStack stack : slots) { + hash = 31 * hash + itemSignature(stack); + } + return hash; + } + + private static int itemSignature(ItemStack stack) { + if (stack == null || stack.isEmpty()) return 0; + int hash = 17; + hash = 31 * hash + Item.getId(stack.getItem()); + hash = 31 * hash + stack.getCount(); + hash = 31 * hash + stack.getDamageValue(); + hash = 31 * hash + stack.getComponents().hashCode(); + return hash; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEffectsRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEffectsRenderer.java new file mode 100644 index 0000000..4665d66 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEffectsRenderer.java @@ -0,0 +1,142 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.EffectIconRenderer; +import dev.loki.lovisual.util.player.effect.StatusEffectTracker; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.world.effect.MobEffectInstance; + +import java.util.List; + +final class NameTagEffectsRenderer { + + private static final int ICON_SIZE = 24; + private static final int EFFECT_LINE_HEIGHT = 26; + private static final int EFFECT_LEVEL_COLOR = 0xFFBFC6D1; + private static final int EFFECT_ROW_GAP = 10; + private static final int EFFECT_ROW_ICON_GAP = 8; + private static final int EFFECT_ROW_LEVEL_GAP = 3; + private static final int EFFECT_ROW_TIME_GAP = 2; + private static final float EFFECT_ROW_SCALE = 1.15f; + private static final float SMALL_TEXT_SCALE = 0.82f; + private static final int EFFECT_LEVEL_STACK_COLOR = 0xFFFF4444; + private static final int EFFECT_TIME_COLOR = 0xFFCCCCCC; + + private NameTagEffectsRenderer() { + } + + static int scaleRow(int value) { + return Math.round(value * EFFECT_ROW_SCALE); + } + + static int computeEnchantLift(NameTags self, TextRenderer textRenderer, int maxLines) { + if (!self.toggles.get("Show armor row")) return 0; + if (maxLines <= 0) return 6; + int lineHeight = (int) Math.round(textRenderer.getHeight(true) * SMALL_TEXT_SCALE) + 1; + return 6 + maxLines * lineHeight; + } + + static void drawRowIcons(GuiGraphicsExtractor ctx, List effects, int centerX, int itemsY, int lift) { + if (effects.isEmpty()) return; + int count = effects.size(); + int iconSize = scaleRow(ICON_SIZE); + int gap = scaleRow(EFFECT_ROW_ICON_GAP); + int rowGap = scaleRow(EFFECT_ROW_GAP); + int rowW = count * iconSize + Math.max(0, count - 1) * gap; + int startX = centerX - rowW / 2; + int y = itemsY - iconSize - rowGap - lift; + + for (int i = 0; i < effects.size(); i++) { + int x = startX + i * (iconSize + gap); + EffectIconRenderer.draw(ctx, effects.get(i), x, y, iconSize); + } + } + + static void drawRowIconOverlays(NameTags self, TextRenderer baseRenderer, TextRenderer levelRenderer, + TextRenderer timeRenderer, List effects, int entityId, + int centerX, int itemsY, int lift) { + if (effects.isEmpty()) return; + + TextRenderer levelTr = levelRenderer == null ? baseRenderer : levelRenderer; + TextRenderer timeTr = timeRenderer == null ? baseRenderer : timeRenderer; + + float rowTextScale = SMALL_TEXT_SCALE * EFFECT_ROW_SCALE; + boolean startedLevel = NameTagRenderer.beginTextRenderer(levelTr, rowTextScale); + boolean startedTime = timeTr != levelTr && NameTagRenderer.beginTextRenderer(timeTr, rowTextScale); + + int levelHeight = (int) levelTr.getHeight(true); + int timeHeight = (int) timeTr.getHeight(true); + int levelGap = scaleRow(EFFECT_ROW_LEVEL_GAP); + int timeGap = scaleRow(EFFECT_ROW_TIME_GAP); + + int count = effects.size(); + int iconSize = scaleRow(ICON_SIZE); + int gap = scaleRow(EFFECT_ROW_ICON_GAP); + int rowGap = scaleRow(EFFECT_ROW_GAP); + int rowW = count * iconSize + Math.max(0, count - 1) * gap; + int startX = centerX - rowW / 2; + int iconY = itemsY - iconSize - rowGap - lift; + + for (int i = 0; i < effects.size(); i++) { + MobEffectInstance inst = effects.get(i); + int level = inst.getAmplifier() + 1; + String dur = formatDuration(entityId, inst); + + int iconX = startX + i * (iconSize + gap); + + if (!dur.isEmpty()) { + int timeW = (int) timeTr.getWidth(dur, true); + int timeX = iconX + (iconSize - timeW) / 2; + int timeY = (level > 1) + ? (iconY - levelHeight - levelGap - timeHeight - timeGap) + : (iconY - timeHeight - levelGap); + timeTr.render(dur, timeX, timeY, new RenderColor(EFFECT_TIME_COLOR), true); + } + + if (level > 1) { + String lvl = roman(level); + int levelW = (int) levelTr.getWidth(lvl, true); + int levelX = iconX + (iconSize - levelW) / 2; + int levelY = iconY - levelHeight - levelGap; + levelTr.render(lvl, levelX, levelY, new RenderColor(EFFECT_LEVEL_STACK_COLOR), true); + } + } + + NameTagRenderer.endTextRenderer(levelTr, startedLevel); + NameTagRenderer.endTextRenderer(timeTr, startedTime); + } + + static String formatDuration(int entityId, MobEffectInstance inst) { + if (StatusEffectTracker.shouldHideDuration(entityId, inst.getEffect())) return ""; + int ticks = inst.getDuration(); + if (ticks < 0 || ticks >= 32767) return ""; + int totalSeconds = Math.max(0, ticks / 20); + int minutes = totalSeconds / 60; + int seconds = totalSeconds % 60; + if (seconds < 10) return minutes + ":0" + seconds; + return minutes + ":" + seconds; + } + + private static String roman(int n) { + if (n <= 0) return String.valueOf(n); + int value = n; + StringBuilder sb = new StringBuilder(); + int[] vals = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; + String[] syms = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; + for (int i = 0; i < vals.length; i++) { + while (value >= vals[i]) { + value -= vals[i]; + sb.append(syms[i]); + } + } + return sb.toString(); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEnchantFormatter.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEnchantFormatter.java new file mode 100644 index 0000000..60b97b4 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEnchantFormatter.java @@ -0,0 +1,105 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.util.item.EnchantMeta; +import dev.loki.lovisual.util.item.EnchantRegistry; +import dev.loki.lovisual.util.item.EnchantUtil; +import dev.loki.lovisual.util.item.IllegalItemUtil; +import dev.loki.lovisual.util.item.TopEnchantUtil; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.minecraft.core.Holder; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.ItemEnchantments; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +final class NameTagEnchantFormatter { + + private NameTagEnchantFormatter() { + } + + static List formatEnchantments(NameTags self, ItemStack stack) { + List parts = new ArrayList<>(); + + ItemEnchantments enchComp = EnchantmentHelper.getEnchantmentsForCrafting(stack); + for (Object2IntMap.Entry> entry : enchComp.entrySet()) { + Holder ref = entry.getKey(); + int level = entry.getIntValue(); + if (level <= 0) continue; + + ResourceKey key = ref.unwrapKey().orElse(null); + if (key == null) continue; + + EnchantMeta meta = EnchantRegistry.REGISTRY.get(key); + if (meta == null) continue; + + Enchantment value = ref.value(); + boolean singleLevel = value.getMaxLevel() == 1; + boolean overMax = EnchantUtil.isInvalidLevel(ref, level); + if (!isEnchantEnabled(self, meta.category(), meta.key()) + && !(self.illegalEnchantsAlways.get() && overMax)) { + continue; + } + + String text = singleLevel && level == 1 + ? meta.shortName() + : meta.shortName() + level; + + int color = overMax + ? IllegalItemUtil.illegalColor() + : (level == value.getMaxLevel() ? TopEnchantUtil.topColor() : 0xFFFFFFFF); + + parts.add(new NameTagModel.EnchantLine(text, color)); + } + + return parts; + } + + static boolean isEnchantEnabled(NameTags self, String category, String path) { + Map map = switch (category) { + case "armor" -> self.enchantArmor.get(); + case "melee" -> self.enchantMelee.get(); + case "tools" -> self.enchantTools.get(); + case "bow" -> self.enchantBow.get(); + case "fishing" -> self.enchantFishing.get(); + case "trident" -> self.enchantTrident.get(); + case "crossbow" -> self.enchantCrossbow.get(); + case "mace" -> self.enchantMace.get(); + default -> self.enchantOther.get(); + }; + return map.getOrDefault(path, false); + } + + static List> buildEnchantLines(NameTags self, ItemStack[] slots) { + List> result = new ArrayList<>(slots.length); + for (ItemStack stack : slots) { + if (stack.isEmpty()) { + result.add(List.of()); + continue; + } + List lines = formatEnchantments(self, stack); + result.add(lines.isEmpty() ? List.of() : lines); + } + return result; + } + + static int maxEnchantLines(List> lines) { + int max = 0; + for (List entry : lines) { + int size = entry.size(); + if (size > max) max = size; + } + return max; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEquipmentRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEquipmentRenderer.java new file mode 100644 index 0000000..1206bd6 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagEquipmentRenderer.java @@ -0,0 +1,123 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.pvp.CooldownRegistry; +import dev.loki.lovisual.util.pvp.ItemCooldownSnapshot; +import dev.loki.lovisual.util.pvp.opponents.OpponentCooldownManager; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +final class NameTagEquipmentRenderer { + + private static final int ICON_SIZE = 24; + private static final int ICON_GAP = 5; + private static final float EQUIP_ICON_SCALE = 1.10f; + private static final float ENCHANT_TEXT_SHADOW_OFFSET = 0.7f; + + private NameTagEquipmentRenderer() { + } + + static int equipIconSize() { + return Math.round(ICON_SIZE * EQUIP_ICON_SCALE); + } + + static int equipIconGap() { + return Math.round(ICON_GAP * EQUIP_ICON_SCALE); + } + + static void drawRow(NameTags self, GuiGraphicsExtractor ctx, Player player, ItemStack[] slots, int centerX, int y) { + int iconSize = equipIconSize(); + int gap = equipIconGap(); + int rowWidth = slots.length * (iconSize + gap) - gap; + int startX = centerX - rowWidth / 2; + int seed = 0; + + for (int i = 0; i < slots.length; i++) { + ItemStack stack = slots[i]; + int x = startX + i * (iconSize + gap); + if (stack.isEmpty()) continue; + + float scale = iconSize / 16f; + int overlayFlags = Renderer2D.ITEM_OVERLAY_COUNT; + if (self.toggles.get("Item durability bar")) { + overlayFlags |= Renderer2D.ITEM_OVERLAY_DURABILITY; + } + Renderer2D.COLOR.item(stack, x, y, scale, seed++, overlayFlags, null, + self.durabilityStartPercent.get(), 70); + drawOpponentItemCooldown(self, player, stack, x, y, scale); + } + } + + static void drawOpponentItemCooldown(NameTags self, Player player, ItemStack stack, float x, float y, float scale) { + if (!NameTagOpponentRenderer.shouldRenderOpponentStuff(self, player)) return; + if (stack == null || stack.isEmpty()) return; + + Item item = stack.getItem(); + if (!CooldownRegistry.isTracked(item)) return; + + ItemCooldownSnapshot snapshot = OpponentCooldownManager.snapshot(player.getUUID(), item); + if (!snapshot.visible()) return; + float progress = snapshot.cooling() ? snapshot.cooldownProgress() : snapshot.usesProgress(); + if (progress <= 0f) return; + + int top = Mth.floor(16.0F * (1.0F - progress)); + int bottom = top + Mth.ceil(16.0F * progress); + Renderer2D.COLOR.quad( + x, + y + top * scale, + 16.0f * scale, + (bottom - top) * scale, + snapshot.cooling() ? 0x80FFA500 : 0x706D9DFF + ); + } + + static void drawRowText(TextRenderer textRenderer, ItemStack[] slots, + List> enchantLines, int centerX, int y) { + int iconSize = equipIconSize(); + int gap = equipIconGap(); + int rowWidth = slots.length * (iconSize + gap) - gap; + int startX = centerX - rowWidth / 2; + + for (int i = 0; i < slots.length; i++) { + ItemStack stack = slots[i]; + int x = startX + i * (iconSize + gap); + if (stack.isEmpty()) continue; + + List ench = enchantLines.get(i); + if (!ench.isEmpty()) { + int lineHeight = (int) textRenderer.getHeight(true) + 1; + int startY = y - 14; + for (int idx = 0; idx < ench.size(); idx++) { + NameTagModel.EnchantLine line = ench.get(idx); + int lineY = startY - idx * lineHeight; + int textX = x + iconSize / 2 - (int) textRenderer.getWidth(line.text(), true) / 2; + renderEquipmentText(textRenderer, line.text(), textX, lineY, line.color()); + } + } + } + } + + private static void renderEquipmentText(TextRenderer textRenderer, String text, double x, double y, int color) { + RenderColor shadow = new RenderColor(0xB0000000); + double o = ENCHANT_TEXT_SHADOW_OFFSET; + textRenderer.render(text, x + o, y, shadow, false); + textRenderer.render(text, x - o, y, shadow, false); + textRenderer.render(text, x, y + o, shadow, false); + textRenderer.render(text, x, y - o, shadow, false); + textRenderer.render(text, x, y, new RenderColor(color), false); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagFaceRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagFaceRenderer.java new file mode 100644 index 0000000..40e1428 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagFaceRenderer.java @@ -0,0 +1,42 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.helpers.MatteHudStyle; +import dev.loki.lovisual.render.helpers.PlayerHeadRenderer; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.world.entity.player.Player; + +final class NameTagFaceRenderer { + + private NameTagFaceRenderer() { + } + + static boolean shouldRenderPlayerHead(NameTags self, Player player) { + return self.playerHead.get() && player instanceof AbstractClientPlayer; + } + + static void drawRoundedHead(GuiGraphicsExtractor ctx, NameTagModel.NameplateLayout layout, + AbstractClientPlayer clientPlayer, int alpha) { + PlayerHeadRenderer.drawRounded( + ctx, + layout.headX(), + layout.headY(), + layout.headSize(), + Math.min(6.0f, layout.headSize() * 0.48f), + clientPlayer, + new RenderColor(MatteHudStyle.withAlpha(0xFFFFFFFF, alpha)), + true, + null, + 0.0f, + false + ); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagLabelBuilder.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagLabelBuilder.java new file mode 100644 index 0000000..f85b153 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagLabelBuilder.java @@ -0,0 +1,185 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.features.relations.PlayerRelations; +import dev.loki.lovisual.util.player.PlayerHealthResolver; +import dev.loki.lovisual.util.pvp.PvpTargetState; +import dev.loki.lovisual.util.text.LegacyTextUtil; +import net.minecraft.client.multiplayer.PlayerInfo; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.GameType; + +final class NameTagLabelBuilder { + + private static final int HP_GREEN = 0xFF55FF55; + private static final int HP_CYAN = 0xFF55FFFF; + private static final int HP_RED = 0xFFFF5555; + + private NameTagLabelBuilder() { + } + + static NameTagModel.LabelInfo buildLabelInfo(NameTags self, Player player) { + Component styledName = resolveNameplateText(self, player); + String name = styledName == null ? "" : styledName.getString(); + String prefix = ""; + if (self.pvpPrefix.get() && PvpTargetState.isTargetInPvp(player.getUUID())) { + prefix = "[PVP] "; + } + int ping = getPlayerPing(self, player); + String pingText = shouldShowPingText(self) && ping >= 0 ? ping + "ms" : ""; + if (isCreative(self, player)) { + return new NameTagModel.LabelInfo(prefix, styledName, name, ping, pingText, "GM", PlayerRelations.get().colorStaff()); + } + PlayerHealthResolver.HealthSnapshot health = PlayerHealthResolver.resolve(player); + String hp = formatHealth(self, health.totalHealth()); + int color = resolveHealthColor(self, health.totalHealth(), health.maxHealth()); + return new NameTagModel.LabelInfo(prefix, styledName, name, ping, pingText, hp, color); + } + + static Component resolveNameplateText(NameTags self, Player player) { + if (player == null) return Component.empty(); + String fallback = player.getGameProfile().name(); + if (!shouldUseTabNames(self)) return Component.literal(fallback); + + var handler = self.mc.getConnection(); + if (handler == null) return Component.literal(fallback); + PlayerInfo entry = handler.getPlayerInfo(player.getUUID()); + if (entry == null) return Component.literal(fallback); + + Component displayName = entry.getTabListDisplayName(); + if (displayName == null) return Component.literal(fallback); + + Component parsed = LegacyTextUtil.convertLegacyCodes(displayName); + if (parsed == null || parsed.getString().isBlank()) return Component.literal(fallback); + return parsed; + } + + static String formatHealth(NameTags self, float hp) { + if (self.hpDecimals.get()) { + return formatTenths(hp); + } + int value = (int) Math.ceil(hp); + return String.valueOf(value); + } + + static String formatNameplateHp(String hp) { + return hp == null ? "" : hp; + } + + private static String formatTenths(float value) { + int tenth = Math.round(value * 10f); + int whole = tenth / 10; + int frac = Math.abs(tenth % 10); + return whole + "." + frac; + } + + static int resolveHealthColor(NameTags self, float current, float max) { + if (current > max) return HP_CYAN; + if ("Static".equalsIgnoreCase(self.hpColorMode.get())) { + return HP_GREEN; + } + return gradientHealthColor(current, max); + } + + private static int gradientHealthColor(float current, float max) { + if (max <= 0f) return HP_RED; + float clamped = Mth.clamp(current, 0f, max); + if (max <= 20f) { + float t = clamped / max; + return lerpColor(HP_RED, HP_GREEN, t); + } + if (clamped <= 20f) { + float t = clamped / 20f; + return lerpColor(HP_RED, HP_GREEN, t); + } + float t = (clamped - 20f) / (max - 20f); + return lerpColor(HP_GREEN, HP_CYAN, Mth.clamp(t, 0f, 1f)); + } + + static boolean isCreative(NameTags self, Player player) { + if (player.isCreative()) return true; + var handler = self.mc.getConnection(); + if (handler == null) return false; + PlayerInfo entry = handler.getPlayerInfo(player.getUUID()); + if (entry == null) return false; + GameType mode = entry.getGameMode(); + return mode == GameType.CREATIVE; + } + + static boolean shouldUseTabNames(NameTags self) { + return self.nameplateExtras.get("Tab names"); + } + + static boolean shouldShowPingText(NameTags self) { + return self.nameplateExtras.get("Ping"); + } + + static int getPlayerPing(NameTags self, Player player) { + if (player == null || self.mc == null || self.mc.getConnection() == null) return -1; + PlayerInfo entry = self.mc.getConnection().getPlayerInfo(player.getUUID()); + return entry != null ? entry.getLatency() : -1; + } + + static int resolvePingColor(int ping) { + if (ping < 0) { + return 0xFFD0D0D0; + } + if (ping <= 70) { + return 0xFF55FF55; + } + if (ping >= 200) { + return 0xFFFF5555; + } + if (ping <= 135) { + float t = (ping - 70.0f) / 65.0f; + return mixColor(0xFF55FF55, 0xFFFFFF55, t); + } + float t = (ping - 135.0f) / 65.0f; + return mixColor(0xFFFFFF55, 0xFFFF5555, t); + } + + private static int mixColor(int start, int end, float t) { + t = Mth.clamp(t, 0.0f, 1.0f); + int sa = (start >>> 24) & 0xFF; + int sr = (start >>> 16) & 0xFF; + int sg = (start >>> 8) & 0xFF; + int sb = start & 0xFF; + int ea = (end >>> 24) & 0xFF; + int er = (end >>> 16) & 0xFF; + int eg = (end >>> 8) & 0xFF; + int eb = end & 0xFF; + int a = (int) (sa + (ea - sa) * t + 0.5f); + int r = (int) (sr + (er - sr) * t + 0.5f); + int g = (int) (sg + (eg - sg) * t + 0.5f); + int b = (int) (sb + (eb - sb) * t + 0.5f); + return (a << 24) | (r << 16) | (g << 8) | b; + } + + private static int lerpColor(int a, int b, float t) { + int aA = (a >>> 24) & 0xFF; + int aR = (a >>> 16) & 0xFF; + int aG = (a >>> 8) & 0xFF; + int aB = a & 0xFF; + int bA = (b >>> 24) & 0xFF; + int bR = (b >>> 16) & 0xFF; + int bG = (b >>> 8) & 0xFF; + int bB = b & 0xFF; + int oA = Math.round(lerp(aA, bA, t)); + int oR = Math.round(lerp(aR, bR, t)); + int oG = Math.round(lerp(aG, bG, t)); + int oB = Math.round(lerp(aB, bB, t)); + return (oA << 24) | (oR << 16) | (oG << 8) | oB; + } + + private static float lerp(float a, float b, float t) { + return a + (b - a) * t; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagLayoutEngine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagLayoutEngine.java new file mode 100644 index 0000000..48151c3 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagLayoutEngine.java @@ -0,0 +1,168 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.features.module.Modules; +import dev.loki.lovisual.features.relations.CategoryService; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.text.TextRenderUtil; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; + +final class NameTagLayoutEngine { + + static final float NAMEPLATE_SCALE = 1.08f; + static final int DIST_TEXT_GAP = 5; + static final int NAMEPLATE_PAD_X = 4; + static final int NAMEPLATE_PAD_Y = 2; + static final float TOTEM_BADGE_TEXT_GAP = 2.0f; + static final float TOTEM_BADGE_TEXT_SCALE = 0.72f; + private static final int PING_TEXT_GAP = 4; + private static final int HP_TEXT_GAP = 4; + private static final float MATTE_HEAD_MIN_SIZE = 12.0f; + private static final float MATTE_HEAD_DIVIDER_GAP = 4.0f; + private static final float MATTE_HEAD_DIVIDER_WIDTH = 1.0f; + private static final float MATTE_HEAD_TEXT_GAP = 5.0f; + private static final float TOTEM_BADGE_GAP = 4.0f; + private static final float TOTEM_BADGE_DIVIDER_WIDTH = 1.0f; + private static final float TOTEM_BADGE_DIVIDER_GAP = 4.0f; + private static final float TOTEM_BADGE_ICON_SIZE = 10.0f; + private static final float NAMEPLATE_LIFT_MAX = 12f; + private static final float NAMEPLATE_LIFT_RANGE = 20f; + private static final int ESP_NAME_SECTION_LIFT = 9; + private static final int NAMEPLATE_LIFT_POWER = 4; + + private NameTagLayoutEngine() { + } + + static NameTagModel.NameplateLayout buildLayout(NameTags self, Player player, TextRenderer nameRenderer, + TextRenderer hpRenderer, NameTagModel.LabelInfo info, + double dist, int centerX, int nameY, + int totemPopCount, float totemPopAnimation) { + if (info == null) return null; + float labelScale = NAMEPLATE_SCALE; + String prefix = info.pvpPrefix(); + String name = info.name(); + String hp = NameTagLabelBuilder.formatNameplateHp(info.hp()); + String pingText = info.pingText(); + int pingWidth = pingText.isEmpty() ? 0 : (int) (nameRenderer.getWidth(pingText) * labelScale); + int pingGap = pingWidth > 0 ? PING_TEXT_GAP : 0; + double prefixWidth = prefix.isEmpty() ? 0.0 : nameRenderer.getWidth(prefix); + double rawNameWidth = info.styledName() != null + ? measureStyledWidth(nameRenderer, info.styledName(), CategoryService.getColor(player)) + : nameRenderer.getWidth(name); + int nameWidth = (int) ((prefixWidth + rawNameWidth) * labelScale); + int hpWidth = hp == null || hp.isEmpty() ? 0 : (int) (hpRenderer.getWidth(hp) * labelScale); + int hpGap = hpWidth > 0 ? HP_TEXT_GAP : 0; + boolean showDist = shouldShowDistanceText(self, player); + String distText = showDist ? (int) Math.round(dist) + "m" : ""; + int distWidth = showDist ? (int) (nameRenderer.getWidth(distText) * labelScale) : 0; + int distGap = distWidth > 0 ? DIST_TEXT_GAP : 0; + int nameHeight = (int) (nameRenderer.getHeight() * labelScale); + boolean renderHead = NameTagFaceRenderer.shouldRenderPlayerHead(self, player); + float headSize = renderHead ? Math.max(MATTE_HEAD_MIN_SIZE, nameHeight + NAMEPLATE_PAD_Y * 1.5f) : 0.0f; + float headBlock = renderHead + ? headSize + MATTE_HEAD_DIVIDER_GAP + MATTE_HEAD_DIVIDER_WIDTH + MATTE_HEAD_TEXT_GAP + : 0.0f; + int textWidth = pingWidth + pingGap + nameWidth + hpGap + hpWidth + distGap + distWidth; + int scaledHeight = Math.max(nameHeight, renderHead ? Math.round(headSize) : nameHeight); + boolean renderTotemBadge = self.totemPopCounter.get() && totemPopCount > 0 && totemPopAnimation > 0.001f; + String totemText = renderTotemBadge ? "x" + totemPopCount : ""; + float totemIconSize = renderTotemBadge + ? Math.min(TOTEM_BADGE_ICON_SIZE, Math.max(8.0f, scaledHeight - 2.0f)) + : 0.0f; + float totemTextWidth = renderTotemBadge + ? (float) hpRenderer.getWidth(totemText) * TOTEM_BADGE_TEXT_SCALE + : 0.0f; + float totemBadgeHeight = renderTotemBadge ? scaledHeight : 0.0f; + float totemBadgeWidth = renderTotemBadge + ? totemIconSize + TOTEM_BADGE_TEXT_GAP + totemTextWidth + : 0.0f; + float totemBlock = renderTotemBadge + ? TOTEM_BADGE_GAP + TOTEM_BADGE_DIVIDER_WIDTH + TOTEM_BADGE_DIVIDER_GAP + totemBadgeWidth + : 0.0f; + int totalWidth = Math.round(headBlock + textWidth + totemBlock); + int scaledWidth = totalWidth; + int contentX = centerX - scaledWidth / 2; + int nameX = Math.round(contentX + headBlock); + + float bgX = contentX - NAMEPLATE_PAD_X; + float bgY = nameY - NAMEPLATE_PAD_Y; + float bgW = scaledWidth + NAMEPLATE_PAD_X * 2f; + float bgH = scaledHeight + NAMEPLATE_PAD_Y * 2f; + float headX = contentX; + float headY = nameY + (scaledHeight - headSize) * 0.5f; + float dividerX = headX + headSize + MATTE_HEAD_DIVIDER_GAP; + float dividerH = Math.max(3.0f, bgH * 0.48f); + float dividerY = bgY + (bgH - dividerH) * 0.5f; + float totemDividerX = renderTotemBadge ? contentX + headBlock + textWidth + TOTEM_BADGE_GAP : 0.0f; + float totemDividerH = renderTotemBadge ? Math.max(3.0f, bgH * 0.48f) : 0.0f; + float totemDividerY = renderTotemBadge ? bgY + (bgH - totemDividerH) * 0.5f : 0.0f; + float totemBadgeX = renderTotemBadge ? totemDividerX + TOTEM_BADGE_DIVIDER_WIDTH + TOTEM_BADGE_DIVIDER_GAP : 0.0f; + float totemBadgeY = renderTotemBadge ? nameY : 0.0f; + + return new NameTagModel.NameplateLayout(nameX, nameY, scaledWidth, scaledHeight, labelScale, pingText, distText, bgX, bgY, bgW, bgH, + pingWidth, pingGap, nameWidth, hpWidth, hpGap, renderHead, headX, headY, headSize, + dividerX, dividerY, MATTE_HEAD_DIVIDER_WIDTH, dividerH, + renderTotemBadge, totemDividerX, totemDividerY, TOTEM_BADGE_DIVIDER_WIDTH, totemDividerH, + totemBadgeX, totemBadgeY, totemBadgeWidth, totemBadgeHeight, totemIconSize); + } + + static int computeNameY(NameTagModel.ScreenRect rect, int anchorY, float distOffset) { + if (rect != null) { + float rectH = (float) (rect.maxY() - rect.minY()); + float dynamicGap = Math.max(3f, rectH * 0.06f); + return Math.round((float) rect.minY() - dynamicGap - distOffset); + } + return Math.round(anchorY - 7 - distOffset); + } + + static int computeEspNameSectionLift(Player player) { + ESP esp = Modules.get(ESP.class); + if (esp == null || !esp.shouldLiftNameTagsSection(player)) return 0; + return ESP_NAME_SECTION_LIFT; + } + + static int computeItemsY(NameTagModel.ScreenRect rect, int nameY, float distOffset) { + int iconSize = NameTagEquipmentRenderer.equipIconSize(); + if (rect != null) { + float rectH = (float) (rect.maxY() - rect.minY()); + float itemGap = Math.max(4f, rectH * 0.08f); + return Math.round((float) rect.minY() - itemGap - iconSize - 6 - distOffset); + } + return Math.round(nameY - iconSize - 6 - distOffset); + } + + static float computeDistanceOffset(double dist) { + float d = (float) Math.max(0.0, dist); + float range = Math.max(1f, NAMEPLATE_LIFT_RANGE); + float max = Math.max(0f, NAMEPLATE_LIFT_MAX); + float power = Mth.clamp(NAMEPLATE_LIFT_POWER, 1, 6); + float t = Mth.clamp(d / range, 0f, 1f); + float eased = 1.0f - (float) Math.pow(1.0f - t, power); + return max * eased; + } + + static boolean shouldShowDistanceText(NameTags self, Player player) { + if (!self.toggles.get("Show distance")) return false; + if (player == null || self.mc.player == null) return false; + if (player != self.mc.player) return true; + Freecam freecam = Modules.get(Freecam.class); + return freecam != null && freecam.isEnabled(); + } + + private static float measureStyledWidth(TextRenderer textRenderer, Component text, int defaultColor) { + if (text == null) return 0.0f; + float width = 0.0f; + for (TextRenderUtil.Part part : TextRenderUtil.flattenStyled(text, defaultColor)) { + width += (float) textRenderer.getWidth(part.text()); + } + return width; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagModel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagModel.java new file mode 100644 index 0000000..e688289 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagModel.java @@ -0,0 +1,67 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.config.values.EnumValue; +import net.minecraft.network.chat.Component; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +public final class NameTagModel { + + private NameTagModel() { + } + + enum NameplateStyle implements EnumValue.IdProvider { + LIQUID_GLASS, + MATTE + } + + static final class EffectCache { + int lastTick = -1; + List effects = List.of(); + } + + static final class EnchantCache { + int lastTick = -1; + int signature = 0; + List> lines = List.of(); + int maxLines = 0; + } + + public record ScreenRect(double minX, double minY, double maxX, double maxY) { + } + + public record NameplateLayout(int nameX, int nameY, int width, int height, float labelScale, + String pingText, String distText, float bgX, float bgY, float bgW, float bgH, + int pingWidth, int pingGap, int nameWidth, int hpWidth, int hpGap, + boolean renderHead, float headX, float headY, float headSize, + float dividerX, float dividerY, float dividerW, float dividerH, + boolean renderTotemBadge, float totemDividerX, float totemDividerY, + float totemDividerW, float totemDividerH, float totemBadgeX, float totemBadgeY, + float totemBadgeW, float totemBadgeH, float totemIconSize) { + } + + public record EnchantLine(String text, int color) { + } + + public record RenderEntry(Player player, double dist, float distOffset, int centerX, int nameY, int itemsY, + ScreenRect rect, boolean renderSlots, boolean renderNameplate, + boolean renderEffects, LabelInfo labelInfo, int infoColor, + NameplateLayout nameplateLayout, + ItemStack[] slots, List> enchantLines, int maxEnchantLines, + List effects, int totemPopCount, float totemPopAnimation) { + } + + public record LabelInfo(String pvpPrefix, Component styledName, String name, int ping, String pingText, String hp, + int infoColor) { + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagOpponentRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagOpponentRenderer.java new file mode 100644 index 0000000..2b3ffe8 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagOpponentRenderer.java @@ -0,0 +1,125 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.features.module.Modules; +import dev.loki.lovisual.features.module.modules.combat.PvpCooldowns; +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.util.pvp.CooldownRegistry; +import dev.loki.lovisual.util.pvp.ItemCooldownSnapshot; +import dev.loki.lovisual.util.pvp.PvpTargetState; +import dev.loki.lovisual.util.pvp.opponents.OpponentCooldownManager; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +import java.util.UUID; + +final class NameTagOpponentRenderer { + + private static final int ICON_SIZE = 24; + private static final int ICON_GAP = 5; + private static final int EFFECT_LINE_HEIGHT = 26; + private static final int EFFECT_X_OFFSET = 6; + private static final int OPP_TIME_COLOR = 0xFFFFFFFF; + private static final int OPP_TIME_COLOR_GRACE = 0xFF4DA6FF; + private static final int OPP_STACK_Y_OFFSET = 10; + + private NameTagOpponentRenderer() { + } + + static boolean shouldRenderOpponentStuff(NameTags self, Player p) { + if (p == null || self.mc.player == null) return false; + if (p == self.mc.player) return false; + if (!self.opponentAppleCooldowns.get()) return false; + if (!isOpponentAppleTrackingEnabled()) return false; + if (!PvpTargetState.isTargetInPvp(p.getUUID()) && !hasOpponentCooldowns(p.getUUID())) return false; + double maxDist = NameTags.OPPONENT_DISTANCE; + return !(maxDist > 0) || !(self.mc.player.distanceToSqr(p) > maxDist * maxDist); + } + + static boolean isOpponentAppleTrackingEnabled() { + PvpCooldowns mod = Modules.get(PvpCooldowns.class); + return mod != null && mod.isSystemEnabled(); + } + + private static boolean hasOpponentCooldowns(UUID playerId) { + if (playerId == null) return false; + for (Item item : CooldownRegistry.trackedItems()) { + if (OpponentCooldownManager.snapshot(playerId, item).visible()) { + return true; + } + } + return false; + } + + static int computeOpponentStackY(NameTagModel.ScreenRect rect, int nameY) { + if (rect != null) { + double rectH = rect.maxY() - rect.minY(); + double upperCenter = rect.minY() + rectH * 0.25; + int target = (int) Math.round(upperCenter - ICON_SIZE * 0.5); + return Math.max(target, nameY + 2); + } + return nameY + OPP_STACK_Y_OFFSET; + } + + static void drawOpponentCooldownsStackedIcons(NameTags self, GuiGraphicsExtractor ctx, Player player, + NameTagModel.ScreenRect rect, int centerX, int nameY) { + if (!shouldRenderOpponentStuff(self, player)) return; + + int startX = rect != null + ? (int) rect.maxX() + EFFECT_X_OFFSET + : centerX + (ICON_SIZE + ICON_GAP) * 2 + 8; + int startY = computeOpponentStackY(rect, nameY); + + int y = startY; + int seed = 0; + for (Item item : CooldownRegistry.trackedItems()) { + ItemCooldownSnapshot snapshot = OpponentCooldownManager.snapshot(player.getUUID(), item); + if (!snapshot.visible()) continue; + + ItemStack icon = new ItemStack(item); + float scale = ICON_SIZE / 16f; + Renderer2D.COLOR.item(icon, startX, y, scale, seed++, Renderer2D.ITEM_OVERLAY_NONE, null); + + y += EFFECT_LINE_HEIGHT; + } + } + + static void drawOpponentCooldownsStackedText(NameTags self, TextRenderer textRenderer, Player player, + NameTagModel.ScreenRect rect, int centerX, int nameY) { + if (!shouldRenderOpponentStuff(self, player)) return; + + int startX = rect != null + ? (int) rect.maxX() + EFFECT_X_OFFSET + : centerX + (ICON_SIZE + ICON_GAP) * 2 + 8; + int startY = computeOpponentStackY(rect, nameY); + + int timeColor = PvpTargetState.isTargetInPvp(player.getUUID()) + ? OPP_TIME_COLOR + : OPP_TIME_COLOR_GRACE; + int y = startY; + for (Item item : CooldownRegistry.trackedItems()) { + ItemCooldownSnapshot snapshot = OpponentCooldownManager.snapshot(player.getUUID(), item); + if (!snapshot.visible()) continue; + + String prefix = snapshot.compactText(); + if (!prefix.isEmpty()) { + int textX = startX + ICON_SIZE + 6; + int textY = y + 4; + textRenderer.render(prefix + " ", textX, textY, + new RenderColor(snapshot.cooling() ? timeColor : OPP_TIME_COLOR_GRACE), true); + } + + y += EFFECT_LINE_HEIGHT; + } + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagPlateRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagPlateRenderer.java new file mode 100644 index 0000000..bed9da6 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagPlateRenderer.java @@ -0,0 +1,200 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.features.gui.hud.HudRenderUtil; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.FontInfo; +import dev.loki.lovisual.render.engine.text.Fonts; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.MatteHudStyle; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +import static dev.loki.lovisual.features.theme.Theme.theme; + +final class NameTagPlateRenderer { + + private static final float NAMEPLATE_RADIUS = 7.0f; + private static final float MATTE_NAMEPLATE_RADIUS = 4.0f; + private static final int NAMEPLATE_GLASS_TINT = 0xFFFFFFFF; + private static final int NAMEPLATE_GLASS_VEIL = 0x2A141414; + private static final float NAMEPLATE_GLASS_THICKNESS = 11.0f; + private static final float NAMEPLATE_GLASS_FRESNEL_POWER = -18.0f; + private static final float NAMEPLATE_GLASS_FRESNEL_ALPHA = 1.0f; + private static final float NAMEPLATE_GLASS_BASE_ALPHA = 0.82f; + private static final float NAMEPLATE_GLASS_FRESNEL_MIX = 0.38f; + private static final float NAMEPLATE_GLASS_DISTORT = 0.135f; + private static ItemStack totemBadgeStack; + + private NameTagPlateRenderer() { + } + + private static ItemStack totemBadgeStack() { + if (totemBadgeStack == null || totemBadgeStack.isEmpty()) { + totemBadgeStack = new ItemStack(Items.TOTEM_OF_UNDYING); + } + return totemBadgeStack; + } + + static boolean isMatteNameplate(NameTags self) { + return self.nameplateStyle.get() == NameTagModel.NameplateStyle.MATTE; + } + + static float nameplateRadius(NameTags self, NameTagModel.NameplateLayout layout) { + if (layout == null) return isMatteNameplate(self) ? MATTE_NAMEPLATE_RADIUS : NAMEPLATE_RADIUS; + if (isMatteNameplate(self)) { + return Math.min(MATTE_NAMEPLATE_RADIUS, Math.max(2.5f, layout.bgH() * 0.30f)); + } + return Math.min(NAMEPLATE_RADIUS, Math.max(4.5f, layout.bgH() * 0.5f)); + } + + static void drawBackground(NameTags self, Renderer2D renderer, Player player, NameTagModel.NameplateLayout layout) { + if (layout == null) return; + int alpha = clampAlpha(self.nameplateAlpha.get()); + if (alpha <= 0) return; + + float globalAlpha = alpha / 255.0f; + if (isMatteNameplate(self)) { + MatteHudStyle.drawPlate(renderer, layout.bgX(), layout.bgY(), layout.bgW(), layout.bgH(), + nameplateRadius(self, layout), globalAlpha); + return; + } + + float radius = nameplateRadius(self, layout); + Renderer2D.COLOR.liquidGlassRect( + layout.bgX(), + layout.bgY(), + layout.bgW(), + layout.bgH(), + radius, + NAMEPLATE_GLASS_THICKNESS, + NAMEPLATE_GLASS_TINT, + globalAlpha, + NAMEPLATE_GLASS_FRESNEL_POWER, + NAMEPLATE_GLASS_FRESNEL_ALPHA, + NAMEPLATE_GLASS_BASE_ALPHA, + NAMEPLATE_GLASS_FRESNEL_MIX, + NAMEPLATE_GLASS_DISTORT, + 0.0f + ); + renderer.roundedRect( + layout.bgX(), + layout.bgY(), + layout.bgW(), + layout.bgH(), + radius, + 1.0f, + HudRenderUtil.scaleAlpha(NAMEPLATE_GLASS_VEIL, globalAlpha) + ); + } + + static void drawHead(NameTags self, Renderer2D renderer, GuiGraphicsExtractor ctx, Player player, + NameTagModel.NameplateLayout layout) { + if (ctx == null || layout == null || !layout.renderHead()) return; + if (!(player instanceof AbstractClientPlayer clientPlayer)) return; + + int alpha = clampAlpha(self.nameplateAlpha.get()); + if (alpha <= 0) return; + float globalAlpha = alpha / 255.0f; + + NameTagFaceRenderer.drawRoundedHead(ctx, layout, clientPlayer, alpha); + + drawDivider(self, renderer, + layout.dividerX(), layout.dividerY(), layout.dividerW(), layout.dividerH(), globalAlpha); + } + + static void drawDivider(NameTags self, Renderer2D renderer, + float x, float y, float width, float height, float globalAlpha) { + if (renderer == null || width <= 0.0f || height <= 0.0f || globalAlpha <= 0.001f) return; + int color = isMatteNameplate(self) + ? MatteHudStyle.strokeColor(globalAlpha * 0.82f) + : MatteHudStyle.withAlpha(0xFFFFFF, Math.round(58.0f * globalAlpha)); + float drawWidth = Math.max(0.8f, width); + renderer.roundedRect( + x + (width - drawWidth) * 0.5f, + y, + drawWidth, + height, + Math.min(drawWidth, height) * 0.5f, + 0.0f, + color + ); + } + + static void drawTotemBadge(NameTags self, Renderer2D renderer, TextRenderer fallbackRenderer, + NameTagModel.NameplateLayout layout, int count, float animation) { + if (renderer == null || layout == null || !layout.renderTotemBadge()) return; + if (count <= 0 || animation <= 0.001f) return; + + float anim = AnimationUtility.easeInOutCubic(animation); + float globalAlpha = (clampAlpha(self.nameplateAlpha.get()) / 255.0f) * anim; + if (globalAlpha <= 0.001f) return; + + drawDivider(self, renderer, + layout.totemDividerX(), + layout.totemDividerY(), + layout.totemDividerW(), + layout.totemDividerH(), + globalAlpha + ); + + float blockX = layout.totemBadgeX(); + float blockY = layout.totemBadgeY(); + float blockH = layout.totemBadgeH(); + float iconScale = 0.86f + 0.14f * anim; + float iconSize = Math.max(1.0f, layout.totemIconSize() * iconScale); + float iconX = blockX; + float iconY = blockY + (blockH - iconSize) * 0.5f; + renderer.item(totemBadgeStack(), iconX, iconY, Math.max(0.1f, iconSize / 16.0f), 911, + Renderer2D.ITEM_OVERLAY_NONE, null); + + String text = "x" + count; + TextRenderer badgeRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, fallbackRenderer); + float textScale = NameTagLayoutEngine.TOTEM_BADGE_TEXT_SCALE * (0.94f + 0.06f * anim); + float textX = iconX + iconSize + NameTagLayoutEngine.TOTEM_BADGE_TEXT_GAP; + float textH = (float) badgeRenderer.getHeight(false) * textScale; + float textY = blockY + (blockH - textH) * 0.5f - 0.1f; + int textColor = HudRenderUtil.setAlpha(theme().textPrimary(), Math.round(255.0f * globalAlpha)); + + badgeRenderer.begin(textScale, false, false); + try { + if (globalAlpha > 0.96f) { + int baseColor = textColor; + int darkColor = HudRenderUtil.mixColor(baseColor, + HudRenderUtil.setAlpha(0xFF181B1F, Math.round(255.0f * globalAlpha)), 0.18f); + int lightColor = HudRenderUtil.mixColor(baseColor, + HudRenderUtil.setAlpha(theme().accentSoft(), Math.round(255.0f * globalAlpha)), 0.24f); + float time = (float) (net.minecraft.util.Util.getMillis() / 1000.0); + float pulse = time * 2.35f; + badgeRenderer.renderGradient(text, textX, textY, (idx, cp, gx, out) -> { + float p = pulse + idx * 0.62f; + float t0 = 0.5f + 0.5f * (float) Math.sin(p); + float t1 = 0.5f + 0.5f * (float) Math.sin(p + 1.05f); + out[0] = HudRenderUtil.mixColor(darkColor, lightColor, t0); + out[1] = HudRenderUtil.mixColor(darkColor, lightColor, t1); + }, false); + } else { + badgeRenderer.render(text, textX, textY, new RenderColor(textColor), false); + } + } finally { + badgeRenderer.end(); + } + } + + static int clampAlpha(int a) { + if (a < 0) return 0; + if (a > 255) return 255; + return a; + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagRenderer.java new file mode 100644 index 0000000..97c6b60 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTagRenderer.java @@ -0,0 +1,196 @@ +/* + * 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.features.module.modules.visuals; + +import dev.loki.lovisual.features.relations.CategoryService; +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.FontInfo; +import dev.loki.lovisual.render.engine.text.Fonts; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.EffectIconRenderer; +import dev.loki.lovisual.render.helpers.ScissorFunction; +import dev.loki.lovisual.util.text.TextRenderUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; + +import java.util.List; + +final class NameTagRenderer { + + static final float SMALL_TEXT_SCALE = 0.82f; + private static final float NAMEPLATE_TEXT_SHADOW_OFFSET = 0.0f; + + private NameTagRenderer() { + } + + static void ensureFontCache(NameTags self, TextRenderer fallback) { + self.cachedNameTr = Fonts.renderer("OnestBold", FontInfo.Type.Regular, fallback); + self.cachedHpTr = Fonts.renderer("OnestMedium", FontInfo.Type.Regular, self.cachedNameTr); + self.cachedLevelTr = Fonts.renderer("OnestBold", FontInfo.Type.Regular, fallback); + self.cachedTimeTr = Fonts.renderer("OnestMedium", FontInfo.Type.Regular, fallback); + } + + static void renderNameTagForeground(NameTags self, Renderer2D renderer, GuiGraphicsExtractor ctx, + TextRenderer textRenderer, NameTagModel.RenderEntry entry) { + Player player = entry.player(); + int centerX = entry.centerX(); + int nameY = entry.nameY(); + int itemsY = entry.itemsY(); + float distOffset = entry.distOffset(); + NameTagModel.ScreenRect rect = entry.rect(); + + if (entry.renderNameplate() && entry.nameplateLayout() != null) { + NameTagPlateRenderer.drawBackground(self, renderer, player, entry.nameplateLayout()); + NameTagPlateRenderer.drawHead(self, renderer, ctx, player, entry.nameplateLayout()); + } + + final int effectsLift = NameTagEffectsRenderer.scaleRow( + NameTagEffectsRenderer.computeEnchantLift(self, textRenderer, entry.maxEnchantLines())); + + if (entry.renderSlots()) { + NameTagEquipmentRenderer.drawRow(self, ctx, entry.player(), entry.slots(), centerX, itemsY); + } + + if (entry.renderEffects()) { + EffectIconRenderer.beginBatch(); + NameTagEffectsRenderer.drawRowIcons(ctx, entry.effects(), centerX, itemsY, effectsLift); + EffectIconRenderer.endBatch(); + } + + NameTagOpponentRenderer.drawOpponentCooldownsStackedIcons(self, ctx, player, rect, centerX, nameY); + + boolean startedBaseText = beginTextRenderer(textRenderer, SMALL_TEXT_SCALE); + try { + if (entry.renderSlots()) { + NameTagEquipmentRenderer.drawRowText(textRenderer, entry.slots(), entry.enchantLines(), centerX, itemsY); + } + + if (entry.renderEffects()) { + TextRenderer levelTr = self.cachedLevelTr != null ? self.cachedLevelTr : textRenderer; + TextRenderer timeTr = self.cachedTimeTr != null ? self.cachedTimeTr : textRenderer; + NameTagEffectsRenderer.drawRowIconOverlays(self, textRenderer, levelTr, timeTr, + entry.effects(), entry.player().getId(), centerX, itemsY, effectsLift); + } + + NameTagOpponentRenderer.drawOpponentCooldownsStackedText(self, textRenderer, player, rect, centerX, nameY); + } finally { + endTextRenderer(textRenderer, startedBaseText); + } + + if (entry.renderNameplate() && entry.labelInfo() != null) { + NameTagModel.LabelInfo info = entry.labelInfo(); + NameTagModel.NameplateLayout layout = entry.nameplateLayout(); + if (layout != null) { + TextRenderer nameTr = self.cachedNameTr != null ? self.cachedNameTr : textRenderer; + TextRenderer hpTr = self.cachedHpTr != null ? self.cachedHpTr : nameTr; + boolean clipped = pushScissor(layout); + float scale = layout.labelScale(); + double nameX = layout.nameX(); + boolean startedName = beginTextRenderer(nameTr, scale); + double cursorX = nameX; + try { + if (!layout.pingText().isEmpty()) { + renderNameplateText(nameTr, layout.pingText(), cursorX, nameY, + NameTagLabelBuilder.resolvePingColor(info.ping())); + cursorX += layout.pingWidth() + layout.pingGap(); + } + String prefix = info.pvpPrefix(); + if (!prefix.isEmpty()) { + renderNameplateText(nameTr, prefix, cursorX, nameY, self.pvpPrefixColor.getArgb()); + cursorX += nameTr.getWidth(prefix); + } + if (NameTagLabelBuilder.shouldUseTabNames(self)) { + renderStyledNameplateText(nameTr, info.styledName(), cursorX, nameY, CategoryService.getColor(player)); + } else { + renderNameplateText(nameTr, info.name(), cursorX, nameY, CategoryService.getColor(player)); + } + } finally { + endTextRenderer(nameTr, startedName); + } + + if (!info.hp().isEmpty()) { + double hpX = nameX + layout.pingWidth() + layout.pingGap() + layout.nameWidth() + layout.hpGap(); + boolean startedHp = beginTextRenderer(hpTr, scale); + try { + renderNameplateText(hpTr, NameTagLabelBuilder.formatNameplateHp(info.hp()), hpX, nameY, entry.infoColor()); + } finally { + endTextRenderer(hpTr, startedHp); + } + } + + if (!layout.distText().isEmpty()) { + double distX = nameX + layout.pingWidth() + layout.pingGap() + layout.nameWidth() + layout.hpGap() + + layout.hpWidth() + (layout.hpWidth() > 0 ? NameTagLayoutEngine.DIST_TEXT_GAP : 0); + boolean startedDist = beginTextRenderer(nameTr, scale); + try { + renderNameplateText(nameTr, layout.distText(), distX, nameY, 0xFFD0D0D0); + } finally { + endTextRenderer(nameTr, startedDist); + } + } + if (clipped) ScissorFunction.pop(); + NameTagPlateRenderer.drawTotemBadge(self, renderer, textRenderer, layout, + entry.totemPopCount(), entry.totemPopAnimation()); + } + } + } + + static void renderNameplateText(TextRenderer textRenderer, String text, double x, double y, int color) { + if (text == null || text.isEmpty()) return; + if (NAMEPLATE_TEXT_SHADOW_OFFSET > 0.001f) { + RenderColor shadow = new RenderColor(0x42000000); + double o = NAMEPLATE_TEXT_SHADOW_OFFSET; + textRenderer.render(text, x + o, y, shadow, false); + textRenderer.render(text, x - o, y, shadow, false); + textRenderer.render(text, x, y + o, shadow, false); + textRenderer.render(text, x, y - o, shadow, false); + } + textRenderer.render(text, x, y, new RenderColor(color), false); + } + + static void renderStyledNameplateText(TextRenderer textRenderer, Component text, double x, double y, int defaultColor) { + if (text == null) return; + List parts = TextRenderUtil.flattenStyled(text, defaultColor); + double cursorX = x; + for (TextRenderUtil.Part part : parts) { + renderNameplateText(textRenderer, part.text(), cursorX, y, part.color()); + cursorX += textRenderer.getWidth(part.text()); + } + } + + static boolean beginTextRenderer(TextRenderer textRenderer, double scale) { + if (textRenderer == null || textRenderer.isBuilding()) return false; + textRenderer.begin(scale); + return true; + } + + static void endTextRenderer(TextRenderer textRenderer, boolean started) { + if (!started || textRenderer == null || !textRenderer.isBuilding()) return; + textRenderer.end(); + } + + static boolean pushScissor(NameTagModel.NameplateLayout layout) { + if (layout == null) return false; + Minecraft mc = Minecraft.getInstance(); + if (mc == null || mc.getWindow() == null) return false; + + int sw = mc.getWindow().getScreenWidth(); + int sh = mc.getWindow().getScreenHeight(); + + int x1 = Math.max(0, (int) Math.floor(layout.bgX())); + int y1 = Math.max(0, (int) Math.floor(layout.bgY())); + int x2 = Math.min(sw, (int) Math.ceil(layout.bgX() + layout.bgW())); + int y2 = Math.min(sh, (int) Math.ceil(layout.bgY() + layout.bgH())); + + if (x2 <= x1 || y2 <= y1) return false; + return ScissorFunction.pushRawRect(x1, y1, x2, y2); + } +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTags.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTags.java index a0bf137..501b23d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTags.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NameTags.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,140 +7,43 @@ package dev.loki.lovisual.features.module.modules.visuals; +import dev.loki.lovisual.config.SettingDef; +import dev.loki.lovisual.config.common.CommonSettingSchemas; import dev.loki.lovisual.config.values.*; +import dev.loki.lovisual.features.gui.clickgui.settings.TextListSetting; import dev.loki.lovisual.features.module.*; import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.render.helpers.*; -import dev.loki.lovisual.util.item.EnchantUtil; -import it.unimi.dsi.fastutil.objects.Object2IntMap; +import dev.loki.lovisual.mixininterface.IEntity; +import dev.loki.lovisual.render.engine.animation.AnimationUtility; +import dev.loki.lovisual.render.engine.renderer.Renderer2D; +import dev.loki.lovisual.render.engine.text.TextRenderer; +import dev.loki.lovisual.render.helpers.ScreenProjection; +import dev.loki.lovisual.util.item.IllegalItemUtil; +import dev.loki.lovisual.util.item.TopEnchantUtil; +import dev.loki.lovisual.util.player.effect.StatusEffectView; +import dev.loki.lovisual.util.pvp.opponents.TotemPopCounter; +import dev.loki.lovisual.util.pvp.opponents.TotemPopSnapshot; import net.minecraft.client.CameraType; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.client.multiplayer.PlayerInfo; -import net.minecraft.client.player.AbstractClientPlayer; -import net.minecraft.client.resources.language.I18n; -import net.minecraft.core.Holder; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.util.Mth; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.item.enchantment.ItemEnchantments; -import net.minecraft.world.level.GameType; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.SettingDef; -import dev.loki.lovisual.config.common.CommonSettingSchemas; -import dev.loki.lovisual.features.gui.clickgui.settings.TextListSetting; -import dev.loki.lovisual.features.gui.hud.HudRenderUtil; -import dev.loki.lovisual.features.module.modules.combat.PvpCooldowns; -import dev.loki.lovisual.features.relations.CategoryService; -import dev.loki.lovisual.features.relations.PlayerRelations; -import dev.loki.lovisual.mixininterface.IEntity; -import dev.loki.lovisual.render.engine.animation.AnimationUtility; -import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.renderer.Renderer2D; -import dev.loki.lovisual.render.engine.text.FontInfo; -import dev.loki.lovisual.render.engine.text.Fonts; -import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.util.item.EnchantMeta; -import dev.loki.lovisual.util.item.EnchantRegistry; -import dev.loki.lovisual.util.item.IllegalItemUtil; -import dev.loki.lovisual.util.item.TopEnchantUtil; -import dev.loki.lovisual.util.player.PlayerHealthResolver; -import dev.loki.lovisual.util.player.effect.StatusEffectTracker; -import dev.loki.lovisual.util.player.effect.StatusEffectView; -import dev.loki.lovisual.util.pvp.CooldownRegistry; -import dev.loki.lovisual.util.pvp.ItemCooldownSnapshot; -import dev.loki.lovisual.util.pvp.PvpTargetState; -import dev.loki.lovisual.util.pvp.opponents.OpponentCooldownManager; -import dev.loki.lovisual.util.pvp.opponents.TotemPopCounter; -import dev.loki.lovisual.util.pvp.opponents.TotemPopSnapshot; -import dev.loki.lovisual.util.text.LegacyTextUtil; -import dev.loki.lovisual.util.text.TextRenderUtil; import java.util.*; -import static dev.loki.lovisual.features.theme.Theme.theme; - //todo Description @ModuleInfo(id = "nametags", displayName = "NameTags", aliases = {"nametag", "tags", "names"}, category = ModuleCategory.VISUALS) public class NameTags extends Module { - private static final int ICON_SIZE = 24; - private static final int ICON_GAP = 5; - private static final float EQUIP_ICON_SCALE = 1.10f; - private static final int EFFECT_LINE_HEIGHT = 26; - private static final int EFFECT_X_OFFSET = 6; - private static final int EFFECT_LEVEL_COLOR = 0xFFBFC6D1; - private static final int EFFECT_ROW_GAP = 10; - private static final int EFFECT_ROW_ICON_GAP = 8; - private static final int EFFECT_ROW_TEXT_GAP = 4; - private static final int EFFECT_ROW_LEVEL_GAP = 3; - private static final int EFFECT_ROW_TIME_GAP = 2; - private static final float EFFECT_ROW_SCALE = 1.15f; - private static final float NAMEPLATE_SCALE = 1.08f; - private static final float SMALL_TEXT_SCALE = 0.82f; - private static final int NAMEPLATE_PAD_X = 4; - private static final int NAMEPLATE_PAD_Y = 2; - private static final float NAMEPLATE_RADIUS = 7.0f; - private static final float MATTE_NAMEPLATE_RADIUS = 4.0f; - private static final float MATTE_HEAD_MIN_SIZE = 12.0f; - private static final float MATTE_HEAD_DIVIDER_GAP = 4.0f; - private static final float MATTE_HEAD_DIVIDER_WIDTH = 1.0f; - private static final float MATTE_HEAD_TEXT_GAP = 5.0f; - private static final float TOTEM_BADGE_GAP = 4.0f; - private static final float TOTEM_BADGE_DIVIDER_WIDTH = 1.0f; - private static final float TOTEM_BADGE_DIVIDER_GAP = 4.0f; - private static final float TOTEM_BADGE_MIN_WIDTH = 23.0f; - private static final float TOTEM_BADGE_PAD_X = 3.0f; - private static final float TOTEM_BADGE_ICON_SIZE = 10.0f; - private static final float TOTEM_BADGE_TEXT_GAP = 2.0f; - private static final float TOTEM_BADGE_TEXT_SCALE = 0.72f; - private static final float TOTEM_BADGE_ANIM_SPEED = 10.0f; - private static final float NAMEPLATE_SHADOW_BLUR = 4.6f; - private static final float NAMEPLATE_SHADOW_INNER_ALPHA = 0.18f; - private static final float NAMEPLATE_TEXT_SHADOW_OFFSET = 0.0f; - private static final int NAMEPLATE_GLASS_TINT = 0xFFFFFFFF; - private static final int NAMEPLATE_GLASS_VEIL = 0x2A141414; - private static final float NAMEPLATE_GLASS_THICKNESS = 11.0f; - private static final float NAMEPLATE_GLASS_FRESNEL_POWER = -18.0f; - private static final float NAMEPLATE_GLASS_FRESNEL_ALPHA = 1.0f; - private static final float NAMEPLATE_GLASS_BASE_ALPHA = 0.82f; - private static final float NAMEPLATE_GLASS_FRESNEL_MIX = 0.38f; - private static final float NAMEPLATE_GLASS_DISTORT = 0.135f; - private static final int DIST_TEXT_GAP = 5; - private static final int PING_TEXT_GAP = 4; - private static final float ENCHANT_TEXT_SHADOW_OFFSET = 0.7f; - private static final int HP_TEXT_GAP = 4; - private static final int HP_GREEN = 0xFF55FF55; - private static final int HP_CYAN = 0xFF55FFFF; - private static final int HP_RED = 0xFFFF5555; + static final int OPPONENT_DISTANCE = 80; private static final int INFO_COLOR_DEFAULT = 0xFFFF8A8A; - private static final int EFFECT_LEVEL_STACK_COLOR = 0xFFFF4444; - private static final int EFFECT_TIME_COLOR = 0xFFCCCCCC; - private static final int OPP_TIME_COLOR = 0xFFFFFFFF; - private static final int OPP_TIME_COLOR_GRACE = 0xFF4DA6FF; - private static final int OPP_STACK_Y_OFFSET = 10; - private static final int OPPONENT_DISTANCE = 80; - private static final int EFFECT_CACHE_TICKS = 4; - private static final int ENCHANT_CACHE_TICKS = 2; + private static final float NAMEPLATE_EXTRA_LIFT = 8f; private static final ItemStack[] EMPTY_SLOTS = new ItemStack[0]; - private static ItemStack totemBadgeStack; - private static ItemStack totemBadgeStack() { - if (totemBadgeStack == null || totemBadgeStack.isEmpty()) { - totemBadgeStack = new ItemStack(Items.TOTEM_OF_UNDYING); - } - return totemBadgeStack; - } private static final String SETTING_TOGGLES = "toggles"; private static final String SETTING_DURABILITY_START = "durability_start_percent"; private static final String SETTING_DISTANCE_TOGGLES = "distance_toggles"; @@ -160,35 +63,28 @@ public class NameTags extends Module { private static final String SETTING_ILLEGAL_ENCHANTS_ALWAYS = "illegal_enchants_always"; private static final String SETTING_TOP_ENCHANT_COLOR = "top_enchant_color"; private static final String SETTING_TOP_ENCHANT_IGNORE_LIST = "top_enchant_ignore_list"; - private static final String SETTING_DEFAULT_NAME_COLOR = "default_name_color"; - private static final String SETTING_FRIEND_NAME_COLOR = "friend_name_color"; - private static final String SETTING_ENEMY_NAME_COLOR = "enemy_name_color"; - private static final String SETTING_STAFF_NAME_COLOR = "staff_name_color"; private static final String SETTING_HP_DECIMALS = "hp_decimals"; private static final String SETTING_HP_COLOR_MODE = "hp_color_mode"; private static final String SETTING_NAMEPLATE_ALPHA = "nameplate_alpha"; private static final String SETTING_NAMEPLATE_STYLE = "nameplate_style"; private static final String SETTING_PLAYER_HEAD = "player_head"; private static final String SETTING_NAMEPLATE_EXTRAS = "nameplate_extras"; - private static final float NAMEPLATE_LIFT_MAX = 12f; - private static final float NAMEPLATE_LIFT_RANGE = 20f; - private static final float NAMEPLATE_EXTRA_LIFT = 8f; - private static final int ESP_NAME_SECTION_LIFT = 9; - private static final int NAMEPLATE_LIFT_POWER = 4; private static final String SETTING_OPPONENT_APPLE_COOLDOWNS = "opponent_apple_cooldowns"; private static final String SETTING_PVP_PREFIX = "pvp_prefix"; private static final String SETTING_PVP_PREFIX_COLOR = "pvp_prefix_color"; - private final Minecraft mc = Minecraft.getInstance(); + + final Minecraft mc = Minecraft.getInstance(); private final ItemIdSetValue topIgnore = TopEnchantUtil.ignoreValue(); - private final List renderQueue = new ArrayList<>(); + private final List renderQueue = new ArrayList<>(); private final List playerBuffer = new ArrayList<>(); - private final Map slotCache = new HashMap<>(); - private final Map effectCache = new HashMap<>(); - private final Map enchantCache = new HashMap<>(); - private final Map totemPopAnimations = new HashMap<>(); - private final Map totemPopLastCounts = new HashMap<>(); - private final HashSet seenIds = new HashSet<>(); - private final BooleanMapValue toggles = group("nameTagsToggles", SETTING_TOGGLES, Map.of( + final Map slotCache = new HashMap<>(); + final Map effectCache = new HashMap<>(); + final Map enchantCache = new HashMap<>(); + final Map totemPopAnimations = new HashMap<>(); + final Map totemPopLastCounts = new HashMap<>(); + final HashSet seenIds = new HashSet<>(); + + final BooleanMapValue toggles = group("nameTagsToggles", SETTING_TOGGLES, Map.of( "Show nameplate", true, "Show distance", true, "Show armor row", true, @@ -196,7 +92,7 @@ public class NameTags extends Module { "Show effects", true, "Show self in 3rd person", false )); - private final NumberValue durabilityStartPercent = + final NumberValue durabilityStartPercent = visibleWhen(num("nameTagsDurabilityStartPercent", SETTING_DURABILITY_START, 99, 0, 100), () -> toggles.get("Item durability bar")); private final BooleanMapValue distanceToggles = @@ -214,20 +110,20 @@ public class NameTags extends Module { private final NumberValue effectsDistance = visibleWhen(num("nameTagsEffectsDistance", SETTING_EFFECTS_CUTOFF, 90, 5, 256), () -> toggles.get("Show effects")); - private final NumberValue nameplateAlpha = + final NumberValue nameplateAlpha = visibleWhen(num("nameTagsNameplateAlpha", SETTING_NAMEPLATE_ALPHA, 180, 0, 255), () -> toggles.get("Show nameplate")); - private final EnumValue nameplateStyle = - visibleWhen(enumSetting("nameTagsNameplateStyle", SETTING_NAMEPLATE_STYLE, NameplateStyle.LIQUID_GLASS, NameplateStyle.values()), + final EnumValue nameplateStyle = + visibleWhen(enumSetting("nameTagsNameplateStyle", SETTING_NAMEPLATE_STYLE, NameTagModel.NameplateStyle.LIQUID_GLASS, NameTagModel.NameplateStyle.values()), () -> toggles.get("Show nameplate")); - private final BooleanValue playerHead = + final BooleanValue playerHead = visibleWhen(bool("nameTagsPlayerHead", SETTING_PLAYER_HEAD, false), () -> toggles.get("Show nameplate")); - private final BooleanMapValue nameplateExtras = visibleWhen(group("nameTagsNameplateExtras", SETTING_NAMEPLATE_EXTRAS, new LinkedHashMap<>() {{ + final BooleanMapValue nameplateExtras = visibleWhen(group("nameTagsNameplateExtras", SETTING_NAMEPLATE_EXTRAS, new LinkedHashMap<>() {{ put("Tab names", false); put("Ping", false); }}), () -> toggles.get("Show nameplate")); - private final BooleanMapValue enchantArmor = group("nameTagsEnchantArmor", SETTING_ARMOR_ENCHANTS, Map.ofEntries( + final BooleanMapValue enchantArmor = group("nameTagsEnchantArmor", SETTING_ARMOR_ENCHANTS, Map.ofEntries( Map.entry("protection", true), Map.entry("fire_protection", false), Map.entry("feather_falling", false), @@ -241,7 +137,7 @@ public class NameTags extends Module { Map.entry("soul_speed", false), Map.entry("swift_sneak", false) )); - private final BooleanMapValue enchantMelee = group("nameTagsEnchantMelee", SETTING_MELEE_ENCHANTS, Map.ofEntries( + final BooleanMapValue enchantMelee = group("nameTagsEnchantMelee", SETTING_MELEE_ENCHANTS, Map.ofEntries( Map.entry("sharpness", true), Map.entry("smite", false), Map.entry("bane_of_arthropods", false), @@ -250,60 +146,61 @@ public class NameTags extends Module { Map.entry("looting", true), Map.entry("sweeping_edge", false) )); - private final BooleanMapValue enchantTools = group("nameTagsEnchantTools", SETTING_TOOLS_ENCHANTS, Map.ofEntries( + final BooleanMapValue enchantTools = group("nameTagsEnchantTools", SETTING_TOOLS_ENCHANTS, Map.ofEntries( Map.entry("efficiency", true), Map.entry("silk_touch", true), Map.entry("fortune", true) )); - private final BooleanMapValue enchantBow = group("nameTagsEnchantBow", SETTING_BOW_ENCHANTS, Map.ofEntries( + final BooleanMapValue enchantBow = group("nameTagsEnchantBow", SETTING_BOW_ENCHANTS, Map.ofEntries( Map.entry("power", true), Map.entry("punch", true), Map.entry("flame", false), Map.entry("infinity", false) )); - private final BooleanMapValue enchantFishing = group("nameTagsEnchantFishing", SETTING_FISHING_ENCHANTS, Map.ofEntries( + final BooleanMapValue enchantFishing = group("nameTagsEnchantFishing", SETTING_FISHING_ENCHANTS, Map.ofEntries( Map.entry("luck_of_the_sea", false), Map.entry("lure", false) )); - private final BooleanMapValue enchantTrident = group("nameTagsEnchantTrident", SETTING_TRIDENT_ENCHANTS, Map.ofEntries( + final BooleanMapValue enchantTrident = group("nameTagsEnchantTrident", SETTING_TRIDENT_ENCHANTS, Map.ofEntries( Map.entry("loyalty", false), Map.entry("impaling", false), Map.entry("riptide", false), Map.entry("channeling", false) )); - private final BooleanMapValue enchantCrossbow = group("nameTagsEnchantCrossbow", SETTING_CROSSBOW_ENCHANTS, Map.ofEntries( + final BooleanMapValue enchantCrossbow = group("nameTagsEnchantCrossbow", SETTING_CROSSBOW_ENCHANTS, Map.ofEntries( Map.entry("multishot", false), Map.entry("quick_charge", false), Map.entry("piercing", true) )); - private final BooleanMapValue enchantMace = group("nameTagsEnchantMace", SETTING_MACE_ENCHANTS, Map.ofEntries( + final BooleanMapValue enchantMace = group("nameTagsEnchantMace", SETTING_MACE_ENCHANTS, Map.ofEntries( Map.entry("density", true), Map.entry("breach", false), Map.entry("wind_burst", true) )); - private final BooleanMapValue enchantOther = group("nameTagsEnchantOther", SETTING_OTHER_ENCHANTS, Map.ofEntries( + final BooleanMapValue enchantOther = group("nameTagsEnchantOther", SETTING_OTHER_ENCHANTS, Map.ofEntries( Map.entry("mending", false), Map.entry("unbreaking", false), Map.entry("vanishing_curse", false), Map.entry("lunge", true) )); - private final BooleanValue illegalEnchantsAlways = bool("nameTagsIllegalEnchantsAlways", SETTING_ILLEGAL_ENCHANTS_ALWAYS, true); - private final BooleanValue opponentAppleCooldowns = bool("nameTagsOpponentAppleCooldowns", SETTING_OPPONENT_APPLE_COOLDOWNS, true); - private final BooleanValue totemPopCounter = TotemPopCounter.enabledValue(); + final BooleanValue illegalEnchantsAlways = bool("nameTagsIllegalEnchantsAlways", SETTING_ILLEGAL_ENCHANTS_ALWAYS, true); + final BooleanValue opponentAppleCooldowns = bool("nameTagsOpponentAppleCooldowns", SETTING_OPPONENT_APPLE_COOLDOWNS, true); + final BooleanValue totemPopCounter = TotemPopCounter.enabledValue(); private final NumberValue totemPopResetSeconds = TotemPopCounter.resetAfterSecondsValue(); - private final BooleanValue pvpPrefix = bool("nameTagsPvpPrefix", SETTING_PVP_PREFIX, false); - private final RGBColorValue pvpPrefixColor = + final BooleanValue pvpPrefix = bool("nameTagsPvpPrefix", SETTING_PVP_PREFIX, false); + final RGBColorValue pvpPrefixColor = visibleWhen(colorNoAlpha("nameTagsPvpPrefixColor", SETTING_PVP_PREFIX_COLOR, "#FF0000"), pvpPrefix::get); - private final BooleanValue hpDecimals = + final BooleanValue hpDecimals = visibleWhen(bool("nameTagsHpDecimals", SETTING_HP_DECIMALS, false), () -> toggles.get("Show nameplate")); - private final ModeValue hpColorMode = + final ModeValue hpColorMode = visibleWhen(modeSetting("nameTagsHpColorMode", SETTING_HP_COLOR_MODE, "Static", "Static", "Gradient"), () -> toggles.get("Show nameplate")); - private transient TextRenderer cachedNameTr; - private transient TextRenderer cachedHpTr; - private transient TextRenderer cachedLevelTr; - private transient TextRenderer cachedTimeTr; + + transient TextRenderer cachedNameTr; + transient TextRenderer cachedHpTr; + transient TextRenderer cachedLevelTr; + transient TextRenderer cachedTimeTr; { setting(SettingDef.bool(totemPopCounter) @@ -316,170 +213,6 @@ public class NameTags extends Module { setting(SettingDef.textList(SETTING_TOP_ENCHANT_IGNORE_LIST, topIgnore, TextListSetting.PickerMode.ENCHANTMENTS)); } - private static int withAlpha(int argb, int alpha) { - return (argb & 0x00FFFFFF) | (alpha << 24); - } - - private static String formatNameplateHp(String hp) { - return hp == null ? "" : hp; - } - - private static int clampAlpha(int a) { - if (a < 0) return 0; - if (a > 255) return 255; - return a; - } - - private static int equipmentSignature(ItemStack[] slots) { - if (slots == null || slots.length == 0) return 1; - int hash = 1; - for (ItemStack stack : slots) { - hash = 31 * hash + itemSignature(stack); - } - return hash; - } - - private static int itemSignature(ItemStack stack) { - if (stack == null || stack.isEmpty()) return 0; - int hash = 17; - hash = 31 * hash + Item.getId(stack.getItem()); - hash = 31 * hash + stack.getCount(); - hash = 31 * hash + stack.getDamageValue(); - hash = 31 * hash + stack.getComponents().hashCode(); - return hash; - } - - private static int scaleRow(int value) { - return Math.round(value * EFFECT_ROW_SCALE); - } - - private static int equipIconSize() { - return Math.round(ICON_SIZE * EQUIP_ICON_SCALE); - } - - private static int equipIconGap() { - return Math.round(ICON_GAP * EQUIP_ICON_SCALE); - } - - private static float measureStyledWidth(TextRenderer textRenderer, Component text, int defaultColor) { - if (text == null) return 0.0f; - float width = 0.0f; - for (TextRenderUtil.Part part : TextRenderUtil.flattenStyled(text, defaultColor)) { - width += (float) textRenderer.getWidth(part.text()); - } - return width; - } - - private static int resolvePingColor(int ping) { - if (ping < 0) { - return 0xFFD0D0D0; - } - if (ping <= 70) { - return 0xFF55FF55; - } - if (ping >= 200) { - return 0xFFFF5555; - } - - if (ping <= 135) { - float t = (ping - 70.0f) / 65.0f; - return mixColor(0xFF55FF55, 0xFFFFFF55, t); - } - - float t = (ping - 135.0f) / 65.0f; - return mixColor(0xFFFFFF55, 0xFFFF5555, t); - } - - private static int mixColor(int start, int end, float t) { - t = Mth.clamp(t, 0.0f, 1.0f); - int sa = (start >>> 24) & 0xFF; - int sr = (start >>> 16) & 0xFF; - int sg = (start >>> 8) & 0xFF; - int sb = start & 0xFF; - int ea = (end >>> 24) & 0xFF; - int er = (end >>> 16) & 0xFF; - int eg = (end >>> 8) & 0xFF; - int eb = end & 0xFF; - int a = (int) (sa + (ea - sa) * t + 0.5f); - int r = (int) (sr + (er - sr) * t + 0.5f); - int g = (int) (sg + (eg - sg) * t + 0.5f); - int b = (int) (sb + (eb - sb) * t + 0.5f); - return (a << 24) | (r << 16) | (g << 8) | b; - } - - private static boolean beginTextRenderer(TextRenderer textRenderer, double scale) { - if (textRenderer == null || textRenderer.isBuilding()) return false; - textRenderer.begin(scale); - return true; - } - - private static void endTextRenderer(TextRenderer textRenderer, boolean started) { - if (!started || textRenderer == null || !textRenderer.isBuilding()) return; - textRenderer.end(); - } - - private static int lerpColor(int a, int b, float t) { - int aA = (a >>> 24) & 0xFF; - int aR = (a >>> 16) & 0xFF; - int aG = (a >>> 8) & 0xFF; - int aB = a & 0xFF; - int bA = (b >>> 24) & 0xFF; - int bR = (b >>> 16) & 0xFF; - int bG = (b >>> 8) & 0xFF; - int bB = b & 0xFF; - int oA = Math.round(lerp(aA, bA, t)); - int oR = Math.round(lerp(aR, bR, t)); - int oG = Math.round(lerp(aG, bG, t)); - int oB = Math.round(lerp(aB, bB, t)); - return (oA << 24) | (oR << 16) | (oG << 8) | oB; - } - - private static float lerp(float a, float b, float t) { - return a + (b - a) * t; - } - - private static boolean hasOpponentCooldowns(UUID playerId) { - if (playerId == null) return false; - for (Item item : CooldownRegistry.trackedItems()) { - if (OpponentCooldownManager.snapshot(playerId, item).visible()) { - return true; - } - } - return false; - } - - private static String secondsTextInt(float secondsLeft) { - int sec = Math.max(0, (int) Math.ceil(secondsLeft)); - return String.valueOf(sec); - } - - private static boolean pushNameplateScissor(NameplateLayout layout) { - if (layout == null) return false; - Minecraft mc = Minecraft.getInstance(); - if (mc == null || mc.getWindow() == null) return false; - - int sw = mc.getWindow().getScreenWidth(); - int sh = mc.getWindow().getScreenHeight(); - - int x1 = Math.max(0, (int) Math.floor(layout.bgX())); - int y1 = Math.max(0, (int) Math.floor(layout.bgY())); - int x2 = Math.min(sw, (int) Math.ceil(layout.bgX() + layout.bgW())); - int y2 = Math.min(sh, (int) Math.ceil(layout.bgY() + layout.bgH())); - - if (x2 <= x1 || y2 <= y1) return false; - return ScissorFunction.pushRawRect(x1, y1, x2, y2); - } - - private static int computeOpponentStackY(ScreenRect rect, int nameY) { - if (rect != null) { - double rectH = rect.maxY - rect.minY; - double upperCenter = rect.minY + rectH * 0.25; - int target = (int) Math.round(upperCenter - ICON_SIZE * 0.5); - return Math.max(target, nameY + 2); - } - return nameY + OPP_STACK_Y_OFFSET; - } - @Override public HudPhase getHudPhase() { return HudPhase.AFTER_MISC_OVERLAYS; @@ -493,7 +226,7 @@ public class NameTags extends Module { public void onRenderHudEngine(Renderer2D renderer, TextRenderer textRenderer, GuiGraphicsExtractor ctx, float tickDelta) { if (!isEnabled() || mc.level == null || mc.player == null) return; - ensureFontCache(textRenderer); + NameTagRenderer.ensureFontCache(this, textRenderer); StatusEffectView.sync(mc); TotemPopCounter.tick(); @@ -506,7 +239,7 @@ public class NameTags extends Module { boolean wantNameplate = toggles.get("Show nameplate"); boolean wantSlots = toggles.get("Show armor row"); boolean wantEffects = toggles.get("Show effects"); - boolean wantOpponent = opponentAppleCooldowns.get() && isOpponentAppleTrackingEnabled(); + boolean wantOpponent = opponentAppleCooldowns.get() && NameTagOpponentRenderer.isOpponentAppleTrackingEnabled(); if (!wantNameplate && !wantSlots && !wantEffects && !wantOpponent) return; boolean hasUnlimited = false; @@ -569,21 +302,21 @@ public class NameTags extends Module { AABB box = player.getBoundingBox().move(pos.subtract(player.position())); Vec3 anchor = new Vec3(box.getCenter().x, box.maxY + 0.5, box.getCenter().z); - ScreenRect rect = projectBoxScreen(box, tickDelta); + NameTagModel.ScreenRect rect = projectBoxScreen(box, tickDelta); int centerX; int anchorY; if (rect != null) { - centerX = (int) Math.round((rect.minX + rect.maxX) * 0.5); - anchorY = (int) Math.round(rect.minY); + centerX = (int) Math.round((rect.minX() + rect.maxX()) * 0.5); + anchorY = (int) Math.round(rect.minY()); } else { Vec3 screen = ScreenProjection.worldToScreen(anchor, tickDelta); if (screen == null) continue; centerX = (int) screen.x; anchorY = (int) screen.y; } - float distOffset = computeDistanceOffset(dist); - int nameY = computeNameY(rect, anchorY, distOffset); - int sectionLift = Math.round(NAMEPLATE_EXTRA_LIFT) + computeEspNameSectionLift(player); + float distOffset = NameTagLayoutEngine.computeDistanceOffset(dist); + int nameY = NameTagLayoutEngine.computeNameY(rect, anchorY, distOffset); + int sectionLift = Math.round(NAMEPLATE_EXTRA_LIFT) + NameTagLayoutEngine.computeEspNameSectionLift(player); nameY -= sectionLift; boolean renderSlots = wantSlots; @@ -597,14 +330,15 @@ public class NameTags extends Module { if (renderEffects && distanceToggles.get("effects") && dist > effectsDistance.get()) renderEffects = false; TotemPopSnapshot totemPopSnapshot = TotemPopCounter.snapshot(player.getUUID()); - float totemPopAnimation = updateTotemPopAnimation(player, totemPopSnapshot, dt); - int totemPopCount = resolveTotemPopCount(player, totemPopSnapshot, totemPopAnimation); + float totemPopAnimation = NameTagCache.updateTotemPopAnimation(this, player, totemPopSnapshot, dt); + int totemPopCount = NameTagCache.resolveTotemPopCount(this, player, totemPopSnapshot, totemPopAnimation); - LabelInfo labelInfo = renderNameplate ? buildLabelInfo(player) : null; + NameTagModel.LabelInfo labelInfo = renderNameplate ? NameTagLabelBuilder.buildLabelInfo(this, player) : null; int infoColor = labelInfo != null ? labelInfo.infoColor() : INFO_COLOR_DEFAULT; - NameplateLayout nameplateLayout = null; + NameTagModel.NameplateLayout nameplateLayout = null; if (renderNameplate && labelInfo != null) { - nameplateLayout = buildNameplateLayout( + nameplateLayout = NameTagLayoutEngine.buildLayout( + this, player, cachedNameTr != null ? cachedNameTr : textRenderer, cachedHpTr != null ? cachedHpTr : textRenderer, @@ -617,34 +351,34 @@ public class NameTags extends Module { ); } - ItemStack[] slots = renderSlots ? getCachedEquipmentSlots(player) : EMPTY_SLOTS; - List> enchantLines = List.of(); + ItemStack[] slots = renderSlots ? NameTagCache.getCachedEquipmentSlots(this, player) : EMPTY_SLOTS; + List> enchantLines = List.of(); int maxEnchantLines = 0; if (renderSlots) { - EnchantCache cache = resolveEnchantCache(player, slots); + NameTagModel.EnchantCache cache = NameTagCache.resolveEnchantCache(this, player, slots); enchantLines = cache.lines; maxEnchantLines = cache.maxLines; } - List effects = renderEffects ? resolveEffects(player) : List.of(); + List effects = renderEffects ? NameTagCache.resolveEffects(this, player) : List.of(); - int itemsY = computeItemsY(rect, nameY, distOffset); + int itemsY = NameTagLayoutEngine.computeItemsY(rect, nameY, distOffset); itemsY -= sectionLift; - renderQueue.add(new RenderEntry(player, dist, distOffset, centerX, nameY, itemsY, rect, + renderQueue.add(new NameTagModel.RenderEntry(player, dist, distOffset, centerX, nameY, itemsY, rect, renderSlots, renderNameplate, renderEffects, labelInfo, infoColor, nameplateLayout, slots, enchantLines, maxEnchantLines, effects, totemPopCount, totemPopAnimation)); } - pruneCaches(); + NameTagCache.pruneCaches(this); } @Override public void onRenderHudEngineForeground(Renderer2D renderer, TextRenderer textRenderer, GuiGraphicsExtractor ctx, float tickDelta) { if (!isEnabled() || mc.level == null || mc.player == null) return; - ensureFontCache(textRenderer); + NameTagRenderer.ensureFontCache(this, textRenderer); - for (RenderEntry entry : renderQueue) { - renderNameTagForeground(renderer, ctx, textRenderer, entry); + for (NameTagModel.RenderEntry entry : renderQueue) { + NameTagRenderer.renderNameTagForeground(this, renderer, ctx, textRenderer, entry); } } @@ -659,1025 +393,15 @@ public class NameTags extends Module { return !"FreeCamera".equals(name); } - private int computeNameY(ScreenRect rect, int anchorY, float distOffset) { - if (rect != null) { - float rectH = (float) (rect.maxY - rect.minY); - float dynamicGap = Math.max(3f, rectH * 0.06f); - return Math.round((float) rect.minY - dynamicGap - distOffset); - } - return Math.round(anchorY - 7 - distOffset); - } - - private int computeEspNameSectionLift(Player player) { - ESP esp = Modules.get(ESP.class); - if (esp == null || !esp.shouldLiftNameTagsSection(player)) return 0; - return ESP_NAME_SECTION_LIFT; - } - - private int computeItemsY(ScreenRect rect, int nameY, float distOffset) { - int iconSize = equipIconSize(); - if (rect != null) { - float rectH = (float) (rect.maxY - rect.minY); - float itemGap = Math.max(4f, rectH * 0.08f); - return Math.round((float) rect.minY - itemGap - iconSize - 6 - distOffset); - } - return Math.round(nameY - iconSize - 6 - distOffset); - } - - private float computeDistanceOffset(double dist) { - float d = (float) Math.max(0.0, dist); - float range = Math.max(1f, NAMEPLATE_LIFT_RANGE); - float max = Math.max(0f, NAMEPLATE_LIFT_MAX); - float power = Mth.clamp(NAMEPLATE_LIFT_POWER, 1, 6); - float t = Mth.clamp(d / range, 0f, 1f); - float eased = 1.0f - (float) Math.pow(1.0f - t, power); - return max * eased; - } - - private boolean isMatteNameplate() { - return nameplateStyle.get() == NameplateStyle.MATTE; - } - - private void drawNameplateBackground(Renderer2D renderer, Player player, NameplateLayout layout) { - if (layout == null) return; - int alpha = clampAlpha(nameplateAlpha.get()); - if (alpha <= 0) return; - - float globalAlpha = alpha / 255.0f; - if (isMatteNameplate()) { - MatteHudStyle.drawPlate(renderer, layout.bgX(), layout.bgY(), layout.bgW(), layout.bgH(), nameplateRadius(layout), globalAlpha); - return; - } - - float radius = nameplateRadius(layout); - Renderer2D.COLOR.liquidGlassRect( - layout.bgX(), - layout.bgY(), - layout.bgW(), - layout.bgH(), - radius, - NAMEPLATE_GLASS_THICKNESS, - NAMEPLATE_GLASS_TINT, - globalAlpha, - NAMEPLATE_GLASS_FRESNEL_POWER, - NAMEPLATE_GLASS_FRESNEL_ALPHA, - NAMEPLATE_GLASS_BASE_ALPHA, - NAMEPLATE_GLASS_FRESNEL_MIX, - NAMEPLATE_GLASS_DISTORT, - 0.0f - ); - renderer.roundedRect( - layout.bgX(), - layout.bgY(), - layout.bgW(), - layout.bgH(), - radius, - 1.0f, - HudRenderUtil.scaleAlpha(NAMEPLATE_GLASS_VEIL, globalAlpha) - ); - } - - private float nameplateRadius(NameplateLayout layout) { - if (layout == null) return isMatteNameplate() ? MATTE_NAMEPLATE_RADIUS : NAMEPLATE_RADIUS; - if (isMatteNameplate()) { - return Math.min(MATTE_NAMEPLATE_RADIUS, Math.max(2.5f, layout.bgH() * 0.30f)); - } - return Math.min(NAMEPLATE_RADIUS, Math.max(4.5f, layout.bgH() * 0.5f)); - } - - private boolean shouldRenderPlayerHead(Player player) { - return playerHead.get() && player instanceof AbstractClientPlayer; - } - - private NameplateLayout buildNameplateLayout(Player player, TextRenderer nameRenderer, TextRenderer hpRenderer, LabelInfo info, - double dist, int centerX, int nameY, - int totemPopCount, float totemPopAnimation) { - if (info == null) return null; - float labelScale = NAMEPLATE_SCALE; - String prefix = info.pvpPrefix(); - String name = info.name(); - String hp = formatNameplateHp(info.hp()); - String pingText = info.pingText(); - int pingWidth = pingText.isEmpty() ? 0 : (int) (nameRenderer.getWidth(pingText) * labelScale); - int pingGap = pingWidth > 0 ? PING_TEXT_GAP : 0; - double prefixWidth = prefix.isEmpty() ? 0.0 : nameRenderer.getWidth(prefix); - double rawNameWidth = info.styledName() != null - ? measureStyledWidth(nameRenderer, info.styledName(), CategoryService.getColor(player)) - : nameRenderer.getWidth(name); - int nameWidth = (int) ((prefixWidth + rawNameWidth) * labelScale); - int hpWidth = hp == null || hp.isEmpty() ? 0 : (int) (hpRenderer.getWidth(hp) * labelScale); - int hpGap = hpWidth > 0 ? HP_TEXT_GAP : 0; - boolean showDist = shouldShowDistanceText(player); - String distText = showDist ? (int) Math.round(dist) + "m" : ""; - int distWidth = showDist ? (int) (nameRenderer.getWidth(distText) * labelScale) : 0; - int distGap = distWidth > 0 ? DIST_TEXT_GAP : 0; - int nameHeight = (int) (nameRenderer.getHeight() * labelScale); - boolean renderHead = shouldRenderPlayerHead(player); - float headSize = renderHead ? Math.max(MATTE_HEAD_MIN_SIZE, nameHeight + NAMEPLATE_PAD_Y * 1.5f) : 0.0f; - float headBlock = renderHead - ? headSize + MATTE_HEAD_DIVIDER_GAP + MATTE_HEAD_DIVIDER_WIDTH + MATTE_HEAD_TEXT_GAP - : 0.0f; - int textWidth = pingWidth + pingGap + nameWidth + hpGap + hpWidth + distGap + distWidth; - int scaledHeight = Math.max(nameHeight, renderHead ? Math.round(headSize) : nameHeight); - boolean renderTotemBadge = totemPopCounter.get() && totemPopCount > 0 && totemPopAnimation > 0.001f; - String totemText = renderTotemBadge ? "x" + totemPopCount : ""; - float totemIconSize = renderTotemBadge - ? Math.min(TOTEM_BADGE_ICON_SIZE, Math.max(8.0f, scaledHeight - 2.0f)) - : 0.0f; - float totemTextWidth = renderTotemBadge - ? (float) hpRenderer.getWidth(totemText) * TOTEM_BADGE_TEXT_SCALE - : 0.0f; - float totemBadgeHeight = renderTotemBadge ? scaledHeight : 0.0f; - float totemBadgeWidth = renderTotemBadge - ? totemIconSize + TOTEM_BADGE_TEXT_GAP + totemTextWidth - : 0.0f; - float totemBlock = renderTotemBadge - ? TOTEM_BADGE_GAP + TOTEM_BADGE_DIVIDER_WIDTH + TOTEM_BADGE_DIVIDER_GAP + totemBadgeWidth - : 0.0f; - int totalWidth = Math.round(headBlock + textWidth + totemBlock); - int scaledWidth = totalWidth; - int contentX = centerX - scaledWidth / 2; - int nameX = Math.round(contentX + headBlock); - - float bgX = contentX - NAMEPLATE_PAD_X; - float bgY = nameY - NAMEPLATE_PAD_Y; - float bgW = scaledWidth + NAMEPLATE_PAD_X * 2f; - float bgH = scaledHeight + NAMEPLATE_PAD_Y * 2f; - float headX = contentX; - float headY = nameY + (scaledHeight - headSize) * 0.5f; - float dividerX = headX + headSize + MATTE_HEAD_DIVIDER_GAP; - float dividerH = Math.max(3.0f, bgH * 0.48f); - float dividerY = bgY + (bgH - dividerH) * 0.5f; - float totemDividerX = renderTotemBadge ? contentX + headBlock + textWidth + TOTEM_BADGE_GAP : 0.0f; - float totemDividerH = renderTotemBadge ? Math.max(3.0f, bgH * 0.48f) : 0.0f; - float totemDividerY = renderTotemBadge ? bgY + (bgH - totemDividerH) * 0.5f : 0.0f; - float totemBadgeX = renderTotemBadge ? totemDividerX + TOTEM_BADGE_DIVIDER_WIDTH + TOTEM_BADGE_DIVIDER_GAP : 0.0f; - float totemBadgeY = renderTotemBadge ? nameY : 0.0f; - - return new NameplateLayout(nameX, nameY, scaledWidth, scaledHeight, labelScale, pingText, distText, bgX, bgY, bgW, bgH, - pingWidth, pingGap, nameWidth, hpWidth, hpGap, renderHead, headX, headY, headSize, - dividerX, dividerY, MATTE_HEAD_DIVIDER_WIDTH, dividerH, - renderTotemBadge, totemDividerX, totemDividerY, TOTEM_BADGE_DIVIDER_WIDTH, totemDividerH, - totemBadgeX, totemBadgeY, totemBadgeWidth, totemBadgeHeight, totemIconSize); - } - - private void renderNameTagForeground(Renderer2D renderer, GuiGraphicsExtractor ctx, TextRenderer textRenderer, RenderEntry entry) { - Player player = entry.player(); - int centerX = entry.centerX(); - int nameY = entry.nameY(); - int itemsY = entry.itemsY(); - float distOffset = entry.distOffset(); - ScreenRect rect = entry.rect(); - - if (entry.renderNameplate() && entry.nameplateLayout() != null) { - drawNameplateBackground(renderer, player, entry.nameplateLayout()); - drawNameplateHead(renderer, ctx, player, entry.nameplateLayout()); - } - - final int effectsLift = scaleRow(computeEnchantLift(textRenderer, entry.maxEnchantLines())); - - if (entry.renderSlots()) { - drawEquipmentRow(ctx, entry.player(), entry.slots(), centerX, itemsY); - } - - if (entry.renderEffects()) { - EffectIconRenderer.beginBatch(); - drawEffectsRowIcons(ctx, entry.effects(), centerX, itemsY, effectsLift); - EffectIconRenderer.endBatch(); - } - - drawOpponentCooldownsStackedIcons(ctx, player, rect, centerX, nameY, distOffset); - - boolean startedBaseText = beginTextRenderer(textRenderer, SMALL_TEXT_SCALE); - try { - if (entry.renderSlots()) { - drawEquipmentRowText(textRenderer, entry.slots(), entry.enchantLines(), centerX, itemsY); - } - - if (entry.renderEffects()) { - TextRenderer levelTr = cachedLevelTr != null ? cachedLevelTr : textRenderer; - TextRenderer timeTr = cachedTimeTr != null ? cachedTimeTr : textRenderer; - drawEffectsRowIconOverlays(textRenderer, levelTr, timeTr, entry.effects(), entry.player().getId(), centerX, itemsY, effectsLift); - } - - drawOpponentCooldownsStackedText(textRenderer, player, rect, centerX, nameY, distOffset); - } finally { - endTextRenderer(textRenderer, startedBaseText); - } - - if (entry.renderNameplate() && entry.labelInfo() != null) { - LabelInfo info = entry.labelInfo(); - NameplateLayout layout = entry.nameplateLayout(); - if (layout != null) { - TextRenderer nameTr = cachedNameTr != null ? cachedNameTr : textRenderer; - TextRenderer hpTr = cachedHpTr != null ? cachedHpTr : nameTr; - boolean clipped = pushNameplateScissor(layout); - float scale = layout.labelScale(); - double nameX = layout.nameX(); - boolean startedName = beginTextRenderer(nameTr, scale); - double cursorX = nameX; - try { - if (!layout.pingText().isEmpty()) { - renderNameplateText(nameTr, layout.pingText(), cursorX, nameY, resolvePingColor(info.ping())); - cursorX += layout.pingWidth() + layout.pingGap(); - } - String prefix = info.pvpPrefix(); - if (!prefix.isEmpty()) { - renderNameplateText(nameTr, prefix, cursorX, nameY, pvpPrefixColor.getArgb()); - cursorX += nameTr.getWidth(prefix); - } - if (shouldUseTabNames()) { - renderStyledNameplateText(nameTr, info.styledName(), cursorX, nameY, CategoryService.getColor(player)); - } else { - renderNameplateText(nameTr, info.name(), cursorX, nameY, CategoryService.getColor(player)); - } - } finally { - endTextRenderer(nameTr, startedName); - } - - if (!info.hp().isEmpty()) { - double hpX = nameX + layout.pingWidth() + layout.pingGap() + layout.nameWidth() + layout.hpGap(); - boolean startedHp = beginTextRenderer(hpTr, scale); - try { - renderNameplateText(hpTr, formatNameplateHp(info.hp()), hpX, nameY, entry.infoColor()); - } finally { - endTextRenderer(hpTr, startedHp); - } - } - - if (!layout.distText().isEmpty()) { - double distX = nameX + layout.pingWidth() + layout.pingGap() + layout.nameWidth() + layout.hpGap() + layout.hpWidth() - + (layout.hpWidth() > 0 ? DIST_TEXT_GAP : 0); - boolean startedDist = beginTextRenderer(nameTr, scale); - try { - renderNameplateText(nameTr, layout.distText(), distX, nameY, 0xFFD0D0D0); - } finally { - endTextRenderer(nameTr, startedDist); - } - } - if (clipped) ScissorFunction.pop(); - drawNameplateTotemBadge(renderer, textRenderer, layout, entry.totemPopCount(), entry.totemPopAnimation()); - } - } - } - - private void drawNameplateTotemBadge(Renderer2D renderer, - TextRenderer fallbackRenderer, - NameplateLayout layout, - int count, - float animation) { - if (renderer == null || layout == null || !layout.renderTotemBadge()) return; - if (count <= 0 || animation <= 0.001f) return; - - float anim = AnimationUtility.easeInOutCubic(animation); - float globalAlpha = (clampAlpha(nameplateAlpha.get()) / 255.0f) * anim; - if (globalAlpha <= 0.001f) return; - - drawNameplateDivider( - renderer, - layout.totemDividerX(), - layout.totemDividerY(), - layout.totemDividerW(), - layout.totemDividerH(), - globalAlpha - ); - - float blockX = layout.totemBadgeX(); - float blockY = layout.totemBadgeY(); - float blockH = layout.totemBadgeH(); - float iconScale = 0.86f + 0.14f * anim; - float iconSize = Math.max(1.0f, layout.totemIconSize() * iconScale); - float iconX = blockX; - float iconY = blockY + (blockH - iconSize) * 0.5f; - renderer.item(totemBadgeStack(), iconX, iconY, Math.max(0.1f, iconSize / 16.0f), 911, Renderer2D.ITEM_OVERLAY_NONE, null); - - String text = "x" + count; - TextRenderer badgeRenderer = Fonts.renderer("Inter", FontInfo.Type.Bold, fallbackRenderer); - float textScale = TOTEM_BADGE_TEXT_SCALE * (0.94f + 0.06f * anim); - float textX = iconX + iconSize + TOTEM_BADGE_TEXT_GAP; - float textH = (float) badgeRenderer.getHeight(false) * textScale; - float textY = blockY + (blockH - textH) * 0.5f - 0.1f; - int textColor = HudRenderUtil.setAlpha(theme().textPrimary(), Math.round(255.0f * globalAlpha)); - - badgeRenderer.begin(textScale, false, false); - try { - if (globalAlpha > 0.96f) { - int baseColor = textColor; - int darkColor = HudRenderUtil.mixColor(baseColor, HudRenderUtil.setAlpha(0xFF181B1F, Math.round(255.0f * globalAlpha)), 0.18f); - int lightColor = HudRenderUtil.mixColor(baseColor, HudRenderUtil.setAlpha(theme().accentSoft(), Math.round(255.0f * globalAlpha)), 0.24f); - float time = (float) (net.minecraft.util.Util.getMillis() / 1000.0); - float pulse = time * 2.35f; - badgeRenderer.renderGradient(text, textX, textY, (idx, cp, gx, out) -> { - float p = pulse + idx * 0.62f; - float t0 = 0.5f + 0.5f * (float) Math.sin(p); - float t1 = 0.5f + 0.5f * (float) Math.sin(p + 1.05f); - out[0] = HudRenderUtil.mixColor(darkColor, lightColor, t0); - out[1] = HudRenderUtil.mixColor(darkColor, lightColor, t1); - }, false); - } else { - badgeRenderer.render(text, textX, textY, new RenderColor(textColor), false); - } - } finally { - badgeRenderer.end(); - } - } - - private void drawNameplateHead(Renderer2D renderer, GuiGraphicsExtractor ctx, Player player, NameplateLayout layout) { - if (ctx == null || layout == null || !layout.renderHead()) return; - if (!(player instanceof AbstractClientPlayer clientPlayer)) return; - - int alpha = clampAlpha(nameplateAlpha.get()); - if (alpha <= 0) return; - float globalAlpha = alpha / 255.0f; - - PlayerHeadRenderer.drawRounded( - ctx, - layout.headX(), - layout.headY(), - layout.headSize(), - Math.min(6.0f, layout.headSize() * 0.48f), - clientPlayer, - new RenderColor(MatteHudStyle.withAlpha(0xFFFFFFFF, alpha)), - true, - null, - 0.0f, - false - ); - - drawNameplateDivider( - renderer, - layout.dividerX(), - layout.dividerY(), - layout.dividerW(), - layout.dividerH(), - globalAlpha - ); - } - - private void drawNameplateDivider(Renderer2D renderer, - float x, - float y, - float width, - float height, - float globalAlpha) { - if (renderer == null || width <= 0.0f || height <= 0.0f || globalAlpha <= 0.001f) return; - int color = isMatteNameplate() - ? MatteHudStyle.strokeColor(globalAlpha * 0.82f) - : MatteHudStyle.withAlpha(0xFFFFFF, Math.round(58.0f * globalAlpha)); - float drawWidth = Math.max(0.8f, width); - renderer.roundedRect( - x + (width - drawWidth) * 0.5f, - y, - drawWidth, - height, - Math.min(drawWidth, height) * 0.5f, - 0.0f, - color - ); - } - - private void ensureFontCache(TextRenderer fallback) { - cachedNameTr = Fonts.renderer("OnestBold", FontInfo.Type.Regular, fallback); - cachedHpTr = Fonts.renderer("OnestMedium", FontInfo.Type.Regular, cachedNameTr); - cachedLevelTr = Fonts.renderer("OnestBold", FontInfo.Type.Regular, fallback); - cachedTimeTr = Fonts.renderer("OnestMedium", FontInfo.Type.Regular, fallback); - } - public void onResourceReload() { cachedNameTr = null; cachedHpTr = null; cachedLevelTr = null; cachedTimeTr = null; - enchantCache.clear(); + NameTagCache.clearCaches(this); } - private boolean shouldShowDistanceText(Player player) { - if (!toggles.get("Show distance")) return false; - if (player == null || mc.player == null) return false; - if (player != mc.player) return true; - Freecam freecam = Modules.get(Freecam.class); - return freecam != null && freecam.isEnabled(); - } - - private ItemStack[] getCachedEquipmentSlots(Player player) { - UUID id = player.getUUID(); - ItemStack[] slots = slotCache.computeIfAbsent(id, key -> new ItemStack[6]); - slots[0] = player.getMainHandItem(); - slots[1] = player.getItemBySlot(EquipmentSlot.FEET); - slots[2] = player.getItemBySlot(EquipmentSlot.LEGS); - slots[3] = player.getItemBySlot(EquipmentSlot.CHEST); - slots[4] = player.getItemBySlot(EquipmentSlot.HEAD); - slots[5] = player.getOffhandItem(); - return slots; - } - - private List resolveEffects(Player player) { - UUID id = player.getUUID(); - EffectCache cache = effectCache.computeIfAbsent(id, key -> new EffectCache()); - int tick = player.tickCount; - if (tick - cache.lastTick >= EFFECT_CACHE_TICKS || cache.effects.isEmpty()) { - cache.effects = collectEffects(player); - cache.lastTick = tick; - } - return cache.effects; - } - - private EnchantCache resolveEnchantCache(Player player, ItemStack[] slots) { - UUID id = player.getUUID(); - EnchantCache cache = enchantCache.computeIfAbsent(id, key -> new EnchantCache()); - int tick = player.tickCount; - int signature = equipmentSignature(slots); - if (signature != cache.signature - || tick - cache.lastTick >= ENCHANT_CACHE_TICKS - || cache.lines.isEmpty()) { - List> lines = buildEnchantLines(slots); - cache.lines = lines; - cache.maxLines = maxEnchantLines(lines); - cache.lastTick = tick; - cache.signature = signature; - } - return cache; - } - - private float updateTotemPopAnimation(Player player, TotemPopSnapshot snapshot, float dt) { - if (player == null) return 0.0f; - UUID id = player.getUUID(); - boolean visible = snapshot != null && snapshot.visible(); - if (visible) { - totemPopLastCounts.put(id, snapshot.count()); - } - - float current = totemPopAnimations.getOrDefault(id, 0.0f); - float target = visible ? 1.0f : 0.0f; - float next = AnimationUtility.approach(current, target, dt, TOTEM_BADGE_ANIM_SPEED); - next = AnimationUtility.snap(next, target, 0.001f); - - if (next <= 0.001f && !visible) { - totemPopAnimations.remove(id); - totemPopLastCounts.remove(id); - return 0.0f; - } - - totemPopAnimations.put(id, next); - return next; - } - - private int resolveTotemPopCount(Player player, TotemPopSnapshot snapshot, float animation) { - if (player == null) return 0; - if (snapshot != null && snapshot.visible()) { - return snapshot.count(); - } - if (animation > 0.001f) { - return Math.max(0, totemPopLastCounts.getOrDefault(player.getUUID(), 0)); - } - return 0; - } - - private void pruneCaches() { - if (seenIds.isEmpty()) { - slotCache.clear(); - effectCache.clear(); - enchantCache.clear(); - totemPopAnimations.clear(); - totemPopLastCounts.clear(); - return; - } - slotCache.keySet().removeIf(id -> !seenIds.contains(id)); - effectCache.keySet().removeIf(id -> !seenIds.contains(id)); - enchantCache.keySet().removeIf(id -> !seenIds.contains(id)); - totemPopAnimations.keySet().removeIf(id -> !seenIds.contains(id)); - totemPopLastCounts.keySet().removeIf(id -> !seenIds.contains(id)); - } - - private void drawEquipmentRow(GuiGraphicsExtractor ctx, Player player, ItemStack[] slots, int centerX, int y) { - int iconSize = equipIconSize(); - int gap = equipIconGap(); - int rowWidth = slots.length * (iconSize + gap) - gap; - int startX = centerX - rowWidth / 2; - int seed = 0; - - for (int i = 0; i < slots.length; i++) { - ItemStack stack = slots[i]; - int x = startX + i * (iconSize + gap); - if (stack.isEmpty()) continue; - - float scale = iconSize / 16f; - int overlayFlags = Renderer2D.ITEM_OVERLAY_COUNT; - if (toggles.get("Item durability bar")) { - overlayFlags |= Renderer2D.ITEM_OVERLAY_DURABILITY; - } - Renderer2D.COLOR.item(stack, x, y, scale, seed++, overlayFlags, null, - durabilityStartPercent.get(), 70); - drawOpponentItemCooldown(player, stack, x, y, scale); - } - } - - private void drawOpponentItemCooldown(Player player, ItemStack stack, float x, float y, float scale) { - if (!shouldRenderOpponentStuff(player)) return; - if (stack == null || stack.isEmpty()) return; - - Item item = stack.getItem(); - if (!CooldownRegistry.isTracked(item)) return; - - ItemCooldownSnapshot snapshot = OpponentCooldownManager.snapshot(player.getUUID(), item); - if (!snapshot.visible()) return; - float progress = snapshot.cooling() ? snapshot.cooldownProgress() : snapshot.usesProgress(); - if (progress <= 0f) return; - - int top = Mth.floor(16.0F * (1.0F - progress)); - int bottom = top + Mth.ceil(16.0F * progress); - Renderer2D.COLOR.quad( - x, - y + top * scale, - 16.0f * scale, - (bottom - top) * scale, - snapshot.cooling() ? 0x80FFA500 : 0x706D9DFF - ); - - // no text inside slot - } - - private void drawEquipmentRowText(TextRenderer textRenderer, ItemStack[] slots, List> enchantLines, - int centerX, int y) { - int iconSize = equipIconSize(); - int gap = equipIconGap(); - int rowWidth = slots.length * (iconSize + gap) - gap; - int startX = centerX - rowWidth / 2; - - for (int i = 0; i < slots.length; i++) { - ItemStack stack = slots[i]; - int x = startX + i * (iconSize + gap); - if (stack.isEmpty()) continue; - - List ench = enchantLines.get(i); - if (!ench.isEmpty()) { - int lineHeight = (int) textRenderer.getHeight(true) + 1; - int startY = y - 14; - for (int idx = 0; idx < ench.size(); idx++) { - EnchantLine line = ench.get(idx); - int lineY = startY - idx * lineHeight; - int textX = x + iconSize / 2 - (int) textRenderer.getWidth(line.text(), true) / 2; - renderEquipmentText(textRenderer, line.text(), textX, lineY, line.color()); - } - } - - } - } - - private void renderEquipmentText(TextRenderer textRenderer, String text, double x, double y, int color) { - RenderColor shadow = new RenderColor(0xB0000000); - double o = ENCHANT_TEXT_SHADOW_OFFSET; - textRenderer.render(text, x + o, y, shadow, false); - textRenderer.render(text, x - o, y, shadow, false); - textRenderer.render(text, x, y + o, shadow, false); - textRenderer.render(text, x, y - o, shadow, false); - textRenderer.render(text, x, y, new RenderColor(color), false); - } - - private void renderNameplateText(TextRenderer textRenderer, String text, double x, double y, int color) { - if (text == null || text.isEmpty()) return; - if (NAMEPLATE_TEXT_SHADOW_OFFSET > 0.001f) { - RenderColor shadow = new RenderColor(0x42000000); - double o = NAMEPLATE_TEXT_SHADOW_OFFSET; - textRenderer.render(text, x + o, y, shadow, false); - textRenderer.render(text, x - o, y, shadow, false); - textRenderer.render(text, x, y + o, shadow, false); - textRenderer.render(text, x, y - o, shadow, false); - } - textRenderer.render(text, x, y, new RenderColor(color), false); - } - - private void renderStyledNameplateText(TextRenderer textRenderer, Component text, double x, double y, int defaultColor) { - if (text == null) return; - List parts = TextRenderUtil.flattenStyled(text, defaultColor); - double cursorX = x; - for (TextRenderUtil.Part part : parts) { - renderNameplateText(textRenderer, part.text(), cursorX, y, part.color()); - cursorX += textRenderer.getWidth(part.text()); - } - } - - private boolean shouldUseTabNames() { - return nameplateExtras.get("Tab names"); - } - - private boolean shouldShowPingText() { - return nameplateExtras.get("Ping"); - } - - private int getPlayerPing(Player player) { - if (player == null || mc == null || mc.getConnection() == null) return -1; - PlayerInfo entry = mc.getConnection().getPlayerInfo(player.getUUID()); - return entry != null ? entry.getLatency() : -1; - } - - private void drawEffectsIcons(GuiGraphicsExtractor ctx, List effects, int x, int y) { - if (effects.isEmpty()) return; - - int cursorY = y; - EffectIconRenderer.beginBatch(); - for (MobEffectInstance inst : effects) { - EffectIconRenderer.draw(ctx, inst, x, cursorY, ICON_SIZE); - cursorY += EFFECT_LINE_HEIGHT; - } - EffectIconRenderer.endBatch(); - } - - private void drawEffectsText(TextRenderer textRenderer, List effects, int entityId, int x, int y) { - if (effects.isEmpty()) return; - - int cursorY = y; - for (MobEffectInstance inst : effects) { - int textX = x + ICON_SIZE + 6; - int textY = cursorY + 4; - String dur = formatDuration(entityId, inst); - String name = I18n.get(inst.getEffect().value().getDescriptionId()); - int level = inst.getAmplifier() + 1; - - if (!dur.isEmpty()) { - String seg = dur + " "; - textRenderer.render(seg, textX, textY, new RenderColor(0xFFFFFFFF), true); - textX += (int) textRenderer.getWidth(seg, true); - } - textRenderer.render(name, textX, textY, new RenderColor(0xFFFFFFFF), true); - textX += (int) textRenderer.getWidth(name, true); - if (level > 1) { - String lvl = " " + level; - textRenderer.render(lvl, textX, textY, new RenderColor(EFFECT_LEVEL_COLOR), true); - } - cursorY += EFFECT_LINE_HEIGHT; - } - } - - private void drawEffectIconOverlays(TextRenderer baseRenderer, TextRenderer levelRenderer, TextRenderer timeRenderer, - List effects, int entityId, int x, int y) { - if (effects.isEmpty()) return; - - TextRenderer levelTr = levelRenderer == null ? baseRenderer : levelRenderer; - TextRenderer timeTr = timeRenderer == null ? baseRenderer : timeRenderer; - - boolean startedLevel = beginTextRenderer(levelTr, SMALL_TEXT_SCALE); - boolean startedTime = timeTr != levelTr && beginTextRenderer(timeTr, SMALL_TEXT_SCALE); - - int levelHeight = (int) levelTr.getHeight(true); - int timeHeight = (int) timeTr.getHeight(true); - int levelGap = scaleRow(EFFECT_ROW_LEVEL_GAP); - int timeGap = scaleRow(EFFECT_ROW_TIME_GAP); - - int cursorY = y; - for (MobEffectInstance inst : effects) { - int level = inst.getAmplifier() + 1; - String dur = formatDuration(entityId, inst); - - int iconX = x; - int iconY = cursorY; - - if (!dur.isEmpty()) { - int timeW = (int) timeTr.getWidth(dur, true); - int timeX = iconX + (ICON_SIZE - timeW) / 2; - int timeY = iconY - timeHeight - 1; - timeTr.render(dur, timeX, timeY, new RenderColor(EFFECT_TIME_COLOR), true); - } - - if (level > 1) { - String lvl = String.valueOf(level); - int levelW = (int) levelTr.getWidth(lvl, true); - int levelX = iconX + (ICON_SIZE - levelW) / 2; - int levelY = !dur.isEmpty() - ? (iconY - timeHeight - 1 - levelHeight - 1) - : (iconY - levelHeight - 1); - levelTr.render(lvl, levelX, levelY, new RenderColor(EFFECT_LEVEL_STACK_COLOR), true); - } - cursorY += EFFECT_LINE_HEIGHT; - } - - endTextRenderer(levelTr, startedLevel); - endTextRenderer(timeTr, startedTime); - } - - private void drawEffectsRowIconOverlays(TextRenderer baseRenderer, TextRenderer levelRenderer, TextRenderer timeRenderer, - List effects, int entityId, int centerX, int itemsY, int lift) { - if (effects.isEmpty()) return; - - TextRenderer levelTr = levelRenderer == null ? baseRenderer : levelRenderer; - TextRenderer timeTr = timeRenderer == null ? baseRenderer : timeRenderer; - - float rowTextScale = SMALL_TEXT_SCALE * EFFECT_ROW_SCALE; - boolean startedLevel = beginTextRenderer(levelTr, rowTextScale); - boolean startedTime = timeTr != levelTr && beginTextRenderer(timeTr, rowTextScale); - - int levelHeight = (int) levelTr.getHeight(true); - int timeHeight = (int) timeTr.getHeight(true); - int levelGap = scaleRow(EFFECT_ROW_LEVEL_GAP); - int timeGap = scaleRow(EFFECT_ROW_TIME_GAP); - - int count = effects.size(); - int iconSize = scaleRow(ICON_SIZE); - int gap = scaleRow(EFFECT_ROW_ICON_GAP); - int rowGap = scaleRow(EFFECT_ROW_GAP); - int rowW = count * iconSize + Math.max(0, count - 1) * gap; - int startX = centerX - rowW / 2; - int iconY = itemsY - iconSize - rowGap - lift; - - for (int i = 0; i < effects.size(); i++) { - MobEffectInstance inst = effects.get(i); - int level = inst.getAmplifier() + 1; - String dur = formatDuration(entityId, inst); - - int iconX = startX + i * (iconSize + gap); - - if (!dur.isEmpty()) { - int timeW = (int) timeTr.getWidth(dur, true); - int timeX = iconX + (iconSize - timeW) / 2; - int timeY = (level > 1) - ? (iconY - levelHeight - levelGap - timeHeight - timeGap) - : (iconY - timeHeight - levelGap); - timeTr.render(dur, timeX, timeY, new RenderColor(EFFECT_TIME_COLOR), true); - } - - if (level > 1) { - String lvl = roman(level); - int levelW = (int) levelTr.getWidth(lvl, true); - int levelX = iconX + (iconSize - levelW) / 2; - int levelY = iconY - levelHeight - levelGap; - levelTr.render(lvl, levelX, levelY, new RenderColor(EFFECT_LEVEL_STACK_COLOR), true); - } - } - - endTextRenderer(levelTr, startedLevel); - endTextRenderer(timeTr, startedTime); - } - - private void drawEffectsRowIcons(GuiGraphicsExtractor ctx, List effects, int centerX, int itemsY, int lift) { - if (effects.isEmpty()) return; - int count = effects.size(); - int iconSize = scaleRow(ICON_SIZE); - int gap = scaleRow(EFFECT_ROW_ICON_GAP); - int rowGap = scaleRow(EFFECT_ROW_GAP); - int rowW = count * iconSize + Math.max(0, count - 1) * gap; - int startX = centerX - rowW / 2; - int y = itemsY - iconSize - rowGap - lift; - - for (int i = 0; i < effects.size(); i++) { - int x = startX + i * (iconSize + gap); - EffectIconRenderer.draw(ctx, effects.get(i), x, y, iconSize); - } - } - - private int computeEnchantLift(TextRenderer textRenderer, int maxLines) { - if (!toggles.get("Show armor row")) return 0; - if (maxLines <= 0) return 6; - int lineHeight = (int) Math.round(textRenderer.getHeight(true) * SMALL_TEXT_SCALE) + 1; - return 6 + maxLines * lineHeight; - } - - private LabelInfo buildLabelInfo(Player player) { - Component styledName = resolveNameplateText(player); - String name = styledName == null ? "" : styledName.getString(); - String prefix = ""; - if (pvpPrefix.get() && PvpTargetState.isTargetInPvp(player.getUUID())) { - prefix = "[PVP] "; - } - int ping = getPlayerPing(player); - String pingText = shouldShowPingText() && ping >= 0 ? ping + "ms" : ""; - if (isCreative(player)) { - return new LabelInfo(prefix, styledName, name, ping, pingText, "GM", PlayerRelations.get().colorStaff()); - } - PlayerHealthResolver.HealthSnapshot health = PlayerHealthResolver.resolve(player); - String hp = formatHealth(health.totalHealth()); - int color = resolveHealthColor(health.totalHealth(), health.maxHealth()); - return new LabelInfo(prefix, styledName, name, ping, pingText, hp, color); - } - - private Component resolveNameplateText(Player player) { - if (player == null) return Component.empty(); - String fallback = player.getGameProfile().name(); - if (!shouldUseTabNames()) return Component.literal(fallback); - - var handler = mc.getConnection(); - if (handler == null) return Component.literal(fallback); - PlayerInfo entry = handler.getPlayerInfo(player.getUUID()); - if (entry == null) return Component.literal(fallback); - - Component displayName = entry.getTabListDisplayName(); - if (displayName == null) return Component.literal(fallback); - - Component parsed = LegacyTextUtil.convertLegacyCodes(displayName); - if (parsed == null || parsed.getString().isBlank()) return Component.literal(fallback); - return parsed; - } - - private String formatHealth(float hp) { - if (hpDecimals.get()) { - return formatTenths(hp); - } - int value = (int) Math.ceil(hp); - return String.valueOf(value); - } - - private float totalHealth(Player player) { - return PlayerHealthResolver.resolve(player).totalHealth(); - } - - private float maxTotalHealth(Player player) { - return PlayerHealthResolver.resolve(player).maxHealth(); - } - - private String formatTenths(float value) { - int tenth = Math.round(value * 10f); - int whole = tenth / 10; - int frac = Math.abs(tenth % 10); - return whole + "." + frac; - } - - private int resolveHealthColor(float current, float max) { - if (current > max) return HP_CYAN; - if ("Static".equalsIgnoreCase(hpColorMode.get())) { - return HP_GREEN; - } - return gradientHealthColor(current, max); - } - - private int gradientHealthColor(float current, float max) { - if (max <= 0f) return HP_RED; - float clamped = Mth.clamp(current, 0f, max); - if (max <= 20f) { - float t = clamped / max; - return lerpColor(HP_RED, HP_GREEN, t); - } - if (clamped <= 20f) { - float t = clamped / 20f; - return lerpColor(HP_RED, HP_GREEN, t); - } - float t = (clamped - 20f) / (max - 20f); - return lerpColor(HP_GREEN, HP_CYAN, Mth.clamp(t, 0f, 1f)); - } - - private boolean isCreative(Player player) { - if (player.isCreative()) return true; - var handler = mc.getConnection(); - if (handler == null) return false; - PlayerInfo entry = handler.getPlayerInfo(player.getUUID()); - if (entry == null) return false; - GameType mode = entry.getGameMode(); - return mode == GameType.CREATIVE; - } - - private String formatEffectText(int entityId, MobEffectInstance inst) { - String name = I18n.get(inst.getEffect().value().getDescriptionId()); - int level = inst.getAmplifier() + 1; - if (level > 1) name = name + " " + level; - String dur = formatDuration(entityId, inst); - return dur.isEmpty() ? name : dur + " " + name; - } - - private String formatDuration(int entityId, MobEffectInstance inst) { - if (StatusEffectTracker.shouldHideDuration(entityId, inst.getEffect())) return ""; - int ticks = inst.getDuration(); - if (ticks < 0 || ticks >= 32767) return ""; - int totalSeconds = Math.max(0, ticks / 20); - int minutes = totalSeconds / 60; - int seconds = totalSeconds % 60; - if (seconds < 10) return minutes + ":0" + seconds; - return minutes + ":" + seconds; - } - - private List collectEffects(Player player) { - return StatusEffectView.collectHudEffects(player); - } - - private String roman(int n) { - if (n <= 0) return String.valueOf(n); - int value = n; - StringBuilder sb = new StringBuilder(); - int[] vals = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; - String[] syms = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; - for (int i = 0; i < vals.length; i++) { - while (value >= vals[i]) { - value -= vals[i]; - sb.append(syms[i]); - } - } - return sb.toString(); - } - - private List formatEnchantments(ItemStack stack) { - List parts = new ArrayList<>(); - - ItemEnchantments enchComp = EnchantmentHelper.getEnchantmentsForCrafting(stack); - for (Object2IntMap.Entry> entry : enchComp.entrySet()) { - Holder ref = entry.getKey(); - int level = entry.getIntValue(); - if (level <= 0) continue; - - ResourceKey key = ref.unwrapKey().orElse(null); - if (key == null) continue; - - EnchantMeta meta = EnchantRegistry.REGISTRY.get(key); - if (meta == null) continue; - - Enchantment value = ref.value(); - boolean singleLevel = value.getMaxLevel() == 1; - boolean overMax = EnchantUtil.isInvalidLevel(ref, level); - if (!isEnchantEnabled(meta.category(), meta.key()) - && !(illegalEnchantsAlways.get() && overMax)) { - continue; - } - - String text = singleLevel && level == 1 - ? meta.shortName() - : meta.shortName() + level; - - int color = overMax - ? IllegalItemUtil.illegalColor() - : (level == value.getMaxLevel() ? TopEnchantUtil.topColor() : 0xFFFFFFFF); - - parts.add(new EnchantLine(text, color)); - } - - return parts; - } - - private boolean isEnchantEnabled(String category, String path) { - Map map = switch (category) { - case "armor" -> enchantArmor.get(); - case "melee" -> enchantMelee.get(); - case "tools" -> enchantTools.get(); - case "bow" -> enchantBow.get(); - case "fishing" -> enchantFishing.get(); - case "trident" -> enchantTrident.get(); - case "crossbow" -> enchantCrossbow.get(); - case "mace" -> enchantMace.get(); - default -> enchantOther.get(); - }; - return map.getOrDefault(path, false); - } - - private boolean shouldRenderOpponentStuff(Player p) { - if (p == null || mc.player == null) return false; - if (p == mc.player) return false; - if (!opponentAppleCooldowns.get()) return false; - if (!isOpponentAppleTrackingEnabled()) return false; - if (!PvpTargetState.isTargetInPvp(p.getUUID()) && !hasOpponentCooldowns(p.getUUID())) return false; - double maxDist = OPPONENT_DISTANCE; - return !(maxDist > 0) || !(mc.player.distanceToSqr(p) > maxDist * maxDist); - } - - private boolean isOpponentAppleTrackingEnabled() { - PvpCooldowns mod = Modules.get(PvpCooldowns.class); - return mod != null && mod.isSystemEnabled(); - } - - private void drawOpponentCooldownsStackedIcons(GuiGraphicsExtractor ctx, Player player, ScreenRect rect, int centerX, int nameY, float distOffset) { - if (!shouldRenderOpponentStuff(player)) return; - - int startX = rect != null - ? (int) rect.maxX + EFFECT_X_OFFSET - : centerX + (ICON_SIZE + ICON_GAP) * 2 + 8; - int startY = computeOpponentStackY(rect, nameY); - - int y = startY; - int seed = 0; - for (Item item : CooldownRegistry.trackedItems()) { - ItemCooldownSnapshot snapshot = OpponentCooldownManager.snapshot(player.getUUID(), item); - if (!snapshot.visible()) continue; - - ItemStack icon = new ItemStack(item); - float scale = ICON_SIZE / 16f; - Renderer2D.COLOR.item(icon, startX, y, scale, seed++, Renderer2D.ITEM_OVERLAY_NONE, null); - - y += EFFECT_LINE_HEIGHT; - } - } - - private void drawOpponentCooldownsStackedText(TextRenderer textRenderer, Player player, ScreenRect rect, int centerX, int nameY, float distOffset) { - if (!shouldRenderOpponentStuff(player)) return; - - int startX = rect != null - ? (int) rect.maxX + EFFECT_X_OFFSET - : centerX + (ICON_SIZE + ICON_GAP) * 2 + 8; - int startY = computeOpponentStackY(rect, nameY); - - int timeColor = PvpTargetState.isTargetInPvp(player.getUUID()) - ? OPP_TIME_COLOR - : OPP_TIME_COLOR_GRACE; - int y = startY; - for (Item item : CooldownRegistry.trackedItems()) { - ItemCooldownSnapshot snapshot = OpponentCooldownManager.snapshot(player.getUUID(), item); - if (!snapshot.visible()) continue; - - String prefix = snapshot.compactText(); - if (!prefix.isEmpty()) { - int textX = startX + ICON_SIZE + 6; - int textY = y + 4; - textRenderer.render(prefix + " ", textX, textY, new RenderColor(snapshot.cooling() ? timeColor : OPP_TIME_COLOR_GRACE), true); - } - - y += EFFECT_LINE_HEIGHT; - } - } - - private Vec3 obtainEntityLerpedPos(Entity e, float tickDelta) { + private static Vec3 obtainEntityLerpedPos(Entity e, float tickDelta) { try { return e.getPosition(tickDelta); } catch (NoSuchMethodError ex) { @@ -1688,7 +412,7 @@ public class NameTags extends Module { } } - private ScreenRect projectBoxScreen(AABB box, float tickDelta) { + private static NameTagModel.ScreenRect projectBoxScreen(AABB box, float tickDelta) { double minX = Double.POSITIVE_INFINITY, minY = Double.POSITIVE_INFINITY; double maxX = Double.NEGATIVE_INFINITY, maxY = Double.NEGATIVE_INFINITY; boolean any = false; @@ -1709,83 +433,6 @@ public class NameTags extends Module { } } if (!any) return null; - return new ScreenRect(minX, minY, maxX, maxY); - } - - private ItemStack[] getEquipmentSlots(Player player) { - ItemStack main = player.getMainHandItem(); - ItemStack off = player.getOffhandItem(); - ItemStack boots = player.getItemBySlot(EquipmentSlot.FEET); - ItemStack legs = player.getItemBySlot(EquipmentSlot.LEGS); - ItemStack chest = player.getItemBySlot(EquipmentSlot.CHEST); - ItemStack head = player.getItemBySlot(EquipmentSlot.HEAD); - return new ItemStack[]{main, boots, legs, chest, head, off}; - } - - private List> buildEnchantLines(ItemStack[] slots) { - List> result = new ArrayList<>(slots.length); - for (ItemStack stack : slots) { - if (stack.isEmpty()) { - result.add(List.of()); - continue; - } - List lines = formatEnchantments(stack); - result.add(lines.isEmpty() ? List.of() : lines); - } - return result; - } - - private int maxEnchantLines(List> lines) { - int max = 0; - for (List entry : lines) { - int size = entry.size(); - if (size > max) max = size; - } - return max; - } - - private enum NameplateStyle implements EnumValue.IdProvider { - LIQUID_GLASS, - MATTE - } - - private static final class EffectCache { - int lastTick = -1; - List effects = List.of(); - } - - private static final class EnchantCache { - int lastTick = -1; - int signature = 0; - List> lines = List.of(); - int maxLines = 0; - } - - private record ScreenRect(double minX, double minY, double maxX, double maxY) { - } - - private record NameplateLayout(int nameX, int nameY, int width, int height, float labelScale, - String pingText, String distText, float bgX, float bgY, float bgW, float bgH, - int pingWidth, int pingGap, int nameWidth, int hpWidth, int hpGap, - boolean renderHead, float headX, float headY, float headSize, - float dividerX, float dividerY, float dividerW, float dividerH, - boolean renderTotemBadge, float totemDividerX, float totemDividerY, - float totemDividerW, float totemDividerH, float totemBadgeX, float totemBadgeY, - float totemBadgeW, float totemBadgeH, float totemIconSize) { - } - - private record EnchantLine(String text, int color) { - } - - private record RenderEntry(Player player, double dist, float distOffset, int centerX, int nameY, int itemsY, - ScreenRect rect, boolean renderSlots, boolean renderNameplate, - boolean renderEffects, LabelInfo labelInfo, int infoColor, - NameplateLayout nameplateLayout, - ItemStack[] slots, List> enchantLines, int maxEnchantLines, - List effects, int totemPopCount, float totemPopAnimation) { - } - - private record LabelInfo(String pvpPrefix, Component styledName, String name, int ping, String pingText, String hp, - int infoColor) { + return new NameTagModel.ScreenRect(minX, minY, maxX, maxY); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NoRender.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NoRender.java index 999f4a7..e698031 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NoRender.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/NoRender.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -79,7 +79,7 @@ public class NoRender extends Module { return false; } - private static double combatant$squaredDistanceToBox(Vec3 point, AABB box) { + private static double lovisual$squaredDistanceToBox(Vec3 point, AABB box) { double nearestX = Mth.clamp(point.x, box.minX, box.maxX); double nearestY = Mth.clamp(point.y, box.minY, box.maxY); double nearestZ = Mth.clamp(point.z, box.minZ, box.maxZ); @@ -157,7 +157,7 @@ public class NoRender extends Module { Camera camera = client.gameRenderer.mainCamera(); Vec3 cameraPos = camera.position(); AABB box = entity.getBoundingBox().inflate(VIEW_OBSTRUCTION_BOX_EXPAND_XZ, VIEW_OBSTRUCTION_BOX_EXPAND_Y, VIEW_OBSTRUCTION_BOX_EXPAND_XZ); - double obstructionDistance = Math.sqrt(combatant$squaredDistanceToBox(cameraPos, box)); + double obstructionDistance = Math.sqrt(lovisual$squaredDistanceToBox(cameraPos, box)); Vec3 rayEnd = cameraPos.add(Vec3.directionFromRotation(camera.xRot(), camera.yRot()).scale(VIEW_OBSTRUCTION_FADE_DISTANCE)); Optional hit = box.clip(cameraPos, rayEnd); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/PostFX.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/PostFX.java index 865b9a1..956d578 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/PostFX.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/PostFX.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,7 +15,7 @@ import dev.loki.lovisual.config.values.RGBColorValue; import dev.loki.lovisual.features.module.Module; import dev.loki.lovisual.features.module.ModuleCategory; import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; @@ -152,9 +152,9 @@ public class PostFX extends Module implements PostProcessPass { ubo[31] = lutMode; PostFXUniforms.update(ubo); - FullScreenRenderer.begin("Combatant Fullscreen Pass") + FullScreenRenderer.begin("LoVisual Fullscreen Pass") .attachment(dst) - .pipeline(CombatantRenderPipelines.POST_FX) + .pipeline(LoVisualRenderPipelines.POST_FX) .uniform("PostFX", PostFXUniforms.get()) .sampler("u_Texture", src, PostProcessManager.getSampler()) .sampler("u_Lut", lutView, PostProcessManager.getSampler()) diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Predictions.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Predictions.java index fb80494..a0a9c1d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Predictions.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Predictions.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -53,7 +53,7 @@ import dev.loki.lovisual.render.engine.RenderState; import dev.loki.lovisual.render.engine.TextureStorage; import dev.loki.lovisual.render.engine.animation.AnimationUtility; import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.text.FontInfo; @@ -934,7 +934,7 @@ public class Predictions extends Module { private boolean isInGround(AbstractArrow arrow) { if (arrow == null) return false; try { - return ((PersistentProjectileEntityAccessor) arrow).combatant$isInGround(); + return ((PersistentProjectileEntityAccessor) arrow).lovisual$isInGround(); } catch (Throwable t) { return false; } @@ -1083,8 +1083,8 @@ public class Predictions extends Module { boolean walls = glowWallsValue.get(); RenderPipeline pipeline = walls - ? CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE - : CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE; + ? LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE + : LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE; Renderer3D.DepthMode depthMode = walls ? Renderer3D.DepthMode.MAIN : Renderer3D.DepthMode.PRE_DEPTH; MeshBuilder mesh = renderer.batchTextured(pipeline, TextureStorage.BLOOM, depthMode); if (mesh == null) return; @@ -1134,7 +1134,7 @@ public class Predictions extends Module { AimPrediction pred = computeAimPrediction(player, tickDelta); if (pred == null) return; - RenderPipeline pipeline = CombatantRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE; + RenderPipeline pipeline = LoVisualRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE; Renderer3D.DepthMode depthMode = Renderer3D.DepthMode.NONE; float prevWidth = RenderState.lineWidth; @@ -1183,8 +1183,8 @@ public class Predictions extends Module { private void renderGlowTrajectories(Renderer3D renderer, List results, int baseColor) { boolean walls = glowWallsValue.get(); RenderPipeline pipeline = walls - ? CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE - : CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE; + ? LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE + : LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE; Renderer3D.DepthMode depthMode = walls ? Renderer3D.DepthMode.MAIN : Renderer3D.DepthMode.PRE_DEPTH; MeshBuilder mesh = renderer.batchTextured(pipeline, TextureStorage.BLOOM, depthMode); if (mesh == null) return; @@ -1230,8 +1230,8 @@ public class Predictions extends Module { private void renderLineTrajectories(Renderer3D renderer, List results, int baseColor) { boolean walls = glowWallsValue.get(); RenderPipeline pipeline = walls - ? CombatantRenderPipelines.WORLD_COLORED_LINES_LIQUID_BLEND - : CombatantRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE; + ? LoVisualRenderPipelines.WORLD_COLORED_LINES_LIQUID_BLEND + : LoVisualRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE; Renderer3D.DepthMode depthMode = walls ? Renderer3D.DepthMode.MAIN : Renderer3D.DepthMode.PRE_DEPTH; float prevWidth = RenderState.lineWidth; @@ -1266,12 +1266,12 @@ public class Predictions extends Module { private void renderImpactEffects(Renderer3D renderer, List results, int baseColor, float tickDelta) { boolean walls = glowWallsValue.get(); RenderPipeline linePipeline = walls - ? CombatantRenderPipelines.WORLD_COLORED_LINES_LIQUID_BLEND - : CombatantRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE; + ? LoVisualRenderPipelines.WORLD_COLORED_LINES_LIQUID_BLEND + : LoVisualRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE; Renderer3D.DepthMode lineDepthMode = walls ? Renderer3D.DepthMode.MAIN : Renderer3D.DepthMode.PRE_DEPTH; RenderPipeline decalPipeline = walls - ? CombatantRenderPipelines.WORLD_DECAL_SDF - : CombatantRenderPipelines.WORLD_DECAL_SDF_DEPTH; + ? LoVisualRenderPipelines.WORLD_DECAL_SDF + : LoVisualRenderPipelines.WORLD_DECAL_SDF_DEPTH; Renderer3D.DepthMode decalDepthMode = walls ? Renderer3D.DepthMode.NONE : Renderer3D.DepthMode.PRE_DEPTH; float prevWidth = RenderState.lineWidth; RenderState.lineWidth = IMPACT_RING_LINE_WIDTH; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ReimaginedVisual.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ReimaginedVisual.java index 15c122a..64f010f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ReimaginedVisual.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ReimaginedVisual.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -18,10 +18,10 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.resources.language.I18n; import org.joml.Matrix4f; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; -import dev.loki.lovisual.render.engine.core.CombatantWorldMatrices; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualWorldMatrices; import dev.loki.lovisual.render.engine.depth.WorldSceneDepth; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; import dev.loki.lovisual.render.engine.uniform.impl.DepthOfFieldUniforms; import dev.loki.lovisual.render.helpers.SodiumMaterialFlags; @@ -411,9 +411,9 @@ public class ReimaginedVisual extends Module implements PostProcessPass { try { FullScreenRenderer.ensureInit(); - FullScreenRenderer.begin("Combatant DepthOfField Pass") + FullScreenRenderer.begin("LoVisual DepthOfField Pass") .attachment(dst) - .pipeline(CombatantRenderPipelines.DEPTH_OF_FIELD) + .pipeline(LoVisualRenderPipelines.DEPTH_OF_FIELD) .uniform("DepthOfField", DepthOfFieldUniforms.get()) .sampler("u_Texture", src, PostProcessManager.getSampler()) .sampler("u_MainDepth", depth.mainOr(src), PostProcessManager.getSampler()) @@ -425,7 +425,7 @@ public class ReimaginedVisual extends Module implements PostProcessPass { .end(); } catch (Throwable t) { depthSamplerSupported = false; - DebugLog.warn("[Combatant] DepthOfField depth sampler path failed; disabling DoF depth sampling for this session: " + t); + DebugLog.warn("[LoVisual] DepthOfField depth sampler path failed; disabling DoF depth sampling for this session: " + t); return false; } @@ -433,7 +433,7 @@ public class ReimaginedVisual extends Module implements PostProcessPass { } private void buildProjection() { - Matrix4f projection = CombatantWorldMatrices.renderProjectionMatrix(); + Matrix4f projection = LoVisualWorldMatrices.renderProjectionMatrix(); if (projection == null) { projection = RenderState.worldProjection; } @@ -471,7 +471,7 @@ public class ReimaginedVisual extends Module implements PostProcessPass { if (lastWavyVegetationActive == active && lastWavyVegetationSettingsPacked == settingsPacked) return; lastWavyVegetationActive = active; lastWavyVegetationSettingsPacked = settingsPacked; - CombatantRenderSystem.sodium().reloadWorldRenderer(); + LoVisualRenderSystem.sodium().reloadWorldRenderer(); } private int packWavyVegetationSettings() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/SeeInvisibles.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/SeeInvisibles.java index e9b770f..e7219f2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/SeeInvisibles.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/SeeInvisibles.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/SoundESP.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/SoundESP.java index a6aa7ab..56880f8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/SoundESP.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/SoundESP.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TargetESP.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TargetESP.java index 66f21b9..d720adc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TargetESP.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TargetESP.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -32,7 +32,7 @@ import dev.loki.lovisual.render.engine.TextureStorage; import dev.loki.lovisual.render.engine.animation.AnimationUtility; import dev.loki.lovisual.render.engine.animation.AnimatedRenderColors; import dev.loki.lovisual.render.engine.math.RenderMath; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import dev.loki.lovisual.util.target.TargetManager; @@ -201,7 +201,7 @@ public class TargetESP extends Module { float iAge = (float) interpolate(target.tickCount - 1, target.tickCount, tickDelta); MeshBuilder mesh = renderer.batchTextured( - CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE, + LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE, GHOST_PARTICLE_TEXTURE, Renderer3D.DepthMode.MAIN ); @@ -236,7 +236,7 @@ public class TargetESP extends Module { double tPosZ = pos.z; MeshBuilder mesh = renderer.batchTextured( - CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE, + LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE, CAPTURE_MARK_TEXTURE, Renderer3D.DepthMode.MAIN ); @@ -640,19 +640,19 @@ public class TargetESP extends Module { Renderer3D.DepthMode depthMode = Renderer3D.DepthMode.PRE_DEPTH; MeshBuilder additiveMesh = renderer.batch( - CombatantRenderPipelines.WORLD_COLORED_ADDITIVE_DEPTH, + LoVisualRenderPipelines.WORLD_COLORED_ADDITIVE_DEPTH, depthMode ); MeshBuilder fillMesh = renderer.batch( - CombatantRenderPipelines.WORLD_COLORED_DEPTH, + LoVisualRenderPipelines.WORLD_COLORED_DEPTH, depthMode ); MeshBuilder lineMesh = renderer.batch( - CombatantRenderPipelines.WORLD_COLORED_LINES_DEPTH, + LoVisualRenderPipelines.WORLD_COLORED_LINES_DEPTH, depthMode ); MeshBuilder bloomMesh = renderer.batchTextured( - CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE_DEPTH, + LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE_DEPTH, CRYSTAL_BLOOM, depthMode ); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TazikHat.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TazikHat.java index 953cdec..e727e68 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TazikHat.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TazikHat.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -27,7 +27,7 @@ import dev.loki.lovisual.features.module.WorldPhase; import dev.loki.lovisual.features.relations.CategoryService; import dev.loki.lovisual.render.engine.animation.AnimationUtility; import dev.loki.lovisual.render.engine.animation.AnimatedRenderColors; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import dev.loki.lovisual.render.helpers.HeadAnchor; @@ -345,8 +345,8 @@ public final class TazikHat extends Module { MeshBuilder tris = renderer.batch( depthTest.get() - ? CombatantRenderPipelines.WORLD_COLORED_DEPTH - : CombatantRenderPipelines.WORLD_COLORED, + ? LoVisualRenderPipelines.WORLD_COLORED_DEPTH + : LoVisualRenderPipelines.WORLD_COLORED, depthTest.get() ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.NONE @@ -354,8 +354,8 @@ public final class TazikHat extends Module { MeshBuilder lines = renderer.batch( depthTest.get() - ? CombatantRenderPipelines.WORLD_COLORED_LINES_DEPTH - : CombatantRenderPipelines.WORLD_COLORED_LINES, + ? LoVisualRenderPipelines.WORLD_COLORED_LINES_DEPTH + : LoVisualRenderPipelines.WORLD_COLORED_LINES, depthTest.get() ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.NONE diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TotemFX.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TotemFX.java index b14ea35..5691fa3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TotemFX.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/TotemFX.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,7 +14,7 @@ import dev.loki.lovisual.config.values.NumberValue; import dev.loki.lovisual.features.module.Module; import dev.loki.lovisual.features.module.ModuleCategory; import dev.loki.lovisual.features.module.ModuleInfo; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; @@ -123,9 +123,9 @@ public class TotemFX extends Module implements PostProcessPass { ); FullScreenRenderer.ensureInit(); - FullScreenRenderer.begin("Combatant Fullscreen Pass") + FullScreenRenderer.begin("LoVisual Fullscreen Pass") .attachment(dst) - .pipeline(CombatantRenderPipelines.HEAT_FX) + .pipeline(LoVisualRenderPipelines.HEAT_FX) .uniform("Heat", HeatUniforms.get()) .sampler("u_Texture", src, PostProcessManager.getSampler()) .end(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Tracers.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Tracers.java index db9e32b..ed351a3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Tracers.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Tracers.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -30,7 +30,7 @@ import dev.loki.lovisual.mixininterface.IEntity; import dev.loki.lovisual.render.engine.animation.AnimationUtility; import dev.loki.lovisual.render.engine.color.RenderColor; import dev.loki.lovisual.render.engine.core.ViewportContext; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.MeshRenderer; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.renderer.Renderer3D; @@ -65,7 +65,7 @@ public class Tracers extends Module { private static final float ARROW_RADIUS_MIN_FACTOR = 0.55f; private static final float ARROW_RADIUS_MAX_FACTOR = 1.0f; private static final MeshBuilder ARROW_MESH = - new MeshBuilder(CombatantRenderPipelines.UI_TEXTURED_ADDITIVE); + new MeshBuilder(LoVisualRenderPipelines.UI_TEXTURED_ADDITIVE); private final Minecraft mc = Minecraft.getInstance(); private final BooleanValue traceFriendsValue = bool("tracersTraceFriends", SETTING_TRACE_FRIENDS, false); private final ModeValue tracersMode = @@ -154,7 +154,7 @@ public class Tracers extends Module { MeshRenderer.begin() .attachments(mc.gameRenderer.mainRenderTarget()) - .pipeline(CombatantRenderPipelines.UI_TEXTURED_ADDITIVE) + .pipeline(LoVisualRenderPipelines.UI_TEXTURED_ADDITIVE) .mesh(ARROW_MESH) .transform(transform) .sampler("u_Texture", view, sampler) diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Trails.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Trails.java index 9d8a024..0f7f3c3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Trails.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Trails.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -27,7 +27,7 @@ import dev.loki.lovisual.render.engine.RenderState; import dev.loki.lovisual.render.engine.TextureStorage; import dev.loki.lovisual.render.engine.animation.AnimatedRenderColors; import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import dev.loki.lovisual.render.helpers.Particle3D; @@ -253,7 +253,7 @@ public class Trails extends Module { if (onlySelf.get() && player != mc.player) continue; active.add(player.getUUID()); - List trails = ((IEntity) player).combatant$getTrails(); + List trails = ((IEntity) player).lovisual$getTrails(); Vec3 last = ((IEntity) player).get$InstantRenderPos(); boolean skipSelfInFirstPerson = hideFirstPerson.get() @@ -300,7 +300,7 @@ public class Trails extends Module { public void onDisable() { if (mc.level == null) return; for (Player player : mc.level.players()) { - ((IEntity) player).combatant$getTrails().clear(); + ((IEntity) player).lovisual$getTrails().clear(); } extraParticles.clear(); groundState.clear(); @@ -321,8 +321,8 @@ public class Trails extends Module { } RenderPipeline pipeline = useDepth - ? CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE; + ? LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE; Renderer3D.DepthMode depthMode = useDepth ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.MAIN; MeshBuilder mesh = renderer.batchTextured(pipeline, TextureStorage.FIRE_FLY, depthMode); if (mesh == null) return; @@ -343,7 +343,7 @@ public class Trails extends Module { continue; } - List trails = ((IEntity) player).combatant$getTrails(); + List trails = ((IEntity) player).lovisual$getTrails(); int size = trails.size(); if (size == 0) continue; @@ -381,8 +381,8 @@ public class Trails extends Module { private void renderRibbonTrails(Renderer3D renderer, float tickDelta, boolean useDepth) { RenderPipeline pipeline = useDepth - ? CombatantRenderPipelines.WORLD_COLORED_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_COLORED; + ? LoVisualRenderPipelines.WORLD_COLORED_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_COLORED; Renderer3D.DepthMode depthMode = useDepth ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.MAIN; MeshBuilder mesh = renderer.batch(pipeline, depthMode); if (mesh == null) return; @@ -394,8 +394,8 @@ public class Trails extends Module { RenderState.lineWidth = Math.max(0.5f, trailStrokeWidth.get()); strokeMesh = renderer.batch( useDepth - ? CombatantRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_COLORED_LINES, + ? LoVisualRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_COLORED_LINES, depthMode ); } finally { @@ -415,7 +415,7 @@ public class Trails extends Module { continue; } - List trails = ((IEntity) player).combatant$getTrails(); + List trails = ((IEntity) player).lovisual$getTrails(); int size = trails.size(); if (size < 2) continue; @@ -494,7 +494,7 @@ public class Trails extends Module { private boolean isInGround(AbstractArrow projectile) { if (projectile == null) return false; try { - return ((PersistentProjectileEntityAccessor) projectile).combatant$isInGround(); + return ((PersistentProjectileEntityAccessor) projectile).lovisual$isInGround(); } catch (Throwable t) { return false; } @@ -548,8 +548,8 @@ public class Trails extends Module { private void renderExtraParticles(Renderer3D renderer, float tickDelta) { boolean useDepth = depthTest.get(); RenderPipeline pipeline = useDepth - ? CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE; + ? LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE; Renderer3D.DepthMode depthMode = useDepth ? Renderer3D.DepthMode.PRE_DEPTH : Renderer3D.DepthMode.MAIN; Quaternionf camRot = RenderState.cameraRotation; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ViewModel.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ViewModel.java index 8d0f45e..557e650 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ViewModel.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/ViewModel.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/WorldParticles.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/WorldParticles.java index 390f17b..085aa45 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/WorldParticles.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/WorldParticles.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -27,7 +27,7 @@ import dev.loki.lovisual.render.engine.animation.AnimatedRenderColors; import dev.loki.lovisual.render.engine.color.ColorBlendMode; import dev.loki.lovisual.render.engine.color.ColorEffects; import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.profiler.RenderCostProfiler; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; @@ -396,8 +396,8 @@ public class WorldParticles extends Module { boolean bubbleMode = isBubbleMode(); MeshBuilder spriteMesh = renderer.batchTextured( - useDepth ? CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_TEXTURED_ADDITIVE, + useDepth ? LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_TEXTURED_ADDITIVE, TextureStorage.BLOOM, depthMode ); @@ -408,8 +408,8 @@ public class WorldParticles extends Module { try { RenderState.lineWidth = Math.max(0.5f, lineWidth.get().floatValue()); lineMesh = renderer.batch( - useDepth ? CombatantRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_COLORED_LINES, + useDepth ? LoVisualRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_COLORED_LINES, depthMode ); } finally { @@ -420,8 +420,8 @@ public class WorldParticles extends Module { Quaternionf camRot = RenderState.cameraRotation; MeshBuilder bubbleShellMesh = bubbleMode ? renderer.batch( - useDepth ? CombatantRenderPipelines.WORLD_COLORED_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_COLORED, + useDepth ? LoVisualRenderPipelines.WORLD_COLORED_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_COLORED, depthMode ) : null; @@ -720,8 +720,8 @@ public class WorldParticles extends Module { Identifier texture) { return renderer.batch( useDepth - ? CombatantRenderPipelines.WORLD_TEXTURED_TINT_ADDITIVE_LIQUID_IGNORE - : CombatantRenderPipelines.WORLD_TEXTURED_TINT_ADDITIVE, + ? LoVisualRenderPipelines.WORLD_TEXTURED_TINT_ADDITIVE_LIQUID_IGNORE + : LoVisualRenderPipelines.WORLD_TEXTURED_TINT_ADDITIVE, depthMode, Renderer3D.BatchBindings.none() .withSampler("u_Texture", texture) diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/WorldTweaks.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/WorldTweaks.java index fdbbef3..b4a6f94 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/WorldTweaks.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/WorldTweaks.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -177,8 +177,8 @@ public class WorldTweaks extends Module { if (!(world instanceof WorldAccessor accessor)) return 0.0f; return Mth.lerp( tickDelta, - accessor.combatant$getLastRainGradientRaw(), - accessor.combatant$getRainGradientRaw() + accessor.lovisual$getLastRainGradientRaw(), + accessor.lovisual$getRainGradientRaw() ); } @@ -186,8 +186,8 @@ public class WorldTweaks extends Module { if (!(world instanceof WorldAccessor accessor)) return 0.0f; float thunder = Mth.lerp( tickDelta, - accessor.combatant$getLastThunderGradientRaw(), - accessor.combatant$getThunderGradientRaw() + accessor.lovisual$getLastThunderGradientRaw(), + accessor.lovisual$getThunderGradientRaw() ); return thunder * getRawRainGradient(world, tickDelta); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Zoom.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Zoom.java index 03d06f0..78d0616 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Zoom.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/module/modules/visuals/Zoom.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryRules.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryRules.java index 329611b..55f039c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryRules.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryRules.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryService.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryService.java index 9329c15..3372415 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryService.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryService.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryType.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryType.java index c56e37f..2cbace9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryType.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/CategoryType.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/EntityFilters.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/EntityFilters.java index dff8e16..a0ec7a0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/EntityFilters.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/EntityFilters.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/PlayerRelations.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/PlayerRelations.java index 9567242..0ebf884 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/PlayerRelations.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/PlayerRelations.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffData.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffData.java index a5769bc..563b06c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffData.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffData.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffHeuristicsConfig.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffHeuristicsConfig.java index da257b3..64ee7b0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffHeuristicsConfig.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffHeuristicsConfig.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffHeuristicsMatcher.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffHeuristicsMatcher.java index b2fdc6d..0b8a09f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffHeuristicsMatcher.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffHeuristicsMatcher.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffTracker.java index bd3e46c..04f0787 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffTracker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/relations/StaffTracker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/security/BackdoorProtection.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/security/BackdoorProtection.java index db0a25a..289ed48 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/security/BackdoorProtection.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/security/BackdoorProtection.java @@ -1,12 +1,12 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on ExploitPreventer. * Original work copyright (c) 2025 Niklas S. * * Original portions remain under the MIT License. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/security/FilteredTranslatableTextContent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/security/FilteredTranslatableTextContent.java index 1b48ba6..bad5ff8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/security/FilteredTranslatableTextContent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/security/FilteredTranslatableTextContent.java @@ -1,12 +1,12 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on ExploitPreventer. * Original work copyright (c) 2025 Niklas S. * * Original portions remain under the MIT License. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/EditableClickGuiTheme.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/EditableClickGuiTheme.java index ac8f408..e24e352 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/EditableClickGuiTheme.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/EditableClickGuiTheme.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/Theme.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/Theme.java index 3e5ec61..aac629d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/Theme.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/Theme.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/ThemeStore.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/ThemeStore.java index 8798fe5..7b9cb28 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/ThemeStore.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/ThemeStore.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/Themes.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/Themes.java index 96402f4..6e25725 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/Themes.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/features/theme/Themes.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IEntity.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IEntity.java index 8e30011..aa2456f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IEntity.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IEntity.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,5 +15,5 @@ import java.util.List; public interface IEntity { Vec3 get$InstantRenderPos(); - List combatant$getTrails(); + List lovisual$getTrails(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGlBackendInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGlBackendInfo.java index 9921194..5285a60 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGlBackendInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGlBackendInfo.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import com.mojang.blaze3d.opengl.DirectStateAccess; import com.mojang.blaze3d.opengl.FrameBufferCache; public interface IGlBackendInfo { - DirectStateAccess combatant$directStateAccess(); + DirectStateAccess lovisual$directStateAccess(); - FrameBufferCache combatant$frameBufferCache(); + FrameBufferCache lovisual$frameBufferCache(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGpuDevice.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGpuDevice.java index 43f2030..43d0a90 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGpuDevice.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGpuDevice.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.mixininterface; public interface IGpuDevice { - void combatant$pushScissor(int x, int y, int width, int height); + void lovisual$pushScissor(int x, int y, int width, int height); - void combatant$popScissor(); + void lovisual$popScissor(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGuiGraphics.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGuiGraphics.java index d0b1a5f..1c21688 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGuiGraphics.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IGuiGraphics.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,18 +11,18 @@ public interface IGuiGraphics { /** * Runs a task without vanilla UI scaling applied to DrawContext's matrix stack. */ - void combatant$runUnscaled(Runnable task); + void lovisual$runUnscaled(Runnable task); /** * Runs a task with an additional 2D transform applied to DrawContext's matrix stack. * Order: translate(tx, ty) then rotate(angleRad). Angle in radians. */ - void combatant$withTransform(float tx, float ty, float angleRad, Runnable task); + void lovisual$withTransform(float tx, float ty, float angleRad, Runnable task); - void combatant$drawItemBar(net.minecraft.world.item.ItemStack stack, int x, int y); + void lovisual$drawItemBar(net.minecraft.world.item.ItemStack stack, int x, int y); - void combatant$drawCooldownProgress(net.minecraft.world.item.ItemStack stack, int x, int y); + void lovisual$drawCooldownProgress(net.minecraft.world.item.ItemStack stack, int x, int y); - void combatant$addDeferredHudMarker(dev.loki.lovisual.render.engine.renderer.Renderer2D.Deferred2DLayer layer); + void lovisual$addDeferredHudMarker(dev.loki.lovisual.render.engine.renderer.Renderer2D.Deferred2DLayer layer); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IItemEntityRenderState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IItemEntityRenderState.java index 5b508d4..ae07b71 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IItemEntityRenderState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IItemEntityRenderState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.mixininterface; public interface IItemEntityRenderState { - boolean combatant$isOnGround(); + boolean lovisual$isOnGround(); - void combatant$setOnGround(boolean onGround); + void lovisual$setOnGround(boolean onGround); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/ILocalPlayer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/ILocalPlayer.java index b41d833..4630da1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/ILocalPlayer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/ILocalPlayer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,11 +8,11 @@ package dev.loki.lovisual.mixininterface; public interface ILocalPlayer { - float combatant$getLastYaw(); + float lovisual$getLastYaw(); - float combatant$getLastPitch(); + float lovisual$getLastPitch(); - void combatant$setLastYaw(float yaw); + void lovisual$setLastYaw(float yaw); - void combatant$setLastPitch(float pitch); + void lovisual$setLastPitch(float pitch); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IMsaaDevice.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IMsaaDevice.java index 19c4970..60cfd93 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IMsaaDevice.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IMsaaDevice.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import com.mojang.blaze3d.textures.GpuTexture; @Deprecated public interface IMsaaDevice { - GpuTexture combatant$createMsaaTexture(String label, + GpuTexture lovisual$createMsaaTexture(String label, int usage, GpuFormat format, int width, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IMsaaTexture.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IMsaaTexture.java index 9692830..729aea1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IMsaaTexture.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IMsaaTexture.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,11 +8,11 @@ package dev.loki.lovisual.mixininterface; public interface IMsaaTexture { - void combatant$setSamples(int samples); + void lovisual$setSamples(int samples); - int combatant$getSamples(); + int lovisual$getSamples(); - boolean combatant$isMsaa(); + boolean lovisual$isMsaa(); - int combatant$getGlId(); + int lovisual$getGlId(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IPlayerAttackCooldown.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IPlayerAttackCooldown.java index 5e4a17b..7f7053e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IPlayerAttackCooldown.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IPlayerAttackCooldown.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.mixininterface; public interface IPlayerAttackCooldown { - float combatant$getAttackCooldownProgress(float tickDelta); + float lovisual$getAttackCooldownProgress(float tickDelta); - boolean combatant$isAttackCharged(float tickDelta); + boolean lovisual$isAttackCharged(float tickDelta); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IRenderPipeline.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IRenderPipeline.java index a338577..27cbea7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IRenderPipeline.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IRenderPipeline.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -16,11 +16,11 @@ package dev.loki.lovisual.mixininterface; import dev.loki.lovisual.render.engine.rhi.clip.ShapeClipRenderPassContract; public interface IRenderPipeline { - void combatant$setLineSmooth(boolean lineSmooth); + void lovisual$setLineSmooth(boolean lineSmooth); - boolean combatant$getLineSmooth(); + boolean lovisual$getLineSmooth(); - void combatant$setShapeClipContract(ShapeClipRenderPassContract contract); + void lovisual$setShapeClipContract(ShapeClipRenderPassContract contract); - ShapeClipRenderPassContract combatant$getShapeClipContract(); + ShapeClipRenderPassContract lovisual$getShapeClipContract(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IRoundedHitbox.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IRoundedHitbox.java index 2a1cdcd..03ab457 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IRoundedHitbox.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixininterface/IRoundedHitbox.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,11 +8,11 @@ package dev.loki.lovisual.mixininterface; public interface IRoundedHitbox { - void combatant$setRoundedHitbox(float radius); + void lovisual$setRoundedHitbox(float radius); - void combatant$clearRoundedHitbox(); + void lovisual$clearRoundedHitbox(); - float combatant$getRoundedHitbox(); + float lovisual$getRoundedHitbox(); - boolean combatant$useRoundedHitbox(); + boolean lovisual$useRoundedHitbox(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractClientPlayerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractClientPlayerMixin.java index 199e51e..87c26f5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractClientPlayerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractClientPlayerMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -32,10 +32,10 @@ public class AbstractClientPlayerMixin { @Unique - private boolean combatant$wasUsing = false; + private boolean lovisual$wasUsing = false; @Inject(method = "getFieldOfViewModifier", at = @At("HEAD"), cancellable = true) - private void combatant$overrideFovMultiplier(boolean changingFov, float fovEffectScale, + private void lovisual$overrideFovMultiplier(boolean changingFov, float fovEffectScale, CallbackInfoReturnable cir) { FovControl module = Modules.get(FovControl.class); if (module == null || !module.isEnabled()) return; @@ -90,12 +90,12 @@ public class AbstractClientPlayerMixin { } @Inject(method = "tick", at = @At("TAIL")) - private void combatant$trackEat(CallbackInfo ci) { + private void lovisual$trackEat(CallbackInfo ci) { AbstractClientPlayer p = (AbstractClientPlayer) (Object) this; Minecraft mc = Minecraft.getInstance(); if (mc.player == null || p == mc.player) { - combatant$wasUsing = p.isUsingItem(); + lovisual$wasUsing = p.isUsingItem(); return; } @@ -103,18 +103,18 @@ public class AbstractClientPlayerMixin { PvpCooldowns mod = Modules.get(PvpCooldowns.class); if (mod == null || !mod.isSystemEnabled() || !PvpTargetState.isTargetInPvp(p.getUUID())) { - combatant$wasUsing = using; + lovisual$wasUsing = using; return; } - if (using && !combatant$wasUsing) { + if (using && !lovisual$wasUsing) { ItemStack stack = p.getUseItem(); if (!stack.isEmpty() && CooldownRegistry.isTracked(stack.getItem())) { OpponentCooldownManager.recordUse(p.getUUID(), stack.getItem()); } } - combatant$wasUsing = using; + lovisual$wasUsing = using; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractContainerScreenMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractContainerScreenMixin.java index ac54e3f..7f36d59 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractContainerScreenMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractContainerScreenMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,18 +12,12 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.InventoryMove; @Mixin(AbstractContainerScreen.class) public abstract class AbstractContainerScreenMixin { @Inject(method = "onClose", at = @At("HEAD"), cancellable = true) - private void combatant$inventoryMove$deferClose(CallbackInfo ci) { - InventoryMove module = Modules.get(InventoryMove.class); - if (module == null || !module.isEnabled()) return; - if (module.shouldCancelHandledScreenClose((AbstractContainerScreen) (Object) this)) { - ci.cancel(); - } + private void lovisual$inventoryMove$deferClose(CallbackInfo ci) { + // InventoryMove module removed; keep hook for compatibility. } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractSelectionListMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractSelectionListMixin.java index f574732..1c90b64 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractSelectionListMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractSelectionListMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -19,7 +19,7 @@ import dev.loki.lovisual.features.gui.hud.nondraggable.impl.BetterButtons; public abstract class AbstractSelectionListMixin { @Inject(method = "enableScissor(Lnet/minecraft/client/gui/GuiGraphicsExtractor;)V", at = @At("HEAD")) - private void combatant$pushScissor(GuiGraphicsExtractor context, CallbackInfo ci) { + private void lovisual$pushScissor(GuiGraphicsExtractor context, CallbackInfo ci) { AbstractSelectionList self = (AbstractSelectionList) (Object) this; BetterButtons.pushScissorContext(self.getX(), self.getY(), self.getRight(), self.getBottom()); } @@ -28,7 +28,7 @@ public abstract class AbstractSelectionListMixin { method = "extractWidgetRenderState(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphicsExtractor;disableScissor()V") ) - private void combatant$popScissor(GuiGraphicsExtractor context, int mouseX, int mouseY, float deltaTicks, CallbackInfo ci) { + private void lovisual$popScissor(GuiGraphicsExtractor context, int mouseX, int mouseY, float deltaTicks, CallbackInfo ci) { BetterButtons.popScissorContext(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractSliderButtonMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractSliderButtonMixin.java index 116e084..b915009 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractSliderButtonMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractSliderButtonMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -24,7 +24,7 @@ import dev.loki.lovisual.mixins.accessors.SliderWidgetAccessor; public abstract class AbstractSliderButtonMixin { @Inject(method = "extractWidgetRenderState(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("HEAD"), cancellable = true) - private void combatant$renderWidget(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void lovisual$renderWidget(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { BetterButtons buttons = BetterButtons.get(); if (buttons == null || !buttons.useUiButtons()) return; Minecraft mc = Minecraft.getInstance(); @@ -33,10 +33,10 @@ public abstract class AbstractSliderButtonMixin { AbstractWidget widget = self; boolean hovered = widget.isMouseOver(mouseX, mouseY); - boolean dragging = ((SliderWidgetAccessor) self).combatant$isDragging(); + boolean dragging = ((SliderWidgetAccessor) self).lovisual$isDragging(); float hover = BetterButtons.updateHover(widget, hovered || dragging); - double value = ((SliderWidgetAccessor) self).combatant$getValue(); + double value = ((SliderWidgetAccessor) self).lovisual$getValue(); BetterButtons.enqueueSlider(widget, (float) value, dragging, hover); if (hovered) { BetterButtons.captureTooltip(widget, mouseX, mouseY); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractWidgetMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractWidgetMixin.java index 5a8fe27..6437e61 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractWidgetMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AbstractWidgetMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -19,35 +19,35 @@ import dev.loki.lovisual.mixininterface.IRoundedHitbox; public abstract class AbstractWidgetMixin implements IRoundedHitbox { @Unique - private float combatant$roundedRadius = 0.0f; + private float lovisual$roundedRadius = 0.0f; @Unique - private boolean combatant$roundedEnabled = false; + private boolean lovisual$roundedEnabled = false; @Override - public void combatant$setRoundedHitbox(float radius) { - combatant$roundedRadius = Math.max(0.0f, radius); - combatant$roundedEnabled = combatant$roundedRadius > 0.0f; + public void lovisual$setRoundedHitbox(float radius) { + lovisual$roundedRadius = Math.max(0.0f, radius); + lovisual$roundedEnabled = lovisual$roundedRadius > 0.0f; } @Override - public void combatant$clearRoundedHitbox() { - combatant$roundedRadius = 0.0f; - combatant$roundedEnabled = false; + public void lovisual$clearRoundedHitbox() { + lovisual$roundedRadius = 0.0f; + lovisual$roundedEnabled = false; } @Override - public float combatant$getRoundedHitbox() { - return combatant$roundedRadius; + public float lovisual$getRoundedHitbox() { + return lovisual$roundedRadius; } @Override - public boolean combatant$useRoundedHitbox() { - return combatant$roundedEnabled; + public boolean lovisual$useRoundedHitbox() { + return lovisual$roundedEnabled; } @Inject(method = "isMouseOver(DD)Z", at = @At("HEAD"), cancellable = true) - private void combatant$isMouseOverRounded(double mouseX, double mouseY, CallbackInfoReturnable cir) { - if (!combatant$roundedEnabled) return; + private void lovisual$isMouseOverRounded(double mouseX, double mouseY, CallbackInfoReturnable cir) { + if (!lovisual$roundedEnabled) return; AbstractWidget self = (AbstractWidget) (Object) this; float x = self.getX(); @@ -60,7 +60,7 @@ public abstract class AbstractWidgetMixin implements IRoundedHitbox { return; } - float r = Math.min(combatant$roundedRadius, Math.min(w, h) * 0.5f); + float r = Math.min(lovisual$roundedRadius, Math.min(w, h) * 0.5f); if (r <= 0.0f) { cir.setReturnValue(true); return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AtmosphericFogEnvironmentMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AtmosphericFogEnvironmentMixin.java index ab29f8f..7063053 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AtmosphericFogEnvironmentMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/AtmosphericFogEnvironmentMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -24,7 +24,7 @@ import dev.loki.lovisual.features.module.modules.visuals.WorldTweaks; public class AtmosphericFogEnvironmentMixin { @Inject(method = "setupFog", at = @At("HEAD"), cancellable = true) - private void combatant$noDimensionFog(FogData data, + private void lovisual$noDimensionFog(FogData data, Camera camera, ClientLevel world, float viewDistance, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BatchingRenderCommandQueueMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BatchingRenderCommandQueueMixin.java index 1228545..0bc736a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BatchingRenderCommandQueueMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BatchingRenderCommandQueueMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -21,51 +21,51 @@ import java.util.Arrays; @Mixin(SubmitNodeCollection.class) public abstract class BatchingRenderCommandQueueMixin { @Unique - private static final int COMBATANT_VIEW_FADE_DITHER_MARK = 0x00010001; + private static final int LOVISUAL_VIEW_FADE_DITHER_MARK = 0x00010001; @Unique - private static final int COMBATANT_VIEW_FADE_A2C_MARK = 0x00010100; + private static final int LOVISUAL_VIEW_FADE_A2C_MARK = 0x00010100; @Unique - private static int combatant$markViewObstructionFade(int argb, float alpha, boolean msaaActive) { - int rgb = (argb & 0x00FEFEFE) | (msaaActive ? COMBATANT_VIEW_FADE_A2C_MARK : COMBATANT_VIEW_FADE_DITHER_MARK); + private static int lovisual$markViewObstructionFade(int argb, float alpha, boolean msaaActive) { + int rgb = (argb & 0x00FEFEFE) | (msaaActive ? LOVISUAL_VIEW_FADE_A2C_MARK : LOVISUAL_VIEW_FADE_DITHER_MARK); int alphaByte = Math.round(255.0f * Mth.clamp(alpha, 0.0f, 1.0f)); return rgb | ((alphaByte & 0xFF) << 24); } @Unique - private static boolean combatant$shouldApplyViewObstructionFade() { + private static boolean lovisual$shouldApplyViewObstructionFade() { return ViewObstructionFadeContext.isActive() && ViewObstructionFadeContext.alpha() < 0.99f; } @Unique - private static int combatant$applyFadeToArgb(int color) { + private static int lovisual$applyFadeToArgb(int color) { int baseColor = color == -1 ? 0xFFFFFFFF : ((color & 0x00FFFFFF) | 0xFF000000); - return combatant$markViewObstructionFade(baseColor, ViewObstructionFadeContext.alpha(), MsaaWorldTarget.isActive()); + return lovisual$markViewObstructionFade(baseColor, ViewObstructionFadeContext.alpha(), MsaaWorldTarget.isActive()); } @ModifyVariable(method = "submitModel", at = @At("HEAD"), argsOnly = true, index = 7) - private int combatant$applyViewObstructionFadeAlpha(int tintedColor) { - if (!combatant$shouldApplyViewObstructionFade()) { + private int lovisual$applyViewObstructionFadeAlpha(int tintedColor) { + if (!lovisual$shouldApplyViewObstructionFade()) { return tintedColor; } - return combatant$applyFadeToArgb(tintedColor); + return lovisual$applyFadeToArgb(tintedColor); } @ModifyVariable(method = "submitItem", at = @At("HEAD"), argsOnly = true, index = 6) - private int[] combatant$applyViewObstructionFadeAlphaToItemTints(int[] tints) { - if (!combatant$shouldApplyViewObstructionFade()) { + private int[] lovisual$applyViewObstructionFadeAlphaToItemTints(int[] tints) { + if (!lovisual$shouldApplyViewObstructionFade()) { return tints; } - int sentinel = combatant$applyFadeToArgb(-1); + int sentinel = lovisual$applyFadeToArgb(-1); if (tints == null || tints.length == 0) { return new int[]{sentinel}; } int[] faded = Arrays.copyOf(tints, tints.length); - faded[0] = combatant$applyFadeToArgb(faded[0]); + faded[0] = lovisual$applyFadeToArgb(faded[0]); for (int i = 1; i < faded.length; i++) { - faded[i] = combatant$applyFadeToArgb(faded[i]); + faded[i] = lovisual$applyFadeToArgb(faded[i]); } return faded; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BlockCollisionSpliteratorMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BlockCollisionSpliteratorMixin.java index 59a99df..8d8c350 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BlockCollisionSpliteratorMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BlockCollisionSpliteratorMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * Portions derived from ThunderHack Recode, copyright (c) 2023-2024 Pan4ur & 06ED. * Upstream: https://github.com/Pan4ur/ThunderHack-Recode @@ -29,7 +29,7 @@ public abstract class BlockCollisionSpliteratorMixin { target = "Lnet/minecraft/world/level/BlockGetter;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;" ) ) - private BlockState combatant$collisionHook(BlockGetter instance, BlockPos blockPos) { + private BlockState lovisual$collisionHook(BlockGetter instance, BlockPos blockPos) { BlockState state = instance.getBlockState(blockPos); if (!Events.BUS.hasListeners(EventCollision.class)) { return state; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BlockMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BlockMixin.java index f6e1b10..3a8a210 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BlockMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BlockMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BossHealthOverlayMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BossHealthOverlayMixin.java index f796ed3..3a36ef2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BossHealthOverlayMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BossHealthOverlayMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BufferManagerDefaultBufferManagerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BufferManagerDefaultBufferManagerMixin.java index e74f653..60e6f54 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BufferManagerDefaultBufferManagerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/BufferManagerDefaultBufferManagerMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,12 +11,12 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; @Mixin(targets = "com.mojang.blaze3d.opengl.DirectStateAccess$Emulated") public abstract class BufferManagerDefaultBufferManagerMixin { @Inject(method = "bindFrameBufferTextures", at = @At("HEAD"), cancellable = true) - private void combatant$setupFramebuffer(int framebuffer, + private void lovisual$setupFramebuffer(int framebuffer, int[] colorAttachments, int[] colorMipLevels, int depthAttachment, @@ -29,7 +29,7 @@ public abstract class BufferManagerDefaultBufferManagerMixin { int colorAttachment = colorAttachments[0]; int mipLevel = colorMipLevels != null && colorMipLevels.length > 0 ? colorMipLevels[0] : depthMipLevel; - if (CombatantRenderSystem.rhi().msaa().setupFramebuffer(framebuffer, colorAttachment, depthAttachment, mipLevel, bindTarget)) { + if (LoVisualRenderSystem.rhi().msaa().setupFramebuffer(framebuffer, colorAttachment, depthAttachment, mipLevel, bindTarget)) { ci.cancel(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ButtonWidgetTextMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ButtonWidgetTextMixin.java index 957c368..57ffc9a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ButtonWidgetTextMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ButtonWidgetTextMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ import dev.loki.lovisual.features.gui.hud.nondraggable.impl.BetterButtons; public abstract class ButtonWidgetTextMixin { @Inject(method = "extractContents(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("HEAD"), cancellable = true) - private void combatant$drawIcon(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void lovisual$drawIcon(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { BetterButtons buttons = BetterButtons.get(); if (buttons == null || !buttons.useUiButtons()) return; Minecraft mc = Minecraft.getInstance(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CameraMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CameraMixin.java index 615ad2b..f710361 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CameraMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CameraMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -45,14 +45,14 @@ public abstract class CameraMixin { private Entity entity; @Unique - private static float combatant$getGameFov() { + private static float lovisual$getGameFov() { Minecraft mc = Minecraft.getInstance(); if (mc == null) return 70.0f; return mc.options.fov().get(); } @Unique - private static float combatant$getFovEffectScale() { + private static float lovisual$getFovEffectScale() { Minecraft mc = Minecraft.getInstance(); if (mc == null) return 1.0f; return mc.options.fovEffectScale().get().floatValue(); @@ -62,7 +62,7 @@ public abstract class CameraMixin { protected abstract void move(float surge, float heave, float sway); @Inject(method = "getMaxZoom(F)F", at = @At("HEAD"), cancellable = true) - private void combatant$disableCameraCollision(float desiredDistance, CallbackInfoReturnable cir) { + private void lovisual$disableCameraCollision(float desiredDistance, CallbackInfoReturnable cir) { CameraClip mod = Modules.get(CameraClip.class); if (mod != null && mod.isEnabled() && isThirdPerson()) { // Skip collision shortening and apply distance multiplier @@ -72,7 +72,7 @@ public abstract class CameraMixin { } @Inject(method = "update", at = @At("TAIL")) - private void combatant$applyCameraOffsets(DeltaTracker tickCounter, CallbackInfo ci) { + private void lovisual$applyCameraOffsets(DeltaTracker tickCounter, CallbackInfo ci) { CameraClip mod = Modules.get(CameraClip.class); if (mod == null || !mod.isEnabled() || !isThirdPerson()) return; @@ -87,12 +87,12 @@ public abstract class CameraMixin { } @Inject(method = "calculateFov", at = @At("RETURN"), cancellable = true) - private void combatant$adjustCalculatedFov(float tickDelta, CallbackInfoReturnable cir) { - cir.setReturnValue(combatant$adjustFovValue(cir.getReturnValue())); + private void lovisual$adjustCalculatedFov(float tickDelta, CallbackInfoReturnable cir) { + cir.setReturnValue(lovisual$adjustFovValue(cir.getReturnValue())); } @Unique - private float combatant$adjustFovValue(float fov) { + private float lovisual$adjustFovValue(float fov) { FovControl module = Modules.get(FovControl.class); Zoom zoom = Modules.get(Zoom.class); @@ -101,7 +101,7 @@ public abstract class CameraMixin { if (!hasFovControl && !hasZoom) return fov; if (hasFovControl && module.useCustomFov()) { - float base = combatant$getGameFov(); + float base = lovisual$getGameFov(); float custom = module.getCustomFov(); if (base > 0.01f) { fov = fov * (custom / base); @@ -113,7 +113,7 @@ public abstract class CameraMixin { if (hasFovControl && module.disableFluidFov()) { FogType type = ((Camera) (Object) this).getFluidInCamera(); if (type == FogType.WATER || type == FogType.LAVA) { - float effectScale = combatant$getFovEffectScale(); + float effectScale = lovisual$getFovEffectScale(); float factor = Mth.lerp(effectScale, 1.0f, 0.85714287f); if (factor > 0.0001f) { fov /= factor; @@ -149,10 +149,10 @@ public abstract class CameraMixin { public abstract Matrix4f getViewRotationMatrix(Matrix4f matrix); @Invoker("createProjectionMatrixForCulling") - protected abstract Matrix4f combatant$createProjectionMatrixForCulling(); + protected abstract Matrix4f lovisual$createProjectionMatrixForCulling(); @Invoker("prepareCullFrustum") - protected abstract void combatant$prepareCullFrustum(Matrix4fc viewMatrix, Matrix4f projectionMatrix, Vec3 cameraPos); + protected abstract void lovisual$prepareCullFrustum(Matrix4fc viewMatrix, Matrix4f projectionMatrix, Vec3 cameraPos); @Inject(method = "update", at = @At("TAIL")) private void freecam$override( @@ -175,11 +175,11 @@ public abstract class CameraMixin { fc.syncCameraEntity(fc.camPos, fc.camPosPrev); this.setPosition(p); - this.combatant$prepareCullFrustum(this.getViewRotationMatrix(new Matrix4f()), this.combatant$createProjectionMatrixForCulling(), p); + this.lovisual$prepareCullFrustum(this.getViewRotationMatrix(new Matrix4f()), this.lovisual$createProjectionMatrixForCulling(), p); } @Inject(method = "extractRenderState", at = @At("TAIL")) - private void combatant$freecamExtractRenderState(CameraRenderState renderState, float tickDelta, CallbackInfo ci) { + private void lovisual$freecamExtractRenderState(CameraRenderState renderState, float tickDelta, CallbackInfo ci) { Freecam fc = Modules.get(Freecam.class); if (fc == null || !fc.isEnabled() || fc.camEntity == null) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ChatComponentMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ChatComponentMixin.java index efdd8cb..b65f04a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ChatComponentMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ChatComponentMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,7 +25,7 @@ import dev.loki.lovisual.features.gui.chat.BetterChatStoreManager; import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.features.module.modules.misc.MessageFilter; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; @Mixin(ChatComponent.class) public class ChatComponentMixin { @@ -35,12 +35,12 @@ public class ChatComponentMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$filterChatFull(Component message, + private void lovisual$filterChatFull(Component message, MessageSignature signatureData, GuiMessageSource source, GuiMessageTag indicator, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; MessageFilter messageFilter = Modules.get(MessageFilter.class); if (messageFilter != null && messageFilter.shouldHideChat(message)) { ci.cancel(); @@ -52,15 +52,15 @@ public class ChatComponentMixin { } @Inject(method = "logChatMessage(Lnet/minecraft/client/multiplayer/chat/GuiMessage;)V", at = @At("HEAD"), cancellable = true) - private void combatant$commands$suppressClientLog(GuiMessage message, CallbackInfo ci) { + private void lovisual$commands$suppressClientLog(GuiMessage message, CallbackInfo ci) { if (message != null && CommandOutput.isLoVisualMessage(message.content())) { ci.cancel(); } } @Inject(method = "clearMessages(Z)V", at = @At("TAIL")) - private void combatant$betterChat$clear(boolean clearHistory, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + private void lovisual$betterChat$clear(boolean clearHistory, CallbackInfo ci) { + if (!Lifecycle.canRunHud()) return; if (!BetterChat.isActive()) return; // Never wipe BetterChat store on vanilla clear; just persist to disk. BetterChatStoreManager.flushActive(); @@ -68,7 +68,7 @@ public class ChatComponentMixin { @Inject(method = "extractRenderState(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/gui/Font;IIILnet/minecraft/client/gui/components/ChatComponent$DisplayMode;Z)V", at = @At("HEAD"), cancellable = true) - private void combatant$betterChat$hideVanilla(GuiGraphicsExtractor context, + private void lovisual$betterChat$hideVanilla(GuiGraphicsExtractor context, Font textRenderer, int currentTick, int mouseX, @@ -76,7 +76,7 @@ public class ChatComponentMixin { DisplayMode displayMode, boolean inChat, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; if (!BetterChat.isActive()) return; BetterChat cfg = BetterChat.get(); if (cfg != null && cfg.hideVanilla()) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ChatScreenMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ChatScreenMixin.java index 0a9460b..71796ce 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ChatScreenMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ChatScreenMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,14 +25,14 @@ import dev.loki.lovisual.features.command.CommandManager; import dev.loki.lovisual.features.gui.chat.BetterChatRenderer; import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; import dev.loki.lovisual.mixins.accessors.ChatScreenSuggestorAccessor; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; @Mixin(ChatScreen.class) public class ChatScreenMixin { @Inject(method = "extractRenderState(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("HEAD"), cancellable = true) - private void combatant$betterChat$render(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + private void lovisual$betterChat$render(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + if (!Lifecycle.canRunHud()) return; if (BetterChat.isActive()) { BetterChat cfg = BetterChat.get(); if (cfg != null && cfg.hideVanilla()) { @@ -50,34 +50,34 @@ public class ChatScreenMixin { target = "Lnet/minecraft/client/gui/components/ChatComponent;captureClickableText(Lnet/minecraft/client/gui/ActiveTextCollector;IILnet/minecraft/client/gui/components/ChatComponent$DisplayMode;)V" ) ) - private void combatant$betterChat$disableVanillaChatClickHitbox(ChatComponent chatHud, + private void lovisual$betterChat$disableVanillaChatClickHitbox(ChatComponent chatHud, ActiveTextCollector textConsumer, int windowHeight, int currentTick, DisplayMode displayMode) { - if (combatant$betterChat$shouldHideVanillaChat()) { + if (lovisual$betterChat$shouldHideVanillaChat()) { return; } chatHud.captureClickableText(textConsumer, windowHeight, currentTick, displayMode); } @Inject(method = "mouseScrolled(DDDD)Z", at = @At("HEAD"), cancellable = true) - private void combatant$betterChat$disableVanillaChatScroll(double mouseX, + private void lovisual$betterChat$disableVanillaChatScroll(double mouseX, double mouseY, double horizontalAmount, double verticalAmount, CallbackInfoReturnable cir) { - if (combatant$betterChat$shouldHideVanillaChat()) { + if (lovisual$betterChat$shouldHideVanillaChat()) { cir.setReturnValue(true); } } @Inject(method = "keyPressed(Lnet/minecraft/client/input/KeyEvent;)Z", at = @At("HEAD")) - private void combatant$betterChat$allowEscape(KeyEvent input, CallbackInfoReturnable cir) { - if (!RuntimeGate.canRunHud()) return; + private void lovisual$betterChat$allowEscape(KeyEvent input, CallbackInfoReturnable cir) { + if (!Lifecycle.canRunHud()) return; if (!BetterChat.isActive()) return; if (!input.isEscape()) return; - CommandSuggestions suggestor = ((ChatScreenSuggestorAccessor) this).getCombatant$suggestor(); + CommandSuggestions suggestor = ((ChatScreenSuggestorAccessor) this).getLoVisual$suggestor(); if (suggestor != null) { suggestor.setAllowSuggestions(false); suggestor.hide(); @@ -85,16 +85,16 @@ public class ChatScreenMixin { } @Inject(method = "handleChatInput(Ljava/lang/String;Z)V", at = @At("HEAD"), cancellable = true, require = 0) - private void combatant$commands$sendMessage(String message, boolean addToHistory, CallbackInfo ci) { - if (!RuntimeGate.canRunClientLogic()) return; + private void lovisual$commands$sendMessage(String message, boolean addToHistory, CallbackInfo ci) { + if (!Lifecycle.isActive()) return; if (CommandManager.handle(message)) { ci.cancel(); } } @Unique - private boolean combatant$betterChat$shouldHideVanillaChat() { - if (!RuntimeGate.canRunHud()) return false; + private boolean lovisual$betterChat$shouldHideVanillaChat() { + if (!Lifecycle.canRunHud()) return false; if (!BetterChat.isActive()) return false; BetterChat cfg = BetterChat.get(); return cfg != null && cfg.hideVanilla(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientClockManagerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientClockManagerMixin.java index ce85b44..7f563a3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientClockManagerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientClockManagerMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -22,7 +22,7 @@ import dev.loki.lovisual.features.module.modules.visuals.WorldTweaks; public abstract class ClientClockManagerMixin { @Inject(method = "getTotalTicks", at = @At("HEAD"), cancellable = true) - private void combatant$overrideRenderClock(Holder clock, CallbackInfoReturnable cir) { + private void lovisual$overrideRenderClock(Holder clock, CallbackInfoReturnable cir) { if (clock == null || !clock.is(WorldClocks.OVERWORLD)) return; WorldTweaks worldTweaks = Modules.get(WorldTweaks.class); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientCommonPacketListenerImplMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientCommonPacketListenerImplMixin.java index 403a21c..00e224f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientCommonPacketListenerImplMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientCommonPacketListenerImplMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -18,8 +18,6 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.Flight; @Mixin(ClientCommonPacketListenerImpl.class) public abstract class ClientCommonPacketListenerImplMixin { @@ -29,16 +27,7 @@ public abstract class ClientCommonPacketListenerImplMixin { protected Connection connection; @Inject(method = "send(Lnet/minecraft/network/protocol/Packet;)V", at = @At("HEAD"), cancellable = true) - private void combatant$flightSendPacket(Packet packet, CallbackInfo ci) { - if (!((Object) this instanceof ClientPacketListener)) return; - if (!(packet instanceof ServerboundMovePlayerPacket move)) return; - Flight flight = Modules.get(Flight.class); - if (flight == null || !flight.isEnabled()) return; - - ServerboundMovePlayerPacket replacement = flight.onSendMovePacket(move); - if (replacement != null && replacement != move) { - ci.cancel(); - connection.send(replacement); - } + private void lovisual$flightSendPacket(Packet packet, CallbackInfo ci) { + // Flight module removed; no move-packet override remains. } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientLevelMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientLevelMixin.java index e804dad..bd02287 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientLevelMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientLevelMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -26,7 +26,7 @@ import dev.loki.lovisual.util.block.BlockObservationHub; public abstract class ClientLevelMixin { @Inject(method = "setServerVerifiedBlockState", at = @At("TAIL")) - private void combatant$recordBlockUpdate(BlockPos pos, BlockState state, @Block.UpdateFlags int flags, CallbackInfo ci) { + private void lovisual$recordBlockUpdate(BlockPos pos, BlockState state, @Block.UpdateFlags int flags, CallbackInfo ci) { BlockObservationHub.observeWorldUpdate(pos, state); } @@ -35,7 +35,7 @@ public abstract class ClientLevelMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$noRenderEatParticles( + private void lovisual$noRenderEatParticles( ParticleOptions effect, boolean force, boolean canSpawnOnMinimal, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientPacketListenerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientPacketListenerMixin.java index f856f04..1b88e22 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientPacketListenerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ClientPacketListenerMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -28,7 +28,6 @@ import dev.loki.lovisual.events.impl.PvpTabEvent; import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.features.module.modules.combat.PvpCooldowns; import dev.loki.lovisual.features.module.modules.misc.NoSound; -import dev.loki.lovisual.features.module.modules.movement.Flight; import dev.loki.lovisual.features.module.modules.visuals.SoundESP; import dev.loki.lovisual.features.module.modules.visuals.TotemFX; import dev.loki.lovisual.features.module.modules.visuals.WorldTweaks; @@ -58,16 +57,12 @@ public abstract class ClientPacketListenerMixin { Pattern.compile("Пинг:\\s*(\\d+)"); @Inject(method = "handlePlayerAbilities", at = @At("HEAD"), cancellable = true) - private void combatant$flightAbilities(ClientboundPlayerAbilitiesPacket packet, CallbackInfo ci) { - Flight flight = Modules.get(Flight.class); - if (flight == null || !flight.isEnabled()) return; - if (flight.onReceiveAbilities(packet)) { - ci.cancel(); - } + private void lovisual$flightAbilities(ClientboundPlayerAbilitiesPacket packet, CallbackInfo ci) { + // Flight module removed; no abilities override remains. } @Inject(method = "handleTabListCustomisation", at = @At("TAIL")) - private void combatant$captureTab(ClientboundTabListPacket packet, CallbackInfo ci) { + private void lovisual$captureTab(ClientboundTabListPacket packet, CallbackInfo ci) { String header = packet.header() == null ? "" : packet.header().getString(); String footer = packet.footer() == null ? "" : packet.footer().getString(); ServerDumpUtil.dumpTabText("HEADER", packet.header()); @@ -95,7 +90,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleSoundEvent", at = @At("HEAD")) - private void combatant$onChorus(ClientboundSoundPacket packet, CallbackInfo ci) { + private void lovisual$onChorus(ClientboundSoundPacket packet, CallbackInfo ci) { // Opponent cooldown tracking disabled (legacy system). /* if (!CooldownsState.shouldTrackOpponents()) return; @@ -116,7 +111,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handlePlayerChat", at = @At("HEAD")) - private void combatant$pvpChatMessage(ClientboundPlayerChatPacket packet, CallbackInfo ci) { + private void lovisual$pvpChatMessage(ClientboundPlayerChatPacket packet, CallbackInfo ci) { String msg = packet == null ? null : packet.body().content(); if (msg == null || msg.isBlank()) return; if (Events.BUS.hasListeners(PvpChatEvent.class)) { @@ -125,7 +120,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleRemoveEntities", at = @At("TAIL")) - private void combatant$onEntitiesDestroy(ClientboundRemoveEntitiesPacket packet, CallbackInfo ci) { + private void lovisual$onEntitiesDestroy(ClientboundRemoveEntitiesPacket packet, CallbackInfo ci) { Minecraft mc = Minecraft.getInstance(); ClientLevel world = mc.level; @@ -141,7 +136,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleAddEntity", at = @At("TAIL")) - private void combatant$onEntitySpawn(ClientboundAddEntityPacket packet, CallbackInfo ci) { + private void lovisual$onEntitySpawn(ClientboundAddEntityPacket packet, CallbackInfo ci) { Minecraft mc = Minecraft.getInstance(); ClientLevel world = mc.level; @@ -156,7 +151,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handlePlayerInfoUpdate", at = @At("TAIL")) - private void combatant$onPlayerList(ClientboundPlayerInfoUpdatePacket packet, CallbackInfo ci) { + private void lovisual$onPlayerList(ClientboundPlayerInfoUpdatePacket packet, CallbackInfo ci) { var actions = packet.actions(); boolean listedAffects = actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED) @@ -184,7 +179,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handlePlayerInfoRemove", at = @At("TAIL")) - private void combatant$onPlayerRemove(ClientboundPlayerInfoRemovePacket packet, CallbackInfo ci) { + private void lovisual$onPlayerRemove(ClientboundPlayerInfoRemovePacket packet, CallbackInfo ci) { for (UUID id : packet.profileIds()) { @@ -197,12 +192,12 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleSetTime", at = @At("HEAD")) - private void combatant$captureServerTime(ClientboundSetTimePacket packet, CallbackInfo ci) { + private void lovisual$captureServerTime(ClientboundSetTimePacket packet, CallbackInfo ci) { WorldTweaks.setServerTimeOfDay(packet.gameTime()); } @Inject(method = "handleTabListCustomisation", at = @At("TAIL")) - private void combatant$onTab(ClientboundTabListPacket packet, CallbackInfo ci) { + private void lovisual$onTab(ClientboundTabListPacket packet, CallbackInfo ci) { parse(packet.header()); } @@ -231,31 +226,31 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleContainerSetSlot", at = @At("HEAD")) - private void combatant$debugSlotUpdate(ClientboundContainerSetSlotPacket packet, CallbackInfo ci) { + private void lovisual$debugSlotUpdate(ClientboundContainerSetSlotPacket packet, CallbackInfo ci) { // PvP cooldown confirmation disabled (legacy system). /* int syncId = packet.getSyncId(); int slot = packet.getSlot(); ItemStack stack = packet.getStack(); - //System.out.println("[Combatant][DEBUG] Packet slot update: syncId=" + syncId + " slot=" + slot + " item=" + stack.getItem() + " x" + stack.getCount()); + //System.out.println("[LoVisual][DEBUG] Packet slot update: syncId=" + syncId + " slot=" + slot + " item=" + stack.getItem() + " x" + stack.getCount()); var pending = CooldownsState.PENDING.consumeIfConfirmed(slot, stack.getCount()); if (pending != null) { - //System.out.println("[Combatant][DEBUG] Confirmed use of " + pending.item() + " (count decreased from " + pending.count() + " to " + stack.getCount() + ")"); + //System.out.println("[LoVisual][DEBUG] Confirmed use of " + pending.item() + " (count decreased from " + pending.count() + " to " + stack.getCount() + ")"); CooldownsState.MANAGER.commitConfirmedUse(pending.item(), pending.startedAtMs()); } */ } @Inject(method = "handleContainerContent", at = @At("HEAD")) - private void combatant$debugFullInventory(ClientboundContainerSetContentPacket packet, CallbackInfo ci) { + private void lovisual$debugFullInventory(ClientboundContainerSetContentPacket packet, CallbackInfo ci) { // PvP cooldown confirmation disabled (legacy system). /* int syncId = packet.syncId(); List contents = packet.contents(); - //System.out.println("[Combatant][DEBUG] Full inventory syncId=" + syncId + ", size=" + contents.size()); + //System.out.println("[LoVisual][DEBUG] Full inventory syncId=" + syncId + ", size=" + contents.size()); for (int i = 0; i < contents.size(); i++) { ItemStack stack = contents.get(i); @@ -263,7 +258,7 @@ public abstract class ClientPacketListenerMixin { var pending = CooldownsState.PENDING.consumeIfConfirmed(i, stack.getCount()); if (pending != null) { - //System.out.println("[Combatant][DEBUG] Confirmed (FULL INV) " + pending.item() + " slot=" + i + " count=" + stack.getCount()); + //System.out.println("[LoVisual][DEBUG] Confirmed (FULL INV) " + pending.item() + " slot=" + i + " count=" + stack.getCount()); CooldownsState.MANAGER.commitConfirmedUse(pending.item(), pending.startedAtMs()); } } @@ -271,7 +266,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleSoundEvent", at = @At("HEAD"), cancellable = true) - private void combatant$filterSound(ClientboundSoundPacket packet, CallbackInfo ci) { + private void lovisual$filterSound(ClientboundSoundPacket packet, CallbackInfo ci) { NoSound module = Modules.get(NoSound.class); if (module == null || !module.isEnabled()) return; if (packet == null || packet.getSound() == null) return; @@ -282,7 +277,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleSoundEntityEvent", at = @At("HEAD"), cancellable = true) - private void combatant$filterSoundFromEntity(ClientboundSoundEntityPacket packet, CallbackInfo ci) { + private void lovisual$filterSoundFromEntity(ClientboundSoundEntityPacket packet, CallbackInfo ci) { NoSound module = Modules.get(NoSound.class); if (module == null || !module.isEnabled()) return; if (packet == null || packet.getSound() == null) return; @@ -293,7 +288,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleParticleEvent", at = @At("HEAD")) - private void combatant$heuristicParticle(ClientboundLevelParticlesPacket packet, CallbackInfo ci) { + private void lovisual$heuristicParticle(ClientboundLevelParticlesPacket packet, CallbackInfo ci) { var p = packet.getParticle(); // Log raw particles once per hook for diagnostics DebugLog.info("Particle packet type=%s pos=%.2f %.2f %.2f count=%d", @@ -304,7 +299,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleSoundEvent", at = @At("HEAD")) - private void combatant$onPearl(ClientboundSoundPacket packet, CallbackInfo ci) { + private void lovisual$onPearl(ClientboundSoundPacket packet, CallbackInfo ci) { // Opponent cooldown tracking disabled (legacy system). /* if (!CooldownsState.shouldTrackOpponents()) return; @@ -325,7 +320,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleSoundEvent", at = @At("HEAD")) - private void combatant$onPlaySound(ClientboundSoundPacket packet, CallbackInfo ci) { + private void lovisual$onPlaySound(ClientboundSoundPacket packet, CallbackInfo ci) { SoundESP esp = Modules.get(SoundESP.class); if (esp == null || !esp.isEnabled()) return; if (packet == null || packet.getSound() == null) return; @@ -334,7 +329,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleSoundEntityEvent", at = @At("HEAD")) - private void combatant$onPlaySoundFromEntity(ClientboundSoundEntityPacket packet, CallbackInfo ci) { + private void lovisual$onPlaySoundFromEntity(ClientboundSoundEntityPacket packet, CallbackInfo ci) { SoundESP esp = Modules.get(SoundESP.class); if (esp == null || !esp.isEnabled()) return; if (packet == null || packet.getSound() == null) return; @@ -348,7 +343,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleUpdateMobEffect", at = @At("HEAD")) - private void combatant$logStatusEffect(ClientboundUpdateMobEffectPacket packet, CallbackInfo ci) { + private void lovisual$logStatusEffect(ClientboundUpdateMobEffectPacket packet, CallbackInfo ci) { DebugLog.server("Packet: add/refresh effect eid=%d effect=%s amp=%d dur=%d particles=%s icon=%s ambient=%s keepFading=%s", packet.getEntityId(), packet.getEffect().unwrapKey().map(k -> k.identifier().toString()).orElse("unknown"), @@ -362,7 +357,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleRemoveMobEffect", at = @At("HEAD")) - private void combatant$logRemove(ClientboundRemoveMobEffectPacket packet, CallbackInfo ci) { + private void lovisual$logRemove(ClientboundRemoveMobEffectPacket packet, CallbackInfo ci) { DebugLog.server("Packet: remove effect eid=%d (%s) effect=%s", packet.entityId(), resolveName(packet.entityId()), @@ -380,7 +375,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleSoundEvent", at = @At("HEAD")) - private void combatant$onTotemSound(ClientboundSoundPacket packet, CallbackInfo ci) { + private void lovisual$onTotemSound(ClientboundSoundPacket packet, CallbackInfo ci) { // Opponent cooldown tracking disabled (legacy system). /* if (!CooldownsState.shouldTrackOpponents()) return; @@ -401,7 +396,7 @@ public abstract class ClientPacketListenerMixin { } @Inject(method = "handleEntityEvent", at = @At("HEAD")) - private void combatant$onTotemStatus(ClientboundEntityEventPacket packet, CallbackInfo ci) { + private void lovisual$onTotemStatus(ClientboundEntityEventPacket packet, CallbackInfo ci) { if (packet.getEventId() == 35) { // 35 = сработал тотем бессмертия ClientPacketListener handler = (ClientPacketListener) (Object) this; Minecraft client = Minecraft.getInstance(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CommandEncoderMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CommandEncoderMixin.java index 1e1b87b..4418bc4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CommandEncoderMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CommandEncoderMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.rhi.scissor.GlobalScissorState; import dev.loki.lovisual.util.logging.DebugLog; @@ -32,7 +32,7 @@ import java.util.function.Supplier; @Mixin(CommandEncoder.class) public abstract class CommandEncoderMixin { @Unique - private static String combatant$label(Supplier label) { + private static String lovisual$label(Supplier label) { try { return label != null ? label.get() : ""; } catch (Throwable t) { @@ -41,7 +41,7 @@ public abstract class CommandEncoderMixin { } @Unique - private static @Nullable GpuTextureView combatant$firstColorView( + private static @Nullable GpuTextureView lovisual$firstColorView( List>> colorAttachments ) { if (colorAttachments == null) { @@ -56,7 +56,7 @@ public abstract class CommandEncoderMixin { } @Unique - private static @Nullable GpuTextureView combatant$depthView( + private static @Nullable GpuTextureView lovisual$depthView( @Nullable RenderPassDescriptor.Attachment depthAttachment ) { return depthAttachment == null ? null : depthAttachment.textureView(); @@ -64,7 +64,7 @@ public abstract class CommandEncoderMixin { @Unique - private static boolean combatant$isVulkanBackend() { + private static boolean lovisual$isVulkanBackend() { try { if (RenderSystem.getDevice() == null || RenderSystem.getDevice().getDeviceInfo() == null) return false; String backendName = RenderSystem.getDevice().getDeviceInfo().backendName(); @@ -75,7 +75,7 @@ public abstract class CommandEncoderMixin { } @Inject(method = "createRenderPass(Lcom/mojang/blaze3d/systems/RenderPassDescriptor;)Lcom/mojang/blaze3d/systems/RenderPass;", at = @At("RETURN")) - private void combatant$onCreateRenderPass( + private void lovisual$onCreateRenderPass( RenderPassDescriptor descriptor, CallbackInfoReturnable cir ) { @@ -86,27 +86,27 @@ public abstract class CommandEncoderMixin { try { GlobalScissorState.applyTo(pass, descriptor.renderArea); } catch (Throwable t) { - DebugLog.error("[Scissor] render pass scissor hook failed for %s", t, combatant$label(descriptor.label())); + DebugLog.error("[Scissor] render pass scissor hook failed for %s", t, lovisual$label(descriptor.label())); } try { - CombatantRenderSystem.rhi().shapeClip().beginRenderPass( - combatant$label(descriptor.label()), - combatant$firstColorView(descriptor.colorAttachments()), - combatant$depthView(descriptor.depthAttachment()) + LoVisualRenderSystem.rhi().shapeClip().beginRenderPass( + lovisual$label(descriptor.label()), + lovisual$firstColorView(descriptor.colorAttachments()), + lovisual$depthView(descriptor.depthAttachment()) ); } catch (Throwable t) { - DebugLog.error("[ShapeClip] beginRenderPass hook failed for %s", t, combatant$label(descriptor.label())); + DebugLog.error("[ShapeClip] beginRenderPass hook failed for %s", t, lovisual$label(descriptor.label())); } } @Inject(method = "submitRenderPass", at = @At("HEAD")) - private void combatant$resetRhiRenderPassState(CallbackInfo ci) { - if (combatant$isVulkanBackend()) { + private void lovisual$resetRhiRenderPassState(CallbackInfo ci) { + if (lovisual$isVulkanBackend()) { return; } try { - CombatantRenderSystem.rhi().pipelineState().resetRenderPassState(); + LoVisualRenderSystem.rhi().pipelineState().resetRenderPassState(); } catch (Throwable t) { DebugLog.error("[ShapeClip/GL] render pass reset hook failed", t); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ConnectionMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ConnectionMixin.java index 2ff395d..85a8d4d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ConnectionMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ConnectionMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -33,14 +33,14 @@ public class ConnectionMixin { } @Inject(method = "genericsFtw", at = @At("HEAD"), cancellable = true) - private static void combatant$onHandlePacket(Packet packet, PacketListener listener, CallbackInfo ci) { + private static void lovisual$onHandlePacket(Packet packet, PacketListener listener, CallbackInfo ci) { if (BlinkManager.isSilentlyHandlingPackets()) return; if (!Events.BUS.hasListeners(PacketEvent.Receive.class)) return; if (packet instanceof ClientboundBundlePacket packs) { ci.cancel(); for (Packet p : packs.subPackets()) { try { - combatant$handlePacketUnchecked(p, listener); + lovisual$handlePacketUnchecked(p, listener); } catch (RunningOnDifferentThreadException ignored) { } } @@ -55,12 +55,12 @@ public class ConnectionMixin { @Unique @SuppressWarnings({"rawtypes", "unchecked"}) - private static void combatant$handlePacketUnchecked(Packet packet, PacketListener listener) { + private static void lovisual$handlePacketUnchecked(Packet packet, PacketListener listener) { ConnectionMixin.genericsFtw((Packet) packet, listener); } @Inject(method = "genericsFtw", at = @At("TAIL")) - private static void combatant$onHandlePacketPost(Packet packet, PacketListener listener, CallbackInfo ci) { + private static void lovisual$onHandlePacketPost(Packet packet, PacketListener listener, CallbackInfo ci) { if (BlinkManager.isSilentlyHandlingPackets()) return; if (!Events.BUS.hasListeners(PacketEvent.ReceivePost.class)) return; if (packet instanceof ClientboundBundlePacket packs) { @@ -75,7 +75,7 @@ public class ConnectionMixin { } @Inject(method = "send(Lnet/minecraft/network/protocol/Packet;)V", at = @At("HEAD"), cancellable = true) - private void combatant$onSendPacketPre(Packet packet, CallbackInfo ci) { + private void lovisual$onSendPacketPre(Packet packet, CallbackInfo ci) { if (BlinkManager.isSilentlyHandlingPackets()) return; if (!Events.BUS.hasListeners(PacketEvent.Send.class)) return; PacketEvent.Send event = new PacketEvent.Send(packet); @@ -86,7 +86,7 @@ public class ConnectionMixin { } @Inject(method = "send(Lnet/minecraft/network/protocol/Packet;)V", at = @At("RETURN")) - private void combatant$onSendPacketPost(Packet packet, CallbackInfo ci) { + private void lovisual$onSendPacketPost(Packet packet, CallbackInfo ci) { if (BlinkManager.isSilentlyHandlingPackets()) return; if (!Events.BUS.hasListeners(PacketEvent.SendPost.class)) return; PacketEvent.SendPost event = new PacketEvent.SendPost(packet); @@ -94,7 +94,7 @@ public class ConnectionMixin { } @Inject(method = "configurePacketHandler", at = @At("HEAD")) - private void combatant$installProxyHandler(ChannelPipeline pipeline, CallbackInfo ci) { + private void lovisual$installProxyHandler(ChannelPipeline pipeline, CallbackInfo ci) { ProxyNettyInstaller.install(pipeline); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ContextualBarMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ContextualBarMixin.java index 9943774..ebb5298 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ContextualBarMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ContextualBarMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,17 +16,17 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.loki.lovisual.features.gui.hud.nondraggable.impl.CustomBar; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; @Mixin(ContextualBar.class) public interface ContextualBarMixin { @Inject(method = "extractExperienceLevel", at = @At("HEAD"), cancellable = true) - private static void combatant$drawExperienceLevel(GuiGraphicsExtractor context, + private static void lovisual$drawExperienceLevel(GuiGraphicsExtractor context, Font textRenderer, int level, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CycleButtonMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CycleButtonMixin.java index dc2ba7f..b384f27 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CycleButtonMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/CycleButtonMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,7 +25,7 @@ import dev.loki.lovisual.mixins.accessors.CyclingButtonWidgetAccessor; public abstract class CycleButtonMixin { @Inject(method = "extractContents(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("HEAD"), cancellable = true) - private void combatant$drawIcon(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void lovisual$drawIcon(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { BetterButtons buttons = BetterButtons.get(); if (buttons == null || !buttons.useUiButtons()) return; Minecraft mc = Minecraft.getInstance(); @@ -37,11 +37,11 @@ public abstract class CycleButtonMixin { float hover = BetterButtons.updateHover(widget, hovered, mouseX, mouseY); CyclingButtonWidgetAccessor accessor = (CyclingButtonWidgetAccessor) self; - Identifier icon = accessor.combatant$getIcon() != null - ? accessor.combatant$getIcon().apply(self, self.getValue()) + Identifier icon = accessor.lovisual$getIcon() != null + ? accessor.lovisual$getIcon().apply(self, self.getValue()) : null; - boolean showLabel = accessor.combatant$getLabelType() != CycleButton.DisplayState.HIDE; + boolean showLabel = accessor.lovisual$getLabelType() != CycleButton.DisplayState.HIDE; BetterButtons.enqueueCyclingButton(self, icon, showLabel, hover, widget.isActive(), widget.isFocused()); if (hovered) { BetterButtons.captureTooltip(widget, mouseX, mouseY); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/DebugHudMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/DebugHudMixin.java index cee35b1..0b16c58 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/DebugHudMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/DebugHudMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,12 +12,11 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyArg; import dev.loki.lovisual.config.MainConfig; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.debug.RenderThread2DDebugRenderer; import dev.loki.lovisual.render.engine.msaa.MsaaWorldTarget; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.text.FontDebugStats; -import dev.loki.lovisual.runtime.RuntimeGate; import dev.loki.lovisual.util.logging.DebugMode; import dev.loki.lovisual.util.wav.WavDebugStats; @@ -35,13 +34,13 @@ public abstract class DebugHudMixin { ), index = 1 ) - private List combatant$addEngineInfo(List list) { - if (RuntimeGate.isPanic() || list == null) return list; + private List lovisual$addEngineInfo(List list) { + if (list == null) return list; DebugMode debugMode = MainConfig.get().getDebugMode(); if (debugMode != DebugMode.ALL && debugMode != DebugMode.RENDER_THREAD) return list; int samples = MainConfig.get().getMsaa3dSamples(); - boolean supported = CombatantRenderSystem.rhi().msaa().supported(); + boolean supported = LoVisualRenderSystem.rhi().msaa().supported(); MsaaWorldTarget.DebugStatus msaaStatus = MsaaWorldTarget.debugStatus(); String msaa; if (samples <= 1) { @@ -62,7 +61,7 @@ public abstract class DebugHudMixin { } List out = new ArrayList<>(list.size() + 20); - out.add("§cCombatant Engine"); + out.add("§cLoVisual Engine"); out.add("status:§aok"); out.add(msaa); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/DynamicUniformStorageMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/DynamicUniformStorageMixin.java index ae44db4..22fac7e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/DynamicUniformStorageMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/DynamicUniformStorageMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -29,8 +29,8 @@ public abstract class DynamicUniformStorageMixin { target = "Lorg/slf4j/Logger;info(Ljava/lang/String;[Ljava/lang/Object;)V" ) ) - private void combatant$redirectResizeLog(Logger logger, String format, Object[] args) { - if (label != null && label.startsWith("Combatant")) { + private void lovisual$redirectResizeLog(Logger logger, String format, Object[] args) { + if (label != null && label.startsWith("LoVisual")) { String message = "Resizing " + args[0] + ", capacity limit of " + args[1] + " reached during a single frame. New capacity will be " + args[2] + "."; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/EntityMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/EntityMixin.java index a919afe..35316ef 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/EntityMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/EntityMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -27,8 +27,6 @@ import dev.loki.lovisual.events.impl.PlayerStepEvent; import dev.loki.lovisual.events.impl.PlayerStepSuccessEvent; import dev.loki.lovisual.events.impl.PlayerVelocityStrafe; import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.NoPush; -import dev.loki.lovisual.features.module.modules.movement.NoStun; import dev.loki.lovisual.mixininterface.IEntity; import dev.loki.lovisual.mixins.accessors.EntityAccessor; import dev.loki.lovisual.mixins.accessors.EntityInvoker; @@ -50,11 +48,11 @@ public abstract class EntityMixin implements IEntity { @Shadow public double zOld; @Unique - private MoverType combatant$lastMoveType = MoverType.SELF; + private MoverType lovisual$lastMoveType = MoverType.SELF; @Unique - private Vec3 combatant$stepBeforePos = Vec3.ZERO; + private Vec3 lovisual$stepBeforePos = Vec3.ZERO; @Unique - private Vec3 combatant$stepRequestedMovement = Vec3.ZERO; + private Vec3 lovisual$stepRequestedMovement = Vec3.ZERO; @Unique @Override @@ -64,41 +62,41 @@ public abstract class EntityMixin implements IEntity { @Unique @Override - public List combatant$getTrails() { + public List lovisual$getTrails() { return trails; } @Inject(method = "move", at = @At("HEAD")) - private void combatant$cacheMoveType(MoverType type, Vec3 movement, CallbackInfo ci) { - combatant$lastMoveType = type; + private void lovisual$cacheMoveType(MoverType type, Vec3 movement, CallbackInfo ci) { + lovisual$lastMoveType = type; Entity self = (Entity) (Object) this; if (self instanceof LocalPlayer) { - combatant$stepBeforePos = self.position(); - combatant$stepRequestedMovement = movement; + lovisual$stepBeforePos = self.position(); + lovisual$stepRequestedMovement = movement; } } @ModifyVariable(method = "move", at = @At("HEAD"), argsOnly = true, index = 2) - private Vec3 combatant$onMove(Vec3 movement) { + private Vec3 lovisual$onMove(Vec3 movement) { Entity self = (Entity) (Object) this; if (!(self instanceof LocalPlayer)) return movement; if (!Events.BUS.hasListeners(PlayerMoveEvent.class)) return movement; - PlayerMoveEvent event = new PlayerMoveEvent(combatant$lastMoveType, movement); + PlayerMoveEvent event = new PlayerMoveEvent(lovisual$lastMoveType, movement); Events.BUS.post(event); Vec3 out = event.getMovement(); return out != null ? out : movement; } @Inject(method = "move", at = @At("RETURN")) - private void combatant$onMoveReturn(MoverType type, Vec3 movement, CallbackInfo ci) { + private void lovisual$onMoveReturn(MoverType type, Vec3 movement, CallbackInfo ci) { Entity self = (Entity) (Object) this; if (!(self instanceof LocalPlayer)) return; if (!Events.BUS.hasListeners(PlayerStepSuccessEvent.class)) return; - Vec3 before = combatant$stepBeforePos; + Vec3 before = lovisual$stepBeforePos; Vec3 after = self.position(); - Vec3 requested = combatant$stepRequestedMovement; + Vec3 requested = lovisual$stepRequestedMovement; double yDelta = after.y - before.y; double horizontalRequested = Math.hypot(requested.x, requested.z); if (yDelta <= 0.5 || horizontalRequested <= 1.0E-5) return; @@ -107,7 +105,7 @@ public abstract class EntityMixin implements IEntity { } @ModifyReturnValue(method = "maxUpStep", at = @At("RETURN")) - private float combatant$modifyStepHeight(float original) { + private float lovisual$modifyStepHeight(float original) { Entity self = (Entity) (Object) this; if (!(self instanceof LocalPlayer)) return original; if (!Events.BUS.hasListeners(PlayerStepEvent.class)) return original; @@ -124,9 +122,9 @@ public abstract class EntityMixin implements IEntity { target = "Lnet/minecraft/world/entity/Entity;getInputVector(Lnet/minecraft/world/phys/Vec3;FF)Lnet/minecraft/world/phys/Vec3;" ) ) - private Vec3 combatant$velocityStrafe(Vec3 movementInput, float speed, float yaw) { + private Vec3 lovisual$velocityStrafe(Vec3 movementInput, float speed, float yaw) { Entity self = (Entity) (Object) this; - Vec3 vanilla = EntityInvoker.combatant$movementInputToVelocity(movementInput, speed, yaw); + Vec3 vanilla = EntityInvoker.lovisual$movementInputToVelocity(movementInput, speed, yaw); if (!(self instanceof LocalPlayer)) return vanilla; if (!Events.BUS.hasListeners(PlayerVelocityStrafe.class)) return vanilla; @@ -141,7 +139,7 @@ public abstract class EntityMixin implements IEntity { ordinal = 0, argsOnly = true ) - private float combatant$rotationVectorPitch(float pitch) { + private float lovisual$rotationVectorPitch(float pitch) { if (!((Object) this instanceof LocalPlayer)) { return pitch; } @@ -158,32 +156,14 @@ public abstract class EntityMixin implements IEntity { target = "Lnet/minecraft/world/entity/Entity;push(DDD)V" ) ) - private void combatant$cancelEntityPush(Entity instance, double x, double y, double z) { - NoPush noPush = Modules.get(NoPush.class); - if (noPush == null || !noPush.off("players")) { - instance.push(x, y, z); - } + private void lovisual$cancelEntityPush(Entity instance, double x, double y, double z) { + // NoPush module removed; keep vanilla entity pushing. + instance.push(x, y, z); } @Inject(method = "makeStuckInBlock", at = @At("HEAD"), cancellable = true) private void nostun$cancelSlowMovement(BlockState state, Vec3 multiplier, CallbackInfo ci) { - Entity self = (Entity) (Object) this; - if (!(self instanceof LocalPlayer)) return; - - NoStun ns = Modules.get(NoStun.class); - if (ns == null || !ns.isEnabled()) return; - - Vec3 override = ns.getSlowMovementOverride(state, multiplier); - if (override != null && self instanceof EntityAccessor accessor) { - self.resetFallDistance(); - accessor.combatant$setMovementMultiplier(override); - ci.cancel(); - return; - } - - if (ns.shouldCancelSlowMovement(state)) { - ci.cancel(); - } + // NoStun module removed; no slow-movement override remains. } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/EquipmentLayerRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/EquipmentLayerRendererMixin.java index cd20fb4..2c96ac9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/EquipmentLayerRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/EquipmentLayerRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ public abstract class EquipmentLayerRendererMixin { method = "renderLayers(Lnet/minecraft/client/resources/model/EquipmentClientInfo$LayerType;Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/client/model/Model;Ljava/lang/Object;Lnet/minecraft/world/item/ItemStack;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/resources/Identifier;II)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/rendertype/RenderTypes;armorCutoutNoCull(Lnet/minecraft/resources/Identifier;)Lnet/minecraft/client/renderer/rendertype/RenderType;") ) - private RenderType combatant$useTranslucentArmorWhenViewFaded(Identifier texture) { + private RenderType lovisual$useTranslucentArmorWhenViewFaded(Identifier texture) { if (IrisRuntime.isRenderingShadowPass()) { return RenderTypes.armorCutoutNoCull(texture); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ExperienceBarMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ExperienceBarMixin.java index 8c4c68f..5f2eee8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ExperienceBarMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ExperienceBarMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,14 +16,14 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.loki.lovisual.features.gui.hud.nondraggable.impl.CustomBar; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; @Mixin(ExperienceBar.class) public abstract class ExperienceBarMixin { @Inject(method = "extractBackground", at = @At("HEAD"), cancellable = true) - private void combatant$renderXpBar(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + private void lovisual$renderXpBar(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { + if (!Lifecycle.canRunHud()) return; Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; @@ -36,8 +36,8 @@ public abstract class ExperienceBarMixin { } @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) - private void combatant$renderXpAddons(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + private void lovisual$renderXpAddons(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { + if (!Lifecycle.canRunHud()) return; Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FireworkRocketEntityMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FireworkRocketEntityMixin.java index de409c7..6190550 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FireworkRocketEntityMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FireworkRocketEntityMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -43,7 +43,7 @@ public abstract class FireworkRocketEntityMixin { target = "Lnet/minecraft/world/entity/LivingEntity;getLookAngle()Lnet/minecraft/world/phys/Vec3;" ) ) - private Vec3 combatant$fireworkMoveRotation(LivingEntity instance, Operation original) { + private Vec3 lovisual$fireworkMoveRotation(LivingEntity instance, Operation original) { Minecraft mc = Minecraft.getInstance(); if (mc == null || attachedToEntity != mc.player) { return original.call(instance); @@ -60,7 +60,7 @@ public abstract class FireworkRocketEntityMixin { ordinal = 0 ) ) - private Vec3 combatant$fireworkVelocityHook(LivingEntity instance, Operation original) { + private Vec3 lovisual$fireworkVelocityHook(LivingEntity instance, Operation original) { Minecraft mc = Minecraft.getInstance(); Vec3 velocity = original.call(instance); if (mc == null || attachedToEntity != mc.player || !Events.BUS.hasListeners(FireworkEvent.class)) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FlowingFluidMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FlowingFluidMixin.java index 2163715..22f593f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FlowingFluidMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FlowingFluidMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * Portions derived from ThunderHack Recode, copyright (c) 2023-2024 Pan4ur & 06ED. * Upstream: https://github.com/Pan4ur/ThunderHack-Recode @@ -20,8 +20,6 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.NoPush; import static net.minecraft.world.level.material.FlowingFluid.FALLING; @@ -32,24 +30,7 @@ public abstract class FlowingFluidMixin { protected abstract boolean isSolidFace(BlockGetter world, BlockPos pos, Direction direction); @Inject(method = "getFlow", at = @At("HEAD"), cancellable = true) - private void combatant$getVelocity(BlockGetter world, BlockPos pos, FluidState state, CallbackInfoReturnable cir) { - NoPush np = Modules.get(NoPush.class); - if (np == null || !np.liquidsEnabled()) return; - - double d = 0.0; - double e = 0.0; - BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); - Vec3 vec3d = new Vec3(d, 0.0, e); - if (state.getValue(FALLING)) { - for (Direction direction2 : Direction.Plane.HORIZONTAL) { - mutable.setWithOffset(pos, direction2); - if (!this.isSolidFace(world, mutable, direction2) && !this.isSolidFace(world, mutable.above(), direction2)) { - continue; - } - vec3d = vec3d.normalize().add(0.0, -6.0, 0.0); - break; - } - } - cir.setReturnValue(vec3d.normalize()); + private void lovisual$getVelocity(BlockGetter world, BlockPos pos, FluidState state, CallbackInfoReturnable cir) { + // NoPush module removed; no fluid velocity override remains. } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FogRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FogRendererMixin.java index fe86c41..2553bd5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FogRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FogRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -29,7 +29,7 @@ public class FogRendererMixin { at = @At("HEAD"), argsOnly = true, index = 2) - private int combatant$disableDistanceFog(int value) { + private int lovisual$disableDistanceFog(int value) { WorldTweaks module = Modules.get(WorldTweaks.class); if (module == null || !module.isFogControlEnabled()) return value; Minecraft mc = Minecraft.getInstance(); @@ -61,7 +61,7 @@ public class FogRendererMixin { at = @At("RETURN"), cancellable = true ) - private void combatant$modifyFogColor(Camera camera, + private void lovisual$modifyFogColor(Camera camera, float tickDelta, ClientLevel world, int viewDistance, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FontManagerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FontManagerMixin.java index 22e44b9..b1cdc85 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FontManagerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/FontManagerMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -24,7 +24,7 @@ public abstract class FontManagerMixin { target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;[Ljava/lang/Object;)V" ) ) - private static void combatant$maybeSuppressFontLoadWarn( + private static void lovisual$maybeSuppressFontLoadWarn( Logger logger, String format, Object[] args diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GameRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GameRendererMixin.java index 664a50b..7ca0f07 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GameRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GameRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -52,15 +52,15 @@ import dev.loki.lovisual.features.module.modules.visuals.*; import dev.loki.lovisual.mixins.accessors.GameRendererAccessor; import dev.loki.lovisual.mixins.accessors.LocalPlayerAccessor; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; -import dev.loki.lovisual.render.engine.core.CombatantWorldMatrices; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualWorldMatrices; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.RenderPhaseScope; import dev.loki.lovisual.render.engine.depth.WorldSceneDepth; // import dev.loki.lovisual.render.engine.debug.RenderThread2DDebugRenderer; // disabled: debug probes are manual-only import dev.loki.lovisual.render.engine.msaa.MsaaWorldTarget; import dev.loki.lovisual.config.MainConfig; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.postprocess.MenuBackgroundRenderer; import dev.loki.lovisual.render.engine.profiler.ProfilerPhase; @@ -70,8 +70,8 @@ import dev.loki.lovisual.render.engine.renderer.MeshRenderer; 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.render.engine.visuals.CombatantVisuals; -import dev.loki.lovisual.render.iris.IrisCombatantFrameHooks; +import dev.loki.lovisual.render.engine.visuals.LoVisualVisuals; +import dev.loki.lovisual.render.iris.IrisLoVisualFrameHooks; import dev.loki.lovisual.render.iris.IrisFinalizedSceneRenderer; import dev.loki.lovisual.render.iris.IrisCompatibilityGuards; import dev.loki.lovisual.render.iris.IrisRuntime; @@ -81,17 +81,17 @@ import dev.loki.lovisual.util.logging.DebugLog; public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { @Unique - private static final boolean COMBATANT_DEBUG_PRIMITIVE = false; + private static final boolean LOVISUAL_DEBUG_PRIMITIVE = false; @Unique - private static final boolean COMBATANT_DEBUG_CLIP_SPACE = false; + private static final boolean LOVISUAL_DEBUG_CLIP_SPACE = false; @Unique - private static final long COMBATANT_DEBUG_INTERVAL_MS = 2000L; + private static final long LOVISUAL_DEBUG_INTERVAL_MS = 2000L; @Unique - private static long COMBATANT_DEBUG_LAST_MS; + private static long LOVISUAL_DEBUG_LAST_MS; @Unique - private final PoseStack combatant$matrices = new PoseStack(); + private final PoseStack lovisual$matrices = new PoseStack(); @Unique - private final PoseStack combatant$postMatrices = new PoseStack(); + private final PoseStack lovisual$postMatrices = new PoseStack(); @Shadow @Final private Minecraft minecraft; @@ -106,16 +106,16 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { @Shadow private float spinningEffectSpeed; @Unique - private Renderer3D combatant$renderer; + private Renderer3D lovisual$renderer; @Unique - private Renderer3D combatant$depthRenderer; + private Renderer3D lovisual$depthRenderer; @Unique - private Renderer3D combatant$postRenderer; + private Renderer3D lovisual$postRenderer; @Unique - private Renderer3D combatant$postDepthRenderer; + private Renderer3D lovisual$postDepthRenderer; @Unique - private static void combatant$drawDebugCube(Renderer3D rdr, + private static void lovisual$drawDebugCube(Renderer3D rdr, double x1, double y1, double z1, double x2, double y2, double z2) { rdr.line(x1, y1, z1, x2, y1, z1, 255, 0, 0, 255); @@ -148,7 +148,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { protected abstract void bobHurt(CameraRenderState cameraRenderState, PoseStack matrices); @Unique - private static boolean combatant$needsResolvedMainDepth() { + private static boolean lovisual$needsResolvedMainDepth() { ReimaginedVisual module = Modules.get(ReimaginedVisual.class); if (module == null) return false; if (module.needsResolvedMainDepthCapture()) return true; @@ -156,19 +156,19 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { } @Inject(method = "tick", at = @At("HEAD"), cancellable = true) - private void combatant$skipTickWithoutPlayer(CallbackInfo ci) { + private void lovisual$skipTickWithoutPlayer(CallbackInfo ci) { if (minecraft != null && minecraft.level != null && minecraft.player == null) { ci.cancel(); } } @Inject(method = "extract(Lnet/minecraft/client/DeltaTracker;Z)V", at = @At("HEAD")) - private void combatant$beginDeferred2DExtract(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { + private void lovisual$beginDeferred2DExtract(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { Renderer2D.beginDeferredExtractFrame(); } @Inject(method = "extract(Lnet/minecraft/client/DeltaTracker;Z)V", at = @At("TAIL")) - private void combatant$endDeferred2DExtract(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { + private void lovisual$endDeferred2DExtract(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { Renderer2D.endDeferredExtractFrame(); } @@ -179,7 +179,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { target = "Lnet/minecraft/client/renderer/GameRenderer;bobView(Lnet/minecraft/client/renderer/state/level/CameraRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;)V" ) ) - private void combatant$viewModel$replaceHandBobbing(GameRenderer instance, + private void lovisual$viewModel$replaceHandBobbing(GameRenderer instance, CameraRenderState cameraRenderState, PoseStack matrices, CameraRenderState originalCameraRenderState, @@ -201,7 +201,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { } @Inject(method = "extractCamera", at = @At("TAIL")) - private void combatant$modifyAspect(DeltaTracker tickCounter, float tickDelta, float fov, CallbackInfo ci) { + private void lovisual$modifyAspect(DeltaTracker tickCounter, float tickDelta, float fov, CallbackInfo ci) { AspectRatio ar = Modules.get(AspectRatio.class); if (ar == null || !ar.isEnabled()) { @@ -221,16 +221,16 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { } @Inject(method = "extractCamera", at = @At("TAIL")) - private void combatant$captureProjectionFor2DOverlays(DeltaTracker tickCounter, float tickDelta, float fov, CallbackInfo ci) { + private void lovisual$captureProjectionFor2DOverlays(DeltaTracker tickCounter, float tickDelta, float fov, CallbackInfo ci) { if (gameRenderState == null || gameRenderState.levelRenderState == null) return; CameraRenderState cameraRenderState = gameRenderState.levelRenderState.cameraRenderState; if (cameraRenderState == null || cameraRenderState.viewRotationMatrix == null || cameraRenderState.projectionMatrix == null) return; PoseStack effectMatrices = new PoseStack(); - Matrix4f renderProjection = combatant$buildWorldProjection(fov, effectMatrices, tickDelta); + Matrix4f renderProjection = lovisual$buildWorldProjection(fov, effectMatrices, tickDelta); AspectRatio.applyToProjection(renderProjection); Matrix4f screenProjection = new Matrix4f(cameraRenderState.projectionMatrix); - CombatantWorldMatrices.capture( + LoVisualWorldMatrices.capture( cameraRenderState.viewRotationMatrix, renderProjection, screenProjection, @@ -239,7 +239,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { } @Inject(method = "mainRenderTarget", at = @At("HEAD"), cancellable = true) - private void combatant$overrideWorldFramebuffer(CallbackInfoReturnable cir) { + private void lovisual$overrideWorldFramebuffer(CallbackInfoReturnable cir) { com.mojang.blaze3d.pipeline.RenderTarget msaa = MsaaWorldTarget.getFramebufferOverride(); if (msaa != null) { cir.setReturnValue(msaa); @@ -247,20 +247,20 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { } @Unique - private void combatant$renderWorldEngine(DeltaTracker tickCounter) { + private void lovisual$renderWorldEngine(DeltaTracker tickCounter) { try (ProfilerPhase.Scope phaseScope = ProfilerPhase.scope("3d:world"); TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("3d:world")) { float tickDelta = tickCounter.getGameTimeDeltaPartialTick(true); float fov = mainCamera.getFov(); - Matrix4f capturedPosition = CombatantWorldMatrices.positionMatrix(); - Matrix4f capturedProjection = CombatantWorldMatrices.renderProjectionMatrix(); + Matrix4f capturedPosition = LoVisualWorldMatrices.positionMatrix(); + Matrix4f capturedProjection = LoVisualWorldMatrices.renderProjectionMatrix(); boolean useCapturedMatrices = capturedPosition != null && capturedProjection != null; Matrix4f position = useCapturedMatrices ? capturedPosition : new Matrix4f().rotation(mainCamera.rotation().conjugate(new org.joml.Quaternionf())); RenderState.rendering3D = true; RenderState.tickDelta = tickDelta; - Vec3 capturedCameraPos = CombatantWorldMatrices.cameraPosition(); + Vec3 capturedCameraPos = LoVisualWorldMatrices.cameraPosition(); RenderState.cameraPos = capturedCameraPos != null ? capturedCameraPos : mainCamera.position(); RenderState.cameraRotation.set(mainCamera.rotation()); RenderState.cameraYaw = mainCamera.yRot(); @@ -275,7 +275,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { ? mainCamera.getCapturedFrustum() : null; - if (COMBATANT_DEBUG_CLIP_SPACE) { + if (LOVISUAL_DEBUG_CLIP_SPACE) { var mv = com.mojang.blaze3d.systems.RenderSystem.getModelViewStack(); mv.pushMatrix(); mv.identity(); @@ -283,76 +283,76 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { MeshRenderer.setProjection(new Matrix4f().identity()); RenderState.rendering3D = false; - if (combatant$renderer == null) { - combatant$renderer = new Renderer3D( - CombatantRenderPipelines.WORLD_COLORED_LINES, - CombatantRenderPipelines.WORLD_COLORED + if (lovisual$renderer == null) { + lovisual$renderer = new Renderer3D( + LoVisualRenderPipelines.WORLD_COLORED_LINES, + LoVisualRenderPipelines.WORLD_COLORED ); } - combatant$renderer.begin(); + lovisual$renderer.begin(); // Clip-space square + diagonals (NDC) - combatant$renderer.line(-0.8, -0.8, 0.0, 0.8, -0.8, 0.0, 255, 0, 0, 255); - combatant$renderer.line(0.8, -0.8, 0.0, 0.8, 0.8, 0.0, 0, 255, 0, 255); - combatant$renderer.line(0.8, 0.8, 0.0, -0.8, 0.8, 0.0, 0, 0, 255, 255); - combatant$renderer.line(-0.8, 0.8, 0.0, -0.8, -0.8, 0.0, 255, 255, 0, 255); - combatant$renderer.line(-0.8, -0.8, 0.0, 0.8, 0.8, 0.0, 255, 0, 255, 255); - combatant$renderer.line(0.8, -0.8, 0.0, -0.8, 0.8, 0.0, 0, 255, 255, 255); + lovisual$renderer.line(-0.8, -0.8, 0.0, 0.8, -0.8, 0.0, 255, 0, 0, 255); + lovisual$renderer.line(0.8, -0.8, 0.0, 0.8, 0.8, 0.0, 0, 255, 0, 255); + lovisual$renderer.line(0.8, 0.8, 0.0, -0.8, 0.8, 0.0, 0, 0, 255, 255); + lovisual$renderer.line(-0.8, 0.8, 0.0, -0.8, -0.8, 0.0, 255, 255, 0, 255); + lovisual$renderer.line(-0.8, -0.8, 0.0, 0.8, 0.8, 0.0, 255, 0, 255, 255); + lovisual$renderer.line(0.8, -0.8, 0.0, -0.8, 0.8, 0.0, 0, 255, 255, 255); - combatant$renderer.render(new PoseStack()); + lovisual$renderer.render(new PoseStack()); mv.popMatrix(); RenderState.rendering3D = false; return; } - if (combatant$renderer == null) { - combatant$renderer = new Renderer3D( - CombatantRenderPipelines.WORLD_COLORED_LINES, - CombatantRenderPipelines.WORLD_COLORED + if (lovisual$renderer == null) { + lovisual$renderer = new Renderer3D( + LoVisualRenderPipelines.WORLD_COLORED_LINES, + LoVisualRenderPipelines.WORLD_COLORED ); } - if (combatant$depthRenderer == null) { - combatant$depthRenderer = new Renderer3D( - CombatantRenderPipelines.WORLD_COLORED_LINES_DEPTH, - CombatantRenderPipelines.WORLD_COLORED_DEPTH + if (lovisual$depthRenderer == null) { + lovisual$depthRenderer = new Renderer3D( + LoVisualRenderPipelines.WORLD_COLORED_LINES_DEPTH, + LoVisualRenderPipelines.WORLD_COLORED_DEPTH ); } var mv = com.mojang.blaze3d.systems.RenderSystem.getModelViewStack(); mv.pushMatrix(); - if (IrisCombatantFrameHooks.isRenderingAfterIrisFinalization()) { + if (IrisLoVisualFrameHooks.isRenderingAfterIrisFinalization()) { mv.identity(); } mv.mul(position); - combatant$matrices.pushPose(); + lovisual$matrices.pushPose(); Matrix4f projection = useCapturedMatrices ? capturedProjection - : combatant$buildWorldProjection(fov, combatant$matrices, tickDelta); + : lovisual$buildWorldProjection(fov, lovisual$matrices, tickDelta); MeshRenderer.setProjection(projection); - CombatantRenderSystem.beginFrame( + LoVisualRenderSystem.beginFrame( tickDelta, tickCounter.getGameTimeDeltaTicks(), tickCounter.getRealtimeDeltaTicks(), projection, new Matrix4f(mv) ); - try (RenderPhaseScope combatant$beforeTranslucentPhase = CombatantRenderSystem.phase(RenderPhase.WORLD_BEFORE_TRANSLUCENT)) { + try (RenderPhaseScope lovisual$beforeTranslucentPhase = LoVisualRenderSystem.phase(RenderPhase.WORLD_BEFORE_TRANSLUCENT)) { RenderState.worldProjection.set(projection); RenderState.frustum = new Frustum(position, projection); RenderState.frustum.prepare(RenderState.cameraPos.x, RenderState.cameraPos.y, RenderState.cameraPos.z); if (!useCapturedMatrices) { - Matrix4f inverseBob = new Matrix4f(combatant$matrices.last().pose()).invert(); + Matrix4f inverseBob = new Matrix4f(lovisual$matrices.last().pose()).invert(); mv.mul(inverseBob); } - combatant$renderer.begin(); - combatant$depthRenderer.begin(); + lovisual$renderer.begin(); + lovisual$depthRenderer.begin(); - if (COMBATANT_DEBUG_PRIMITIVE) { + if (LOVISUAL_DEBUG_PRIMITIVE) { Vec3 camPos = mainCamera.position(); float yaw = mainCamera.yRot() * ((float) Math.PI / 180.0f); float pitch = mainCamera.xRot() * ((float) Math.PI / 180.0f); @@ -371,18 +371,18 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { double ox2 = 1.0, oy2 = 1.0, oz2 = 1.0; // Wire cube (no depth) and depth variant - Renderer3D[] targets = new Renderer3D[]{combatant$renderer, combatant$depthRenderer}; + Renderer3D[] targets = new Renderer3D[]{lovisual$renderer, lovisual$depthRenderer}; for (Renderer3D rdr : targets) { - combatant$drawDebugCube(rdr, x1, y1, z1, x2, y2, z2); - combatant$drawDebugCube(rdr, ox1, oy1, oz1, ox2, oy2, oz2); + lovisual$drawDebugCube(rdr, x1, y1, z1, x2, y2, z2); + lovisual$drawDebugCube(rdr, ox1, oy1, oz1, ox2, oy2, oz2); } long now = System.currentTimeMillis(); - if (now - COMBATANT_DEBUG_LAST_MS >= COMBATANT_DEBUG_INTERVAL_MS) { - COMBATANT_DEBUG_LAST_MS = now; + if (now - LOVISUAL_DEBUG_LAST_MS >= LOVISUAL_DEBUG_INTERVAL_MS) { + LOVISUAL_DEBUG_LAST_MS = now; Matrix4f mvMat = com.mojang.blaze3d.systems.RenderSystem.getModelViewMatrixCopy(); DebugLog.renderThread( - "[Combatant] Debug diag: cam=" + camPos + "[LoVisual] Debug diag: cam=" + camPos + " proj=[" + projection.m00() + "," + projection.m11() + "," + projection.m22() + "," + projection.m33() + "]" + " mv=[" + mvMat.m30() + "," + mvMat.m31() + "," + mvMat.m32() + "]" ); @@ -391,39 +391,39 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { try (ProfilerPhase.Scope phase = ProfilerPhase.scope("3d:modules_before_translucent"); RenderProfiler3D.Section ignored = RenderProfiler3D.section("modules_before_translucent")) { - ModuleManager.renderWorldEngine(WorldPhase.BEFORE_TRANSLUCENT, combatant$renderer, combatant$depthRenderer, tickDelta); + ModuleManager.renderWorldEngine(WorldPhase.BEFORE_TRANSLUCENT, lovisual$renderer, lovisual$depthRenderer, tickDelta); AddonRenderPipelineManager.render3D(LoVisualRenderStage.WORLD_BEFORE_TRANSLUCENT, - WorldPhase.BEFORE_TRANSLUCENT, combatant$renderer, combatant$depthRenderer, combatant$matrices, tickDelta); + WorldPhase.BEFORE_TRANSLUCENT, lovisual$renderer, lovisual$depthRenderer, lovisual$matrices, tickDelta); } try (ProfilerPhase.Scope phase = ProfilerPhase.scope("3d:flush_before_translucent"); TracyGpuProfiler.Scope gpuFlush = TracyGpuProfiler.beginZone("3d:flush_before_translucent"); RenderProfiler3D.Section ignored = RenderProfiler3D.section("flush_before_translucent")) { - combatant$renderer.render(combatant$matrices); - combatant$depthRenderer.render(combatant$matrices); + lovisual$renderer.render(lovisual$matrices); + lovisual$depthRenderer.render(lovisual$matrices); } } // Start a new batch for END_MAIN so overlays render above grass. - combatant$renderer.begin(); - combatant$depthRenderer.begin(); + lovisual$renderer.begin(); + lovisual$depthRenderer.begin(); - try (RenderPhaseScope combatant$afterTranslucentPhase = CombatantRenderSystem.phase(RenderPhase.WORLD_AFTER_TRANSLUCENT)) { + try (RenderPhaseScope lovisual$afterTranslucentPhase = LoVisualRenderSystem.phase(RenderPhase.WORLD_AFTER_TRANSLUCENT)) { try (ProfilerPhase.Scope phase = ProfilerPhase.scope("3d:modules_end_main"); RenderProfiler3D.Section ignored = RenderProfiler3D.section("modules_end_main")) { - ModuleManager.renderWorldEngine(WorldPhase.END_MAIN, combatant$renderer, combatant$depthRenderer, tickDelta); + ModuleManager.renderWorldEngine(WorldPhase.END_MAIN, lovisual$renderer, lovisual$depthRenderer, tickDelta); AddonRenderPipelineManager.render3D(LoVisualRenderStage.WORLD_END_MAIN, - WorldPhase.END_MAIN, combatant$renderer, combatant$depthRenderer, combatant$matrices, tickDelta); + WorldPhase.END_MAIN, lovisual$renderer, lovisual$depthRenderer, lovisual$matrices, tickDelta); } try (ProfilerPhase.Scope phase = ProfilerPhase.scope("3d:flush_end_main"); TracyGpuProfiler.Scope gpuFlush = TracyGpuProfiler.beginZone("3d:flush_end_main"); RenderProfiler3D.Section ignored = RenderProfiler3D.section("flush_end_main")) { - combatant$renderer.render(combatant$matrices); - combatant$depthRenderer.render(combatant$matrices); + lovisual$renderer.render(lovisual$matrices); + lovisual$depthRenderer.render(lovisual$matrices); } } - combatant$matrices.popPose(); + lovisual$matrices.popPose(); mv.popMatrix(); RenderState.rendering3D = false; } @@ -431,16 +431,16 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { @Inject(method = "renderLevel", at = @At("HEAD")) - private void combatant$beginWorldMsaa(DeltaTracker tickCounter, CallbackInfo ci) { - IrisCombatantFrameHooks.beginRenderLevel(tickCounter); - CombatantWorldMatrices.reset(); + private void lovisual$beginWorldMsaa(DeltaTracker tickCounter, CallbackInfo ci) { + IrisLoVisualFrameHooks.beginRenderLevel(tickCounter); + LoVisualWorldMatrices.reset(); int samples = MainConfig.get().getMsaa3dSamples(); - MsaaWorldTarget.begin(minecraft, samples, combatant$needsResolvedMainDepth()); + MsaaWorldTarget.begin(minecraft, samples, lovisual$needsResolvedMainDepth()); } @Inject(method = "renderLevel", at = @At("RETURN")) - private void combatant$endIrisFrameHooks(DeltaTracker tickCounter, CallbackInfo ci) { - IrisCombatantFrameHooks.endRenderLevel(tickCounter); + private void lovisual$endIrisFrameHooks(DeltaTracker tickCounter, CallbackInfo ci) { + IrisLoVisualFrameHooks.endRenderLevel(tickCounter); } @WrapOperation( @@ -450,7 +450,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { target = "Lnet/minecraft/client/renderer/ProjectionMatrixBuffer;getBuffer(Lorg/joml/Matrix4f;)Lcom/mojang/blaze3d/buffers/GpuBufferSlice;" ) ) - private GpuBufferSlice combatant$captureFullWorldMatrices(ProjectionMatrixBuffer instance, + private GpuBufferSlice lovisual$captureFullWorldMatrices(ProjectionMatrixBuffer instance, Matrix4f renderProjectionMatrix, Operation original) { if (renderProjectionMatrix != null @@ -460,7 +460,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { && gameRenderState.levelRenderState.cameraRenderState.viewRotationMatrix != null && gameRenderState.levelRenderState.cameraRenderState.projectionMatrix != null) { CameraRenderState cameraRenderState = gameRenderState.levelRenderState.cameraRenderState; - CombatantWorldMatrices.capture( + LoVisualWorldMatrices.capture( cameraRenderState.viewRotationMatrix, renderProjectionMatrix, cameraRenderState.projectionMatrix, @@ -479,21 +479,21 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { shift = At.Shift.AFTER ) ) - private void combatant$postProcess(DeltaTracker tickCounter, CallbackInfo ci) { + private void lovisual$postProcess(DeltaTracker tickCounter, CallbackInfo ci) { if (IrisRuntime.isShaderpackRendererActive() && IrisCompatibilityGuards.deferIrisFinalizationForSecondHandScene()) { return; } - combatant$renderPreHandPostProcess(tickCounter); + lovisual$renderPreHandPostProcess(tickCounter); } @Unique - private void combatant$renderPreHandPostProcess(DeltaTracker tickCounter) { + private void lovisual$renderPreHandPostProcess(DeltaTracker tickCounter) { ProfilerPhase.begin("3d:post_pre_hand"); try (TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("3d:post_pre_hand")) { if (minecraft != null) { boolean needsResolvedDepth = !IrisRuntime.isShaderpackRendererActive() - && combatant$needsResolvedMainDepth(); + && lovisual$needsResolvedMainDepth(); boolean capturedMsaaDepth = needsResolvedDepth && MsaaWorldTarget.isActive() && WorldSceneDepth.captureResolvedMain(MsaaWorldTarget.getMsaaFramebuffer()); @@ -501,37 +501,37 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { if (needsResolvedDepth && !capturedMsaaDepth) { WorldSceneDepth.captureResolvedMain(minecraft.gameRenderer.mainRenderTarget()); } - CombatantVisuals.renderWorldBase(minecraft, tickCounter.getGameTimeDeltaPartialTick(true)); + LoVisualVisuals.renderWorldBase(minecraft, tickCounter.getGameTimeDeltaPartialTick(true)); } - try (RenderPhaseScope combatant$postPreHandPhase = CombatantRenderSystem.phase(RenderPhase.WORLD_POST_PRE_HAND)) { + try (RenderPhaseScope lovisual$postPreHandPhase = LoVisualRenderSystem.phase(RenderPhase.WORLD_POST_PRE_HAND)) { PostProcessManager.renderAll(PostProcessPass.Phase.PRE_HAND, tickCounter.getGameTimeDeltaPartialTick(true)); - combatant$renderCombatantWorldAfterPreHandPostProcess(tickCounter); + lovisual$renderLoVisualWorldAfterPreHandPostProcess(tickCounter); } } ProfilerPhase.end("3d:post_pre_hand"); } @Unique - private void combatant$renderCombatantWorldAfterPreHandPostProcess(DeltaTracker tickCounter) { + private void lovisual$renderLoVisualWorldAfterPreHandPostProcess(DeltaTracker tickCounter) { if (minecraft == null) { - combatant$renderWorldEngine(tickCounter); - combatant$renderPostProcessWorld(tickCounter); + lovisual$renderWorldEngine(tickCounter); + lovisual$renderPostProcessWorld(tickCounter); return; } MsaaWorldTarget.begin(minecraft, MainConfig.get().getMsaa3dSamples(), false, true); try { - combatant$renderWorldEngine(tickCounter); - combatant$renderPostProcessWorld(tickCounter); + lovisual$renderWorldEngine(tickCounter); + lovisual$renderPostProcessWorld(tickCounter); } finally { MsaaWorldTarget.resolveToMain(minecraft); } } @Override - public void combatant$renderAfterIrisFinalization(DeltaTracker tickCounter) { - combatant$renderPreHandPostProcess(tickCounter); + public void lovisual$renderAfterIrisFinalization(DeltaTracker tickCounter) { + lovisual$renderPreHandPostProcess(tickCounter); } @Inject( @@ -542,13 +542,13 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { shift = At.Shift.AFTER ) ) - private void combatant$postProcessAfterHand(DeltaTracker tickCounter, CallbackInfo ci) { + private void lovisual$postProcessAfterHand(DeltaTracker tickCounter, CallbackInfo ci) { ProfilerPhase.begin("3d:post_after_hand"); try (TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("3d:post_after_hand")) { if (minecraft != null) { MsaaWorldTarget.resolveToMain(minecraft); } - try (RenderPhaseScope combatant$postHandPhase = CombatantRenderSystem.phase(RenderPhase.WORLD_POST_HAND)) { + try (RenderPhaseScope lovisual$postHandPhase = LoVisualRenderSystem.phase(RenderPhase.WORLD_POST_HAND)) { PostProcessManager.renderAll(PostProcessPass.Phase.POST_HAND, tickCounter.getGameTimeDeltaPartialTick(true)); } @@ -557,13 +557,13 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { } @Unique - private void combatant$renderPostProcessWorld(DeltaTracker tickCounter) { + private void lovisual$renderPostProcessWorld(DeltaTracker tickCounter) { try (ProfilerPhase.Scope phaseScope = ProfilerPhase.scope("3d:world_post"); TracyGpuProfiler.Scope gpuScope = TracyGpuProfiler.beginZone("3d:world_post")) { float tickDelta = tickCounter.getGameTimeDeltaPartialTick(true); float fov = mainCamera.getFov(); - Matrix4f capturedPosition = CombatantWorldMatrices.positionMatrix(); - Matrix4f capturedProjection = CombatantWorldMatrices.renderProjectionMatrix(); + Matrix4f capturedPosition = LoVisualWorldMatrices.positionMatrix(); + Matrix4f capturedProjection = LoVisualWorldMatrices.renderProjectionMatrix(); boolean useCapturedMatrices = capturedPosition != null && capturedProjection != null; Matrix4f position = useCapturedMatrices ? capturedPosition @@ -571,90 +571,90 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { RenderState.rendering3D = true; RenderState.tickDelta = tickDelta; - Vec3 capturedCameraPos = CombatantWorldMatrices.cameraPosition(); + Vec3 capturedCameraPos = LoVisualWorldMatrices.cameraPosition(); RenderState.cameraPos = capturedCameraPos != null ? capturedCameraPos : mainCamera.position(); RenderState.cameraRotation.set(mainCamera.rotation()); RenderState.cameraYaw = mainCamera.yRot(); RenderState.cameraPitch = mainCamera.xRot(); - if (combatant$postRenderer == null) { - combatant$postRenderer = new Renderer3D( - CombatantRenderPipelines.WORLD_COLORED_LINES, - CombatantRenderPipelines.WORLD_COLORED + if (lovisual$postRenderer == null) { + lovisual$postRenderer = new Renderer3D( + LoVisualRenderPipelines.WORLD_COLORED_LINES, + LoVisualRenderPipelines.WORLD_COLORED ); } - if (combatant$postDepthRenderer == null) { - combatant$postDepthRenderer = new Renderer3D( - CombatantRenderPipelines.WORLD_COLORED_LINES_DEPTH, - CombatantRenderPipelines.WORLD_COLORED_DEPTH + if (lovisual$postDepthRenderer == null) { + lovisual$postDepthRenderer = new Renderer3D( + LoVisualRenderPipelines.WORLD_COLORED_LINES_DEPTH, + LoVisualRenderPipelines.WORLD_COLORED_DEPTH ); } var mv = com.mojang.blaze3d.systems.RenderSystem.getModelViewStack(); mv.pushMatrix(); - if (IrisCombatantFrameHooks.isRenderingAfterIrisFinalization()) { + if (IrisLoVisualFrameHooks.isRenderingAfterIrisFinalization()) { mv.identity(); } mv.mul(position); - combatant$postMatrices.pushPose(); + lovisual$postMatrices.pushPose(); Matrix4f projection = useCapturedMatrices ? capturedProjection - : combatant$buildWorldProjection(fov, combatant$postMatrices, tickDelta); + : lovisual$buildWorldProjection(fov, lovisual$postMatrices, tickDelta); MeshRenderer.setProjection(projection); - CombatantRenderSystem.beginFrame( + LoVisualRenderSystem.beginFrame( tickDelta, tickCounter.getGameTimeDeltaTicks(), tickCounter.getRealtimeDeltaTicks(), projection, new Matrix4f(mv) ); - try (RenderPhaseScope combatant$postWorldPhase = CombatantRenderSystem.phase(RenderPhase.WORLD_POST_PRE_HAND)) { + try (RenderPhaseScope lovisual$postWorldPhase = LoVisualRenderSystem.phase(RenderPhase.WORLD_POST_PRE_HAND)) { RenderState.worldProjection.set(projection); RenderState.frustum = new Frustum(position, projection); RenderState.frustum.prepare(RenderState.cameraPos.x, RenderState.cameraPos.y, RenderState.cameraPos.z); if (!useCapturedMatrices) { - Matrix4f inverseBob = new Matrix4f(combatant$postMatrices.last().pose()).invert(); + Matrix4f inverseBob = new Matrix4f(lovisual$postMatrices.last().pose()).invert(); mv.mul(inverseBob); } - combatant$postRenderer.begin(); - combatant$postDepthRenderer.begin(); + lovisual$postRenderer.begin(); + lovisual$postDepthRenderer.begin(); try (ProfilerPhase.Scope phase = ProfilerPhase.scope("3d:post_modules"); RenderProfiler3D.Section ignored = RenderProfiler3D.section("modules")) { - ModuleManager.renderWorldEngine(WorldPhase.AFTER_POST_PROCESS, combatant$postRenderer, combatant$postDepthRenderer, tickDelta); + ModuleManager.renderWorldEngine(WorldPhase.AFTER_POST_PROCESS, lovisual$postRenderer, lovisual$postDepthRenderer, tickDelta); AddonRenderPipelineManager.render3D(LoVisualRenderStage.WORLD_POST_PROCESS, - WorldPhase.AFTER_POST_PROCESS, combatant$postRenderer, combatant$postDepthRenderer, combatant$postMatrices, tickDelta); + WorldPhase.AFTER_POST_PROCESS, lovisual$postRenderer, lovisual$postDepthRenderer, lovisual$postMatrices, tickDelta); } try (ProfilerPhase.Scope phase = ProfilerPhase.scope("3d:post_flush"); TracyGpuProfiler.Scope gpuFlush = TracyGpuProfiler.beginZone("3d:post_flush"); RenderProfiler3D.Section ignored = RenderProfiler3D.section("flush")) { - combatant$postRenderer.render(combatant$postMatrices); - combatant$postDepthRenderer.render(combatant$postMatrices); + lovisual$postRenderer.render(lovisual$postMatrices); + lovisual$postDepthRenderer.render(lovisual$postMatrices); } } - combatant$postMatrices.popPose(); + lovisual$postMatrices.popPose(); mv.popMatrix(); RenderState.rendering3D = false; } } @Unique - private Matrix4f combatant$buildWorldProjection(float fov, PoseStack viewEffectMatrices, float tickDelta) { + private Matrix4f lovisual$buildWorldProjection(float fov, PoseStack viewEffectMatrices, float tickDelta) { CameraRenderState cameraRenderState = new CameraRenderState(); mainCamera.extractRenderState(cameraRenderState, fov); Matrix4f projection = new Matrix4f(cameraRenderState.projectionMatrix); - combatant$applyViewEffectMatrices(viewEffectMatrices, tickDelta); + lovisual$applyViewEffectMatrices(viewEffectMatrices, tickDelta); projection.mul(viewEffectMatrices.last().pose()); - combatant$applyNauseaProjection(projection, tickDelta); + lovisual$applyNauseaProjection(projection, tickDelta); return projection; } @Unique - private void combatant$applyViewEffectMatrices(PoseStack matrices, float cameraTickProgress) { + private void lovisual$applyViewEffectMatrices(PoseStack matrices, float cameraTickProgress) { NoRender noRender = Modules.get(NoRender.class); CameraRenderState cameraRenderState = new CameraRenderState(); mainCamera.extractRenderState(cameraRenderState, mainCamera.getFov()); @@ -671,7 +671,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { } @Unique - private void combatant$applyNauseaProjection(Matrix4f projection, float tickDelta) { + private void lovisual$applyNauseaProjection(Matrix4f projection, float tickDelta) { LocalPlayer player = minecraft.player; if (player == null) return; @@ -682,8 +682,8 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { if (player instanceof LocalPlayerAccessor accessor) { nauseaIntensity = Mth.lerp( tickDelta, - accessor.combatant$getLastNauseaIntensity(), - accessor.combatant$getNauseaIntensity() + accessor.lovisual$getLastNauseaIntensity(), + accessor.lovisual$getNauseaIntensity() ); } @@ -715,7 +715,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { target = "Lnet/minecraft/client/renderer/feature/FeatureRenderDispatcher;renderAllFeatures(Lnet/minecraft/client/renderer/SubmitNodeStorage;)V" ) ) - private void combatant$renderChamsHandPreparedFrame(FeatureRenderDispatcher dispatcher, + private void lovisual$renderChamsHandPreparedFrame(FeatureRenderDispatcher dispatcher, SubmitNodeStorage storage, Operation original, CameraRenderState cameraRenderState, @@ -729,7 +729,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { } @Inject(method = "render(Lnet/minecraft/client/DeltaTracker;Z)V", at = @At("TAIL")) - private void combatant$flushQueuedButtons(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { + private void lovisual$flushQueuedButtons(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { Minecraft mc = Minecraft.getInstance(); if (mc == null || ClientScreen.current() == null) return; if (!BetterButtons.hasPending()) { @@ -748,7 +748,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { shift = At.Shift.BEFORE ) ) - private void combatant$captureWorldForHudGlass(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { + private void lovisual$captureWorldForHudGlass(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { MenuBackgroundRenderer.drainDeferred(minecraft); Renderer2D.captureWorldGlassSource(); if (AddonRenderPipelineManager.hasActiveCallbacks(LoVisualRenderStage.SCREEN_BEFORE_VANILLA_GUI)) { @@ -759,12 +759,12 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { Renderer2D.COLOR.render(); } Renderer2D.drainDeferred2D(Renderer2D.Deferred2DLayer.BEFORE_VANILLA_GUI); - combatant$drainHudLayersBelowScreenGui(); + lovisual$drainHudLayersBelowScreenGui(); } /** * Gui.extractRenderState() extracts vanilla HUD first and the current Screen after it. - * Normal gameplay keeps Combatant HUD spliced into that HUD order through HudDeferredGuiElement + * Normal gameplay keeps LoVisual HUD spliced into that HUD order through HudDeferredGuiElement * markers. When a real Screen is open, however, the screen must remain the top GUI owner: * HUD/world overlaysare drained before GuiRenderer.render(), * preserving their internal order while keeping container/inventory GUI above them. @@ -772,7 +772,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { * intentionally not drained here. */ @Unique - private static void combatant$drainHudLayersBelowScreenGui() { + private static void lovisual$drainHudLayersBelowScreenGui() { if (ClientScreen.current() == null) { return; } @@ -795,7 +795,7 @@ public abstract class GameRendererMixin implements IrisFinalizedSceneRenderer { shift = At.Shift.AFTER ) ) - private void combatant$debug2dImmediateAfterGui(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { + private void lovisual$debug2dImmediateAfterGui(DeltaTracker tickCounter, boolean tick, CallbackInfo ci) { Renderer2D.drainDeferred2D(Renderer2D.Deferred2DLayer.AFTER_VANILLA_GUI); if (AddonRenderPipelineManager.hasActiveCallbacks(LoVisualRenderStage.SCREEN_AFTER_VANILLA_GUI)) { float tickDelta = tickCounter.getGameTimeDeltaPartialTick(true); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GameRendererViewEffectsMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GameRendererViewEffectsMixin.java index 86bc63b..e08e8af 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GameRendererViewEffectsMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GameRendererViewEffectsMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlDeviceBackendMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlDeviceBackendMixin.java index a9659aa..2f861c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlDeviceBackendMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlDeviceBackendMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,9 +17,9 @@ import dev.loki.lovisual.mixininterface.IGlBackendInfo; public abstract class GlDeviceBackendMixin implements IGlBackendInfo { @Override @Invoker("directStateAccess") - public abstract DirectStateAccess combatant$directStateAccess(); + public abstract DirectStateAccess lovisual$directStateAccess(); @Override @Invoker("frameBufferCache") - public abstract FrameBufferCache combatant$frameBufferCache(); + public abstract FrameBufferCache lovisual$frameBufferCache(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlStateManagerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlStateManagerMixin.java index 93a94a8..15eb1a1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlStateManagerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlStateManagerMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,17 +17,17 @@ import dev.loki.lovisual.render.engine.profiler.GlSyncTracker; @Mixin(GlStateManager.class) public class GlStateManagerMixin { @Inject(method = "_glFenceSync", at = @At("RETURN")) - private static void combatant$onFenceSync(int condition, int flags, CallbackInfoReturnable cir) { + private static void lovisual$onFenceSync(int condition, int flags, CallbackInfoReturnable cir) { GlSyncTracker.onFence(cir.getReturnValue()); } @Inject(method = "_glClientWaitSync", at = @At("HEAD")) - private static void combatant$onClientWaitSync(long sync, int flags, long timeout, CallbackInfoReturnable cir) { + private static void lovisual$onClientWaitSync(long sync, int flags, long timeout, CallbackInfoReturnable cir) { GlSyncTracker.onWaitStart(sync); } @Inject(method = "_glClientWaitSync", at = @At("RETURN")) - private static void combatant$onClientWaitSyncReturn(long sync, int flags, long timeout, CallbackInfoReturnable cir) { + private static void lovisual$onClientWaitSyncReturn(long sync, int flags, long timeout, CallbackInfoReturnable cir) { GlSyncTracker.onWaitEnd(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlTextureMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlTextureMixin.java index 9a8d414..7806fa8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlTextureMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GlTextureMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.loki.lovisual.mixininterface.IMsaaTexture; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; @Mixin(GlTexture.class) public abstract class GlTextureMixin implements IMsaaTexture { @@ -25,31 +25,31 @@ public abstract class GlTextureMixin implements IMsaaTexture { protected int id; @Unique - private int combatant$samples = 1; + private int lovisual$samples = 1; @Override - public void combatant$setSamples(int samples) { - combatant$samples = samples; + public void lovisual$setSamples(int samples) { + lovisual$samples = samples; } @Override - public int combatant$getSamples() { - return combatant$samples; + public int lovisual$getSamples() { + return lovisual$samples; } @Override - public boolean combatant$isMsaa() { - return combatant$samples > 1; + public boolean lovisual$isMsaa() { + return lovisual$samples > 1; } @Override - public int combatant$getGlId() { + public int lovisual$getGlId() { return id; } @Inject(method = "destroyImmediately", at = @At("HEAD")) - private void combatant$onFree(CallbackInfo ci) { - CombatantRenderSystem.rhi().msaa().unregisterTexture(id); + private void lovisual$onFree(CallbackInfo ci) { + LoVisualRenderSystem.rhi().msaa().unregisterTexture(id); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GpuDeviceMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GpuDeviceMixin.java index 8bca540..9f5bb95 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GpuDeviceMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GpuDeviceMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,23 +13,23 @@ import com.mojang.blaze3d.textures.GpuTexture; import org.spongepowered.asm.mixin.Mixin; import dev.loki.lovisual.mixininterface.IGpuDevice; import dev.loki.lovisual.mixininterface.IMsaaDevice; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.rhi.scissor.GlobalScissorState; @Mixin(GpuDevice.class) public abstract class GpuDeviceMixin implements IGpuDevice, IMsaaDevice { @Override - public void combatant$pushScissor(int x, int y, int width, int height) { + public void lovisual$pushScissor(int x, int y, int width, int height) { GlobalScissorState.push(x, y, width, height); } @Override - public void combatant$popScissor() { + public void lovisual$popScissor() { GlobalScissorState.pop(); } @Override - public GpuTexture combatant$createMsaaTexture(String label, int usage, GpuFormat format, int width, int height, int samples) { - return CombatantRenderSystem.rhi().msaa().createTexture(label, usage, format, width, height, samples); + public GpuTexture lovisual$createMsaaTexture(String label, int usage, GpuFormat format, int width, int height, int samples) { + return LoVisualRenderSystem.rhi().msaa().createTexture(label, usage, format, width, height, samples); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GpuSurfaceMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GpuSurfaceMixin.java index 41925e8..3101762 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GpuSurfaceMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GpuSurfaceMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.profiler.TracyGpuProfiler; import dev.loki.lovisual.render.engine.profiler.TracyProfiler; import dev.loki.lovisual.render.engine.renderer.Renderer2D; @@ -24,23 +24,23 @@ import dev.loki.lovisual.util.FastFps; public abstract class GpuSurfaceMixin { /** * This is the last safe point before Minecraft copies the main render target into the - * window surface. Combatant queued text/UI/RHI submission must be flushed here, not in + * window surface. LoVisual queued text/UI/RHI submission must be flushed here, not in * present(), otherwise those draws happen after the surface blit and are not visible in * the frame that produced them. */ @Inject(method = "blitFromTexture", at = @At("HEAD")) - private void combatant$beforeSurfaceBlit(CommandEncoder encoder, GpuTextureView textureView, CallbackInfo info) { - CombatantRenderSystem.endRenderSubmission(); + private void lovisual$beforeSurfaceBlit(CommandEncoder encoder, GpuTextureView textureView, CallbackInfo info) { + LoVisualRenderSystem.endRenderSubmission(); } @Inject(method = "present", at = @At("HEAD")) - private void combatant$onPresentHead(CallbackInfo info) { + private void lovisual$onPresentHead(CallbackInfo info) { FastFps.onFrame(); } @Inject(method = "present", at = @At("TAIL")) - private void combatant$onPresentTail(CallbackInfo info) { - CombatantRenderSystem.onFramePresented(); + private void lovisual$onPresentTail(CallbackInfo info) { + LoVisualRenderSystem.onFramePresented(); if (TracyGpuProfiler.isEnabled()) { TracyGpuProfiler.onFrameEnd(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiGraphicsMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiGraphicsMixin.java index 223cd1a..d91a155 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiGraphicsMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiGraphicsMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -58,7 +58,7 @@ public abstract class GuiGraphicsMixin implements IGuiGraphics { public abstract int guiHeight(); @Override - public void combatant$runUnscaled(Runnable task) { + public void lovisual$runUnscaled(Runnable task) { Minecraft mc = Minecraft.getInstance(); double scale = mc.getWindow().getGuiScale(); double uiScale = ViewportContext.getUiScale(); @@ -72,7 +72,7 @@ public abstract class GuiGraphicsMixin implements IGuiGraphics { } @Override - public void combatant$withTransform(float tx, float ty, float angleRad, Runnable task) { + public void lovisual$withTransform(float tx, float ty, float angleRad, Runnable task) { pose.pushMatrix(); try { pose.translate(tx, ty); @@ -84,7 +84,7 @@ public abstract class GuiGraphicsMixin implements IGuiGraphics { } @Override - public void combatant$addDeferredHudMarker(Renderer2D.Deferred2DLayer layer) { + public void lovisual$addDeferredHudMarker(Renderer2D.Deferred2DLayer layer) { if (layer == null || guiRenderState == null) return; int width = Math.max(1, guiWidth()); int height = Math.max(1, guiHeight()); @@ -92,32 +92,32 @@ public abstract class GuiGraphicsMixin implements IGuiGraphics { } @Override - public void combatant$drawItemBar(ItemStack stack, int x, int y) { - combatant$invokeDrawItemBar(stack, x, y); + public void lovisual$drawItemBar(ItemStack stack, int x, int y) { + lovisual$invokeDrawItemBar(stack, x, y); } @Override - public void combatant$drawCooldownProgress(ItemStack stack, int x, int y) { - combatant$invokeDrawCooldownProgress(stack, x, y); + public void lovisual$drawCooldownProgress(ItemStack stack, int x, int y) { + lovisual$invokeDrawCooldownProgress(stack, x, y); } @Invoker("itemBar") - public abstract void combatant$invokeDrawItemBar(ItemStack stack, int x, int y); + public abstract void lovisual$invokeDrawItemBar(ItemStack stack, int x, int y); @Invoker("itemCooldown") - public abstract void combatant$invokeDrawCooldownProgress(ItemStack stack, int x, int y); + public abstract void lovisual$invokeDrawCooldownProgress(ItemStack stack, int x, int y); @Accessor("deferredTooltip") - public abstract Runnable combatant$getTooltipDrawer(); + public abstract Runnable lovisual$getTooltipDrawer(); @Accessor("deferredTooltip") - public abstract void combatant$setTooltipDrawer(Runnable drawer); + public abstract void lovisual$setTooltipDrawer(Runnable drawer); @Inject(method = "extractDeferredElements", at = @At("HEAD")) - private void combatant$suppressVanillaTooltip(int mouseX, int mouseY, float tickDelta, CallbackInfo ci) { + private void lovisual$suppressVanillaTooltip(int mouseX, int mouseY, float tickDelta, CallbackInfo ci) { if (!BetterTooltips.hasTooltip()) return; - if (combatant$getTooltipDrawer() == null) return; - combatant$setTooltipDrawer(null); + if (lovisual$getTooltipDrawer() == null) return; + lovisual$setTooltipDrawer(null); } @Inject( @@ -125,7 +125,7 @@ public abstract class GuiGraphicsMixin implements IGuiGraphics { at = @At("HEAD"), cancellable = true ) - private void combatant$drawCustomTooltip(net.minecraft.client.gui.Font tr, + private void lovisual$drawCustomTooltip(net.minecraft.client.gui.Font tr, java.util.List lines, ClientTooltipPositioner positioner, int x, int y, boolean focused, @@ -143,7 +143,7 @@ public abstract class GuiGraphicsMixin implements IGuiGraphics { at = @At("HEAD"), cancellable = true ) - private void combatant$drawCustomItemTooltip(net.minecraft.client.gui.Font tr, + private void lovisual$drawCustomItemTooltip(net.minecraft.client.gui.Font tr, ItemStack stack, int x, int y, CallbackInfo ci) { @@ -173,7 +173,7 @@ public abstract class GuiGraphicsMixin implements IGuiGraphics { at = @At("HEAD"), cancellable = true ) - private void combatant$drawCustomTooltipWithData(net.minecraft.client.gui.Font tr, + private void lovisual$drawCustomTooltipWithData(net.minecraft.client.gui.Font tr, java.util.List lines, java.util.Optional data, int x, int y, @@ -207,7 +207,7 @@ public abstract class GuiGraphicsMixin implements IGuiGraphics { at = @At("HEAD"), cancellable = true ) - private void combatant$drawCustomTooltipWithDataNoStyle(net.minecraft.client.gui.Font tr, + private void lovisual$drawCustomTooltipWithDataNoStyle(net.minecraft.client.gui.Font tr, java.util.List lines, java.util.Optional data, int x, int y, @@ -237,7 +237,7 @@ public abstract class GuiGraphicsMixin implements IGuiGraphics { @Inject(method = "itemCooldown", at = @At("HEAD"), cancellable = true) - private void combatant$renderCustomPvpCooldown(ItemStack stack, int x, int y, CallbackInfo ci) { + private void lovisual$renderCustomPvpCooldown(ItemStack stack, int x, int y, CallbackInfo ci) { if (stack.isEmpty()) return; PvpCooldowns cooldowns = Modules.get(PvpCooldowns.class); if (cooldowns == null || !cooldowns.isSystemEnabled()) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiMixin.java index 52fde6e..2852f8e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -42,13 +42,13 @@ import dev.loki.lovisual.features.module.modules.misc.MessageFilter; import dev.loki.lovisual.features.module.modules.visuals.Crosshair; import dev.loki.lovisual.features.module.modules.visuals.NoRender; import dev.loki.lovisual.mixininterface.IGuiGraphics; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.RenderPhaseScope; import dev.loki.lovisual.render.engine.core.ViewportContext; // import dev.loki.lovisual.render.engine.debug.RenderThread2DDebugRenderer; // disabled: debug probes are manual-only import dev.loki.lovisual.render.engine.renderer.Renderer2D; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import dev.loki.lovisual.util.item.IllegalItemUtil; import dev.loki.lovisual.util.item.RarityColorUtil; import dev.loki.lovisual.util.item.TopEnchantUtil; @@ -68,12 +68,12 @@ public abstract class GuiMixin { private Minecraft minecraft; @Inject(method = "extractRenderState(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V", at = @At("TAIL")) - private void combatant$debug2dGuiStateProbe(GuiGraphicsExtractor ctx, DeltaTracker tickCounter, CallbackInfo ci) { + private void lovisual$debug2dGuiStateProbe(GuiGraphicsExtractor ctx, DeltaTracker tickCounter, CallbackInfo ci) { // RenderThread2DDebugRenderer.extractGuiStateProbe(ctx); } @Unique - private static void combatant$renderCustomBarOnly(GuiGraphicsExtractor ctx, + private static void lovisual$renderCustomBarOnly(GuiGraphicsExtractor ctx, DeltaTracker tickCounter, Minecraft mc, CustomBar bar) { @@ -81,9 +81,9 @@ public abstract class GuiMixin { boolean useLocator = !useJump && CustomBar.shouldUseLocator(mc, bar); boolean drawXp = !useJump && !useLocator; - CombatantRenderSystem.ensureFrameContext(); - try (RenderPhaseScope ignored = CombatantRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_bar")) { - Renderer2D.withDeferredLayer(COMBATANT$VANILLA_HUD_REPLACEMENT_LAYER, () -> { + LoVisualRenderSystem.ensureFrameContext(); + try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_bar")) { + Renderer2D.withDeferredLayer(LOVISUAL$VANILLA_HUD_REPLACEMENT_LAYER, () -> { ViewportContext.beginUnscaled(ctx); Renderer2D.COLOR.begin(); if (drawXp) { @@ -102,19 +102,19 @@ public abstract class GuiMixin { CustomBar.renderXpBarText(ctx, mc); } }); - combatant$appendVanillaHudReplacementMarker(ctx); + lovisual$appendVanillaHudReplacementMarker(ctx); } } @Unique - private static final Renderer2D.Deferred2DLayer COMBATANT$VANILLA_HUD_REPLACEMENT_LAYER = + private static final Renderer2D.Deferred2DLayer LOVISUAL$VANILLA_HUD_REPLACEMENT_LAYER = Renderer2D.Deferred2DLayer.HUD_AFTER_MISC_OVERLAYS; @Unique - private static void combatant$appendVanillaHudReplacementMarker(GuiGraphicsExtractor ctx) { + private static void lovisual$appendVanillaHudReplacementMarker(GuiGraphicsExtractor ctx) { if (!(ctx instanceof IGuiGraphics graphics)) return; ctx.nextStratum(); - graphics.combatant$addDeferredHudMarker(COMBATANT$VANILLA_HUD_REPLACEMENT_LAYER); + graphics.lovisual$addDeferredHudMarker(LOVISUAL$VANILLA_HUD_REPLACEMENT_LAYER); ctx.nextStratum(); } @@ -135,8 +135,8 @@ public abstract class GuiMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$hideScoreboardSidebar(GuiGraphicsExtractor context, Objective objective, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$hideScoreboardSidebar(GuiGraphicsExtractor context, Objective objective, CallbackInfo ci) { + NoRender noRender = Modules.get(NoRender.class); if ((noRender != null && noRender.hideScoreboard()) || Scoreboard.shouldReplaceVanilla()) { ci.cancel(); @@ -148,7 +148,7 @@ public abstract class GuiMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$filterOverlayMessage(net.minecraft.network.chat.Component message, boolean tinted, CallbackInfo ci) { + private void lovisual$filterOverlayMessage(net.minecraft.network.chat.Component message, boolean tinted, CallbackInfo ci) { if (DebugLog.serverOnly()) { if (message == null) { // DebugLog.server("HUD overlay message: tinted=%s raw=null", tinted); @@ -161,7 +161,7 @@ public abstract class GuiMixin { if (Events.BUS.hasListeners(PvpOverlayEvent.class)) { Events.BUS.post(new PvpOverlayEvent(message, tinted)); } - if (RuntimeGate.isPanic()) return; + MessageFilter messageFilter = Modules.get(MessageFilter.class); if (messageFilter != null && messageFilter.shouldHideHud(message)) { ci.cancel(); @@ -173,8 +173,8 @@ public abstract class GuiMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$hideVanillaPotions(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$hideVanillaPotions(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { + Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; if (!DraggableHudElementRegistry.isEnabled(Potions.class)) return; @@ -188,8 +188,8 @@ public abstract class GuiMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$replaceCrosshair(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$replaceCrosshair(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { + Crosshair crosshair = Modules.get(Crosshair.class); if (crosshair != null && crosshair.shouldHideVanilla()) { ci.cancel(); @@ -201,8 +201,8 @@ public abstract class GuiMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$killVignette(GuiGraphicsExtractor context, Entity entity, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$killVignette(GuiGraphicsExtractor context, Entity entity, CallbackInfo ci) { + // Completely remove vanilla vignette post-processing ci.cancel(); } @@ -212,8 +212,8 @@ public abstract class GuiMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$customHotbar(GuiGraphicsExtractor ctx, DeltaTracker tickCounter, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$customHotbar(GuiGraphicsExtractor ctx, DeltaTracker tickCounter, CallbackInfo ci) { + Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; @@ -230,9 +230,9 @@ public abstract class GuiMixin { boolean useLocator = barEnabled && !useJump && CustomBar.shouldUseLocator(mc, bar); boolean drawXp = barEnabled && !useJump && !useLocator; - CombatantRenderSystem.ensureFrameContext(); - try (RenderPhaseScope ignored = CombatantRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_hotbar")) { - Renderer2D.withDeferredLayer(COMBATANT$VANILLA_HUD_REPLACEMENT_LAYER, () -> { + LoVisualRenderSystem.ensureFrameContext(); + try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_hotbar")) { + Renderer2D.withDeferredLayer(LOVISUAL$VANILLA_HUD_REPLACEMENT_LAYER, () -> { ViewportContext.beginUnscaled(ctx); Renderer2D.COLOR.begin(); if (hotbarEnabled) { @@ -254,7 +254,7 @@ public abstract class GuiMixin { CustomHotbar.renderItems(ctx, tickCounter, mc); } }); - combatant$appendVanillaHudReplacementMarker(ctx); + lovisual$appendVanillaHudReplacementMarker(ctx); if (drawXp) { CustomBar.renderXpBarText(ctx, mc); @@ -269,8 +269,8 @@ public abstract class GuiMixin { method = "extractItemHotbar(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V", at = @At("TAIL") ) - private void combatant$customBarAfterVanillaHotbar(GuiGraphicsExtractor ctx, DeltaTracker tickCounter, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$customBarAfterVanillaHotbar(GuiGraphicsExtractor ctx, DeltaTracker tickCounter, CallbackInfo ci) { + Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; @@ -280,7 +280,7 @@ public abstract class GuiMixin { CustomBar bar = CustomBar.get(); if (bar == null || !bar.isHudBarEnabled() || !bar.isHotbarXpBarEnabled()) return; - combatant$renderCustomBarOnly(ctx, tickCounter, mc, bar); + lovisual$renderCustomBarOnly(ctx, tickCounter, mc, bar); } @Inject( @@ -288,8 +288,8 @@ public abstract class GuiMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$disableVanillaPortalOverlay(GuiGraphicsExtractor context, float nauseaStrength, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$disableVanillaPortalOverlay(GuiGraphicsExtractor context, float nauseaStrength, CallbackInfo ci) { + ci.cancel(); } @@ -298,8 +298,8 @@ public abstract class GuiMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$disableVanillaSleepOverlay(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$disableVanillaSleepOverlay(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { + ci.cancel(); } @@ -308,23 +308,23 @@ public abstract class GuiMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$renderHealthBar(GuiGraphicsExtractor context, + private void lovisual$renderHealthBar(GuiGraphicsExtractor context, Player player, int x, int y, int lines, int regeneratingHeartIndex, float maxHealth, int lastHealth, int health, int absorption, boolean blinking, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; if (!(player instanceof LocalPlayer clientPlayer)) return; Minecraft mc = Minecraft.getInstance(); if (mc == null) return; if (!CustomHealthBar.shouldRenderHealthBar(mc, clientPlayer, maxHealth)) return; - CombatantRenderSystem.ensureFrameContext(); - try (RenderPhaseScope ignored = CombatantRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_health")) { - Renderer2D.withDeferredLayer(COMBATANT$VANILLA_HUD_REPLACEMENT_LAYER, () -> { + LoVisualRenderSystem.ensureFrameContext(); + try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_health")) { + Renderer2D.withDeferredLayer(LOVISUAL$VANILLA_HUD_REPLACEMENT_LAYER, () -> { ViewportContext.beginUnscaled(context); Renderer2D.COLOR.begin(); CustomHealthBar.HealthTextInfo textInfo = @@ -340,14 +340,14 @@ public abstract class GuiMixin { Renderer2D.COLOR.render(); ViewportContext.end(context); }); - combatant$appendVanillaHudReplacementMarker(context); + lovisual$appendVanillaHudReplacementMarker(context); ci.cancel(); } } @Inject(method = "extractSelectedItemName", at = @At("HEAD"), cancellable = true) - private void combatant$colorizeHeldItemTooltip(GuiGraphicsExtractor context, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + private void lovisual$colorizeHeldItemTooltip(GuiGraphicsExtractor context, CallbackInfo ci) { + if (!Lifecycle.canRunHud()) return; SwapTooltip swapTooltip = SwapTooltip.get(); if (swapTooltip == null || !swapTooltip.isEnabled()) { return; @@ -392,8 +392,8 @@ public abstract class GuiMixin { target = "Lnet/minecraft/world/entity/player/Player;getAbsorptionAmount()F" ) ) - private float combatant$ignoreAbsorptionForLayout(Player player) { - if (!RuntimeGate.canRunHud()) { + private float lovisual$ignoreAbsorptionForLayout(Player player) { + if (!Lifecycle.canRunHud()) { return player.getAbsorptionAmount(); } Minecraft mc = Minecraft.getInstance(); @@ -413,8 +413,8 @@ public abstract class GuiMixin { target = "Lnet/minecraft/world/entity/player/Player;getAttributeValue(Lnet/minecraft/core/Holder;)D" ) ) - private double combatant$clampMaxHealthForLayout(Player player, Holder attribute) { - if (!RuntimeGate.canRunHud()) { + private double lovisual$clampMaxHealthForLayout(Player player, Holder attribute) { + if (!Lifecycle.canRunHud()) { return player.getAttributes().getValue(attribute); } if (attribute == Attributes.MAX_HEALTH) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiRendererMixin.java index bd334db..32ec327 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -51,10 +51,10 @@ public abstract class GuiRendererMixin { private ProjectionMatrixBuffer guiProjectionMatrixBuffer; @Unique - private final ObjectArrayList combatant$hudMarkers = new ObjectArrayList<>(16); + private final ObjectArrayList lovisual$hudMarkers = new ObjectArrayList<>(16); @Unique - private GuiRenderState.TraverseRange combatant$currentTraverseRange; + private GuiRenderState.TraverseRange lovisual$currentTraverseRange; @Shadow private void executeDrawRange(Supplier supplier, @@ -66,56 +66,56 @@ public abstract class GuiRendererMixin { } @Inject(method = "render", at = @At("HEAD")) - private void combatant$clearHudMarkersAtFrameStart(CallbackInfo ci) { - combatant$hudMarkers.clear(); + private void lovisual$clearHudMarkersAtFrameStart(CallbackInfo ci) { + lovisual$hudMarkers.clear(); } @Inject(method = "render", at = @At("RETURN")) - private void combatant$clearHudMarkersAtFrameEnd(CallbackInfo ci) { - combatant$hudMarkers.clear(); + private void lovisual$clearHudMarkersAtFrameEnd(CallbackInfo ci) { + lovisual$hudMarkers.clear(); } @Inject(method = "addElementsToMeshes", at = @At("HEAD")) - private void combatant$enterTraverseRange(GuiRenderState.TraverseRange range, CallbackInfo ci) { - combatant$currentTraverseRange = range; + private void lovisual$enterTraverseRange(GuiRenderState.TraverseRange range, CallbackInfo ci) { + lovisual$currentTraverseRange = range; } @Inject(method = "addElementsToMeshes", at = @At("RETURN")) - private void combatant$exitTraverseRange(GuiRenderState.TraverseRange range, CallbackInfo ci) { - combatant$currentTraverseRange = null; + private void lovisual$exitTraverseRange(GuiRenderState.TraverseRange range, CallbackInfo ci) { + lovisual$currentTraverseRange = null; } @Inject(method = "addElementToMesh", at = @At("HEAD"), cancellable = true) - private void combatant$captureHudDeferredMarker(GuiElementRenderState element, CallbackInfo ci) { + private void lovisual$captureHudDeferredMarker(GuiElementRenderState element, CallbackInfo ci) { if (!(element instanceof HudDeferredGuiElement marker)) return; int drawIndex = draws != null ? draws.size() : 0; - GuiRenderState.TraverseRange range = combatant$currentTraverseRange != null - ? combatant$currentTraverseRange + GuiRenderState.TraverseRange range = lovisual$currentTraverseRange != null + ? lovisual$currentTraverseRange : GuiRenderState.TraverseRange.BEFORE_BLUR; - combatant$hudMarkers.add(new QueuedHudMarker(drawIndex, range, marker.layer())); + lovisual$hudMarkers.add(new QueuedHudMarker(drawIndex, range, marker.layer())); ci.cancel(); } @Inject(method = "draw", at = @At("HEAD"), cancellable = true) - private void combatant$drawWithDeferredHudMarkers(CallbackInfo ci) { - if (combatant$hudMarkers.isEmpty()) return; + private void lovisual$drawWithDeferredHudMarkers(CallbackInfo ci) { + if (lovisual$hudMarkers.isEmpty()) return; if (draws == null || draws.isEmpty()) { - combatant$drainHudMarkersUpTo(Integer.MAX_VALUE); + lovisual$drainHudMarkersUpTo(Integer.MAX_VALUE); ci.cancel(); return; } Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.gameRenderer == null) { - combatant$drainHudMarkersUpTo(Integer.MAX_VALUE); + lovisual$drainHudMarkersUpTo(Integer.MAX_VALUE); ci.cancel(); return; } WindowRenderState window = mc.gameRenderer.gameRenderState().windowRenderState; if (window == null || window.guiScale == 0) { - combatant$drainHudMarkersUpTo(Integer.MAX_VALUE); + lovisual$drainHudMarkersUpTo(Integer.MAX_VALUE); ci.cancel(); return; } @@ -131,7 +131,7 @@ public abstract class GuiRendererMixin { RenderTarget target = mc.gameRenderer.mainRenderTarget(); if (target == null) { - combatant$drainHudMarkersUpTo(Integer.MAX_VALUE); + lovisual$drainHudMarkersUpTo(Integer.MAX_VALUE); ci.cancel(); return; } @@ -141,7 +141,7 @@ public abstract class GuiRendererMixin { int beforeBlurEnd = Math.min(firstDrawIndexAfterBlur, draws.size()); if (beforeBlurEnd > 0) { - combatant$executeDrawRangeWithHudMarkers( + lovisual$executeDrawRangeWithHudMarkers( () -> "gui before blur", target, transform, @@ -150,19 +150,19 @@ public abstract class GuiRendererMixin { GuiRenderState.TraverseRange.BEFORE_BLUR ); } else { - combatant$drainHudMarkersInRange(GuiRenderState.TraverseRange.BEFORE_BLUR, Integer.MAX_VALUE); + lovisual$drainHudMarkersInRange(GuiRenderState.TraverseRange.BEFORE_BLUR, Integer.MAX_VALUE); } - boolean hasAfterBlurMarkers = combatant$hasPendingHudMarkersInRange(GuiRenderState.TraverseRange.AFTER_BLUR); + boolean hasAfterBlurMarkers = lovisual$hasPendingHudMarkersInRange(GuiRenderState.TraverseRange.AFTER_BLUR); if (draws.size() <= firstDrawIndexAfterBlur && !hasAfterBlurMarkers) { - combatant$drainHudMarkersUpTo(Integer.MAX_VALUE); + lovisual$drainHudMarkersUpTo(Integer.MAX_VALUE); ci.cancel(); return; } RenderSystem.getDevice().createCommandEncoder().clearDepthTexture(target.getDepthTexture(), 0.0D); mc.gameRenderer.processBlurEffect(); - combatant$executeDrawRangeWithHudMarkers( + lovisual$executeDrawRangeWithHudMarkers( () -> "gui after blur", target, transform, @@ -170,25 +170,25 @@ public abstract class GuiRendererMixin { draws.size(), GuiRenderState.TraverseRange.AFTER_BLUR ); - combatant$drainHudMarkersUpTo(Integer.MAX_VALUE); + lovisual$drainHudMarkersUpTo(Integer.MAX_VALUE); ci.cancel(); } @Unique - private void combatant$executeDrawRangeWithHudMarkers(Supplier label, + private void lovisual$executeDrawRangeWithHudMarkers(Supplier label, RenderTarget target, GpuBufferSlice transform, int start, int end, GuiRenderState.TraverseRange range) { int cursor = start; - for (int i = 0, size = combatant$hudMarkers.size(); i < size; i++) { - QueuedHudMarker marker = combatant$hudMarkers.get(i); + for (int i = 0, size = lovisual$hudMarkers.size(); i < size; i++) { + QueuedHudMarker marker = lovisual$hudMarkers.get(i); if (marker == null || marker.drained || marker.range != range) continue; int markerIndex = marker.drawIndex; if (markerIndex < start) { - combatant$drainHudMarker(marker); + lovisual$drainHudMarker(marker); continue; } if (markerIndex > end) continue; @@ -196,7 +196,7 @@ public abstract class GuiRendererMixin { if (cursor < markerIndex) { executeDrawRange(label, target, transform, cursor, markerIndex); } - combatant$drainHudMarker(marker); + lovisual$drainHudMarker(marker); cursor = Math.max(cursor, markerIndex); } @@ -206,9 +206,9 @@ public abstract class GuiRendererMixin { } @Unique - private boolean combatant$hasPendingHudMarkersInRange(GuiRenderState.TraverseRange range) { - for (int i = 0, size = combatant$hudMarkers.size(); i < size; i++) { - QueuedHudMarker marker = combatant$hudMarkers.get(i); + private boolean lovisual$hasPendingHudMarkersInRange(GuiRenderState.TraverseRange range) { + for (int i = 0, size = lovisual$hudMarkers.size(); i < size; i++) { + QueuedHudMarker marker = lovisual$hudMarkers.get(i); if (marker != null && !marker.drained && marker.range == range) { return true; } @@ -217,29 +217,29 @@ public abstract class GuiRendererMixin { } @Unique - private void combatant$drainHudMarkersInRange(GuiRenderState.TraverseRange range, int drawIndexInclusive) { - for (int i = 0, size = combatant$hudMarkers.size(); i < size; i++) { - QueuedHudMarker marker = combatant$hudMarkers.get(i); + private void lovisual$drainHudMarkersInRange(GuiRenderState.TraverseRange range, int drawIndexInclusive) { + for (int i = 0, size = lovisual$hudMarkers.size(); i < size; i++) { + QueuedHudMarker marker = lovisual$hudMarkers.get(i); if (marker == null || marker.drained || marker.range != range) continue; if (marker.drawIndex <= drawIndexInclusive) { - combatant$drainHudMarker(marker); + lovisual$drainHudMarker(marker); } } } @Unique - private void combatant$drainHudMarkersUpTo(int drawIndexInclusive) { - for (int i = 0, size = combatant$hudMarkers.size(); i < size; i++) { - QueuedHudMarker marker = combatant$hudMarkers.get(i); + private void lovisual$drainHudMarkersUpTo(int drawIndexInclusive) { + for (int i = 0, size = lovisual$hudMarkers.size(); i < size; i++) { + QueuedHudMarker marker = lovisual$hudMarkers.get(i); if (marker == null || marker.drained) continue; if (marker.drawIndex <= drawIndexInclusive) { - combatant$drainHudMarker(marker); + lovisual$drainHudMarker(marker); } } } @Unique - private void combatant$drainHudMarker(QueuedHudMarker marker) { + private void lovisual$drainHudMarker(QueuedHudMarker marker) { if (marker == null || marker.drained) return; marker.drained = true; Renderer2D.drainDeferred2D(marker.layer); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiScreenMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiScreenMixin.java index 271f4d3..01f25a8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiScreenMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/GuiScreenMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -27,7 +27,7 @@ import dev.loki.lovisual.features.gui.clickgui.ClickGuiScreen; import dev.loki.lovisual.features.gui.hud.nondraggable.impl.CustomBar; import dev.loki.lovisual.features.gui.hud.nondraggable.impl.DynamicIsland; import dev.loki.lovisual.features.module.modules.misc.ClickGui; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.RenderPhaseScope; import dev.loki.lovisual.render.engine.renderer.Renderer2D; @@ -36,7 +36,7 @@ import dev.loki.lovisual.render.engine.renderer.Renderer2D; public abstract class GuiScreenMixin { @Unique - private static void combatant$extractCustomBarHeads(GuiGraphicsExtractor drawContext, DeltaTracker tickCounter) { + private static void lovisual$extractCustomBarHeads(GuiGraphicsExtractor drawContext, DeltaTracker tickCounter) { Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; if (ClientScreen.current() != null) return; @@ -45,8 +45,8 @@ public abstract class GuiScreenMixin { if (bar == null || !bar.isHudBarEnabled() || !bar.isHotbarXpBarEnabled()) return; if (CustomBar.shouldUseJumpBar(mc) || !CustomBar.shouldUseLocator(mc, bar)) return; - CombatantRenderSystem.ensureFrameContext(); - try (RenderPhaseScope ignored = CombatantRenderSystem.phase(RenderPhase.SCREEN_TOP, "2d:hud:custom_bar_heads")) { + LoVisualRenderSystem.ensureFrameContext(); + try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.SCREEN_TOP, "2d:hud:custom_bar_heads")) { Renderer2D.withDeferredLayer(Renderer2D.Deferred2DLayer.AFTER_VANILLA_GUI, () -> { CustomBar.renderLocatorHeads(drawContext, tickCounter, mc); Renderer2D.COLOR.render(); @@ -55,7 +55,7 @@ public abstract class GuiScreenMixin { } @Inject(method = "setScreen", at = @At("HEAD")) - private void combatant$closeClickGuiOnScreen(Screen screen, CallbackInfo ci) { + private void lovisual$closeClickGuiOnScreen(Screen screen, CallbackInfo ci) { if (!ModuleManager.isEnabled("clickgui")) { return; } @@ -87,14 +87,14 @@ public abstract class GuiScreenMixin { target = "Lnet/minecraft/client/gui/GuiGraphicsExtractor;applyCursor(Lcom/mojang/blaze3d/platform/Window;)V" ) ) - private void combatant$extractTopLayer(DeltaTracker tickCounter, boolean renderLevel, boolean renderScreens, CallbackInfo ci, + private void lovisual$extractTopLayer(DeltaTracker tickCounter, boolean renderLevel, boolean renderScreens, CallbackInfo ci, @Local(ordinal = 0) GuiGraphicsExtractor drawContext) { if (drawContext == null) { return; } drawContext.nextStratum(); - combatant$extractCustomBarHeads(drawContext, tickCounter); + lovisual$extractCustomBarHeads(drawContext, tickCounter); DynamicIsland.renderScreenOverlay(drawContext, tickCounter.getGameTimeDeltaTicks()); ClickGuiRenderer.renderTopLayer(drawContext, tickCounter.getGameTimeDeltaTicks()); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/HoneyBlockMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/HoneyBlockMixin.java index 5cd9f53..c742041 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/HoneyBlockMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/HoneyBlockMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/InputMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/InputMixin.java index 181777c..c753b58 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/InputMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/InputMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,23 +12,12 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.Sprint; @Mixin(ClientInput.class) public abstract class InputMixin { @Inject(method = "hasForwardImpulse", at = @At("HEAD"), cancellable = true) private void allowAllDirections(CallbackInfoReturnable cir) { - Sprint module = Modules.get(Sprint.class); - if (module == null || !module.shouldAllowDirectionalSprint()) return; - - ClientInput input = (ClientInput) (Object) this; - if (input.keyPresses.forward() - || input.keyPresses.backward() - || input.keyPresses.left() - || input.keyPresses.right()) { - cir.setReturnValue(true); - } + // Sprint module removed; keep vanilla forward impulse check. } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemCooldownsMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemCooldownsMixin.java index c840b09..24c6a34 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemCooldownsMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemCooldownsMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -18,7 +18,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.features.module.modules.combat.TPSSync; -import dev.loki.lovisual.features.module.modules.movement.Timer; import dev.loki.lovisual.mixins.accessors.ItemCooldownEntryAccessor; import java.util.Iterator; @@ -33,36 +32,34 @@ public abstract class ItemCooldownsMixin { @Final private Map cooldowns; @Unique - private float combatant$timerRemainder = 0f; + private float lovisual$timerRemainder = 0f; @Shadow protected abstract void onCooldownEnded(Identifier groupId); @Inject(method = "tick", at = @At("HEAD"), cancellable = true) - private void combatant$timerCompensate(CallbackInfo ci) { - float mult = Timer.getTickTimer(); + private void lovisual$timerCompensate(CallbackInfo ci) { + // Timer module removed; scale only by server TPS when active. float serverDelta = 1.0f; TPSSync tps = Modules.get(TPSSync.class); if (tps != null && tps.isEnabled()) { serverDelta = tps.getServerTickDelta(); } - float scale = (mult <= 0.0001f) ? 1.0f : (serverDelta / mult); - if (scale > 1.0f) scale = 1.0f; - if (scale < 0.0f) scale = 0.0f; + if (serverDelta > 1.0f) serverDelta = 1.0f; + if (serverDelta < 0.0f) serverDelta = 0.0f; - if (Math.abs(scale - 1.0f) < 0.0001f) { + if (Math.abs(serverDelta - 1.0f) < 0.0001f) { return; } - float step = scale; - combatant$timerRemainder += step; - int inc = (int) combatant$timerRemainder; + lovisual$timerRemainder += serverDelta; + int inc = (int) lovisual$timerRemainder; if (inc <= 0) { ci.cancel(); return; } - combatant$timerRemainder -= inc; + lovisual$timerRemainder -= inc; tickCount += inc; if (!cooldowns.isEmpty()) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemEntityRenderStateMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemEntityRenderStateMixin.java index 6b46cf5..c1ed885 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemEntityRenderStateMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemEntityRenderStateMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,15 +15,15 @@ import dev.loki.lovisual.mixininterface.IItemEntityRenderState; @Mixin(ItemEntityRenderState.class) public class ItemEntityRenderStateMixin implements IItemEntityRenderState { @Unique - private boolean combatant$onGround; + private boolean lovisual$onGround; @Override - public boolean combatant$isOnGround() { - return combatant$onGround; + public boolean lovisual$isOnGround() { + return lovisual$onGround; } @Override - public void combatant$setOnGround(boolean onGround) { - combatant$onGround = onGround; + public void lovisual$setOnGround(boolean onGround) { + lovisual$onGround = onGround; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemEntityRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemEntityRendererMixin.java index 3d3625f..36146c0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemEntityRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemEntityRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -39,12 +39,12 @@ public abstract class ItemEntityRendererMixin extends EntityRenderer>> 24) & 0xFF; if (alpha >= 255) { return false; } int rgbMarker = argb & 0x00010101; - return rgbMarker == COMBATANT_VIEW_FADE_DITHER_MARK || rgbMarker == COMBATANT_VIEW_FADE_A2C_MARK; + return rgbMarker == LOVISUAL_VIEW_FADE_DITHER_MARK || rgbMarker == LOVISUAL_VIEW_FADE_A2C_MARK; } @Unique - private static boolean combatant$hasViewFadeTint(int[] tints) { - return tints != null && tints.length > 0 && combatant$isViewFadeMarked(tints[0]); + private static boolean lovisual$hasViewFadeTint(int[] tints) { + return tints != null && tints.length > 0 && lovisual$isViewFadeMarked(tints[0]); } @ModifyReturnValue( method = "getLayerColorSafe([ILnet/minecraft/client/resources/model/geometry/BakedQuad$MaterialInfo;)I", at = @At("RETURN") ) - private static int combatant$applyViewFadeToUntintedItemQuads(int original, + private static int lovisual$applyViewFadeToUntintedItemQuads(int original, int[] tints, BakedQuad.MaterialInfo materialInfo) { - if (original != -1 || !combatant$hasViewFadeTint(tints)) { + if (original != -1 || !lovisual$hasViewFadeTint(tints)) { return original; } return tints[0]; @@ -56,7 +56,7 @@ public abstract class ItemFeatureRendererMixin { method = "prepareMainSubmit", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/geometry/BakedQuad$MaterialInfo;itemRenderType()Lnet/minecraft/client/renderer/rendertype/RenderType;") ) - private RenderType combatant$useTranslucentRenderTypeForViewFadeItem(RenderType original, + private RenderType lovisual$useTranslucentRenderTypeForViewFadeItem(RenderType original, @Local(argsOnly = true) ItemFeatureRenderer.Submit submit, @Local(ordinal = 0) BakedQuad.MaterialInfo materialInfo) { // Vanilla item translucent sheets render into ITEM_ENTITY_TARGET. For entity fade this can diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemInHandRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemInHandRendererMixin.java index 390f20c..e502d33 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemInHandRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemInHandRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -33,7 +33,7 @@ import dev.loki.lovisual.features.module.modules.visuals.ViewModel; public abstract class ItemInHandRendererMixin { @Inject(method = "tick", at = @At("HEAD"), cancellable = true) - private void combatant$skipTickWithoutPlayer(CallbackInfo ci) { + private void lovisual$skipTickWithoutPlayer(CallbackInfo ci) { Minecraft mc = Minecraft.getInstance(); if (mc.level != null && mc.player == null) { ci.cancel(); @@ -44,7 +44,7 @@ public abstract class ItemInHandRendererMixin { method = "submitArmWithItem", at = @At("HEAD") ) - private void combatant$applyOffsets( + private void lovisual$applyOffsets( AbstractClientPlayer player, float tickDelta, float pitch, @@ -72,7 +72,7 @@ public abstract class ItemInHandRendererMixin { at = @At("HEAD"), argsOnly = true, index = 7) - private float combatant$scaleEquipProgress(float equipProgress) { + private float lovisual$scaleEquipProgress(float equipProgress) { ViewModel viewModel = Modules.get(ViewModel.class); if (viewModel == null || !viewModel.isEnabled()) return equipProgress; return equipProgress * viewModel.equipLowering.get(); @@ -90,7 +90,7 @@ public abstract class ItemInHandRendererMixin { target = "Lnet/minecraft/client/renderer/item/ItemStackRenderState;submit(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;III)V" ) ) - private void combatant$scaleMiniItems( + private void lovisual$scaleMiniItems( LivingEntity entity, ItemStack stack, ItemDisplayContext ctx, @@ -113,7 +113,7 @@ public abstract class ItemInHandRendererMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$customSwing( + private void lovisual$customSwing( float swingProgress, PoseStack ms, int direction, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemMixin.java index c7e55da..9ae0ade 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,7 +25,7 @@ public class ItemMixin { target = "Lnet/minecraft/world/entity/player/Player;calculateViewVector(FF)Lnet/minecraft/world/phys/Vec3;" ) ) - private static Vec3 combatant$raycastRotation(Player player, float pitch, float yaw) { + private static Vec3 lovisual$raycastRotation(Player player, float pitch, float yaw) { return RotationManager.INSTANCE.getMovementRotation().directionVector(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemStackMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemStackMixin.java index 69ed7c9..ab3c1ed 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemStackMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ItemStackMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -50,7 +50,7 @@ public class ItemStackMixin { } @Inject(method = "getTooltipLines", at = @At("RETURN"), cancellable = true) - private void combatant$colorizeTooltip(Item.TooltipContext tooltipContext, @Nullable Player player, TooltipFlag type, CallbackInfoReturnable> cir) { + private void lovisual$colorizeTooltip(Item.TooltipContext tooltipContext, @Nullable Player player, TooltipFlag type, CallbackInfoReturnable> cir) { BetterTooltips tooltips = BetterTooltips.get(); if (tooltips == null || !tooltips.isItemInfoColorizeEnabled()) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/JoinMultiplayerScreenMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/JoinMultiplayerScreenMixin.java index 4598506..2fa500d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/JoinMultiplayerScreenMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/JoinMultiplayerScreenMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -30,32 +30,32 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Screen.class) public abstract class JoinMultiplayerScreenMixin { @Unique - private static final float COMBATANT_PROXY_BUTTON_X = 8f; + private static final float LOVISUAL_PROXY_BUTTON_X = 8f; @Unique - private static final float COMBATANT_PROXY_BUTTON_Y = 8f; + private static final float LOVISUAL_PROXY_BUTTON_Y = 8f; @Unique - private static final float COMBATANT_PROXY_BUTTON_W = 24f; + private static final float LOVISUAL_PROXY_BUTTON_W = 24f; @Unique - private static final float COMBATANT_PROXY_BUTTON_H = 24f; + private static final float LOVISUAL_PROXY_BUTTON_H = 24f; @Unique - private float combatant$proxyHover; + private float lovisual$proxyHover; @Unique - private float combatant$proxyPress; + private float lovisual$proxyPress; @Inject(method = "extractRenderState(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("RETURN")) - private void combatant$renderProxyEntry(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void lovisual$renderProxyEntry(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta, CallbackInfo ci) { Screen self = (Screen) (Object) this; if (!(self instanceof JoinMultiplayerScreen)) return; float dt = AnimationUtility.deltaTime(); - boolean hovered = combatant$inside(mouseX, mouseY, COMBATANT_PROXY_BUTTON_X, COMBATANT_PROXY_BUTTON_Y, - COMBATANT_PROXY_BUTTON_W, COMBATANT_PROXY_BUTTON_H); - combatant$proxyHover = combatant$animate(combatant$proxyHover, hovered ? 1f : 0f, dt, 11f); - combatant$proxyPress = combatant$animate(combatant$proxyPress, 0f, dt, 8f); + boolean hovered = lovisual$inside(mouseX, mouseY, LOVISUAL_PROXY_BUTTON_X, LOVISUAL_PROXY_BUTTON_Y, + LOVISUAL_PROXY_BUTTON_W, LOVISUAL_PROXY_BUTTON_H); + lovisual$proxyHover = lovisual$animate(lovisual$proxyHover, hovered ? 1f : 0f, dt, 11f); + lovisual$proxyPress = lovisual$animate(lovisual$proxyPress, 0f, dt, 8f); ViewportContext.beginScaled(context); Renderer2D.COLOR.begin(); try { - combatant$drawProxyButton(); + lovisual$drawProxyButton(); } finally { Renderer2D.COLOR.render(); ViewportContext.end(context); @@ -63,17 +63,17 @@ public abstract class JoinMultiplayerScreenMixin { } @Unique - private void combatant$drawProxyButton() { - float hover = AnimationUtility.easeOutCubic(combatant$proxyHover); - float press = AnimationUtility.easeOutCubic(combatant$proxyPress); + private void lovisual$drawProxyButton() { + float hover = AnimationUtility.easeOutCubic(lovisual$proxyHover); + float press = AnimationUtility.easeOutCubic(lovisual$proxyPress); Themes.Theme theme = Theme.theme(); boolean enabled = ProxyBackend.isEnabled(); ProxyEntry active = ProxyBackend.activeProxy(); boolean configured = active.isConfigured(); - float size = COMBATANT_PROXY_BUTTON_W * (1.0f + hover * 0.035f - press * 0.025f); - float x = COMBATANT_PROXY_BUTTON_X + (COMBATANT_PROXY_BUTTON_W - size) * 0.5f; - float y = COMBATANT_PROXY_BUTTON_Y + (COMBATANT_PROXY_BUTTON_H - size) * 0.5f - hover * 0.35f; + float size = LOVISUAL_PROXY_BUTTON_W * (1.0f + hover * 0.035f - press * 0.025f); + float x = LOVISUAL_PROXY_BUTTON_X + (LOVISUAL_PROXY_BUTTON_W - size) * 0.5f; + float y = LOVISUAL_PROXY_BUTTON_Y + (LOVISUAL_PROXY_BUTTON_H - size) * 0.5f - hover * 0.35f; float radius = 5.0f; float centerX = x + size * 0.5f; float centerY = y + size * 0.5f; @@ -97,13 +97,13 @@ public abstract class JoinMultiplayerScreenMixin { } @Unique - private static float combatant$animate(float current, float target, float dt, float speed) { + private static float lovisual$animate(float current, float target, float dt, float speed) { float next = AnimationUtility.approach(current, target, dt, speed); return AnimationUtility.snap(next, target, 0.001f); } @Unique - private static boolean combatant$inside(float mx, float my, float x, float y, float w, float h) { + private static boolean lovisual$inside(float mx, float my, float x, float y, float w, float h) { return mx >= x && mx <= x + w && my >= y && my <= y + h; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/JumpBarMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/JumpBarMixin.java index 0f0ba0c..2ff452f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/JumpBarMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/JumpBarMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,14 +16,14 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.loki.lovisual.features.gui.hud.nondraggable.impl.CustomBar; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; @Mixin(JumpableVehicleBar.class) public abstract class JumpBarMixin { @Inject(method = "extractBackground", at = @At("HEAD"), cancellable = true) - private void combatant$renderJumpBar(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + private void lovisual$renderJumpBar(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { + if (!Lifecycle.canRunHud()) return; Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; @@ -35,8 +35,8 @@ public abstract class JumpBarMixin { } @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) - private void combatant$renderJumpAddons(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + private void lovisual$renderJumpAddons(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { + if (!Lifecycle.canRunHud()) return; Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyMappingMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyMappingMixin.java index 29edad7..baa7e42 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyMappingMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyMappingMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ public class KeyMappingMixin { private boolean isDown; @Inject(method = "isDown", at = @At("HEAD"), cancellable = true) - private void combatant$keybindIsPressedEvent(CallbackInfoReturnable cir) { + private void lovisual$keybindIsPressedEvent(CallbackInfoReturnable cir) { if (!Events.BUS.hasListeners(KeybindIsPressedEvent.class)) { return; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyboardInputMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyboardInputMixin.java index f72206c..2c01366 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyboardInputMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyboardInputMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -28,7 +28,7 @@ public abstract class KeyboardInputMixin extends InputMixin { target = "(ZZZZZZZ)Lnet/minecraft/world/entity/player/Input;" ) ) - private Input combatant$applyFreeCorrection(Input original) { + private Input lovisual$applyFreeCorrection(Input original) { Minecraft mc = Minecraft.getInstance(); if (mc.player == null) { return original; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyboardMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyboardMixin.java index db965fb..84cd61a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyboardMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/KeyboardMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -34,7 +34,7 @@ import dev.loki.lovisual.features.gui.clickgui.*; import dev.loki.lovisual.features.gui.hud.draggable.impl.BetterChat; import dev.loki.lovisual.features.module.ModuleManager; import dev.loki.lovisual.mixins.accessors.ChatScreenAccessor; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import dev.loki.lovisual.util.NarratorBlocker; import dev.loki.lovisual.util.input.KeyManager; import dev.loki.lovisual.util.text.ClipboardUtil; @@ -70,9 +70,9 @@ public class KeyboardMixin { // ===== CHAR TYPING ===== @Inject(method = "charTyped", at = @At("HEAD"), cancellable = true) - private void combatant$onChar(long window, CharacterEvent input, CallbackInfo ci) { + private void lovisual$onChar(long window, CharacterEvent input, CallbackInfo ci) { Minecraft mc = Minecraft.getInstance(); - if (RuntimeGate.canRunHud() + if (Lifecycle.canRunHud() && ClientScreen.current() instanceof ChatScreen && BetterChat.isActive() && BetterChatSearch.isActive()) { @@ -80,7 +80,7 @@ public class KeyboardMixin { ci.cancel(); return; } - if (!RuntimeGate.canRunClientLogic() || !ModuleManager.isEnabled("clickgui")) return; + if (!Lifecycle.isActive() || !ModuleManager.isEnabled("clickgui")) return; char c = (char) input.codepoint(); @@ -97,7 +97,7 @@ public class KeyboardMixin { // ===== KEY DOWN ===== @Inject(method = "keyPress", at = @At("HEAD"), cancellable = true) - private void combatant$onKey(long window, int action, KeyEvent input, CallbackInfo ci) { + private void lovisual$onKey(long window, int action, KeyEvent input, CallbackInfo ci) { KeyManager.handleKeyEvent(input.key(), input.scancode(), action); Minecraft mc = Minecraft.getInstance(); @@ -112,7 +112,7 @@ public class KeyboardMixin { boolean narratorHotkeyContext = screen == null || !(screen.getFocused() instanceof EditBox) || !((EditBox) screen.getFocused()).canConsumeInput(); - if (RuntimeGate.canRunClientLogic() + if (Lifecycle.isActive() && NarratorBlocker.isBlocked() && narratorHotkeyContext && action != GLFW.GLFW_RELEASE @@ -123,7 +123,7 @@ public class KeyboardMixin { return; } - if (RuntimeGate.canRunClientLogic() + if (Lifecycle.isActive() && ModuleManager.isEnabled("clickgui") && (ClientScreen.current() instanceof ClickGuiScreen || ClientScreen.current() instanceof ClickGuiPickerScreen @@ -135,7 +135,7 @@ public class KeyboardMixin { forwardMovementKeys(mc.options, input, action != GLFW.GLFW_RELEASE); } } - if (RuntimeGate.canRunHud() + if (Lifecycle.canRunHud() && ClientScreen.current() instanceof ChatScreen && BetterChat.isActive() && BetterChatSearch.isActive()) { @@ -176,7 +176,7 @@ public class KeyboardMixin { } } } - if (RuntimeGate.canRunHud() + if (Lifecycle.canRunHud() && ClientScreen.current() instanceof ChatScreen && BetterChat.isActive() && !BetterChatSearch.isActive()) { @@ -188,7 +188,7 @@ public class KeyboardMixin { } } } - if (!RuntimeGate.canRunClientLogic() || !ModuleManager.isEnabled("clickgui")) return; + if (!Lifecycle.isActive() || !ModuleManager.isEnabled("clickgui")) return; int key = input.key(); int scancode = input.scancode(); @@ -224,11 +224,11 @@ public class KeyboardMixin { } @Inject(method = "keyPress", at = @At("HEAD")) - private void combatant$betterChatCopy(long window, int action, KeyEvent input, CallbackInfo ci) { + private void lovisual$betterChatCopy(long window, int action, KeyEvent input, CallbackInfo ci) { if (action != 1) return; // GLFW_PRESS Minecraft mc = Minecraft.getInstance(); if (!(ClientScreen.current() instanceof ChatScreen)) return; - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; if (!BetterChat.isActive()) return; if ((input.modifiers() & GLFW.GLFW_MOD_CONTROL) == 0) return; if (input.key() == GLFW.GLFW_KEY_C) { @@ -237,12 +237,12 @@ public class KeyboardMixin { } @Inject(method = "keyPress", at = @At("HEAD")) - private void combatant$betterChat$clearOnDebug(long window, int action, KeyEvent input, CallbackInfo ci) { + private void lovisual$betterChat$clearOnDebug(long window, int action, KeyEvent input, CallbackInfo ci) { if (action != GLFW.GLFW_PRESS) return; if (input.key() != GLFW.GLFW_KEY_D) return; Minecraft mc = Minecraft.getInstance(); if (mc == null) return; - if (!RuntimeGate.canRunHud()) return; + if (!Lifecycle.canRunHud()) return; // F3 + D clears vanilla chat; mirror it for BetterChat if (InputConstants.isKeyDown(mc.getWindow(), GLFW.GLFW_KEY_F3)) { BetterChatStoreManager.clearActive(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LavaFogModifierMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LavaFogModifierMixin.java index ae157de..2f854b4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LavaFogModifierMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LavaFogModifierMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ import dev.loki.lovisual.features.module.modules.visuals.WorldTweaks; public class LavaFogModifierMixin { @Inject(method = "setupFog", at = @At("HEAD"), cancellable = true) - private void combatant$noLavaFog(FogData data, + private void lovisual$noLavaFog(FogData data, Camera camera, ClientLevel world, float viewDistance, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelExtractorMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelExtractorMixin.java index 1114af1..a984e96 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelExtractorMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelExtractorMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -46,7 +46,7 @@ public abstract class LevelExtractorMixin { } } - EntityRenderState state = ((LevelExtractorAccessor) this).combatant$invokeExtractEntity( + EntityRenderState state = ((LevelExtractorAccessor) this).lovisual$invokeExtractEntity( mc.player, tickCounter.getGameTimeDeltaPartialTick(false) ); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelMixin.java index 0683b3d..a547363 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelRendererMixin.java index 6e40ee8..3968feb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LevelRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -40,7 +40,7 @@ import dev.loki.lovisual.features.module.modules.visuals.ReimaginedVisual; import dev.loki.lovisual.features.module.modules.visuals.WorldTweaks; import dev.loki.lovisual.mixins.accessors.GameRendererAccessor; import dev.loki.lovisual.mixins.accessors.LevelRendererAccessor; -import dev.loki.lovisual.render.engine.core.CombatantWorldMatrices; +import dev.loki.lovisual.render.engine.core.LoVisualWorldMatrices; import dev.loki.lovisual.render.engine.depth.PreTranslucentDepth; import dev.loki.lovisual.render.engine.depth.WorldSceneDepth; import dev.loki.lovisual.render.iris.IrisRuntime; @@ -61,12 +61,12 @@ public abstract class LevelRendererMixin { target = "Lnet/minecraft/client/renderer/GameRenderer;mainRenderTarget()Lcom/mojang/blaze3d/pipeline/RenderTarget;" ) ) - private RenderTarget combatant$stableSkyRendererTarget(GameRenderer instance, Operation original) { - return ((GameRendererAccessor) instance).combatant$getMainRenderTargetRaw(); + private RenderTarget lovisual$stableSkyRendererTarget(GameRenderer instance, Operation original) { + return ((GameRendererAccessor) instance).lovisual$getMainRenderTargetRaw(); } @Unique - private static void combatant$dependsOn(FramePass pass, ResourceHandle handle) { + private static void lovisual$dependsOn(FramePass pass, ResourceHandle handle) { if (pass != null && handle != null) { pass.reads(handle); } @@ -74,12 +74,12 @@ public abstract class LevelRendererMixin { @Unique @SuppressWarnings("unchecked") - private static ResourceHandle combatant$asRenderTargetHandle(ResourceHandle handle) { + private static ResourceHandle lovisual$asRenderTargetHandle(ResourceHandle handle) { return (ResourceHandle) handle; } @Unique - private static RenderTarget combatant$getFramebuffer(ResourceHandle handle) { + private static RenderTarget lovisual$getFramebuffer(ResourceHandle handle) { if (handle == null) { return null; } @@ -91,7 +91,7 @@ public abstract class LevelRendererMixin { } @Unique - private static boolean combatant$needsWorldSceneDepthCapture() { + private static boolean lovisual$needsWorldSceneDepthCapture() { ReimaginedVisual module = Modules.get(ReimaginedVisual.class); return module != null && module.needsWorldSceneDepthCapture(); } @@ -107,7 +107,7 @@ public abstract class LevelRendererMixin { } @Inject(method = "render", at = @At("HEAD")) - private void combatant$captureIrisModelView( + private void lovisual$captureIrisModelView( GraphicsResourceAllocator allocator, DeltaTracker tickCounter, boolean renderBlockOutline, @@ -122,8 +122,8 @@ public abstract class LevelRendererMixin { return; } - if (CombatantWorldMatrices.isValid()) { - CombatantWorldMatrices.capturePosition( + if (LoVisualWorldMatrices.isValid()) { + LoVisualWorldMatrices.capturePosition( positionMatrix, cameraRenderState != null && cameraRenderState.pos != null ? cameraRenderState.pos @@ -133,7 +133,7 @@ public abstract class LevelRendererMixin { } if (cameraRenderState != null && cameraRenderState.projectionMatrix != null) { - CombatantWorldMatrices.capture( + LoVisualWorldMatrices.capture( positionMatrix, cameraRenderState.projectionMatrix, cameraRenderState.projectionMatrix, @@ -147,7 +147,7 @@ public abstract class LevelRendererMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$disableVanillaOutline(PoseStack matrices, + private void lovisual$disableVanillaOutline(PoseStack matrices, SubmitNodeCollector consumers, LevelRenderState renderState, CallbackInfo ci) { @@ -165,7 +165,7 @@ public abstract class LevelRendererMixin { shift = At.Shift.AFTER ) ) - private void combatant$captureWorldSceneDepth( + private void lovisual$captureWorldSceneDepth( GraphicsResourceAllocator allocator, DeltaTracker tickCounter, boolean renderBlockOutline, @@ -183,7 +183,7 @@ public abstract class LevelRendererMixin { if (frameGraphBuilder == null || targets == null || targets.main == null) { return; } - if (!combatant$needsWorldSceneDepthCapture()) { + if (!lovisual$needsWorldSceneDepthCapture()) { WorldSceneDepth.reset(); return; } @@ -194,15 +194,15 @@ public abstract class LevelRendererMixin { ResourceHandle particles = targets.particles; ResourceHandle weather = targets.weather; - FramePass pass = frameGraphBuilder.addPass("combatant_scene_depth_capture"); - combatant$dependsOn(pass, main); - combatant$dependsOn(pass, translucent); - combatant$dependsOn(pass, itemEntity); - combatant$dependsOn(pass, particles); - combatant$dependsOn(pass, weather); + FramePass pass = frameGraphBuilder.addPass("lovisual_scene_depth_capture"); + lovisual$dependsOn(pass, main); + lovisual$dependsOn(pass, translucent); + lovisual$dependsOn(pass, itemEntity); + lovisual$dependsOn(pass, particles); + lovisual$dependsOn(pass, weather); pass.disableCulling(); pass.executes(() -> { - RenderTarget mainFramebuffer = combatant$getFramebuffer(main); + RenderTarget mainFramebuffer = lovisual$getFramebuffer(main); Minecraft client = Minecraft.getInstance(); RenderTarget fallbackFramebuffer = client != null ? client.gameRenderer.mainRenderTarget() : null; int width = mainFramebuffer != null ? mainFramebuffer.width : fallbackFramebuffer != null ? fallbackFramebuffer.width : 1; @@ -210,20 +210,20 @@ public abstract class LevelRendererMixin { WorldSceneDepth.beginFrame(width, height); WorldSceneDepth.captureMain(mainFramebuffer); - WorldSceneDepth.captureTranslucent(combatant$getFramebuffer(translucent)); - WorldSceneDepth.captureItemEntity(combatant$getFramebuffer(itemEntity)); - WorldSceneDepth.captureParticles(combatant$getFramebuffer(particles)); - WorldSceneDepth.captureWeather(combatant$getFramebuffer(weather)); + WorldSceneDepth.captureTranslucent(lovisual$getFramebuffer(translucent)); + WorldSceneDepth.captureItemEntity(lovisual$getFramebuffer(itemEntity)); + WorldSceneDepth.captureParticles(lovisual$getFramebuffer(particles)); + WorldSceneDepth.captureWeather(lovisual$getFramebuffer(weather)); }); } @Inject(method = "addSkyPass", at = @At("HEAD"), cancellable = true) - private void combatant$renderSky(FrameGraphBuilder frameGraphBuilder, net.minecraft.client.renderer.state.level.CameraRenderState cameraRenderState, GpuBufferSlice fog, CallbackInfo ci) { + private void lovisual$renderSky(FrameGraphBuilder frameGraphBuilder, net.minecraft.client.renderer.state.level.CameraRenderState cameraRenderState, GpuBufferSlice fog, CallbackInfo ci) { if (IrisRuntime.isModLoaded()) return; if (shouldSkipSky(cameraRenderState)) return; LevelRendererAccessor accessor = (LevelRendererAccessor) this; - SkyRenderState sky = accessor.combatant$getWorldRenderState().skyRenderState; + SkyRenderState sky = accessor.lovisual$getWorldRenderState().skyRenderState; if (sky == null || sky.skybox != DimensionType.Skybox.OVERWORLD) return; WorldTweaks worldTweaks = Modules.get(WorldTweaks.class); @@ -240,9 +240,9 @@ public abstract class LevelRendererMixin { : null; if (camera == null) return; - FramePass pass = frameGraphBuilder.addPass("combatant_sky"); + FramePass pass = frameGraphBuilder.addPass("lovisual_sky"); targets.main = pass.readsAndWrites(targets.main); - pass.executes(() -> CustomSkyboxRenderer.render(camera, fog, sky, accessor.combatant$getSkyRendering())); + pass.executes(() -> CustomSkyboxRenderer.render(camera, fog, sky, accessor.lovisual$getSkyRendering())); ci.cancel(); } @@ -256,7 +256,7 @@ public abstract class LevelRendererMixin { ), remap = false ) - private void combatant$capturePreWaterScene( + private void lovisual$capturePreWaterScene( GpuBufferSlice fogBuffer, LevelRenderState worldRenderState, net.minecraft.util.profiling.ProfilerFiller profiler, @@ -272,7 +272,7 @@ public abstract class LevelRendererMixin { if (IrisRuntime.isShaderpackRendererActive()) { return; } - RenderTarget mainFramebuffer = combatant$getFramebuffer(combatant$asRenderTargetHandle(mainFramebufferHandle)); + RenderTarget mainFramebuffer = lovisual$getFramebuffer(lovisual$asRenderTargetHandle(mainFramebufferHandle)); if (mainFramebuffer == null) { Minecraft mc = Minecraft.getInstance(); mainFramebuffer = mc != null && mc.gameRenderer != null ? mc.gameRenderer.mainRenderTarget() : null; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LibraryMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LibraryMixin.java index 2105d10..623c6c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LibraryMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LibraryMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,12 +23,12 @@ import dev.loki.lovisual.util.wav.CustomSoundEngine; @Mixin(Library.class) public class LibraryMixin { @Inject(method = "init", at = @At("RETURN")) - private void combatant$resetOnInit(@Nullable String deviceSpecifier, DeviceList deviceList, boolean directionalAudio, CallbackInfo ci) { + private void lovisual$resetOnInit(@Nullable String deviceSpecifier, DeviceList deviceList, boolean directionalAudio, CallbackInfo ci) { CustomSoundEngine.get().reset(); } @Inject(method = "cleanup", at = @At("HEAD")) - private void combatant$resetOnClose(CallbackInfo ci) { + private void lovisual$resetOnClose(CallbackInfo ci) { CustomSoundEngine.get().reset(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LightmapMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LightmapMixin.java index 8308dc0..3b88bb1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LightmapMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LightmapMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -27,7 +27,7 @@ public abstract class LightmapMixin { ), index = 0 ) - private float combatant$ambientLightEvent(float original) { + private float lovisual$ambientLightEvent(float original) { LightmapEvent event = new LightmapEvent(original); Events.BUS.post(event); float value = event.getAmbientLight(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LightmapRenderStateExtractorMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LightmapRenderStateExtractorMixin.java index 9ede4ca..22ce18b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LightmapRenderStateExtractorMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LightmapRenderStateExtractorMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,7 +20,7 @@ import dev.loki.lovisual.render.engine.light.LightmapState; @Mixin(LightmapRenderStateExtractor.class) public abstract class LightmapRenderStateExtractorMixin { @Inject(method = "extract", at = @At("TAIL")) - private void combatant$modifyLightmapState(LightmapRenderState state, float tickDelta, CallbackInfo ci) { + private void lovisual$modifyLightmapState(LightmapRenderState state, float tickDelta, CallbackInfo ci) { if (state == null) return; LightmapModifyEvent event = new LightmapModifyEvent(state); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityMixin.java index 094dc73..4922883 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityMixin.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -55,9 +55,6 @@ import dev.loki.lovisual.events.impl.PlayerJumpEvent; import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.features.module.modules.combat.PvpCooldowns; import dev.loki.lovisual.features.module.modules.combat.TPSSync; -import dev.loki.lovisual.features.module.modules.movement.ElytraFly; -import dev.loki.lovisual.features.module.modules.movement.NoStun; -import dev.loki.lovisual.features.module.modules.movement.Timer; import dev.loki.lovisual.features.module.modules.visuals.NoRender; import dev.loki.lovisual.features.module.modules.visuals.WorldTweaks; import dev.loki.lovisual.util.aiming.RotationManager; @@ -71,28 +68,28 @@ import dev.loki.lovisual.util.pvp.opponents.TotemPopCounter; public abstract class LivingEntityMixin { @Unique - private float combatant$itemUseRemainder = 0f; + private float lovisual$itemUseRemainder = 0f; @Unique - private float combatant$effectTickRemainder = 0f; + private float lovisual$effectTickRemainder = 0f; @Shadow protected int useItemRemaining; @Unique - private PlayerJumpEvent combatant$playerJumpEvent; + private PlayerJumpEvent lovisual$playerJumpEvent; @Shadow protected abstract float getJumpPower(); @Inject(method = "getAttributeValue", at = @At("RETURN")) - private void combatant$noStunSlownessMovementSpeed(Holder attribute, CallbackInfoReturnable cir) { + private void lovisual$noStunSlownessMovementSpeed(Holder attribute, CallbackInfoReturnable cir) { if (!attribute.equals(Attributes.MOVEMENT_SPEED)) return; return; } @ModifyReturnValue(method = "getMainHandItem", at = @At("RETURN")) - private ItemStack combatant$applyInventorySwapLeaseForMainHand(ItemStack original) { + private ItemStack lovisual$applyInventorySwapLeaseForMainHand(ItemStack original) { Minecraft mc = Minecraft.getInstance(); if ((Object) this == mc.player) { InventorySwap.INSTANCE.isHotbarLeased(); @@ -107,7 +104,7 @@ public abstract class LivingEntityMixin { * This never cancels item use; it only starts a visible local timer when explicitly configured. */ @Inject(method = "updatingUsingItem", at = @At("HEAD")) - private void combatant$onFinishEating(CallbackInfo ci) { + private void lovisual$onFinishEating(CallbackInfo ci) { LivingEntity self = (LivingEntity) (Object) this; Minecraft mc = Minecraft.getInstance(); if (self != mc.player) return; @@ -124,32 +121,32 @@ public abstract class LivingEntityMixin { } @Inject(method = "updatingUsingItem", at = @At("HEAD"), cancellable = true) - private void combatant$fixItemUseSpeed(CallbackInfo ci) { + private void lovisual$fixItemUseSpeed(CallbackInfo ci) { LivingEntity self = (LivingEntity) (Object) this; if (!(self instanceof Player player)) { - combatant$itemUseRemainder = 0f; + lovisual$itemUseRemainder = 0f; return; } if (!player.level().isClientSide()) return; if (!player.isUsingItem()) { - combatant$itemUseRemainder = 0f; + lovisual$itemUseRemainder = 0f; return; } - float scale = combatant$clientTickScale(); + float scale = lovisual$clientTickScale(); if (scale >= 0.999f) { - combatant$itemUseRemainder = 0f; + lovisual$itemUseRemainder = 0f; return; } - combatant$itemUseRemainder += scale; - if (combatant$itemUseRemainder < 1.0f) { + lovisual$itemUseRemainder += scale; + if (lovisual$itemUseRemainder < 1.0f) { ci.cancel(); return; } - combatant$itemUseRemainder -= 1.0f; + lovisual$itemUseRemainder -= 1.0f; } @Redirect( @@ -159,7 +156,7 @@ public abstract class LivingEntityMixin { target = "Lnet/minecraft/world/effect/MobEffectInstance;tickClient()V" ) ) - private void combatant$scaleClientEffects(MobEffectInstance instance) { + private void lovisual$scaleClientEffects(MobEffectInstance instance) { LivingEntity self = (LivingEntity) (Object) this; if (!self.level().isClientSide()) { instance.tickClient(); @@ -172,42 +169,39 @@ public abstract class LivingEntityMixin { return; } - float scale = combatant$clientTickScale(); + float scale = lovisual$clientTickScale(); if (scale >= 0.999f) { - combatant$effectTickRemainder = 0f; + lovisual$effectTickRemainder = 0f; instance.tickClient(); return; } - combatant$effectTickRemainder += scale; - if (combatant$effectTickRemainder < 1.0f) { + lovisual$effectTickRemainder += scale; + if (lovisual$effectTickRemainder < 1.0f) { return; } - combatant$effectTickRemainder -= 1.0f; + lovisual$effectTickRemainder -= 1.0f; instance.tickClient(); } @Unique - private float combatant$clientTickScale() { - float mult = Timer.getTickTimer(); - if (mult <= 0.0001f) return 1.0f; - + private float lovisual$clientTickScale() { + // Timer module removed; scale only by server TPS when active. float serverDelta = 1.0f; TPSSync tps = Modules.get(TPSSync.class); if (tps != null && tps.isEnabled()) { serverDelta = tps.getServerTickDelta(); } - float scale = serverDelta / mult; - if (scale > 1.0f) return 1.0f; - return Math.max(scale, 0.0f); + if (serverDelta > 1.0f) return 1.0f; + return Math.max(serverDelta, 0.0f); } /** * Local totem cooldowns are handled from the confirmed entity-status packet when explicitly configured. */ @Inject(method = "checkTotemDeathProtection", at = @At("RETURN")) - private void combatant$onTotemUse(DamageSource source, CallbackInfoReturnable cir) { + private void lovisual$onTotemUse(DamageSource source, CallbackInfoReturnable cir) { // no local use blocking or prediction here } @@ -215,7 +209,7 @@ public abstract class LivingEntityMixin { * Сброс кулдаунов при смерти. */ @Inject(method = "die", at = @At("HEAD")) - private void combatant$onDeath(DamageSource source, CallbackInfo ci) { + private void lovisual$onDeath(DamageSource source, CallbackInfo ci) { LivingEntity self = (LivingEntity) (Object) this; if (self instanceof Player player) { TotemPopCounter.onPlayerDeath(player.getUUID()); @@ -248,22 +242,7 @@ public abstract class LivingEntityMixin { @Inject(method = "aiStep", at = @At("HEAD")) private void preventCrash(CallbackInfo ci) { - LivingEntity self = (LivingEntity) (Object) this; - - if (!(self instanceof Player p)) return; - ElytraFly elytraFly = Modules.get(ElytraFly.class); - if (elytraFly == null || !elytraFly.isEnabled()) return; - if (!elytraFly.noCrash.get()) return; - if (!p.isFallFlying()) return; - - Vec3 vel = p.getDeltaMovement(); - - if (vel.horizontalDistance() < 1) return; - AABB next = p.getBoundingBox().move(vel); - - if (!p.level().noCollision(next)) { - p.setDeltaMovement(0, 0, 0); - } + // ElytraFly module removed; no crash-prevention override remains. } @ModifyExpressionValue( @@ -273,7 +252,7 @@ public abstract class LivingEntityMixin { target = "Lnet/minecraft/world/entity/LivingEntity;getLookAngle()Lnet/minecraft/world/phys/Vec3;" ) ) - private Vec3 combatant$modifyGlidingRotationVector(Vec3 original) { + private Vec3 lovisual$modifyGlidingRotationVector(Vec3 original) { LivingEntity self = (LivingEntity) (Object) this; Minecraft mc = Minecraft.getInstance(); if (!(self instanceof LocalPlayer player) || mc == null || player != mc.player) { @@ -298,7 +277,7 @@ public abstract class LivingEntityMixin { target = "Lnet/minecraft/world/entity/LivingEntity;getXRot()F" ) ) - private float combatant$modifyGlidingPitch(float original) { + private float lovisual$modifyGlidingPitch(float original) { LivingEntity self = (LivingEntity) (Object) this; Minecraft mc = Minecraft.getInstance(); if (!(self instanceof LocalPlayer player) || mc == null || player != mc.player) { @@ -337,28 +316,28 @@ public abstract class LivingEntityMixin { } @Inject(method = "jumpFromGround", at = @At("HEAD"), cancellable = true) - private void combatant$onJumpHead(CallbackInfo ci) { + private void lovisual$onJumpHead(CallbackInfo ci) { LivingEntity self = (LivingEntity) (Object) this; if (!(self instanceof LocalPlayer player)) { - combatant$playerJumpEvent = null; + lovisual$playerJumpEvent = null; return; } Minecraft mc = Minecraft.getInstance(); if (mc == null || player != mc.player) { - combatant$playerJumpEvent = null; + lovisual$playerJumpEvent = null; return; } PlayerJumpEvent event = new PlayerJumpEvent(self.getYRot(), getJumpPower()); Events.BUS.post(event); if (event.isCancelled()) { - combatant$playerJumpEvent = null; + lovisual$playerJumpEvent = null; ci.cancel(); return; } - combatant$playerJumpEvent = event; + lovisual$playerJumpEvent = event; } @ModifyExpressionValue( @@ -368,8 +347,8 @@ public abstract class LivingEntityMixin { target = "Lnet/minecraft/world/entity/LivingEntity;getJumpPower()F" ) ) - private float combatant$modifyJumpMotion(float original) { - return combatant$playerJumpEvent != null ? combatant$playerJumpEvent.getMotion() : original; + private float lovisual$modifyJumpMotion(float original) { + return lovisual$playerJumpEvent != null ? lovisual$playerJumpEvent.getMotion() : original; } @ModifyExpressionValue( @@ -379,7 +358,7 @@ public abstract class LivingEntityMixin { target = "(DDD)Lnet/minecraft/world/phys/Vec3;" ) ) - private Vec3 combatant$fixJumpRotation(Vec3 original) { + private Vec3 lovisual$fixJumpRotation(Vec3 original) { LivingEntity self = (LivingEntity) (Object) this; Minecraft mc = Minecraft.getInstance(); if (!(self instanceof LocalPlayer player) || mc == null || player != mc.player) { @@ -403,13 +382,13 @@ public abstract class LivingEntityMixin { target = "Lnet/minecraft/world/entity/LivingEntity;getYRot()F" ) ) - private float combatant$omniSprintJumpYaw(LivingEntity instance) { - return combatant$playerJumpEvent != null ? combatant$playerJumpEvent.getYaw() : instance.getYRot(); + private float lovisual$omniSprintJumpYaw(LivingEntity instance) { + return lovisual$playerJumpEvent != null ? lovisual$playerJumpEvent.getYaw() : instance.getYRot(); } @Inject(method = "jumpFromGround", at = @At("RETURN")) - private void combatant$onJumpReturn(CallbackInfo ci) { - combatant$playerJumpEvent = null; + private void lovisual$onJumpReturn(CallbackInfo ci) { + lovisual$playerJumpEvent = null; } @Unique @@ -426,38 +405,7 @@ public abstract class LivingEntityMixin { cancellable = true ) private void nostun$soulSandVelocity(CallbackInfoReturnable cir) { - LivingEntity self = (LivingEntity) (Object) this; - if (!(self instanceof Player player)) return; - Minecraft client = Minecraft.getInstance(); - if (client == null || player != client.player) return; - - NoStun ns = Modules.get(NoStun.class); - if (ns == null || !ns.isEnabled()) return; - if (ns.isVulcan297()) { - BlockPos pos = player.blockPosition(); - BlockState state = player.level().getBlockState(pos); - if (state.is(Blocks.SOUL_SAND)) { - cir.setReturnValue(ns.getSoulSandVelocityMultiplier(cir.getReturnValue())); - } - return; - } - - // общий тумблер env - if (!ns.isFunctionEnabled(NoStun.fnEnvBlocks())) return; - - // конкретный тумблер песка душ - if (!ns.isEnvBlockEnabled(NoStun.envSoulSand())) return; - - BlockPos pos = player.blockPosition(); - BlockState state = player.level().getBlockState(pos); - - if (!state.is(Blocks.SOUL_SAND)) return; - - float vanilla = cir.getReturnValue(); - - if (vanilla < 1.0F) { - cir.setReturnValue(1.0F); - } + // NoStun module removed; no velocity override remains. } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityRenderStateMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityRenderStateMixin.java index 897d59a..ecdc97c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityRenderStateMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityRenderStateMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,41 +15,41 @@ import dev.loki.lovisual.render.ViewObstructionFadeState; @Mixin(LivingEntityRenderState.class) public abstract class LivingEntityRenderStateMixin implements ViewObstructionFadeState { @Unique - private boolean combatant$viewObstructionFadeActive; + private boolean lovisual$viewObstructionFadeActive; @Unique - private float combatant$viewObstructionFadeAlpha = 1.0f; + private float lovisual$viewObstructionFadeAlpha = 1.0f; @Unique - private boolean combatant$seeInvisibleFadeActive; + private boolean lovisual$seeInvisibleFadeActive; @Override - public boolean combatant$isViewObstructionFadeActive() { - return combatant$viewObstructionFadeActive; + public boolean lovisual$isViewObstructionFadeActive() { + return lovisual$viewObstructionFadeActive; } @Override - public float combatant$getViewObstructionFadeAlpha() { - return combatant$viewObstructionFadeAlpha; + public float lovisual$getViewObstructionFadeAlpha() { + return lovisual$viewObstructionFadeAlpha; } @Override - public void combatant$setViewObstructionFadeActive(boolean active) { - this.combatant$viewObstructionFadeActive = active; + public void lovisual$setViewObstructionFadeActive(boolean active) { + this.lovisual$viewObstructionFadeActive = active; } @Override - public void combatant$setViewObstructionFadeAlpha(float alpha) { - this.combatant$viewObstructionFadeAlpha = alpha; + public void lovisual$setViewObstructionFadeAlpha(float alpha) { + this.lovisual$viewObstructionFadeAlpha = alpha; } @Override - public boolean combatant$isSeeInvisibleFadeActive() { - return combatant$seeInvisibleFadeActive; + public boolean lovisual$isSeeInvisibleFadeActive() { + return lovisual$seeInvisibleFadeActive; } @Override - public void combatant$setSeeInvisibleFadeActive(boolean active) { - this.combatant$seeInvisibleFadeActive = active; + public void lovisual$setSeeInvisibleFadeActive(boolean active) { + this.lovisual$seeInvisibleFadeActive = active; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityRendererMixin.java index 5b591ae..9be16c0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LivingEntityRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -55,7 +55,7 @@ public abstract class LivingEntityRendererMixin cir) { + private void lovisual$hideVanillaLabels(T entity, double distanceSq, CallbackInfoReturnable cir) { if (entity instanceof Player && Modules.get(NameTags.class) != null && Modules.get(NameTags.class).isEnabled()) { cir.setReturnValue(false); } @@ -65,7 +65,7 @@ public abstract class LivingEntityRendererMixin= 0.99f) { + || !fadeState.lovisual$isViewObstructionFadeActive() + || fadeState.lovisual$getViewObstructionFadeAlpha() >= 0.99f) { return original; } return RenderTypes.entityTranslucent(getTextureLocation(state), true); @@ -173,11 +173,11 @@ public abstract class LivingEntityRendererMixin cir) { - NoStun ns = Modules.get(NoStun.class); - if (ns == null || !ns.isEnabled()) return; - if (!ns.isFunctionEnabled(NoStun.fnUseSpeed())) return; - - LocalPlayer player = (LocalPlayer) (Object) this; - if (player.isUsingItem() && !player.isPassenger()) { - Vec2 base = cir.getReturnValue(); - - // 0.0 -> vanilla (no change), 1.0 -> normal walking speed. - // In vanilla, most item-use slowdowns are ~0.2x, so we approximate by lerping 1..5. - float t = ns.getEatSpeed01(); - float mult = 1.0f + t * 4.0f; - - if (mult > 1.001f) { - cir.setReturnValue(base.scale(mult)); - } - } + // NoStun module removed; no item-use speed boost remains. } @Inject(method = "aiStep", at = @At("HEAD")) - private void combatant$elytraFlyVanilla(CallbackInfo ci) { - LocalPlayer player = (LocalPlayer) (Object) this; - ElytraFly elytraFly = Modules.get(ElytraFly.class); - if (elytraFly == null || !elytraFly.shouldApplyVanillaHook(player)) { - return; - } - - Vec3 velocity = player.getDeltaMovement(); - Vec3 look = player.getViewVector(1.0f); - float pitch = player.getXRot(); - - velocity = velocity.scale(elytraFly.getVanillaDragFactor()); - velocity = velocity.add(look.scale(elytraFly.getVanillaForwardBoostFactor())); - - double lift = -Math.sin(Math.toRadians(pitch)) * elytraFly.getVanillaPitchLiftFactor(); - player.setDeltaMovement(velocity.add(0.0, lift, 0.0)); + private void lovisual$elytraFlyVanilla(CallbackInfo ci) { + // ElytraFly module removed; no vanilla elytra override remains. } @Shadow @@ -362,7 +328,7 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { shift = At.Shift.AFTER ) ) - private void combatant$afterInputTickSprint(CallbackInfo ci) { + private void lovisual$afterInputTickSprint(CallbackInfo ci) { if (this.input == null) return; Input original = this.input.keyPresses; @@ -375,19 +341,19 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { Events.BUS.post(event); Input eventInput = event.toPlayerInput(); - if (!combatant$sameInput(input, eventInput)) { + if (!lovisual$sameInput(input, eventInput)) { input = eventInput; } } - Input transformedInput = combatant$transformDirection(input); - if (!combatant$sameInput(input, transformedInput)) { + Input transformedInput = lovisual$transformDirection(input); + if (!lovisual$sameInput(input, transformedInput)) { input = transformedInput; } if (Events.BUS.hasListeners(SprintControlEvent.class)) { - float forward = combatant$impulse(input.forward(), input.backward()); - float sideways = combatant$impulse(input.left(), input.right()); + float forward = lovisual$impulse(input.forward(), input.backward()); + float sideways = lovisual$impulse(input.left(), input.right()); SprintControlEvent event = new SprintControlEvent( forward, @@ -410,13 +376,13 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { } } - if (!combatant$sameInput(original, input)) { - combatant$applyPlayerInput(input); + if (!lovisual$sameInput(original, input)) { + lovisual$applyPlayerInput(input); } } @Unique - private void combatant$applyPlayerInput(Input input) { + private void lovisual$applyPlayerInput(Input input) { if (this.input == null || input == null) { return; } @@ -424,14 +390,14 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { InputAccessor accessor = (InputAccessor) this.input; accessor.setPlayerInput(input); - float forward = combatant$impulse(input.forward(), input.backward()); - float sideways = combatant$impulse(input.left(), input.right()); + float forward = lovisual$impulse(input.forward(), input.backward()); + float sideways = lovisual$impulse(input.left(), input.right()); accessor.setMovementVector(new Vec2(sideways, forward).normalized()); } @Unique - private Input combatant$transformDirection(Input input) { + private Input lovisual$transformDirection(Input input) { // Free correction now runs at KeyboardInput.tick(), matching the input pipeline. // Keep this post-input hook inert to avoid double-transforming movement input. return input; @@ -490,38 +456,36 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { @Unique private boolean shouldFreezeNow() { - boolean freezeModule = Modules.enabled(Freeze.class); Freecam freecam = Modules.get(Freecam.class); - boolean freecamFreeze = freecam != null && freecam.freezePlayer() && freecam.isCameraInput(); - return freezeModule || freecamFreeze; + return freecam != null && freecam.freezePlayer() && freecam.isCameraInput(); } @Inject(method = "sendPosition", at = @At("HEAD"), cancellable = true) - private void combatant$eventSync(CallbackInfo ci) { + private void lovisual$eventSync(CallbackInfo ci) { if (!Events.BUS.hasListeners(EventSync.class)) return; - combatant$eventPostAction = null; + lovisual$eventPostAction = null; LocalPlayer self = (LocalPlayer) (Object) this; EventSync event = new EventSync(self.getYRot(), self.getXRot()); Events.BUS.post(event); - combatant$activeSyncEvent = event; - combatant$eventPostAction = event.getPostAction(); + lovisual$activeSyncEvent = event; + lovisual$eventPostAction = event.getPostAction(); if (event.isCancelled()) { - combatant$activeSyncEvent = null; - combatant$eventPostAction = null; + lovisual$activeSyncEvent = null; + lovisual$eventPostAction = null; ci.cancel(); } } @Inject(method = "sendPosition", at = @At("RETURN")) - private void combatant$eventPostSync(CallbackInfo ci) { + private void lovisual$eventPostSync(CallbackInfo ci) { if (Events.BUS.hasListeners(EventPostSync.class)) { Events.BUS.post(new EventPostSync()); } - if (combatant$eventPostAction != null) { - combatant$eventPostAction.run(); - combatant$eventPostAction = null; + if (lovisual$eventPostAction != null) { + lovisual$eventPostAction.run(); + lovisual$eventPostAction = null; } - combatant$activeSyncEvent = null; + lovisual$activeSyncEvent = null; } @ModifyExpressionValue( @@ -531,10 +495,10 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { target = "Lnet/minecraft/client/player/LocalPlayer;getYRot()F" ) ) - private float combatant$eventSyncYaw(float original) { - combatant$updateVisualBodyYaw(); + private float lovisual$eventSyncYaw(float original) { + lovisual$updateVisualBodyYaw(); - EventSync event = combatant$activeSyncEvent; + EventSync event = lovisual$activeSyncEvent; if (event != null && event.hasRotationOverride()) return event.getYaw(); Rotation rotation = RotationManager.INSTANCE.getCurrentRotation(); @@ -548,8 +512,8 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { target = "Lnet/minecraft/client/player/LocalPlayer;getXRot()F" ) ) - private float combatant$eventSyncPitch(float original) { - EventSync event = combatant$activeSyncEvent; + private float lovisual$eventSyncPitch(float original) { + EventSync event = lovisual$activeSyncEvent; if (event != null && event.hasRotationOverride()) return Mth.clamp(event.getPitch(), -90.0f, 90.0f); Rotation rotation = RotationManager.INSTANCE.getCurrentRotation(); @@ -563,8 +527,8 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { target = "Lnet/minecraft/client/player/LocalPlayer;getYRot()F" ) ) - private float combatant$visualTickYaw(float original) { - combatant$updateVisualBodyYaw(); + private float lovisual$visualTickYaw(float original) { + lovisual$updateVisualBodyYaw(); Rotation rotation = RotationManager.INSTANCE.getCurrentRotation(); return rotation != null ? rotation.yaw() : original; @@ -577,7 +541,7 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { target = "Lnet/minecraft/client/player/LocalPlayer;getXRot()F" ) ) - private float combatant$visualTickPitch(float original) { + private float lovisual$visualTickPitch(float original) { Rotation rotation = RotationManager.INSTANCE.getCurrentRotation(); return rotation != null ? Mth.clamp(rotation.pitch(), -90.0f, 90.0f) : original; } @@ -592,9 +556,9 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { ), cancellable = true ) - private void combatant$postPlayerUpdate(CallbackInfo ci) { + private void lovisual$postPlayerUpdate(CallbackInfo ci) { if (!Events.BUS.hasListeners(PostPlayerUpdateEvent.class)) return; - if (combatant$postUpdateLock) return; + if (lovisual$postUpdateLock) return; PostPlayerUpdateEvent event = new PostPlayerUpdateEvent(); Events.BUS.post(event); @@ -608,22 +572,20 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { LocalPlayer self = (LocalPlayer) (Object) this; for (int i = 0; i < iterations; i++) { - combatant$postUpdateLock = true; + lovisual$postUpdateLock = true; self.tick(); - combatant$postUpdateLock = false; + lovisual$postUpdateLock = false; sendPosition(); } } @Inject(method = "sendPosition", at = @At("HEAD"), cancellable = true) private void cancelPackets(CallbackInfo ci) { - if (Modules.enabled(Freeze.class)) { - ci.cancel(); - } + // Freeze module removed; only Freecam may still freeze movement. } @Inject(method = "aiStep", at = @At("HEAD"), cancellable = true) - private void combatant$freezeTickMovement(CallbackInfo ci) { + private void lovisual$freezeTickMovement(CallbackInfo ci) { LocalPlayer p = (LocalPlayer) (Object) this; if (!shouldFreezeNow()) { @@ -659,241 +621,74 @@ public abstract class LocalPlayerMixin implements ILocalPlayer { } @Inject(method = "aiStep", at = @At("HEAD")) - private void combatant$noStunTickMovement(CallbackInfo ci) { - NoStun ns = Modules.get(NoStun.class); - if (ns == null || !ns.isEnabled()) return; - - Freecam fc = Modules.get(Freecam.class); - if (fc != null && fc.isEnabled() && fc.isCameraInput()) { - return; - } - - LocalPlayer player = (LocalPlayer) (Object) this; - if (ns.isFunctionEnabled(NoStun.fnNoHurtStun())) { - if (player.hurtTime == 0) { - lastInput = player.input.keyPresses; - } else if (lastInput != null) { - player.input.keyPresses = lastInput; - } - } - + private void lovisual$noStunTickMovement(CallbackInfo ci) { + // NoStun module removed; no hurt-time input override remains. } @Unique - private void combatant$updateVisualBodyYaw() { + private void lovisual$updateVisualBodyYaw() { LocalPlayer self = (LocalPlayer) (Object) this; Rotation rotation = RotationManager.INSTANCE.getCurrentRotation(); if (rotation == null) { - combatant$rotationPrevX = self.getX(); - combatant$rotationPrevZ = self.getZ(); - combatant$rotationPrevBodyYaw = self.getVisualRotationYInDegrees(); + lovisual$rotationPrevX = self.getX(); + lovisual$rotationPrevZ = self.getZ(); + lovisual$rotationPrevBodyYaw = self.getVisualRotationYInDegrees(); return; } - float newBodyYaw = combatant$simulateBodyYaw( + float newBodyYaw = lovisual$simulateBodyYaw( rotation.yaw(), - combatant$rotationPrevBodyYaw, - combatant$rotationPrevX, - combatant$rotationPrevZ, + lovisual$rotationPrevBodyYaw, + lovisual$rotationPrevX, + lovisual$rotationPrevZ, self.getX(), self.getZ(), self.attackAnim ); self.setYBodyRot(newBodyYaw); - combatant$rotationPrevBodyYaw = newBodyYaw; - combatant$rotationPrevX = self.getX(); - combatant$rotationPrevZ = self.getZ(); + lovisual$rotationPrevBodyYaw = newBodyYaw; + lovisual$rotationPrevX = self.getX(); + lovisual$rotationPrevZ = self.getZ(); } @Inject(method = "tick", at = @At("HEAD")) private void detectPearlImpact(CallbackInfo ci) { - NoPush noPush = Modules.get(NoPush.class); - if (noPush == null || !noPush.off("pearl_phase")) - return; - - LocalPlayer p = (LocalPlayer) (Object) this; - - List pearls = new ArrayList<>(); - p.level().getEntities( - EntityTypeTest.forClass(ThrownEnderpearl.class), - p.getBoundingBox().inflate(1.5), - e -> true, - pearls - ); - - // перл соприкасается → сейчас будет телепорт → готовим спуф - if (!pearls.isEmpty()) { - pendingSpoof = true; - } + // NoPush module removed; no pearl-phase spoofing remains. } @Inject(method = "sendPosition", at = @At("HEAD")) private void sendSpoofAfterPearl(CallbackInfo ci) { - NoPush noPush = Modules.get(NoPush.class); - if (noPush == null || !noPush.off("pearl_phase")) - return; - - if (!pendingSpoof) return; - LocalPlayer p = (LocalPlayer) (Object) this; - // Avoid spoof when we only bonk a ceiling (causes freezes while looking up). - if (p.verticalCollision && !p.horizontalCollision) { - pendingSpoof = false; - return; - } - pendingSpoof = false; - - Vec3 pos = p.position(); - - p.connection.send(new ServerboundMovePlayerPacket.Pos( - pos.x, - pos.y + 0.0313, // легитная фаза - pos.z, - p.onGround(), - false // horizontalCollision - )); + // NoPush module removed; no pearl-phase spoofing remains. } @Inject(method = "aiStep", at = @At("TAIL")) private void onCollideBoost(CallbackInfo ci) { - - Speed speed = Modules.get(Speed.class); - if (speed == null || !speed.enabled("entity_boost")) - return; - - LocalPlayer p = (LocalPlayer) (Object) this; - - if (boostTicks > 0) { - boostTicks--; - - Vec3 vel = p.getDeltaMovement(); - double vx = vel.x + boostX; - double vz = vel.z + boostZ; - - double max = 0.48; - double h = Math.hypot(vx, vz); - if (h > max) { - double s = max / h; - vx *= s; - vz *= s; - } - - p.setDeltaMovement(vx, vel.y, vz); - return; - } - - List nearby = p.level().getEntities(p, p.getBoundingBox().inflate(0.15), e -> e instanceof LivingEntity); - if (nearby.isEmpty()) return; - - Vec3 vel = p.getDeltaMovement(); - double dirX = vel.x; - double dirZ = vel.z; - - if (dirX == 0 && dirZ == 0) return; - - double len = Math.sqrt(dirX * dirX + dirZ * dirZ); - if (len < 1e-5) return; - - dirX /= len; - dirZ /= len; - - double boost = speed.entityBoostStrength.get(); - - boostX = (dirX * boost) / 3.0; - boostZ = (dirZ * boost) / 3.0; - boostTicks = 3; + // Speed module removed; no entity-collision boost remains. } @Inject(method = "aiStep", at = @At("TAIL")) private void omniLongJump(CallbackInfo ci) { - Speed speed = Modules.get(Speed.class); - if (speed == null || !speed.enabled("jump_boost")) return; - LocalPlayer p = (LocalPlayer) (Object) this; - - boolean onGround = p.onGround(); - - if (p.isFallFlying()) { - wasGround = onGround; - return; - } - - if (wasGround && !onGround && p.isSprinting() && !p.isInWater()) { - - Vec2 move = p.input.getMoveVector(); - float mx = move.x; - float mz = move.y; - - if (mx == 0 && mz == 0) { - wasGround = onGround; - return; - } - - float norm = Mth.sqrt(mx * mx + mz * mz); - mx /= norm; - mz /= norm; - - float yaw = p.getYRot(); - float rad = (float) Math.toRadians(yaw); - - double dirX = mz * -Mth.sin(rad) + mx * Mth.cos(rad); - double dirZ = mz * Mth.cos(rad) + mx * Mth.sin(rad); - - Vec3 vel = p.getDeltaMovement(); - double ui = speed.jumpAcceleration.get(); - double internal = ui * 0.832; - double strength = 0.33 * internal; - - double vx = dirX * strength; - double vz = dirZ * strength; - double max = 0.42; - double h = Math.hypot(vx, vz); - - if (h > max) { - double scale = max / h; - vx *= scale; - vz *= scale; - } - - p.setDeltaMovement(vx, vel.y, vz); - } - - wasGround = onGround; + // Speed module removed; no jump boost remains. } @Inject(method = "modifyInput", at = @At("RETURN"), cancellable = true) private void applyLegitSpeed(Vec2 input, CallbackInfoReturnable cir) { - Speed speed = Modules.get(Speed.class); - if (speed == null || !speed.isEnabled()) return; - if (!speed.enabled("legit_speed")) return; - Vec2 base = cir.getReturnValue(); - float mult = speed.legitMultiplier.get(); - cir.setReturnValue(base.scale(mult)); + // Speed module removed; no input speed multiplier remains. } @Inject(method = "closeContainer", at = @At("HEAD"), cancellable = true) - private void combatant$inventoryMove$deferCloseHandledScreen(CallbackInfo ci) { - InventoryMove module = Modules.get(InventoryMove.class); - if (module == null || !module.isEnabled()) return; - if (module.shouldCancelCloseHandledScreen()) { - ci.cancel(); - } + private void lovisual$inventoryMove$deferCloseHandledScreen(CallbackInfo ci) { + // InventoryMove module removed; no container close deferral remains. } @Inject(method = "closeContainer", at = @At("HEAD"), cancellable = true) - private void combatant$keepInventoryOpen(CallbackInfo ci) { - if (!Modules.enabled(XCarry.class)) return; - - // Cancel only when closing own inventory screen (PlayerScreenHandler) to retain crafting/cursor items - var screen = ClientScreen.current(net.minecraft.client.Minecraft.getInstance()); - if (screen instanceof net.minecraft.client.gui.screens.inventory.AbstractContainerScreen handled - && handled.getMenu() instanceof InventoryMenu) { - ((LocalPlayer) (Object) this).clientSideCloseContainer(); // client-side close without sending packet - ci.cancel(); // skip packet CloseHandledScreen - } + private void lovisual$keepInventoryOpen(CallbackInfo ci) { + // XCarry module removed; no inventory close suppression remains. } @Inject(method = "moveTowardsClosestSpace", at = @At("HEAD"), cancellable = true) - private void combatant$noPushOutOfBlocks(double x, double z, CallbackInfo ci) { + private void lovisual$noPushOutOfBlocks(double x, double z, CallbackInfo ci) { if (!Events.BUS.hasListeners(EventPushOutOfBlocks.class)) return; EventPushOutOfBlocks event = new EventPushOutOfBlocks(x, z); Events.BUS.post(event); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LocatorBarMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LocatorBarMixin.java index 96e9841..5caf526 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LocatorBarMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/LocatorBarMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,14 +16,14 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.loki.lovisual.features.gui.hud.nondraggable.impl.CustomBar; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; @Mixin(LocatorBar.class) public abstract class LocatorBarMixin { @Inject(method = "extractBackground", at = @At("HEAD"), cancellable = true) - private void combatant$renderLocatorBar(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + private void lovisual$renderLocatorBar(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { + if (!Lifecycle.canRunHud()) return; Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; @@ -36,8 +36,8 @@ public abstract class LocatorBarMixin { } @Inject(method = "extractRenderState", at = @At("HEAD"), cancellable = true) - private void combatant$renderLocatorAddons(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { - if (!RuntimeGate.canRunHud()) return; + private void lovisual$renderLocatorAddons(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) { + if (!Lifecycle.canRunHud()) return; Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.player == null) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MinecraftMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MinecraftMixin.java index 7ed736b..41677d8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MinecraftMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MinecraftMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -37,8 +37,6 @@ import dev.loki.lovisual.events.impl.CrosshairTargetUpdateEvent; import dev.loki.lovisual.features.gui.chat.BetterChatStoreManager; import dev.loki.lovisual.features.module.ModuleManager; import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.*; -import dev.loki.lovisual.features.module.modules.movement.Timer; import dev.loki.lovisual.features.module.modules.player.NoDelay; import dev.loki.lovisual.features.module.modules.player.NoInteract; import dev.loki.lovisual.features.module.modules.visuals.Freecam; @@ -56,20 +54,20 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { private GpuSurface windowSurface; @Unique - private GameConfig combatant$gameConfig; + private GameConfig lovisual$gameConfig; @Inject(method = "", at = @At("RETURN")) - private void combatant$captureGameConfig(GameConfig config, CallbackInfo ci) { - this.combatant$gameConfig = config; + private void lovisual$captureGameConfig(GameConfig config, CallbackInfo ci) { + this.lovisual$gameConfig = config; } @Override - public GameConfig combatant$getGameConfig() { - return combatant$gameConfig; + public GameConfig lovisual$getGameConfig() { + return lovisual$gameConfig; } @Unique - private static BlockHitResult combatant$miss(Vec3 pos) { + private static BlockHitResult lovisual$miss(Vec3 pos) { return new BlockHitResult( pos, Direction.UP, @@ -79,7 +77,7 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { } @Unique - private static void combatant$guardSingleplayerSaveWithAltUsername() { + private static void lovisual$guardSingleplayerSaveWithAltUsername() { SessionChanger.restoreSingleplayerJoinSessionForDisconnect(); } @@ -88,12 +86,6 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { NoDelay noDelay = Modules.get(NoDelay.class); if (noDelay != null && noDelay.handleFastUse()) { ci.cancel(); - return; - } - - AutoBow autoBow = Modules.get(AutoBow.class); - if (autoBow != null && autoBow.shouldCancelVanillaDoItemUse()) { - ci.cancel(); } } @@ -120,16 +112,8 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { } } - @Inject(method = "handleKeybinds", at = @At("TAIL")) - private void combatant$autobow$finishInputCycle(CallbackInfo ci) { - AutoBow autoBow = Modules.get(AutoBow.class); - if (autoBow != null && autoBow.isEnabled()) { - autoBow.onInputCycleHandled(); - } - } - @Inject(method = "shouldEntityAppearGlowing", at = @At("HEAD"), cancellable = true) - private void combatant$disablePvpGlow(Entity entity, CallbackInfoReturnable cir) { + private void lovisual$disablePvpGlow(Entity entity, CallbackInfoReturnable cir) { if (!(entity instanceof Player)) return; PvpCooldowns mod = Modules.get(PvpCooldowns.class); if (mod == null || !mod.shouldHideTargetGlow()) return; @@ -141,56 +125,17 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { @Inject(method = "continueAttack", at = @At("HEAD"), cancellable = true) private void onHandleBlockBreaking(boolean breaking, CallbackInfo ci) { - Minecraft client = Minecraft.getInstance(); - LocalPlayer player = client.player; - if (player == null) return; - - // Hitbox должен работать даже при ломании блоков: не блокируем vanilla логику - Hitbox hitbox = Modules.get(Hitbox.class); - if (hitbox != null && hitbox.isEnabled()) { - return; - } - - boolean attackKeyPressed = client.options.keyAttack.isDown(); - - AutoAttack autoAttack = Modules.get(AutoAttack.class); - boolean blockByAutoAttack = autoAttack != null - && autoAttack.isEnabled() - && !autoAttack.isAutoMode() - && autoAttack.shouldBlockBreaking(); - boolean shouldBlockBreaking = blockByAutoAttack; - - if (shouldBlockBreaking && attackKeyPressed) { - - // блокируем ломание - ci.cancel(); - - if (client.gameMode != null) - client.gameMode.stopDestroyBlock(); - - // имитация удара - } + // AutoAttack / Hitbox modules removed; no block-breaking override remains. } @Inject(method = "startAttack", at = @At("HEAD"), cancellable = true) private void onDoAttack(CallbackInfoReturnable cir) { - AttributeSwap attributeSwap = Modules.get(AttributeSwap.class); - if (attributeSwap != null && attributeSwap.isEnabled() && attributeSwap.handleManualAttack()) { - cir.setReturnValue(true); - cir.cancel(); - return; - } - - AutoAttack autoAttack = Modules.get(AutoAttack.class); - if (autoAttack != null && autoAttack.isEnabled()) { - cir.setReturnValue(false); - cir.cancel(); - } + // AttributeSwap / AutoAttack modules removed; no attack override remains. } @Inject(method = "disconnect(Lnet/minecraft/client/gui/screens/Screen;ZZ)V", at = @At("HEAD")) - private void combatant$betterChat$saveOnDisconnect(net.minecraft.client.gui.screens.Screen screen, boolean transferring, boolean bl, CallbackInfo ci) { - combatant$guardSingleplayerSaveWithAltUsername(); + private void lovisual$betterChat$saveOnDisconnect(net.minecraft.client.gui.screens.Screen screen, boolean transferring, boolean bl, CallbackInfo ci) { + lovisual$guardSingleplayerSaveWithAltUsername(); try { BetterChatStoreManager.flushAll(); } catch (Throwable ignored) { @@ -198,7 +143,7 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { } @Inject(method = "disconnect(Lnet/minecraft/client/gui/screens/Screen;ZZ)V", at = @At("TAIL")) - private void combatant$sessionRestoreAfterDisconnect(net.minecraft.client.gui.screens.Screen screen, boolean transferring, boolean bl, CallbackInfo ci) { + private void lovisual$sessionRestoreAfterDisconnect(net.minecraft.client.gui.screens.Screen screen, boolean transferring, boolean bl, CallbackInfo ci) { SessionChanger.restoreDeferredSessionAfterDisconnect(); } @@ -234,7 +179,7 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { // FREECAM + NO INTERACT // =============================== if (!fc.allowInteract()) { - mc.hitResult = combatant$miss(start); + mc.hitResult = lovisual$miss(start); mc.crosshairPickEntity = null; ci.cancel(); return; @@ -288,7 +233,7 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { } @Inject(method = "pick", at = @At("RETURN")) - private void combatant$dispatchCrosshairTargetEvent(float tickDelta, CallbackInfo ci) { + private void lovisual$dispatchCrosshairTargetEvent(float tickDelta, CallbackInfo ci) { Minecraft mc = Minecraft.getInstance(); if (mc.player == null || mc.level == null) return; @@ -340,7 +285,7 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { } @Inject(method = "setLevel", at = @At("TAIL")) - private void combatant$captureSingleplayerJoinSession(ClientLevel world, CallbackInfo ci) { + private void lovisual$captureSingleplayerJoinSession(ClientLevel world, CallbackInfo ci) { if (world == null) { SessionChanger.clearSingleplayerJoinSession(); } else { @@ -349,7 +294,7 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { } @Inject(method = "clearDownloadedResourcePacks", at = @At("HEAD")) - private void combatant$onDisconnected(CallbackInfo ci) { + private void lovisual$onDisconnected(CallbackInfo ci) { StaffTracker.resetAll(); AntiBotTracker.INSTANCE.reset(); } @@ -362,7 +307,7 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { shift = At.Shift.AFTER ) ) - private void combatant$frameModulesAfterRenderTick(boolean tick, CallbackInfo ci) { + private void lovisual$frameModulesAfterRenderTick(boolean tick, CallbackInfo ci) { ModuleManager.frameAll(TickDelta.frameDeltaTicks()); } @@ -375,7 +320,7 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { shift = At.Shift.AFTER ) ) - private void combatant$paceImmediateNoVsync(boolean tick, CallbackInfo ci) { + private void lovisual$paceImmediateNoVsync(boolean tick, CallbackInfo ci) { Minecraft mc = (Minecraft) (Object) this; if (mc == null || mc.options == null || mc.getWindow() == null || windowSurface == null) { return; @@ -394,27 +339,23 @@ public class MinecraftMixin implements MinecraftGameConfigHolder { } int refreshRate = mc.getWindow().getRefreshRate(); - int targetFps = combatant$immediatePacingTarget(refreshRate); + int targetFps = lovisual$immediatePacingTarget(refreshRate); FramerateLimiter.limitDisplayFPS(targetFps); } @Unique - private static int combatant$immediatePacingTarget(int refreshRate) { + private static int lovisual$immediatePacingTarget(int refreshRate) { int base = refreshRate > 0 ? refreshRate : 120; return Mth.clamp(base * 2, 120, 360); } @Inject(method = "getTickTargetMillis", at = @At("RETURN"), cancellable = true) - private void combatant$applyTimer(float millis, CallbackInfoReturnable cir) { - float mult = Timer.getTickTimer(); - if (mult <= 0.0001f) return; - if (Math.abs(mult - 1.0f) < 0.0001f) return; - float base = cir.getReturnValue(); - cir.setReturnValue(base / mult); + private void lovisual$applyTimer(float millis, CallbackInfoReturnable cir) { + // Timer module removed; tick speed remains unchanged. } @Inject(method = "isLevelRunningNormally", at = @At("HEAD"), cancellable = true) - private void combatant$skipPlayerDependentTicksWithoutPlayer(CallbackInfoReturnable cir) { + private void lovisual$skipPlayerDependentTicksWithoutPlayer(CallbackInfoReturnable cir) { Minecraft mc = Minecraft.getInstance(); if (mc.level != null && mc.player == null) { cir.setReturnValue(false); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MouseMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MouseMixin.java index 0aa669c..99da3d2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MouseMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MouseMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -33,7 +33,7 @@ import dev.loki.lovisual.features.module.ModuleManager; import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.features.module.modules.visuals.Freecam; import dev.loki.lovisual.features.module.modules.visuals.Zoom; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import dev.loki.lovisual.util.input.KeyManager; import dev.loki.lovisual.util.logging.DebugLog; @@ -46,19 +46,19 @@ public class MouseMixin { @Unique private double lastY; @Unique - private static final float COMBATANT_PROXY_BUTTON_X = 8f; + private static final float LOVISUAL_PROXY_BUTTON_X = 8f; @Unique - private static final float COMBATANT_PROXY_BUTTON_Y = 8f; + private static final float LOVISUAL_PROXY_BUTTON_Y = 8f; @Unique - private static final float COMBATANT_PROXY_BUTTON_W = 24f; + private static final float LOVISUAL_PROXY_BUTTON_W = 24f; @Unique - private static final float COMBATANT_PROXY_BUTTON_H = 24f; + private static final float LOVISUAL_PROXY_BUTTON_H = 24f; // ===== Mouse scroll for ClickGUI ===== @Inject(method = "onScroll", at = @At("HEAD"), cancellable = true) public void onMouseScroll(long window, double horizontal, double vertical, CallbackInfo ci) { Minecraft mc = Minecraft.getInstance(); - if (RuntimeGate.canRunClientLogic() + if (Lifecycle.isActive() && ModuleManager.isEnabled("clickgui") && !(ClientScreen.current() instanceof ClickGuiScreen || ClientScreen.current() instanceof ClickGuiPickerScreen @@ -67,7 +67,7 @@ public class MouseMixin { ci.cancel(); return; } - if (RuntimeGate.canRunHud() + if (Lifecycle.canRunHud() && ClientScreen.current(net.minecraft.client.Minecraft.getInstance()) instanceof net.minecraft.client.gui.screens.ChatScreen) { if (BetterChatRenderer.onScroll(vertical)) { ci.cancel(); @@ -80,14 +80,14 @@ public class MouseMixin { KeyManager.handleMouseButtonEvent(input.button(), action); net.minecraft.client.Minecraft mc = net.minecraft.client.Minecraft.getInstance(); - if (RuntimeGate.canRunHud() && mc != null) { + if (Lifecycle.canRunHud() && mc != null) { boolean pressed = action == 1; int button = input.button(); if (pressed && button == 0 && ClientScreen.current() instanceof JoinMultiplayerScreen screen) { double scale = Math.max(1.0, mc.getWindow().getGuiScale()); float mx = (float) (mc.mouseHandler.xpos() / scale); float my = (float) (mc.mouseHandler.ypos() / scale); - if (combatant$proxyButtonHit(mx, my)) { + if (lovisual$proxyButtonHit(mx, my)) { ClientScreen.show(mc, new LoVisualProxyManagerScreen(screen)); ci.cancel(); return; @@ -110,18 +110,18 @@ public class MouseMixin { } @Unique - private static boolean combatant$proxyButtonHit(float mx, float my) { - return mx >= COMBATANT_PROXY_BUTTON_X - && mx <= COMBATANT_PROXY_BUTTON_X + COMBATANT_PROXY_BUTTON_W - && my >= COMBATANT_PROXY_BUTTON_Y - && my <= COMBATANT_PROXY_BUTTON_Y + COMBATANT_PROXY_BUTTON_H; + private static boolean lovisual$proxyButtonHit(float mx, float my) { + return mx >= LOVISUAL_PROXY_BUTTON_X + && mx <= LOVISUAL_PROXY_BUTTON_X + LOVISUAL_PROXY_BUTTON_W + && my >= LOVISUAL_PROXY_BUTTON_Y + && my <= LOVISUAL_PROXY_BUTTON_Y + LOVISUAL_PROXY_BUTTON_H; } // ===== Mouse button for ClickGUI ===== @Inject(method = "onButton", at = @At("HEAD"), cancellable = true) private void clickGuiMouseButton(long window, MouseButtonInfo input, int action, CallbackInfo ci) { Minecraft mc = Minecraft.getInstance(); - if (RuntimeGate.canRunClientLogic() + if (Lifecycle.isActive() && ModuleManager.isEnabled("clickgui") && !(ClientScreen.current() instanceof ClickGuiScreen || ClientScreen.current() instanceof ClickGuiPickerScreen @@ -152,7 +152,7 @@ public class MouseMixin { lastX = x; lastY = y; - if (RuntimeGate.canRunClientLogic() + if (Lifecycle.isActive() && ModuleManager.isEnabled("clickgui") && !(ClientScreen.current() instanceof ClickGuiScreen || ClientScreen.current() instanceof ClickGuiPickerScreen @@ -162,7 +162,7 @@ public class MouseMixin { return; } - if (RuntimeGate.canRunHud() + if (Lifecycle.canRunHud() && ClientScreen.current() instanceof net.minecraft.client.gui.screens.ChatScreen) { BetterChatRenderer.onMouseMove(x, y); } @@ -178,7 +178,7 @@ public class MouseMixin { private void freecam$look(LocalPlayer player, double dx, double dy) { Freecam fc = Modules.get(Freecam.class); - if (!RuntimeGate.canRunClientLogic() || fc == null || !fc.isEnabled()) { + if (!Lifecycle.isActive() || fc == null || !fc.isEnabled()) { player.turn(dx, dy); return; } @@ -211,9 +211,9 @@ public class MouseMixin { ordinal = 0 ) ) - private Object combatant$zoomSensitivity(Object original) { + private Object lovisual$zoomSensitivity(Object original) { Zoom zoom = Modules.get(Zoom.class); - if (!RuntimeGate.canRunClientLogic() || zoom == null || !zoom.isEnabled() || !zoom.shouldApplyZoom()) + if (!Lifecycle.isActive() || zoom == null || !zoom.isEnabled() || !zoom.shouldApplyZoom()) return original; if (!(original instanceof Double originalValue)) return original; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MultiPlayerGameModeMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MultiPlayerGameModeMixin.java index 77e9683..60d9207 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MultiPlayerGameModeMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/MultiPlayerGameModeMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -30,9 +30,6 @@ import dev.loki.lovisual.events.impl.AttackEntityEvent; import dev.loki.lovisual.events.impl.EventBreakBlock; import dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud; import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.AttributeSwap; -import dev.loki.lovisual.features.module.modules.combat.Criticals; -import dev.loki.lovisual.features.module.modules.combat.Hitbox; import dev.loki.lovisual.features.module.modules.combat.PvpCooldowns; import dev.loki.lovisual.features.module.modules.misc.HitSounds; import dev.loki.lovisual.features.module.modules.visuals.Freecam; @@ -45,14 +42,14 @@ import dev.loki.lovisual.util.target.TargetManager; public class MultiPlayerGameModeMixin { @Inject(method = "tick", at = @At("HEAD"), cancellable = true) - private void combatant$skipTickWithoutPlayer(CallbackInfo ci) { + private void lovisual$skipTickWithoutPlayer(CallbackInfo ci) { if (Minecraft.getInstance().player == null) { ci.cancel(); } } @Inject(method = "ensureHasSentCarriedItem", at = @At("HEAD"), cancellable = true) - private void combatant$skipCarriedItemSyncWithoutPlayer(CallbackInfo ci) { + private void lovisual$skipCarriedItemSyncWithoutPlayer(CallbackInfo ci) { if (Minecraft.getInstance().player == null) { ci.cancel(); } @@ -65,12 +62,12 @@ public class MultiPlayerGameModeMixin { target = "Lnet/minecraft/world/entity/player/Inventory;getSelectedSlot()I" ) ) - private int combatant$hookSilentSelectedSlot(int original) { + private int lovisual$hookSilentSelectedSlot(int original) { return InventorySwap.INSTANCE.effectiveSelectedSlot(); } @Inject(method = "destroyBlock", at = @At("RETURN")) - private void combatant$breakBlockEvent(BlockPos pos, CallbackInfoReturnable cir) { + private void lovisual$breakBlockEvent(BlockPos pos, CallbackInfoReturnable cir) { if (!cir.getReturnValue()) return; if (!Events.BUS.hasListeners(EventBreakBlock.class)) return; Events.BUS.post(new EventBreakBlock(pos)); @@ -146,22 +143,12 @@ public class MultiPlayerGameModeMixin { @Inject(method = "attack(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/entity/Entity;)V", at = @At("HEAD")) private void onAttackEntity(Player player, Entity target, CallbackInfo ci) { - if (!((WorldAccessor) player.level()).combatant$isClient()) return; - - if (player instanceof LocalPlayer clientPlayer) { - Criticals criticals = Modules.get(Criticals.class); - if (criticals != null && criticals.isEnabled()) { - criticals.beforeAttack(Minecraft.getInstance(), clientPlayer, target); - } - } + if (!((WorldAccessor) player.level()).lovisual$isClient()) return; if (Events.BUS.hasListeners(AttackEntityEvent.class)) { Events.BUS.post(new AttackEntityEvent(player, target)); } - Hitbox hitbox = Modules.get(Hitbox.class); - if (hitbox != null) hitbox.markHit(target); - HitSounds hitSounds = Modules.get(HitSounds.class); if (hitSounds != null) { hitSounds.handleHit(target); @@ -178,8 +165,7 @@ public class MultiPlayerGameModeMixin { @Inject(method = "attack(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/entity/Entity;)V", at = @At("RETURN")) - private void combatant$attributeSwapAfterClientAttack(Player player, Entity target, CallbackInfo ci) { - if (player != Minecraft.getInstance().player) return; - AttributeSwap.tryBreakShieldAfterClientAttack(target); + private void lovisual$attributeSwapAfterClientAttack(Player player, Entity target, CallbackInfo ci) { + // AttributeSwap module removed; no post-attack shield break remains. } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/NarratorManagerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/NarratorManagerMixin.java index 7d426e8..acef28e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/NarratorManagerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/NarratorManagerMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -29,7 +29,7 @@ public class NarratorManagerMixin { private Minecraft minecraft; @Inject(method = "sayChatQueued(Lnet/minecraft/network/chat/Component;)V", at = @At("HEAD"), cancellable = true) - private void combatant$muteChat(Component message, CallbackInfo ci) { + private void lovisual$muteChat(Component message, CallbackInfo ci) { if (shouldMute()) { NarratorBlocker.enforce(this.minecraft); ci.cancel(); @@ -37,7 +37,7 @@ public class NarratorManagerMixin { } @Inject(method = "saySystemChatQueued(Lnet/minecraft/network/chat/Component;)V", at = @At("HEAD"), cancellable = true) - private void combatant$muteNarrator(Component message, CallbackInfo ci) { + private void lovisual$muteNarrator(Component message, CallbackInfo ci) { if (shouldMute()) { NarratorBlocker.enforce(this.minecraft); ci.cancel(); @@ -45,7 +45,7 @@ public class NarratorManagerMixin { } @Inject(method = "saySystemQueued(Lnet/minecraft/network/chat/Component;)V", at = @At("HEAD"), cancellable = true) - private void combatant$muteSystem(Component message, CallbackInfo ci) { + private void lovisual$muteSystem(Component message, CallbackInfo ci) { if (shouldMute()) { NarratorBlocker.enforce(this.minecraft); ci.cancel(); @@ -53,7 +53,7 @@ public class NarratorManagerMixin { } @Inject(method = "saySystemNow(Lnet/minecraft/network/chat/Component;)V", at = @At("HEAD"), cancellable = true) - private void combatant$muteImmediateText(Component message, CallbackInfo ci) { + private void lovisual$muteImmediateText(Component message, CallbackInfo ci) { if (shouldMute()) { NarratorBlocker.enforce(this.minecraft); ci.cancel(); @@ -61,7 +61,7 @@ public class NarratorManagerMixin { } @Inject(method = "saySystemNow(Ljava/lang/String;)V", at = @At("HEAD"), cancellable = true) - private void combatant$muteImmediateString(String message, CallbackInfo ci) { + private void lovisual$muteImmediateString(String message, CallbackInfo ci) { if (shouldMute()) { NarratorBlocker.enforce(this.minecraft); ci.cancel(); @@ -69,7 +69,7 @@ public class NarratorManagerMixin { } @Inject(method = "narrateMessage(Ljava/lang/String;Z)V", at = @At("HEAD"), cancellable = true) - private void combatant$muteSay(String message, boolean interrupt, CallbackInfo ci) { + private void lovisual$muteSay(String message, boolean interrupt, CallbackInfo ci) { if (shouldMute()) { NarratorBlocker.enforce(this.minecraft); ci.cancel(); @@ -77,21 +77,21 @@ public class NarratorManagerMixin { } @Inject(method = "updateNarratorStatus", at = @At("HEAD"), cancellable = true) - private void combatant$blockToggle(NarratorStatus mode, CallbackInfo ci) { + private void lovisual$blockToggle(NarratorStatus mode, CallbackInfo ci) { if (!shouldMute()) return; NarratorBlocker.enforce(this.minecraft); ci.cancel(); } @Inject(method = "checkStatus", at = @At("HEAD"), cancellable = true) - private void combatant$skipNarratorLibraryCheck(boolean narratorEnabled, CallbackInfo ci) { + private void lovisual$skipNarratorLibraryCheck(boolean narratorEnabled, CallbackInfo ci) { if (!shouldMute()) return; NarratorBlocker.enforce(this.minecraft); ci.cancel(); } @Inject(method = "isActive", at = @At("HEAD"), cancellable = true) - private void combatant$reportInactive(CallbackInfoReturnable cir) { + private void lovisual$reportInactive(CallbackInfoReturnable cir) { if (!shouldMute()) return; cir.setReturnValue(false); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/OptionsNarratorMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/OptionsNarratorMixin.java index bd6f4a5..38bcf92 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/OptionsNarratorMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/OptionsNarratorMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -24,22 +24,22 @@ import java.io.File; public abstract class OptionsNarratorMixin { @Inject(method = "(Lnet/minecraft/client/Minecraft;Ljava/io/File;)V", at = @At("RETURN")) - private void combatant$enforceNarratorDefaults(Minecraft client, File optionsFile, CallbackInfo ci) { + private void lovisual$enforceNarratorDefaults(Minecraft client, File optionsFile, CallbackInfo ci) { NarratorBlocker.enforce((Options) (Object) this); } @Inject(method = "save", at = @At("HEAD")) - private void combatant$enforceNarratorBeforeWrite(CallbackInfo ci) { + private void lovisual$enforceNarratorBeforeWrite(CallbackInfo ci) { NarratorBlocker.enforce((Options) (Object) this); } @Inject(method = "narrator", at = @At("HEAD")) - private void combatant$enforceNarratorGetter(CallbackInfoReturnable> cir) { + private void lovisual$enforceNarratorGetter(CallbackInfoReturnable> cir) { NarratorBlocker.enforce((Options) (Object) this); } @Inject(method = "narratorHotkey", at = @At("HEAD")) - private void combatant$enforceNarratorHotkeyGetter(CallbackInfoReturnable> cir) { + private void lovisual$enforceNarratorHotkeyGetter(CallbackInfoReturnable> cir) { NarratorBlocker.enforce((Options) (Object) this); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ParticleManagerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ParticleManagerMixin.java index 7b7c68d..7d95a80 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ParticleManagerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ParticleManagerMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -19,7 +19,7 @@ import dev.loki.lovisual.util.player.effect.StatusEffectHeuristics; public class ParticleManagerMixin { @Inject(method = "createParticle(Lnet/minecraft/core/particles/ParticleOptions;DDDDDD)Lnet/minecraft/client/particle/Particle;", at = @At("HEAD")) - private void combatant$heuristicParticle(ParticleOptions parameters, double x, double y, double z, double velocityX, double velocityY, double velocityZ, CallbackInfoReturnable cir) { + private void lovisual$heuristicParticle(ParticleOptions parameters, double x, double y, double z, double velocityX, double velocityY, double velocityZ, CallbackInfoReturnable cir) { // dev.loki.lovisual.util.logging.DebugLog.info("ParticleManager add type=%s pos=%.2f %.2f %.2f", parameters.getType().toString(), x, y, z); StatusEffectHeuristics.handle(parameters, x, y, z); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PauseScreenMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PauseScreenMixin.java index 9433645..1ddd055 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PauseScreenMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PauseScreenMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -28,53 +28,53 @@ public abstract class PauseScreenMixin { private Button disconnectButton; @Unique - private Button combatant$lastExitButton; + private Button lovisual$lastExitButton; @Unique - private boolean combatant$disconnectBlocked; + private boolean lovisual$disconnectBlocked; @Unique - private boolean combatant$previousExitActive = true; + private boolean lovisual$previousExitActive = true; @Inject(method = "init", at = @At("TAIL")) - private void combatant$blockDisconnectOnInit(CallbackInfo ci) { - combatant$syncDisconnectButton(); + private void lovisual$blockDisconnectOnInit(CallbackInfo ci) { + lovisual$syncDisconnectButton(); } @Inject(method = "extractRenderState", at = @At("HEAD")) - private void combatant$blockDisconnectOnRender(GuiGraphicsExtractor context, int mouseX, int mouseY, float deltaTicks, CallbackInfo ci) { - combatant$syncDisconnectButton(); + private void lovisual$blockDisconnectOnRender(GuiGraphicsExtractor context, int mouseX, int mouseY, float deltaTicks, CallbackInfo ci) { + lovisual$syncDisconnectButton(); } @Unique - private void combatant$syncDisconnectButton() { + private void lovisual$syncDisconnectButton() { Button button = disconnectButton; if (button == null) { - combatant$lastExitButton = null; - combatant$disconnectBlocked = false; + lovisual$lastExitButton = null; + lovisual$disconnectBlocked = false; return; } - if (button != combatant$lastExitButton) { - combatant$lastExitButton = button; - combatant$disconnectBlocked = false; - combatant$previousExitActive = button.active; + if (button != lovisual$lastExitButton) { + lovisual$lastExitButton = button; + lovisual$disconnectBlocked = false; + lovisual$previousExitActive = button.active; } PvpCooldowns cooldowns = Modules.get(PvpCooldowns.class); boolean shouldBlock = cooldowns != null && cooldowns.shouldBlockDisconnect(); if (shouldBlock) { - if (!combatant$disconnectBlocked) { - combatant$previousExitActive = button.active; + if (!lovisual$disconnectBlocked) { + lovisual$previousExitActive = button.active; } - combatant$disconnectBlocked = true; + lovisual$disconnectBlocked = true; button.active = false; button.setTooltip(Tooltip.create(cooldowns.getDisconnectBlockTooltip())); return; } - if (combatant$disconnectBlocked) { - button.active = combatant$previousExitActive; + if (lovisual$disconnectBlocked) { + button.active = lovisual$previousExitActive; button.setTooltip(null); - combatant$disconnectBlocked = false; + lovisual$disconnectBlocked = false; } } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerEntityMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerEntityMixin.java index 6bb8e45..8fa85d1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerEntityMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerEntityMixin.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -39,8 +39,6 @@ import dev.loki.lovisual.events.impl.PlayerSafeWalkEvent; import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.features.module.modules.player.NoDelay; import dev.loki.lovisual.features.module.modules.combat.TPSSync; -import dev.loki.lovisual.features.module.modules.movement.NoStun; -import dev.loki.lovisual.features.module.modules.movement.Timer; import dev.loki.lovisual.mixininterface.IPlayerAttackCooldown; import dev.loki.lovisual.util.aiming.RotationManager; @@ -52,7 +50,7 @@ public abstract class PlayerEntityMixin implements IPlayerAttackCooldown { private ItemCooldowns cooldowns; @Inject(method = "isStayingOnGroundSurface", at = @At("RETURN"), cancellable = true) - private void combatant$safeWalk(CallbackInfoReturnable cir) { + private void lovisual$safeWalk(CallbackInfoReturnable cir) { if (cir.getReturnValue()) return; if ((Object) this != Minecraft.getInstance().player) return; if (!Events.BUS.hasListeners(PlayerSafeWalkEvent.class)) return; @@ -65,11 +63,8 @@ public abstract class PlayerEntityMixin implements IPlayerAttackCooldown { } @Inject(method = "isMobilityRestricted", at = @At("HEAD"), cancellable = true) - private void combatant$noStunBlindnessSprint(CallbackInfoReturnable cir) { - NoStun noStun = Modules.get(NoStun.class); - if (noStun != null && noStun.shouldIgnoreBlindness((Player) (Object) this)) { - cir.setReturnValue(false); - } + private void lovisual$noStunBlindnessSprint(CallbackInfoReturnable cir) { + // NoStun module removed; no mobility override remains. } @ModifyExpressionValue( @@ -79,7 +74,7 @@ public abstract class PlayerEntityMixin implements IPlayerAttackCooldown { target = "Lnet/minecraft/world/entity/player/Player;getYRot()F" ) ) - private float combatant$fixKnockbackYaw(float original) { + private float lovisual$fixKnockbackYaw(float original) { if ((Object) this != Minecraft.getInstance().player) { return original; } @@ -93,7 +88,7 @@ public abstract class PlayerEntityMixin implements IPlayerAttackCooldown { target = "Lnet/minecraft/world/entity/player/Player;getYRot()F" ) ) - private float combatant$fixSweepYaw(float original) { + private float lovisual$fixSweepYaw(float original) { if ((Object) this != Minecraft.getInstance().player) { return original; } @@ -107,7 +102,7 @@ public abstract class PlayerEntityMixin implements IPlayerAttackCooldown { target = "Lnet/minecraft/world/entity/player/Player;getLookAngle()Lnet/minecraft/world/phys/Vec3;" ) ) - private Vec3 combatant$fixTravelRotationVector(Vec3 original) { + private Vec3 lovisual$fixTravelRotationVector(Vec3 original) { if ((Object) this != Minecraft.getInstance().player) { return original; } @@ -131,7 +126,7 @@ public abstract class PlayerEntityMixin implements IPlayerAttackCooldown { method = "getCurrentItemAttackStrengthDelay", at = @At("RETURN") ) - private float combatant$tpsSyncAttackCooldown(float original) { + private float lovisual$tpsSyncAttackCooldown(float original) { float result = original; TPSSync tpsSync = Modules.get(TPSSync.class); @@ -143,22 +138,17 @@ public abstract class PlayerEntityMixin implements IPlayerAttackCooldown { } } - float timerMult = Timer.getTickTimer(); - if (timerMult > 0.0001f && Math.abs(timerMult - 1.0f) > 0.0001f) { - result = result * timerMult; - } - return result; } @Override - public float combatant$getAttackCooldownProgress(float tickDelta) { + public float lovisual$getAttackCooldownProgress(float tickDelta) { Player self = (Player) (Object) this; return self.getAttackStrengthScale(tickDelta); } @Override - public boolean combatant$isAttackCharged(float tickDelta) { - return combatant$getAttackCooldownProgress(tickDelta) >= 1.0f; + public boolean lovisual$isAttackCharged(float tickDelta) { + return lovisual$getAttackCooldownProgress(tickDelta) >= 1.0f; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerInfoMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerInfoMixin.java index 90d00de..8728d96 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerInfoMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerInfoMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerInventoryMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerInventoryMixin.java index 9484d91..3c594eb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerInventoryMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerInventoryMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -30,13 +30,13 @@ public abstract class PlayerInventoryMixin { public abstract ItemStack getItem(int slot); @ModifyReturnValue(method = "getSelectedSlot", at = @At("RETURN")) - private int combatant$silentSelectedSlot(int original) { + private int lovisual$silentSelectedSlot(int original) { Minecraft mc = Minecraft.getInstance(); return player == mc.player ? InventorySwap.INSTANCE.effectiveSelectedSlot() : original; } @ModifyReturnValue(method = "getSelectedItem", at = @At("RETURN")) - private ItemStack combatant$silentSelectedStack(ItemStack original) { + private ItemStack lovisual$silentSelectedStack(ItemStack original) { Minecraft mc = Minecraft.getInstance(); if (player == mc.player && InventorySwap.INSTANCE.isHotbarLeased()) { return getItem(InventorySwap.INSTANCE.effectiveSelectedSlot()); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerTabOverlayMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerTabOverlayMixin.java index d7ac581..5bde179 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerTabOverlayMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerTabOverlayMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,6 @@ package dev.loki.lovisual.mixins; import dev.loki.lovisual.features.gui.hud.nondraggable.impl.tab.CustomTabList; -import dev.loki.lovisual.runtime.RuntimeGate; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.PlayerTabOverlay; import net.minecraft.world.scores.Objective; @@ -25,12 +24,12 @@ public abstract class PlayerTabOverlayMixin { at = @At("HEAD"), cancellable = true ) - private void combatant$extractCustomTabList(GuiGraphicsExtractor context, + private void lovisual$extractCustomTabList(GuiGraphicsExtractor context, int width, Scoreboard scoreboard, Objective objective, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + if (!CustomTabList.shouldReplaceVanilla()) return; CustomTabList.renderVanillaTabStratum(context, width); ci.cancel(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PowderSnowFogModifierMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PowderSnowFogModifierMixin.java index bdb1a84..b0ef448 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PowderSnowFogModifierMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PowderSnowFogModifierMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ import dev.loki.lovisual.features.module.modules.visuals.WorldTweaks; public class PowderSnowFogModifierMixin { @Inject(method = "setupFog", at = @At("HEAD"), cancellable = true) - private void combatant$noPowderFog(FogData data, + private void lovisual$noPowderFog(FogData data, Camera camera, ClientLevel world, float viewDistance, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ProjectileUtilMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ProjectileUtilMixin.java index 20559d2..a17719e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ProjectileUtilMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ProjectileUtilMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,8 +16,6 @@ import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.Hitbox; import java.util.ArrayList; import java.util.List; @@ -27,7 +25,7 @@ import java.util.function.Predicate; public class ProjectileUtilMixin { // Intercept getOtherEntities in ProjectileUtil.raycast: - // - If Hitbox is disabled/panic -> keep vanilla list. + // - If Hitbox is disabled -> keep vanilla list. // - If enabled -> drop dead LivingEntity and those Hitbox wants to ignore. @Redirect( method = "getEntityHitResult(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;D)Lnet/minecraft/world/phys/EntityHitResult;", @@ -36,21 +34,9 @@ public class ProjectileUtilMixin { target = "Lnet/minecraft/world/level/Level;getEntities(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;)Ljava/util/List;" ) ) - private static List combatant$filterEntities(Level world, Entity source, AABB box, Predicate predicate) { - List original = world.getEntities(source, box, predicate); - if (original == null || original.isEmpty()) return original; - - Hitbox hb = Modules.get(Hitbox.class); - if (hb == null || !hb.isEnabled()) return original; - - List filtered = new ArrayList<>(original.size()); - for (Entity e : original) { - if (e instanceof LivingEntity living && !living.isAlive()) continue; - if (hb.shouldIgnore(e)) continue; - filtered.add(e); - } - - return filtered; + private static List lovisual$filterEntities(Level world, Entity source, AABB box, Predicate predicate) { + // Hitbox module removed; keep vanilla entity list. + return world.getEntities(source, box, predicate); } // Intercept getBoundingBox: add padding only for live targets allowed by Hitbox. @@ -61,24 +47,14 @@ public class ProjectileUtilMixin { target = "Lnet/minecraft/world/entity/Entity;getBoundingBox()Lnet/minecraft/world/phys/AABB;" ) ) - private static AABB combatant$padBoundingBox(Entity target, + private static AABB lovisual$padBoundingBox(Entity target, Entity source, Vec3 start, Vec3 end, AABB box, Predicate predicate, double maxDistance) { - Hitbox hb = Modules.get(Hitbox.class); - AABB bb = target.getBoundingBox(); - if (hb == null || !hb.shouldExpandFor(target)) { - return bb; - } - - double baseDistanceSq = Hitbox.boxDistanceSq(bb, start); - if (baseDistanceSq > maxDistance) { - return bb; - } - - return bb.inflate(hb.getPadding()); + // Hitbox module removed; keep vanilla bounding box. + return target.getBoundingBox(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RecipeBookScreenMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RecipeBookScreenMixin.java index 46bca11..40ae200 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RecipeBookScreenMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RecipeBookScreenMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -26,7 +26,7 @@ public abstract class RecipeBookScreenMixin { private RecipeBookComponent recipeBookComponent; @Inject(method = "initButton", at = @At("HEAD"), cancellable = true) - private void combatant$disableRecipeBook(CallbackInfo ci) { + private void lovisual$disableRecipeBook(CallbackInfo ci) { BetterMinecraft module = Modules.get(BetterMinecraft.class); if (module != null && module.isHideRecipeBookEnabled()) { ci.cancel(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RenderPassMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RenderPassMixin.java index 9c40d86..3377d99 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RenderPassMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RenderPassMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,15 +13,15 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.util.logging.DebugLog; @Mixin(RenderPass.class) public abstract class RenderPassMixin { @Inject(method = "setPipeline", at = @At("RETURN")) - private void combatant$applyRhiPipelineState(RenderPipeline pipeline, CallbackInfo ci) { + private void lovisual$applyRhiPipelineState(RenderPipeline pipeline, CallbackInfo ci) { try { - CombatantRenderSystem.rhi().pipelineState().applyPipelineState(pipeline); + LoVisualRenderSystem.rhi().pipelineState().applyPipelineState(pipeline); } catch (Throwable t) { DebugLog.error("[ShapeClip] pipeline state hook failed for " + pipeline, t); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RenderPipelineMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RenderPipelineMixin.java index c21479a..ded4ca0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RenderPipelineMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/RenderPipelineMixin.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -22,28 +22,28 @@ import dev.loki.lovisual.render.engine.rhi.clip.ShapeClipRenderPassContract; @Mixin(RenderPipeline.class) public abstract class RenderPipelineMixin implements IRenderPipeline { @Unique - private boolean combatant$lineSmooth; + private boolean lovisual$lineSmooth; @Unique - private ShapeClipRenderPassContract combatant$shapeClipContract = ShapeClipRenderPassContract.NONE; + private ShapeClipRenderPassContract lovisual$shapeClipContract = ShapeClipRenderPassContract.NONE; @Override - public void combatant$setLineSmooth(boolean lineSmooth) { - this.combatant$lineSmooth = lineSmooth; + public void lovisual$setLineSmooth(boolean lineSmooth) { + this.lovisual$lineSmooth = lineSmooth; } @Override - public boolean combatant$getLineSmooth() { - return combatant$lineSmooth; + public boolean lovisual$getLineSmooth() { + return lovisual$lineSmooth; } @Override - public void combatant$setShapeClipContract(ShapeClipRenderPassContract contract) { - this.combatant$shapeClipContract = contract == null ? ShapeClipRenderPassContract.NONE : contract; + public void lovisual$setShapeClipContract(ShapeClipRenderPassContract contract) { + this.lovisual$shapeClipContract = contract == null ? ShapeClipRenderPassContract.NONE : contract; } @Override - public ShapeClipRenderPassContract combatant$getShapeClipContract() { - return combatant$shapeClipContract; + public ShapeClipRenderPassContract lovisual$getShapeClipContract() { + return lovisual$shapeClipContract; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ScreenEffectRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ScreenEffectRendererMixin.java index e852557..22946c1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ScreenEffectRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ScreenEffectRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -32,7 +32,7 @@ public abstract class ScreenEffectRendererMixin { "Lnet/minecraft/client/renderer/ScreenEffectRenderer;submitFire(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;)V" ) ) - private static void combatant$maybeRenderFireOverlay( + private static void lovisual$maybeRenderFireOverlay( PoseStack matrices, SubmitNodeCollector vertexConsumers, TextureAtlasSprite sprite @@ -66,7 +66,7 @@ public abstract class ScreenEffectRendererMixin { "Lnet/minecraft/client/renderer/ScreenEffectRenderer;submitBlockSprite(Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;I)V" ) ) - private static void combatant$maybeRenderBlockOverlay( + private static void lovisual$maybeRenderBlockOverlay( TextureAtlasSprite sprite, PoseStack matrices, SubmitNodeCollector vertexConsumers, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ScreenMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ScreenMixin.java index 7d11bdc..7c0d820 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ScreenMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ScreenMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -24,20 +24,19 @@ import dev.loki.lovisual.features.command.CommandManager; import dev.loki.lovisual.features.gui.hud.nondraggable.impl.BetterButtons; import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.features.module.modules.visuals.NoRender; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.RenderPhaseScope; import dev.loki.lovisual.render.engine.postprocess.MenuBackgroundRenderer; -import dev.loki.lovisual.runtime.RuntimeGate; import dev.loki.lovisual.util.NarratorBlocker; @Mixin(Screen.class) public abstract class ScreenMixin { @Unique - private RenderPhaseScope combatant$screenPhaseScope; + private RenderPhaseScope lovisual$screenPhaseScope; @Inject(method = "defaultHandleGameClickEvent", at = @At("HEAD"), cancellable = true) - private static void combatant$runClientChatCommand(ClickEvent event, + private static void lovisual$runClientChatCommand(ClickEvent event, Minecraft client, Screen screen, CallbackInfo ci) { @@ -50,7 +49,7 @@ public abstract class ScreenMixin { } @Inject(method = "extractMenuBackgroundTexture", at = @At("HEAD"), cancellable = true) - private static void combatant$replaceMenuBackground(GuiGraphicsExtractor context, + private static void lovisual$replaceMenuBackground(GuiGraphicsExtractor context, Identifier texture, int x, int y, @@ -60,7 +59,7 @@ public abstract class ScreenMixin { int height, CallbackInfo ci) { if (texture == null || context == null) return; - if (RuntimeGate.isPanic()) return; + if (!Screen.MENU_BACKGROUND.equals(texture)) return; if (x != 0 || y != 0) return; @@ -79,14 +78,14 @@ public abstract class ScreenMixin { } @Inject(method = "shouldRunNarration", at = @At("HEAD"), cancellable = true) - private void combatant$disableNarratorUi(CallbackInfoReturnable cir) { + private void lovisual$disableNarratorUi(CallbackInfoReturnable cir) { if (!NarratorBlocker.isBlocked()) return; cir.setReturnValue(false); } @Inject(method = "extractBackground(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("HEAD"), cancellable = true) - private void combatant$replaceScreenBackground(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$replaceScreenBackground(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.level != null) return; MainConfig cfg = MainConfig.get(); @@ -99,7 +98,7 @@ public abstract class ScreenMixin { } @Inject(method = "extractBackground(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("HEAD"), cancellable = true) - private void combatant$noRender$cancelDarkening(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void lovisual$noRender$cancelDarkening(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta, CallbackInfo ci) { NoRender module = Modules.get(NoRender.class); Minecraft mc = Minecraft.getInstance(); if (module != null && mc != null && mc.level != null && module.screenDarkeningDisabled()) { @@ -108,7 +107,7 @@ public abstract class ScreenMixin { } @Inject(method = "extractTransparentBackground(Lnet/minecraft/client/gui/GuiGraphicsExtractor;)V", at = @At("HEAD"), cancellable = true) - private void combatant$noRender$cancelInGameBackground(GuiGraphicsExtractor context, CallbackInfo ci) { + private void lovisual$noRender$cancelInGameBackground(GuiGraphicsExtractor context, CallbackInfo ci) { NoRender module = Modules.get(NoRender.class); Minecraft mc = Minecraft.getInstance(); if (module != null && mc != null && mc.level != null && module.screenDarkeningDisabled()) { @@ -117,8 +116,8 @@ public abstract class ScreenMixin { } @Inject(method = "extractPanorama", at = @At("HEAD"), cancellable = true, require = 0) - private void combatant$replaceTitlePanorama(GuiGraphicsExtractor context, float delta, CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$replaceTitlePanorama(GuiGraphicsExtractor context, float delta, CallbackInfo ci) { + Screen self = (Screen) (Object) this; if (!(self instanceof TitleScreen)) return; @@ -135,25 +134,25 @@ public abstract class ScreenMixin { } @Inject(method = "extractRenderStateWithTooltipAndSubtitles(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("HEAD")) - private void combatant$beginButtonQueue(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void lovisual$beginButtonQueue(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { BetterButtons.beginFrame(ctx); } @Inject(method = "extractRenderStateWithTooltipAndSubtitles(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("HEAD")) - private void combatant$phaseScreenHead(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void lovisual$phaseScreenHead(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { Screen self = (Screen) (Object) this; String label = "2d:screen:" + self.getClass().getSimpleName(); - CombatantRenderSystem.ensureFrameContext(); - combatant$screenPhaseScope = CombatantRenderSystem.phase(RenderPhase.SCREEN, label); + LoVisualRenderSystem.ensureFrameContext(); + lovisual$screenPhaseScope = LoVisualRenderSystem.phase(RenderPhase.SCREEN, label); } @Inject(method = "extractRenderStateWithTooltipAndSubtitles(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("RETURN")) - private void combatant$phaseScreenTail(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void lovisual$phaseScreenTail(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { Screen self = (Screen) (Object) this; String label = "2d:screen:" + self.getClass().getSimpleName(); - if (combatant$screenPhaseScope != null) { - combatant$screenPhaseScope.close(); - combatant$screenPhaseScope = null; + if (lovisual$screenPhaseScope != null) { + lovisual$screenPhaseScope.close(); + lovisual$screenPhaseScope = null; } } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ServerboundUseItemPacketMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ServerboundUseItemPacketMixin.java index b8eeac4..11c3df1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ServerboundUseItemPacketMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ServerboundUseItemPacketMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -33,7 +33,7 @@ public class ServerboundUseItemPacketMixin { private float xRot; @Inject(method = "(Lnet/minecraft/world/InteractionHand;IFF)V", at = @At("RETURN")) - private void combatant$applyRotation(InteractionHand hand, int sequence, float yaw, float pitch, CallbackInfo ci) { + private void lovisual$applyRotation(InteractionHand hand, int sequence, float yaw, float pitch, CallbackInfo ci) { Rotation rotation = RotationManager.INSTANCE.getCurrentRotation(); if (rotation == null) { return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ShaderLoaderMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ShaderLoaderMixin.java index c278636..a72ef52 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ShaderLoaderMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ShaderLoaderMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,7 +25,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.loki.lovisual.mixins.accessors.ShaderLoaderDefinitionsAccessor; import dev.loki.lovisual.mixins.accessors.ShaderSourceKeyAccessor; -import dev.loki.lovisual.render.engine.shader.CombatantShaderSources; +import dev.loki.lovisual.render.engine.shader.LoVisualShaderSources; import dev.loki.lovisual.render.iris.IrisCompatibilityGuards; import dev.loki.lovisual.util.logging.DebugLog; import dev.loki.lovisual.util.resources.RenderResourceReadiness; @@ -38,37 +38,37 @@ import java.util.Map; @Mixin(ShaderManager.class) public abstract class ShaderLoaderMixin { @Unique - private static final Identifier COMBATANT_ENTITY_VERTEX = Identifier.fromNamespaceAndPath("lovisual", "shaders/core/entity_dither.vsh"); + private static final Identifier LOVISUAL_ENTITY_VERTEX = Identifier.fromNamespaceAndPath("lovisual", "shaders/core/entity_dither.vsh"); @Unique - private static final Identifier COMBATANT_ENTITY_FRAGMENT = Identifier.fromNamespaceAndPath("lovisual", "shaders/core/entity_dither.fsh"); + private static final Identifier LOVISUAL_ENTITY_FRAGMENT = Identifier.fromNamespaceAndPath("lovisual", "shaders/core/entity_dither.fsh"); @Unique private static final Identifier VANILLA_ENTITY_ID = Identifier.withDefaultNamespace("core/entity"); @Unique - private static boolean combatant$loggedEntityOverride; + private static boolean lovisual$loggedEntityOverride; @Unique - private static boolean combatant$loggedExtendedShaderSources; + private static boolean lovisual$loggedExtendedShaderSources; @Unique - private static boolean combatant$loggedShaderLoadError; + private static boolean lovisual$loggedShaderLoadError; @Unique - private static Constructor combatant$shaderSourceKeyConstructor; + private static Constructor lovisual$shaderSourceKeyConstructor; @Unique - private static int combatant$shaderLoadFailCount; + private static int lovisual$shaderLoadFailCount; @WrapOperation( method = "prepare", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ShaderManager;loadShader(Lnet/minecraft/resources/Identifier;Lnet/minecraft/server/packs/resources/Resource;Lcom/mojang/blaze3d/shaders/ShaderType;Ljava/util/Map;Lcom/google/common/collect/ImmutableMap$Builder;)V") ) - private static void combatant$wrapLoadShader(Identifier id, Resource resource, ShaderType type, + private static void lovisual$wrapLoadShader(Identifier id, Resource resource, ShaderType type, Map allResources, ImmutableMap.Builder builder, Operation original) { try { original.call(id, resource, type, allResources, builder); } catch (Throwable t) { - combatant$shaderLoadFailCount++; - if (!combatant$loggedShaderLoadError) { - combatant$loggedShaderLoadError = true; + lovisual$shaderLoadFailCount++; + if (!lovisual$loggedShaderLoadError) { + lovisual$loggedShaderLoadError = true; DebugLog.error("[Shader] Failed to load shader", t); } DebugLog.warn("[Shader] Skipping shader {}: {}", id, t.getMessage()); @@ -76,8 +76,8 @@ public abstract class ShaderLoaderMixin { } @Unique - private static boolean combatant$addExtendedShaderSources(ResourceManager resourceManager, Map shaderSources) { - Map resources = resourceManager.listResources("shaders", CombatantShaderSources::isCombatantExtendedSource); + private static boolean lovisual$addExtendedShaderSources(ResourceManager resourceManager, Map shaderSources) { + Map resources = resourceManager.listResources("shaders", LoVisualShaderSources::isLoVisualExtendedSource); if (resources.isEmpty()) { return false; } @@ -85,30 +85,30 @@ public abstract class ShaderLoaderMixin { int added = 0; for (Map.Entry entry : resources.entrySet()) { Identifier resourceId = entry.getKey(); - ShaderType type = CombatantShaderSources.typeByLocation(resourceId); + ShaderType type = LoVisualShaderSources.typeByLocation(resourceId); if (type == null) continue; - String source = CombatantShaderSources.load(resourceManager, resourceId, entry.getValue()); - shaderSources.put(combatant$newShaderSourceKey(resourceId, type), source); + String source = LoVisualShaderSources.load(resourceManager, resourceId, entry.getValue()); + shaderSources.put(lovisual$newShaderSourceKey(resourceId, type), source); added++; - Identifier canonicalId = CombatantShaderSources.canonicalShaderId(resourceId); + Identifier canonicalId = LoVisualShaderSources.canonicalShaderId(resourceId); if (!canonicalId.equals(resourceId)) { - shaderSources.put(combatant$newShaderSourceKey(canonicalId, type), source); + shaderSources.put(lovisual$newShaderSourceKey(canonicalId, type), source); added++; } } - if (added > 0 && !combatant$loggedExtendedShaderSources) { - combatant$loggedExtendedShaderSources = true; - DebugLog.renderThread("[ShaderSource] registered Combatant .vert/.frag sources in ShaderManager: " + added + " keys"); + if (added > 0 && !lovisual$loggedExtendedShaderSources) { + lovisual$loggedExtendedShaderSources = true; + DebugLog.renderThread("[ShaderSource] registered LoVisual .vert/.frag sources in ShaderManager: " + added + " keys"); } return added > 0; } @Unique - private static boolean combatant$allowVanillaEntityShaderOverride() { - if (IrisCompatibilityGuards.suppressCombatantTerrainShaderOverrides()) { + private static boolean lovisual$allowVanillaEntityShaderOverride() { + if (IrisCompatibilityGuards.suppressLoVisualTerrainShaderOverrides()) { return false; } @@ -116,12 +116,12 @@ public abstract class ShaderLoaderMixin { } @Unique - private static boolean combatant$applyEntityOverride(ResourceManager resourceManager, Map shaderSources) { - String entityFragmentSrc = combatant$loadShaderSource(resourceManager, COMBATANT_ENTITY_FRAGMENT); - String entityVertexSrc = combatant$loadShaderSource(resourceManager, COMBATANT_ENTITY_VERTEX); - if (((entityFragmentSrc == null || entityFragmentSrc.isEmpty()) || (entityVertexSrc == null || entityVertexSrc.isEmpty())) && !combatant$loggedEntityOverride) { - combatant$loggedEntityOverride = true; - DebugLog.warn("[ShaderOverride] entity fade override skipped: combatant entity_dither shader missing"); + private static boolean lovisual$applyEntityOverride(ResourceManager resourceManager, Map shaderSources) { + String entityFragmentSrc = lovisual$loadShaderSource(resourceManager, LOVISUAL_ENTITY_FRAGMENT); + String entityVertexSrc = lovisual$loadShaderSource(resourceManager, LOVISUAL_ENTITY_VERTEX); + if (((entityFragmentSrc == null || entityFragmentSrc.isEmpty()) || (entityVertexSrc == null || entityVertexSrc.isEmpty())) && !lovisual$loggedEntityOverride) { + lovisual$loggedEntityOverride = true; + DebugLog.warn("[ShaderOverride] entity fade override skipped: lovisual entity_dither shader missing"); } if ((entityFragmentSrc == null || entityFragmentSrc.isEmpty()) || (entityVertexSrc == null || entityVertexSrc.isEmpty())) { @@ -133,46 +133,46 @@ public abstract class ShaderLoaderMixin { for (Map.Entry entry : shaderSources.entrySet()) { Object key = entry.getKey(); - if (entityVertexSrc != null && !entityVertexSrc.isEmpty() && combatant$isEntityVertexKey(key)) { + if (entityVertexSrc != null && !entityVertexSrc.isEmpty() && lovisual$isEntityVertexKey(key)) { entry.setValue(entityVertexSrc); entityVertexChanged = true; continue; } - if (entityFragmentSrc != null && !entityFragmentSrc.isEmpty() && combatant$isEntityFragmentKey(key)) { + if (entityFragmentSrc != null && !entityFragmentSrc.isEmpty() && lovisual$isEntityFragmentKey(key)) { entry.setValue(entityFragmentSrc); entityFragmentChanged = true; } } - if ((!entityFragmentChanged || !entityVertexChanged) && !combatant$loggedEntityOverride) { - combatant$loggedEntityOverride = true; + if ((!entityFragmentChanged || !entityVertexChanged) && !lovisual$loggedEntityOverride) { + lovisual$loggedEntityOverride = true; DebugLog.warn("[ShaderOverride] entity fade override skipped: entity shader key not found"); } - if (entityFragmentChanged && entityVertexChanged && !combatant$loggedEntityOverride) { - combatant$loggedEntityOverride = true; - DebugLog.renderThread("[ShaderOverride] override applied: core/entity -> combatant entity_dither"); + if (entityFragmentChanged && entityVertexChanged && !lovisual$loggedEntityOverride) { + lovisual$loggedEntityOverride = true; + DebugLog.renderThread("[ShaderOverride] override applied: core/entity -> lovisual entity_dither"); } return entityFragmentChanged || entityVertexChanged; } @Unique - private static boolean combatant$isEntityFragmentKey(Object key) { + private static boolean lovisual$isEntityFragmentKey(Object key) { if (!(key instanceof ShaderSourceKeyAccessor accessor)) return false; - return VANILLA_ENTITY_ID.equals(accessor.combatant$getId()) && accessor.combatant$getType() == ShaderType.FRAGMENT; + return VANILLA_ENTITY_ID.equals(accessor.lovisual$getId()) && accessor.lovisual$getType() == ShaderType.FRAGMENT; } @Unique - private static boolean combatant$isEntityVertexKey(Object key) { + private static boolean lovisual$isEntityVertexKey(Object key) { if (!(key instanceof ShaderSourceKeyAccessor accessor)) return false; - return VANILLA_ENTITY_ID.equals(accessor.combatant$getId()) && accessor.combatant$getType() == ShaderType.VERTEX; + return VANILLA_ENTITY_ID.equals(accessor.lovisual$getId()) && accessor.lovisual$getType() == ShaderType.VERTEX; } @Unique - private static String combatant$loadShaderSource(ResourceManager resourceManager, Identifier id) { + private static String lovisual$loadShaderSource(ResourceManager resourceManager, Identifier id) { try { - return CombatantShaderSources.load(resourceManager, id); + return LoVisualShaderSources.load(resourceManager, id); } catch (Exception e) { DebugLog.error("[ShaderOverride] read shader override failed: " + id, e); return null; @@ -180,22 +180,22 @@ public abstract class ShaderLoaderMixin { } @Unique - private static Object combatant$newShaderSourceKey(Identifier id, ShaderType type) { + private static Object lovisual$newShaderSourceKey(Identifier id, ShaderType type) { try { - if (combatant$shaderSourceKeyConstructor == null) { + if (lovisual$shaderSourceKeyConstructor == null) { Class keyClass = Class.forName("net.minecraft.client.renderer.ShaderManager$ShaderSourceKey"); Constructor constructor = keyClass.getDeclaredConstructor(Identifier.class, ShaderType.class); constructor.setAccessible(true); - combatant$shaderSourceKeyConstructor = constructor; + lovisual$shaderSourceKeyConstructor = constructor; } - return combatant$shaderSourceKeyConstructor.newInstance(id, type); + return lovisual$shaderSourceKeyConstructor.newInstance(id, type); } catch (ReflectiveOperationException e) { throw new IllegalStateException("Failed to create ShaderManager shader source key for " + type + " " + id, e); } } @Inject(method = "apply", at = @At("HEAD")) - private void combatant$beforeShaderReload(ShaderManager.Configs definitions, + private void lovisual$beforeShaderReload(ShaderManager.Configs definitions, ResourceManager resourceManager, ProfilerFiller profiler, CallbackInfo ci) { @@ -203,7 +203,7 @@ public abstract class ShaderLoaderMixin { } @Inject(method = "apply", at = @At("TAIL")) - private void combatant$afterShaderReload(ShaderManager.Configs definitions, + private void lovisual$afterShaderReload(ShaderManager.Configs definitions, ResourceManager resourceManager, ProfilerFiller profiler, CallbackInfo ci) { @@ -211,24 +211,24 @@ public abstract class ShaderLoaderMixin { } @ModifyReturnValue(method = "prepare", at = @At("RETURN")) - private ShaderManager.Configs combatant$extendShaderSources(ShaderManager.Configs definitions, + private ShaderManager.Configs lovisual$extendShaderSources(ShaderManager.Configs definitions, ResourceManager resourceManager, ProfilerFiller profiler) { ShaderLoaderDefinitionsAccessor accessor = (ShaderLoaderDefinitionsAccessor) (Object) definitions; - Map shaderSources = accessor.combatant$getShaderSources(); + Map shaderSources = accessor.lovisual$getShaderSources(); Map replaced = new LinkedHashMap<>(shaderSources.size() + 64); replaced.putAll(shaderSources); - boolean changed = combatant$addExtendedShaderSources(resourceManager, replaced); - if (combatant$allowVanillaEntityShaderOverride()) { - changed |= combatant$applyEntityOverride(resourceManager, replaced); + boolean changed = lovisual$addExtendedShaderSources(resourceManager, replaced); + if (lovisual$allowVanillaEntityShaderOverride()) { + changed |= lovisual$applyEntityOverride(resourceManager, replaced); } if (!changed) { return definitions; } - Map postChains = accessor.combatant$getPostChains(); + Map postChains = accessor.lovisual$getPostChains(); @SuppressWarnings({"rawtypes", "unchecked"}) ShaderManager.Configs updated = new ShaderManager.Configs((Map) replaced, postChains); return updated; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SkyRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SkyRendererMixin.java index c10a74f..557b774 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SkyRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SkyRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -40,7 +40,7 @@ public abstract class SkyRendererMixin { opcode = Opcodes.GETFIELD ) ) - private RenderTarget combatant$currentWorldTarget(SkyRenderer instance) { + private RenderTarget lovisual$currentWorldTarget(SkyRenderer instance) { RenderTarget msaa = MsaaWorldTarget.getFramebufferOverride(); return msaa != null ? msaa : renderTarget; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SlimeBlockMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SlimeBlockMixin.java index 126332e..f99652a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SlimeBlockMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SlimeBlockMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,18 +16,12 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.NoStun; @Mixin(SlimeBlock.class) public class SlimeBlockMixin { @Inject(method = "stepOn", at = @At("HEAD"), cancellable = true) private void nostun$onSteppedOn(Level world, BlockPos pos, BlockState state, Entity entity, CallbackInfo ci) { - NoStun ns = Modules.get(NoStun.class); - if (ns == null || !ns.isEnabled()) return; - if (!ns.isFunctionEnabled(NoStun.fnEnvBlocks())) return; - if (!ns.isEnvBlockEnabled(NoStun.envSlime())) return; - ci.cancel(); + // NoStun module removed; no slime-block override remains. } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SpriteIconButtonCenteredIconMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SpriteIconButtonCenteredIconMixin.java index 2381c5a..08c4985 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SpriteIconButtonCenteredIconMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SpriteIconButtonCenteredIconMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ import dev.loki.lovisual.features.gui.hud.nondraggable.impl.BetterButtons; public abstract class SpriteIconButtonCenteredIconMixin { @Inject(method = "extractContents(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("HEAD"), cancellable = true) - private void combatant$drawIcon(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void lovisual$drawIcon(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { BetterButtons buttons = BetterButtons.get(); if (buttons == null || !buttons.useUiButtons()) return; Minecraft mc = Minecraft.getInstance(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SpriteIconButtonTextAndIconMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SpriteIconButtonTextAndIconMixin.java index e898fcf..0bc1977 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SpriteIconButtonTextAndIconMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/SpriteIconButtonTextAndIconMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ import dev.loki.lovisual.features.gui.hud.nondraggable.impl.BetterButtons; public abstract class SpriteIconButtonTextAndIconMixin { @Inject(method = "extractContents(Lnet/minecraft/client/gui/GuiGraphicsExtractor;IIF)V", at = @At("HEAD"), cancellable = true) - private void combatant$drawIcon(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void lovisual$drawIcon(GuiGraphicsExtractor ctx, int mouseX, int mouseY, float delta, CallbackInfo ci) { BetterButtons buttons = BetterButtons.get(); if (buttons == null || !buttons.useUiButtons()) return; Minecraft mc = Minecraft.getInstance(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/TitleScreenMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/TitleScreenMixin.java index 21a4559..677d7fe 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/TitleScreenMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/TitleScreenMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,14 +15,13 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.loki.lovisual.features.gui.mainmenu.LoVisualMainMenuScreen; -import dev.loki.lovisual.runtime.RuntimeGate; @Mixin(TitleScreen.class) public abstract class TitleScreenMixin { @Inject(method = "init", at = @At("HEAD"), cancellable = true) - private void combatant$replaceTitleScreen(CallbackInfo ci) { - if (RuntimeGate.isPanic()) return; + private void lovisual$replaceTitleScreen(CallbackInfo ci) { + if (LoVisualMainMenuScreen.shouldUseVanillaTitleScreen()) return; Minecraft mc = Minecraft.getInstance(); if (mc == null) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ToastManagerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ToastManagerMixin.java index 2260b8f..92d56cf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ToastManagerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/ToastManagerMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,7 +20,7 @@ import dev.loki.lovisual.features.module.modules.visuals.NoRender; public abstract class ToastManagerMixin { @Inject(method = "addToast(Lnet/minecraft/client/gui/components/toasts/Toast;)V", at = @At("HEAD"), cancellable = true) - private void combatant$noRender$hideToasts(Toast toast, CallbackInfo ci) { + private void lovisual$noRender$hideToasts(Toast toast, CallbackInfo ci) { NoRender module = Modules.get(NoRender.class); if (module != null && module.hideToastHints()) { ci.cancel(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/TooltipRenderUtilMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/TooltipRenderUtilMixin.java index a01434e..6f67946 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/TooltipRenderUtilMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/TooltipRenderUtilMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanCommandEncoderMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanCommandEncoderMixin.java index a257ebf..5457679 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanCommandEncoderMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanCommandEncoderMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.rhi.backend.vulkan.clip.VulkanShapeClipBridge; import dev.loki.lovisual.render.engine.rhi.backend.vulkan.msaa.VulkanMsaaResolveBridge; import dev.loki.lovisual.render.engine.rhi.backend.vulkan.util.VulkanRenderStateBridge; @@ -33,7 +33,7 @@ import static org.lwjgl.vulkan.VK12.*; @Mixin(VulkanCommandEncoder.class) public abstract class VulkanCommandEncoderMixin { @Inject(method = "createRenderPass", at = @At("HEAD")) - private void combatant$beginVulkanRenderPassState(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { + private void lovisual$beginVulkanRenderPassState(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { VulkanMsaaResolveBridge.beginRenderPass(); VulkanRenderStateBridge.beginRenderPass(descriptor); } @@ -43,7 +43,7 @@ public abstract class VulkanCommandEncoderMixin { method = "createRenderPass", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/KHRDynamicRendering;vkCmdBeginRenderingKHR(Lorg/lwjgl/vulkan/VkCommandBuffer;Lorg/lwjgl/vulkan/VkRenderingInfo;)V", shift = At.Shift.BEFORE) ) - private void combatant$configureAttachments(RenderPassDescriptor descriptor, + private void lovisual$configureAttachments(RenderPassDescriptor descriptor, CallbackInfoReturnable cir, @Local MemoryStack stack, @Local VkRenderingInfo renderingInfo) { @@ -83,10 +83,10 @@ public abstract class VulkanCommandEncoderMixin { @Inject(method = "submitRenderPass", at = @At("TAIL")) - private void combatant$endVulkanRenderPassState(CallbackInfo ci) { + private void lovisual$endVulkanRenderPassState(CallbackInfo ci) { VulkanMsaaResolveBridge.finishRenderPass(); try { - CombatantRenderSystem.rhi().shapeClip().endRenderPass(); + LoVisualRenderSystem.rhi().shapeClip().endRenderPass(); } catch (Throwable ignored) { // Render pass teardown must never make Vulkan submission fail. } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanDeviceMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanDeviceMixin.java index 294a505..337567b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanDeviceMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanDeviceMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -46,13 +46,13 @@ public abstract class VulkanDeviceMixin { private ShaderSource defaultShaderSource; @Unique - private final Map combatant$pipelineVariants = new HashMap<>(); + private final Map lovisual$pipelineVariants = new HashMap<>(); @Invoker("compilePipeline") - protected abstract VulkanRenderPipeline combatant$compilePipelineVariant(RenderPipeline pipeline, ShaderSource source); + protected abstract VulkanRenderPipeline lovisual$compilePipelineVariant(RenderPipeline pipeline, ShaderSource source); @Inject(method = "", at = @At("RETURN")) - private void combatant$captureMsaaCapabilities(ShaderSource shaderSource, + private void lovisual$captureMsaaCapabilities(ShaderSource shaderSource, VulkanInstance instance, VulkanPhysicalDevice physicalDevice, Set enabledExtensions, @@ -71,19 +71,19 @@ public abstract class VulkanDeviceMixin { | GpuTexture.USAGE_COPY_SRC | GpuTexture.USAGE_TEXTURE_BINDING | GpuTexture.USAGE_RENDER_ATTACHMENT; - framebufferSamples &= combatant$imageSampleCounts( + framebufferSamples &= lovisual$imageSampleCounts( stack, physicalDevice, GpuFormat.RGBA8_UNORM, VulkanConst.textureUsageToVk(textureUsage, GpuFormat.RGBA8_UNORM) ); - framebufferSamples &= combatant$imageSampleCounts( + framebufferSamples &= lovisual$imageSampleCounts( stack, physicalDevice, GpuFormat.D32_FLOAT, VulkanConst.textureUsageToVk(textureUsage, GpuFormat.D32_FLOAT) ); - framebufferSamples &= combatant$imageSampleCounts( + framebufferSamples &= lovisual$imageSampleCounts( stack, physicalDevice, GpuFormat.S8_UINT, @@ -114,7 +114,7 @@ public abstract class VulkanDeviceMixin { } @Unique - private static int combatant$imageSampleCounts(MemoryStack stack, + private static int lovisual$imageSampleCounts(MemoryStack stack, VulkanPhysicalDevice physicalDevice, GpuFormat format, int usage) { @@ -132,23 +132,23 @@ public abstract class VulkanDeviceMixin { } @Inject(method = "getOrCompilePipeline", at = @At("HEAD"), cancellable = true) - private void combatant$getOrCompilePipelineVariant(RenderPipeline pipeline, + private void lovisual$getOrCompilePipelineVariant(RenderPipeline pipeline, CallbackInfoReturnable cir) { if (!VulkanRenderStateBridge.needsPipelineVariant(pipeline)) return; VulkanRenderStateBridge.PipelineVariantKey key = VulkanRenderStateBridge.pipelineVariantKey(pipeline); - VulkanRenderPipeline variant = combatant$pipelineVariants.get(key); + VulkanRenderPipeline variant = lovisual$pipelineVariants.get(key); if (variant != null) { cir.setReturnValue(variant); return; } try { - variant = combatant$compilePipelineVariant(pipeline, defaultShaderSource); + variant = lovisual$compilePipelineVariant(pipeline, defaultShaderSource); if (variant == null || !variant.isValid()) { throw new IllegalStateException("Vulkan returned an invalid pipeline variant"); } - combatant$pipelineVariants.put(key, variant); + lovisual$pipelineVariants.put(key, variant); DebugLog.stencilOnChange( "vulkan.pipeline.variant.compile", key.toString(), @@ -173,9 +173,9 @@ public abstract class VulkanDeviceMixin { } @Inject(method = "clearPipelineCache", at = @At("RETURN")) - private void combatant$clearPipelineVariants(CallbackInfo ci) { - if (combatant$pipelineVariants.isEmpty()) return; - for (VulkanRenderPipeline pipeline : combatant$pipelineVariants.values()) { + private void lovisual$clearPipelineVariants(CallbackInfo ci) { + if (lovisual$pipelineVariants.isEmpty()) return; + for (VulkanRenderPipeline pipeline : lovisual$pipelineVariants.values()) { try { pipeline.destroy(); } catch (Throwable t) { @@ -188,6 +188,6 @@ public abstract class VulkanDeviceMixin { ); } } - combatant$pipelineVariants.clear(); + lovisual$pipelineVariants.clear(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanGpuTextureMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanGpuTextureMixin.java index 158b0a6..1d63b36 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanGpuTextureMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanGpuTextureMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -26,7 +26,7 @@ import static org.lwjgl.vulkan.VK12.*; @Mixin(VulkanGpuTexture.class) public abstract class VulkanGpuTextureMixin implements IMsaaTexture { @Unique - private int combatant$samples = 1; + private int lovisual$samples = 1; /** * Mojang 26.2 maps render-attachment usage only for color/depth aspects. Pure S8_UINT @@ -37,7 +37,7 @@ public abstract class VulkanGpuTextureMixin implements IMsaaTexture { method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vulkan/VulkanConst;textureUsageToVk(ILcom/mojang/blaze3d/GpuFormat;)I") ) - private int combatant$stencilAttachmentUsage(int usage, GpuFormat format) { + private int lovisual$stencilAttachmentUsage(int usage, GpuFormat format) { int vkUsage = com.mojang.blaze3d.vulkan.VulkanConst.textureUsageToVk(usage, format); if (format != null && format.hasStencilAspect() && (usage & com.mojang.blaze3d.textures.GpuTexture.USAGE_RENDER_ATTACHMENT) != 0) { vkUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; @@ -54,7 +54,7 @@ public abstract class VulkanGpuTextureMixin implements IMsaaTexture { method = "", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VkImageSubresourceRange;aspectMask(I)Lorg/lwjgl/vulkan/VkImageSubresourceRange;") ) - private VkImageSubresourceRange combatant$stencilImageAspect(VkImageSubresourceRange range, + private VkImageSubresourceRange lovisual$stencilImageAspect(VkImageSubresourceRange range, int original, VulkanDevice device, int usage, @@ -75,12 +75,12 @@ public abstract class VulkanGpuTextureMixin implements IMsaaTexture { at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VkImageCreateInfo;samples(I)Lorg/lwjgl/vulkan/VkImageCreateInfo;"), index = 0 ) - private int combatant$useRequestedMsaaSamples(int original) { + private int lovisual$useRequestedMsaaSamples(int original) { return VulkanRenderStateBridge.requestedTextureSamples(); } @Inject(method = "", at = @At("RETURN")) - private void combatant$rememberSamples(VulkanDevice device, + private void lovisual$rememberSamples(VulkanDevice device, int usage, String label, GpuFormat format, @@ -89,26 +89,26 @@ public abstract class VulkanGpuTextureMixin implements IMsaaTexture { int depthOrLayers, int mipLevels, CallbackInfo ci) { - combatant$samples = VulkanRenderStateBridge.requestedTextureSamples(); + lovisual$samples = VulkanRenderStateBridge.requestedTextureSamples(); } @Override - public void combatant$setSamples(int samples) { - combatant$samples = VulkanRenderStateBridge.normalizeSamples(samples); + public void lovisual$setSamples(int samples) { + lovisual$samples = VulkanRenderStateBridge.normalizeSamples(samples); } @Override - public int combatant$getSamples() { - return combatant$samples; + public int lovisual$getSamples() { + return lovisual$samples; } @Override - public boolean combatant$isMsaa() { - return combatant$samples > 1; + public boolean lovisual$isMsaa() { + return lovisual$samples > 1; } @Override - public int combatant$getGlId() { + public int lovisual$getGlId() { return 0; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanGpuTextureViewMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanGpuTextureViewMixin.java index 5eedd62..ac5408b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanGpuTextureViewMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanGpuTextureViewMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -29,7 +29,7 @@ public abstract class VulkanGpuTextureViewMixin { method = "", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VkImageSubresourceRange;aspectMask(I)Lorg/lwjgl/vulkan/VkImageSubresourceRange;") ) - private VkImageSubresourceRange combatant$stencilViewAspect(VkImageSubresourceRange range, + private VkImageSubresourceRange lovisual$stencilViewAspect(VkImageSubresourceRange range, int original, VulkanDevice device, VulkanGpuTexture texture, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanRenderPassMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanRenderPassMixin.java index 4f7d2b1..b917f59 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanRenderPassMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanRenderPassMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,24 +23,24 @@ import java.util.function.Supplier; @Mixin(VulkanRenderPass.class) public abstract class VulkanRenderPassMixin { @Invoker("commandBuffer") - protected abstract VkCommandBuffer combatant$commandBuffer(); + protected abstract VkCommandBuffer lovisual$commandBuffer(); @Inject(method = "pushDebugGroup", at = @At("HEAD"), cancellable = true) - private void combatant$disableRenderPassDebugGroup(Supplier label, CallbackInfo ci) { + private void lovisual$disableRenderPassDebugGroup(Supplier label, CallbackInfo ci) { if (!VulkanRenderStateBridge.forceDisableDebugLabels()) return; ci.cancel(); } @Inject(method = "popDebugGroup", at = @At("HEAD"), cancellable = true) - private void combatant$disableRenderPassDebugGroupPop(CallbackInfo ci) { + private void lovisual$disableRenderPassDebugGroupPop(CallbackInfo ci) { if (!VulkanRenderStateBridge.forceDisableDebugLabels()) return; ci.cancel(); } @Inject(method = "setPipeline", at = @At("TAIL")) - private void combatant$applyDynamicPipelineState(RenderPipeline pipeline, CallbackInfo ci) { + private void lovisual$applyDynamicPipelineState(RenderPipeline pipeline, CallbackInfo ci) { if (!VulkanRenderStateBridge.vulkanBackendActive()) return; - VkCommandBuffer commandBuffer = combatant$commandBuffer(); + VkCommandBuffer commandBuffer = lovisual$commandBuffer(); if (!VulkanRenderStateBridge.forceDisableStencil() && VulkanRenderStateBridge.currentRenderPassHasStencilAttachment()) { VK12.vkCmdSetStencilReference( commandBuffer, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanRenderPipelineMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanRenderPipelineMixin.java index 17e986b..7b81d0e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanRenderPipelineMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/VulkanRenderPipelineMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -33,7 +33,7 @@ import static org.lwjgl.vulkan.VK12.*; @Mixin(VulkanRenderPipeline.class) public abstract class VulkanRenderPipelineMixin { @Inject(method = "compile", at = @At("HEAD")) - private static void combatant$beginCompile(VulkanDevice device, + private static void lovisual$beginCompile(VulkanDevice device, VulkanBindGroupLayout layout, RenderPipeline pipeline, long vertexModule, @@ -45,7 +45,7 @@ public abstract class VulkanRenderPipelineMixin { } @Inject(method = "compile", at = @At("RETURN")) - private static void combatant$endCompile(VulkanDevice device, + private static void lovisual$endCompile(VulkanDevice device, VulkanBindGroupLayout layout, RenderPipeline pipeline, long vertexModule, @@ -58,7 +58,7 @@ public abstract class VulkanRenderPipelineMixin { method = "compile", at = @At(value = "INVOKE", target = "Lorg/lwjgl/system/MemoryStack;ints(II)Ljava/nio/IntBuffer;") ) - private static IntBuffer combatant$addDynamicStates(MemoryStack stack, int first, int second) { + private static IntBuffer lovisual$addDynamicStates(MemoryStack stack, int first, int second) { if (!VulkanRenderStateBridge.vulkanBackendActive()) { return stack.ints(first, second); } @@ -73,7 +73,7 @@ public abstract class VulkanRenderPipelineMixin { at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VkPipelineRasterizationStateCreateInfo;cullMode(I)Lorg/lwjgl/vulkan/VkPipelineRasterizationStateCreateInfo;"), index = 0 ) - private static int combatant$disableCullForStencilMask(int original) { + private static int lovisual$disableCullForStencilMask(int original) { return VulkanRenderStateBridge.vulkanBackendActive() && VulkanRenderStateBridge.suppressColorWrites() ? VK_CULL_MODE_NONE : original; } @@ -82,7 +82,7 @@ public abstract class VulkanRenderPipelineMixin { at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VkPipelineDepthStencilStateCreateInfo;depthTestEnable(Z)Lorg/lwjgl/vulkan/VkPipelineDepthStencilStateCreateInfo;"), index = 0 ) - private static boolean combatant$disableDepthTestForStencilMask(boolean original) { + private static boolean lovisual$disableDepthTestForStencilMask(boolean original) { return (!VulkanRenderStateBridge.vulkanBackendActive() || !VulkanRenderStateBridge.suppressColorWrites()) && original; } @@ -91,7 +91,7 @@ public abstract class VulkanRenderPipelineMixin { at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VkPipelineDepthStencilStateCreateInfo;depthWriteEnable(Z)Lorg/lwjgl/vulkan/VkPipelineDepthStencilStateCreateInfo;"), index = 0 ) - private static boolean combatant$disableDepthWriteForStencilMask(boolean original) { + private static boolean lovisual$disableDepthWriteForStencilMask(boolean original) { return (!VulkanRenderStateBridge.vulkanBackendActive() || !VulkanRenderStateBridge.suppressColorWrites()) && original; } @@ -100,7 +100,7 @@ public abstract class VulkanRenderPipelineMixin { at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VkPipelineMultisampleStateCreateInfo;rasterizationSamples(I)Lorg/lwjgl/vulkan/VkPipelineMultisampleStateCreateInfo;"), index = 0 ) - private static int combatant$useCurrentRenderPassSamples(int original) { + private static int lovisual$useCurrentRenderPassSamples(int original) { return VulkanRenderStateBridge.vulkanBackendActive() ? VulkanRenderStateBridge.currentVkSampleCount() : original; } @@ -109,7 +109,7 @@ public abstract class VulkanRenderPipelineMixin { at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VkPipelineColorBlendAttachmentState$Buffer;colorWriteMask(I)Lorg/lwjgl/vulkan/VkPipelineColorBlendAttachmentState$Buffer;"), index = 0 ) - private static int combatant$suppressColorWritesForStencilMask(int original) { + private static int lovisual$suppressColorWritesForStencilMask(int original) { return VulkanRenderStateBridge.vulkanBackendActive() && VulkanRenderStateBridge.suppressColorWrites() ? 0 : original; } @@ -117,7 +117,7 @@ public abstract class VulkanRenderPipelineMixin { method = "compile", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VK12;vkCreateGraphicsPipelines(Lorg/lwjgl/vulkan/VkDevice;JLorg/lwjgl/vulkan/VkGraphicsPipelineCreateInfo$Buffer;Lorg/lwjgl/vulkan/VkAllocationCallbacks;Ljava/nio/LongBuffer;)I", ordinal = 0, shift = At.Shift.BEFORE) ) - private static void combatant$configureStencilPipeline(VulkanDevice device, + private static void lovisual$configureStencilPipeline(VulkanDevice device, VulkanBindGroupLayout layout, RenderPipeline pipeline, long vertexModule, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/WaterFogEnvironmentMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/WaterFogEnvironmentMixin.java index b36995b..55fc7fd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/WaterFogEnvironmentMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/WaterFogEnvironmentMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ import dev.loki.lovisual.features.module.modules.visuals.WorldTweaks; public class WaterFogEnvironmentMixin { @Inject(method = "setupFog", at = @At("HEAD"), cancellable = true) - private void combatant$noWaterFog(FogData data, + private void lovisual$noWaterFog(FogData data, Camera camera, ClientLevel world, float viewDistance, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/BossHealthOverlayAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/BossHealthOverlayAccessor.java index b17063c..8b30d07 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/BossHealthOverlayAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/BossHealthOverlayAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatInputSuggestorAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatInputSuggestorAccessor.java index 5802e25..edacc36 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatInputSuggestorAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatInputSuggestorAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,10 +17,10 @@ import java.util.concurrent.CompletableFuture; @Mixin(CommandSuggestions.class) public interface ChatInputSuggestorAccessor { @Accessor("suggestions") - CommandSuggestions.SuggestionsList getCombatant$window(); + CommandSuggestions.SuggestionsList getLoVisual$window(); @Accessor("pendingSuggestions") - CompletableFuture getCombatant$pendingSuggestions(); + CompletableFuture getLoVisual$pendingSuggestions(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatScreenAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatScreenAccessor.java index f8b7d67..cccdb2b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatScreenAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatScreenAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatScreenSuggestorAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatScreenSuggestorAccessor.java index 341ea31..295b796 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatScreenSuggestorAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ChatScreenSuggestorAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,7 +15,7 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(ChatScreen.class) public interface ChatScreenSuggestorAccessor { @Accessor("commandSuggestions") - CommandSuggestions getCombatant$suggestor(); + CommandSuggestions getLoVisual$suggestor(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClickableWidgetAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClickableWidgetAccessor.java index c21b043..a26fa41 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClickableWidgetAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClickableWidgetAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,7 +15,7 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(AbstractWidget.class) public interface ClickableWidgetAccessor { @Accessor("tooltip") - WidgetTooltipHolder combatant$getTooltipState(); + WidgetTooltipHolder lovisual$getTooltipState(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientLevelAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientLevelAccessor.java index 5cafcbc..ca780cd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientLevelAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientLevelAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ public interface ClientLevelAccessor { double vx, double vy, double vz); @Invoker("getBlockStatePredictionHandler") - BlockStatePredictionHandler combatant$getPendingUpdateManager(); + BlockStatePredictionHandler lovisual$getPendingUpdateManager(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientboundExplodePacketAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientboundExplodePacketAccessor.java index 4fe86ab..e43519f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientboundExplodePacketAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientboundExplodePacketAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,5 +20,5 @@ public interface ClientboundExplodePacketAccessor { @Mutable @Accessor("playerKnockback") - void combatant$setPlayerKnockback(Optional playerKnockback); + void lovisual$setPlayerKnockback(Optional playerKnockback); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientboundSetEntityMotionPacketAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientboundSetEntityMotionPacketAccessor.java index b9d9bcd..959e847 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientboundSetEntityMotionPacketAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ClientboundSetEntityMotionPacketAccessor.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -24,5 +24,5 @@ public interface ClientboundSetEntityMotionPacketAccessor { @Mutable @Accessor("movement") - void combatant$setVelocity(Vec3 velocity); + void lovisual$setVelocity(Vec3 velocity); } \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/CyclingButtonWidgetAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/CyclingButtonWidgetAccessor.java index 0055479..c4daa8f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/CyclingButtonWidgetAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/CyclingButtonWidgetAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,13 +16,13 @@ import java.util.function.Function; @Mixin(CycleButton.class) public interface CyclingButtonWidgetAccessor { @Accessor("spriteSupplier") - CycleButton.SpriteSupplier combatant$getIcon(); + CycleButton.SpriteSupplier lovisual$getIcon(); @Accessor("displayState") - CycleButton.DisplayState combatant$getLabelType(); + CycleButton.DisplayState lovisual$getLabelType(); @Accessor("valueStringifier") - Function combatant$getValueToText(); + Function lovisual$getValueToText(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EffectParticleEffectAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EffectParticleEffectAccessor.java index 59abaa8..de87242 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EffectParticleEffectAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EffectParticleEffectAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(SpellParticleOption.class) public interface EffectParticleEffectAccessor { @Accessor("color") - int combatant$getColor(); + int lovisual$getColor(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityAccessor.java index af1c4fe..5b679c2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -18,13 +18,13 @@ import org.spongepowered.asm.mixin.gen.Invoker; public interface EntityAccessor { @Accessor("portalProcess") - PortalProcessor combatant$getPortalManager(); + PortalProcessor lovisual$getPortalManager(); @Accessor("stuckSpeedMultiplier") - void combatant$setMovementMultiplier(Vec3 multiplier); + void lovisual$setMovementMultiplier(Vec3 multiplier); @Invoker("unsetRemoved") - void combatant$unsetRemoved(); + void lovisual$unsetRemoved(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityInvoker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityInvoker.java index 904b6b8..f599647 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityInvoker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityInvoker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.gen.Invoker; public interface EntityInvoker { @Invoker("getInputVector") - static Vec3 combatant$movementInputToVelocity(Vec3 movementInput, float speed, float yaw) { + static Vec3 lovisual$movementInputToVelocity(Vec3 movementInput, float speed, float yaw) { throw new AssertionError(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityRenderManagerAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityRenderManagerAccessor.java index 19efe64..5ac2b04 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityRenderManagerAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityRenderManagerAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,10 +20,10 @@ import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(EntityRenderDispatcher.class) public interface EntityRenderManagerAccessor { @Invoker("getRenderer") - EntityRenderer combatant$invokeGetRenderer(Entity entity); + EntityRenderer lovisual$invokeGetRenderer(Entity entity); @Invoker("submit") - void combatant$invokeRender(EntityRenderState renderState, + void lovisual$invokeRender(EntityRenderState renderState, CameraRenderState cameraState, double offsetX, double offsetY, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityRendererAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityRendererAccessor.java index 18ba2ac..49cabeb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityRendererAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/EntityRendererAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,8 +16,8 @@ import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(EntityRenderer.class) public interface EntityRendererAccessor { @Invoker("createRenderState") - EntityRenderState combatant$invokeCreateRenderState(); + EntityRenderState lovisual$invokeCreateRenderState(); @Invoker("extractRenderState") - void combatant$invokeUpdateRenderState(Entity entity, EntityRenderState state, float tickProgress); + void lovisual$invokeUpdateRenderState(Entity entity, EntityRenderState state, float tickProgress); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/FireworksComponentAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/FireworksComponentAccessor.java index 2e43067..731fe4a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/FireworksComponentAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/FireworksComponentAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(Fireworks.class) public interface FireworksComponentAccessor { @Accessor("flightDuration") - int combatant$getFlightDuration(); + int lovisual$getFlightDuration(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GameRendererAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GameRendererAccessor.java index 771de7a..bf01604 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GameRendererAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GameRendererAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -33,23 +33,23 @@ public interface GameRendererAccessor { void invokeRenderHand(CameraRenderState cameraRenderState, float tickDelta, Matrix4fc positionMatrix); @Accessor("gameRenderState") - GameRenderState combatant$getGameRenderState(); + GameRenderState lovisual$getGameRenderState(); @Accessor("handAndScreenSubmitNodeStorage") - SubmitNodeStorage combatant$getHandAndScreenSubmitNodeStorage(); + SubmitNodeStorage lovisual$getHandAndScreenSubmitNodeStorage(); @Accessor("mainRenderTarget") - RenderTarget combatant$getMainRenderTargetRaw(); + RenderTarget lovisual$getMainRenderTargetRaw(); @Accessor("guiRenderer") - GuiRenderer combatant$getGuiRenderer(); + GuiRenderer lovisual$getGuiRenderer(); @Accessor("fogRenderer") - FogRenderer combatant$getFogRenderer(); + FogRenderer lovisual$getFogRenderer(); @Accessor("spinningEffectTime") - float combatant$getNauseaEffectTime(); + float lovisual$getNauseaEffectTime(); @Accessor("spinningEffectSpeed") - float combatant$getNauseaEffectSpeed(); + float lovisual$getNauseaEffectSpeed(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GlTextureInvoker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GlTextureInvoker.java index 658e527..53c30fc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GlTextureInvoker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GlTextureInvoker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(GlTexture.class) public interface GlTextureInvoker { @Invoker("") - static GlTexture combatant$create(int usage, + static GlTexture lovisual$create(int usage, String label, GpuFormat format, int width, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GpuDeviceAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GpuDeviceAccessor.java index b76fff2..83730da 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GpuDeviceAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/GpuDeviceAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,5 +15,5 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(GpuDevice.class) public interface GpuDeviceAccessor { @Accessor("backend") - GpuDeviceBackend combatant$getBackend(); + GpuDeviceBackend lovisual$getBackend(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/InGameOverlayRendererAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/InGameOverlayRendererAccessor.java index 7a376cf..06ac512 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/InGameOverlayRendererAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/InGameOverlayRendererAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/InputAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/InputAccessor.java index d5fcbb6..0da9a36 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/InputAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/InputAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemCooldownEntryAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemCooldownEntryAccessor.java index 345633f..a2668f9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemCooldownEntryAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemCooldownEntryAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemCooldownManagerAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemCooldownManagerAccessor.java index a64d187..22bd61d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemCooldownManagerAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemCooldownManagerAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemRenderStateLayerAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemRenderStateLayerAccessor.java index 1628e69..7854b2e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemRenderStateLayerAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ItemRenderStateLayerAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LevelExtractorAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LevelExtractorAccessor.java index 93f6985..c181890 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LevelExtractorAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LevelExtractorAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,5 +17,5 @@ import org.spongepowered.asm.mixin.gen.Invoker; public interface LevelExtractorAccessor { @Invoker("extractEntity") - EntityRenderState combatant$invokeExtractEntity(Entity entity, float tickDelta); + EntityRenderState lovisual$invokeExtractEntity(Entity entity, float tickDelta); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LevelRendererAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LevelRendererAccessor.java index 4dba6e8..d3eb75e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LevelRendererAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LevelRendererAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -19,31 +19,31 @@ import org.spongepowered.asm.mixin.gen.Invoker; public interface LevelRendererAccessor { @Accessor("levelRenderState") - LevelRenderState combatant$getWorldRenderState(); + LevelRenderState lovisual$getWorldRenderState(); @Accessor("skyRenderer") - SkyRenderer combatant$getSkyRendering(); + SkyRenderer lovisual$getSkyRendering(); @Accessor("submitNodeStorage") - SubmitNodeStorage combatant$getEntityRenderCommandQueue(); + SubmitNodeStorage lovisual$getEntityRenderCommandQueue(); @Accessor("featureRenderDispatcher") - FeatureRenderDispatcher combatant$getEntityRenderDispatcher(); + FeatureRenderDispatcher lovisual$getEntityRenderDispatcher(); @Accessor("renderBuffers") - RenderBuffers combatant$getRenderBuffers(); + RenderBuffers lovisual$getRenderBuffers(); @Accessor("renderBuffers") - void combatant$setRenderBuffers(RenderBuffers renderBuffers); + void lovisual$setRenderBuffers(RenderBuffers renderBuffers); @Accessor("chunkLayerSampler") - GpuSampler combatant$getTerrainSampler(); + GpuSampler lovisual$getTerrainSampler(); @Accessor("chunkLayerSampler") - void combatant$setTerrainSampler(GpuSampler terrainSampler); + void lovisual$setTerrainSampler(GpuSampler terrainSampler); @Invoker("submitEntities") - void combatant$invokeSubmitEntities(com.mojang.blaze3d.vertex.PoseStack poseStack, + void lovisual$invokeSubmitEntities(com.mojang.blaze3d.vertex.PoseStack poseStack, LevelRenderState levelRenderState, SubmitNodeCollector collector); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LivingEntityAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LivingEntityAccessor.java index a6c52ab..627ef0a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LivingEntityAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LivingEntityAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,7 +20,7 @@ public interface LivingEntityAccessor { void setTicksSinceLastAttack(int ticks); @Accessor("noJumpDelay") - void combatant$setJumpingCooldown(int cooldown); + void lovisual$setJumpingCooldown(int cooldown); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LivingEntityRenderStateAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LivingEntityRenderStateAccessor.java index 546aadb..98dee98 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LivingEntityRenderStateAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LivingEntityRenderStateAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,11 +15,11 @@ import org.spongepowered.asm.mixin.gen.Accessor; public interface LivingEntityRenderStateAccessor { @Accessor("bodyRot") - void combatant$setBodyYaw(float bodyYaw); + void lovisual$setBodyYaw(float bodyYaw); @Accessor("yRot") - void combatant$setRelativeHeadYaw(float relativeHeadYaw); + void lovisual$setRelativeHeadYaw(float relativeHeadYaw); @Accessor("xRot") - void combatant$setPitch(float pitch); + void lovisual$setPitch(float pitch); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LocalPlayerAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LocalPlayerAccessor.java index 301498e..949592d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LocalPlayerAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/LocalPlayerAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,31 +20,31 @@ public interface LocalPlayerAccessor { Minecraft getClient(); @Accessor("portalEffectIntensity") - float combatant$getNauseaIntensity(); + float lovisual$getNauseaIntensity(); @Accessor("portalEffectIntensity") - void combatant$setNauseaIntensity(float value); + void lovisual$setNauseaIntensity(float value); @Accessor("oPortalEffectIntensity") - float combatant$getLastNauseaIntensity(); + float lovisual$getLastNauseaIntensity(); @Accessor("oPortalEffectIntensity") - void combatant$setLastNauseaIntensity(float value); + void lovisual$setLastNauseaIntensity(float value); @Accessor("positionReminder") - void combatant$setTicksSinceLastPositionPacketSent(int ticks); + void lovisual$setTicksSinceLastPositionPacketSent(int ticks); @Accessor("wasSprinting") - void combatant$setLastSprinting(boolean sprinting); + void lovisual$setLastSprinting(boolean sprinting); @Invoker("canStartSprinting") - boolean combatant$canStartSprinting(); + boolean lovisual$canStartSprinting(); @Invoker("shouldStopRunSprinting") - boolean combatant$shouldStopSprinting(); + boolean lovisual$shouldStopSprinting(); @Invoker("shouldStopSwimSprinting") - boolean combatant$shouldStopSwimSprinting(); + boolean lovisual$shouldStopSwimSprinting(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/MinecraftAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/MinecraftAccessor.java index b2c5a67..4d2e4be 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/MinecraftAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/MinecraftAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -31,56 +31,56 @@ import java.util.concurrent.CompletableFuture; public interface MinecraftAccessor { @Accessor("rightClickDelay") - int combatant$getItemUseCooldown(); + int lovisual$getItemUseCooldown(); @Accessor("rightClickDelay") - void combatant$setItemUseCooldown(int itemUseCooldown); + void lovisual$setItemUseCooldown(int itemUseCooldown); @Mutable @Accessor("user") - void combatant$setSession(User session); + void lovisual$setSession(User session); @Mutable @Accessor("services") - void combatant$setServices(Services services); + void lovisual$setServices(Services services); @Mutable @Accessor("profileFuture") - void combatant$setProfileFuture(CompletableFuture profileFuture); + void lovisual$setProfileFuture(CompletableFuture profileFuture); @Mutable @Accessor("userApiService") - void combatant$setUserApiService(UserApiService userApiService); + void lovisual$setUserApiService(UserApiService userApiService); @Mutable @Accessor("userPropertiesFuture") - void combatant$setUserPropertiesFuture(CompletableFuture userPropertiesFuture); + void lovisual$setUserPropertiesFuture(CompletableFuture userPropertiesFuture); @Mutable @Accessor("playerSocialManager") - void combatant$setPlayerSocialManager(PlayerSocialManager playerSocialManager); + void lovisual$setPlayerSocialManager(PlayerSocialManager playerSocialManager); @Accessor("remoteFriendListUpdateHandler") - RemoteFriendListUpdateHandler combatant$getRemoteFriendListUpdateHandler(); + RemoteFriendListUpdateHandler lovisual$getRemoteFriendListUpdateHandler(); @Mutable @Accessor("remoteFriendListUpdateHandler") - void combatant$setRemoteFriendListUpdateHandler(RemoteFriendListUpdateHandler remoteFriendListUpdateHandler); + void lovisual$setRemoteFriendListUpdateHandler(RemoteFriendListUpdateHandler remoteFriendListUpdateHandler); @Mutable @Accessor("telemetryManager") - void combatant$setTelemetryManager(ClientTelemetryManager telemetryManager); + void lovisual$setTelemetryManager(ClientTelemetryManager telemetryManager); @Mutable @Accessor("profileKeyPairManager") - void combatant$setProfileKeyPairManager(ProfileKeyPairManager profileKeyPairManager); + void lovisual$setProfileKeyPairManager(ProfileKeyPairManager profileKeyPairManager); @Mutable @Accessor("reportingContext") - void combatant$setReportingContext(ReportingContext reportingContext); + void lovisual$setReportingContext(ReportingContext reportingContext); @Invoker("createUserApiService") - static UserApiService combatant$createUserApiService(YggdrasilAuthenticationService service, GameConfig config) { + static UserApiService lovisual$createUserApiService(YggdrasilAuthenticationService service, GameConfig config) { throw new AssertionError(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/MultiPlayerGameModeAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/MultiPlayerGameModeAccessor.java index a690840..6b559a8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/MultiPlayerGameModeAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/MultiPlayerGameModeAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,26 +17,26 @@ import org.spongepowered.asm.mixin.gen.Invoker; public interface MultiPlayerGameModeAccessor { @Accessor("destroyBlockPos") - BlockPos combatant$getCurrentBreakingPos(); + BlockPos lovisual$getCurrentBreakingPos(); @Accessor("destroyProgress") - float combatant$getCurrentBreakingProgress(); + float lovisual$getCurrentBreakingProgress(); @Accessor("destroyProgress") - void combatant$setCurrentBreakingProgress(float progress); + void lovisual$setCurrentBreakingProgress(float progress); @Accessor("destroyDelay") - int combatant$getBlockBreakingCooldown(); + int lovisual$getBlockBreakingCooldown(); @Accessor("destroyDelay") - void combatant$setBlockBreakingCooldown(int cooldown); + void lovisual$setBlockBreakingCooldown(int cooldown); @Accessor("carriedIndex") - int combatant$getLastSelectedSlot(); + int lovisual$getLastSelectedSlot(); @Accessor("carriedIndex") - void combatant$setLastSelectedSlot(int slot); + void lovisual$setLastSelectedSlot(int slot); @Invoker("ensureHasSentCarriedItem") - void combatant$syncSelectedSlot(); + void lovisual$syncSelectedSlot(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PersistentProjectileEntityAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PersistentProjectileEntityAccessor.java index a2a141b..5147a82 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PersistentProjectileEntityAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PersistentProjectileEntityAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(AbstractArrow.class) public interface PersistentProjectileEntityAccessor { @Invoker("isInGround") - boolean combatant$isInGround(); + boolean lovisual$isInGround(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PlayerInventoryAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PlayerInventoryAccessor.java index 0fd7043..4a2b16e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PlayerInventoryAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PlayerInventoryAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,10 +14,10 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(Inventory.class) public interface PlayerInventoryAccessor { @Accessor("selected") - int combatant$getSelectedSlot(); + int lovisual$getSelectedSlot(); @Accessor("selected") - void combatant$setSelectedSlot(int slot); + void lovisual$setSelectedSlot(int slot); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PlayerTabOverlayAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PlayerTabOverlayAccessor.java index fa1371c..92f689b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PlayerTabOverlayAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/PlayerTabOverlayAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,8 +15,8 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(PlayerTabOverlay.class) public interface PlayerTabOverlayAccessor { @Accessor("header") - Component combatant$getHeader(); + Component lovisual$getHeader(); @Accessor("footer") - Component combatant$getFooter(); + Component lovisual$getFooter(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/RenderLayerInvokerAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/RenderLayerInvokerAccessor.java index 7a0389b..e79b0b4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/RenderLayerInvokerAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/RenderLayerInvokerAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ServerboundInteractPacketAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ServerboundInteractPacketAccessor.java index 5e2f2dd..f0cef6a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ServerboundInteractPacketAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ServerboundInteractPacketAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,5 +14,5 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(ServerboundInteractPacket.class) public interface ServerboundInteractPacketAccessor { @Accessor("entityId") - int combatant$getEntityId(); + int lovisual$getEntityId(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ServerboundMovePlayerPacketAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ServerboundMovePlayerPacketAccessor.java index 3b1e587..a7e42ae 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ServerboundMovePlayerPacketAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ServerboundMovePlayerPacketAccessor.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -22,17 +22,17 @@ import org.spongepowered.asm.mixin.gen.Accessor; public interface ServerboundMovePlayerPacketAccessor { @Mutable @Accessor("x") - void combatant$setX(double x); + void lovisual$setX(double x); @Mutable @Accessor("y") - void combatant$setY(double y); + void lovisual$setY(double y); @Mutable @Accessor("z") - void combatant$setZ(double z); + void lovisual$setZ(double z); @Mutable @Accessor("onGround") - void combatant$setOnGround(boolean onGround); + void lovisual$setOnGround(boolean onGround); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ShaderLoaderDefinitionsAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ShaderLoaderDefinitionsAccessor.java index 031b4ab..3612595 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ShaderLoaderDefinitionsAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ShaderLoaderDefinitionsAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -18,8 +18,8 @@ import java.util.Map; @Mixin(ShaderManager.Configs.class) public interface ShaderLoaderDefinitionsAccessor { @Accessor("shaderSources") - Map combatant$getShaderSources(); + Map lovisual$getShaderSources(); @Accessor("postChains") - Map combatant$getPostChains(); + Map lovisual$getPostChains(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ShaderSourceKeyAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ShaderSourceKeyAccessor.java index 0fc454d..2d913d2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ShaderSourceKeyAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/ShaderSourceKeyAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,8 +15,8 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(targets = "net.minecraft.client.renderer.ShaderManager$ShaderSourceKey") public interface ShaderSourceKeyAccessor { @Accessor("id") - Identifier combatant$getId(); + Identifier lovisual$getId(); @Accessor("type") - ShaderType combatant$getType(); + ShaderType lovisual$getType(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SliderWidgetAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SliderWidgetAccessor.java index 9bceeed..d26ddc6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SliderWidgetAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SliderWidgetAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,10 +14,10 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(AbstractSliderButton.class) public interface SliderWidgetAccessor { @Accessor("value") - double combatant$getValue(); + double lovisual$getValue(); @Accessor("dragging") - boolean combatant$isDragging(); + boolean lovisual$isDragging(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SlotAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SlotAccessor.java index c3a1efe..e5f8383 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SlotAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SlotAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,5 +14,5 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(Slot.class) public interface SlotAccessor { @Accessor("slot") - int combatant$getIndex(); + int lovisual$getIndex(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SuggestionWindowAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SuggestionWindowAccessor.java index 9572f9a..60ad85a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SuggestionWindowAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/SuggestionWindowAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,22 +17,22 @@ import java.util.List; @Mixin(CommandSuggestions.SuggestionsList.class) public interface SuggestionWindowAccessor { @Accessor("rect") - Rect2i getCombatant$area(); + Rect2i getLoVisual$area(); @Accessor("suggestionList") - List getCombatant$suggestions(); + List getLoVisual$suggestions(); @Accessor("current") - int getCombatant$selection(); + int getLoVisual$selection(); @Accessor("current") - void setCombatant$selection(int selection); + void setLoVisual$selection(int selection); @Accessor("offset") - int getCombatant$inWindowIndex(); + int getLoVisual$inWindowIndex(); @Accessor("offset") - void setCombatant$inWindowIndex(int index); + void setLoVisual$inWindowIndex(int index); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/TextFieldWidgetAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/TextFieldWidgetAccessor.java index c4ba90f..e1aa489 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/TextFieldWidgetAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/TextFieldWidgetAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,8 +14,8 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(EditBox.class) public interface TextFieldWidgetAccessor { @Accessor("cursorPos") - int combatant$getSelectionStart(); + int lovisual$getSelectionStart(); @Accessor("highlightPos") - int combatant$getSelectionEnd(); + int lovisual$getSelectionEnd(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/TextIconButtonWidgetAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/TextIconButtonWidgetAccessor.java index 1d220f6..0ff6605 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/TextIconButtonWidgetAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/TextIconButtonWidgetAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,13 +15,13 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(SpriteIconButton.class) public interface TextIconButtonWidgetAccessor { @Accessor("spriteWidth") - int combatant$getTextureWidth(); + int lovisual$getTextureWidth(); @Accessor("spriteHeight") - int combatant$getTextureHeight(); + int lovisual$getTextureHeight(); @Accessor("sprite") - WidgetSprites combatant$getTexture(); + WidgetSprites lovisual$getTexture(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/WorldAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/WorldAccessor.java index 14a3835..e3ae689 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/WorldAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/accessors/WorldAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,19 +15,19 @@ import org.spongepowered.asm.mixin.gen.Accessor; public interface WorldAccessor { @Accessor("isClientSide") - boolean combatant$isClient(); + boolean lovisual$isClient(); @Accessor("rainLevel") - float combatant$getRainGradientRaw(); + float lovisual$getRainGradientRaw(); @Accessor("oRainLevel") - float combatant$getLastRainGradientRaw(); + float lovisual$getLastRainGradientRaw(); @Accessor("thunderLevel") - float combatant$getThunderGradientRaw(); + float lovisual$getThunderGradientRaw(); @Accessor("oThunderLevel") - float combatant$getLastThunderGradientRaw(); + float lovisual$getLastThunderGradientRaw(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisCommonUniformsMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisCommonUniformsMixin.java index 0a38aa5..f32b28d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisCommonUniformsMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisCommonUniformsMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,17 +16,17 @@ import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import dev.loki.lovisual.render.iris.CombatantIrisUniforms; +import dev.loki.lovisual.render.iris.LoVisualIrisUniforms; @Pseudo @Mixin(targets = "net.irisshaders.iris.uniforms.CommonUniforms", remap = false) public abstract class IrisCommonUniformsMixin { @Inject(method = "addNonDynamicUniforms", at = @At("TAIL"), remap = false) - private static void combatant$addCombatantUniforms(UniformHolder uniforms, + private static void lovisual$addLoVisualUniforms(UniformHolder uniforms, IdMap idMap, PackDirectives packDirectives, FrameUpdateNotifier updateNotifier, CallbackInfo ci) { - CombatantIrisUniforms.add(uniforms); + LoVisualIrisUniforms.add(uniforms); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisGameRendererInteropMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisGameRendererInteropMixin.java index 530de02..41381ff 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisGameRendererInteropMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisGameRendererInteropMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import dev.loki.lovisual.render.iris.IrisCombatantFrameHooks; +import dev.loki.lovisual.render.iris.IrisLoVisualFrameHooks; import dev.loki.lovisual.render.iris.IrisSecondHandScene; @Mixin(value = GameRenderer.class, priority = 900) @@ -26,9 +26,9 @@ public abstract class IrisGameRendererInteropMixin { shift = At.Shift.BEFORE ) ) - private void combatant$renderIrisHandInSecondScene(DeltaTracker tickCounter, CallbackInfo ci) { + private void lovisual$renderIrisHandInSecondScene(DeltaTracker tickCounter, CallbackInfo ci) { IrisSecondHandScene.finalizeWorld(); - IrisCombatantFrameHooks.renderAfterIrisFinalization(); + IrisLoVisualFrameHooks.renderAfterIrisFinalization(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisHandRendererAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisHandRendererAccessor.java index 53ec095..022067c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisHandRendererAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisHandRendererAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -21,10 +21,10 @@ import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(value = HandRenderer.class, remap = false) public interface IrisHandRendererAccessor { @Accessor(value = "renderingSolid", remap = false) - void combatant$setRenderingSolid(boolean renderingSolid); + void lovisual$setRenderingSolid(boolean renderingSolid); @Invoker(value = "setupGlState", remap = false) - PoseStack combatant$invokeSetupGlState(GameRenderer renderer, + PoseStack lovisual$invokeSetupGlState(GameRenderer renderer, CameraRenderState cameraRenderState, Matrix4fc positionMatrix, float tickDelta); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisHandRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisHandRendererMixin.java index a0215e7..d9ffc11 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisHandRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisHandRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,7 +25,7 @@ import dev.loki.lovisual.render.iris.IrisSecondHandScene; @Mixin(value = HandRenderer.class, remap = false) public abstract class IrisHandRendererMixin { @Inject(method = "renderSolid", at = @At("HEAD"), cancellable = true, remap = false) - private void combatant$disableIrisSolidHand(Matrix4fc modelMatrix, + private void lovisual$disableIrisSolidHand(Matrix4fc modelMatrix, float tickDelta, Camera camera, CameraRenderState cameraRenderState, @@ -38,7 +38,7 @@ public abstract class IrisHandRendererMixin { } @Inject(method = "renderTranslucent", at = @At("HEAD"), cancellable = true, remap = false) - private void combatant$disableIrisTranslucentHand(Matrix4fc modelMatrix, + private void lovisual$disableIrisTranslucentHand(Matrix4fc modelMatrix, float tickDelta, Camera camera, CameraRenderState cameraRenderState, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisIncludeProcessorMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisIncludeProcessorMixin.java index 0f3fff1..bff4605 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisIncludeProcessorMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisIncludeProcessorMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,12 +25,12 @@ import java.util.Objects; @Mixin(value = IncludeProcessor.class, remap = false) public abstract class IrisIncludeProcessorMixin { @Unique - private ShaderPatchEngine.Session combatant$patchSession; + private ShaderPatchEngine.Session lovisual$patchSession; @Unique - private String combatant$patchSessionPackName; + private String lovisual$patchSessionPackName; @Unique - private static String combatant$currentShaderPackName() { + private static String lovisual$currentShaderPackName() { String loadingPackName = ShaderPatchEngine.loadingShaderPackName(); if (loadingPackName != null && !loadingPackName.isBlank()) { return loadingPackName; @@ -44,27 +44,27 @@ public abstract class IrisIncludeProcessorMixin { } @ModifyReturnValue(method = "getIncludedFile", at = @At("RETURN"), remap = false) - private ImmutableList combatant$compileShaderpackPatch(ImmutableList lines, AbsolutePackPath path) { + private ImmutableList lovisual$compileShaderpackPatch(ImmutableList lines, AbsolutePackPath path) { if (lines == null || path == null) { return lines; } - String packName = combatant$currentShaderPackName(); - if (combatant$patchSession == null || !Objects.equals(packName, combatant$patchSessionPackName)) { - combatant$patchSessionPackName = packName; - combatant$patchSession = ShaderPatchEngine.newSession(packName); + String packName = lovisual$currentShaderPackName(); + if (lovisual$patchSession == null || !Objects.equals(packName, lovisual$patchSessionPackName)) { + lovisual$patchSessionPackName = packName; + lovisual$patchSession = ShaderPatchEngine.newSession(packName); DebugLog.info("[IrisPatch] IncludeProcessor hook active: shaderPack='%s' active=%s firstPath=%s", packName == null ? "" : packName, - combatant$patchSession.isActive(), + lovisual$patchSession.isActive(), path.getPathString()); } - if (!combatant$patchSession.isActive()) { + if (!lovisual$patchSession.isActive()) { return lines; } IncludeProcessor processor = (IncludeProcessor) (Object) this; - return combatant$patchSession.patch( + return lovisual$patchSession.patch( path.getPathString(), lines, candidate -> processor.getIncludedFile(AbsolutePackPath.fromAbsolutePath(candidate)) diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisRenderingPipelineFinalizeMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisRenderingPipelineFinalizeMixin.java index 7a6ace0..65d3870 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisRenderingPipelineFinalizeMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisRenderingPipelineFinalizeMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,7 +17,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.loki.lovisual.render.engine.depth.PreTranslucentDepth; -import dev.loki.lovisual.render.iris.IrisCombatantFrameHooks; +import dev.loki.lovisual.render.iris.IrisLoVisualFrameHooks; import dev.loki.lovisual.render.iris.IrisSceneDepth; @Pseudo @@ -28,27 +28,27 @@ public abstract class IrisRenderingPipelineFinalizeMixin { private RenderTargets renderTargets; @Inject(method = "beginLevelRendering", at = @At("HEAD"), remap = false) - private void combatant$resetIrisSceneDepth(CallbackInfo ci) { + private void lovisual$resetIrisSceneDepth(CallbackInfo ci) { IrisSceneDepth.resetFrame(); } @Inject(method = "beginTranslucents", at = @At("HEAD"), remap = false) - private void combatant$capturePreTranslucentDepth(CallbackInfo ci) { + private void lovisual$capturePreTranslucentDepth(CallbackInfo ci) { PreTranslucentDepth.capture(); } @Inject(method = "finalizeLevelRendering", at = @At("HEAD"), remap = false) - private void combatant$captureIrisSceneBeforeFinalPass(CallbackInfo ci) { + private void lovisual$captureIrisSceneBeforeFinalPass(CallbackInfo ci) { IrisSceneDepth.capture(renderTargets); } @Inject(method = "finalizeLevelRendering", at = @At("TAIL"), remap = false) - private void combatant$renderAfterIrisFinalPass(CallbackInfo ci) { - IrisCombatantFrameHooks.renderAfterIrisFinalization(); + private void lovisual$renderAfterIrisFinalPass(CallbackInfo ci) { + IrisLoVisualFrameHooks.renderAfterIrisFinalization(); } @Inject(method = "destroy", at = @At("HEAD"), remap = false) - private void combatant$shutdownDepth(CallbackInfo ci) { + private void lovisual$shutdownDepth(CallbackInfo ci) { IrisSceneDepth.shutdown(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisShaderPackLoadMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisShaderPackLoadMixin.java index 389df43..555c2b7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisShaderPackLoadMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisShaderPackLoadMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -19,12 +19,12 @@ import dev.loki.lovisual.render.iris.patch.ShaderPatchEngine; @Mixin(value = Iris.class, remap = false) public abstract class IrisShaderPackLoadMixin { @Inject(method = "loadExternalShaderpack", at = @At("HEAD"), remap = false) - private static void combatant$beginShaderPatchSession(String shaderPackName, CallbackInfoReturnable cir) { + private static void lovisual$beginShaderPatchSession(String shaderPackName, CallbackInfoReturnable cir) { ShaderPatchEngine.beginShaderPackLoad(shaderPackName); } @Inject(method = "loadExternalShaderpack", at = @At("RETURN"), remap = false) - private static void combatant$endShaderPatchSession(String shaderPackName, CallbackInfoReturnable cir) { + private static void lovisual$endShaderPatchSession(String shaderPackName, CallbackInfoReturnable cir) { ShaderPatchEngine.endShaderPackLoad(shaderPackName); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisVanillaHandInteropMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisVanillaHandInteropMixin.java index 2a22343..2379d05 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisVanillaHandInteropMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/iris/IrisVanillaHandInteropMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -31,7 +31,7 @@ public abstract class IrisVanillaHandInteropMixin { remap = false ) ) - private void combatant$renderHandInFinalScene(CameraRenderState cameraRenderState, + private void lovisual$renderHandInFinalScene(CameraRenderState cameraRenderState, float tickProgress, Matrix4fc positionMatrix, CallbackInfo ci) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/moreculling/CullingUtilsMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/moreculling/CullingUtilsMixin.java index 086c411..c169a65 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/moreculling/CullingUtilsMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/moreculling/CullingUtilsMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,21 +23,21 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; public abstract class CullingUtilsMixin { @Inject(method = "shouldCullBack", at = @At("HEAD"), cancellable = true, remap = false) - private static void combatant$shaderEspKeepsItemFrameBack(ItemFrameRenderState state, CallbackInfoReturnable cir) { + private static void lovisual$shaderEspKeepsItemFrameBack(ItemFrameRenderState state, CallbackInfoReturnable cir) { if (ShaderEspRenderContext.isActive()) { cir.setReturnValue(false); } } @Inject(method = "shouldShowMapFace", at = @At("HEAD"), cancellable = true, remap = false) - private static void combatant$shaderEspKeepsMapFace(Direction direction, ItemFrameRenderState state, Vec3 cameraPos, CallbackInfoReturnable cir) { + private static void lovisual$shaderEspKeepsMapFace(Direction direction, ItemFrameRenderState state, Vec3 cameraPos, CallbackInfoReturnable cir) { if (ShaderEspRenderContext.isActive()) { cir.setReturnValue(true); } } @Inject(method = "shouldCullPaintingBack", at = @At("HEAD"), cancellable = true, remap = false) - private static void combatant$shaderEspKeepsPaintingBack(BlockPos pos, Direction direction, CallbackInfoReturnable cir) { + private static void lovisual$shaderEspKeepsPaintingBack(BlockPos pos, Direction direction, CallbackInfoReturnable cir) { if (ShaderEspRenderContext.isActive()) { cir.setReturnValue(false); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/AbstractSignEditScreenMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/AbstractSignEditScreenMixin.java index c1a0bd9..74b032f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/AbstractSignEditScreenMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/AbstractSignEditScreenMixin.java @@ -1,12 +1,12 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on ExploitPreventer. * Original work copyright (c) 2025 Niklas S. * * Original portions remain under the MIT License. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -41,7 +41,7 @@ public abstract class AbstractSignEditScreenMixin { method = "(Lnet/minecraft/world/level/block/entity/SignBlockEntity;ZZLnet/minecraft/network/chat/Component;)V", at = @At("RETURN") ) - private void combatant$backdoor$filterSignMessages(SignBlockEntity blockEntity, boolean front, boolean filtered, Component title, CallbackInfo ci) { + private void lovisual$backdoor$filterSignMessages(SignBlockEntity blockEntity, boolean front, boolean filtered, Component title, CallbackInfo ci) { for (int line = 0; line < this.messages.length; line++) { Component safeText = BackdoorProtection.filterText(this.text.getMessage(line, filtered)); this.messages[line] = safeText.getString(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/AnvilScreenMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/AnvilScreenMixin.java index a192f51..e5c3fe6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/AnvilScreenMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/AnvilScreenMixin.java @@ -1,12 +1,12 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on ExploitPreventer. * Original work copyright (c) 2025 Niklas S. * * Original portions remain under the MIT License. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -30,12 +30,12 @@ import dev.loki.lovisual.features.security.BackdoorProtection; public abstract class AnvilScreenMixin { @WrapOperation(method = "onNameChanged", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getHoverName()Lnet/minecraft/network/chat/Component;")) - private Component combatant$backdoor$filterRenameName(ItemStack stack, Operation original) { + private Component lovisual$backdoor$filterRenameName(ItemStack stack, Operation original) { return BackdoorProtection.filterText(original.call(stack)); } @WrapOperation(method = "slotChanged", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getHoverName()Lnet/minecraft/network/chat/Component;")) - private Component combatant$backdoor$filterSlotUpdateName(ItemStack stack, Operation original) { + private Component lovisual$backdoor$filterSlotUpdateName(ItemStack stack, Operation original) { return BackdoorProtection.filterText(original.call(stack)); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/ClientLoginNetworkHandlerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/ClientLoginNetworkHandlerMixin.java index 1abdc3f..6d6b418 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/ClientLoginNetworkHandlerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/ClientLoginNetworkHandlerMixin.java @@ -1,12 +1,12 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on ExploitPreventer. * Original work copyright (c) 2025 Niklas S. * * Original portions remain under the MIT License. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -36,7 +36,7 @@ public abstract class ClientLoginNetworkHandlerMixin { private Connection connection; @Inject(method = "handleLoginFinished", at = @At("HEAD")) - private void combatant$backdoor$captureServerConnection(ClientboundLoginFinishedPacket packet, CallbackInfo ci) { + private void lovisual$backdoor$captureServerConnection(ClientboundLoginFinishedPacket packet, CallbackInfo ci) { BackdoorProtection.updateServerConnection(connection); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/GameOptionsMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/GameOptionsMixin.java index ed507f3..3678a4e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/GameOptionsMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/GameOptionsMixin.java @@ -1,12 +1,12 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on ExploitPreventer. * Original work copyright (c) 2025 Niklas S. * * Original portions remain under the MIT License. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -38,7 +38,7 @@ public abstract class GameOptionsMixin { public KeyMapping[] keyMappings; @Inject(method = "(Lnet/minecraft/client/Minecraft;Ljava/io/File;)V", at = @At("TAIL")) - private void combatant$backdoor$registerVanillaKeybinds(Minecraft client, File optionsFile, CallbackInfo ci) { + private void lovisual$backdoor$registerVanillaKeybinds(Minecraft client, File optionsFile, CallbackInfo ci) { BackdoorProtection.resetVanillaKeybinds(); for (KeyMapping keyBinding : keyMappings) { BackdoorProtection.registerVanillaKeybind(keyBinding.getName()); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/NetworkUtilsMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/NetworkUtilsMixin.java index bdd3f23..c512a9c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/NetworkUtilsMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/NetworkUtilsMixin.java @@ -1,12 +1,12 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on ExploitPreventer. * Original work copyright (c) 2025 Niklas S. * * Original portions remain under the MIT License. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -40,12 +40,12 @@ import java.util.Map; public abstract class NetworkUtilsMixin { @ModifyVariable(method = "downloadFile", at = @At("HEAD"), argsOnly = true, ordinal = 0) - private static Path combatant$backdoor$isolatePackCache(Path original) { + private static Path lovisual$backdoor$isolatePackCache(Path original) { return BackdoorProtection.isolatePackCachePath(original); } @WrapOperation(method = "downloadFile", at = @At(value = "INVOKE", target = "Ljava/net/HttpURLConnection;getInputStream()Ljava/io/InputStream;")) - private static InputStream combatant$backdoor$guardLocalRedirects( + private static InputStream lovisual$backdoor$guardLocalRedirects( HttpURLConnection connection, Operation original, @Local(argsOnly = true) Map headers, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/TranslatableTextContentMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/TranslatableTextContentMixin.java index dfa5b7e..c6cf55d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/TranslatableTextContentMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/TranslatableTextContentMixin.java @@ -1,12 +1,12 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on ExploitPreventer. * Original work copyright (c) 2025 Niklas S. * * Original portions remain under the MIT License. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -29,7 +29,7 @@ import dev.loki.lovisual.features.security.FilteredTranslatableTextContent; public abstract class TranslatableTextContentMixin { @WrapOperation(method = "decompose", at = @At(value = "INVOKE", target = "Lnet/minecraft/locale/Language;getOrDefault(Ljava/lang/String;)Ljava/lang/String;")) - private String combatant$backdoor$resolveNoFallback(Language language, String key, Operation original) { + private String lovisual$backdoor$resolveNoFallback(Language language, String key, Operation original) { if ((Object) this instanceof FilteredTranslatableTextContent filtered && filtered.getResolved() != null) { return filtered.getResolved(); } @@ -37,7 +37,7 @@ public abstract class TranslatableTextContentMixin { } @WrapOperation(method = "decompose", at = @At(value = "INVOKE", target = "Lnet/minecraft/locale/Language;getOrDefault(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) - private String combatant$backdoor$resolveFallback(Language language, String key, String fallback, Operation original) { + private String lovisual$backdoor$resolveFallback(Language language, String key, String fallback, Operation original) { if ((Object) this instanceof FilteredTranslatableTextContent filtered && filtered.getResolved() != null) { return filtered.getResolved(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/TranslationStorageMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/TranslationStorageMixin.java index 0a62866..219d04b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/TranslationStorageMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/security/TranslationStorageMixin.java @@ -1,12 +1,12 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on ExploitPreventer. * Original work copyright (c) 2025 Niklas S. * * Original portions remain under the MIT License. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -37,7 +37,7 @@ import java.util.function.BiConsumer; public abstract class TranslationStorageMixin { @Inject(method = "loadFrom(Lnet/minecraft/server/packs/resources/ResourceManager;Ljava/util/List;Z)Lnet/minecraft/client/resources/language/ClientLanguage;", at = @At("HEAD")) - private static void combatant$backdoor$resetLoadedTranslations(ResourceManager resourceManager, List definitions, boolean rightToLeft, CallbackInfoReturnable cir) { + private static void lovisual$backdoor$resetLoadedTranslations(ResourceManager resourceManager, List definitions, boolean rightToLeft, CallbackInfoReturnable cir) { BackdoorProtection.resetLoadedTranslations(); } @@ -45,7 +45,7 @@ public abstract class TranslationStorageMixin { method = "appendFrom(Ljava/lang/String;Ljava/util/List;Ljava/util/Map;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/locale/Language;loadFromJson(Ljava/io/InputStream;Ljava/util/function/BiConsumer;)V") ) - private static void combatant$backdoor$captureTranslations( + private static void lovisual$backdoor$captureTranslations( InputStream inputStream, BiConsumer consumer, Operation original, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumBlockRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumBlockRendererMixin.java index 89502ec..09564f9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumBlockRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumBlockRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -21,19 +21,19 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.loki.lovisual.render.helpers.SodiumSurfaceFlagContext; -import dev.loki.lovisual.render.sodium.terrain.CombatantChunkVertexExtension; +import dev.loki.lovisual.render.sodium.terrain.LoVisualChunkVertexExtension; @Pseudo @Mixin(targets = "net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderer") public abstract class SodiumBlockRendererMixin { @Inject(method = "renderModel", at = @At("HEAD"), remap = false) - private void combatant$pushSurfaceState(BlockStateModel model, BlockState state, BlockPos pos, BlockPos origin, CallbackInfo ci) { + private void lovisual$pushSurfaceState(BlockStateModel model, BlockState state, BlockPos pos, BlockPos origin, CallbackInfo ci) { SodiumSurfaceFlagContext.pushForState(state, origin); } @Inject(method = "renderModel", at = @At("RETURN"), remap = false) - private void combatant$popSurfaceState(BlockStateModel model, BlockState state, BlockPos pos, BlockPos origin, CallbackInfo ci) { + private void lovisual$popSurfaceState(BlockStateModel model, BlockState state, BlockPos pos, BlockPos origin, CallbackInfo ci) { SodiumSurfaceFlagContext.pop(); } @@ -46,7 +46,7 @@ public abstract class SodiumBlockRendererMixin { shift = At.Shift.AFTER), remap = false ) - private void combatant$writeSurfaceFlags(MutableQuadViewImpl quad, float[] brightness, Material material, CallbackInfo ci, @Local(ordinal = 0) ChunkVertexEncoder.Vertex vertex) { - ((CombatantChunkVertexExtension) vertex).combatant$setSurfaceFlags(SodiumSurfaceFlagContext.getSurfaceFlags(vertex.y)); + private void lovisual$writeSurfaceFlags(MutableQuadViewImpl quad, float[] brightness, Material material, CallbackInfo ci, @Local(ordinal = 0) ChunkVertexEncoder.Vertex vertex) { + ((LoVisualChunkVertexExtension) vertex).lovisual$setSurfaceFlags(SodiumSurfaceFlagContext.getSurfaceFlags(vertex.y)); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumBlockVisibilityMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumBlockVisibilityMixin.java index 05ae9a1..23a5347 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumBlockVisibilityMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumBlockVisibilityMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -26,31 +26,31 @@ import java.util.ArrayDeque; @Mixin(targets = "net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderer") public abstract class SodiumBlockVisibilityMixin { @Unique - private static final ThreadLocal> COMBATANT_BLOCK_STACK = + private static final ThreadLocal> LOVISUAL_BLOCK_STACK = ThreadLocal.withInitial(ArrayDeque::new); @Inject(method = "renderModel", at = @At("HEAD"), remap = false) - private void combatant$pushRenderedBlock(BlockStateModel model, BlockState state, BlockPos pos, BlockPos origin, CallbackInfo ci) { - COMBATANT_BLOCK_STACK.get().addLast(new RenderedBlock(pos, state)); + private void lovisual$pushRenderedBlock(BlockStateModel model, BlockState state, BlockPos pos, BlockPos origin, CallbackInfo ci) { + LOVISUAL_BLOCK_STACK.get().addLast(new RenderedBlock(pos, state)); } @Inject(method = "renderModel", at = @At("RETURN"), remap = false) - private void combatant$popRenderedBlock(BlockStateModel model, BlockState state, BlockPos pos, BlockPos origin, CallbackInfo ci) { - ArrayDeque stack = COMBATANT_BLOCK_STACK.get(); + private void lovisual$popRenderedBlock(BlockStateModel model, BlockState state, BlockPos pos, BlockPos origin, CallbackInfo ci) { + ArrayDeque stack = LOVISUAL_BLOCK_STACK.get(); if (!stack.isEmpty()) { stack.removeLast(); } if (stack.isEmpty()) { - COMBATANT_BLOCK_STACK.remove(); + LOVISUAL_BLOCK_STACK.remove(); } } @Inject(method = "bufferQuad", at = @At("HEAD"), remap = false) - private void combatant$observeBufferedQuad(MutableQuadViewImpl quad, + private void lovisual$observeBufferedQuad(MutableQuadViewImpl quad, float[] brightness, Material material, CallbackInfo ci) { - ArrayDeque stack = COMBATANT_BLOCK_STACK.get(); + ArrayDeque stack = LOVISUAL_BLOCK_STACK.get(); if (stack.isEmpty()) { return; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkBuilderMeshingTaskMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkBuilderMeshingTaskMixin.java index 3912a80..d571b99 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkBuilderMeshingTaskMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkBuilderMeshingTaskMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -25,7 +25,7 @@ public abstract class SodiumChunkBuilderMeshingTaskMixin { ordinal = 0, remap = false ) - private BlockState combatant$captureSodiumSectionBlock(BlockState state, + private BlockState lovisual$captureSodiumSectionBlock(BlockState state, @Local(index = 22) int x, @Local(index = 20) int y, @Local(index = 21) int z) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkMeshFormatsMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkMeshFormatsMixin.java index 9cce6af..b473901 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkMeshFormatsMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkMeshFormatsMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,7 +7,7 @@ package dev.loki.lovisual.mixins.sodium; -import dev.loki.lovisual.render.sodium.terrain.CombatantChunkMeshFormats; +import dev.loki.lovisual.render.sodium.terrain.LoVisualChunkMeshFormats; import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import org.spongepowered.asm.mixin.Mixin; @@ -18,12 +18,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; /** * Sodium 0.9.1 routes the vertex format used by the renderer, builder and * region arenas through this method. Replacing it here keeps all three users - * on Combatant's extended 24-byte layout. + * on LoVisual's extended 24-byte layout. */ @Mixin(ChunkMeshFormats.class) public abstract class SodiumChunkMeshFormatsMixin { @Inject(method = "getCurrent", at = @At("HEAD"), cancellable = true, remap = false) - private static void combatant$useExtendedVertexFormat(CallbackInfoReturnable cir) { - cir.setReturnValue(CombatantChunkMeshFormats.SURFACE_FLAGS); + private static void lovisual$useExtendedVertexFormat(CallbackInfoReturnable cir) { + cir.setReturnValue(LoVisualChunkMeshFormats.SURFACE_FLAGS); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkVertexMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkVertexMixin.java index 1b49b14..fedca75 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkVertexMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumChunkVertexMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,30 +13,30 @@ import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import dev.loki.lovisual.render.sodium.terrain.CombatantChunkVertexExtension; +import dev.loki.lovisual.render.sodium.terrain.LoVisualChunkVertexExtension; @Mixin(ChunkVertexEncoder.Vertex.class) -public abstract class SodiumChunkVertexMixin implements CombatantChunkVertexExtension { +public abstract class SodiumChunkVertexMixin implements LoVisualChunkVertexExtension { @Unique - private int combatant$surfaceFlags; + private int lovisual$surfaceFlags; @Inject(method = "copyVertexTo", at = @At("HEAD")) - private static void combatant$copyVertexData(ChunkVertexEncoder.Vertex from, ChunkVertexEncoder.Vertex to, CallbackInfo ci) { - ((CombatantChunkVertexExtension) from).combatant$copyData((CombatantChunkVertexExtension) to); + private static void lovisual$copyVertexData(ChunkVertexEncoder.Vertex from, ChunkVertexEncoder.Vertex to, CallbackInfo ci) { + ((LoVisualChunkVertexExtension) from).lovisual$copyData((LoVisualChunkVertexExtension) to); } @Override - public void combatant$setSurfaceFlags(int surfaceFlags) { - this.combatant$surfaceFlags = surfaceFlags; + public void lovisual$setSurfaceFlags(int surfaceFlags) { + this.lovisual$surfaceFlags = surfaceFlags; } @Override - public int combatant$getSurfaceFlags() { - return this.combatant$surfaceFlags; + public int lovisual$getSurfaceFlags() { + return this.lovisual$surfaceFlags; } @Override - public void combatant$copyData(CombatantChunkVertexExtension dest) { - dest.combatant$setSurfaceFlags(this.combatant$surfaceFlags); + public void lovisual$copyData(LoVisualChunkVertexExtension dest) { + dest.lovisual$setSurfaceFlags(this.lovisual$surfaceFlags); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumShaderChunkRendererMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumShaderChunkRendererMixin.java index 8ad3209..5e6b5d0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumShaderChunkRendererMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumShaderChunkRendererMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,12 +12,12 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyArg; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; /** * Sodium 26.2 builds terrain shaders as Mojang RenderPipeline objects. * The old ShaderLoader/DefaultShaderInterface/GlUniform path no longer exists, - * so Combatant overrides the pipeline shader ids and keeps the shader resources + * so LoVisual overrides the pipeline shader ids and keeps the shader resources * in vanilla .vsh/.fsh form. */ @Pseudo @@ -31,8 +31,8 @@ public abstract class SodiumShaderChunkRendererMixin { ), index = 0 ) - private Identifier combatant$useCombatantSodiumVertexShader(Identifier original) { - return CombatantRenderSystem.sodium().shaderWorkarounds().overrideShaderIdentifier(original); + private Identifier lovisual$useLoVisualSodiumVertexShader(Identifier original) { + return LoVisualRenderSystem.sodium().shaderWorkarounds().overrideShaderIdentifier(original); } @ModifyArg( @@ -43,7 +43,7 @@ public abstract class SodiumShaderChunkRendererMixin { ), index = 0 ) - private Identifier combatant$useCombatantSodiumFragmentShader(Identifier original) { - return CombatantRenderSystem.sodium().shaderWorkarounds().overrideShaderIdentifier(original); + private Identifier lovisual$useLoVisualSodiumFragmentShader(Identifier original) { + return LoVisualRenderSystem.sodium().shaderWorkarounds().overrideShaderIdentifier(original); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumVertexConsumerTrackerMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumVertexConsumerTrackerMixin.java index 70eecdf..2e0a977 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumVertexConsumerTrackerMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumVertexConsumerTrackerMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -27,12 +27,12 @@ public abstract class SodiumVertexConsumerTrackerMixin { ), remap = false ) - private static void combatant$redirectBadConsumerWarn(Logger logger, String message, Object arg) { - DebugLog.warn("[Sodium] %s", combatant$formatSlf4jSingleArg(message, arg)); + private static void lovisual$redirectBadConsumerWarn(Logger logger, String message, Object arg) { + DebugLog.warn("[Sodium] %s", lovisual$formatSlf4jSingleArg(message, arg)); } @Unique - private static String combatant$formatSlf4jSingleArg(String message, Object arg) { + private static String lovisual$formatSlf4jSingleArg(String message, Object arg) { String safeMessage = String.valueOf(message); int placeholder = safeMessage.indexOf("{}"); if (placeholder < 0) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumWorldRendererFreecamMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumWorldRendererFreecamMixin.java index 8cc63c0..16dfb3c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumWorldRendererFreecamMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/sodium/SodiumWorldRendererFreecamMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -24,7 +24,7 @@ public abstract class SodiumWorldRendererFreecamMixin { argsOnly = true, ordinal = 0 ) - private boolean combatant$freecamUsesSpectatorOcclusionRules(boolean spectator) { + private boolean lovisual$freecamUsesSpectatorOcclusionRules(boolean spectator) { Freecam freecam = Modules.get(Freecam.class); return spectator || (freecam != null && freecam.isEnabled() && freecam.camEntity != null); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/minimap/AbstractWaypointRenderProviderMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/minimap/AbstractWaypointRenderProviderMixin.java index 6e8f23f..a415ef6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/minimap/AbstractWaypointRenderProviderMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/minimap/AbstractWaypointRenderProviderMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -34,7 +34,7 @@ public abstract class AbstractWaypointRenderProviderMixin { target = "Lxaero/hud/minimap/waypoint/WaypointCollector;collect(Ljava/util/List;)V" ) ) - private void combatant$addTriangulatorWaypoint(WaypointCollector instance, + private void lovisual$addTriangulatorWaypoint(WaypointCollector instance, List destination, Operation original, MinimapElementRenderLocation location, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/worldmap/WaypointRenderProviderMixin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/worldmap/WaypointRenderProviderMixin.java index 8020477..58377be 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/worldmap/WaypointRenderProviderMixin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/worldmap/WaypointRenderProviderMixin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -31,50 +31,50 @@ public final class WaypointRenderProviderMixin { private SupportXaeroMinimap minimap; @Unique - private Queue combatant$pendingWaypoints; + private Queue lovisual$pendingWaypoints; @Unique - private boolean combatant$originalHadNext; + private boolean lovisual$originalHadNext; @Inject(method = "begin*", at = @At("HEAD")) - private void combatant$begin(ElementRenderLocation location, + private void lovisual$begin(ElementRenderLocation location, WaypointRenderContext context, CallbackInfo ci) { - combatant$pendingWaypoints = new ArrayDeque<>(); + lovisual$pendingWaypoints = new ArrayDeque<>(); Waypoint triangulatorWaypoint = TriangulatorXaeroWorldMapCompat.getWaypoint(minimap); if (triangulatorWaypoint != null) { - combatant$pendingWaypoints.add(triangulatorWaypoint); + lovisual$pendingWaypoints.add(triangulatorWaypoint); } - combatant$originalHadNext = false; + lovisual$originalHadNext = false; } @Inject(method = "hasNext*", at = @At("RETURN"), cancellable = true) - private void combatant$hasNext(ElementRenderLocation location, + private void lovisual$hasNext(ElementRenderLocation location, WaypointRenderContext context, CallbackInfoReturnable cir) { - combatant$originalHadNext = cir.getReturnValue(); - cir.setReturnValue(combatant$originalHadNext - || (combatant$pendingWaypoints != null && !combatant$pendingWaypoints.isEmpty())); + lovisual$originalHadNext = cir.getReturnValue(); + cir.setReturnValue(lovisual$originalHadNext + || (lovisual$pendingWaypoints != null && !lovisual$pendingWaypoints.isEmpty())); } @Inject(method = "getNext*", at = @At("HEAD"), cancellable = true) - private void combatant$getNext(ElementRenderLocation location, + private void lovisual$getNext(ElementRenderLocation location, WaypointRenderContext context, CallbackInfoReturnable cir) { - if (combatant$originalHadNext) { - combatant$originalHadNext = false; + if (lovisual$originalHadNext) { + lovisual$originalHadNext = false; return; } - if (combatant$pendingWaypoints != null && !combatant$pendingWaypoints.isEmpty()) { - cir.setReturnValue(combatant$pendingWaypoints.poll()); + if (lovisual$pendingWaypoints != null && !lovisual$pendingWaypoints.isEmpty()) { + cir.setReturnValue(lovisual$pendingWaypoints.poll()); } } @Inject(method = "end*", at = @At("HEAD")) - private void combatant$end(ElementRenderLocation location, + private void lovisual$end(ElementRenderLocation location, WaypointRenderContext context, CallbackInfo ci) { - combatant$pendingWaypoints = null; - combatant$originalHadNext = false; + lovisual$pendingWaypoints = null; + lovisual$originalHadNext = false; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/worldmap/WorldMapWaypointAccessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/worldmap/WorldMapWaypointAccessor.java index dc3c431..d614e71 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/worldmap/WorldMapWaypointAccessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/xaero/worldmap/WorldMapWaypointAccessor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/CombatantEntityRenderTypes.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/LoVisualEntityRenderTypes.java similarity index 93% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/CombatantEntityRenderTypes.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/LoVisualEntityRenderTypes.java index 9641030..4f78a1d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/CombatantEntityRenderTypes.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/LoVisualEntityRenderTypes.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -24,7 +24,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -public enum CombatantEntityRenderTypes { +public enum LoVisualEntityRenderTypes { ; private static final RenderPipeline ENTITY_TRANSLUCENT_NO_DEPTH_WRITE = RenderPipeline.builder() @@ -65,7 +65,7 @@ public enum CombatantEntityRenderTypes { private static final Map ENTITY_TRANSLUCENT_CACHE = new ConcurrentHashMap<>(); public static RenderType entityTranslucentNoDepthWrite(Identifier texture, boolean cull) { - return ENTITY_TRANSLUCENT_CACHE.computeIfAbsent(new Key(texture, cull), CombatantEntityRenderTypes::createEntityTranslucent); + return ENTITY_TRANSLUCENT_CACHE.computeIfAbsent(new Key(texture, cull), LoVisualEntityRenderTypes::createEntityTranslucent); } public static List irisMappedPipelines() { @@ -86,7 +86,7 @@ public enum CombatantEntityRenderTypes { .setOutline(RenderSetup.OutlineProperty.AFFECTS_OUTLINE) .createRenderSetup(); return RenderLayerInvokerAccessor.callOf( - key.cull ? "combatant_entity_translucent_no_depth_write" : "combatant_entity_translucent_no_depth_write_no_cull", + key.cull ? "lovisual_entity_translucent_no_depth_write" : "lovisual_entity_translucent_no_depth_write_no_cull", setup ); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ShaderEspRenderContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ShaderEspRenderContext.java index 3a418ea..24f3c59 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ShaderEspRenderContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ShaderEspRenderContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ViewObstructionFadeContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ViewObstructionFadeContext.java index 36e14de..38810ba 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ViewObstructionFadeContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ViewObstructionFadeContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,8 +20,8 @@ public enum ViewObstructionFadeContext { } STACK.get().addLast(new State( - state.combatant$isViewObstructionFadeActive(), - state.combatant$getViewObstructionFadeAlpha() + state.lovisual$isViewObstructionFadeActive(), + state.lovisual$getViewObstructionFadeAlpha() )); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ViewObstructionFadeState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ViewObstructionFadeState.java index 3283ba6..938529c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ViewObstructionFadeState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/ViewObstructionFadeState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,15 +8,15 @@ package dev.loki.lovisual.render; public interface ViewObstructionFadeState { - boolean combatant$isViewObstructionFadeActive(); + boolean lovisual$isViewObstructionFadeActive(); - float combatant$getViewObstructionFadeAlpha(); + float lovisual$getViewObstructionFadeAlpha(); - void combatant$setViewObstructionFadeActive(boolean active); + void lovisual$setViewObstructionFadeActive(boolean active); - void combatant$setViewObstructionFadeAlpha(float alpha); + void lovisual$setViewObstructionFadeAlpha(float alpha); - boolean combatant$isSeeInvisibleFadeActive(); + boolean lovisual$isSeeInvisibleFadeActive(); - void combatant$setSeeInvisibleFadeActive(boolean active); + void lovisual$setSeeInvisibleFadeActive(boolean active); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/compat/EntityCullingCompat.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/compat/EntityCullingCompat.java index 9be619f..4b15fbf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/compat/EntityCullingCompat.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/compat/EntityCullingCompat.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/effects/NetherPortalRiftPass.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/effects/NetherPortalRiftPass.java index 627b385..95746e0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/effects/NetherPortalRiftPass.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/effects/NetherPortalRiftPass.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,12 +13,11 @@ import net.minecraft.util.Mth; import net.minecraft.world.entity.PortalProcessor; import net.minecraft.world.level.block.Blocks; import dev.loki.lovisual.mixins.accessors.EntityAccessor; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; import dev.loki.lovisual.render.engine.uniform.impl.HeatUniforms; -import dev.loki.lovisual.runtime.RuntimeGate; public final class NetherPortalRiftPass implements PostProcessPass { private static final float FADE_IN_SECONDS = 0.25f; @@ -30,7 +29,7 @@ public final class NetherPortalRiftPass implements PostProcessPass { @Override public boolean isActive() { - return !RuntimeGate.isPanic() && mc != null && mc.player != null && mc.level != null; + return mc != null && mc.player != null && mc.level != null; } @Override @@ -45,17 +44,12 @@ public final class NetherPortalRiftPass implements PostProcessPass { @Override public boolean render(GpuTextureView src, GpuTextureView dst, float tickDelta) { - if (RuntimeGate.isPanic()) { - strength = 0.0f; - lastUpdateMs = 0L; - return false; - } if (mc == null || mc.player == null || mc.level == null) return false; if (src == null || dst == null) return false; PortalProcessor portalManager = null; if (mc.player instanceof EntityAccessor accessor) { - portalManager = accessor.combatant$getPortalManager(); + portalManager = accessor.lovisual$getPortalManager(); } boolean active = portalManager != null && portalManager.isInsidePortalThisTick() && isInNetherPortalBlock(); float t = smoothTowards(active ? 1.0f : 0.0f); @@ -82,9 +76,9 @@ public final class NetherPortalRiftPass implements PostProcessPass { ); FullScreenRenderer.ensureInit(); - FullScreenRenderer.begin("Combatant Fullscreen Pass") + FullScreenRenderer.begin("LoVisual Fullscreen Pass") .attachment(dst) - .pipeline(CombatantRenderPipelines.PORTAL_RIFT) + .pipeline(LoVisualRenderPipelines.PORTAL_RIFT) .uniform("Heat", HeatUniforms.get()) .sampler("u_Texture", src, PostProcessManager.getSampler()) .end(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/effects/SleepOverlayPass.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/effects/SleepOverlayPass.java index b805299..320a2ef 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/effects/SleepOverlayPass.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/effects/SleepOverlayPass.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,12 +10,11 @@ package dev.loki.lovisual.render.effects; import com.mojang.blaze3d.textures.GpuTextureView; import net.minecraft.client.Minecraft; import net.minecraft.util.Mth; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; import dev.loki.lovisual.render.engine.uniform.impl.PostProcessUniforms; -import dev.loki.lovisual.runtime.RuntimeGate; public final class SleepOverlayPass implements PostProcessPass { private static final float FADE_IN_SECONDS = 0.6f; @@ -27,7 +26,7 @@ public final class SleepOverlayPass implements PostProcessPass { @Override public boolean isActive() { - return !RuntimeGate.isPanic() && mc != null && mc.player != null && mc.level != null; + return mc != null && mc.player != null && mc.level != null; } @Override @@ -42,11 +41,6 @@ public final class SleepOverlayPass implements PostProcessPass { @Override public boolean render(GpuTextureView src, GpuTextureView dst, float tickDelta) { - if (RuntimeGate.isPanic()) { - strength = 0.0f; - lastUpdateMs = 0L; - return false; - } if (mc == null || mc.player == null || mc.level == null) return false; if (src == null || dst == null) return false; @@ -61,9 +55,9 @@ public final class SleepOverlayPass implements PostProcessPass { PostProcessUniforms.update(vignette, desat, contrast, 0.0f); FullScreenRenderer.ensureInit(); - FullScreenRenderer.begin("Combatant Fullscreen Pass") + FullScreenRenderer.begin("LoVisual Fullscreen Pass") .attachment(dst) - .pipeline(CombatantRenderPipelines.SLEEP_OVERLAY) + .pipeline(LoVisualRenderPipelines.SLEEP_OVERLAY) .uniform("PostProcess", PostProcessUniforms.get()) .sampler("u_Texture", src, PostProcessManager.getSampler()) .end(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/CombatantRenderEngineBootstrap.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/LoVisualRenderEngineBootstrap.java similarity index 73% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/CombatantRenderEngineBootstrap.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/LoVisualRenderEngineBootstrap.java index dcff1ef..4fd4f89 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/CombatantRenderEngineBootstrap.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/LoVisualRenderEngineBootstrap.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,10 +10,10 @@ package dev.loki.lovisual.render.engine; import dev.loki.lovisual.render.engine.guard.RenderBoundaryAudit; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.svg.SvgRegistry; -import dev.loki.lovisual.render.engine.visuals.CombatantVisuals; +import dev.loki.lovisual.render.engine.visuals.LoVisualVisuals; import dev.loki.lovisual.render.iris.IrisRuntime; -public enum CombatantRenderEngineBootstrap { +public enum LoVisualRenderEngineBootstrap { ; public static void init() { @@ -21,9 +21,9 @@ public enum CombatantRenderEngineBootstrap { // RHI backend selection must be lazy: onInitializeClient can run before RenderSystem has // created the final GpuDevice, which would permanently select the wrong backend on Vulkan. Renderer2D.init(); - IrisRuntime.registerCombatantPipelines(); + IrisRuntime.registerLoVisualPipelines(); SvgRegistry.init(); - CombatantVisuals.init(); + LoVisualVisuals.init(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/Projection2D.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/Projection2D.java index 70d5372..875d5c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/Projection2D.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/Projection2D.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/RenderState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/RenderState.java index 97d1eb3..da72f7c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/RenderState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/RenderState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/Texture.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/Texture.java index ddad1b8..083eaa7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/Texture.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/Texture.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/TextureStorage.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/TextureStorage.java index b3c500c..030957e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/TextureStorage.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/TextureStorage.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedClockText.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedClockText.java index fbffa63..404176f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedClockText.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedClockText.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedGlyphSlot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedGlyphSlot.java index aede6f3..9615426 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedGlyphSlot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedGlyphSlot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedRenderColors.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedRenderColors.java index 1f17e7c..21d6757 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedRenderColors.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedRenderColors.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextLine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextLine.java index 5e83939..bc9acf4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextLine.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextLine.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextStyle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextStyle.java index 6781a64..5d56914 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextStyle.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextStyle.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextTransition.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextTransition.java index 51e8898..bcf78cb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextTransition.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimatedTextTransition.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimationUtility.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimationUtility.java index 417cdbf..25cddce 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimationUtility.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/animation/AnimationUtility.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorBlendMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorBlendMode.java index 6ad5e68..06d8443 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorBlendMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorBlendMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorEffects.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorEffects.java index 12cfafc..c81ed31 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorEffects.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorEffects.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorUtils.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorUtils.java index 227980d..788281c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorUtils.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/ColorUtils.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * Portions derived from ThunderHack Recode, copyright (c) 2023-2024 Pan4ur & 06ED. * Upstream: https://github.com/Pan4ur/ThunderHack-Recode diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/RenderColor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/RenderColor.java index 32f5e8f..7b8e938 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/RenderColor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/color/RenderColor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/RenderCommandBuffer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/RenderCommandBuffer.java index 3fa1bea..a3959a8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/RenderCommandBuffer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/RenderCommandBuffer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiBatchBackendCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiBatchBackendCommand.java index 887242a..fc1f0ad 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiBatchBackendCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiBatchBackendCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommand.java index 8157af7..121e512 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandBuffer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandBuffer.java index e14b938..2e4b49a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandBuffer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandBuffer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,7 +7,7 @@ package dev.loki.lovisual.render.engine.command; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import java.util.ArrayList; @@ -29,7 +29,7 @@ public final class UiCommandBuffer implements RenderCommandBuffer { public void add(UiCommand command) { if (command == null) return; - RenderFrameContext ctx = CombatantRenderSystem.currentContext(); + RenderFrameContext ctx = LoVisualRenderSystem.currentContext(); if (ctx != null) stats.beginFrame(ctx.frameId()); commands.add(command); stats.record(command); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandKind.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandKind.java index 3d4293d..2df4f4a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandKind.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandKind.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandStats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandStats.java index 5480877..ec84cb0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandStats.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiCommandStats.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiEffectCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiEffectCommand.java index c433418..2302411 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiEffectCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiEffectCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiEffectRegionCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiEffectRegionCommand.java index fb1f92a..7cd05b8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiEffectRegionCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiEffectRegionCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiItemCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiItemCommand.java index bef8309..94be32b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiItemCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiItemCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiPathCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiPathCommand.java index 8104a8a..ae5c393 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiPathCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiPathCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiPrimitiveCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiPrimitiveCommand.java index 78895e3..5838bd3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiPrimitiveCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiPrimitiveCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiShapeCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiShapeCommand.java index 331d12b..7ae5224 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiShapeCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiShapeCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiStatsSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiStatsSnapshot.java index db5b1da..883e82d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiStatsSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiStatsSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextCommand.java index 8e246e2..9e9ff0d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextureCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextureCommand.java index 4757166..ae8c028 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextureCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextureCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextureDrawCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextureDrawCommand.java index 5100a80..618fc28 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextureDrawCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/UiTextureDrawCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/WorldCommandBuffer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/WorldCommandBuffer.java index 64c5e9d..1ea0f38 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/WorldCommandBuffer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/command/WorldCommandBuffer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,7 +7,7 @@ package dev.loki.lovisual.render.engine.command; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.rhi.RhiDrawCommand; @@ -34,7 +34,7 @@ public final class WorldCommandBuffer implements RenderCommandBuffer { @Override public void submit(RenderFrameContext context) { for (RhiDrawCommand command : commands) { - CombatantRenderSystem.rhi().drawMesh(command); + LoVisualRenderSystem.rhi().drawMesh(command); } clear(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastBridge.java index 408eae6..ed8dc62 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastRuntime.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastRuntime.java index 071b38d..f5fd187 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastRuntime.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastRuntime.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastRuntimeSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastRuntimeSnapshot.java index 846ed95..d48908c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastRuntimeSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/compat/immediatelyfast/ImmediatelyFastRuntimeSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/CameraContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/CameraContext.java index b503eb5..fee2cbd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/CameraContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/CameraContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,7 +13,7 @@ import org.joml.Matrix4f; import org.joml.Quaternionf; /** - * Camera data captured once for a Combatant frame/phase. + * Camera data captured once for a LoVisual frame/phase. */ public record CameraContext(Vec3 position, Vec3 look, Quaternionf rotation, Matrix4f projection, Matrix4f modelView) { public CameraContext(Vec3 position, Vec3 look, Quaternionf rotation, Matrix4f projection, Matrix4f modelView) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/FrameLifecycle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/FrameLifecycle.java index 24e9a54..d74b07e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/FrameLifecycle.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/FrameLifecycle.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/FramebufferContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/FramebufferContext.java index 60326a3..c619718 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/FramebufferContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/FramebufferContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/CombatantRenderSystem.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/LoVisualRenderSystem.java similarity index 83% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/CombatantRenderSystem.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/LoVisualRenderSystem.java index 8e0986b..c9ad386 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/CombatantRenderSystem.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/LoVisualRenderSystem.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,16 +20,16 @@ import dev.loki.lovisual.render.engine.RenderState; import dev.loki.lovisual.render.engine.core.policy.LightPolicy; import dev.loki.lovisual.render.engine.core.policy.VanillaWorldFogProvider; import dev.loki.lovisual.render.engine.depth.WorldSceneDepth; -import dev.loki.lovisual.render.engine.framegraph.CombatantFrameGraph; +import dev.loki.lovisual.render.engine.framegraph.LoVisualFrameGraph; import dev.loki.lovisual.render.engine.profiler.FrameStutterProfiler; import dev.loki.lovisual.render.engine.profiler.RenderFrameProfiler; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; import dev.loki.lovisual.render.engine.rhi.RhiStatsSnapshot; import dev.loki.lovisual.render.engine.rhi.backend.SodiumGlBackend; -import dev.loki.lovisual.render.engine.rhi.backend.vulkan.CombatantVulkanBackend; +import dev.loki.lovisual.render.engine.rhi.backend.vulkan.LoVisualVulkanBackend; import dev.loki.lovisual.render.engine.rhi.resource.RenderResourceManager; import dev.loki.lovisual.render.engine.rhi.resource.RenderResourceStatsSnapshot; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; import dev.loki.lovisual.render.engine.rhi.uniform.UniformAllocatorStatsSnapshot; import dev.loki.lovisual.render.engine.text.TextCommandStatsSnapshot; import dev.loki.lovisual.render.engine.text.TextRenderSystem; @@ -41,19 +41,19 @@ import dev.loki.lovisual.util.logging.DebugLog; import java.util.Locale; /** - * Single owner of Combatant render lifecycle. - * - one Combatant frame per Minecraft-presented frame; + * Single owner of LoVisual render lifecycle. + * - one LoVisual frame per Minecraft-presented frame; * - many scoped RenderPhase entries inside that frame; * - backend submission is flushed before framePresented(), not by random renderer classes; * - RenderState is a compatibility shim, not the lifecycle owner. */ -public enum CombatantRenderSystem { +public enum LoVisualRenderSystem { ; private static final SodiumRenderBridge SODIUM = new SodiumRenderBridge(); - private static final CombatantFrameGraph FRAME_GRAPH = new CombatantFrameGraph(); - private static final CombatantUniformAllocator UNIFORMS = new CombatantUniformAllocator(); + private static final LoVisualFrameGraph FRAME_GRAPH = new LoVisualFrameGraph(); + private static final LoVisualUniformAllocator UNIFORMS = new LoVisualUniformAllocator(); - private static CombatantRhi rhi; + private static LoVisualRhi rhi; private static BackendKind backendKind = BackendKind.UNKNOWN; private static RenderFrameContext currentContext; private static long frameId; @@ -78,17 +78,17 @@ public enum CombatantRenderSystem { rhi = createBackend(backendKind); initialized = true; DebugLog.renderThreadOnChange( - "combatant.rhi.backend", + "lovisual.rhi.backend", backendKind, - "[CombatantRHI] backend initialized: %s", + "[LoVisualRHI] backend initialized: %s", backendKind ); ensureBackendMatchesDevice(); } - private static CombatantRhi createBackend(BackendKind kind) { + private static LoVisualRhi createBackend(BackendKind kind) { if (kind == BackendKind.VULKAN) { - return new CombatantVulkanBackend(); + return new LoVisualVulkanBackend(); } return new SodiumGlBackend(); } @@ -100,22 +100,22 @@ public enum CombatantRenderSystem { if (frameOpen) { DebugLog.warnOnChange( - "combatant.rhi.backend.switch.deferred", + "lovisual.rhi.backend.switch.deferred", backendKind + "->" + desired + "|frameOpen", - "[CombatantRHI] backend switch deferred until frame end: %s -> %s", + "[LoVisualRHI] backend switch deferred until frame end: %s -> %s", backendKind, desired ); return; } - CombatantRhi previous = rhi; + LoVisualRhi previous = rhi; BackendKind previousKind = backendKind; - CombatantRhi next; + LoVisualRhi next; try { next = createBackend(desired); } catch (Throwable t) { - DebugLog.error("[CombatantRHI] failed to create backend " + desired, t); + DebugLog.error("[LoVisualRHI] failed to create backend " + desired, t); return; } @@ -125,9 +125,9 @@ public enum CombatantRenderSystem { previous.close(); } catch (Throwable t) { DebugLog.warnOnChange( - "combatant.rhi.backend.old.close.failed", + "lovisual.rhi.backend.old.close.failed", previousKind + "|" + desired + "|" + t.getClass().getSimpleName(), - "[CombatantRHI] old backend close failed during switch %s -> %s: %s: %s", + "[LoVisualRHI] old backend close failed during switch %s -> %s: %s: %s", previousKind, desired, t.getClass().getSimpleName(), @@ -135,9 +135,9 @@ public enum CombatantRenderSystem { ); } DebugLog.renderThreadOnChange( - "combatant.rhi.backend", + "lovisual.rhi.backend", backendKind, - "[CombatantRHI] backend switched: %s -> %s", + "[LoVisualRHI] backend switched: %s -> %s", previousKind, backendKind ); @@ -169,7 +169,7 @@ public enum CombatantRenderSystem { return BackendKind.UNKNOWN; } - public static CombatantRhi rhi() { + public static LoVisualRhi rhi() { init(); ensureBackendMatchesDevice(); return rhi; @@ -183,11 +183,11 @@ public enum CombatantRenderSystem { return rhi().resources(); } - public static CombatantFrameGraph frameGraph() { + public static LoVisualFrameGraph frameGraph() { return FRAME_GRAPH; } - public static CombatantUniformAllocator uniforms() { + public static LoVisualUniformAllocator uniforms() { return UNIFORMS; } @@ -200,7 +200,7 @@ public enum CombatantRenderSystem { } /** - * Opens the Combatant frame if needed, otherwise refreshes camera/viewport data without advancing frameId. + * Opens the LoVisual frame if needed, otherwise refreshes camera/viewport data without advancing frameId. */ public static RenderFrameContext beginFrame(float tickDelta, Matrix4f projection, Matrix4f modelView) { return beginFrame(tickDelta, tickDelta, tickDelta, projection, modelView); @@ -211,7 +211,7 @@ public enum CombatantRenderSystem { float fixedDeltaTicks, Matrix4f projection, Matrix4f modelView) { - CombatantRhi activeRhi = rhi(); + LoVisualRhi activeRhi = rhi(); SodiumFrameContext sodiumFrame; if (!frameOpen) { frameId++; @@ -301,7 +301,7 @@ public enum CombatantRenderSystem { /** * Called after the window surface has been presented. Rendering submission must already - * be closed before GpuSurface.blitFromTexture(), otherwise late Combatant draws miss the + * be closed before GpuSurface.blitFromTexture(), otherwise late LoVisual draws miss the * presented frame and can leave stale main-target contents for the next frame. */ public static void onFramePresented() { @@ -309,7 +309,7 @@ public enum CombatantRenderSystem { try { if (!submissionEnded) { // Fallback for unusual renderFrame paths. Normal visible frames close in - // GpuSurfaceMixin#combatant$beforeSurfaceBlit, before the surface copy. + // GpuSurfaceMixin#lovisual$beforeSurfaceBlit, before the surface copy. endRenderSubmission(); } rhi.framePresented(); @@ -363,20 +363,4 @@ public enum CombatantRenderSystem { public static TextCommandStatsSnapshot textStatsSnapshot() { return TextRenderSystem.statsSnapshot(); } - - public static void shutdown() { - if (!initialized) return; - try { - UNIFORMS.close(); - rhi.close(); - } finally { - initialized = false; - currentContext = null; - frameOpen = false; - submissionEnded = false; - lifecycle = FrameLifecycle.IDLE; - rhi = null; - RenderState.clearContextBackedState(); - } - } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/CombatantWorldMatrices.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/LoVisualWorldMatrices.java similarity index 95% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/CombatantWorldMatrices.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/LoVisualWorldMatrices.java index 14a09c6..0298b46 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/CombatantWorldMatrices.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/LoVisualWorldMatrices.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import org.joml.Matrix4f; import org.joml.Matrix4fc; import net.minecraft.world.phys.Vec3; -public enum CombatantWorldMatrices { +public enum LoVisualWorldMatrices { ; private static final Matrix4f POSITION = new Matrix4f(); private static final Matrix4f RENDER_PROJECTION = new Matrix4f(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderFrameContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderFrameContext.java index b94f9ca..029f724 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderFrameContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderFrameContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderPhase.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderPhase.java index fea5e88..2b8662f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderPhase.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderPhase.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.engine.core; /** - * Explicit render phase used by the Combatant frame graph. + * Explicit render phase used by the LoVisual frame graph. * This is intentionally independent from Fabric/Minecraft event names: event hooks map into these phases. */ public enum RenderPhase { @@ -23,7 +23,7 @@ public enum RenderPhase { HUD_MAIN, HUD_EFFECTS, /** - * Dedicated topmost in-game screen layer. Used for Combatant ClickGUI so the whole + * Dedicated topmost in-game screen layer. Used for LoVisual ClickGUI so the whole * vanilla InGameHud is below it even on Minecraft versions where Screen rendering * and HUD rendering interleave differently. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderPhaseScope.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderPhaseScope.java index ed55e56..51eaa56 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderPhaseScope.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/RenderPhaseScope.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -38,7 +38,7 @@ public final class RenderPhaseScope implements AutoCloseable { } catch (Exception ignored) { // Profiling must never break render lifecycle recovery. } finally { - CombatantRenderSystem.restorePhase(previous); + LoVisualRenderSystem.restorePhase(previous); } } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/ViewportContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/ViewportContext.java index 33be540..439a40d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/ViewportContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/ViewportContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -47,7 +47,7 @@ public record ViewportContext( private static ProjectionMatrixBuffer matrixBuffer() { ProjectionMatrixBuffer buffer = matrixBuffer; if (buffer == null) { - buffer = new ProjectionMatrixBuffer("combatant-projection-matrix"); + buffer = new ProjectionMatrixBuffer("lovisual-projection-matrix"); matrixBuffer = buffer; } return buffer; @@ -283,7 +283,7 @@ public record ViewportContext( */ UNSCALED, /** - * Combatant logical HUD coordinates from HudScale. + * LoVisual logical HUD coordinates from HudScale. */ LOGICAL, /** diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/DepthProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/DepthProvider.java index 70d15a9..75e8e75 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/DepthProvider.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/DepthProvider.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/FogProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/FogProvider.java index 3c8c07c..a48db2b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/FogProvider.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/FogProvider.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/LightPolicy.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/LightPolicy.java index e1bd0bc..dd5fcc9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/LightPolicy.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/LightPolicy.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.engine.core.policy; /** - * Placeholder for Combatant lighting policy. Kept explicit so fullbright/ambient/shaderpack hooks do not leak into renderers. + * Placeholder for LoVisual lighting policy. Kept explicit so fullbright/ambient/shaderpack hooks do not leak into renderers. */ public interface LightPolicy { LightPolicy VANILLA = new LightPolicy() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VanillaWorldFogProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VanillaWorldFogProvider.java index 4ce3cd9..6592db5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VanillaWorldFogProvider.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VanillaWorldFogProvider.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -26,7 +26,7 @@ public final class VanillaWorldFogProvider implements FogProvider { public @Nullable GpuBufferSlice fogUniformSlice() { Minecraft mc = Minecraft.getInstance(); if (mc == null || !(mc.gameRenderer instanceof GameRendererAccessor accessor)) return null; - FogRenderer fogRenderer = accessor.combatant$getFogRenderer(); + FogRenderer fogRenderer = accessor.lovisual$getFogRenderer(); return fogRenderer != null ? fogRenderer.getBuffer(FogRenderer.FogMode.WORLD) : null; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VisibilityProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VisibilityProvider.java index 6b6d72e..4756f9a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VisibilityProvider.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VisibilityProvider.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VisibilityQuery.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VisibilityQuery.java index a15077a..cd9b264 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VisibilityQuery.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/core/policy/VisibilityQuery.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/debug/RenderThread2DDebugRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/debug/RenderThread2DDebugRenderer.java index d1bf85a..f09a8af 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/debug/RenderThread2DDebugRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/debug/RenderThread2DDebugRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -18,7 +18,7 @@ import net.minecraft.client.renderer.Projection; import net.minecraft.client.renderer.ProjectionMatrixBuffer; import org.joml.Matrix4f; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.RenderPhaseScope; import dev.loki.lovisual.render.engine.renderer.MeshRenderer; @@ -35,7 +35,7 @@ import dev.loki.lovisual.util.logging.DebugLog; * * *

This deliberately does not move production HUD rendering. It only tells which side is broken: - * vanilla GUI/root-layer extraction or Combatant immediate Renderer2D/RHI.

+ * vanilla GUI/root-layer extraction or LoVisual immediate Renderer2D/RHI.

*/ public enum RenderThread2DDebugRenderer { ; @@ -68,7 +68,7 @@ public enum RenderThread2DDebugRenderer { private static ProjectionMatrixBuffer debugProjection() { ProjectionMatrixBuffer buffer = debugProjection; if (buffer == null) { - buffer = new ProjectionMatrixBuffer("combatant-debug-2d-render-thread-projection"); + buffer = new ProjectionMatrixBuffer("lovisual-debug-2d-render-thread-projection"); debugProjection = buffer; } return buffer; @@ -136,7 +136,7 @@ public enum RenderThread2DDebugRenderer { var modelView = RenderSystem.getModelViewStack(); boolean pushedModelView = false; - try (RenderPhaseScope ignored = CombatantRenderSystem.phase(RenderPhase.HUD_MAIN, "debug:2d_immediate_after_gui")) { + try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "debug:2d_immediate_after_gui")) { modelView.pushMatrix(); pushedModelView = true; modelView.identity(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/depth/PreTranslucentDepth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/depth/PreTranslucentDepth.java index 428c573..53d8888 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/depth/PreTranslucentDepth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/depth/PreTranslucentDepth.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,7 +15,7 @@ import com.mojang.blaze3d.textures.GpuTexture; import com.mojang.blaze3d.textures.GpuTextureView; import net.minecraft.client.Minecraft; import dev.loki.lovisual.mixininterface.IMsaaTexture; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.msaa.MsaaWorldTarget; /** @@ -48,9 +48,9 @@ public enum PreTranslucentDepth { captured = false; capturedMsaa = false; - boolean isMsaa = source.getDepthTexture() instanceof IMsaaTexture msaa && msaa.combatant$isMsaa(); + boolean isMsaa = source.getDepthTexture() instanceof IMsaaTexture msaa && msaa.lovisual$isMsaa(); if (isMsaa) { - int samples = ((IMsaaTexture) source.getDepthTexture()).combatant$getSamples(); + int samples = ((IMsaaTexture) source.getDepthTexture()).lovisual$getSamples(); ensureMsaaDepthCopy(w, h, samples); if (msaaDepthCopy != null && source.getDepthTexture() != null) { try { @@ -63,7 +63,7 @@ public enum PreTranslucentDepth { ); msaaDepthView = msaaDepthCopyView; capturedMsaa = true; - if (CombatantRenderSystem.rhi().msaa().eagerPreTranslucentDepthResolve()) { + if (LoVisualRenderSystem.rhi().msaa().eagerPreTranslucentDepthResolve()) { captured = resolveMsaaDepthCopy(); } } catch (IllegalArgumentException ignored) { @@ -79,8 +79,8 @@ public enum PreTranslucentDepth { } else { msaaDepthView = null; capturedMsaa = false; - depthCopy = CombatantRenderSystem.resources().persistentFramebuffer( - "combatant-pretrans-depth", w, h, true, "PreTranslucentDepth"); + depthCopy = LoVisualRenderSystem.resources().persistentFramebuffer( + "lovisual-pretrans-depth", w, h, true, "PreTranslucentDepth"); depthCopyW = w; depthCopyH = h; depthCopy.copyDepthFrom(source); @@ -108,7 +108,7 @@ public enum PreTranslucentDepth { } if (capturedMsaa && msaaDepthView != null - && !CombatantRenderSystem.rhi().msaa().supportsDepthSnapshotResolve()) { + && !LoVisualRenderSystem.rhi().msaa().supportsDepthSnapshotResolve()) { return msaaDepthView; } return WorldSceneDepth.mainDepthView(); @@ -139,12 +139,12 @@ public enum PreTranslucentDepth { } private static void ensureMsaaDepthCopy(int w, int h, int samples) { - if (!CombatantRenderSystem.rhi().msaa().supported()) return; + if (!LoVisualRenderSystem.rhi().msaa().supported()) return; if (msaaDepthCopy == null || w != msaaDepthCopyW || h != msaaDepthCopyH || msaaSamples != samples) { releaseMsaaDepthCopy(); int usage = GpuTexture.USAGE_COPY_DST | GpuTexture.USAGE_COPY_SRC | GpuTexture.USAGE_RENDER_ATTACHMENT; - msaaDepthCopy = CombatantRenderSystem.rhi().msaa().createTexture( - "combatant-pretrans-depth-msaa", + msaaDepthCopy = LoVisualRenderSystem.rhi().msaa().createTexture( + "lovisual-pretrans-depth-msaa", usage, GpuFormat.D32_FLOAT, w, @@ -159,8 +159,8 @@ public enum PreTranslucentDepth { } private static void ensureResolvedDepthCopy(int w, int h) { - depthCopy = CombatantRenderSystem.resources().persistentFramebuffer( - "combatant-pretrans-depth", + depthCopy = LoVisualRenderSystem.resources().persistentFramebuffer( + "lovisual-pretrans-depth", w, h, true, @@ -175,13 +175,13 @@ public enum PreTranslucentDepth { if (!capturedMsaa || msaaDepthCopyView == null || msaaDepthCopyW <= 0 || msaaDepthCopyH <= 0) { return false; } - if (!CombatantRenderSystem.rhi().msaa().supportsDepthSnapshotResolve()) { + if (!LoVisualRenderSystem.rhi().msaa().supportsDepthSnapshotResolve()) { return false; } ensureResolvedDepthCopy(msaaDepthCopyW, msaaDepthCopyH); captured = depthCopy != null && depthCopy.getDepthTextureView() != null - && CombatantRenderSystem.rhi().msaa().resolveDepthSnapshot( + && LoVisualRenderSystem.rhi().msaa().resolveDepthSnapshot( msaaDepthCopyView, depthCopy.getDepthTextureView() ); @@ -190,8 +190,8 @@ public enum PreTranslucentDepth { private static int samples(GpuTextureView view) { if (view == null || view.texture() == null) return 1; - return view.texture() instanceof IMsaaTexture msaa && msaa.combatant$isMsaa() - ? msaa.combatant$getSamples() + return view.texture() instanceof IMsaaTexture msaa && msaa.lovisual$isMsaa() + ? msaa.lovisual$getSamples() : 1; } @@ -201,7 +201,7 @@ public enum PreTranslucentDepth { msaaDepthCopyView = null; } if (msaaDepthCopy != null) { - CombatantRenderSystem.resources().retireTexture(msaaDepthCopy); + LoVisualRenderSystem.resources().retireTexture(msaaDepthCopy); msaaDepthCopy = null; } msaaDepthView = null; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/depth/WorldSceneDepth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/depth/WorldSceneDepth.java index e0e1861..9646afb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/depth/WorldSceneDepth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/depth/WorldSceneDepth.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.pipeline.TextureTarget; import com.mojang.blaze3d.textures.GpuTextureView; import dev.loki.lovisual.mixininterface.IMsaaTexture; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; /** * Persistent copy of the depth buffers that vanilla composes through its world transparency @@ -21,12 +21,12 @@ import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; */ public enum WorldSceneDepth { ; - private static final Stage MAIN = new Stage("main", "combatant-world-scene-depth-main"); - private static final Stage TRANSLUCENT = new Stage("translucent", "combatant-world-scene-depth-translucent"); - private static final Stage ITEM_ENTITY = new Stage("item_entity", "combatant-world-scene-depth-item-entity"); - private static final Stage PARTICLES = new Stage("particles", "combatant-world-scene-depth-particles"); - private static final Stage WEATHER = new Stage("weather", "combatant-world-scene-depth-weather"); - private static final Stage CLOUDS = new Stage("clouds", "combatant-world-scene-depth-clouds"); + private static final Stage MAIN = new Stage("main", "lovisual-world-scene-depth-main"); + private static final Stage TRANSLUCENT = new Stage("translucent", "lovisual-world-scene-depth-translucent"); + private static final Stage ITEM_ENTITY = new Stage("item_entity", "lovisual-world-scene-depth-item-entity"); + private static final Stage PARTICLES = new Stage("particles", "lovisual-world-scene-depth-particles"); + private static final Stage WEATHER = new Stage("weather", "lovisual-world-scene-depth-weather"); + private static final Stage CLOUDS = new Stage("clouds", "lovisual-world-scene-depth-clouds"); private static int width = -1; private static int height = -1; @@ -178,7 +178,7 @@ public enum WorldSceneDepth { } try { - depthCopy = CombatantRenderSystem.resources().persistentFramebuffer( + depthCopy = LoVisualRenderSystem.resources().persistentFramebuffer( framebufferName, w, h, @@ -189,15 +189,15 @@ public enum WorldSceneDepth { return false; } - boolean msaa = source.getDepthTexture() instanceof IMsaaTexture texture && texture.combatant$isMsaa(); + boolean msaa = source.getDepthTexture() instanceof IMsaaTexture texture && texture.lovisual$isMsaa(); if (msaa) { - if (CombatantRenderSystem.rhi().msaa().supportsDepthSnapshotResolve()) { - captured = CombatantRenderSystem.rhi().msaa().resolveDepthSnapshot( + if (LoVisualRenderSystem.rhi().msaa().supportsDepthSnapshotResolve()) { + captured = LoVisualRenderSystem.rhi().msaa().resolveDepthSnapshot( source.getDepthTextureView(), depthCopy.getDepthTextureView() ); } else { - captured = CombatantRenderSystem.rhi().msaa().resolve(source, depthCopy, false, true); + captured = LoVisualRenderSystem.rhi().msaa().resolve(source, depthCopy, false, true); } } else { depthCopy.copyDepthFrom(source); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/CombatantFrameGraph.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/LoVisualFrameGraph.java similarity index 71% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/CombatantFrameGraph.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/LoVisualFrameGraph.java index a61cbd3..a4ac1a1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/CombatantFrameGraph.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/LoVisualFrameGraph.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,7 +7,7 @@ package dev.loki.lovisual.render.engine.framegraph; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.RenderPhaseScope; @@ -15,7 +15,7 @@ import dev.loki.lovisual.render.engine.core.RenderPhaseScope; import java.util.function.Consumer; -public final class CombatantFrameGraph { +public final class LoVisualFrameGraph { private final PassScheduler scheduler = new PassScheduler(); public void add(RenderPhase phase, Consumer handler) { @@ -29,13 +29,13 @@ public final class CombatantFrameGraph { public void execute(RenderPhase phase, RenderFrameContext baseContext) { String label = "framegraph:" + (phase == null ? "none" : phase.name().toLowerCase()); - try (RenderPhaseScope ignored = CombatantRenderSystem.phase(phase, label)) { - RenderFrameContext ctx = CombatantRenderSystem.currentContext(); + try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(phase, label)) { + RenderFrameContext ctx = LoVisualRenderSystem.currentContext(); if (ctx == null && baseContext != null) ctx = baseContext.withPhase(phase); if (ctx == null) return; for (RenderPassNode node : scheduler.nodes(phase)) { - try (RenderPhaseScope nodeScope = CombatantRenderSystem.phase(phase, "pass:" + node.label())) { - node.execute(CombatantRenderSystem.currentContext()); + try (RenderPhaseScope nodeScope = LoVisualRenderSystem.phase(phase, "pass:" + node.label())) { + node.execute(LoVisualRenderSystem.currentContext()); } } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/PassScheduler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/PassScheduler.java index e9d82ff..2bc9bc3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/PassScheduler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/PassScheduler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/RenderPassNode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/RenderPassNode.java index 2e8fa9a..4e0dbd2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/RenderPassNode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/framegraph/RenderPassNode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,7 +14,7 @@ import java.util.Objects; import java.util.function.Consumer; /** - * A named frame-graph node bound to a Combatant render phase. + * A named frame-graph node bound to a LoVisual render phase. */ public final class RenderPassNode { private final RenderPhase phase; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/LegacyRenderPath.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/LegacyRenderPath.java index 6d18f53..7911829 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/LegacyRenderPath.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/LegacyRenderPath.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderArchitectureGuard.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderArchitectureGuard.java index 519ab82..29c6e18 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderArchitectureGuard.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderArchitectureGuard.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,10 +7,10 @@ package dev.loki.lovisual.render.engine.guard; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; /** - * Final architecture lock for the Combatant RHI migration. + * Final architecture lock for the LoVisual RHI migration. *

* This class is intentionally small and dependency-light: it is used from low-level legacy facades to make sure old * render paths cannot silently become production paths again. A path can only be enabled through an explicit system @@ -18,12 +18,12 @@ import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; */ public enum RenderArchitectureGuard { ; - public static final boolean DEBUG = Boolean.getBoolean("combatant.render.debug"); - public static final boolean STRICT = !Boolean.getBoolean("combatant.render.allowLegacyPaths"); - public static final boolean ALLOW_LEGACY_MESH_RENDERER = Boolean.getBoolean("combatant.render.allowLegacyMeshRenderer"); - public static final boolean ALLOW_LEGACY_FULLSCREEN_MESH = Boolean.getBoolean("combatant.render.allowLegacyFullscreenMesh"); - public static final boolean ALLOW_IMMEDIATE_UPLOAD = Boolean.getBoolean("combatant.rhi.allowImmediateFallback") - || Boolean.getBoolean("combatant.render.allowImmediateUpload"); + public static final boolean DEBUG = Boolean.getBoolean("lovisual.render.debug"); + public static final boolean STRICT = !Boolean.getBoolean("lovisual.render.allowLegacyPaths"); + public static final boolean ALLOW_LEGACY_MESH_RENDERER = Boolean.getBoolean("lovisual.render.allowLegacyMeshRenderer"); + public static final boolean ALLOW_LEGACY_FULLSCREEN_MESH = Boolean.getBoolean("lovisual.render.allowLegacyFullscreenMesh"); + public static final boolean ALLOW_IMMEDIATE_UPLOAD = Boolean.getBoolean("lovisual.rhi.allowImmediateFallback") + || Boolean.getBoolean("lovisual.render.allowImmediateUpload"); public static void requireAllowed(LegacyRenderPath path, String owner) { boolean allowed = switch (path) { @@ -38,13 +38,13 @@ public enum RenderArchitectureGuard { throw new IllegalStateException("Legacy render path is locked: " + path.description() + " owner=" + owner - + ". Use CombatantRHI/SodiumGlBackend path instead. " + + ". Use LoVisualRHI/SodiumGlBackend path instead. " + "Temporary override: -D" + overrideProperty(path) + "=true"); } public static void record(LegacyRenderPath path) { try { - CombatantRenderSystem.rhi().stats().legacyPath(path); + LoVisualRenderSystem.rhi().stats().legacyPath(path); } catch (Throwable ignored) { // Guard must be safe during bootstrap/static initialization. } @@ -52,10 +52,10 @@ public enum RenderArchitectureGuard { private static String overrideProperty(LegacyRenderPath path) { return switch (path) { - case IMMEDIATE_MESH_UPLOAD -> "combatant.rhi.allowImmediateFallback"; - case LEGACY_FULLSCREEN_MESH -> "combatant.render.allowLegacyFullscreenMesh"; - case LEGACY_MESH_RENDERER -> "combatant.render.allowLegacyMeshRenderer"; - default -> "combatant.render.allowLegacyPaths"; + case IMMEDIATE_MESH_UPLOAD -> "lovisual.rhi.allowImmediateFallback"; + case LEGACY_FULLSCREEN_MESH -> "lovisual.render.allowLegacyFullscreenMesh"; + case LEGACY_MESH_RENDERER -> "lovisual.render.allowLegacyMeshRenderer"; + default -> "lovisual.render.allowLegacyPaths"; }; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundary.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundary.java index 284140b..6e8e571 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundary.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundary.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundaryAudit.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundaryAudit.java index 658bdba..a2ea564 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundaryAudit.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundaryAudit.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -18,7 +18,7 @@ import java.util.List; public enum RenderBoundaryAudit { ; private static final List LOCKED_RULES = List.of( - "Renderer3D/Renderer2D/Text/PostProcess must submit through CombatantRHI or command layers", + "Renderer3D/Renderer2D/Text/PostProcess must submit through LoVisualRHI or command layers", "Direct GL is backend/profiler/MSAA-legacy only", "Direct Sodium runtime access is SodiumRenderBridge/terrain interop only", "Immediate mesh upload is emergency fallback only", @@ -32,9 +32,9 @@ public enum RenderBoundaryAudit { if (ran) return; ran = true; if (!RenderArchitectureGuard.DEBUG) return; - DebugLog.renderThread("[CombatantRHI] render architecture boundary locked:"); + DebugLog.renderThread("[LoVisualRHI] render architecture boundary locked:"); for (String rule : LOCKED_RULES) { - DebugLog.renderThread("[CombatantRHI] - " + rule); + DebugLog.renderThread("[LoVisualRHI] - " + rule); } } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundaryExempt.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundaryExempt.java index 7e13be8..2881d3d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundaryExempt.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/guard/RenderBoundaryExempt.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/light/LightmapState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/light/LightmapState.java index 2db3428..1f2d25d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/light/LightmapState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/light/LightmapState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/ColorMath.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/ColorMath.java index 8c6120f..701f93f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/ColorMath.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/ColorMath.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/HudScale.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/HudScale.java index 39bcd35..80b205b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/HudScale.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/HudScale.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/RenderMath.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/RenderMath.java index b8b660d..a54912e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/RenderMath.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/math/RenderMath.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaFramebuffer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaFramebuffer.java index 28b98da..8a515fc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaFramebuffer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaFramebuffer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.textures.GpuTexture; import dev.loki.lovisual.mixininterface.IMsaaTexture; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import lombok.Getter; @Getter @@ -27,13 +27,13 @@ public final class MsaaFramebuffer extends RenderTarget { } private static int textureSamples(GpuTexture texture) { - return texture instanceof IMsaaTexture msaa ? msaa.combatant$getSamples() : 1; + return texture instanceof IMsaaTexture msaa ? msaa.lovisual$getSamples() : 1; } @Override public void createBuffers(int width, int height) { RenderSystem.assertOnRenderThread(); - if (!CombatantRenderSystem.rhi().msaa().supported()) { + if (!LoVisualRenderSystem.rhi().msaa().supported()) { throw new IllegalStateException("MSAA device not available"); } @@ -47,7 +47,7 @@ public final class MsaaFramebuffer extends RenderTarget { try { if (this.useDepth) { - this.depthTexture = CombatantRenderSystem.rhi().msaa().createTexture( + this.depthTexture = LoVisualRenderSystem.rhi().msaa().createTexture( this.label + " / Depth", usage, GpuFormat.D32_FLOAT, @@ -58,7 +58,7 @@ public final class MsaaFramebuffer extends RenderTarget { this.depthTextureView = RenderSystem.getDevice().createTextureView(this.depthTexture); } - this.colorTexture = CombatantRenderSystem.rhi().msaa().createTexture( + this.colorTexture = LoVisualRenderSystem.rhi().msaa().createTexture( this.label + " / Color", usage, GpuFormat.RGBA8_UNORM, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaResolveUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaResolveUtil.java index 4dc0ad3..6a2d565 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaResolveUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaResolveUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -9,7 +9,7 @@ package dev.loki.lovisual.render.engine.msaa; import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.systems.RenderSystem; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; @Deprecated public enum MsaaResolveUtil { @@ -17,6 +17,6 @@ public enum MsaaResolveUtil { public static boolean resolve(RenderTarget src, RenderTarget dst, boolean color, boolean depth) { RenderSystem.assertOnRenderThread(); - return CombatantRenderSystem.rhi().msaa().resolve(src, dst, color, depth); + return LoVisualRenderSystem.rhi().msaa().resolve(src, dst, color, depth); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaTextureRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaTextureRegistry.java index 8d88f9b..c23e4ed 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaTextureRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaTextureRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaWorldTarget.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaWorldTarget.java index 7ab2cf2..69e6662 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaWorldTarget.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/msaa/MsaaWorldTarget.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -9,9 +9,8 @@ package dev.loki.lovisual.render.engine.msaa; import com.mojang.blaze3d.pipeline.RenderTarget; import net.minecraft.client.Minecraft; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.mixins.accessors.GameRendererAccessor; -import dev.loki.lovisual.runtime.RuntimeGate; import dev.loki.lovisual.util.logging.DebugLog; public enum MsaaWorldTarget { @@ -47,11 +46,6 @@ public enum MsaaWorldTarget { active = false; return; } - if (RuntimeGate.isPanic()) { - state = "panic"; - shutdown(mc); - return; - } if (sampleCount <= 1) { state = "off"; supported = false; @@ -60,7 +54,7 @@ public enum MsaaWorldTarget { } return; } - supported = CombatantRenderSystem.rhi().msaa().supported(); + supported = LoVisualRenderSystem.rhi().msaa().supported(); if (!supported) { state = "unsupported"; shutdown(mc); @@ -98,7 +92,7 @@ public enum MsaaWorldTarget { active = false; return; } - boolean seeded = CombatantRenderSystem.rhi().msaa().resolve(main, msaa, true, false); + boolean seeded = LoVisualRenderSystem.rhi().msaa().resolve(main, msaa, true, false); if (!seeded) { lastResolveOk = false; state = "seed_failed"; @@ -116,9 +110,9 @@ public enum MsaaWorldTarget { } try { - CombatantRenderSystem.rhi().msaa().prepareTarget(msaa, main, true, needDepthResolve); + LoVisualRenderSystem.rhi().msaa().prepareTarget(msaa, main, true, needDepthResolve); } catch (Throwable t) { - CombatantRenderSystem.rhi().msaa().abandonTarget(msaa); + LoVisualRenderSystem.rhi().msaa().abandonTarget(msaa); lastResolveOk = false; state = "prepare_failed"; DebugLog.warnOnChange("msaa.world.prepare_failed", @@ -140,13 +134,13 @@ public enum MsaaWorldTarget { } RenderTarget main = rawMain(mc); if (main == null) { - CombatantRenderSystem.rhi().msaa().abandonTarget(msaa); + LoVisualRenderSystem.rhi().msaa().abandonTarget(msaa); active = false; lastResolveOk = false; state = "resolve_no_main"; return; } - lastResolveOk = CombatantRenderSystem.rhi().msaa().resolve(msaa, main, true, resolveDepth); + lastResolveOk = LoVisualRenderSystem.rhi().msaa().resolve(msaa, main, true, resolveDepth); active = false; } @@ -159,8 +153,8 @@ public enum MsaaWorldTarget { } if (msaa != null) { MsaaFramebuffer retired = msaa; - CombatantRenderSystem.rhi().msaa().abandonTarget(retired); - CombatantRenderSystem.resources().retire(retired::destroyBuffers); + LoVisualRenderSystem.rhi().msaa().abandonTarget(retired); + LoVisualRenderSystem.resources().retire(retired::destroyBuffers); msaa = null; } active = false; @@ -174,20 +168,20 @@ public enum MsaaWorldTarget { if (msaa == null || allocationRequestSamples != sampleCount) { MsaaFramebuffer previous = msaa; try { - MsaaFramebuffer next = new MsaaFramebuffer("combatant-msaa-world", w, h, true, sampleCount); + MsaaFramebuffer next = new MsaaFramebuffer("lovisual-msaa-world", w, h, true, sampleCount); msaa = next; samples = next.getSamples(); allocationRequestSamples = sampleCount; width = w; height = h; if (previous != null) { - CombatantRenderSystem.rhi().msaa().abandonTarget(previous); - CombatantRenderSystem.resources().retire(previous::destroyBuffers); + LoVisualRenderSystem.rhi().msaa().abandonTarget(previous); + LoVisualRenderSystem.resources().retire(previous::destroyBuffers); } } catch (Throwable t) { if (previous != null) { - CombatantRenderSystem.rhi().msaa().abandonTarget(previous); - CombatantRenderSystem.resources().retire(previous::destroyBuffers); + LoVisualRenderSystem.rhi().msaa().abandonTarget(previous); + LoVisualRenderSystem.resources().retire(previous::destroyBuffers); } msaa = null; samples = 0; @@ -209,8 +203,8 @@ public enum MsaaWorldTarget { height = h; } catch (Throwable t) { MsaaFramebuffer retired = msaa; - CombatantRenderSystem.rhi().msaa().abandonTarget(retired); - CombatantRenderSystem.resources().retire(retired::destroyBuffers); + LoVisualRenderSystem.rhi().msaa().abandonTarget(retired); + LoVisualRenderSystem.resources().retire(retired::destroyBuffers); msaa = null; samples = 0; allocationRequestSamples = 0; @@ -230,7 +224,7 @@ public enum MsaaWorldTarget { private static RenderTarget rawMain(Minecraft mc) { return mc != null && mc.gameRenderer != null - ? ((GameRendererAccessor) mc.gameRenderer).combatant$getMainRenderTargetRaw() + ? ((GameRendererAccessor) mc.gameRenderer).lovisual$getMainRenderTargetRaw() : null; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/DepthTestFunction.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/DepthTestFunction.java index 1897683..4789965 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/DepthTestFunction.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/DepthTestFunction.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/ExtendedRenderPipelineBuilder.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/ExtendedRenderPipelineBuilder.java index c408b8a..87c7947 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/ExtendedRenderPipelineBuilder.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/ExtendedRenderPipelineBuilder.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -122,9 +122,9 @@ public class ExtendedRenderPipelineBuilder { public RenderPipeline build() { applyBindGroupLayout(); RenderPipeline pipeline = delegate.build(); - IRenderPipeline combatantPipeline = (IRenderPipeline) pipeline; - combatantPipeline.combatant$setLineSmooth(lineSmooth); - combatantPipeline.combatant$setShapeClipContract(shapeClipContract); + IRenderPipeline lovisualPipeline = (IRenderPipeline) pipeline; + lovisualPipeline.lovisual$setLineSmooth(lineSmooth); + lovisualPipeline.lovisual$setShapeClipContract(shapeClipContract); return pipeline; } @@ -134,7 +134,7 @@ public class ExtendedRenderPipelineBuilder { } private boolean isUiCanvasPipeline() { - if (location == null || !"combatant".equals(location.getNamespace())) return false; + if (location == null || !"lovisual".equals(location.getNamespace())) return false; String path = location.getPath(); return path.startsWith("pipeline/ui_") || path.startsWith("pipeline/menu_") diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/CombatantRenderPipelines.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/LoVisualRenderPipelines.java similarity index 90% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/CombatantRenderPipelines.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/LoVisualRenderPipelines.java index 0149680..2cbe545 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/CombatantRenderPipelines.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/pipeline/LoVisualRenderPipelines.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -25,8 +25,8 @@ import net.minecraft.server.packs.resources.ResourceManager; import dev.loki.lovisual.mixininterface.IRenderPipeline; import dev.loki.lovisual.render.engine.rhi.clip.ShapeClipRenderPassContract; import dev.loki.lovisual.render.engine.rhi.pipeline.RenderPipelineRegistry; -import dev.loki.lovisual.render.engine.shader.CombatantShaderSources; -import dev.loki.lovisual.render.engine.vertex.CombatantVertexFormats; +import dev.loki.lovisual.render.engine.shader.LoVisualShaderSources; +import dev.loki.lovisual.render.engine.vertex.LoVisualVertexFormats; import dev.loki.lovisual.util.logging.DebugLog; import java.util.ArrayList; @@ -34,11 +34,11 @@ import java.util.Collections; import java.util.List; /** - * Pipeline registry for Combatant's custom rendering engine. + * Pipeline registry for LoVisual's custom rendering engine. * *

Keep this class free of module-specific logic: it is the foundation for all custom 3D/2D effects.

*/ -public enum CombatantRenderPipelines { +public enum LoVisualRenderPipelines { ; // Shaders (assets/lovisual/shaders/*) public static final Identifier SHADER_POS_COLOR_VERT = Identifier.fromNamespaceAndPath("lovisual", "shaders/pos_color.vert"); @@ -160,7 +160,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline WORLD_WIDE_COLORED_LINES = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/world_wide_colored_lines")) - .withVertexFormat(CombatantVertexFormats.POS3_COLOR_LINE, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS3_COLOR_LINE, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_WIDE_LINE_VERT) .withFragmentShader(SHADER_POS_COLOR_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -233,7 +233,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline WORLD_DECAL_SDF = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/world_decal_sdf")) - .withVertexFormat(CombatantVertexFormats.POS3_TEXTURE_COLOR_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS3_TEXTURE_COLOR_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_TEX_COLOR_PARAMS2_VERT) .withFragmentShader(SHADER_WORLD_DECAL_SDF_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -247,7 +247,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline WORLD_DECAL_SDF_DEPTH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/world_decal_sdf_depth")) - .withVertexFormat(CombatantVertexFormats.POS3_TEXTURE_COLOR_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS3_TEXTURE_COLOR_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_TEX_COLOR_PARAMS2_VERT) .withFragmentShader(SHADER_WORLD_DECAL_SDF_FRAG) .withDepthTestFunction(DepthTestFunction.GEQUAL_DEPTH_TEST) @@ -384,7 +384,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline WORLD_WIDE_COLORED_LINES_DEPTH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/world_wide_colored_lines_depth")) - .withVertexFormat(CombatantVertexFormats.POS3_COLOR_LINE, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS3_COLOR_LINE, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_WIDE_LINE_VERT) .withFragmentShader(SHADER_POS_COLOR_FRAG) .withDepthTestFunction(DepthTestFunction.GEQUAL_DEPTH_TEST) @@ -428,7 +428,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline WORLD_WIDE_COLORED_LINES_LIQUID_BLEND = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/world_wide_colored_lines_liquid_blend")) - .withVertexFormat(CombatantVertexFormats.POS3_COLOR_LINE, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS3_COLOR_LINE, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_WIDE_LINE_VERT) .withFragmentShader(SHADER_POS_COLOR_FRAG) .withDepthTestFunction(DepthTestFunction.GEQUAL_DEPTH_TEST) @@ -502,7 +502,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline WORLD_WIDE_COLORED_LINES_LIQUID_IGNORE = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/world_wide_colored_lines_liquid_ignore")) - .withVertexFormat(CombatantVertexFormats.POS3_COLOR_LINE, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS3_COLOR_LINE, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_WIDE_LINE_VERT) .withFragmentShader(SHADER_POS_COLOR_FRAG) .withDepthTestFunction(DepthTestFunction.GEQUAL_DEPTH_TEST) @@ -563,7 +563,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline UI_COLORED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_colored")) - .withVertexFormat(CombatantVertexFormats.POS2_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_COLOR_VERT) .withFragmentShader(SHADER_POS_COLOR_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -577,7 +577,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline UI_COLORED_LINES = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_colored_lines")) - .withVertexFormat(CombatantVertexFormats.POS2_COLOR, com.mojang.blaze3d.PrimitiveTopology.DEBUG_LINES) + .withVertexFormat(LoVisualVertexFormats.POS2_COLOR, com.mojang.blaze3d.PrimitiveTopology.DEBUG_LINES) .withVertexShader(SHADER_POS_COLOR_VERT) .withFragmentShader(SHADER_POS_COLOR_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -591,7 +591,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline UI_TEXTURED = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_textured")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_TEX_COLOR_VERT) .withFragmentShader(SHADER_POS_TEX_COLOR_FRAG) .withSampler("u_Texture") @@ -606,7 +606,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline UI_SVG_MSDF = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_svg_msdf")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_TEX_COLOR_VERT) .withFragmentShader(SHADER_SVG_MSDF_FRAG) .withSampler("u_Texture") @@ -622,7 +622,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline UI_TEXTURED_ADDITIVE = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_textured_additive")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_TEX_COLOR_VERT) .withFragmentShader(SHADER_POS_TEX_COLOR_FRAG) .withSampler("u_Texture") @@ -641,7 +641,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline UI_TEXT = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_text")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_TEXT_VERT) .withFragmentShader(SHADER_TEXT_FRAG) .withSampler("u_Texture") @@ -656,7 +656,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline UI_TEXT_MSDF = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_text_msdf")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_TEXT_VERT) .withFragmentShader(SHADER_TEXT_MSDF_FRAG) .withSampler("u_Texture") @@ -669,7 +669,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_TEXT_LIQUID_GLASS = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_text_liquid_glass")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_TEXT_VERT) .withFragmentShader(SHADER_TEXT_LIQUID_GLASS_FRAG) .withSampler("u_Texture") @@ -684,7 +684,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_TEXT_LIQUID_GLASS_MSDF = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_text_liquid_glass_msdf")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_TEXT_VERT) .withFragmentShader(SHADER_TEXT_LIQUID_GLASS_MSDF_FRAG) .withSampler("u_Texture") @@ -700,7 +700,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_BLUR = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_blur")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_TEX_COLOR_VERT) .withFragmentShader(SHADER_UI_BLUR_FRAG) .withSampler("u_Texture") @@ -716,7 +716,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline MENU_BACKGROUND_WAVES = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/menu_background_waves")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_MENU_BACKGROUND_WAVES_FRAG) .withUniform("MenuBackground", UniformType.UNIFORM_BUFFER) @@ -731,7 +731,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline MENU_BACKGROUND_AURORA = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/menu_background_aurora")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_MENU_BACKGROUND_AURORA_FRAG) .withUniform("MenuBackground", UniformType.UNIFORM_BUFFER) @@ -746,7 +746,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline DAMAGE_TINT = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/damage_tint")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_DAMAGE_TINT_FRAG) .withSampler("u_Texture") @@ -762,7 +762,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline POST_FX = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/post_fx")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_POST_FX_FRAG) .withSampler("u_Texture") @@ -779,7 +779,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline MOTION_BLUR = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/motion_blur")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_MOTION_BLUR_FRAG) .withSampler("u_Texture") @@ -796,7 +796,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline DEPTH_OF_FIELD = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/depth_of_field")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_DEPTH_OF_FIELD_FRAG) .withSampler("u_Texture") @@ -818,7 +818,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline HEAT_FX = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/heat_fx")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_HEAT_FX_FRAG) .withSampler("u_Texture") @@ -834,7 +834,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline SHADER_ESP_GRADIENT = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/shader_esp_gradient")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_ESP_GRADIENT_FRAG) .withSampler("u_Texture") @@ -850,7 +850,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline SHADER_ESP_SHADOW = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/shader_esp_shadow")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_ESP_SHADOW_FRAG) .withSampler("u_Texture") @@ -867,7 +867,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline SHADER_ESP_SMOKE = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/shader_esp_smoke")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_ESP_SMOKE_FRAG) .withSampler("u_Texture") @@ -898,7 +898,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline PORTAL_RIFT = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/portal_rift")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_PORTAL_RIFT_FRAG) .withSampler("u_Texture") @@ -914,7 +914,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline SLEEP_OVERLAY = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/sleep_overlay")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_SLEEP_OVERLAY_FRAG) .withSampler("u_Texture") @@ -930,7 +930,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline HAND_GLASS = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/hand_glass")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_HAND_GLASS_FRAG) .withSampler("u_Src") @@ -944,7 +944,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline HAND_SMOKE = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/hand_smoke")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_HAND_SMOKE_FRAG) .withSampler("u_Src") @@ -958,7 +958,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline HAND_METALLIC = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/hand_metallic")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_HAND_METALLIC_FRAG) .withSampler("u_Src") @@ -1010,7 +1010,7 @@ public enum CombatantRenderPipelines { */ public static final RenderPipeline WORLD_REIMAGINED_SKYBOX_SHADER = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, FOG_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/world_reimagined_skybox_shader")) - .withVertexFormat(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_DAMAGE_TINT_VERT) .withFragmentShader(SHADER_REIMAGINED_SKYBOX_FRAG) .withUniform("SkyboxShader", UniformType.UNIFORM_BUFFER) @@ -1025,7 +1025,7 @@ public enum CombatantRenderPipelines { .buildSnippet(); public static final RenderPipeline UI_CIRCLE_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_circle_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS_VERT) .withFragmentShader(SHADER_CIRCLE_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1036,7 +1036,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ARC_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_arc_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS2_VERT) .withFragmentShader(SHADER_ARC_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1047,7 +1047,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ORBIZ_RING_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_orbiz_ring_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS5, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS5, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS5_GENERIC_VERT) .withFragmentShader(SHADER_ORBIZ_RING_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1058,7 +1058,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS_VERT) .withFragmentShader(SHADER_ROUNDED_RECT_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1069,7 +1069,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_FILL_SMOKE_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_fill_smoke_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS5, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS5, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS5_VERT) .withFragmentShader(SHADER_UI_ROUNDED_FILL_SMOKE_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1080,7 +1080,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_STROKE_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_stroke_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS_VERT) .withFragmentShader(SHADER_ROUNDED_RECT_STROKE_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1091,7 +1091,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_STROKE_ANGULAR_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_stroke_angular_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS2_VERT) .withFragmentShader(SHADER_ROUNDED_RECT_STROKE_ANGULAR_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1102,7 +1102,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_CHAMFERED_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_chamfered_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS2_VERT) .withFragmentShader(SHADER_CHAMFERED_RECT_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1113,7 +1113,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_SHAPE_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_shape_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS5, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS5, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS5_VERT) .withFragmentShader(SHADER_UI_SHAPE_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1124,7 +1124,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_CHAMFERED_STROKE_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_chamfered_stroke_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS2_VERT) .withFragmentShader(SHADER_CHAMFERED_RECT_STROKE_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1135,7 +1135,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_STROKE_CORNERS_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_stroke_corners_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS2_VERT) .withFragmentShader(SHADER_ROUNDED_RECT_STROKE_CORNERS_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1146,7 +1146,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_CORNERS_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_corners_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS2_VERT) .withFragmentShader(SHADER_ROUNDED_RECT_CORNERS_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1157,7 +1157,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_GLOW_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_glow_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS_VERT) .withFragmentShader(SHADER_ROUNDED_RECT_GLOW_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1168,7 +1168,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_SHADOW_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_shadow_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS_VERT) .withFragmentShader(SHADER_ROUNDED_RECT_SHADOW_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1179,7 +1179,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_SOFT_SHADOW_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_soft_shadow_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS_VERT) .withFragmentShader(SHADER_ROUNDED_RECT_SOFT_SHADOW_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1190,7 +1190,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_RADIAL_GLOW_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_radial_glow_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS2_VERT) .withFragmentShader(SHADER_RADIAL_GLOW_BATCH_FRAG) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -1201,7 +1201,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_TEXTURED_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_textured_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_TEX_LOCAL_COLOR_RECT_PARAMS_VERT) .withFragmentShader(SHADER_ROUNDED_RECT_TEX_BATCH_FRAG) .withSampler("u_Texture") @@ -1213,7 +1213,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_ROUNDED_TEXTURED_MASK_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_rounded_textured_mask_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_TEX_LOCAL_COLOR_RECT_PARAMS_VERT) .withFragmentShader(SHADER_ROUNDED_RECT_TEX_MASK_BATCH_FRAG) .withSampler("u_Texture") @@ -1225,7 +1225,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_BLUR_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_blur_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS_VERT) .withFragmentShader(SHADER_UI_BLUR_BATCH_FRAG) .withSampler("u_Texture") @@ -1237,7 +1237,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_BLUR_BATCH_CORNERS = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_blur_batch_corners")) - .withVertexFormat(CombatantVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_LOCAL_COLOR_RECT_PARAMS2_VERT) .withFragmentShader(SHADER_UI_BLUR_BATCH_CORNERS_FRAG) .withSampler("u_Texture") @@ -1249,7 +1249,7 @@ public enum CombatantRenderPipelines { ); public static final RenderPipeline UI_LIQUID_GLASS_BATCH = add(new ExtendedRenderPipelineBuilder(MESH_UNIFORMS, UI_BATCH_UNIFORMS) .withLocation(Identifier.fromNamespaceAndPath("lovisual", "pipeline/ui_liquid_glass_batch")) - .withVertexFormat(CombatantVertexFormats.POS2_TEXTURE_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) + .withVertexFormat(LoVisualVertexFormats.POS2_TEXTURE_LOCAL_COLOR_RECT_PARAMS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES) .withVertexShader(SHADER_POS_TEX_LOCAL_COLOR_RECT_PARAMS2_VERT) .withFragmentShader(SHADER_UI_LIQUID_GLASS_BATCH_FRAG) .withSampler("u_Texture") @@ -1269,26 +1269,26 @@ public enum CombatantRenderPipelines { try { device = RenderSystem.getDevice(); } catch (Throwable t) { - DebugLog.warn("[Combatant] RenderSystem not ready in precompile(ResourceManager)"); + DebugLog.warn("[LoVisual] RenderSystem not ready in precompile(ResourceManager)"); return; } - DebugLog.renderThread("[Combatant] Precompiling pipelines: " + PIPELINES.size()); + DebugLog.renderThread("[LoVisual] Precompiling pipelines: " + PIPELINES.size()); for (RenderPipeline pipeline : PIPELINES) { - DebugLog.renderThread("[Combatant] -> pipeline " + pipeline.getLocation()); + DebugLog.renderThread("[LoVisual] -> pipeline " + pipeline.getLocation()); DebugLog.renderThread(" VS = " + pipeline.getVertexShader()); DebugLog.renderThread(" FS = " + pipeline.getFragmentShader()); DebugLog.renderThread(" VF = " + pipeline.getVertexFormatBinding(0)); DebugLog.renderThread(" MODE = " + pipeline.getPrimitiveTopology()); device.precompilePipeline(pipeline, (identifier, shaderType) -> { - DebugLog.renderThread("[Combatant] loading " + shaderType + " " + identifier); - return CombatantShaderSources.load(resources, identifier, shaderType); + DebugLog.renderThread("[LoVisual] loading " + shaderType + " " + identifier); + return LoVisualShaderSources.load(resources, identifier, shaderType); }); } - DebugLog.renderThread("[Combatant] Precompile finished"); + DebugLog.renderThread("[LoVisual] Precompile finished"); } /** @@ -1315,14 +1315,14 @@ public enum CombatantRenderPipelines { } private static void declareDefaultShapeClipContract(RenderPipeline pipeline) { - if (!(pipeline instanceof IRenderPipeline combatantPipeline) || pipeline.getLocation() == null) return; - ShapeClipRenderPassContract current = combatantPipeline.combatant$getShapeClipContract(); + if (!(pipeline instanceof IRenderPipeline lovisualPipeline) || pipeline.getLocation() == null) return; + ShapeClipRenderPassContract current = lovisualPipeline.lovisual$getShapeClipContract(); if (current != ShapeClipRenderPassContract.NONE) return; String namespace = pipeline.getLocation().getNamespace(); String path = pipeline.getLocation().getPath(); - if ("combatant".equals(namespace) && (path.startsWith("pipeline/ui_") || path.equals("pipeline/gui_texture_lookup"))) { - combatantPipeline.combatant$setShapeClipContract(ShapeClipRenderPassContract.WHEN_ACTIVE); + if ("lovisual".equals(namespace) && (path.startsWith("pipeline/ui_") || path.equals("pipeline/gui_texture_lookup"))) { + lovisualPipeline.lovisual$setShapeClipContract(ShapeClipRenderPassContract.WHEN_ACTIVE); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/DepthOfFieldDepthSource.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/DepthOfFieldDepthSource.java index bc6397d..6cc0218 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/DepthOfFieldDepthSource.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/DepthOfFieldDepthSource.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/DepthOfFieldQuality.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/DepthOfFieldQuality.java index b25f587..ab9dc08 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/DepthOfFieldQuality.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/DepthOfFieldQuality.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MenuBackgroundRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MenuBackgroundRenderer.java index 2ee519f..f874aef 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MenuBackgroundRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MenuBackgroundRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -21,11 +21,10 @@ import org.joml.Matrix4f; import dev.loki.lovisual.config.MainConfig; import dev.loki.lovisual.features.theme.Themes; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; import dev.loki.lovisual.render.engine.renderer.MeshRenderer; import dev.loki.lovisual.render.engine.uniform.impl.MenuBackgroundUniforms; -import dev.loki.lovisual.runtime.RuntimeGate; public enum MenuBackgroundRenderer { ; @@ -41,7 +40,7 @@ public enum MenuBackgroundRenderer { } public static void render(Minecraft mc, boolean aurora) { - if (RuntimeGate.isPanic()) return; + if (mc == null) return; if (Renderer2D.isDeferredExtractRecording()) { deferredPending = true; @@ -60,7 +59,7 @@ public enum MenuBackgroundRenderer { } private static void renderNow(Minecraft mc, boolean aurora) { - if (RuntimeGate.isPanic()) return; + if (mc == null) return; RenderTarget fb = mc.gameRenderer.mainRenderTarget(); @@ -99,7 +98,7 @@ public enum MenuBackgroundRenderer { mv.identity(); if (projection == null) { - projection = new ProjectionMatrixBuffer("combatant-menu-bg-projection"); + projection = new ProjectionMatrixBuffer("lovisual-menu-bg-projection"); } Matrix4f proj = IDENTITY.identity(); RenderSystem.setProjectionMatrix(projection.getBuffer(proj), ProjectionType.PERSPECTIVE); @@ -107,10 +106,10 @@ public enum MenuBackgroundRenderer { RenderState.rendering3D = false; var pipeline = aurora - ? CombatantRenderPipelines.MENU_BACKGROUND_AURORA - : CombatantRenderPipelines.MENU_BACKGROUND_WAVES; + ? LoVisualRenderPipelines.MENU_BACKGROUND_AURORA + : LoVisualRenderPipelines.MENU_BACKGROUND_WAVES; - FullScreenRenderer.begin("Combatant Fullscreen Pass") + FullScreenRenderer.begin("LoVisual Fullscreen Pass") .attachment(fb) .pipeline(pipeline) .uniform("MenuBackground", MenuBackgroundUniforms.get()) diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MotionBlurMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MotionBlurMode.java index 117ab5d..766bb96 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MotionBlurMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MotionBlurMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MotionBlurResources.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MotionBlurResources.java index 479c9f6..d2639c1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MotionBlurResources.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/MotionBlurResources.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,7 +10,7 @@ package dev.loki.lovisual.render.engine.postprocess; import com.mojang.blaze3d.pipeline.TextureTarget; import com.mojang.blaze3d.textures.GpuTextureView; import net.minecraft.client.Minecraft; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; public final class MotionBlurResources { private TextureTarget previousColor; @@ -29,8 +29,8 @@ public final class MotionBlurResources { int h = Math.max(1, height); if (w <= 0 || h <= 0) return false; - TextureTarget next = CombatantRenderSystem.resources().persistentFramebuffer( - "combatant-motion-blur-previous-color", w, h, false, "MotionBlurResources"); + TextureTarget next = LoVisualRenderSystem.resources().persistentFramebuffer( + "lovisual-motion-blur-previous-color", w, h, false, "MotionBlurResources"); if (previousColor != next) { previousColor = next; previousValid = false; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessContext.java index 4c46de3..e850d49 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessManager.java index 081668b..4e9ea29 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,15 +17,15 @@ import com.mojang.blaze3d.textures.GpuTextureView; import net.minecraft.client.Minecraft; import org.joml.Matrix4f; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.graph.PostProcessGraph; import dev.loki.lovisual.render.engine.profiler.RenderCostProfiler; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; import dev.loki.lovisual.render.engine.renderer.MeshRenderer; import dev.loki.lovisual.render.engine.rhi.FullscreenDrawCommand; import dev.loki.lovisual.render.engine.uniform.impl.PostProcessUniforms; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import java.util.OptionalDouble; @@ -43,7 +43,7 @@ public enum PostProcessManager { } public static void renderAll(PostProcessPass.Phase phase, float tickDelta) { - if (!RuntimeGate.canRunRender()) return; + if (!Lifecycle.canRunRender()) return; Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.gameRenderer.mainRenderTarget() == null) return; @@ -64,8 +64,8 @@ public enum PostProcessManager { GRAPH.execute( phase, tickDelta, - CombatantRenderSystem.ensureFrameContext(), - CombatantRenderSystem.rhi(), + LoVisualRenderSystem.ensureFrameContext(), + LoVisualRenderSystem.rhi(), PostProcessManager::copy ); } finally { @@ -98,26 +98,21 @@ public enum PostProcessManager { public static void copy(GpuTextureView src, GpuTextureView dst) { try (RenderCostProfiler.Scope ignored = RenderCostProfiler.postPass("copy")) { if (src == null || dst == null || src == dst) return; - if (CombatantRenderSystem.rhi().textureBlitter().copyFast(src, dst)) { + if (LoVisualRenderSystem.rhi().textureBlitter().copyFast(src, dst)) { return; } ensureSampler(); PostProcessUniforms.update(0.0f, 0.0f, 0.0f, 0.0f); - CombatantRenderSystem.rhi().drawFullscreen( - FullscreenDrawCommand.builder("Combatant PostProcess Copy") + LoVisualRenderSystem.rhi().drawFullscreen( + FullscreenDrawCommand.builder("LoVisual PostProcess Copy") .colorAttachment(dst) - .pipeline(CombatantRenderPipelines.DAMAGE_TINT) + .pipeline(LoVisualRenderPipelines.DAMAGE_TINT) .uniform("PostProcess", PostProcessUniforms.get()) .sampler("u_Texture", src, sampler) .build() ); - CombatantRenderSystem.rhi().stats().textureShaderCopy(); + LoVisualRenderSystem.rhi().stats().textureShaderCopy(); } } - - public static void shutdownForRuntime() { - GRAPH.close(); - sampler = null; - } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessPass.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessPass.java index 8cf0f42..f2d9009 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessPass.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/PostProcessPass.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/HistoryBufferManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/HistoryBufferManager.java index a2156d4..d42d8b6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/HistoryBufferManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/HistoryBufferManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/LegacyPostProcessGraphPass.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/LegacyPostProcessGraphPass.java index f8b85ac..fa482aa 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/LegacyPostProcessGraphPass.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/LegacyPostProcessGraphPass.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import com.mojang.blaze3d.textures.GpuTextureView; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.postprocess.PostProcessContext; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; import java.util.Set; @@ -64,7 +64,7 @@ public final class LegacyPostProcessGraphPass implements PostProcessGraphPass { } @Override - public boolean execute(RenderFrameContext context, CombatantRhi rhi, PostProcessGraphResources resources) { + public boolean execute(RenderFrameContext context, LoVisualRhi rhi, PostProcessGraphResources resources) { GpuTextureView src = resources.currentSource(); GpuTextureView dst = resources.currentDestination(); PostProcessContext legacyContext = resources.legacyContext(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraph.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraph.java index f7d563c..f78e275 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraph.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraph.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import com.mojang.blaze3d.textures.GpuTextureView; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; import dev.loki.lovisual.render.engine.profiler.RenderCostProfiler; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; import java.util.ArrayList; import java.util.Comparator; @@ -53,7 +53,7 @@ public final class PostProcessGraph implements AutoCloseable { public boolean execute(PostProcessPass.Phase phase, float tickDelta, RenderFrameContext context, - CombatantRhi rhi, + LoVisualRhi rhi, GraphCopy copy) { if (!hasActivePass(phase, context)) return false; try (RenderCostProfiler.Scope ignoredGraph = RenderCostProfiler.postPass("graph:" + phase)) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraphPass.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraphPass.java index 1d30ddc..0cb965b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraphPass.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraphPass.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -9,7 +9,7 @@ package dev.loki.lovisual.render.engine.postprocess.graph; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.postprocess.PostProcessPass; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; import java.util.Set; @@ -35,5 +35,5 @@ public interface PostProcessGraphPass { /** * Returns true when the pass wrote its destination and the graph should advance ping-pong state. */ - boolean execute(RenderFrameContext context, CombatantRhi rhi, PostProcessGraphResources resources); + boolean execute(RenderFrameContext context, LoVisualRhi rhi, PostProcessGraphResources resources); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraphResources.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraphResources.java index f788c54..f2c8eb6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraphResources.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessGraphResources.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,7 +14,7 @@ import net.minecraft.client.Minecraft; import org.jetbrains.annotations.Nullable; import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.features.module.modules.visuals.ReimaginedVisual; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.depth.PreTranslucentDepth; import dev.loki.lovisual.render.engine.depth.WorldSceneDepth; import dev.loki.lovisual.render.engine.postprocess.PostProcessContext; @@ -139,10 +139,10 @@ public final class PostProcessGraphResources implements AutoCloseable { } private void ensurePingPong(int w, int h) { - ping = CombatantRenderSystem.resources().persistentFramebuffer( - "combatant-postprocess-graph-ping", w, h, false, "PostProcessGraph"); - pong = CombatantRenderSystem.resources().persistentFramebuffer( - "combatant-postprocess-graph-pong", w, h, false, "PostProcessGraph"); + ping = LoVisualRenderSystem.resources().persistentFramebuffer( + "lovisual-postprocess-graph-ping", w, h, false, "PostProcessGraph"); + pong = LoVisualRenderSystem.resources().persistentFramebuffer( + "lovisual-postprocess-graph-pong", w, h, false, "PostProcessGraph"); } private static boolean needsPreTranslucentDepth() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessResolution.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessResolution.java index f4167e6..966698f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessResolution.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessResolution.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessResource.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessResource.java index e7319f2..346de22 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessResource.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/postprocess/graph/PostProcessResource.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/prewarm/RenderPrewarmContributors.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/prewarm/RenderPrewarmContributors.java index 0bc3539..8e7487b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/prewarm/RenderPrewarmContributors.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/prewarm/RenderPrewarmContributors.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/prewarm/RenderPrewarmManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/prewarm/RenderPrewarmManager.java index 08ed286..0bd956b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/prewarm/RenderPrewarmManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/prewarm/RenderPrewarmManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import dev.loki.lovisual.events.impl.RenderPrewarmCollectEvent; import dev.loki.lovisual.features.gui.hud.script.HudScriptLayouts; import dev.loki.lovisual.render.engine.svg.SvgMsdfRegistry; import dev.loki.lovisual.render.engine.text.Fonts; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; import dev.loki.lovisual.util.logging.DebugLog; import net.minecraft.client.Minecraft; import net.minecraft.resources.Identifier; @@ -21,13 +21,13 @@ public enum RenderPrewarmManager { ; public static void prewarm(String reason) { - if (!RuntimeGate.canRunClientLogic()) return; + if (!Lifecycle.isActive()) return; RenderPrewarmCollectEvent event = new RenderPrewarmCollectEvent(reason); Events.BUS.post(event); UiScriptStats uiScripts = prewarmUiScripts(); if (event.isEmpty()) { - DebugLog.renderThread("[Combatant][Prewarm] %s: ui-scripts=%d changed, %d cached, %d errors", + DebugLog.renderThread("[LoVisual][Prewarm] %s: ui-scripts=%d changed, %d cached, %d errors", event.reason(), uiScripts.changed(), uiScripts.cached(), uiScripts.errors()); return; } @@ -40,7 +40,7 @@ public enum RenderPrewarmManager { } } - DebugLog.renderThread("[Combatant][Prewarm] %s: fonts=%d/%d svg-msdf=%d/%d ui-scripts=%d changed, %d cached, %d errors", + DebugLog.renderThread("[LoVisual][Prewarm] %s: fonts=%d/%d svg-msdf=%d/%d ui-scripts=%d changed, %d cached, %d errors", event.reason(), fonts, event.fonts().size(), svg, event.svgMsdfIcons().size(), uiScripts.changed(), uiScripts.cached(), uiScripts.errors()); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/DevProfilerBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/DevProfilerBridge.java index 5994f1f..0ff0a4a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/DevProfilerBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/DevProfilerBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/FrameStutterProfiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/FrameStutterProfiler.java index 99c8b9d..368a7ac 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/FrameStutterProfiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/FrameStutterProfiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/GlSyncTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/GlSyncTracker.java index f6e5c83..3897279 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/GlSyncTracker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/GlSyncTracker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/JfrProfiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/JfrProfiler.java index e538ef2..a6f4cc1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/JfrProfiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/JfrProfiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerLog.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerLog.java index 5c6fa29..a3a6aa5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerLog.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerLog.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerPhase.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerPhase.java index bb84668..26df192 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerPhase.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerPhase.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerSettings.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerSettings.java index 2ac0256..7f230d9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerSettings.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/ProfilerSettings.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderCostProfiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderCostProfiler.java index de0cf43..7c3fe71 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderCostProfiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderCostProfiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderFrameProfiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderFrameProfiler.java index 704a3f0..b877c6c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderFrameProfiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderFrameProfiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderProfiler2D.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderProfiler2D.java index 9e7434c..320dd1b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderProfiler2D.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderProfiler2D.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderProfiler3D.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderProfiler3D.java index a3295cb..3e24e4b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderProfiler3D.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/RenderProfiler3D.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/SamplingProfiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/SamplingProfiler.java index 6b469ed..2e2c3db 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/SamplingProfiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/SamplingProfiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/TracyGpuProfiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/TracyGpuProfiler.java index 9a12c4c..a0744fb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/TracyGpuProfiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/TracyGpuProfiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/TracyProfiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/TracyProfiler.java index b7a4e1a..372c7f1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/TracyProfiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/profiler/TracyProfiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/FullScreenRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/FullScreenRenderer.java index 815e650..91df7e9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/FullScreenRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/FullScreenRenderer.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -19,13 +19,13 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.textures.GpuSampler; import com.mojang.blaze3d.textures.GpuTextureView; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.guard.LegacyRenderPath; import dev.loki.lovisual.render.engine.guard.RenderArchitectureGuard; import dev.loki.lovisual.render.engine.rhi.FullscreenDrawCommand; import dev.loki.lovisual.render.engine.rhi.GpuMeshHandle; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; -import dev.loki.lovisual.render.engine.vertex.CombatantVertexFormats; +import dev.loki.lovisual.render.engine.vertex.LoVisualVertexFormats; /** * Compatibility facade for fullscreen rendering. @@ -40,7 +40,7 @@ public enum FullScreenRenderer { /** * Legacy CPU mesh kept only for detection of old code paths. Production code must use FullScreenRenderer.begin() - * or CombatantRHI.fullscreen() directly. + * or LoVisualRHI.fullscreen() directly. */ @Deprecated(forRemoval = false) public static MeshBuilder mesh; @@ -49,13 +49,13 @@ public enum FullScreenRenderer { public static void init() { if (initialized) return; - GpuMeshHandle quad = CombatantRenderSystem.rhi().fullscreen().quad(); + GpuMeshHandle quad = LoVisualRenderSystem.rhi().fullscreen().quad(); vbo = quad.vertexBuffer(); ibo = quad.indexBuffer(); // Compatibility marker mesh. MeshRenderer detects this object and routes it through the RHI // fullscreen backend, so it does not trigger a CPU quad upload anymore. - mesh = new MeshBuilder(CombatantVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES, 4, 6); + mesh = new MeshBuilder(LoVisualVertexFormats.POS2, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES, 4, 6); mesh.begin(); mesh.quad( mesh.vec2(-1, -1).next(), @@ -86,11 +86,11 @@ public enum FullScreenRenderer { } public static Draw draw(GpuTextureView dst, RenderPipeline pipeline) { - return begin("Combatant Fullscreen Pass").attachment(dst).pipeline(pipeline); + return begin("LoVisual Fullscreen Pass").attachment(dst).pipeline(pipeline); } public static Draw draw(RenderTarget dst, RenderPipeline pipeline) { - return begin("Combatant Fullscreen Pass").attachment(dst).pipeline(pipeline); + return begin("LoVisual Fullscreen Pass").attachment(dst).pipeline(pipeline); } public static final class Draw { @@ -131,7 +131,7 @@ public enum FullScreenRenderer { } public void end() { - CombatantRenderSystem.rhi().drawFullscreen(builder.build()); + LoVisualRenderSystem.rhi().drawFullscreen(builder.build()); } } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/MeshRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/MeshRenderer.java index 7b4728c..354646b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/MeshRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/MeshRenderer.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -27,7 +27,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Matrix4fStack; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.rhi.GpuMeshHandle; import dev.loki.lovisual.render.engine.rhi.MeshOwnership; import dev.loki.lovisual.render.engine.rhi.RhiDrawCommand; @@ -169,7 +169,7 @@ public final class MeshRenderer { if (mesh != null && FullScreenRenderer.isLegacyFullscreenMesh(mesh) && depthAttachment == null && transform == null) { FullscreenDrawCommand.Builder fullscreen = - FullscreenDrawCommand.builder("Combatant MeshRenderer Fullscreen Compatibility") + FullscreenDrawCommand.builder("LoVisual MeshRenderer Fullscreen Compatibility") .pipeline(pipeline) .colorAttachment(colorAttachment) .clearColor(clearColorArgb); @@ -180,19 +180,19 @@ public final class MeshRenderer { SamplerBinding b = e.getValue(); fullscreen.sampler(e.getKey(), b.view, b.sampler); } - CombatantRenderSystem.rhi().drawFullscreen(fullscreen.build()); + LoVisualRenderSystem.rhi().drawFullscreen(fullscreen.build()); return; } if (mesh != null) { - uploaded = CombatantRenderSystem.rhi().dynamicMeshes().upload(mesh); + uploaded = LoVisualRenderSystem.rhi().dynamicMeshes().upload(mesh); } else if (vertexBuffer != null && indexBuffer != null) { uploaded = new GpuMeshHandle(vertexBuffer, indexBuffer, 0L, 0, indexCount, com.mojang.blaze3d.IndexType.INT, MeshOwnership.EXTERNAL); } else { return; } - RhiDrawCommand.Builder command = RhiDrawCommand.builder("Combatant MeshRenderer") + RhiDrawCommand.Builder command = RhiDrawCommand.builder("LoVisual MeshRenderer") .pipeline(pipeline) .colorAttachment(colorAttachment) .depthAttachment(depthAttachment) @@ -209,7 +209,7 @@ public final class MeshRenderer { command.sampler(e.getKey(), b.view, b.sampler); } - CombatantRenderSystem.rhi().drawMesh(command.build()); + LoVisualRenderSystem.rhi().drawMesh(command.build()); uploaded = null; // backend owns release for this draw } finally { if (uploaded != null) uploaded.close(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/RenderWarp.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/RenderWarp.java index da42273..c9f58e0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/RenderWarp.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/RenderWarp.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/RenderWarpStack.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/RenderWarpStack.java index dd9b5b2..28dafa5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/RenderWarpStack.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/RenderWarpStack.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2D.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2D.java index f33c712..080abb7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2D.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2D.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ import org.jetbrains.annotations.Nullable; import dev.loki.lovisual.render.engine.color.RenderColor; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.ViewportContext; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.ui.BlurSource; import dev.loki.lovisual.render.engine.renderer.ui.Deferred2DSubmit; import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; @@ -125,21 +125,21 @@ public final class Renderer2D { public static Renderer2D COLOR; public static Renderer2D TEXTURE; - private final boolean textured; - private final MeshBuilder texturedTriangles; - private final int[] gradientTmp = new int[4]; - private final float[] cornerRadiiTmp = new float[4]; - private final double[] rectShapeTmp = new double[256]; - private final double[] connectorTmp = new double[64]; - private final double[] connectorAnchorTmp = new double[4]; - private final int[] polygonIndexTmp = new int[64]; - private final int[] polygonVertexTmp = new int[64]; - private final double[] progressShapeTmp = new double[256]; - private double alpha = 1.0; + final boolean textured; + final MeshBuilder texturedTriangles; + final int[] gradientTmp = new int[4]; + final float[] cornerRadiiTmp = new float[4]; + final double[] rectShapeTmp = new double[256]; + final double[] connectorTmp = new double[64]; + final double[] connectorAnchorTmp = new double[4]; + final int[] polygonIndexTmp = new int[64]; + final int[] polygonVertexTmp = new int[64]; + final double[] progressShapeTmp = new double[256]; + double alpha = 1.0; public Renderer2D(boolean textured) { this.textured = textured; - this.texturedTriangles = textured ? new MeshBuilder(CombatantRenderPipelines.UI_TEXTURED) : null; + this.texturedTriangles = textured ? new MeshBuilder(LoVisualRenderPipelines.UI_TEXTURED) : null; } public static void init() { @@ -175,10 +175,7 @@ public final class Renderer2D { } public void box(UiBoxShape box, UiPaint paint, UiStroke stroke, boolean fill) { - if (box == null || paint == null) return; - UiStroke safeStroke = stroke == null ? UiStroke.NONE : stroke; - recordUi(new UiShapeCommand(UiShape.box(box), paint, safeStroke, fill)); - renderFlexibleBoxFallback(box, paint, safeStroke, fill); + Renderer2DPolygons.box(this, box, paint, stroke, fill); } public void shape(UiShape shape, UiPaint paint, UiStroke stroke, boolean fill) { @@ -371,25 +368,9 @@ public final class Renderer2D { @Nullable String stackCountText, int durabilityThresholdPercent, int durabilityTextColorThresholdPercent) { - UiItemSubmission.submit( - textured, - alpha, - player, - stack, - x, - y, - scaleX, - scaleY, - pivotX, - pivotY, - pivoted, - seed, - drawItem, - overlayFlags, - stackCountText, - durabilityThresholdPercent, - durabilityTextColorThresholdPercent - ); + Renderer2DItems.submit(this, + player, stack, x, y, scaleX, scaleY, pivotX, pivotY, pivoted, seed, drawItem, overlayFlags, + stackCountText, durabilityThresholdPercent, durabilityTextColorThresholdPercent); } public void begin() { @@ -518,36 +499,7 @@ public final class Renderer2D { double w, double h, int argb) { - if (textured) { - throw new IllegalStateException("Batched texture quad drawing is supported only on Renderer2D.COLOR."); - } - if (samplerView == null || sampler == null) return; - if (w == 0.0 || h == 0.0) return; - - recordUi(new UiTextureDrawCommand(samplerView, sampler, UiShape.rect(x, y, w, h), UiPaint.solid(argb), 0f, 0f, 1f, 1f, false)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.TEXTURED, samplerView, sampler); - if (batch == null) { - endAutoBatch(auto); - return; - } - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - int i1 = mesh.vec2(x, y).raw2(0.0, 0.0).color(r, g, b, a).next(); - int i2 = mesh.vec2(x, y + h).raw2(0.0, 1.0).color(r, g, b, a).next(); - int i3 = mesh.vec2(x + w, y + h).raw2(1.0, 1.0).color(r, g, b, a).next(); - int i4 = mesh.vec2(x + w, y).raw2(1.0, 0.0).color(r, g, b, a).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DTextures.textureQuad(this, samplerView, sampler, x, y, w, h, argb); } public void msdfTextureQuad(GpuTextureView samplerView, @@ -576,120 +528,24 @@ public final class Renderer2D { float pxRange, int atlasWidth, int atlasHeight) { - if (textured) { - throw new IllegalStateException("Batched MSDF texture quad drawing is supported only on Renderer2D.COLOR."); - } - if (samplerView == null || sampler == null) return; - if (w == 0.0 || h == 0.0) return; - if (pxRange <= 0.0f || atlasWidth <= 0 || atlasHeight <= 0) return; - - recordUi(new UiTextureDrawCommand(samplerView, sampler, UiShape.rect(x, y, w, h), UiPaint.solid(topLeft), 0f, 0f, 1f, 1f, false)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreateMsdf(samplerView, sampler, pxRange, atlasWidth, atlasHeight); - if (batch == null) { - endAutoBatch(auto); - return; - } - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int i1 = mesh.vec2(x, y).raw2(0.0, 0.0).color((topLeft >>> 16) & 0xFF, (topLeft >>> 8) & 0xFF, topLeft & 0xFF, (topLeft >>> 24) & 0xFF).next(); - int i2 = mesh.vec2(x, y + h).raw2(0.0, 1.0).color((bottomLeft >>> 16) & 0xFF, (bottomLeft >>> 8) & 0xFF, bottomLeft & 0xFF, (bottomLeft >>> 24) & 0xFF).next(); - int i3 = mesh.vec2(x + w, y + h).raw2(1.0, 1.0).color((bottomRight >>> 16) & 0xFF, (bottomRight >>> 8) & 0xFF, bottomRight & 0xFF, (bottomRight >>> 24) & 0xFF).next(); - int i4 = mesh.vec2(x + w, y).raw2(1.0, 0.0).color((topRight >>> 16) & 0xFF, (topRight >>> 8) & 0xFF, topRight & 0xFF, (topRight >>> 24) & 0xFF).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DTextures.msdfTextureQuad(this, samplerView, sampler, x, y, w, h, + topLeft, topRight, bottomRight, bottomLeft, pxRange, atlasWidth, atlasHeight); } public void quadBatch(Consumer consumer) { - if (textured) { - throw new IllegalStateException("Quad batching is supported only on Renderer2D.COLOR."); - } - if (consumer == null) return; - - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); - if (batch == null) { - endAutoBatch(auto); - return; - } - - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - QuadBatch quadBatch = new QuadBatch(mesh); - try { - consumer.accept(quadBatch); - } finally { - endAutoBatch(auto); - } + Renderer2DRects.quadBatch(this, consumer); } public void line(double x1, double y1, double x2, double y2, int argb) { - double[] p = {x1, y1, x2, y2}; - path(UiShape.polyline(p, 2, false), UiPaint.solid(argb), UiStroke.of(1.0), false); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.LINES, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureLineCapacity(); - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - int i1 = mesh.vec2(x1, y1).color(r, g, b, a).next(); - int i2 = mesh.vec2(x2, y2).color(r, g, b, a).next(); - mesh.line(i1, i2); - - endAutoBatch(auto); + Renderer2DLines.line(this, x1, y1, x2, y2, argb); } public void line(double x1, double y1, double x2, double y2, RenderColor color) { - double[] p = {x1, y1, x2, y2}; - path(UiShape.polyline(p, 2, false), UiPaint.solid(color.argb()), UiStroke.of(1.0), false); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.LINES, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureLineCapacity(); - int i1 = mesh.vec2(x1, y1).color(color.r, color.g, color.b, color.a).next(); - int i2 = mesh.vec2(x2, y2).color(color.r, color.g, color.b, color.a).next(); - mesh.line(i1, i2); - - endAutoBatch(auto); + Renderer2DLines.line(this, x1, y1, x2, y2, color); } public void boxLines(double x, double y, double width, double height, int argb) { - shapeStroke(UiShape.rect(x, y, width, height), UiPaint.solid(argb), UiStroke.of(1.0)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.LINES, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureCapacity(4, 8); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - int i1 = mesh.vec2(x, y).color(r, g, b, a).next(); - int i2 = mesh.vec2(x, y + height).color(r, g, b, a).next(); - int i3 = mesh.vec2(x + width, y + height).color(r, g, b, a).next(); - int i4 = mesh.vec2(x + width, y).color(r, g, b, a).next(); - - mesh.line(i1, i2); - mesh.line(i2, i3); - mesh.line(i3, i4); - mesh.line(i4, i1); - - endAutoBatch(auto); + Renderer2DLines.boxLines(this, x, y, width, height, argb); } public void quad(double x, double y, double width, double height, int argb) { @@ -697,16 +553,7 @@ public final class Renderer2D { } public void quad(double x, double y, double width, double height, int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { - shape(UiShape.rect(x, y, width, height), UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - appendColoredQuad(mesh, x, y, width, height, cTopLeft, cTopRight, cBottomRight, cBottomLeft); - - endAutoBatch(auto); + Renderer2DRects.quadCorners(this, x, y, width, height, cTopLeft, cTopRight, cBottomRight, cBottomLeft); } public void roundedRect(double x, double y, double w, double h, @@ -724,33 +571,7 @@ public final class Renderer2D { } public void circle(double cx, double cy, double radius, float softness, int argb) { - shape(UiShape.circle(cx, cy, radius), UiPaint.solid(argb)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.CIRCLE, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double outerRadius = radius + Math.max(0.0f, softness); - double x = cx - outerRadius; - double y = cy - outerRadius; - double w = outerRadius * 2.0; - double h = outerRadius * 2.0; - - int i1 = mesh.vec2(x, y).local2(x, y).color(r, g, b, a).vec4(x, y, w, h).vec4((float) radius, softness, 0f, 0f).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4((float) radius, softness, 0f, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4((float) radius, softness, 0f, 0f).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(r, g, b, a).vec4(x, y, w, h).vec4((float) radius, softness, 0f, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DCircles.circle(this, cx, cy, radius, softness, argb); } public void circleSoftShadow(double cx, double cy, double radius, float blur, float innerAlpha, int argb) { @@ -764,34 +585,7 @@ public final class Renderer2D { } public void circleStroke(double cx, double cy, double radius, double thickness, float softness, int argb) { - shapeStroke(UiShape.circle(cx, cy, radius), UiPaint.solid(argb), UiStroke.of(thickness)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.CIRCLE, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - float stroke = (float) Math.max(0.0, thickness); - double outerRadius = radius + stroke * 0.5 + softness; - double x = cx - outerRadius; - double y = cy - outerRadius; - double w = outerRadius * 2.0; - double h = outerRadius * 2.0; - - int i1 = mesh.vec2(x, y).local2(x, y).color(r, g, b, a).vec4(x, y, w, h).vec4((float) radius, softness, stroke, 0f).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4((float) radius, softness, stroke, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4((float) radius, softness, stroke, 0f).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(r, g, b, a).vec4(x, y, w, h).vec4((float) radius, softness, stroke, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DCircles.circleStroke(this, cx, cy, radius, thickness, softness, argb); } public void arcStroke(double cx, double cy, double radius, double thickness, @@ -857,157 +651,21 @@ public final class Renderer2D { public void arcStrokeQuad(double cx, double cy, double radius, double thickness, float startAngleDeg, float endAngleDeg, float softness, boolean caps, int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { - float start = normalizeDegrees(startAngleDeg); - float end = normalizeDegrees(endAngleDeg); - float sweep = end - start; - if (sweep <= 0.0f) { - sweep += 360.0f; - } - if (sweep <= 0.001f) { - return; - } - - shapeStroke(UiShape.arc(cx, cy, radius, start, end), UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft), UiStroke.of(thickness)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ARC, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - float stroke = (float) Math.max(0.0, thickness); - double outerRadius = radius + stroke * 0.5 + softness; - double x = cx - outerRadius; - double y = cy - outerRadius; - double w = outerRadius * 2.0; - double h = outerRadius * 2.0; - - int tlA = (cTopLeft >>> 24) & 0xFF; - int tlR = (cTopLeft >>> 16) & 0xFF; - int tlG = (cTopLeft >>> 8) & 0xFF; - int tlB = cTopLeft & 0xFF; - int trA = (cTopRight >>> 24) & 0xFF; - int trR = (cTopRight >>> 16) & 0xFF; - int trG = (cTopRight >>> 8) & 0xFF; - int trB = cTopRight & 0xFF; - int brA = (cBottomRight >>> 24) & 0xFF; - int brR = (cBottomRight >>> 16) & 0xFF; - int brG = (cBottomRight >>> 8) & 0xFF; - int brB = cBottomRight & 0xFF; - int blA = (cBottomLeft >>> 24) & 0xFF; - int blR = (cBottomLeft >>> 16) & 0xFF; - int blG = (cBottomLeft >>> 8) & 0xFF; - int blB = cBottomLeft & 0xFF; - - int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(x, y, w, h) - .vec4((float) radius, softness, stroke, start).vec4(end, caps ? 1f : 0f, 0f, 0f).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(x, y, w, h) - .vec4((float) radius, softness, stroke, start).vec4(end, caps ? 1f : 0f, 0f, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(x, y, w, h) - .vec4((float) radius, softness, stroke, start).vec4(end, caps ? 1f : 0f, 0f, 0f).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(x, y, w, h) - .vec4((float) radius, softness, stroke, start).vec4(end, caps ? 1f : 0f, 0f, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DCircles.arcStrokeQuad(this, cx, cy, radius, thickness, startAngleDeg, endAngleDeg, softness, caps, + cTopLeft, cTopRight, cBottomRight, cBottomLeft); } public void orbizRing(double cx, double cy, - double radius, double thickness, - float startAngleDeg, float sweepAngleDeg, - float softness, float glowRadius, float glowStrength, - int primaryArgb, int secondaryArgb, - int colorMode, float angularOffset, float angularCycles, - float trackAlpha, float bodyAlpha, float headBoost, - float trackGlow, boolean caps) { - if (textured) { - throw new IllegalStateException("Orbiz ring drawing is supported only on Renderer2D.COLOR."); - } - if (radius <= 0.0 || thickness <= 0.0) return; - if (((primaryArgb >>> 24) & 0xFF) <= 0 && ((secondaryArgb >>> 24) & 0xFF) <= 0) return; - - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ORBIZ_RING, null, null); - if (batch == null) { - endAutoBatch(auto); - return; - } - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (primaryArgb >>> 24) & 0xFF; - int r = (primaryArgb >>> 16) & 0xFF; - int g = (primaryArgb >>> 8) & 0xFF; - int b = primaryArgb & 0xFF; - - float sr = ((secondaryArgb >>> 16) & 0xFF) / 255.0f; - float sg = ((secondaryArgb >>> 8) & 0xFF) / 255.0f; - float sb = (secondaryArgb & 0xFF) / 255.0f; - float sa = ((secondaryArgb >>> 24) & 0xFF) / 255.0f; - - float stroke = (float) Math.max(0.0, thickness); - float ringRadius = (float) Math.max(0.0, radius); - float soft = Math.max(0.0f, softness); - float glow = Math.max(0.0f, glowRadius); - float expand = stroke * 0.5f + soft + glow + 1.0f; - double outerRadius = radius + expand; - double x = cx - outerRadius; - double y = cy - outerRadius; - double w = outerRadius * 2.0; - double h = outerRadius * 2.0; - double ringX = cx - radius; - double ringY = cy - radius; - double ringSize = radius * 2.0; - - float start = normalizeDegrees(startAngleDeg); - float sweep = Mth.clamp(sweepAngleDeg, 0.0f, 360.0f); - float offset = angularOffset - (float) Math.floor(angularOffset); - float cycles = Math.max(0.001f, angularCycles); - float mode = Math.max(0, colorMode); - float track = Mth.clamp(trackAlpha, 0.0f, 1.0f); - float body = Mth.clamp(bodyAlpha, 0.0f, 1.0f); - float glowPower = Math.max(0.0f, glowStrength); - float head = Math.max(0.0f, headBoost); - float trackGlowAmount = Mth.clamp(trackGlow, 0.0f, 1.0f); - - int i1 = mesh.vec2(x, y).local2(x, y).color(r, g, b, a) - .vec4(ringX, ringY, ringSize, ringSize) - .vec4(ringRadius, soft, stroke, start) - .vec4(sweep, glow, glowPower, mode) - .vec4(sr, sg, sb, sa) - .vec4(offset, cycles, 0.0f, caps ? 1.0f : 0.0f) - .vec4(track, body, head, trackGlowAmount) - .next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(r, g, b, a) - .vec4(ringX, ringY, ringSize, ringSize) - .vec4(ringRadius, soft, stroke, start) - .vec4(sweep, glow, glowPower, mode) - .vec4(sr, sg, sb, sa) - .vec4(offset, cycles, 0.0f, caps ? 1.0f : 0.0f) - .vec4(track, body, head, trackGlowAmount) - .next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(r, g, b, a) - .vec4(ringX, ringY, ringSize, ringSize) - .vec4(ringRadius, soft, stroke, start) - .vec4(sweep, glow, glowPower, mode) - .vec4(sr, sg, sb, sa) - .vec4(offset, cycles, 0.0f, caps ? 1.0f : 0.0f) - .vec4(track, body, head, trackGlowAmount) - .next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(r, g, b, a) - .vec4(ringX, ringY, ringSize, ringSize) - .vec4(ringRadius, soft, stroke, start) - .vec4(sweep, glow, glowPower, mode) - .vec4(sr, sg, sb, sa) - .vec4(offset, cycles, 0.0f, caps ? 1.0f : 0.0f) - .vec4(track, body, head, trackGlowAmount) - .next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + double radius, double thickness, + float startAngleDeg, float sweepAngleDeg, + float softness, float glowRadius, float glowStrength, + int primaryArgb, int secondaryArgb, + int colorMode, float angularOffset, float angularCycles, + float trackAlpha, float bodyAlpha, float headBoost, + float trackGlow, boolean caps) { + Renderer2DOrbiz.orbizRing(this, cx, cy, radius, thickness, startAngleDeg, sweepAngleDeg, + softness, glowRadius, glowStrength, primaryArgb, secondaryArgb, + colorMode, angularOffset, angularCycles, trackAlpha, bodyAlpha, headBoost, trackGlow, caps); } public void roundedRectMasked(double x, double y, double w, double h, @@ -1018,29 +676,7 @@ public final class Renderer2D { public void roundedRectStroke(double x, double y, double w, double h, float radius, float softness, float thickness, int argb) { - shapeStroke(UiShape.roundedRect(x, y, w, h, radius), UiPaint.solid(argb), UiStroke.of(thickness)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_STROKE, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - float clampedRadius = clampRoundedRadius(radius, w, h); - float stroke = Math.max(0.0f, thickness); - - int i1 = mesh.vec2(x, y).local2(x, y).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DRectsExtra.roundedRectStroke(this, x, y, w, h, radius, softness, thickness, argb); } public void roundedRectStroke(double x, double y, double w, double h, @@ -1051,62 +687,15 @@ public final class Renderer2D { public void roundedRectStrokeAngularGradient(double x, double y, double w, double h, float radius, float softness, float thickness, int startArgb, int endArgb, float offset) { - shapeStroke(UiShape.roundedRect(x, y, w, h, radius), UiPaint.solid(startArgb), UiStroke.of(thickness)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_STROKE_ANGULAR, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int sa = (startArgb >>> 24) & 0xFF; - int sr = (startArgb >>> 16) & 0xFF; - int sg = (startArgb >>> 8) & 0xFF; - int sb = startArgb & 0xFF; - float ea = ((endArgb >>> 24) & 0xFF) / 255.0f; - float er = ((endArgb >>> 16) & 0xFF) / 255.0f; - float eg = ((endArgb >>> 8) & 0xFF) / 255.0f; - float eb = (endArgb & 0xFF) / 255.0f; - float clampedRadius = clampRoundedRadius(radius, w, h); - float stroke = Math.max(0.0f, thickness); - float phase = offset - (float) Math.floor(offset); - - int i1 = mesh.vec2(x, y).local2(x, y).color(sr, sg, sb, sa).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, phase).vec4(er, eg, eb, ea).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(sr, sg, sb, sa).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, phase).vec4(er, eg, eb, ea).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(sr, sg, sb, sa).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, phase).vec4(er, eg, eb, ea).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(sr, sg, sb, sa).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, phase).vec4(er, eg, eb, ea).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DRectsExtra.roundedRectStrokeAngularGradient(this, x, y, w, h, radius, softness, thickness, + startArgb, endArgb, offset); } public void roundedRectStrokeCorners(double x, double y, double w, double h, float radiusTL, float radiusTR, float radiusBR, float radiusBL, float softness, float thickness, int argb) { - shapeStroke(UiShape.roundedRect(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL), UiPaint.solid(argb), UiStroke.of(thickness)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_STROKE_CORNERS, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - normalizeCornerRadii(w, h, radiusTL, radiusTR, radiusBR, radiusBL, cornerRadiiTmp); - float stroke = Math.max(0.0f, thickness); - - int i1 = mesh.vec2(x, y).local2(x, y).color(r, g, b, a).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, stroke, 0f, 0f).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, stroke, 0f, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, stroke, 0f, 0f).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(r, g, b, a).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, stroke, 0f, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DRectsExtra.roundedRectStrokeCorners(this, x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, + softness, thickness, argb); } public void roundedRectStrokeCorners(double x, double y, double w, double h, @@ -1134,40 +723,8 @@ public final class Renderer2D { float radiusTL, float radiusTR, float radiusBR, float radiusBL, float softness, int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { - shape(UiShape.roundedRect(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL), UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_CORNERS, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int tlA = (cTopLeft >>> 24) & 0xFF; - int tlR = (cTopLeft >>> 16) & 0xFF; - int tlG = (cTopLeft >>> 8) & 0xFF; - int tlB = cTopLeft & 0xFF; - int trA = (cTopRight >>> 24) & 0xFF; - int trR = (cTopRight >>> 16) & 0xFF; - int trG = (cTopRight >>> 8) & 0xFF; - int trB = cTopRight & 0xFF; - int brA = (cBottomRight >>> 24) & 0xFF; - int brR = (cBottomRight >>> 16) & 0xFF; - int brG = (cBottomRight >>> 8) & 0xFF; - int brB = cBottomRight & 0xFF; - int blA = (cBottomLeft >>> 24) & 0xFF; - int blR = (cBottomLeft >>> 16) & 0xFF; - int blG = (cBottomLeft >>> 8) & 0xFF; - int blB = cBottomLeft & 0xFF; - normalizeCornerRadii(w, h, radiusTL, radiusTR, radiusBR, radiusBL, cornerRadiiTmp); - - int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, 0f, 0f, 0f).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, 0f, 0f, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, 0f, 0f, 0f).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, 0f, 0f, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DRects.roundedRectCornersQuad(this, x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, softness, + cTopLeft, cTopRight, cBottomRight, cBottomLeft); } public void roundedRectCornersQuad(double x, double y, double w, double h, @@ -1215,20 +772,8 @@ public final class Renderer2D { boolean fromRight, int startArgb, int endArgb, float angleDeg, float offsetPx) { - if (w <= 0.0 || h <= 0.0) return; - float p = Mth.clamp(progress, 0.0f, 1.0f); - if (p <= 0.0001f) return; - if (p >= 0.9999f) { - roundedRectGradient(x, y, w, h, radius, softness, startArgb, endArgb, angleDeg, offsetPx); - return; - } - - double fillW = Math.max(0.0, Math.min(w, w * p)); - double fillX = fromRight ? x + w - fillW : x; - double clipX = fromRight ? fillX : x + fillW; - int count = buildRoundedProgressRect(progressShapeTmp, rectShapeTmp, x, y, w, h, radius, clipX, fromRight); - if (count < 3) return; - polygonGradient(progressShapeTmp, count, fillX, y, fillW, h, startArgb, endArgb, angleDeg, offsetPx); + Renderer2DRectsExtra.roundedProgressRectGradient(this, x, y, w, h, radius, softness, progress, fromRight, + startArgb, endArgb, angleDeg, offsetPx); } public void roundedProgressRectGradient(double x, double y, double w, double h, @@ -1255,74 +800,8 @@ public final class Renderer2D { float flowX, float flowY, float intensity) { - if (w <= 0.0 || h <= 0.0) return; - float fill = Mth.clamp(fillRatio, 0.0f, 1.0f); - if (fill <= 0.0001f) return; - - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_FILL_SMOKE, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a0 = (firstArgb >>> 24) & 0xFF; - int r0 = (firstArgb >>> 16) & 0xFF; - int g0 = (firstArgb >>> 8) & 0xFF; - int b0 = firstArgb & 0xFF; - - float r1 = ((secondArgb >>> 16) & 0xFF) / 255.0f; - float g1 = ((secondArgb >>> 8) & 0xFF) / 255.0f; - float b1 = (secondArgb & 0xFF) / 255.0f; - float a1 = ((secondArgb >>> 24) & 0xFF) / 255.0f; - - float r2 = ((thirdArgb >>> 16) & 0xFF) / 255.0f; - float g2 = ((thirdArgb >>> 8) & 0xFF) / 255.0f; - float b2 = (thirdArgb & 0xFF) / 255.0f; - float a2 = ((thirdArgb >>> 24) & 0xFF) / 255.0f; - - float fromRightFlag = fromRight ? 1.0f : 0.0f; - float safeScale = Math.max(0.1f, smokeScale); - float safeMix = Mth.clamp(smokeMix, 0.0f, 1.0f); - float safeOctaves = Mth.clamp(octaves, 1, 8); - float safeIntensity = Math.max(0.0f, intensity); - - int i1 = mesh.vec2(x, y).local2(x, y).color(r0, g0, b0, a0) - .vec4((float) x, (float) y, (float) w, (float) h) - .vec4(radius, softness, fill, fromRightFlag) - .vec4(r1, g1, b1, a1) - .vec4(r2, g2, b2, a2) - .vec4(time, safeScale, safeMix, safeOctaves) - .vec4(flowX, flowY, safeIntensity, 0.0f) - .next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(r0, g0, b0, a0) - .vec4((float) x, (float) y, (float) w, (float) h) - .vec4(radius, softness, fill, fromRightFlag) - .vec4(r1, g1, b1, a1) - .vec4(r2, g2, b2, a2) - .vec4(time, safeScale, safeMix, safeOctaves) - .vec4(flowX, flowY, safeIntensity, 0.0f) - .next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(r0, g0, b0, a0) - .vec4((float) x, (float) y, (float) w, (float) h) - .vec4(radius, softness, fill, fromRightFlag) - .vec4(r1, g1, b1, a1) - .vec4(r2, g2, b2, a2) - .vec4(time, safeScale, safeMix, safeOctaves) - .vec4(flowX, flowY, safeIntensity, 0.0f) - .next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(r0, g0, b0, a0) - .vec4((float) x, (float) y, (float) w, (float) h) - .vec4(radius, softness, fill, fromRightFlag) - .vec4(r1, g1, b1, a1) - .vec4(r2, g2, b2, a2) - .vec4(time, safeScale, safeMix, safeOctaves) - .vec4(flowX, flowY, safeIntensity, 0.0f) - .next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DSmokeFill.roundedSmokeFill(this, x, y, w, h, radius, softness, fillRatio, fromRight, + firstArgb, secondArgb, thirdArgb, time, smokeScale, smokeMix, octaves, flowX, flowY, intensity); } public void roundedSmokeFill(double x, double y, double w, double h, @@ -1370,122 +849,24 @@ public final class Renderer2D { public void roundedRectGlow(double x, double y, double w, double h, float radius, float softness, float glow, int argb) { - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_GLOW, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - float clampedRadius = clampRoundedRadius(radius, w, h); - - double expand = glow; - double gx = x - expand; - double gy = y - expand; - double gw = w + expand * 2.0f; - double gh = h + expand * 2.0f; - - int i1 = mesh.vec2(gx, gy).local2(gx, gy).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glow, 0f).next(); - int i2 = mesh.vec2(gx, gy + gh).local2(gx, gy + gh).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glow, 0f).next(); - int i3 = mesh.vec2(gx + gw, gy + gh).local2(gx + gw, gy + gh).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glow, 0f).next(); - int i4 = mesh.vec2(gx + gw, gy).local2(gx + gw, gy).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glow, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DRectsGlow.roundedRectGlow(this, x, y, w, h, radius, softness, glow, argb); } public void roundedRectShadow(double x, double y, double w, double h, float radius, float softness, float spread, int argb) { - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_SHADOW, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - float clampedRadius = clampRoundedRadius(radius, w, h); - - double expandX = 2.0f; - double expandY = spread + 2.0f; - double gx = x - expandX; - double gw = w + expandX * 2.0f; - double gy = y; - double gh = h + expandY; - - int i1 = mesh.vec2(gx, gy).local2(gx, gy).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, spread, 0f).next(); - int i2 = mesh.vec2(gx, gy + gh).local2(gx, gy + gh).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, spread, 0f).next(); - int i3 = mesh.vec2(gx + gw, gy + gh).local2(gx + gw, gy + gh).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, spread, 0f).next(); - int i4 = mesh.vec2(gx + gw, gy).local2(gx + gw, gy).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, spread, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DRectsGlow.roundedRectShadow(this, x, y, w, h, radius, softness, spread, argb); } public void roundedRectSoftShadow(double x, double y, double w, double h, float radius, float blur, float innerAlpha, int argb) { - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_SOFT_SHADOW, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - - double expand = blur * 2.0; - double sx = x - expand; - double sy = y - expand; - double sw = w + expand * 2.0; - double sh = h + expand * 2.0; - - int i1 = mesh.vec2(sx, sy).local2(sx, sy).color(r, g, b, a).vec4(x, y, w, h).vec4(radius, blur, innerAlpha, 0f).next(); - int i2 = mesh.vec2(sx, sy + sh).local2(sx, sy + sh).color(r, g, b, a).vec4(x, y, w, h).vec4(radius, blur, innerAlpha, 0f).next(); - int i3 = mesh.vec2(sx + sw, sy + sh).local2(sx + sw, sy + sh).color(r, g, b, a).vec4(x, y, w, h).vec4(radius, blur, innerAlpha, 0f).next(); - int i4 = mesh.vec2(sx + sw, sy).local2(sx + sw, sy).color(r, g, b, a).vec4(x, y, w, h).vec4(radius, blur, innerAlpha, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DRectsGlow.roundedRectSoftShadow(this, x, y, w, h, radius, blur, innerAlpha, argb); } public void radialGlowMasked(double x, double y, double w, double h, float radius, float softness, float glowRadius, float cx, float cy, int argb) { - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.RADIAL_GLOW, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - float clampedRadius = clampRoundedRadius(radius, w, h); - - int i1 = mesh.vec2(x, y).local2(x, y).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glowRadius, 0.0f).vec4(cx, cy, 0f, 0f).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glowRadius, 0.0f).vec4(cx, cy, 0f, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glowRadius, 0.0f).vec4(cx, cy, 0f, 0f).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glowRadius, 0.0f).vec4(cx, cy, 0f, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DRectsGlow.radialGlowMasked(this, x, y, w, h, radius, softness, glowRadius, cx, cy, argb); } public void roundedRectGradientQuad(double x, double y, double w, double h, @@ -1504,80 +885,15 @@ public final class Renderer2D { double maskX, double maskY, double maskW, double maskH, float radius, float softness, int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { - shape(UiShape.roundedRect(maskX, maskY, maskW, maskH, radius), UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int tlA = (cTopLeft >>> 24) & 0xFF; - int tlR = (cTopLeft >>> 16) & 0xFF; - int tlG = (cTopLeft >>> 8) & 0xFF; - int tlB = cTopLeft & 0xFF; - int trA = (cTopRight >>> 24) & 0xFF; - int trR = (cTopRight >>> 16) & 0xFF; - int trG = (cTopRight >>> 8) & 0xFF; - int trB = cTopRight & 0xFF; - int brA = (cBottomRight >>> 24) & 0xFF; - int brR = (cBottomRight >>> 16) & 0xFF; - int brG = (cBottomRight >>> 8) & 0xFF; - int brB = cBottomRight & 0xFF; - int blA = (cBottomLeft >>> 24) & 0xFF; - int blR = (cBottomLeft >>> 16) & 0xFF; - int blG = (cBottomLeft >>> 8) & 0xFF; - int blB = cBottomLeft & 0xFF; - float clampedRadius = clampRoundedRadius(radius, maskW, maskH); - - int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(maskX, maskY, maskW, maskH).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(maskX, maskY, maskW, maskH).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(maskX, maskY, maskW, maskH).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(maskX, maskY, maskW, maskH).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DRects.roundedRectMaskedQuad(this, x, y, w, h, maskX, maskY, maskW, maskH, radius, softness, + cTopLeft, cTopRight, cBottomRight, cBottomLeft); } public void roundedRectStrokeGradientQuad(double x, double y, double w, double h, float radius, float softness, float thickness, int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { - shapeStroke(UiShape.roundedRect(x, y, w, h, radius), UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft), UiStroke.of(thickness)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_STROKE, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int tlA = (cTopLeft >>> 24) & 0xFF; - int tlR = (cTopLeft >>> 16) & 0xFF; - int tlG = (cTopLeft >>> 8) & 0xFF; - int tlB = cTopLeft & 0xFF; - int trA = (cTopRight >>> 24) & 0xFF; - int trR = (cTopRight >>> 16) & 0xFF; - int trG = (cTopRight >>> 8) & 0xFF; - int trB = cTopRight & 0xFF; - int brA = (cBottomRight >>> 24) & 0xFF; - int brR = (cBottomRight >>> 16) & 0xFF; - int brG = (cBottomRight >>> 8) & 0xFF; - int brB = cBottomRight & 0xFF; - int blA = (cBottomLeft >>> 24) & 0xFF; - int blR = (cBottomLeft >>> 16) & 0xFF; - int blG = (cBottomLeft >>> 8) & 0xFF; - int blB = cBottomLeft & 0xFF; - float clampedRadius = clampRoundedRadius(radius, w, h); - float stroke = Math.max(0.0f, thickness); - - int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DRectsExtra.roundedRectStrokeGradientQuad(this, x, y, w, h, radius, softness, thickness, + cTopLeft, cTopRight, cBottomRight, cBottomLeft); } public void roundedRectStrokeGradientQuad(double x, double y, double w, double h, @@ -1591,66 +907,16 @@ public final class Renderer2D { float radius, float softness, double texX1, double texY1, double texX2, double texY2, int argb, GpuTextureView samplerView, GpuSampler sampler) { - if (!textured) { - throw new IllegalStateException("Renderer2D is not configured for textures."); - } - if (samplerView == null || sampler == null) return; - - recordUi(new UiTextureDrawCommand(samplerView, sampler, UiShape.roundedRect(x, y, w, h, radius), UiPaint.solid(argb), - (float) texX1, (float) texY1, (float) texX2, (float) texY2, false)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_TEXTURED, samplerView, sampler); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - float clampedRadius = clampRoundedRadius(radius, w, h); - int i1 = mesh.vec2(x, y).raw2(texX1, texY1).local2(x, y).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - int i2 = mesh.vec2(x, y + h).raw2(texX1, texY2).local2(x, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).raw2(texX2, texY2).local2(x + w, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - int i4 = mesh.vec2(x + w, y).raw2(texX2, texY1).local2(x + w, y).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DTextures.roundedTexRect(this, x, y, w, h, radius, softness, texX1, texY1, texX2, texY2, + argb, samplerView, sampler); } public void roundedTexMaskRect(double x, double y, double w, double h, float radius, float softness, double texX1, double texY1, double texX2, double texY2, int argb, GpuTextureView samplerView, GpuSampler sampler) { - if (!textured) { - throw new IllegalStateException("Renderer2D is not configured for textures."); - } - if (samplerView == null || sampler == null) return; - - recordUi(new UiTextureDrawCommand(samplerView, sampler, UiShape.roundedRect(x, y, w, h, radius), UiPaint.solid(argb), - (float) texX1, (float) texY1, (float) texX2, (float) texY2, true)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_TEXTURED_MASK, samplerView, sampler); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - float clampedRadius = clampRoundedRadius(radius, w, h); - int i1 = mesh.vec2(x, y).raw2(texX1, texY1).local2(x, y).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - int i2 = mesh.vec2(x, y + h).raw2(texX1, texY2).local2(x, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).raw2(texX2, texY2).local2(x + w, y + h).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - int i4 = mesh.vec2(x + w, y).raw2(texX2, texY1).local2(x + w, y).color(r, g, b, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DTextures.roundedTexMaskRect(this, x, y, w, h, radius, softness, texX1, texY1, texX2, texY2, + argb, samplerView, sampler); } public void roundedTexRect(double x, double y, double w, double h, @@ -1852,49 +1118,9 @@ public final class Renderer2D { double chamferBRX, double chamferBRY, double chamferBLX, double chamferBLY, int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { - shape(UiShape.chamferedRectAxes(x, y, w, h, chamferTLX, chamferTLY, chamferTRX, chamferTRY, chamferBRX, chamferBRY, chamferBLX, chamferBLY), - UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.CHAMFERED, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int tlA = (cTopLeft >>> 24) & 0xFF; - int tlR = (cTopLeft >>> 16) & 0xFF; - int tlG = (cTopLeft >>> 8) & 0xFF; - int tlB = cTopLeft & 0xFF; - int trA = (cTopRight >>> 24) & 0xFF; - int trR = (cTopRight >>> 16) & 0xFF; - int trG = (cTopRight >>> 8) & 0xFF; - int trB = cTopRight & 0xFF; - int brA = (cBottomRight >>> 24) & 0xFF; - int brR = (cBottomRight >>> 16) & 0xFF; - int brG = (cBottomRight >>> 8) & 0xFF; - int brB = cBottomRight & 0xFF; - int blA = (cBottomLeft >>> 24) & 0xFF; - int blR = (cBottomLeft >>> 16) & 0xFF; - int blG = (cBottomLeft >>> 8) & 0xFF; - int blB = cBottomLeft & 0xFF; - - float tlX = clampChamferAxis(chamferTLX, w); - float trX = clampChamferAxis(chamferTRX, w); - float brX = clampChamferAxis(chamferBRX, w); - float blX = clampChamferAxis(chamferBLX, w); - float tlY = clampChamferAxis(chamferTLY, h); - float trY = clampChamferAxis(chamferTRY, h); - float brY = clampChamferAxis(chamferBRY, h); - float blY = clampChamferAxis(chamferBLY, h); - - int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(x, y, w, h).vec4(tlX, trX, brX, blX).vec4(tlY, trY, brY, blY).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(x, y, w, h).vec4(tlX, trX, brX, blX).vec4(tlY, trY, brY, blY).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(x, y, w, h).vec4(tlX, trX, brX, blX).vec4(tlY, trY, brY, blY).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(x, y, w, h).vec4(tlX, trX, brX, blX).vec4(tlY, trY, brY, blY).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DChamfered.chamferedRectQuadAxes(this, x, y, w, h, + chamferTLX, chamferTLY, chamferTRX, chamferTRY, chamferBRX, chamferBRY, chamferBLX, chamferBLY, + cTopLeft, cTopRight, cBottomRight, cBottomLeft); } public void chamferedRectStrokeQuad(double x, double y, double w, double h, @@ -1909,47 +1135,9 @@ public final class Renderer2D { double chamferTL, double chamferTR, double chamferBR, double chamferBL, double thickness, int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { - shapeStroke(UiShape.chamferedRect(x, y, w, h, chamferTL, chamferTR, chamferBR, chamferBL), - UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft), UiStroke.of(thickness)); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.CHAMFERED_STROKE, null, null); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int tlA = (cTopLeft >>> 24) & 0xFF; - int tlR = (cTopLeft >>> 16) & 0xFF; - int tlG = (cTopLeft >>> 8) & 0xFF; - int tlB = cTopLeft & 0xFF; - int trA = (cTopRight >>> 24) & 0xFF; - int trR = (cTopRight >>> 16) & 0xFF; - int trG = (cTopRight >>> 8) & 0xFF; - int trB = cTopRight & 0xFF; - int brA = (cBottomRight >>> 24) & 0xFF; - int brR = (cBottomRight >>> 16) & 0xFF; - int brG = (cBottomRight >>> 8) & 0xFF; - int brB = cBottomRight & 0xFF; - int blA = (cBottomLeft >>> 24) & 0xFF; - int blR = (cBottomLeft >>> 16) & 0xFF; - int blG = (cBottomLeft >>> 8) & 0xFF; - int blB = cBottomLeft & 0xFF; - normalizeChamfers(w, h, - (float) chamferTL, - (float) chamferTR, - (float) chamferBR, - (float) chamferBL, - cornerRadiiTmp); - float stroke = (float) Math.max(0.0, thickness); - - int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(stroke, 0f, 0f, 0f).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(stroke, 0f, 0f, 0f).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(stroke, 0f, 0f, 0f).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(stroke, 0f, 0f, 0f).next(); - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); + Renderer2DChamfered.chamferedRectStrokeQuad(this, x, y, w, h, + chamferTL, chamferTR, chamferBR, chamferBL, thickness, + cTopLeft, cTopRight, cBottomRight, cBottomLeft); } public void cutCornerRect(double x, double y, double width, double height, double cut, int argb) { @@ -1975,50 +1163,33 @@ public final class Renderer2D { public void notchedRect(double x, double y, double width, double height, double notchWidth, double notchDepth, int argb) { int count = buildNotchedRect(rectShapeTmp, x, y, width, height, notchWidth, notchDepth); - polygon(rectShapeTmp, count, argb); + Renderer2DPolygons.polygon(this, rectShapeTmp, count, argb); } public void notchedRectGradient(double x, double y, double width, double height, double notchWidth, double notchDepth, int startArgb, int endArgb, float angleDeg, float offsetPx) { int count = buildNotchedRect(rectShapeTmp, x, y, width, height, notchWidth, notchDepth); - polygonGradient(rectShapeTmp, count, x, y, width, height, startArgb, endArgb, angleDeg, offsetPx); + Renderer2DPolygons.polygonGradient(this, rectShapeTmp, count, x, y, width, height, startArgb, endArgb, angleDeg, offsetPx); } public void notchedRectStroke(double x, double y, double width, double height, double notchWidth, double notchDepth, double thickness, int argb) { int count = buildNotchedRect(rectShapeTmp, x, y, width, height, notchWidth, notchDepth); - polygonStroke(rectShapeTmp, count, thickness, true, argb); + Renderer2DPolygons.polygonStroke(this, rectShapeTmp, count, thickness, true, argb); } public void notchedRectStrokeGradient(double x, double y, double width, double height, double notchWidth, double notchDepth, double thickness, int startArgb, int endArgb, float angleDeg, float offsetPx) { int count = buildNotchedRect(rectShapeTmp, x, y, width, height, notchWidth, notchDepth); - polylineLinearGradient(rectShapeTmp, count, thickness, true, + Renderer2DPolygons.polylineLinearGradient(this, rectShapeTmp, count, thickness, true, x, y, width, height, startArgb, endArgb, angleDeg, offsetPx, false); } public void beveledRect(double x, double y, double width, double height, double bevel, int fillArgb, int highlightArgb, int shadowArgb) { - chamferedRect(x, y, width, height, bevel, fillArgb); - double t = Math.max(1.0, Math.min(Math.min(Math.abs(width), Math.abs(height)) * 0.25, bevel)); - connectorTmp[0] = x + bevel; - connectorTmp[1] = y; - connectorTmp[2] = x + width - bevel; - connectorTmp[3] = y; - connectorTmp[4] = x + width; - connectorTmp[5] = y + bevel; - polyline(connectorTmp, 3, t, false, highlightArgb, false); - connectorTmp[0] = x + width; - connectorTmp[1] = y + height - bevel; - connectorTmp[2] = x + width - bevel; - connectorTmp[3] = y + height; - connectorTmp[4] = x + bevel; - connectorTmp[5] = y + height; - connectorTmp[6] = x; - connectorTmp[7] = y + height - bevel; - polyline(connectorTmp, 4, t, false, shadowArgb, false); + Renderer2DChamfered.beveledRect(this, x, y, width, height, bevel, fillArgb, highlightArgb, shadowArgb); } public void beveledRectStroke(double x, double y, double width, double height, @@ -2029,24 +1200,8 @@ public final class Renderer2D { public void beveledRectGradient(double x, double y, double width, double height, double bevel, int startArgb, int endArgb, int highlightArgb, int shadowArgb, float angleDeg, float offsetPx) { - chamferedRectGradient(x, y, width, height, bevel, startArgb, endArgb, angleDeg, offsetPx); - double t = Math.max(1.0, Math.min(Math.min(Math.abs(width), Math.abs(height)) * 0.25, bevel)); - connectorTmp[0] = x + bevel; - connectorTmp[1] = y; - connectorTmp[2] = x + width - bevel; - connectorTmp[3] = y; - connectorTmp[4] = x + width; - connectorTmp[5] = y + bevel; - polyline(connectorTmp, 3, t, false, highlightArgb, false); - connectorTmp[0] = x + width; - connectorTmp[1] = y + height - bevel; - connectorTmp[2] = x + width - bevel; - connectorTmp[3] = y + height; - connectorTmp[4] = x + bevel; - connectorTmp[5] = y + height; - connectorTmp[6] = x; - connectorTmp[7] = y + height - bevel; - polyline(connectorTmp, 4, t, false, shadowArgb, false); + Renderer2DChamfered.beveledRectGradient(this, x, y, width, height, bevel, startArgb, endArgb, + highlightArgb, shadowArgb, angleDeg, offsetPx); } public void beveledRectStrokeGradient(double x, double y, double width, double height, @@ -2056,20 +1211,12 @@ public final class Renderer2D { } public void connector(double x1, double y1, double x2, double y2, double thickness, int argb) { - connectorTmp[0] = x1; - connectorTmp[1] = y1; - connectorTmp[2] = x2; - connectorTmp[3] = y2; - polyline(connectorTmp, 2, thickness, false, argb, true); + Renderer2DConnectors.connector(this, x1, y1, x2, y2, thickness, argb); } public void connectorGradient(double x1, double y1, double x2, double y2, double thickness, int startArgb, int endArgb) { - connectorTmp[0] = x1; - connectorTmp[1] = y1; - connectorTmp[2] = x2; - connectorTmp[3] = y2; - polylineGradient(connectorTmp, 2, thickness, false, startArgb, endArgb, true); + Renderer2DConnectors.connectorGradient(this, x1, y1, x2, y2, thickness, startArgb, endArgb); } public void wire(double x1, double y1, double x2, double y2, double thickness, int argb) { @@ -2101,17 +1248,13 @@ public final class Renderer2D { public void roundedRectConnector(double x1, double y1, double w1, double h1, double radius1, double x2, double y2, double w2, double h2, double radius2, double thickness, int argb) { - roundedRectAnchor(connectorAnchorTmp, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); - roundedRectAnchor(connectorAnchorTmp, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); - connector(connectorAnchorTmp[0], connectorAnchorTmp[1], connectorAnchorTmp[2], connectorAnchorTmp[3], thickness, argb); + Renderer2DConnectors.roundedRectConnector(this, x1, y1, w1, h1, radius1, x2, y2, w2, h2, radius2, thickness, argb); } public void roundedRectConnectorGradient(double x1, double y1, double w1, double h1, double radius1, double x2, double y2, double w2, double h2, double radius2, double thickness, int startArgb, int endArgb) { - roundedRectAnchor(connectorAnchorTmp, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); - roundedRectAnchor(connectorAnchorTmp, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); - connectorGradient(connectorAnchorTmp[0], connectorAnchorTmp[1], connectorAnchorTmp[2], connectorAnchorTmp[3], + Renderer2DConnectors.roundedRectConnectorGradient(this, x1, y1, w1, h1, radius1, x2, y2, w2, h2, radius2, thickness, startArgb, endArgb); } @@ -2121,17 +1264,13 @@ public final class Renderer2D { public void roundedRectNodeGraphEdge(double x1, double y1, double w1, double h1, double radius1, double x2, double y2, double w2, double h2, double radius2, double thickness, int argb) { - roundedRectAnchor(connectorAnchorTmp, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); - roundedRectAnchor(connectorAnchorTmp, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); - nodeGraphEdge(connectorAnchorTmp[0], connectorAnchorTmp[1], connectorAnchorTmp[2], connectorAnchorTmp[3], thickness, argb); + Renderer2DConnectors.roundedRectNodeGraphEdge(this, x1, y1, w1, h1, radius1, x2, y2, w2, h2, radius2, thickness, argb); } public void roundedRectNodeGraphEdgeGradient(double x1, double y1, double w1, double h1, double radius1, double x2, double y2, double w2, double h2, double radius2, double thickness, int startArgb, int endArgb) { - roundedRectAnchor(connectorAnchorTmp, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); - roundedRectAnchor(connectorAnchorTmp, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); - nodeGraphEdgeGradient(connectorAnchorTmp[0], connectorAnchorTmp[1], connectorAnchorTmp[2], connectorAnchorTmp[3], + Renderer2DConnectors.roundedRectNodeGraphEdgeGradient(this, x1, y1, w1, h1, radius1, x2, y2, w2, h2, radius2, thickness, startArgb, endArgb); } @@ -2151,19 +1290,15 @@ public final class Renderer2D { public void roundedRectOrthogonalConnector(double x1, double y1, double w1, double h1, double radius1, double x2, double y2, double w2, double h2, double radius2, double midX, double thickness, int argb) { - roundedRectAnchor(connectorAnchorTmp, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); - roundedRectAnchor(connectorAnchorTmp, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); - orthogonalConnector(connectorAnchorTmp[0], connectorAnchorTmp[1], connectorAnchorTmp[2], connectorAnchorTmp[3], + Renderer2DConnectors.roundedRectOrthogonalConnector(this, x1, y1, w1, h1, radius1, x2, y2, w2, h2, radius2, midX, thickness, argb); } public void roundedRectOrthogonalConnectorGradient(double x1, double y1, double w1, double h1, double radius1, double x2, double y2, double w2, double h2, double radius2, double midX, double thickness, int startArgb, int endArgb) { - roundedRectAnchor(connectorAnchorTmp, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); - roundedRectAnchor(connectorAnchorTmp, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); - orthogonalConnectorGradient(connectorAnchorTmp[0], connectorAnchorTmp[1], connectorAnchorTmp[2], connectorAnchorTmp[3], - midX, thickness, startArgb, endArgb); + Renderer2DConnectors.roundedRectOrthogonalConnectorGradient(this, x1, y1, w1, h1, radius1, + x2, y2, w2, h2, radius2, midX, thickness, startArgb, endArgb); } public void orthogonalConnector(double x1, double y1, double x2, double y2, @@ -2173,28 +1308,12 @@ public final class Renderer2D { public void orthogonalConnector(double x1, double y1, double x2, double y2, double midX, double thickness, int argb) { - connectorTmp[0] = x1; - connectorTmp[1] = y1; - connectorTmp[2] = midX; - connectorTmp[3] = y1; - connectorTmp[4] = midX; - connectorTmp[5] = y2; - connectorTmp[6] = x2; - connectorTmp[7] = y2; - polyline(connectorTmp, 4, thickness, false, argb, true); + Renderer2DConnectors.orthogonalConnector(this, x1, y1, x2, y2, midX, thickness, argb); } public void orthogonalConnectorGradient(double x1, double y1, double x2, double y2, double midX, double thickness, int startArgb, int endArgb) { - connectorTmp[0] = x1; - connectorTmp[1] = y1; - connectorTmp[2] = midX; - connectorTmp[3] = y1; - connectorTmp[4] = midX; - connectorTmp[5] = y2; - connectorTmp[6] = x2; - connectorTmp[7] = y2; - polylineGradient(connectorTmp, 4, thickness, false, startArgb, endArgb, true); + Renderer2DConnectors.orthogonalConnectorGradient(this, x1, y1, x2, y2, midX, thickness, startArgb, endArgb); } public void bezierConnector(double x1, double y1, @@ -2213,8 +1332,7 @@ public final class Renderer2D { int segments, double thickness, int argb) { - int count = buildBezier(connectorTmp, x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments); - polyline(connectorTmp, count, thickness, false, argb, false); + Renderer2DConnectors.bezierConnector(this, x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments, thickness, argb); } public void bezierConnectorGradient(double x1, double y1, @@ -2225,52 +1343,33 @@ public final class Renderer2D { double thickness, int startArgb, int endArgb) { - int count = buildBezier(connectorTmp, x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments); - polylineGradient(connectorTmp, count, thickness, false, startArgb, endArgb, false); + Renderer2DConnectors.bezierConnectorGradient(this, x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments, thickness, startArgb, endArgb); } public void nodeGraphEdge(double x1, double y1, double x2, double y2, double thickness, int argb) { - double dx = Math.abs(x2 - x1); - double c = Math.max(24.0, dx * 0.5); - bezierConnector(x1, y1, x1 + c, y1, x2 - c, y2, x2, y2, thickness, argb); + Renderer2DConnectors.nodeGraphEdge(this, x1, y1, x2, y2, thickness, argb); } public void nodeGraphEdgeGradient(double x1, double y1, double x2, double y2, double thickness, int startArgb, int endArgb) { - double dx = Math.abs(x2 - x1); - double c = Math.max(24.0, dx * 0.5); - bezierConnectorGradient(x1, y1, x1 + c, y1, x2 - c, y2, x2, y2, 20, thickness, startArgb, endArgb); + Renderer2DConnectors.nodeGraphEdgeGradient(this, x1, y1, x2, y2, thickness, startArgb, endArgb); } public void spline(double[] points, int pointCount, double thickness, boolean closed, int argb) { if (points == null || pointCount < 2) return; - polyline(points, pointCount, thickness, closed, argb, true); + Renderer2DPolygons.polyline(this, points, pointCount, thickness, closed, argb, true); } public void splineGradient(double[] points, int pointCount, double thickness, boolean closed, int startArgb, int endArgb) { if (points == null || pointCount < 2) return; - polylineGradient(points, pointCount, thickness, closed, startArgb, endArgb, true); + Renderer2DPolygons.polylineGradient(this, points, pointCount, thickness, closed, startArgb, endArgb, true); } public void texQuad(double x, double y, double width, double height, double texX1, double texY1, double texX2, double texY2, int argb) { - recordUi(new UiShapeCommand(UiShape.rect(x, y, width, height), UiPaint.solid(argb), UiStroke.NONE, true)); - if (texturedTriangles == null) return; - texturedTriangles.alpha = alpha; - texturedTriangles.ensureQuadCapacity(); - - int a = (argb >>> 24) & 0xFF; - int r = (argb >>> 16) & 0xFF; - int g = (argb >>> 8) & 0xFF; - int b = argb & 0xFF; - int i1 = texturedTriangles.vec2(x, y).raw2(texX1, texY1).color(r, g, b, a).next(); - int i2 = texturedTriangles.vec2(x, y + height).raw2(texX1, texY2).color(r, g, b, a).next(); - int i3 = texturedTriangles.vec2(x + width, y + height).raw2(texX2, texY2).color(r, g, b, a).next(); - int i4 = texturedTriangles.vec2(x + width, y).raw2(texX2, texY1).color(r, g, b, a).next(); - - texturedTriangles.quad(i1, i2, i3, i4); + Renderer2DTextures.texQuad(this, x, y, width, height, texX1, texY1, texX2, texY2, argb); } public void liquidGlassCircle(double cx, double cy, double radius, @@ -2646,368 +1745,49 @@ public final class Renderer2D { float fresnelMix, float distortPx, float squirclePower) { - if (w <= 0.0 || h <= 0.0) return; - - effect(UiEffectSpec.liquidGlass(UiShape.roundedRect(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL), - softness, softness, distortPx, tintArgb)); - Minecraft mc = Minecraft.getInstance(); - if (mc == null) return; - RenderTarget fb = mc.gameRenderer.mainRenderTarget(); - if (fb == null) return; - GpuTextureView src = fb.getColorTextureView(); - if (src == null) return; - GpuSampler sampler = PostProcessManager.getSampler(); - if (sampler == null) return; - - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreateBlur(UiBatchType.LIQUID_GLASS, src, sampler, - DEFAULT_LIQUID_GLASS_BLUR_QUALITY, LIQUID_GLASS_KAWASE_OFFSET_PX); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - - mesh.ensureQuadCapacity(); - - int a = (tintArgb >>> 24) & 0xFF; - int r = (tintArgb >>> 16) & 0xFF; - int g = (tintArgb >>> 8) & 0xFF; - int b = tintArgb & 0xFF; - - float clampedGlassAlpha = clamp01(glassAlpha); - float clampedBlurAlpha = clamp01(blurAlpha); - int finalA = (int) (a * clampedGlassAlpha); - - normalizeCornerRadii(w, h, radiusTL, radiusTR, radiusBR, radiusBL, cornerRadiiTmp); - - float thickness = Math.max(0.0f, softness); - float mix = clamp01(fresnelMix); - float fa = clamp01(fresnelAlpha); - float ba = clamp01(baseAlpha); - float packedDistort = packLiquidGlassPayload(distortPx, squirclePower, clampedBlurAlpha); - - int i1 = mesh.vec2(x, y).raw2(mix, packedDistort).local2(x, y).color(r, g, b, finalA) - .vec4(x, y, w, h) - .vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]) - .vec4(thickness, fresnelPower, fa, ba) - .next(); - int i2 = mesh.vec2(x, y + h).raw2(mix, packedDistort).local2(x, y + h).color(r, g, b, finalA) - .vec4(x, y, w, h) - .vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]) - .vec4(thickness, fresnelPower, fa, ba) - .next(); - int i3 = mesh.vec2(x + w, y + h).raw2(mix, packedDistort).local2(x + w, y + h).color(r, g, b, finalA) - .vec4(x, y, w, h) - .vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]) - .vec4(thickness, fresnelPower, fa, ba) - .next(); - int i4 = mesh.vec2(x + w, y).raw2(mix, packedDistort).local2(x + w, y).color(r, g, b, finalA) - .vec4(x, y, w, h) - .vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]) - .vec4(thickness, fresnelPower, fa, ba) - .next(); - - mesh.quad(i1, i2, i3, i4); - - endAutoBatch(auto); - } - - - private static BlurQuality legacyBlurQuality(float legacyQuality) { - if (legacyQuality >= 32.0f) return BlurQuality.ULTRA; - if (legacyQuality >= 12.0f) return BlurQuality.HIGH; - if (legacyQuality >= 5.0f) return BlurQuality.MEDIUM; - return BlurQuality.LOW; - } - - private static float legacyKawaseOffset(float legacyQuality) { - if (!Float.isFinite(legacyQuality)) return DEFAULT_KAWASE_OFFSET_PX; - return Mth.clamp(legacyQuality / 18.0f, 0.85f, 3.25f); + Renderer2DLiquidGlass.liquidGlassRectCorners(this, x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, softness, + tintArgb, glassAlpha, blurAlpha, fresnelPower, fresnelAlpha, baseAlpha, fresnelMix, distortPx, squirclePower); } public void blurRect(double x, double y, double w, double h, float radius, float quality, float brightness, float alpha, int ignoredTintRgb) { - blurRect(x, y, w, h, radius, quality, brightness, alpha, ignoredTintRgb, UiBatchType.BLUR); + Renderer2DBlur.blurRect(this, x, y, w, h, radius, quality, brightness, alpha, ignoredTintRgb, UiBatchType.BLUR); } public void glassBlurRect(double x, double y, double w, double h, float radius, float quality, float brightness, float alpha, int ignoredTintRgb) { - if (w <= 0.0 || h <= 0.0) return; - if (alpha <= 0.001f) return; - - effect(UiEffectSpec.blur(UiShape.roundedRect(x, y, w, h, radius), radius, ignoredTintRgb)); - BlurSource source = getBlurSource(); - if (source == null) return; - - boolean auto = beginAutoBatch(); - try { - DrawBatch batch = UI_BATCHER.getOrCreateBlur(UiBatchType.GLASS_BLUR, source.view, source.sampler, - BlurQuality.HIGH, legacyKawaseOffset(quality)); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = 1.0; - - float finalAlpha = clamp01((float) (alpha * this.alpha)); - if (finalAlpha <= 0.001f) return; - - int a = Math.max(0, Math.min(255, Math.round(finalAlpha * 255.0f))); - float smoothness = 2.0f; - float r = Math.max(0.0f, radius); - - mesh.ensureQuadCapacity(); - int i1 = mesh.vec2(x, y).local2(x, y).color(255, 255, 255, a) - .vec4(x, y, w, h) - .vec4(r, r, r, r) - .vec4(quality, brightness, smoothness, 0.0f) - .next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(255, 255, 255, a) - .vec4(x, y, w, h) - .vec4(r, r, r, r) - .vec4(quality, brightness, smoothness, 0.0f) - .next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(255, 255, 255, a) - .vec4(x, y, w, h) - .vec4(r, r, r, r) - .vec4(quality, brightness, smoothness, 0.0f) - .next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(255, 255, 255, a) - .vec4(x, y, w, h) - .vec4(r, r, r, r) - .vec4(quality, brightness, smoothness, 0.0f) - .next(); - mesh.quad(i1, i2, i3, i4); - } finally { - endAutoBatch(auto); - } - } - - private void blurRect(double x, double y, double w, double h, - float radius, float quality, float brightness, float alpha, int ignoredTintRgb, - UiBatchType batchType) { - if (w <= 0.0 || h <= 0.0) return; - if (alpha <= 0.001f) return; - - effect(UiEffectSpec.blur(UiShape.roundedRect(x, y, w, h, radius), radius, ignoredTintRgb)); - BlurSource source = getBlurSource(); - if (source == null) return; - - boolean auto = beginAutoBatch(); - try { - DrawBatch batch = UI_BATCHER.getOrCreateBlur(batchType, source.view, source.sampler, - legacyBlurQuality(quality), legacyKawaseOffset(quality)); - if (batch == null) return; - MeshBuilder mesh = batch.mesh; - mesh.alpha = 1.0; - - float finalAlpha = (float) (alpha * this.alpha); - mesh.ensureQuadCapacity(); - int i1 = mesh.vec2(x, y).local2(x, y).color(255, 255, 255, 255).vec4(x, y, w, h).vec4(radius, quality, brightness, finalAlpha).next(); - int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(255, 255, 255, 255).vec4(x, y, w, h).vec4(radius, quality, brightness, finalAlpha).next(); - int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(255, 255, 255, 255).vec4(x, y, w, h).vec4(radius, quality, brightness, finalAlpha).next(); - int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(255, 255, 255, 255).vec4(x, y, w, h).vec4(radius, quality, brightness, finalAlpha).next(); - mesh.quad(i1, i2, i3, i4); - } finally { - endAutoBatch(auto); - } + Renderer2DBlur.glassBlurRect(this, x, y, w, h, radius, quality, brightness, alpha, ignoredTintRgb); } public void blurChamferedRect(double x, double y, double w, double h, double chamfer, float quality, float brightness, float alpha, int ignoredTintRgb) { - if (w <= 0.0 || h <= 0.0) return; - if (alpha <= 0.001f) return; - float cut = clampChamfer(chamfer, w, h); - if (cut <= 0.0f) { - blurRect(x, y, w, h, 0.0f, quality, brightness, alpha, ignoredTintRgb); - return; - } - blurRect(x, y, w, h, -cut, quality, brightness, alpha, ignoredTintRgb); + Renderer2DBlur.blurChamferedRect(this, x, y, w, h, chamfer, quality, brightness, alpha, ignoredTintRgb); } public void blurComposite(Consumer consumer) { - if (consumer == null) return; - - BlurSource source = getBlurSource(); - if (source == null) return; - - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreateBlur(UiBatchType.BLUR_COMPLEX, source.view, source.sampler, - DEFAULT_BLUR_QUALITY, DEFAULT_KAWASE_OFFSET_PX); - if (batch == null) return; - - MeshBuilder mesh = batch.mesh; - mesh.alpha = 1.0; - - try { - consumer.accept(new BlurComposite(mesh, (float) this.alpha)); - } finally { - endAutoBatch(auto); - } - } - - private BlurSource getBlurSource() { - Minecraft mc = Minecraft.getInstance(); - if (mc == null) return null; - RenderTarget fb = mc.gameRenderer.mainRenderTarget(); - if (fb == null) return null; - GpuTextureView src = fb.getColorTextureView(); - if (src == null) return null; - GpuSampler sampler = PostProcessManager.getSampler(); - if (sampler == null) return null; - return new BlurSource(src, sampler); - } - - private boolean beginAutoBatch() { - return UiRenderDispatcher.beginAutoBatch(); - } - - private void endAutoBatch(boolean auto) { - UiRenderDispatcher.endAutoBatch(auto); - } - - private void renderFlexibleBoxFallback(UiBoxShape box, UiPaint paint, UiStroke stroke, boolean fill) { - if (textured || box == null || paint == null) return; - int count = UiBoxPathBuilder.write(box, rectShapeTmp, rectShapeTmp.length / 2); - if (count < 3) return; - - if (fill) { - switch (paint.kind()) { - case LINEAR_GRADIENT -> - polygonGradient(rectShapeTmp, count, box.bounds().x(), box.bounds().y(), box.bounds().width(), box.bounds().height(), - paint.topLeft(), paint.topRight(), paint.angleDeg(), paint.offsetPx()); - default -> polygon(rectShapeTmp, count, paint.solidColor()); - } - } else if (stroke != null && stroke.enabled()) { - if (paint.kind() == UiPaintKind.LINEAR_GRADIENT) { - polylineLinearGradient(rectShapeTmp, count, stroke.thickness(), true, - box.bounds().x(), box.bounds().y(), box.bounds().width(), box.bounds().height(), - paint.topLeft(), paint.topRight(), paint.angleDeg(), paint.offsetPx(), - stroke.join() == UiPathJoin.ROUND || stroke.cap() == UiPathCap.ROUND); - } else { - polyline(rectShapeTmp, count, stroke.thickness(), true, paint.solidColor(), - stroke.join() == UiPathJoin.ROUND || stroke.cap() == UiPathCap.ROUND); - } - } + Renderer2DBlur.blurComposite(this, consumer); } public void polygon(double[] points, int pointCount, int argb) { - if (textured) { - throw new IllegalStateException("Polygon drawing is supported only on Renderer2D.COLOR."); - } - int safeCount = Math.min(pointCount, points != null ? points.length / 2 : 0); - safeCount = Math.min(safeCount, Math.min(polygonIndexTmp.length, polygonVertexTmp.length)); - if (points == null || safeCount < 3) return; - - path(UiShape.polyline(points, safeCount, true), UiPaint.solid(argb), UiStroke.NONE, true); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); - if (batch == null) { - endAutoBatch(auto); - return; - } - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - appendPolygon(mesh, points, safeCount, polygonIndexTmp, polygonVertexTmp, argb); - endAutoBatch(auto); + Renderer2DPolygons.polygon(this, points, pointCount, argb); } - private void polygonGradient(double[] points, int pointCount, - double x, double y, double width, double height, - int startArgb, int endArgb, float angleDeg, float offsetPx) { - if (textured) { - throw new IllegalStateException("Polygon drawing is supported only on Renderer2D.COLOR."); - } - if (points == null || pointCount < 3) return; + // ---- Package-private plumbing for helpers in the same package ------------ - path(UiShape.polyline(points, pointCount, true), UiPaint.linear(startArgb, endArgb, angleDeg, offsetPx), UiStroke.NONE, true); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); - if (batch == null) { - endAutoBatch(auto); - return; - } - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - appendPolygonGradient(mesh, points, pointCount, polygonIndexTmp, polygonVertexTmp, - x, y, width, height, startArgb, endArgb, angleDeg, offsetPx); - endAutoBatch(auto); + boolean beginAutoBatch() { + return UiRenderDispatcher.beginAutoBatch(); } - private void polygonStroke(double[] points, int pointCount, double thickness, boolean closed, int argb) { - polyline(points, pointCount, thickness, closed, argb, false); + void endAutoBatch(boolean auto) { + UiRenderDispatcher.endAutoBatch(auto); } - private void polyline(double[] points, int pointCount, double thickness, boolean closed, int argb) { - polyline(points, pointCount, thickness, closed, argb, false); + static void recordUi(UiCommand command) { + UiRenderDispatcher.record(command); } - private void polyline(double[] points, int pointCount, double thickness, boolean closed, int argb, boolean roundCapsAndJoins) { - if (textured) { - throw new IllegalStateException("Polyline drawing is supported only on Renderer2D.COLOR."); - } - if (points == null || pointCount < 2) return; - double t = Math.max(0.0, thickness); - if (t <= 0.0) return; - - path(UiShape.polyline(points, pointCount, closed), UiPaint.solid(argb), - roundCapsAndJoins ? UiStroke.of(t).withRoundCapsAndJoins() : UiStroke.of(t), false); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); - if (batch == null) { - endAutoBatch(auto); - return; - } - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - appendPolyline(mesh, points, pointCount, t, closed, argb, roundCapsAndJoins); - endAutoBatch(auto); - } - - private void polylineGradient(double[] points, int pointCount, double thickness, boolean closed, - int startArgb, int endArgb, boolean roundCapsAndJoins) { - if (textured) { - throw new IllegalStateException("Polyline drawing is supported only on Renderer2D.COLOR."); - } - if (points == null || pointCount < 2) return; - double t = Math.max(0.0, thickness); - if (t <= 0.0) return; - - path(UiShape.polyline(points, pointCount, closed), UiPaint.corners(startArgb, endArgb, endArgb, startArgb), - roundCapsAndJoins ? UiStroke.of(t).withRoundCapsAndJoins() : UiStroke.of(t), false); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); - if (batch == null) { - endAutoBatch(auto); - return; - } - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - appendPolylineGradient(mesh, points, pointCount, t, closed, startArgb, endArgb, roundCapsAndJoins); - endAutoBatch(auto); - } - - private void polylineLinearGradient(double[] points, int pointCount, double thickness, boolean closed, - double x, double y, double width, double height, - int startArgb, int endArgb, float angleDeg, float offsetPx, - boolean roundCapsAndJoins) { - if (textured) { - throw new IllegalStateException("Polyline drawing is supported only on Renderer2D.COLOR."); - } - if (points == null || pointCount < 2) return; - double t = Math.max(0.0, thickness); - if (t <= 0.0) return; - - path(UiShape.polyline(points, pointCount, closed), UiPaint.linear(startArgb, endArgb, angleDeg, offsetPx), - roundCapsAndJoins ? UiStroke.of(t).withRoundCapsAndJoins() : UiStroke.of(t), false); - boolean auto = beginAutoBatch(); - DrawBatch batch = UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); - if (batch == null) { - endAutoBatch(auto); - return; - } - MeshBuilder mesh = batch.mesh; - mesh.alpha = alpha; - appendPolylineLinearGradient(mesh, points, pointCount, t, closed, - x, y, width, height, startArgb, endArgb, angleDeg, offsetPx, roundCapsAndJoins); - endAutoBatch(auto); + static void beginUiLayer() { + UiRenderDispatcher.beginLayer(); } // ---- Engine integration and compatibility bridge -------------------------- @@ -3072,14 +1852,6 @@ public final class Renderer2D { return UiDeferredScheduler.snapshotViewport(); } - private static void beginUiLayer() { - UiRenderDispatcher.beginLayer(); - } - - private static void recordUi(UiCommand command) { - UiRenderDispatcher.record(command); - } - public static void flushUiLayer() { UiRenderDispatcher.flushLayer(); } @@ -3305,7 +2077,7 @@ public final class Renderer2D { private final MeshBuilder mesh; private final float globalAlpha; - private BlurComposite(MeshBuilder mesh, float globalAlpha) { + BlurComposite(MeshBuilder mesh, float globalAlpha) { this.mesh = mesh; this.globalAlpha = globalAlpha; } @@ -3360,7 +2132,7 @@ public final class Renderer2D { public static final class QuadBatch { private final MeshBuilder mesh; - private QuadBatch(MeshBuilder mesh) { + QuadBatch(MeshBuilder mesh) { this.mesh = mesh; } @@ -3376,4 +2148,4 @@ public final class Renderer2D { public static final class BatchStats extends UiBatchStats { } -} +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DBlur.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DBlur.java new file mode 100644 index 0000000..099fe25 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DBlur.java @@ -0,0 +1,157 @@ +/* + * 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.render.engine.renderer; + +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTextureView; +import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; +import dev.loki.lovisual.render.engine.renderer.ui.BlurSource; +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiEffectSpec; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiShape; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; +import net.minecraft.client.Minecraft; +import net.minecraft.util.Mth; + +import java.util.function.Consumer; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.clamp01; +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.clampChamfer; + +final class Renderer2DBlur { + private Renderer2DBlur() { + } + + static Renderer2D.BlurQuality legacyBlurQuality(float legacyQuality) { + if (legacyQuality >= 32.0f) return Renderer2D.BlurQuality.ULTRA; + if (legacyQuality >= 12.0f) return Renderer2D.BlurQuality.HIGH; + if (legacyQuality >= 5.0f) return Renderer2D.BlurQuality.MEDIUM; + return Renderer2D.BlurQuality.LOW; + } + + static float legacyKawaseOffset(float legacyQuality) { + if (!Float.isFinite(legacyQuality)) return Renderer2D.DEFAULT_KAWASE_OFFSET_PX; + return Mth.clamp(legacyQuality / 18.0f, 0.85f, 3.25f); + } + + static BlurSource getBlurSource(Renderer2D r) { + Minecraft mc = Minecraft.getInstance(); + if (mc == null) return null; + RenderTarget fb = mc.gameRenderer.mainRenderTarget(); + if (fb == null) return null; + GpuTextureView src = fb.getColorTextureView(); + if (src == null) return null; + GpuSampler sampler = PostProcessManager.getSampler(); + if (sampler == null) return null; + return new BlurSource(src, sampler); + } + + static void blurRect(Renderer2D r, double x, double y, double w, double h, + float radius, float quality, float brightness, float alpha, int ignoredTintRgb, + UiBatchType batchType) { + if (w <= 0.0 || h <= 0.0) return; + if (alpha <= 0.001f) return; + + r.effect(UiEffectSpec.blur(UiShape.roundedRect(x, y, w, h, radius), radius, ignoredTintRgb)); + BlurSource source = getBlurSource(r); + if (source == null) return; + + boolean auto = r.beginAutoBatch(); + try { + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreateBlur(batchType, source.view, source.sampler, + legacyBlurQuality(quality), legacyKawaseOffset(quality)); + if (batch == null) return; + MeshBuilder mesh = batch.mesh; + mesh.alpha = 1.0; + + float finalAlpha = (float) (alpha * r.alpha); + mesh.ensureQuadCapacity(); + int i1 = mesh.vec2(x, y).local2(x, y).color(255, 255, 255, 255).vec4(x, y, w, h).vec4(radius, quality, brightness, finalAlpha).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(255, 255, 255, 255).vec4(x, y, w, h).vec4(radius, quality, brightness, finalAlpha).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(255, 255, 255, 255).vec4(x, y, w, h).vec4(radius, quality, brightness, finalAlpha).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(255, 255, 255, 255).vec4(x, y, w, h).vec4(radius, quality, brightness, finalAlpha).next(); + mesh.quad(i1, i2, i3, i4); + } finally { + r.endAutoBatch(auto); + } + } + + static void glassBlurRect(Renderer2D r, double x, double y, double w, double h, + float radius, float quality, float brightness, float alpha, int ignoredTintRgb) { + if (w <= 0.0 || h <= 0.0) return; + if (alpha <= 0.001f) return; + + r.effect(UiEffectSpec.blur(UiShape.roundedRect(x, y, w, h, radius), radius, ignoredTintRgb)); + BlurSource source = getBlurSource(r); + if (source == null) return; + + boolean auto = r.beginAutoBatch(); + try { + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreateBlur(UiBatchType.GLASS_BLUR, source.view, source.sampler, + Renderer2D.BlurQuality.HIGH, legacyKawaseOffset(quality)); + if (batch == null) return; + MeshBuilder mesh = batch.mesh; + mesh.alpha = 1.0; + + float finalAlpha = clamp01((float) (alpha * r.alpha)); + if (finalAlpha <= 0.001f) return; + + int a = Math.max(0, Math.min(255, Math.round(finalAlpha * 255.0f))); + float smoothness = 2.0f; + float rad = Math.max(0.0f, radius); + + mesh.ensureQuadCapacity(); + int i1 = mesh.vec2(x, y).local2(x, y).color(255, 255, 255, a) + .vec4(x, y, w, h).vec4(rad, rad, rad, rad).vec4(quality, brightness, smoothness, 0.0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(255, 255, 255, a) + .vec4(x, y, w, h).vec4(rad, rad, rad, rad).vec4(quality, brightness, smoothness, 0.0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(255, 255, 255, a) + .vec4(x, y, w, h).vec4(rad, rad, rad, rad).vec4(quality, brightness, smoothness, 0.0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(255, 255, 255, a) + .vec4(x, y, w, h).vec4(rad, rad, rad, rad).vec4(quality, brightness, smoothness, 0.0f).next(); + mesh.quad(i1, i2, i3, i4); + } finally { + r.endAutoBatch(auto); + } + } + + static void blurChamferedRect(Renderer2D r, double x, double y, double w, double h, + double chamfer, float quality, float brightness, float alpha, int ignoredTintRgb) { + if (w <= 0.0 || h <= 0.0) return; + if (alpha <= 0.001f) return; + float cut = clampChamfer(chamfer, w, h); + if (cut <= 0.0f) { + r.blurRect(x, y, w, h, 0.0f, quality, brightness, alpha, ignoredTintRgb); + return; + } + r.blurRect(x, y, w, h, -cut, quality, brightness, alpha, ignoredTintRgb); + } + + static void blurComposite(Renderer2D r, Consumer consumer) { + if (consumer == null) return; + + BlurSource source = getBlurSource(r); + if (source == null) return; + + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreateBlur(UiBatchType.BLUR_COMPLEX, source.view, source.sampler, + Renderer2D.DEFAULT_BLUR_QUALITY, Renderer2D.DEFAULT_KAWASE_OFFSET_PX); + if (batch == null) return; + + MeshBuilder mesh = batch.mesh; + mesh.alpha = 1.0; + + try { + consumer.accept(new Renderer2D.BlurComposite(mesh, (float) r.alpha)); + } finally { + r.endAutoBatch(auto); + } + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DChamfered.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DChamfered.java new file mode 100644 index 0000000..d26f381 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DChamfered.java @@ -0,0 +1,175 @@ +/* + * 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.render.engine.renderer; + +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiPaint; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiShape; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiStroke; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.clampChamferAxis; +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.normalizeChamfers; + +final class Renderer2DChamfered { + private Renderer2DChamfered() { + } + + static void chamferedRectQuadAxes(Renderer2D r, double x, double y, double w, double h, + double chamferTLX, double chamferTLY, + double chamferTRX, double chamferTRY, + double chamferBRX, double chamferBRY, + double chamferBLX, double chamferBLY, + int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { + r.shape(UiShape.chamferedRectAxes(x, y, w, h, chamferTLX, chamferTLY, chamferTRX, chamferTRY, chamferBRX, chamferBRY, chamferBLX, chamferBLY), + UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.CHAMFERED, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int tlA = (cTopLeft >>> 24) & 0xFF; + int tlR = (cTopLeft >>> 16) & 0xFF; + int tlG = (cTopLeft >>> 8) & 0xFF; + int tlB = cTopLeft & 0xFF; + int trA = (cTopRight >>> 24) & 0xFF; + int trR = (cTopRight >>> 16) & 0xFF; + int trG = (cTopRight >>> 8) & 0xFF; + int trB = cTopRight & 0xFF; + int brA = (cBottomRight >>> 24) & 0xFF; + int brR = (cBottomRight >>> 16) & 0xFF; + int brG = (cBottomRight >>> 8) & 0xFF; + int brB = cBottomRight & 0xFF; + int blA = (cBottomLeft >>> 24) & 0xFF; + int blR = (cBottomLeft >>> 16) & 0xFF; + int blG = (cBottomLeft >>> 8) & 0xFF; + int blB = cBottomLeft & 0xFF; + + float tlX = clampChamferAxis(chamferTLX, w); + float trX = clampChamferAxis(chamferTRX, w); + float brX = clampChamferAxis(chamferBRX, w); + float blX = clampChamferAxis(chamferBLX, w); + float tlY = clampChamferAxis(chamferTLY, h); + float trY = clampChamferAxis(chamferTRY, h); + float brY = clampChamferAxis(chamferBRY, h); + float blY = clampChamferAxis(chamferBLY, h); + + int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(x, y, w, h).vec4(tlX, trX, brX, blX).vec4(tlY, trY, brY, blY).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(x, y, w, h).vec4(tlX, trX, brX, blX).vec4(tlY, trY, brY, blY).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(x, y, w, h).vec4(tlX, trX, brX, blX).vec4(tlY, trY, brY, blY).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(x, y, w, h).vec4(tlX, trX, brX, blX).vec4(tlY, trY, brY, blY).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void chamferedRectStrokeQuad(Renderer2D r, double x, double y, double w, double h, + double chamferTL, double chamferTR, double chamferBR, double chamferBL, + double thickness, + int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { + r.shapeStroke(UiShape.chamferedRect(x, y, w, h, chamferTL, chamferTR, chamferBR, chamferBL), + UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft), UiStroke.of(thickness)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.CHAMFERED_STROKE, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int tlA = (cTopLeft >>> 24) & 0xFF; + int tlR = (cTopLeft >>> 16) & 0xFF; + int tlG = (cTopLeft >>> 8) & 0xFF; + int tlB = cTopLeft & 0xFF; + int trA = (cTopRight >>> 24) & 0xFF; + int trR = (cTopRight >>> 16) & 0xFF; + int trG = (cTopRight >>> 8) & 0xFF; + int trB = cTopRight & 0xFF; + int brA = (cBottomRight >>> 24) & 0xFF; + int brR = (cBottomRight >>> 16) & 0xFF; + int brG = (cBottomRight >>> 8) & 0xFF; + int brB = cBottomRight & 0xFF; + int blA = (cBottomLeft >>> 24) & 0xFF; + int blR = (cBottomLeft >>> 16) & 0xFF; + int blG = (cBottomLeft >>> 8) & 0xFF; + int blB = cBottomLeft & 0xFF; + float[] cornerRadiiTmp = r.cornerRadiiTmp; + normalizeChamfers(w, h, + (float) chamferTL, + (float) chamferTR, + (float) chamferBR, + (float) chamferBL, + cornerRadiiTmp); + float stroke = (float) Math.max(0.0, thickness); + + int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(stroke, 0f, 0f, 0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(stroke, 0f, 0f, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(stroke, 0f, 0f, 0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(stroke, 0f, 0f, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void beveledRect(Renderer2D r, double x, double y, double width, double height, + double bevel, int fillArgb, int highlightArgb, int shadowArgb) { + r.chamferedRect(x, y, width, height, bevel, fillArgb); + double t = Math.max(1.0, Math.min(Math.min(Math.abs(width), Math.abs(height)) * 0.25, bevel)); + double[] connectorTmp = r.connectorTmp; + connectorTmp[0] = x + bevel; + connectorTmp[1] = y; + connectorTmp[2] = x + width - bevel; + connectorTmp[3] = y; + connectorTmp[4] = x + width; + connectorTmp[5] = y + bevel; + Renderer2DPolygons.polyline(r, connectorTmp, 3, t, false, highlightArgb, false); + connectorTmp[0] = x + width; + connectorTmp[1] = y + height - bevel; + connectorTmp[2] = x + width - bevel; + connectorTmp[3] = y + height; + connectorTmp[4] = x + bevel; + connectorTmp[5] = y + height; + connectorTmp[6] = x; + connectorTmp[7] = y + height - bevel; + Renderer2DPolygons.polyline(r, connectorTmp, 4, t, false, shadowArgb, false); + } + + static void beveledRectGradient(Renderer2D r, double x, double y, double width, double height, + double bevel, int startArgb, int endArgb, + int highlightArgb, int shadowArgb, float angleDeg, float offsetPx) { + r.chamferedRectGradient(x, y, width, height, bevel, startArgb, endArgb, angleDeg, offsetPx); + double t = Math.max(1.0, Math.min(Math.min(Math.abs(width), Math.abs(height)) * 0.25, bevel)); + double[] connectorTmp = r.connectorTmp; + connectorTmp[0] = x + bevel; + connectorTmp[1] = y; + connectorTmp[2] = x + width - bevel; + connectorTmp[3] = y; + connectorTmp[4] = x + width; + connectorTmp[5] = y + bevel; + Renderer2DPolygons.polyline(r, connectorTmp, 3, t, false, highlightArgb, false); + connectorTmp[0] = x + width; + connectorTmp[1] = y + height - bevel; + connectorTmp[2] = x + width - bevel; + connectorTmp[3] = y + height; + connectorTmp[4] = x + bevel; + connectorTmp[5] = y + height; + connectorTmp[6] = x; + connectorTmp[7] = y + height - bevel; + Renderer2DPolygons.polyline(r, connectorTmp, 4, t, false, shadowArgb, false); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DCircles.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DCircles.java new file mode 100644 index 0000000..2e4d979 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DCircles.java @@ -0,0 +1,152 @@ +/* + * 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.render.engine.renderer; + +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiPaint; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiShape; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiStroke; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; +import net.minecraft.util.Mth; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.normalizeDegrees; + +final class Renderer2DCircles { + private Renderer2DCircles() { + } + + static void circle(Renderer2D r, double cx, double cy, double radius, float softness, int argb) { + r.shape(UiShape.circle(cx, cy, radius), UiPaint.solid(argb)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.CIRCLE, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + + double outerRadius = radius + Math.max(0.0f, softness); + double x = cx - outerRadius; + double y = cy - outerRadius; + double w = outerRadius * 2.0; + double h = outerRadius * 2.0; + + int i1 = mesh.vec2(x, y).local2(x, y).color(red, green, blue, a).vec4(x, y, w, h).vec4((float) radius, softness, 0f, 0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4((float) radius, softness, 0f, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4((float) radius, softness, 0f, 0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(red, green, blue, a).vec4(x, y, w, h).vec4((float) radius, softness, 0f, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void circleStroke(Renderer2D r, double cx, double cy, double radius, double thickness, float softness, int argb) { + r.shapeStroke(UiShape.circle(cx, cy, radius), UiPaint.solid(argb), UiStroke.of(thickness)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.CIRCLE, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + + float stroke = (float) Math.max(0.0, thickness); + double outerRadius = radius + stroke * 0.5 + softness; + double x = cx - outerRadius; + double y = cy - outerRadius; + double w = outerRadius * 2.0; + double h = outerRadius * 2.0; + + int i1 = mesh.vec2(x, y).local2(x, y).color(red, green, blue, a).vec4(x, y, w, h).vec4((float) radius, softness, stroke, 0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4((float) radius, softness, stroke, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4((float) radius, softness, stroke, 0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(red, green, blue, a).vec4(x, y, w, h).vec4((float) radius, softness, stroke, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void arcStrokeQuad(Renderer2D r, double cx, double cy, double radius, double thickness, + float startAngleDeg, float endAngleDeg, float softness, boolean caps, + int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { + float start = normalizeDegrees(startAngleDeg); + float end = normalizeDegrees(endAngleDeg); + float sweep = end - start; + if (sweep <= 0.0f) { + sweep += 360.0f; + } + if (sweep <= 0.001f) { + return; + } + + r.shapeStroke(UiShape.arc(cx, cy, radius, start, end), UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft), UiStroke.of(thickness)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ARC, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + float stroke = (float) Math.max(0.0, thickness); + double outerRadius = radius + stroke * 0.5 + softness; + double x = cx - outerRadius; + double y = cy - outerRadius; + double w = outerRadius * 2.0; + double h = outerRadius * 2.0; + + int tlA = (cTopLeft >>> 24) & 0xFF; + int tlR = (cTopLeft >>> 16) & 0xFF; + int tlG = (cTopLeft >>> 8) & 0xFF; + int tlB = cTopLeft & 0xFF; + int trA = (cTopRight >>> 24) & 0xFF; + int trR = (cTopRight >>> 16) & 0xFF; + int trG = (cTopRight >>> 8) & 0xFF; + int trB = cTopRight & 0xFF; + int brA = (cBottomRight >>> 24) & 0xFF; + int brR = (cBottomRight >>> 16) & 0xFF; + int brG = (cBottomRight >>> 8) & 0xFF; + int brB = cBottomRight & 0xFF; + int blA = (cBottomLeft >>> 24) & 0xFF; + int blR = (cBottomLeft >>> 16) & 0xFF; + int blG = (cBottomLeft >>> 8) & 0xFF; + int blB = cBottomLeft & 0xFF; + + int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(x, y, w, h) + .vec4((float) radius, softness, stroke, start).vec4(end, caps ? 1f : 0f, 0f, 0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(x, y, w, h) + .vec4((float) radius, softness, stroke, start).vec4(end, caps ? 1f : 0f, 0f, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(x, y, w, h) + .vec4((float) radius, softness, stroke, start).vec4(end, caps ? 1f : 0f, 0f, 0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(x, y, w, h) + .vec4((float) radius, softness, stroke, start).vec4(end, caps ? 1f : 0f, 0f, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DConnectors.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DConnectors.java new file mode 100644 index 0000000..2278b13 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DConnectors.java @@ -0,0 +1,155 @@ +/* + * 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.render.engine.renderer; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.buildBezier; +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.roundedRectAnchor; + +final class Renderer2DConnectors { + private Renderer2DConnectors() { + } + + static void connector(Renderer2D r, double x1, double y1, double x2, double y2, double thickness, int argb) { + double[] c = r.connectorTmp; + c[0] = x1; + c[1] = y1; + c[2] = x2; + c[3] = y2; + Renderer2DPolygons.polyline(r, c, 2, thickness, false, argb, true); + } + + static void connectorGradient(Renderer2D r, double x1, double y1, double x2, double y2, + double thickness, int startArgb, int endArgb) { + double[] c = r.connectorTmp; + c[0] = x1; + c[1] = y1; + c[2] = x2; + c[3] = y2; + Renderer2DPolygons.polylineGradient(r, c, 2, thickness, false, startArgb, endArgb, true); + } + + static void orthogonalConnector(Renderer2D r, double x1, double y1, double x2, double y2, + double midX, double thickness, int argb) { + double[] c = r.connectorTmp; + c[0] = x1; + c[1] = y1; + c[2] = midX; + c[3] = y1; + c[4] = midX; + c[5] = y2; + c[6] = x2; + c[7] = y2; + Renderer2DPolygons.polyline(r, c, 4, thickness, false, argb, true); + } + + static void orthogonalConnectorGradient(Renderer2D r, double x1, double y1, double x2, double y2, + double midX, double thickness, int startArgb, int endArgb) { + double[] c = r.connectorTmp; + c[0] = x1; + c[1] = y1; + c[2] = midX; + c[3] = y1; + c[4] = midX; + c[5] = y2; + c[6] = x2; + c[7] = y2; + Renderer2DPolygons.polylineGradient(r, c, 4, thickness, false, startArgb, endArgb, true); + } + + static void bezierConnector(Renderer2D r, double x1, double y1, + double cx1, double cy1, + double cx2, double cy2, + double x2, double y2, + int segments, + double thickness, + int argb) { + double[] c = r.connectorTmp; + int count = buildBezier(c, x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments); + Renderer2DPolygons.polyline(r, c, count, thickness, false, argb, false); + } + + static void bezierConnectorGradient(Renderer2D r, double x1, double y1, + double cx1, double cy1, + double cx2, double cy2, + double x2, double y2, + int segments, + double thickness, + int startArgb, + int endArgb) { + double[] c = r.connectorTmp; + int count = buildBezier(c, x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments); + Renderer2DPolygons.polylineGradient(r, c, count, thickness, false, startArgb, endArgb, false); + } + + static void nodeGraphEdge(Renderer2D r, double x1, double y1, double x2, double y2, double thickness, int argb) { + double dx = Math.abs(x2 - x1); + double c = Math.max(24.0, dx * 0.5); + bezierConnector(r, x1, y1, x1 + c, y1, x2 - c, y2, x2, y2, 20, thickness, argb); + } + + static void nodeGraphEdgeGradient(Renderer2D r, double x1, double y1, double x2, double y2, + double thickness, int startArgb, int endArgb) { + double dx = Math.abs(x2 - x1); + double c = Math.max(24.0, dx * 0.5); + bezierConnectorGradient(r, x1, y1, x1 + c, y1, x2 - c, y2, x2, y2, 20, thickness, startArgb, endArgb); + } + + static void roundedRectConnector(Renderer2D r, double x1, double y1, double w1, double h1, double radius1, + double x2, double y2, double w2, double h2, double radius2, + double thickness, int argb) { + double[] a = r.connectorAnchorTmp; + roundedRectAnchor(a, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); + roundedRectAnchor(a, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); + connector(r, a[0], a[1], a[2], a[3], thickness, argb); + } + + static void roundedRectConnectorGradient(Renderer2D r, double x1, double y1, double w1, double h1, double radius1, + double x2, double y2, double w2, double h2, double radius2, + double thickness, int startArgb, int endArgb) { + double[] a = r.connectorAnchorTmp; + roundedRectAnchor(a, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); + roundedRectAnchor(a, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); + connectorGradient(r, a[0], a[1], a[2], a[3], thickness, startArgb, endArgb); + } + + static void roundedRectNodeGraphEdge(Renderer2D r, double x1, double y1, double w1, double h1, double radius1, + double x2, double y2, double w2, double h2, double radius2, + double thickness, int argb) { + double[] a = r.connectorAnchorTmp; + roundedRectAnchor(a, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); + roundedRectAnchor(a, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); + nodeGraphEdge(r, a[0], a[1], a[2], a[3], thickness, argb); + } + + static void roundedRectNodeGraphEdgeGradient(Renderer2D r, double x1, double y1, double w1, double h1, double radius1, + double x2, double y2, double w2, double h2, double radius2, + double thickness, int startArgb, int endArgb) { + double[] a = r.connectorAnchorTmp; + roundedRectAnchor(a, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); + roundedRectAnchor(a, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); + nodeGraphEdgeGradient(r, a[0], a[1], a[2], a[3], thickness, startArgb, endArgb); + } + + static void roundedRectOrthogonalConnector(Renderer2D r, double x1, double y1, double w1, double h1, double radius1, + double x2, double y2, double w2, double h2, double radius2, + double midX, double thickness, int argb) { + double[] a = r.connectorAnchorTmp; + roundedRectAnchor(a, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); + roundedRectAnchor(a, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); + orthogonalConnector(r, a[0], a[1], a[2], a[3], midX, thickness, argb); + } + + static void roundedRectOrthogonalConnectorGradient(Renderer2D r, double x1, double y1, double w1, double h1, double radius1, + double x2, double y2, double w2, double h2, double radius2, + double midX, double thickness, int startArgb, int endArgb) { + double[] a = r.connectorAnchorTmp; + roundedRectAnchor(a, 0, x1, y1, w1, h1, radius1, x2 + w2 * 0.5, y2 + h2 * 0.5); + roundedRectAnchor(a, 2, x2, y2, w2, h2, radius2, x1 + w1 * 0.5, y1 + h1 * 0.5); + orthogonalConnectorGradient(r, a[0], a[1], a[2], a[3], midX, thickness, startArgb, endArgb); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DItems.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DItems.java new file mode 100644 index 0000000..a8391a5 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DItems.java @@ -0,0 +1,55 @@ +/* + * 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.render.engine.renderer; + +import dev.loki.lovisual.render.engine.renderer.ui.UiItemSubmission; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +final class Renderer2DItems { + private Renderer2DItems() { + } + + static void submit(Renderer2D r, + @Nullable LocalPlayer player, + ItemStack stack, + double x, + double y, + float scaleX, + float scaleY, + float pivotX, + float pivotY, + boolean pivoted, + int seed, + boolean drawItem, + int overlayFlags, + @Nullable String stackCountText, + int durabilityThresholdPercent, + int durabilityTextColorThresholdPercent) { + UiItemSubmission.submit( + r.textured, + r.alpha, + player, + stack, + x, + y, + scaleX, + scaleY, + pivotX, + pivotY, + pivoted, + seed, + drawItem, + overlayFlags, + stackCountText, + durabilityThresholdPercent, + durabilityTextColorThresholdPercent + ); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DLines.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DLines.java new file mode 100644 index 0000000..f04d2f9 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DLines.java @@ -0,0 +1,95 @@ +/* + * 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.render.engine.renderer; + +import dev.loki.lovisual.render.engine.color.RenderColor; +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiPaint; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiShape; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiStroke; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; + +final class Renderer2DLines { + private Renderer2DLines() { + } + + static void line(Renderer2D r, double x1, double y1, double x2, double y2, int argb) { + double[] p = {x1, y1, x2, y2}; + r.path(UiShape.polyline(p, 2, false), UiPaint.solid(argb), UiStroke.of(1.0), false); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.LINES, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureLineCapacity(); + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + int i1 = mesh.vec2(x1, y1).color(red, green, blue, a).next(); + int i2 = mesh.vec2(x2, y2).color(red, green, blue, a).next(); + mesh.line(i1, i2); + + r.endAutoBatch(auto); + } + + static void line(Renderer2D r, double x1, double y1, double x2, double y2, RenderColor color) { + double[] p = {x1, y1, x2, y2}; + r.path(UiShape.polyline(p, 2, false), UiPaint.solid(color.argb()), UiStroke.of(1.0), false); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.LINES, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureLineCapacity(); + int i1 = mesh.vec2(x1, y1).color(color.r, color.g, color.b, color.a).next(); + int i2 = mesh.vec2(x2, y2).color(color.r, color.g, color.b, color.a).next(); + mesh.line(i1, i2); + + r.endAutoBatch(auto); + } + + static void boxLines(Renderer2D r, double x, double y, double width, double height, int argb) { + r.shapeStroke(UiShape.rect(x, y, width, height), UiPaint.solid(argb), UiStroke.of(1.0)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.LINES, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureCapacity(4, 8); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + int i1 = mesh.vec2(x, y).color(red, green, blue, a).next(); + int i2 = mesh.vec2(x, y + height).color(red, green, blue, a).next(); + int i3 = mesh.vec2(x + width, y + height).color(red, green, blue, a).next(); + int i4 = mesh.vec2(x + width, y).color(red, green, blue, a).next(); + + mesh.line(i1, i2); + mesh.line(i2, i3); + mesh.line(i3, i4); + mesh.line(i4, i1); + + r.endAutoBatch(auto); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DLiquidGlass.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DLiquidGlass.java new file mode 100644 index 0000000..cf90ac9 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DLiquidGlass.java @@ -0,0 +1,109 @@ +/* + * 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.render.engine.renderer; + +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTextureView; +import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiEffectSpec; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiShape; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; +import net.minecraft.client.Minecraft; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.clamp01; +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.normalizeCornerRadii; +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.packLiquidGlassPayload; + +final class Renderer2DLiquidGlass { + private Renderer2DLiquidGlass() { + } + + static void liquidGlassRectCorners(Renderer2D r, double x, double y, double w, double h, + float radiusTL, float radiusTR, float radiusBR, float radiusBL, + float softness, + int tintArgb, + float glassAlpha, + float blurAlpha, + float fresnelPower, + float fresnelAlpha, + float baseAlpha, + float fresnelMix, + float distortPx, + float squirclePower) { + if (w <= 0.0 || h <= 0.0) return; + + r.effect(UiEffectSpec.liquidGlass(UiShape.roundedRect(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL), + softness, softness, distortPx, tintArgb)); + Minecraft mc = Minecraft.getInstance(); + if (mc == null) return; + RenderTarget fb = mc.gameRenderer.mainRenderTarget(); + if (fb == null) return; + GpuTextureView src = fb.getColorTextureView(); + if (src == null) return; + GpuSampler sampler = PostProcessManager.getSampler(); + if (sampler == null) return; + + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreateBlur(UiBatchType.LIQUID_GLASS, src, sampler, + Renderer2D.DEFAULT_LIQUID_GLASS_BLUR_QUALITY, Renderer2D.LIQUID_GLASS_KAWASE_OFFSET_PX); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (tintArgb >>> 24) & 0xFF; + int red = (tintArgb >>> 16) & 0xFF; + int green = (tintArgb >>> 8) & 0xFF; + int blue = tintArgb & 0xFF; + + float clampedGlassAlpha = clamp01(glassAlpha); + float clampedBlurAlpha = clamp01(blurAlpha); + int finalA = (int) (a * clampedGlassAlpha); + + float[] cornerRadiiTmp = r.cornerRadiiTmp; + normalizeCornerRadii(w, h, radiusTL, radiusTR, radiusBR, radiusBL, cornerRadiiTmp); + + float thickness = Math.max(0.0f, softness); + float mix = clamp01(fresnelMix); + float fa = clamp01(fresnelAlpha); + float ba = clamp01(baseAlpha); + float packedDistort = packLiquidGlassPayload(distortPx, squirclePower, clampedBlurAlpha); + + int i1 = mesh.vec2(x, y).raw2(mix, packedDistort).local2(x, y).color(red, green, blue, finalA) + .vec4(x, y, w, h) + .vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]) + .vec4(thickness, fresnelPower, fa, ba) + .next(); + int i2 = mesh.vec2(x, y + h).raw2(mix, packedDistort).local2(x, y + h).color(red, green, blue, finalA) + .vec4(x, y, w, h) + .vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]) + .vec4(thickness, fresnelPower, fa, ba) + .next(); + int i3 = mesh.vec2(x + w, y + h).raw2(mix, packedDistort).local2(x + w, y + h).color(red, green, blue, finalA) + .vec4(x, y, w, h) + .vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]) + .vec4(thickness, fresnelPower, fa, ba) + .next(); + int i4 = mesh.vec2(x + w, y).raw2(mix, packedDistort).local2(x + w, y).color(red, green, blue, finalA) + .vec4(x, y, w, h) + .vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]) + .vec4(thickness, fresnelPower, fa, ba) + .next(); + + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DOrbiz.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DOrbiz.java new file mode 100644 index 0000000..1c7ac44 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DOrbiz.java @@ -0,0 +1,117 @@ +/* + * 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.render.engine.renderer; + +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; +import net.minecraft.util.Mth; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.normalizeDegrees; + +final class Renderer2DOrbiz { + private Renderer2DOrbiz() { + } + + static void orbizRing(Renderer2D r, double cx, double cy, + double radius, double thickness, + float startAngleDeg, float sweepAngleDeg, + float softness, float glowRadius, float glowStrength, + int primaryArgb, int secondaryArgb, + int colorMode, float angularOffset, float angularCycles, + float trackAlpha, float bodyAlpha, float headBoost, + float trackGlow, boolean caps) { + if (r.textured) { + throw new IllegalStateException("Orbiz ring drawing is supported only on Renderer2D.COLOR."); + } + if (radius <= 0.0 || thickness <= 0.0) return; + if (((primaryArgb >>> 24) & 0xFF) <= 0 && ((secondaryArgb >>> 24) & 0xFF) <= 0) return; + + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ORBIZ_RING, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (primaryArgb >>> 24) & 0xFF; + int red = (primaryArgb >>> 16) & 0xFF; + int green = (primaryArgb >>> 8) & 0xFF; + int blue = primaryArgb & 0xFF; + + float sr = ((secondaryArgb >>> 16) & 0xFF) / 255.0f; + float sg = ((secondaryArgb >>> 8) & 0xFF) / 255.0f; + float sb = (secondaryArgb & 0xFF) / 255.0f; + float sa = ((secondaryArgb >>> 24) & 0xFF) / 255.0f; + + float stroke = (float) Math.max(0.0, thickness); + float ringRadius = (float) Math.max(0.0, radius); + float soft = Math.max(0.0f, softness); + float glow = Math.max(0.0f, glowRadius); + float expand = stroke * 0.5f + soft + glow + 1.0f; + double outerRadius = radius + expand; + double x = cx - outerRadius; + double y = cy - outerRadius; + double w = outerRadius * 2.0; + double h = outerRadius * 2.0; + double ringX = cx - radius; + double ringY = cy - radius; + double ringSize = radius * 2.0; + + float start = normalizeDegrees(startAngleDeg); + float sweep = Mth.clamp(sweepAngleDeg, 0.0f, 360.0f); + float offset = angularOffset - (float) Math.floor(angularOffset); + float cycles = Math.max(0.001f, angularCycles); + float mode = Math.max(0, colorMode); + float track = Mth.clamp(trackAlpha, 0.0f, 1.0f); + float body = Mth.clamp(bodyAlpha, 0.0f, 1.0f); + float glowPower = Math.max(0.0f, glowStrength); + float head = Math.max(0.0f, headBoost); + float trackGlowAmount = Mth.clamp(trackGlow, 0.0f, 1.0f); + + int i1 = mesh.vec2(x, y).local2(x, y).color(red, green, blue, a) + .vec4(ringX, ringY, ringSize, ringSize) + .vec4(ringRadius, soft, stroke, start) + .vec4(sweep, glow, glowPower, mode) + .vec4(sr, sg, sb, sa) + .vec4(offset, cycles, 0.0f, caps ? 1.0f : 0.0f) + .vec4(track, body, head, trackGlowAmount) + .next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(red, green, blue, a) + .vec4(ringX, ringY, ringSize, ringSize) + .vec4(ringRadius, soft, stroke, start) + .vec4(sweep, glow, glowPower, mode) + .vec4(sr, sg, sb, sa) + .vec4(offset, cycles, 0.0f, caps ? 1.0f : 0.0f) + .vec4(track, body, head, trackGlowAmount) + .next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(red, green, blue, a) + .vec4(ringX, ringY, ringSize, ringSize) + .vec4(ringRadius, soft, stroke, start) + .vec4(sweep, glow, glowPower, mode) + .vec4(sr, sg, sb, sa) + .vec4(offset, cycles, 0.0f, caps ? 1.0f : 0.0f) + .vec4(track, body, head, trackGlowAmount) + .next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(red, green, blue, a) + .vec4(ringX, ringY, ringSize, ringSize) + .vec4(ringRadius, soft, stroke, start) + .vec4(sweep, glow, glowPower, mode) + .vec4(sr, sg, sb, sa) + .vec4(offset, cycles, 0.0f, caps ? 1.0f : 0.0f) + .vec4(track, body, head, trackGlowAmount) + .next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DPolygons.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DPolygons.java new file mode 100644 index 0000000..16f39ce --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DPolygons.java @@ -0,0 +1,183 @@ +/* + * 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.render.engine.renderer; + +import dev.loki.lovisual.render.engine.command.UiShapeCommand; +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiBoxPathBuilder; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiBoxShape; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiPaint; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiPaintKind; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiPathCap; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiPathJoin; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiShape; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiStroke; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.*; + +final class Renderer2DPolygons { + private Renderer2DPolygons() { + } + + static void box(Renderer2D r, UiBoxShape box, UiPaint paint, UiStroke stroke, boolean fill) { + if (box == null || paint == null) return; + UiStroke safeStroke = stroke == null ? UiStroke.NONE : stroke; + Renderer2D.recordUi(new UiShapeCommand(UiShape.box(box), paint, safeStroke, fill)); + renderFlexibleBoxFallback(r, box, paint, safeStroke, fill); + } + + static void renderFlexibleBoxFallback(Renderer2D r, UiBoxShape box, UiPaint paint, UiStroke stroke, boolean fill) { + if (r.textured || box == null || paint == null) return; + double[] rectShapeTmp = r.rectShapeTmp; + int count = UiBoxPathBuilder.write(box, rectShapeTmp, rectShapeTmp.length / 2); + if (count < 3) return; + + if (fill) { + switch (paint.kind()) { + case LINEAR_GRADIENT -> + polygonGradient(r, rectShapeTmp, count, box.bounds().x(), box.bounds().y(), box.bounds().width(), box.bounds().height(), + paint.topLeft(), paint.topRight(), paint.angleDeg(), paint.offsetPx()); + default -> polygon(r, rectShapeTmp, count, paint.solidColor()); + } + } else if (stroke != null && stroke.enabled()) { + if (paint.kind() == UiPaintKind.LINEAR_GRADIENT) { + polylineLinearGradient(r, rectShapeTmp, count, stroke.thickness(), true, + box.bounds().x(), box.bounds().y(), box.bounds().width(), box.bounds().height(), + paint.topLeft(), paint.topRight(), paint.angleDeg(), paint.offsetPx(), + stroke.join() == UiPathJoin.ROUND || stroke.cap() == UiPathCap.ROUND); + } else { + polyline(r, rectShapeTmp, count, stroke.thickness(), true, paint.solidColor(), + stroke.join() == UiPathJoin.ROUND || stroke.cap() == UiPathCap.ROUND); + } + } + } + + static void polygon(Renderer2D r, double[] points, int pointCount, int argb) { + if (r.textured) { + throw new IllegalStateException("Polygon drawing is supported only on Renderer2D.COLOR."); + } + int safeCount = Math.min(pointCount, points != null ? points.length / 2 : 0); + safeCount = Math.min(safeCount, Math.min(r.polygonIndexTmp.length, r.polygonVertexTmp.length)); + if (points == null || safeCount < 3) return; + + r.path(UiShape.polyline(points, safeCount, true), UiPaint.solid(argb), UiStroke.NONE, true); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + appendPolygon(mesh, points, safeCount, r.polygonIndexTmp, r.polygonVertexTmp, argb); + r.endAutoBatch(auto); + } + + static void polygonGradient(Renderer2D r, double[] points, int pointCount, + double x, double y, double width, double height, + int startArgb, int endArgb, float angleDeg, float offsetPx) { + if (r.textured) { + throw new IllegalStateException("Polygon drawing is supported only on Renderer2D.COLOR."); + } + if (points == null || pointCount < 3) return; + + r.path(UiShape.polyline(points, pointCount, true), UiPaint.linear(startArgb, endArgb, angleDeg, offsetPx), UiStroke.NONE, true); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + appendPolygonGradient(mesh, points, pointCount, r.polygonIndexTmp, r.polygonVertexTmp, + x, y, width, height, startArgb, endArgb, angleDeg, offsetPx); + r.endAutoBatch(auto); + } + + static void polygonStroke(Renderer2D r, double[] points, int pointCount, double thickness, boolean closed, int argb) { + polyline(r, points, pointCount, thickness, closed, argb, false); + } + + static void polyline(Renderer2D r, double[] points, int pointCount, double thickness, boolean closed, int argb) { + polyline(r, points, pointCount, thickness, closed, argb, false); + } + + static void polyline(Renderer2D r, double[] points, int pointCount, double thickness, boolean closed, int argb, boolean roundCapsAndJoins) { + if (r.textured) { + throw new IllegalStateException("Polyline drawing is supported only on Renderer2D.COLOR."); + } + if (points == null || pointCount < 2) return; + double t = Math.max(0.0, thickness); + if (t <= 0.0) return; + + r.path(UiShape.polyline(points, pointCount, closed), UiPaint.solid(argb), + roundCapsAndJoins ? UiStroke.of(t).withRoundCapsAndJoins() : UiStroke.of(t), false); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + appendPolyline(mesh, points, pointCount, t, closed, argb, roundCapsAndJoins); + r.endAutoBatch(auto); + } + + static void polylineGradient(Renderer2D r, double[] points, int pointCount, double thickness, boolean closed, + int startArgb, int endArgb, boolean roundCapsAndJoins) { + if (r.textured) { + throw new IllegalStateException("Polyline drawing is supported only on Renderer2D.COLOR."); + } + if (points == null || pointCount < 2) return; + double t = Math.max(0.0, thickness); + if (t <= 0.0) return; + + r.path(UiShape.polyline(points, pointCount, closed), UiPaint.corners(startArgb, endArgb, endArgb, startArgb), + roundCapsAndJoins ? UiStroke.of(t).withRoundCapsAndJoins() : UiStroke.of(t), false); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + appendPolylineGradient(mesh, points, pointCount, t, closed, startArgb, endArgb, roundCapsAndJoins); + r.endAutoBatch(auto); + } + + static void polylineLinearGradient(Renderer2D r, double[] points, int pointCount, double thickness, boolean closed, + double x, double y, double width, double height, + int startArgb, int endArgb, float angleDeg, float offsetPx, + boolean roundCapsAndJoins) { + if (r.textured) { + throw new IllegalStateException("Polyline drawing is supported only on Renderer2D.COLOR."); + } + if (points == null || pointCount < 2) return; + double t = Math.max(0.0, thickness); + if (t <= 0.0) return; + + r.path(UiShape.polyline(points, pointCount, closed), UiPaint.linear(startArgb, endArgb, angleDeg, offsetPx), + roundCapsAndJoins ? UiStroke.of(t).withRoundCapsAndJoins() : UiStroke.of(t), false); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + appendPolylineLinearGradient(mesh, points, pointCount, t, closed, + x, y, width, height, startArgb, endArgb, angleDeg, offsetPx, roundCapsAndJoins); + r.endAutoBatch(auto); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRects.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRects.java new file mode 100644 index 0000000..ea7d2a3 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRects.java @@ -0,0 +1,152 @@ +/* + * 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.render.engine.renderer; + +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiPaint; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiShape; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; + +import java.util.function.Consumer; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.appendColoredQuad; +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.clampRoundedRadius; +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.normalizeCornerRadii; + +final class Renderer2DRects { + private Renderer2DRects() { + } + + static void quadBatch(Renderer2D r, Consumer consumer) { + if (r.textured) { + throw new IllegalStateException("Quad batching is supported only on Renderer2D.COLOR."); + } + if (consumer == null) return; + + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + Renderer2D.QuadBatch quadBatch = new Renderer2D.QuadBatch(mesh); + try { + consumer.accept(quadBatch); + } finally { + r.endAutoBatch(auto); + } + } + + static void quadCorners(Renderer2D r, double x, double y, double width, double height, + int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { + r.shape(UiShape.rect(x, y, width, height), UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.COLORED, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + appendColoredQuad(mesh, x, y, width, height, cTopLeft, cTopRight, cBottomRight, cBottomLeft); + + r.endAutoBatch(auto); + } + + static void roundedRectMaskedQuad(Renderer2D r, double x, double y, double w, double h, + double maskX, double maskY, double maskW, double maskH, + float radius, float softness, + int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { + r.shape(UiShape.roundedRect(maskX, maskY, maskW, maskH, radius), UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int tlA = (cTopLeft >>> 24) & 0xFF; + int tlR = (cTopLeft >>> 16) & 0xFF; + int tlG = (cTopLeft >>> 8) & 0xFF; + int tlB = cTopLeft & 0xFF; + int trA = (cTopRight >>> 24) & 0xFF; + int trR = (cTopRight >>> 16) & 0xFF; + int trG = (cTopRight >>> 8) & 0xFF; + int trB = cTopRight & 0xFF; + int brA = (cBottomRight >>> 24) & 0xFF; + int brR = (cBottomRight >>> 16) & 0xFF; + int brG = (cBottomRight >>> 8) & 0xFF; + int brB = cBottomRight & 0xFF; + int blA = (cBottomLeft >>> 24) & 0xFF; + int blR = (cBottomLeft >>> 16) & 0xFF; + int blG = (cBottomLeft >>> 8) & 0xFF; + int blB = cBottomLeft & 0xFF; + float clampedRadius = clampRoundedRadius(radius, maskW, maskH); + + int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(maskX, maskY, maskW, maskH).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(maskX, maskY, maskW, maskH).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(maskX, maskY, maskW, maskH).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(maskX, maskY, maskW, maskH).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void roundedRectCornersQuad(Renderer2D r, double x, double y, double w, double h, + float radiusTL, float radiusTR, float radiusBR, float radiusBL, + float softness, + int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { + r.shape(UiShape.roundedRect(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL), UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_CORNERS, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int tlA = (cTopLeft >>> 24) & 0xFF; + int tlR = (cTopLeft >>> 16) & 0xFF; + int tlG = (cTopLeft >>> 8) & 0xFF; + int tlB = cTopLeft & 0xFF; + int trA = (cTopRight >>> 24) & 0xFF; + int trR = (cTopRight >>> 16) & 0xFF; + int trG = (cTopRight >>> 8) & 0xFF; + int trB = cTopRight & 0xFF; + int brA = (cBottomRight >>> 24) & 0xFF; + int brR = (cBottomRight >>> 16) & 0xFF; + int brG = (cBottomRight >>> 8) & 0xFF; + int brB = cBottomRight & 0xFF; + int blA = (cBottomLeft >>> 24) & 0xFF; + int blR = (cBottomLeft >>> 16) & 0xFF; + int blG = (cBottomLeft >>> 8) & 0xFF; + int blB = cBottomLeft & 0xFF; + float[] cornerRadiiTmp = r.cornerRadiiTmp; + normalizeCornerRadii(w, h, radiusTL, radiusTR, radiusBR, radiusBL, cornerRadiiTmp); + + int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, 0f, 0f, 0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, 0f, 0f, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, 0f, 0f, 0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, 0f, 0f, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRectsExtra.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRectsExtra.java new file mode 100644 index 0000000..1df3b94 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRectsExtra.java @@ -0,0 +1,188 @@ +/* + * 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.render.engine.renderer; + +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiPaint; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiShape; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiStroke; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; +import net.minecraft.util.Mth; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.buildRoundedProgressRect; +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.clampRoundedRadius; +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.normalizeCornerRadii; + +final class Renderer2DRectsExtra { + private Renderer2DRectsExtra() { + } + + static void roundedRectStroke(Renderer2D r, double x, double y, double w, double h, + float radius, float softness, float thickness, int argb) { + r.shapeStroke(UiShape.roundedRect(x, y, w, h, radius), UiPaint.solid(argb), UiStroke.of(thickness)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_STROKE, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + float clampedRadius = clampRoundedRadius(radius, w, h); + float stroke = Math.max(0.0f, thickness); + + int i1 = mesh.vec2(x, y).local2(x, y).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void roundedRectStrokeAngularGradient(Renderer2D r, double x, double y, double w, double h, + float radius, float softness, float thickness, + int startArgb, int endArgb, float offset) { + r.shapeStroke(UiShape.roundedRect(x, y, w, h, radius), UiPaint.solid(startArgb), UiStroke.of(thickness)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_STROKE_ANGULAR, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int sa = (startArgb >>> 24) & 0xFF; + int sr = (startArgb >>> 16) & 0xFF; + int sg = (startArgb >>> 8) & 0xFF; + int sb = startArgb & 0xFF; + float ea = ((endArgb >>> 24) & 0xFF) / 255.0f; + float er = ((endArgb >>> 16) & 0xFF) / 255.0f; + float eg = ((endArgb >>> 8) & 0xFF) / 255.0f; + float eb = (endArgb & 0xFF) / 255.0f; + float clampedRadius = clampRoundedRadius(radius, w, h); + float stroke = Math.max(0.0f, thickness); + float phase = offset - (float) Math.floor(offset); + + int i1 = mesh.vec2(x, y).local2(x, y).color(sr, sg, sb, sa).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, phase).vec4(er, eg, eb, ea).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(sr, sg, sb, sa).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, phase).vec4(er, eg, eb, ea).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(sr, sg, sb, sa).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, phase).vec4(er, eg, eb, ea).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(sr, sg, sb, sa).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, phase).vec4(er, eg, eb, ea).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void roundedRectStrokeCorners(Renderer2D r, double x, double y, double w, double h, + float radiusTL, float radiusTR, float radiusBR, float radiusBL, + float softness, float thickness, int argb) { + r.shapeStroke(UiShape.roundedRect(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL), UiPaint.solid(argb), UiStroke.of(thickness)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_STROKE_CORNERS, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + float[] cornerRadiiTmp = r.cornerRadiiTmp; + normalizeCornerRadii(w, h, radiusTL, radiusTR, radiusBR, radiusBL, cornerRadiiTmp); + float stroke = Math.max(0.0f, thickness); + + int i1 = mesh.vec2(x, y).local2(x, y).color(red, green, blue, a).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, stroke, 0f, 0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, stroke, 0f, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, stroke, 0f, 0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(red, green, blue, a).vec4(x, y, w, h).vec4(cornerRadiiTmp[0], cornerRadiiTmp[1], cornerRadiiTmp[2], cornerRadiiTmp[3]).vec4(0.0f, stroke, 0f, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void roundedRectStrokeGradientQuad(Renderer2D r, double x, double y, double w, double h, + float radius, float softness, float thickness, + int cTopLeft, int cTopRight, int cBottomRight, int cBottomLeft) { + r.shapeStroke(UiShape.roundedRect(x, y, w, h, radius), UiPaint.corners(cTopLeft, cTopRight, cBottomRight, cBottomLeft), UiStroke.of(thickness)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_STROKE, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int tlA = (cTopLeft >>> 24) & 0xFF; + int tlR = (cTopLeft >>> 16) & 0xFF; + int tlG = (cTopLeft >>> 8) & 0xFF; + int tlB = cTopLeft & 0xFF; + int trA = (cTopRight >>> 24) & 0xFF; + int trR = (cTopRight >>> 16) & 0xFF; + int trG = (cTopRight >>> 8) & 0xFF; + int trB = cTopRight & 0xFF; + int brA = (cBottomRight >>> 24) & 0xFF; + int brR = (cBottomRight >>> 16) & 0xFF; + int brG = (cBottomRight >>> 8) & 0xFF; + int brB = cBottomRight & 0xFF; + int blA = (cBottomLeft >>> 24) & 0xFF; + int blR = (cBottomLeft >>> 16) & 0xFF; + int blG = (cBottomLeft >>> 8) & 0xFF; + int blB = cBottomLeft & 0xFF; + float clampedRadius = clampRoundedRadius(radius, w, h); + float stroke = Math.max(0.0f, thickness); + + int i1 = mesh.vec2(x, y).local2(x, y).color(tlR, tlG, tlB, tlA).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(blR, blG, blB, blA).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(brR, brG, brB, brA).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(trR, trG, trB, trA).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, stroke, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void roundedProgressRectGradient(Renderer2D r, double x, double y, double w, double h, + float radius, float softness, + float progress, + boolean fromRight, + int startArgb, int endArgb, + float angleDeg, float offsetPx) { + if (w <= 0.0 || h <= 0.0) return; + float p = Mth.clamp(progress, 0.0f, 1.0f); + if (p <= 0.0001f) return; + if (p >= 0.9999f) { + r.roundedRectGradient(x, y, w, h, radius, softness, startArgb, endArgb, angleDeg, offsetPx); + return; + } + + double fillW = Math.max(0.0, Math.min(w, w * p)); + double fillX = fromRight ? x + w - fillW : x; + double clipX = fromRight ? fillX : x + fillW; + int count = buildRoundedProgressRect(r.progressShapeTmp, r.rectShapeTmp, x, y, w, h, radius, clipX, fromRight); + if (count < 3) return; + Renderer2DPolygons.polygonGradient(r, r.progressShapeTmp, count, fillX, y, fillW, h, startArgb, endArgb, angleDeg, offsetPx); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRectsGlow.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRectsGlow.java new file mode 100644 index 0000000..35bd3eb --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DRectsGlow.java @@ -0,0 +1,151 @@ +/* + * 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.render.engine.renderer; + +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.clampRoundedRadius; + +final class Renderer2DRectsGlow { + private Renderer2DRectsGlow() { + } + + static void roundedRectGlow(Renderer2D r, double x, double y, double w, double h, + float radius, float softness, float glow, int argb) { + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_GLOW, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + float clampedRadius = clampRoundedRadius(radius, w, h); + + double expand = glow; + double gx = x - expand; + double gy = y - expand; + double gw = w + expand * 2.0f; + double gh = h + expand * 2.0f; + + int i1 = mesh.vec2(gx, gy).local2(gx, gy).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glow, 0f).next(); + int i2 = mesh.vec2(gx, gy + gh).local2(gx, gy + gh).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glow, 0f).next(); + int i3 = mesh.vec2(gx + gw, gy + gh).local2(gx + gw, gy + gh).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glow, 0f).next(); + int i4 = mesh.vec2(gx + gw, gy).local2(gx + gw, gy).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glow, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void roundedRectShadow(Renderer2D r, double x, double y, double w, double h, + float radius, float softness, float spread, int argb) { + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_SHADOW, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + float clampedRadius = clampRoundedRadius(radius, w, h); + + double expandX = 2.0f; + double expandY = spread + 2.0f; + double gx = x - expandX; + double gw = w + expandX * 2.0f; + double gy = y; + double gh = h + expandY; + + int i1 = mesh.vec2(gx, gy).local2(gx, gy).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, spread, 0f).next(); + int i2 = mesh.vec2(gx, gy + gh).local2(gx, gy + gh).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, spread, 0f).next(); + int i3 = mesh.vec2(gx + gw, gy + gh).local2(gx + gw, gy + gh).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, spread, 0f).next(); + int i4 = mesh.vec2(gx + gw, gy).local2(gx + gw, gy).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, spread, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void roundedRectSoftShadow(Renderer2D r, double x, double y, double w, double h, + float radius, float blur, float innerAlpha, int argb) { + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_SOFT_SHADOW, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + + double expand = blur * 2.0; + double sx = x - expand; + double sy = y - expand; + double sw = w + expand * 2.0; + double sh = h + expand * 2.0; + + int i1 = mesh.vec2(sx, sy).local2(sx, sy).color(red, green, blue, a).vec4(x, y, w, h).vec4(radius, blur, innerAlpha, 0f).next(); + int i2 = mesh.vec2(sx, sy + sh).local2(sx, sy + sh).color(red, green, blue, a).vec4(x, y, w, h).vec4(radius, blur, innerAlpha, 0f).next(); + int i3 = mesh.vec2(sx + sw, sy + sh).local2(sx + sw, sy + sh).color(red, green, blue, a).vec4(x, y, w, h).vec4(radius, blur, innerAlpha, 0f).next(); + int i4 = mesh.vec2(sx + sw, sy).local2(sx + sw, sy).color(red, green, blue, a).vec4(x, y, w, h).vec4(radius, blur, innerAlpha, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void radialGlowMasked(Renderer2D r, double x, double y, double w, double h, + float radius, float softness, + float glowRadius, float cx, float cy, + int argb) { + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.RADIAL_GLOW, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + float clampedRadius = clampRoundedRadius(radius, w, h); + + int i1 = mesh.vec2(x, y).local2(x, y).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glowRadius, 0.0f).vec4(cx, cy, 0f, 0f).next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glowRadius, 0.0f).vec4(cx, cy, 0f, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glowRadius, 0.0f).vec4(cx, cy, 0f, 0f).next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, glowRadius, 0.0f).vec4(cx, cy, 0f, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DSmokeFill.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DSmokeFill.java new file mode 100644 index 0000000..4226230 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DSmokeFill.java @@ -0,0 +1,105 @@ +/* + * 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.render.engine.renderer; + +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; +import net.minecraft.util.Mth; + +final class Renderer2DSmokeFill { + private Renderer2DSmokeFill() { + } + + static void roundedSmokeFill(Renderer2D r, double x, double y, double w, double h, + float radius, float softness, + float fillRatio, + boolean fromRight, + int firstArgb, + int secondArgb, + int thirdArgb, + float time, + float smokeScale, + float smokeMix, + int octaves, + float flowX, + float flowY, + float intensity) { + if (w <= 0.0 || h <= 0.0) return; + float fill = Mth.clamp(fillRatio, 0.0f, 1.0f); + if (fill <= 0.0001f) return; + + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_FILL_SMOKE, null, null); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a0 = (firstArgb >>> 24) & 0xFF; + int r0 = (firstArgb >>> 16) & 0xFF; + int g0 = (firstArgb >>> 8) & 0xFF; + int b0 = firstArgb & 0xFF; + + float r1 = ((secondArgb >>> 16) & 0xFF) / 255.0f; + float g1 = ((secondArgb >>> 8) & 0xFF) / 255.0f; + float b1 = (secondArgb & 0xFF) / 255.0f; + float a1 = ((secondArgb >>> 24) & 0xFF) / 255.0f; + + float r2 = ((thirdArgb >>> 16) & 0xFF) / 255.0f; + float g2 = ((thirdArgb >>> 8) & 0xFF) / 255.0f; + float b2 = (thirdArgb & 0xFF) / 255.0f; + float a2 = ((thirdArgb >>> 24) & 0xFF) / 255.0f; + + float fromRightFlag = fromRight ? 1.0f : 0.0f; + float safeScale = Math.max(0.1f, smokeScale); + float safeMix = Mth.clamp(smokeMix, 0.0f, 1.0f); + float safeOctaves = Mth.clamp(octaves, 1, 8); + float safeIntensity = Math.max(0.0f, intensity); + + int i1 = mesh.vec2(x, y).local2(x, y).color(r0, g0, b0, a0) + .vec4((float) x, (float) y, (float) w, (float) h) + .vec4(radius, softness, fill, fromRightFlag) + .vec4(r1, g1, b1, a1) + .vec4(r2, g2, b2, a2) + .vec4(time, safeScale, safeMix, safeOctaves) + .vec4(flowX, flowY, safeIntensity, 0.0f) + .next(); + int i2 = mesh.vec2(x, y + h).local2(x, y + h).color(r0, g0, b0, a0) + .vec4((float) x, (float) y, (float) w, (float) h) + .vec4(radius, softness, fill, fromRightFlag) + .vec4(r1, g1, b1, a1) + .vec4(r2, g2, b2, a2) + .vec4(time, safeScale, safeMix, safeOctaves) + .vec4(flowX, flowY, safeIntensity, 0.0f) + .next(); + int i3 = mesh.vec2(x + w, y + h).local2(x + w, y + h).color(r0, g0, b0, a0) + .vec4((float) x, (float) y, (float) w, (float) h) + .vec4(radius, softness, fill, fromRightFlag) + .vec4(r1, g1, b1, a1) + .vec4(r2, g2, b2, a2) + .vec4(time, safeScale, safeMix, safeOctaves) + .vec4(flowX, flowY, safeIntensity, 0.0f) + .next(); + int i4 = mesh.vec2(x + w, y).local2(x + w, y).color(r0, g0, b0, a0) + .vec4((float) x, (float) y, (float) w, (float) h) + .vec4(radius, softness, fill, fromRightFlag) + .vec4(r1, g1, b1, a1) + .vec4(r2, g2, b2, a2) + .vec4(time, safeScale, safeMix, safeOctaves) + .vec4(flowX, flowY, safeIntensity, 0.0f) + .next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DTextures.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DTextures.java new file mode 100644 index 0000000..5de8532 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer2DTextures.java @@ -0,0 +1,185 @@ +/* + * 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.render.engine.renderer; + +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTextureView; +import dev.loki.lovisual.render.engine.command.UiShapeCommand; +import dev.loki.lovisual.render.engine.command.UiTextureDrawCommand; +import dev.loki.lovisual.render.engine.renderer.ui.DrawBatch; +import dev.loki.lovisual.render.engine.renderer.ui.UiBatchType; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiPaint; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiShape; +import dev.loki.lovisual.render.engine.renderer.ui.draw.UiStroke; +import dev.loki.lovisual.render.engine.uniform.MeshBuilder; + +import static dev.loki.lovisual.render.engine.renderer.ui.draw.UiMeshGeometry.clampRoundedRadius; + +final class Renderer2DTextures { + private Renderer2DTextures() { + } + + static void textureQuad(Renderer2D r, GpuTextureView samplerView, GpuSampler sampler, + double x, double y, double w, double h, int argb) { + if (r.textured) { + throw new IllegalStateException("Batched texture quad drawing is supported only on Renderer2D.COLOR."); + } + if (samplerView == null || sampler == null) return; + if (w == 0.0 || h == 0.0) return; + + Renderer2D.recordUi(new UiTextureDrawCommand(samplerView, sampler, UiShape.rect(x, y, w, h), UiPaint.solid(argb), 0f, 0f, 1f, 1f, false)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.TEXTURED, samplerView, sampler); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + + int i1 = mesh.vec2(x, y).raw2(0.0, 0.0).color(red, green, blue, a).next(); + int i2 = mesh.vec2(x, y + h).raw2(0.0, 1.0).color(red, green, blue, a).next(); + int i3 = mesh.vec2(x + w, y + h).raw2(1.0, 1.0).color(red, green, blue, a).next(); + int i4 = mesh.vec2(x + w, y).raw2(1.0, 0.0).color(red, green, blue, a).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void msdfTextureQuad(Renderer2D r, GpuTextureView samplerView, GpuSampler sampler, + double x, double y, double w, double h, + int topLeft, int topRight, int bottomRight, int bottomLeft, + float pxRange, int atlasWidth, int atlasHeight) { + if (r.textured) { + throw new IllegalStateException("Batched MSDF texture quad drawing is supported only on Renderer2D.COLOR."); + } + if (samplerView == null || sampler == null) return; + if (w == 0.0 || h == 0.0) return; + if (pxRange <= 0.0f || atlasWidth <= 0 || atlasHeight <= 0) return; + + Renderer2D.recordUi(new UiTextureDrawCommand(samplerView, sampler, UiShape.rect(x, y, w, h), UiPaint.solid(topLeft), 0f, 0f, 1f, 1f, false)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreateMsdf(samplerView, sampler, pxRange, atlasWidth, atlasHeight); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int i1 = mesh.vec2(x, y).raw2(0.0, 0.0).color((topLeft >>> 16) & 0xFF, (topLeft >>> 8) & 0xFF, topLeft & 0xFF, (topLeft >>> 24) & 0xFF).next(); + int i2 = mesh.vec2(x, y + h).raw2(0.0, 1.0).color((bottomLeft >>> 16) & 0xFF, (bottomLeft >>> 8) & 0xFF, bottomLeft & 0xFF, (bottomLeft >>> 24) & 0xFF).next(); + int i3 = mesh.vec2(x + w, y + h).raw2(1.0, 1.0).color((bottomRight >>> 16) & 0xFF, (bottomRight >>> 8) & 0xFF, bottomRight & 0xFF, (bottomRight >>> 24) & 0xFF).next(); + int i4 = mesh.vec2(x + w, y).raw2(1.0, 0.0).color((topRight >>> 16) & 0xFF, (topRight >>> 8) & 0xFF, topRight & 0xFF, (topRight >>> 24) & 0xFF).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void texQuad(Renderer2D r, double x, double y, double width, double height, + double texX1, double texY1, double texX2, double texY2, + int argb) { + Renderer2D.recordUi(new UiShapeCommand(UiShape.rect(x, y, width, height), UiPaint.solid(argb), UiStroke.NONE, true)); + MeshBuilder texturedTriangles = r.texturedTriangles; + if (texturedTriangles == null) return; + texturedTriangles.alpha = r.alpha; + texturedTriangles.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + int i1 = texturedTriangles.vec2(x, y).raw2(texX1, texY1).color(red, green, blue, a).next(); + int i2 = texturedTriangles.vec2(x, y + height).raw2(texX1, texY2).color(red, green, blue, a).next(); + int i3 = texturedTriangles.vec2(x + width, y + height).raw2(texX2, texY2).color(red, green, blue, a).next(); + int i4 = texturedTriangles.vec2(x + width, y).raw2(texX2, texY1).color(red, green, blue, a).next(); + + texturedTriangles.quad(i1, i2, i3, i4); + } + + static void roundedTexRect(Renderer2D r, double x, double y, double w, double h, + float radius, float softness, + double texX1, double texY1, double texX2, double texY2, + int argb, GpuTextureView samplerView, GpuSampler sampler) { + if (!r.textured) { + throw new IllegalStateException("Renderer2D is not configured for textures."); + } + if (samplerView == null || sampler == null) return; + + Renderer2D.recordUi(new UiTextureDrawCommand(samplerView, sampler, UiShape.roundedRect(x, y, w, h, radius), UiPaint.solid(argb), + (float) texX1, (float) texY1, (float) texX2, (float) texY2, false)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_TEXTURED, samplerView, sampler); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + float clampedRadius = clampRoundedRadius(radius, w, h); + int i1 = mesh.vec2(x, y).raw2(texX1, texY1).local2(x, y).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + int i2 = mesh.vec2(x, y + h).raw2(texX1, texY2).local2(x, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).raw2(texX2, texY2).local2(x + w, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + int i4 = mesh.vec2(x + w, y).raw2(texX2, texY1).local2(x + w, y).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } + + static void roundedTexMaskRect(Renderer2D r, double x, double y, double w, double h, + float radius, float softness, + double texX1, double texY1, double texX2, double texY2, + int argb, GpuTextureView samplerView, GpuSampler sampler) { + if (!r.textured) { + throw new IllegalStateException("Renderer2D is not configured for textures."); + } + if (samplerView == null || sampler == null) return; + + Renderer2D.recordUi(new UiTextureDrawCommand(samplerView, sampler, UiShape.roundedRect(x, y, w, h, radius), UiPaint.solid(argb), + (float) texX1, (float) texY1, (float) texX2, (float) texY2, true)); + boolean auto = r.beginAutoBatch(); + DrawBatch batch = Renderer2D.UI_BATCHER.getOrCreate(UiBatchType.ROUNDED_TEXTURED_MASK, samplerView, sampler); + if (batch == null) { + r.endAutoBatch(auto); + return; + } + MeshBuilder mesh = batch.mesh; + mesh.alpha = r.alpha; + + mesh.ensureQuadCapacity(); + + int a = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + float clampedRadius = clampRoundedRadius(radius, w, h); + int i1 = mesh.vec2(x, y).raw2(texX1, texY1).local2(x, y).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + int i2 = mesh.vec2(x, y + h).raw2(texX1, texY2).local2(x, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + int i3 = mesh.vec2(x + w, y + h).raw2(texX2, texY2).local2(x + w, y + h).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + int i4 = mesh.vec2(x + w, y).raw2(texX2, texY1).local2(x + w, y).color(red, green, blue, a).vec4(x, y, w, h).vec4(clampedRadius, 0.0f, 0f, 0f).next(); + mesh.quad(i1, i2, i3, i4); + + r.endAutoBatch(auto); + } +} \ No newline at end of file diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer3D.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer3D.java index d40a7ad..dd02db9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer3D.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/Renderer3D.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -19,7 +19,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.core.policy.VisibilityProvider; import dev.loki.lovisual.render.engine.core.policy.VisibilityQuery; @@ -62,7 +62,7 @@ public final class Renderer3D { * Call once per frame/phase before modules write geometry. */ public void begin() { - RenderFrameContext ctx = CombatantRenderSystem.ensureFrameContext(); + RenderFrameContext ctx = LoVisualRenderSystem.ensureFrameContext(); WORLD_COMPILER.beginFrame(ctx.frameId()); commands.beginFrame(); } @@ -234,8 +234,8 @@ public final class Renderer3D { public static boolean isSectionVisible(AABB box) { if (box == null) return true; - RenderFrameContext ctx = CombatantRenderSystem.currentContext(); - VisibilityProvider provider = ctx != null ? ctx.visibilityProvider() : CombatantRenderSystem.sodium().visibilityProvider(); + RenderFrameContext ctx = LoVisualRenderSystem.currentContext(); + VisibilityProvider provider = ctx != null ? ctx.visibilityProvider() : LoVisualRenderSystem.sodium().visibilityProvider(); if (provider == null) return true; return provider.isBoxVisible(box, VisibilityQuery.worldOverlay(box)); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/BlurSource.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/BlurSource.java index d219bb7..e987606 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/BlurSource.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/BlurSource.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/Deferred2DSubmit.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/Deferred2DSubmit.java index c8ab6b5..f22477e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/Deferred2DSubmit.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/Deferred2DSubmit.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredActionSubmit.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredActionSubmit.java index ff09298..41a4e0b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredActionSubmit.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredActionSubmit.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredOrderedSubmit.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredOrderedSubmit.java index 2f2e620..c0c455a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredOrderedSubmit.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredOrderedSubmit.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredTexturedSubmit.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredTexturedSubmit.java index cf2f02a..dd6e43a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredTexturedSubmit.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DeferredTexturedSubmit.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import com.mojang.blaze3d.textures.GpuSampler; import com.mojang.blaze3d.textures.GpuTextureView; import net.minecraft.client.Minecraft; import dev.loki.lovisual.render.engine.core.ViewportContext; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.MeshRenderer; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.renderer.Renderer2D.Deferred2DLayer; @@ -29,7 +29,7 @@ public record DeferredTexturedSubmit(Deferred2DLayer layer, ViewportContext view if (fb == null) return; MeshRenderer.begin() .attachments(fb.getColorTextureView(), null) - .pipeline(CombatantRenderPipelines.UI_TEXTURED) + .pipeline(LoVisualRenderPipelines.UI_TEXTURED) .mesh(mesh) .sampler(samplerName != null ? samplerName : "u_Texture", samplerView, sampler) .end(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DrawBatch.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DrawBatch.java index ba3c6ea..26f0580 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DrawBatch.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/DrawBatch.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/FrameBlurCacheEntry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/FrameBlurCacheEntry.java index cedf40a..d283ec1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/FrameBlurCacheEntry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/FrameBlurCacheEntry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/HudDeferredGuiElement.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/HudDeferredGuiElement.java index 21dd03a..848ba68 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/HudDeferredGuiElement.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/HudDeferredGuiElement.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,7 +16,7 @@ import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.client.renderer.state.gui.GuiElementRenderState; /** - * Zero-vertex vanilla GuiRenderState marker used to splice Combatant's deferred 2D + * Zero-vertex vanilla GuiRenderState marker used to splice LoVisual's deferred 2D * batches into the same logical HUD order as the Fabric/vanilla HUD callback that * recorded them. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemBatch.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemBatch.java index 5e8b22d..7f97e15 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemBatch.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemBatch.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemBatchRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemBatchRenderer.java index 09d1bd9..17770d4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemBatchRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemBatchRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -28,7 +28,7 @@ import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.profiler.RenderCostProfiler; import dev.loki.lovisual.render.engine.renderer.MeshRenderer; import dev.loki.lovisual.render.engine.text.TextRenderer; @@ -44,7 +44,7 @@ public final class ItemBatchRenderer { private static final int ITEM_DURABILITY_TRACK_COLOR = 0x72000000; private static final int ITEM_DURABILITY_TRACK_HIGHLIGHT = 0x26FFFFFF; private static final int ITEM_OVERLAY_PREALLOCATED_ITEMS = Math.max(32, - Integer.getInteger("combatant.render.itemOverlay.preallocatedItems", 256)); + Integer.getInteger("lovisual.render.itemOverlay.preallocatedItems", 256)); private static FeatureRenderDispatcher itemFeatureDispatcher; private static GuiItemAtlas itemAtlas; @@ -60,10 +60,10 @@ public final class ItemBatchRenderer { } public static void init() { - itemBlitMesh = createItemOverlayMesh(CombatantRenderPipelines.UI_TEXTURED, 1); - itemDurabilityGlowMesh = createItemOverlayMesh(CombatantRenderPipelines.UI_ROUNDED_GLOW_BATCH, 1); - itemDurabilityRoundedMesh = createItemOverlayMesh(CombatantRenderPipelines.UI_ROUNDED_BATCH, 3); - itemCooldownMesh = createItemOverlayMesh(CombatantRenderPipelines.UI_COLORED, 1); + itemBlitMesh = createItemOverlayMesh(LoVisualRenderPipelines.UI_TEXTURED, 1); + itemDurabilityGlowMesh = createItemOverlayMesh(LoVisualRenderPipelines.UI_ROUNDED_GLOW_BATCH, 1); + itemDurabilityRoundedMesh = createItemOverlayMesh(LoVisualRenderPipelines.UI_ROUNDED_BATCH, 3); + itemCooldownMesh = createItemOverlayMesh(LoVisualRenderPipelines.UI_COLORED, 1); } private static MeshBuilder createItemOverlayMesh(RenderPipeline pipeline, int quadsPerItem) { @@ -84,28 +84,28 @@ public final class ItemBatchRenderer { private static MeshBuilder beginItemBlitMesh(int commandCount) { if (itemBlitMesh == null) { - itemBlitMesh = createItemOverlayMesh(CombatantRenderPipelines.UI_TEXTURED, 1); + itemBlitMesh = createItemOverlayMesh(LoVisualRenderPipelines.UI_TEXTURED, 1); } return beginItemOverlayMesh(itemBlitMesh, commandCount, 1); } private static MeshBuilder beginItemDurabilityGlowMesh(int commandCount) { if (itemDurabilityGlowMesh == null) { - itemDurabilityGlowMesh = createItemOverlayMesh(CombatantRenderPipelines.UI_ROUNDED_GLOW_BATCH, 1); + itemDurabilityGlowMesh = createItemOverlayMesh(LoVisualRenderPipelines.UI_ROUNDED_GLOW_BATCH, 1); } return beginItemOverlayMesh(itemDurabilityGlowMesh, commandCount, 1); } private static MeshBuilder beginItemDurabilityRoundedMesh(int commandCount) { if (itemDurabilityRoundedMesh == null) { - itemDurabilityRoundedMesh = createItemOverlayMesh(CombatantRenderPipelines.UI_ROUNDED_BATCH, 3); + itemDurabilityRoundedMesh = createItemOverlayMesh(LoVisualRenderPipelines.UI_ROUNDED_BATCH, 3); } return beginItemOverlayMesh(itemDurabilityRoundedMesh, commandCount, 3); } private static MeshBuilder beginItemCooldownMesh(int commandCount) { if (itemCooldownMesh == null) { - itemCooldownMesh = createItemOverlayMesh(CombatantRenderPipelines.UI_COLORED, 1); + itemCooldownMesh = createItemOverlayMesh(LoVisualRenderPipelines.UI_COLORED, 1); } return beginItemOverlayMesh(itemCooldownMesh, commandCount, 1); } @@ -221,13 +221,13 @@ public final class ItemBatchRenderer { } } - if (submitItemOverlayMesh(mc, CombatantRenderPipelines.UI_ROUNDED_GLOW_BATCH, durabilityGlowMesh, true)) { + if (submitItemOverlayMesh(mc, LoVisualRenderPipelines.UI_ROUNDED_GLOW_BATCH, durabilityGlowMesh, true)) { drawCalls++; } - if (submitItemOverlayMesh(mc, CombatantRenderPipelines.UI_ROUNDED_BATCH, durabilityRoundedMesh, true)) { + if (submitItemOverlayMesh(mc, LoVisualRenderPipelines.UI_ROUNDED_BATCH, durabilityRoundedMesh, true)) { drawCalls++; } - if (submitItemOverlayMesh(mc, CombatantRenderPipelines.UI_COLORED, cooldownMesh, false)) { + if (submitItemOverlayMesh(mc, LoVisualRenderPipelines.UI_COLORED, cooldownMesh, false)) { drawCalls++; } @@ -471,7 +471,7 @@ public final class ItemBatchRenderer { MeshRenderer.begin() .attachments(mc.gameRenderer.mainRenderTarget().getColorTextureView(), null) - .pipeline(CombatantRenderPipelines.UI_TEXTURED) + .pipeline(LoVisualRenderPipelines.UI_TEXTURED) .mesh(mesh) .sampler("u_Texture", atlasTextureView, sampler) .end(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemDrawCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemDrawCommand.java index 5a15f76..f01e036 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemDrawCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemDrawCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemResolveKey.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemResolveKey.java index 9475baf..b595863 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemResolveKey.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/ItemResolveKey.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/OrderedUiBatcher.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/OrderedUiBatcher.java index da5e942..7e11791 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/OrderedUiBatcher.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/OrderedUiBatcher.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.pipeline.TextureTarget; import com.mojang.blaze3d.textures.GpuSampler; import com.mojang.blaze3d.textures.GpuTextureView; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.ViewportContext; import dev.loki.lovisual.render.helpers.ScissorFunction; import dev.loki.lovisual.render.helpers.ClipFunction; @@ -26,7 +26,7 @@ import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import dev.loki.lovisual.render.engine.core.RenderPhase; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.renderer.MeshRenderer; import dev.loki.lovisual.render.engine.renderer.Renderer2D; @@ -536,7 +536,7 @@ public final class OrderedUiBatcher { MeshRenderer.begin() .attachments(mainColorView, null) - .pipeline(CombatantRenderPipelines.UI_TEXTURED) + .pipeline(LoVisualRenderPipelines.UI_TEXTURED) .mesh(fxCompositeMesh) .sampler("u_Texture", fxView, fxSampler) .end(); @@ -737,7 +737,7 @@ public final class OrderedUiBatcher { float uiScale, Renderer2D.BlurQuality blurQuality, float offsetPx) { - if (CombatantRenderSystem.rhi().shapeClip().isActive()) { + if (LoVisualRenderSystem.rhi().shapeClip().isActive()) { adoptFrameBlurCache(sourceView, sourceSampler, screenW, screenH, uiScale, blurQuality, offsetPx); return 0; } @@ -858,7 +858,7 @@ public final class OrderedUiBatcher { MeshRenderer.begin() .attachments(target) .clearColor(0x00000000) - .pipeline(CombatantRenderPipelines.UI_BLUR) + .pipeline(LoVisualRenderPipelines.UI_BLUR) .mesh(compositeMesh) .uniform("UIBlur", UIBlurUniforms.get()) .sampler("u_Texture", sourceView, sourceSampler) diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/SharedBlurProfile.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/SharedBlurProfile.java index 7546ac3..269f8c5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/SharedBlurProfile.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/SharedBlurProfile.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/TextBatch.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/TextBatch.java index 0530337..0377cab 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/TextBatch.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/TextBatch.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,7 +23,7 @@ public final class TextBatch { public void begin(String label, GlyphFont font, RenderPipeline pipeline, TextPlacementMode placement, boolean liquidGlassText, boolean shapeClipActive) { - this.label = label != null ? label : "Combatant UI Text Batch"; + this.label = label != null ? label : "LoVisual UI Text Batch"; this.font = font; this.pipeline = pipeline; this.placement = placement != null ? placement : TextPlacementMode.UI; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchPlan.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchPlan.java index 0915710..606e0d1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchPlan.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchPlan.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchStats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchStats.java index 2287a61..e03cb8e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchStats.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchStats.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchType.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchType.java index 3e61653..d7128c0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchType.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatchType.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,34 +8,34 @@ package dev.loki.lovisual.render.engine.renderer.ui; import com.mojang.blaze3d.pipeline.RenderPipeline; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; public enum UiBatchType { - COLORED(CombatantRenderPipelines.UI_COLORED, false, false), - TEXTURED(CombatantRenderPipelines.UI_TEXTURED, false, true), - SVG_MSDF(CombatantRenderPipelines.UI_SVG_MSDF, false, true), - LINES(CombatantRenderPipelines.UI_COLORED_LINES, false, false), - CIRCLE(CombatantRenderPipelines.UI_CIRCLE_BATCH, true, false), - ARC(CombatantRenderPipelines.UI_ARC_BATCH, true, false), - ORBIZ_RING(CombatantRenderPipelines.UI_ORBIZ_RING_BATCH, true, false), - ROUNDED(CombatantRenderPipelines.UI_ROUNDED_BATCH, true, false), - ROUNDED_FILL_SMOKE(CombatantRenderPipelines.UI_ROUNDED_FILL_SMOKE_BATCH, true, false), - ROUNDED_STROKE(CombatantRenderPipelines.UI_ROUNDED_STROKE_BATCH, true, false), - ROUNDED_STROKE_ANGULAR(CombatantRenderPipelines.UI_ROUNDED_STROKE_ANGULAR_BATCH, true, false), - CHAMFERED(CombatantRenderPipelines.UI_CHAMFERED_BATCH, true, false), - CHAMFERED_STROKE(CombatantRenderPipelines.UI_CHAMFERED_STROKE_BATCH, true, false), - ROUNDED_STROKE_CORNERS(CombatantRenderPipelines.UI_ROUNDED_STROKE_CORNERS_BATCH, true, false), - ROUNDED_CORNERS(CombatantRenderPipelines.UI_ROUNDED_CORNERS_BATCH, true, false), - ROUNDED_GLOW(CombatantRenderPipelines.UI_ROUNDED_GLOW_BATCH, true, false), - ROUNDED_SHADOW(CombatantRenderPipelines.UI_ROUNDED_SHADOW_BATCH, true, false), - ROUNDED_SOFT_SHADOW(CombatantRenderPipelines.UI_ROUNDED_SOFT_SHADOW_BATCH, true, false), - RADIAL_GLOW(CombatantRenderPipelines.UI_RADIAL_GLOW_BATCH, true, false), - ROUNDED_TEXTURED(CombatantRenderPipelines.UI_ROUNDED_TEXTURED_BATCH, true, true), - ROUNDED_TEXTURED_MASK(CombatantRenderPipelines.UI_ROUNDED_TEXTURED_MASK_BATCH, true, true), - BLUR(CombatantRenderPipelines.UI_BLUR_BATCH, true, true), - GLASS_BLUR(CombatantRenderPipelines.UI_BLUR_BATCH_CORNERS, true, true), - BLUR_COMPLEX(CombatantRenderPipelines.UI_BLUR_BATCH_CORNERS, true, true), - LIQUID_GLASS(CombatantRenderPipelines.UI_LIQUID_GLASS_BATCH, true, true); + COLORED(LoVisualRenderPipelines.UI_COLORED, false, false), + TEXTURED(LoVisualRenderPipelines.UI_TEXTURED, false, true), + SVG_MSDF(LoVisualRenderPipelines.UI_SVG_MSDF, false, true), + LINES(LoVisualRenderPipelines.UI_COLORED_LINES, false, false), + CIRCLE(LoVisualRenderPipelines.UI_CIRCLE_BATCH, true, false), + ARC(LoVisualRenderPipelines.UI_ARC_BATCH, true, false), + ORBIZ_RING(LoVisualRenderPipelines.UI_ORBIZ_RING_BATCH, true, false), + ROUNDED(LoVisualRenderPipelines.UI_ROUNDED_BATCH, true, false), + ROUNDED_FILL_SMOKE(LoVisualRenderPipelines.UI_ROUNDED_FILL_SMOKE_BATCH, true, false), + ROUNDED_STROKE(LoVisualRenderPipelines.UI_ROUNDED_STROKE_BATCH, true, false), + ROUNDED_STROKE_ANGULAR(LoVisualRenderPipelines.UI_ROUNDED_STROKE_ANGULAR_BATCH, true, false), + CHAMFERED(LoVisualRenderPipelines.UI_CHAMFERED_BATCH, true, false), + CHAMFERED_STROKE(LoVisualRenderPipelines.UI_CHAMFERED_STROKE_BATCH, true, false), + ROUNDED_STROKE_CORNERS(LoVisualRenderPipelines.UI_ROUNDED_STROKE_CORNERS_BATCH, true, false), + ROUNDED_CORNERS(LoVisualRenderPipelines.UI_ROUNDED_CORNERS_BATCH, true, false), + ROUNDED_GLOW(LoVisualRenderPipelines.UI_ROUNDED_GLOW_BATCH, true, false), + ROUNDED_SHADOW(LoVisualRenderPipelines.UI_ROUNDED_SHADOW_BATCH, true, false), + ROUNDED_SOFT_SHADOW(LoVisualRenderPipelines.UI_ROUNDED_SOFT_SHADOW_BATCH, true, false), + RADIAL_GLOW(LoVisualRenderPipelines.UI_RADIAL_GLOW_BATCH, true, false), + ROUNDED_TEXTURED(LoVisualRenderPipelines.UI_ROUNDED_TEXTURED_BATCH, true, true), + ROUNDED_TEXTURED_MASK(LoVisualRenderPipelines.UI_ROUNDED_TEXTURED_MASK_BATCH, true, true), + BLUR(LoVisualRenderPipelines.UI_BLUR_BATCH, true, true), + GLASS_BLUR(LoVisualRenderPipelines.UI_BLUR_BATCH_CORNERS, true, true), + BLUR_COMPLEX(LoVisualRenderPipelines.UI_BLUR_BATCH_CORNERS, true, true), + LIQUID_GLASS(LoVisualRenderPipelines.UI_LIQUID_GLASS_BATCH, true, true); public final RenderPipeline pipeline; public final boolean needsUiBatch; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatcher.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatcher.java index 29cbe55..db1d208 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatcher.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBatcher.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBlurResources.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBlurResources.java index 507484e..ef4ff01 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBlurResources.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiBlurResources.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,14 +12,14 @@ import com.mojang.blaze3d.pipeline.TextureTarget; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.textures.GpuSampler; import com.mojang.blaze3d.textures.GpuTextureView; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.ViewportContext; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; -import dev.loki.lovisual.render.engine.vertex.CombatantVertexFormats; +import dev.loki.lovisual.render.engine.vertex.LoVisualVertexFormats; import net.minecraft.client.Minecraft; import org.jetbrains.annotations.Nullable; @@ -59,8 +59,8 @@ public final class UiBlurResources { int width = minecraft.getWindow().getWidth(); int height = minecraft.getWindow().getHeight(); if (width <= 0 || height <= 0) return null; - effects = CombatantRenderSystem.resources().persistentFramebuffer( - "combatant-ui-effects", width, height, false, "Renderer2D.effects" + effects = LoVisualRenderSystem.resources().persistentFramebuffer( + "lovisual-ui-effects", width, height, false, "Renderer2D.effects" ); return effects; } @@ -70,8 +70,8 @@ public final class UiBlurResources { int width = minecraft.getWindow().getWidth(); int height = minecraft.getWindow().getHeight(); if (width <= 0 || height <= 0) return null; - glassSource = CombatantRenderSystem.resources().persistentFramebuffer( - "combatant-ui-glass-source", width, height, false, "Renderer2D.glassSource" + glassSource = LoVisualRenderSystem.resources().persistentFramebuffer( + "lovisual-ui-glass-source", width, height, false, "Renderer2D.glassSource" ); return glassSource; } @@ -133,13 +133,13 @@ public final class UiBlurResources { public static TextureTarget ensureKawaseDown(Minecraft minecraft, int level) { return ensureKawaseTarget( - minecraft, KAWASE_DOWN, "combatant-ui-kawase-down-", "Renderer2D.kawaseDown", level + minecraft, KAWASE_DOWN, "lovisual-ui-kawase-down-", "Renderer2D.kawaseDown", level ); } public static TextureTarget ensureKawaseUp(Minecraft minecraft, int level) { return ensureKawaseTarget( - minecraft, KAWASE_UP, "combatant-ui-kawase-up-", "Renderer2D.kawaseUp", level + minecraft, KAWASE_UP, "lovisual-ui-kawase-up-", "Renderer2D.kawaseUp", level ); } @@ -150,7 +150,7 @@ public final class UiBlurResources { } MeshBuilder mesh = new MeshBuilder( - CombatantVertexFormats.POS2_TEXTURE_COLOR, + LoVisualVertexFormats.POS2_TEXTURE_COLOR, com.mojang.blaze3d.PrimitiveTopology.TRIANGLES, 4, 6 @@ -170,12 +170,12 @@ public final class UiBlurResources { } public static long currentFrameId() { - RenderFrameContext context = CombatantRenderSystem.ensureFrameContext(); + RenderFrameContext context = LoVisualRenderSystem.ensureFrameContext(); return context != null ? context.frameId() : Long.MIN_VALUE; } public static RenderPhase currentPhase() { - RenderFrameContext context = CombatantRenderSystem.ensureFrameContext(); + RenderFrameContext context = LoVisualRenderSystem.ensureFrameContext(); return context != null && context.phase() != null ? context.phase() : RenderPhase.NONE; } @@ -268,7 +268,7 @@ public final class UiBlurResources { int divisor = 1 << (level + 1); int width = Math.max(1, minecraft.getWindow().getWidth() / divisor); int height = Math.max(1, minecraft.getWindow().getHeight() / divisor); - TextureTarget target = CombatantRenderSystem.resources().persistentFramebuffer( + TextureTarget target = LoVisualRenderSystem.resources().persistentFramebuffer( namePrefix + level, width, height, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiDeferredScheduler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiDeferredScheduler.java index 90b308e..9cb1289 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiDeferredScheduler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiDeferredScheduler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.systems.RenderSystem; import dev.loki.lovisual.mixininterface.IGpuDevice; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.core.RenderPhase; import dev.loki.lovisual.render.engine.core.ViewportContext; @@ -35,7 +35,7 @@ public final class UiDeferredScheduler { new EnumMap<>(Renderer2D.Deferred2DLayer.class); private static final ObjectArrayList DRAINING = new ObjectArrayList<>(256); private static final ObjectArrayList BATCHER_POOL = new ObjectArrayList<>(8); - private static final int MAX_BATCHER_POOL = Integer.getInteger("combatant.render.deferredBatcherPool", 16); + private static final int MAX_BATCHER_POOL = Integer.getInteger("lovisual.render.deferredBatcherPool", 16); private static ProjectionMatrixBuffer projection; private static boolean recording; @@ -108,13 +108,13 @@ public final class UiDeferredScheduler { try { if (scissor != null && scissor.length == 4) { ((IGpuDevice) RenderSystem.getDevice()) - .combatant$pushScissor(scissor[0], scissor[1], scissor[2], scissor[3]); + .lovisual$pushScissor(scissor[0], scissor[1], scissor[2], scissor[3]); scissored = true; } command.submit(); } finally { if (scissored) { - ((IGpuDevice) RenderSystem.getDevice()).combatant$popScissor(); + ((IGpuDevice) RenderSystem.getDevice()).lovisual$popScissor(); } command.release(); DRAINING.set(i, null); @@ -169,7 +169,7 @@ public final class UiDeferredScheduler { public static Renderer2D.Deferred2DLayer layerForCurrentPhase(boolean pureItemOverlaySubmit) { if (forcedLayer != null) return forcedLayer; - RenderFrameContext frame = CombatantRenderSystem.currentContext(); + RenderFrameContext frame = LoVisualRenderSystem.currentContext(); RenderPhase phase = frame != null ? frame.phase() : RenderPhase.NONE; return phase == RenderPhase.SCREEN_TOP || phase == RenderPhase.SCREEN ? Renderer2D.Deferred2DLayer.AFTER_VANILLA_GUI @@ -226,7 +226,7 @@ public final class UiDeferredScheduler { private static ProjectionMatrixBuffer projection() { ProjectionMatrixBuffer current = projection; if (current == null) { - current = new ProjectionMatrixBuffer("combatant-deferred-2d-projection"); + current = new ProjectionMatrixBuffer("lovisual-deferred-2d-projection"); projection = current; } return current; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiDirectTexturedRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiDirectTexturedRenderer.java index 80a7ce7..2d47207 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiDirectTexturedRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiDirectTexturedRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.textures.GpuSampler; import com.mojang.blaze3d.textures.GpuTextureView; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.MeshRenderer; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; @@ -34,7 +34,7 @@ public final class UiDirectTexturedRenderer { if (mesh.getIndicesCount() <= 0) return; if (UiDeferredScheduler.shouldDefer()) { - MeshBuilder copy = copyMesh(mesh, CombatantRenderPipelines.UI_TEXTURED); + MeshBuilder copy = copyMesh(mesh, LoVisualRenderPipelines.UI_TEXTURED); if (copy != null) { UiDeferredScheduler.enqueue(new DeferredTexturedSubmit( UiDeferredScheduler.layerForCurrentPhase(false), @@ -65,7 +65,7 @@ public final class UiDirectTexturedRenderer { MeshRenderer.begin() .attachments(framebuffer.getColorTextureView(), null) - .pipeline(CombatantRenderPipelines.UI_TEXTURED) + .pipeline(LoVisualRenderPipelines.UI_TEXTURED) .mesh(mesh) .sampler(samplerName, samplerView, sampler) .end(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiEffectGraph.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiEffectGraph.java index 6284df5..6a303f3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiEffectGraph.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiEffectGraph.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import dev.loki.lovisual.render.engine.command.UiCommandBuffer; import dev.loki.lovisual.render.engine.command.UiCommandKind; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.profiler.RenderCostProfiler; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; /** * Owner for UI effects. Blur/liquid draw paths still execute through Renderer2D ordered @@ -21,7 +21,7 @@ import dev.loki.lovisual.render.engine.rhi.CombatantRhi; public final class UiEffectGraph { private int lastEffectCommands; - public void execute(UiCommandBuffer commands, RenderFrameContext context, CombatantRhi rhi) { + public void execute(UiCommandBuffer commands, RenderFrameContext context, LoVisualRhi rhi) { try (RenderCostProfiler.Scope ignored = RenderCostProfiler.uiEffect("ui_effect_graph")) { int effects = 0; if (commands != null) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiItemSubmission.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiItemSubmission.java index cee6933..e94be93 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiItemSubmission.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiItemSubmission.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiPassCompiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiPassCompiler.java index dd6d53c..687662f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiPassCompiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiPassCompiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiPassExecutor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiPassExecutor.java index 425d202..398ffb2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiPassExecutor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiPassExecutor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.engine.renderer.ui; import dev.loki.lovisual.render.engine.core.RenderFrameContext; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; /** * Executes compiled UI passes. Renderer2D ordered batches remain the production executor; @@ -17,7 +17,7 @@ import dev.loki.lovisual.render.engine.rhi.CombatantRhi; public final class UiPassExecutor { private UiBatchPlan lastPlan = UiBatchPlan.EMPTY; - public void execute(UiBatchPlan plan, RenderFrameContext context, CombatantRhi rhi) { + public void execute(UiBatchPlan plan, RenderFrameContext context, LoVisualRhi rhi) { lastPlan = plan != null ? plan : UiBatchPlan.EMPTY; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiRenderDispatcher.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiRenderDispatcher.java index 544f882..dbc8624 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiRenderDispatcher.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiRenderDispatcher.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,7 +10,7 @@ package dev.loki.lovisual.render.engine.renderer.ui; import com.mojang.blaze3d.pipeline.RenderPipeline; import dev.loki.lovisual.render.engine.command.UiCommand; import dev.loki.lovisual.render.engine.command.UiStatsSnapshot; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.text.GlyphFont; import dev.loki.lovisual.render.engine.text.backend.TextPlacementMode; @@ -30,7 +30,7 @@ public final class UiRenderDispatcher { } public static void beginLayer() { - SUBSYSTEM.beginFrame(CombatantRenderSystem.ensureFrameContext()); + SUBSYSTEM.beginFrame(LoVisualRenderSystem.ensureFrameContext()); } public static void record(UiCommand command) { @@ -43,7 +43,7 @@ public final class UiRenderDispatcher { public static void flushLayer() { if (UiDeferredScheduler.shouldDefer()) return; - SUBSYSTEM.flush(CombatantRenderSystem.ensureFrameContext(), CombatantRenderSystem.rhi()); + SUBSYSTEM.flush(LoVisualRenderSystem.ensureFrameContext(), LoVisualRenderSystem.rhi()); } public static void recordBackendCommand(UiBatchType type) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiRendererSubsystem.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiRendererSubsystem.java index 4da11d0..80f849e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiRendererSubsystem.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/UiRendererSubsystem.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import dev.loki.lovisual.render.engine.command.UiCommand; import dev.loki.lovisual.render.engine.command.UiCommandBuffer; import dev.loki.lovisual.render.engine.command.UiStatsSnapshot; import dev.loki.lovisual.render.engine.core.RenderFrameContext; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; /** * UI rendering gateway: Renderer2D records normalized commands here, the compiler builds a @@ -46,7 +46,7 @@ public final class UiRendererSubsystem { return commands.size() > 0; } - public void flush(RenderFrameContext context, CombatantRhi rhi) { + public void flush(RenderFrameContext context, LoVisualRhi rhi) { commands.beginFrame(context); if (commands.size() == 0) { lastPlan = UiBatchPlan.EMPTY; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiBoxPathBuilder.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiBoxPathBuilder.java index 8c7178e..305c0d6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiBoxPathBuilder.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiBoxPathBuilder.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiBoxShape.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiBoxShape.java index 871da1f..756486c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiBoxShape.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiBoxShape.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiChamferRadii.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiChamferRadii.java index 1552bd2..db78cd9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiChamferRadii.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiChamferRadii.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerKind.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerKind.java index ff8ba55..a287dfd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerKind.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerKind.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerMode.java index fe7e5c4..44d3f19 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerRadii.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerRadii.java index c6b894a..3905baa 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerRadii.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerRadii.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerSpec.java index fa53def..fd9c9be 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiCornerSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEdgeKind.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEdgeKind.java index 641a506..3f2b1cd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEdgeKind.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEdgeKind.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEdgeSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEdgeSpec.java index ff0ad32..29f6698 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEdgeSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEdgeSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEffectKind.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEffectKind.java index 505649e..87a3f21 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEffectKind.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEffectKind.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEffectSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEffectSpec.java index cb10eb1..b9871a7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEffectSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiEffectSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiMeshGeometry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiMeshGeometry.java index 7ec9c20..437cda8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiMeshGeometry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiMeshGeometry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaint.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaint.java index 5f51b28..fdc47d0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaint.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaint.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaintKind.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaintKind.java index 2754362..15e5bb0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaintKind.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaintKind.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaints.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaints.java index 5e59470..765ef5a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaints.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPaints.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPathCap.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPathCap.java index 7aafaf4..0e21220 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPathCap.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPathCap.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPathJoin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPathJoin.java index 5159c86..a4f8a91 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPathJoin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiPathJoin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiRect.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiRect.java index 50fec09..37aaa70 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiRect.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiRect.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShape.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShape.java index 4c42117..5cc180c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShape.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShape.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapeKind.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapeKind.java index 1f4f7ba..349b920 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapeKind.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapeKind.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapeShaderParams.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapeShaderParams.java index 8b1f31d..041ce95 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapeShaderParams.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapeShaderParams.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapes.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapes.java index 6287034..a54e52b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapes.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiShapes.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiStroke.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiStroke.java index f593dda..6748b4f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiStroke.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/draw/UiStroke.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiAction.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiAction.java index 8a47cda..4a08299 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiAction.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiAction.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionContext.java index e48e54d..c222ada 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionRef.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionRef.java index b3313d9..0e13862 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionRef.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionRef.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionRegistry.java index 0bfd924..ee237aa 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/action/UiActionRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiAnimationSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiAnimationSpec.java index 10f7157..ba57d15 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiAnimationSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiAnimationSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiAnimationState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiAnimationState.java index ea93ebf..43ae2ed 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiAnimationState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiAnimationState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiEasing.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiEasing.java index 739b9b3..9cc865e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiEasing.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/animation/UiEasing.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetKind.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetKind.java index 727416b..dd6a8aa 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetKind.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetKind.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetProvider.java index 0df6c4b..c8017a0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetProvider.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetProvider.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetRef.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetRef.java index bfc2d65..7967a4e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetRef.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetRef.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetRegistry.java index ef017bc..61949c3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetResolver.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetResolver.java index 6bbe473..e96586b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetResolver.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/asset/UiAssetResolver.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiBounds.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiBounds.java index c346996..3460bfa 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiBounds.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiBounds.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiComponentFactory.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiComponentFactory.java index 35f7a99..e0447ac 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiComponentFactory.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiComponentFactory.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiComponentRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiComponentRegistry.java index 4978dff..e395fad 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiComponentRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiComponentRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiDocument.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiDocument.java index 8dbeded..6cc304d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiDocument.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiDocument.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiLifecycle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiLifecycle.java index 60d3e32..a126a10 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiLifecycle.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiLifecycle.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNode.java index bc280b6..8df023b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNodeSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNodeSpec.java index 7606631..06fe33b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNodeSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNodeSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNodeType.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNodeType.java index bb89886..67303a5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNodeType.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiNodeType.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiProps.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiProps.java index 4dd6dd1..53daf57 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiProps.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiProps.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiRuntime.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiRuntime.java index f8722e3..b5e7f79 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiRuntime.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiRuntime.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiRuntimeException.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiRuntimeException.java index cac82dc..2fd88c0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiRuntimeException.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiRuntimeException.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiState.java index 18ebe2d..38f8fb4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/core/UiState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiPerfCounters.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiPerfCounters.java index c797cee..2164031 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiPerfCounters.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiPerfCounters.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiRuntimeDiagnostics.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiRuntimeDiagnostics.java index 2980151..865b666 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiRuntimeDiagnostics.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiRuntimeDiagnostics.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiTreeDumper.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiTreeDumper.java index f301eb0..c5c974c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiTreeDumper.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/debug/UiTreeDumper.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/error/UiErrorPolicy.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/error/UiErrorPolicy.java index 07b73a9..ca14d64 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/error/UiErrorPolicy.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/error/UiErrorPolicy.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiCursorManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiCursorManager.java index 5888fa2..a751d51 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiCursorManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiCursorManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiFocusManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiFocusManager.java index 4aeab78..176d0b8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiFocusManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiFocusManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiHitResult.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiHitResult.java index 3e863a4..dc4beff 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiHitResult.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiHitResult.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiHitTester.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiHitTester.java index 2a2cd86..62b1432 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiHitTester.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiHitTester.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiInputDispatcher.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiInputDispatcher.java index e209f46..baae8bf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiInputDispatcher.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiInputDispatcher.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiInputState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiInputState.java index 183a304..a5f7158 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiInputState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiInputState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiKeyboardEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiKeyboardEvent.java index 85ff144..31ab90a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiKeyboardEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiKeyboardEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiPointerEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiPointerEvent.java index 7e34aef..18c8ef7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiPointerEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiPointerEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiScrollEvent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiScrollEvent.java index 5bf08e5..54729ba 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiScrollEvent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/input/UiScrollEvent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/layout/UiLayoutEngine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/layout/UiLayoutEngine.java index 6ef8294..1f5b63d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/layout/UiLayoutEngine.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/layout/UiLayoutEngine.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiDiffStats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiDiffStats.java index 9136f12..fc6be58 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiDiffStats.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiDiffStats.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiKeyPath.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiKeyPath.java index 78f9dbd..0fa5ffc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiKeyPath.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiKeyPath.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiNodeMatcher.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiNodeMatcher.java index 382694d..c0f3c2a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiNodeMatcher.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiNodeMatcher.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiReconcileContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiReconcileContext.java index 1944dab..8ec3b4e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiReconcileContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiReconcileContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiReconciler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiReconciler.java index 641415d..a2d1d17 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiReconciler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/reconcile/UiReconciler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiBlendSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiBlendSpec.java index b0e61f6..71ac1c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiBlendSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiBlendSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiClipStack.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiClipStack.java index 015d3ea..467b765 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiClipStack.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiClipStack.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiImageRendererBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiImageRendererBridge.java index 939ad64..8f62554 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiImageRendererBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiImageRendererBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiItemRendererBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiItemRendererBridge.java index 38d7a2d..f695544 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiItemRendererBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiItemRendererBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiPrimitiveRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiPrimitiveRenderer.java index fba95dc..5f92b54 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiPrimitiveRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiPrimitiveRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiProjectionMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiProjectionMode.java index 2a64b12..b4396df 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiProjectionMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiProjectionMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiRenderContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiRenderContext.java index b35d53c..3abd2a5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiRenderContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiRenderContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiRenderer.java index 884bad3..1b6192a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiTextEffectRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiTextEffectRenderer.java index ccc05f1..c84aba1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiTextEffectRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiTextEffectRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiTextRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiTextRenderer.java index b351b42..fafe879 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiTextRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/render/UiTextRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/CachedUiScriptRuntime.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/CachedUiScriptRuntime.java index 4583f57..365c0fc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/CachedUiScriptRuntime.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/CachedUiScriptRuntime.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetNativeResourceLoader.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetNativeResourceLoader.java index 49b6ae0..731c1ee 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetNativeResourceLoader.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetNativeResourceLoader.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,7 +20,7 @@ import java.nio.file.StandardCopyOption; import java.util.concurrent.atomic.AtomicBoolean; /** - * Loads Javet V8 natives from Combatant resources when they are bundled under + * Loads Javet V8 natives from LoVisual resources when they are bundled under * /javet/natives. If the resource bundle is not present, Javet's own classpath * loader is left untouched so dev-runtime native jars can still work. */ @@ -36,7 +36,7 @@ enum JavetNativeResourceLoader { if (libFileName == null || !resourceExists(libFileName)) { return; } - JavetLibLoader.setLibLoadingListener(new CombatantJavetLibLoadingListener(libFileName)); + JavetLibLoader.setLibLoadingListener(new LoVisualJavetLibLoadingListener(libFileName)); } private static String detectLibFileName() { @@ -55,11 +55,11 @@ enum JavetNativeResourceLoader { } } - private static final class CombatantJavetLibLoadingListener implements IJavetLibLoadingListener { + private static final class LoVisualJavetLibLoadingListener implements IJavetLibLoadingListener { private final String libFileName; private volatile File libPath; - private CombatantJavetLibLoadingListener(String libFileName) { + private LoVisualJavetLibLoadingListener(String libFileName) { this.libFileName = libFileName; } @@ -97,7 +97,7 @@ enum JavetNativeResourceLoader { if (stream == null) { throw new UnsatisfiedLinkError("Missing Javet native resource: " + resource); } - Path dir = Files.createTempDirectory("combatant-javet-v8-"); + Path dir = Files.createTempDirectory("lovisual-javet-v8-"); Path target = dir.resolve(libFileName); Files.copy(stream, target, StandardCopyOption.REPLACE_EXISTING); target.toFile().deleteOnExit(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetUiScriptEngine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetUiScriptEngine.java index ad30a7c..d2494c3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetUiScriptEngine.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetUiScriptEngine.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -26,12 +26,12 @@ final class JavetUiScriptEngine implements UiScriptEngine { log() {}, info() {}, warn() {}, error() {}, debug() {}, trace() {} }; globalThis.__ui_default = undefined; - globalThis.__combatant_render = undefined; - globalThis.__combatant_render_ready = false; + globalThis.__lovisual_render = undefined; + globalThis.__lovisual_render_ready = false; """; private static final String RESOLVE_RENDER_SOURCE = """ - globalThis.__combatant_render = (() => { + globalThis.__lovisual_render = (() => { const direct = globalThis.render; if (typeof direct === "function") return direct; @@ -50,7 +50,7 @@ final class JavetUiScriptEngine implements UiScriptEngine { if (exports && typeof exports.buildTemplate === "function") return exports.buildTemplate.bind(exports); return undefined; })(); - globalThis.__combatant_render_ready = typeof globalThis.__combatant_render === "function"; + globalThis.__lovisual_render_ready = typeof globalThis.__lovisual_render === "function"; """; private final UiScriptObjectConverter converter = new UiScriptObjectConverter(); @@ -66,11 +66,11 @@ final class JavetUiScriptEngine implements UiScriptEngine { try { prepare(module); - if (!runtime.getGlobalObject().getBoolean("__combatant_render_ready")) { + if (!runtime.getGlobalObject().getBoolean("__lovisual_render_ready")) { return UiScriptRenderResult.failed(new UiScriptRuntimeError(module.getId(), "render", "Script module does not export render(ctx).", null)); } - Object raw = runtime.getGlobalObject().invokeObject("__combatant_render", contextMap(context)); + Object raw = runtime.getGlobalObject().invokeObject("__lovisual_render", contextMap(context)); UiNodeSpec root = converter.convert(raw); return UiScriptRenderResult.ok(root); } catch (Throwable t) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiBoundsPatchSet.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiBoundsPatchSet.java index 74f7862..50f9cb2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiBoundsPatchSet.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiBoundsPatchSet.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptColor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptColor.java index f88406e..6026d45 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptColor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptColor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptComponent.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptComponent.java index e2f92a7..9d037eb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptComponent.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptComponent.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptEngine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptEngine.java index 9404ad4..d8d42ac 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptEngine.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptEngine.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptEngineProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptEngineProvider.java index 03c1e72..be7f505 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptEngineProvider.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptEngineProvider.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModule.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModule.java index cc79670..1b99e8e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModule.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModule.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,7 +15,7 @@ public record UiScriptModule(UiScriptModuleId id, UiScriptSourceKind sourceKind, } public UiScriptModule { - id = id != null ? id : new UiScriptModuleId("combatant", "main"); + id = id != null ? id : new UiScriptModuleId("lovisual", "main"); sourceKind = sourceKind != null ? sourceKind : UiScriptSourceKind.fromPath(id.path()); source = source != null ? source : ""; metadata = metadata != null ? metadata : UiProps.EMPTY; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleHandle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleHandle.java index ca8b3db..5a56caa 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleHandle.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleHandle.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -29,7 +29,7 @@ public final class UiScriptModuleHandle { } public UiScriptModuleHandle(UiScriptModuleId id, UiScriptModuleLoader loader) { - this.id = id != null ? id : UiScriptModuleId.of("combatant:main"); + this.id = id != null ? id : UiScriptModuleId.of("lovisual:main"); this.loader = loader != null ? loader : new UiScriptModuleLoader(); DebugLog.renderThread("[UI Scripts] handle init id=%s", this.id); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleId.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleId.java index 8fed036..d7fef10 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleId.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleId.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,17 +17,17 @@ public record UiScriptModuleId(String namespace, String path) { public static UiScriptModuleId of(String raw) { if (raw == null || raw.isBlank()) { - return new UiScriptModuleId("combatant", "main"); + return new UiScriptModuleId("lovisual", "main"); } int colon = raw.indexOf(':'); if (colon < 0) { - return new UiScriptModuleId("combatant", raw); + return new UiScriptModuleId("lovisual", raw); } return new UiScriptModuleId(raw.substring(0, colon), raw.substring(colon + 1)); } private static String normalizeNamespace(String raw) { - if (raw == null || raw.isBlank()) return "combatant"; + if (raw == null || raw.isBlank()) return "lovisual"; return raw.trim().toLowerCase(Locale.ROOT); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleLoader.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleLoader.java index 666cc2e..d4121f5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleLoader.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleLoader.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -129,14 +129,14 @@ public final class UiScriptModuleLoader { int slash = base.lastIndexOf('/'); String dir = slash >= 0 ? base.substring(0, slash + 1) : ""; java.nio.file.Path resolved = java.nio.file.Path.of(dir).resolve(normalized).normalize(); - return new UiScriptModuleId(owner != null ? owner.namespace() : "combatant", resolved.toString().replace('\\', '/')); + return new UiScriptModuleId(owner != null ? owner.namespace() : "lovisual", resolved.toString().replace('\\', '/')); } public UiScriptModule load(ResourceManager manager, UiScriptModuleId id) throws IOException { if (manager == null) { throw new IOException("ResourceManager is null."); } - UiScriptModuleId moduleId = id != null ? id : new UiScriptModuleId("combatant", "main"); + UiScriptModuleId moduleId = id != null ? id : new UiScriptModuleId("lovisual", "main"); Loaded loaded = loadExisting(manager, moduleId); return new UiScriptModule( loaded.getId(), diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleRegistry.java index b11e463..1e87fb3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,7 +16,7 @@ public final class UiScriptModuleRegistry { private final Map handles = new LinkedHashMap<>(); public UiScriptModuleHandle handle(UiScriptModuleId id) { - UiScriptModuleId moduleId = id != null ? id : UiScriptModuleId.of("combatant:main"); + UiScriptModuleId moduleId = id != null ? id : UiScriptModuleId.of("lovisual:main"); String key = moduleId.toString(); UiScriptModuleHandle existing = handles.get(key); if (existing != null) return existing; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleTransform.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleTransform.java index 98f27c7..c10e534 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleTransform.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptModuleTransform.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptObjectConverter.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptObjectConverter.java index c6fca60..ed8ae63 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptObjectConverter.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptObjectConverter.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptPatchSet.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptPatchSet.java index 37ff691..fb75043 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptPatchSet.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptPatchSet.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptProps.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptProps.java index 2c0eb94..1967a41 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptProps.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptProps.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRenderContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRenderContext.java index cb84fd2..5787df0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRenderContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRenderContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRenderResult.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRenderResult.java index c44156b..1a2e6a6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRenderResult.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRenderResult.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRuntimeError.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRuntimeError.java index cf207c7..14a7d64 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRuntimeError.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRuntimeError.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRuntimeSource.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRuntimeSource.java index 723145a..18e0230 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRuntimeSource.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptRuntimeSource.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptSourceKind.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptSourceKind.java index 00cebfd..4488a90 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptSourceKind.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiScriptSourceKind.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiTypeScriptStripper.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiTypeScriptStripper.java index 6125c25..a49540c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiTypeScriptStripper.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/UiTypeScriptStripper.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiAlign.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiAlign.java index 880d69c..89591d7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiAlign.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiAlign.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiColor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiColor.java index 5c5a3c9..9bfdc7d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiColor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiColor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiJustify.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiJustify.java index e6c1905..60820d1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiJustify.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiJustify.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiOverflow.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiOverflow.java index 012cd9d..7342c6b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiOverflow.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiOverflow.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiResolvedStyle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiResolvedStyle.java index 5610b73..28e9a50 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiResolvedStyle.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiResolvedStyle.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyle.java index 77e965d..369df8d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyle.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyle.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleCache.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleCache.java index 3628b9c..9ced151 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleCache.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleCache.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleParser.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleParser.java index 99cd7e4..dffd488 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleParser.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleParser.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleResolver.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleResolver.java index d245594..97f0350 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleResolver.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleResolver.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleToken.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleToken.java index 8cdf0a2..55e999a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleToken.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiStyleToken.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiTheme.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiTheme.java index 2190bf2..115d783 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiTheme.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiTheme.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiThemeRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiThemeRegistry.java index d117cdf..41e60ce 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiThemeRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/style/UiThemeRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/FullscreenDrawCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/FullscreenDrawCommand.java index 70add46..d5d4da0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/FullscreenDrawCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/FullscreenDrawCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/GpuMeshHandle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/GpuMeshHandle.java index 38e35c7..de200c0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/GpuMeshHandle.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/GpuMeshHandle.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,7 +13,7 @@ import com.mojang.blaze3d.systems.RenderPass; import org.jetbrains.annotations.Nullable; /** - * GPU mesh range prepared by CombatantRHI. + * GPU mesh range prepared by LoVisualRHI. */ public record GpuMeshHandle(GpuBuffer vertexBuffer, GpuBuffer indexBuffer, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/CombatantRhi.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/LoVisualRhi.java similarity index 91% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/CombatantRhi.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/LoVisualRhi.java index 033dd4a..a6c8c22 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/CombatantRhi.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/LoVisualRhi.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,7 +16,7 @@ import dev.loki.lovisual.render.engine.rhi.resource.RenderResourceManager; import dev.loki.lovisual.render.engine.rhi.state.PipelineStateBackend; import dev.loki.lovisual.render.engine.rhi.upload.DynamicMeshBackend; -public interface CombatantRhi extends AutoCloseable { +public interface LoVisualRhi extends AutoCloseable { DynamicMeshBackend dynamicMeshes(); FullscreenBackend fullscreen(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/MeshOwnership.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/MeshOwnership.java index ec99ea5..4f36fd5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/MeshOwnership.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/MeshOwnership.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiDrawCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiDrawCommand.java index b26da71..58066b0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiDrawCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiDrawCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiSamplerBinding.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiSamplerBinding.java index fd252a6..427877d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiSamplerBinding.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiSamplerBinding.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiStats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiStats.java index 53777d8..eaec982 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiStats.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiStats.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiStatsSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiStatsSnapshot.java index 08b7577..84fcac4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiStatsSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiStatsSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiUniformBinding.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiUniformBinding.java index dee2daa..5c4f91e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiUniformBinding.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/RhiUniformBinding.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/SodiumGlBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/SodiumGlBackend.java index e25d5ce..1e05a27 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/SodiumGlBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/SodiumGlBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -43,7 +43,7 @@ import java.util.OptionalInt; * Current production RHI backend for the Sodium/GL era. * Sodium is the priority integration target; Mojang GPU objects are used as the compatibility surface where needed. */ -public final class SodiumGlBackend implements CombatantRhi { +public final class SodiumGlBackend implements LoVisualRhi { private final RhiStats stats = new RhiStats(); private final Blaze3dDynamicMeshBackend dynamicMeshes = new Blaze3dDynamicMeshBackend(stats); private final Blaze3dFullscreenBackend fullscreen = new Blaze3dFullscreenBackend(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/GlBackendAccess.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/GlBackendAccess.java index ea757d0..3d866b2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/GlBackendAccess.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/GlBackendAccess.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -22,7 +22,7 @@ public enum GlBackendAccess { if (!(device instanceof GpuDeviceAccessor accessor)) { return null; } - GpuDeviceBackend backend = accessor.combatant$getBackend(); + GpuDeviceBackend backend = accessor.lovisual$getBackend(); return backend instanceof IGlBackendInfo glBackend ? glBackend : null; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/clip/GlStencilFramebufferSupport.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/clip/GlStencilFramebufferSupport.java index 9a03e14..8e22090 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/clip/GlStencilFramebufferSupport.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/clip/GlStencilFramebufferSupport.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -72,8 +72,8 @@ final class GlStencilFramebufferSupport { } depthAttachment = glDepthView; } - return backend.combatant$frameBufferCache().getFbo( - backend.combatant$directStateAccess(), + return backend.lovisual$frameBufferCache().getFbo( + backend.lovisual$directStateAccess(), List.of(colorView), depthAttachment ); @@ -203,7 +203,7 @@ final class GlStencilFramebufferSupport { if (framebuffer == null) return fail("main framebuffer is null"); /* - * UI batches in Combatant are rendered into the main color target without passing the + * UI batches in LoVisual are rendered into the main color target without passing the * framebuffer depth attachment to the render pass. GlTextureView keeps separate FBOs for * (color, null-depth) and (color, depthTexture). The shape-clip mask must be prepared and * cleared on the same color-only FBO that Renderer2D will use; otherwise the mask is written diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/clip/GlStencilShapeClipBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/clip/GlStencilShapeClipBackend.java index 0dbc2f0..bcecf83 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/clip/GlStencilShapeClipBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/clip/GlStencilShapeClipBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/state/SodiumGlPipelineStateBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/state/SodiumGlPipelineStateBackend.java index b451cf8..c74eec1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/state/SodiumGlPipelineStateBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/gl/state/SodiumGlPipelineStateBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -32,7 +32,7 @@ public final class SodiumGlPipelineStateBackend implements PipelineStateBackend } private static void applyLineSmooth(RenderPipeline pipeline) { - boolean enabled = pipeline instanceof IRenderPipeline combatantPipeline && combatantPipeline.combatant$getLineSmooth(); + boolean enabled = pipeline instanceof IRenderPipeline lovisualPipeline && lovisualPipeline.lovisual$getLineSmooth(); if (enabled) { glEnable(GL_LINE_SMOOTH); // Wide lines are expanded into geometry before draw submission. Keep native GL lines at 1px: relying @@ -55,8 +55,8 @@ public final class SodiumGlPipelineStateBackend implements PipelineStateBackend msaa.applyPipelineState(pipeline); ShapeClipRenderPassContract contract = ShapeClipRenderPassContract.NONE; - if (pipeline instanceof IRenderPipeline combatantPipeline) { - contract = combatantPipeline.combatant$getShapeClipContract(); + if (pipeline instanceof IRenderPipeline lovisualPipeline) { + contract = lovisualPipeline.lovisual$getShapeClipContract(); } clip.bindPipeline(pipeline, contract); clip.applyNativeState(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/CombatantVulkanBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/LoVisualVulkanBackend.java similarity index 97% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/CombatantVulkanBackend.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/LoVisualVulkanBackend.java index bbb701d..4d769eb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/CombatantVulkanBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/LoVisualVulkanBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -41,9 +41,9 @@ import java.util.OptionalDouble; import java.util.OptionalInt; /** - * Combatant RHI backend for Mojang's Vulkan renderer. + * LoVisual RHI backend for Mojang's Vulkan renderer. */ -public final class CombatantVulkanBackend implements CombatantRhi { +public final class LoVisualVulkanBackend implements LoVisualRhi { private final RhiStats stats = new RhiStats(); private final Blaze3dDynamicMeshBackend dynamicMeshes = new Blaze3dDynamicMeshBackend(stats); private final Blaze3dFullscreenBackend fullscreen = new Blaze3dFullscreenBackend(); @@ -54,7 +54,7 @@ public final class CombatantVulkanBackend implements CombatantRhi { private final RenderPipelineRegistry pipelines = RenderPipelineRegistry.global(); private final RenderResourceManager resources = new RenderResourceManager(); - public CombatantVulkanBackend() { + public LoVisualVulkanBackend() { VulkanRenderStateBridge.setVulkanBackendActive(true); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanShapeClipBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanShapeClipBackend.java index 8a791bb..171e96d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanShapeClipBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanShapeClipBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,7 +16,7 @@ import dev.loki.lovisual.render.engine.rhi.clip.ShapeClipRenderPassContract; import dev.loki.lovisual.util.logging.DebugLog; /** - * Vulkan implementation of Combatant shape clipping using an injected S8 dynamic-rendering attachment. + * Vulkan implementation of LoVisual shape clipping using an injected S8 dynamic-rendering attachment. */ public final class VulkanShapeClipBackend implements ShapeClipBackend, AutoCloseable { private final VulkanStencilAttachmentManager attachments = new VulkanStencilAttachmentManager(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanShapeClipBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanShapeClipBridge.java index 0b9bb6a..0bb9323 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanShapeClipBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanShapeClipBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,7 +13,7 @@ import org.jetbrains.annotations.Nullable; import dev.loki.lovisual.render.engine.rhi.backend.vulkan.util.VulkanRenderStateBridge; /** - * Static entry used by Vulkan mixins without reaching through CombatantRenderSystem repeatedly. + * Static entry used by Vulkan mixins without reaching through LoVisualRenderSystem repeatedly. */ public enum VulkanShapeClipBridge { ; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanStencilAttachmentManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanStencilAttachmentManager.java index 0761eb2..afd2c28 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanStencilAttachmentManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/clip/VulkanStencilAttachmentManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -40,7 +40,7 @@ public final class VulkanStencilAttachmentManager implements AutoCloseable { } private static Attachment createAttachment(String ownerLabel, int width, int height, int samples) { - String label = "combatant-vk-stencil:" + (ownerLabel == null ? "unnamed" : ownerLabel); + String label = "lovisual-vk-stencil:" + (ownerLabel == null ? "unnamed" : ownerLabel); GpuTexture texture = VulkanRenderStateBridge.withTextureSamples(samples, () -> RenderSystem.getDevice().createTexture( label, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/msaa/VulkanMsaaControl.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/msaa/VulkanMsaaControl.java index 268d206..c8961bf 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/msaa/VulkanMsaaControl.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/msaa/VulkanMsaaControl.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -21,7 +21,7 @@ import dev.loki.lovisual.render.engine.rhi.msaa.MsaaControl; import dev.loki.lovisual.util.logging.DebugLog; /** - * Vulkan implementation of Combatant MSAA allocation and dynamic-rendering resolve. + * Vulkan implementation of LoVisual MSAA allocation and dynamic-rendering resolve. */ public final class VulkanMsaaControl implements MsaaControl { @@ -45,7 +45,7 @@ public final class VulkanMsaaControl implements MsaaControl { RenderSystem.getDevice().createTexture(label, usage, format, width, height, 1, 1) ); if (texture instanceof IMsaaTexture msaaTexture) { - msaaTexture.combatant$setSamples(finalSamples); + msaaTexture.lovisual$setSamples(finalSamples); } return texture; } @@ -123,7 +123,7 @@ public final class VulkanMsaaControl implements MsaaControl { try { VulkanMsaaResolveBridge.beginDepthSnapshot(src, dst); - RenderPassDescriptor descriptor = RenderPassDescriptor.create(() -> "Combatant MSAA depth snapshot resolve") + RenderPassDescriptor descriptor = RenderPassDescriptor.create(() -> "LoVisual MSAA depth snapshot resolve") .withDepthAttachment(src) .withRenderArea(new RenderPass.RenderArea(0, 0, src.getWidth(0), src.getHeight(0))); try (RenderPass ignored = RenderSystem.getDevice().createCommandEncoder().createRenderPass(descriptor)) { @@ -147,7 +147,7 @@ public final class VulkanMsaaControl implements MsaaControl { if (!validSnapshotPair(src, dst)) return false; try { VulkanMsaaResolveBridge.beginColorSnapshot(src, dst); - RenderPassDescriptor descriptor = RenderPassDescriptor.create(() -> "Combatant MSAA color snapshot resolve") + RenderPassDescriptor descriptor = RenderPassDescriptor.create(() -> "LoVisual MSAA color snapshot resolve") .withColorAttachment(src) .withRenderArea(new RenderPass.RenderArea(0, 0, src.getWidth(0), src.getHeight(0))); try (RenderPass ignored = RenderSystem.getDevice().createCommandEncoder().createRenderPass(descriptor)) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/msaa/VulkanMsaaResolveBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/msaa/VulkanMsaaResolveBridge.java index 58dee1d..6bcd591 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/msaa/VulkanMsaaResolveBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/msaa/VulkanMsaaResolveBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -26,7 +26,7 @@ import java.util.Set; import static org.lwjgl.vulkan.VK12.*; /** - * Connects Combatant's multisampled world target to Mojang's single-sampled main target. + * Connects LoVisual's multisampled world target to Mojang's single-sampled main target. * *

The resolve is described on the same {@link VkRenderingAttachmentInfo} objects that Mojang * submits to dynamic rendering. No standalone resolve command is recorded, so color and depth @@ -223,7 +223,7 @@ public enum VulkanMsaaResolveBridge { if (source == null || destination == null) { throw new IllegalStateException("Missing " + aspect + " resolve attachment"); } - if (!(source instanceof IMsaaTexture msaa) || !msaa.combatant$isMsaa()) { + if (!(source instanceof IMsaaTexture msaa) || !msaa.lovisual$isMsaa()) { throw new IllegalStateException("Resolve source is not multisampled: " + source.getLabel()); } validateTexturePair(source, destination); @@ -258,7 +258,7 @@ public enum VulkanMsaaResolveBridge { + ", destination=" + destination.texture().getFormat()); } int destinationSamples = destination.texture() instanceof IMsaaTexture msaa - ? msaa.combatant$getSamples() + ? msaa.lovisual$getSamples() : 1; if (destinationSamples != 1) { throw new IllegalStateException("MSAA resolve destination must be single-sampled, got " + destinationSamples + "x"); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/state/VulkanPipelineStateBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/state/VulkanPipelineStateBackend.java index a1b28fb..511efce 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/state/VulkanPipelineStateBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/state/VulkanPipelineStateBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -31,8 +31,8 @@ public final class VulkanPipelineStateBackend implements PipelineStateBackend { msaa.applyPipelineState(pipeline); ShapeClipRenderPassContract contract = ShapeClipRenderPassContract.NONE; - if (pipeline instanceof IRenderPipeline combatantPipeline) { - contract = combatantPipeline.combatant$getShapeClipContract(); + if (pipeline instanceof IRenderPipeline lovisualPipeline) { + contract = lovisualPipeline.lovisual$getShapeClipContract(); } clip.bindPipeline(pipeline, contract); clip.applyNativeState(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/util/VulkanRenderStateBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/util/VulkanRenderStateBridge.java index ec212b7..e70989e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/util/VulkanRenderStateBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/util/VulkanRenderStateBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -21,7 +21,7 @@ import java.util.List; import static org.lwjgl.vulkan.VK12.*; /** - * Vulkan-side fixed pipeline state bridge for Combatant's GL-era dynamic state. + * Vulkan-side fixed pipeline state bridge for LoVisual's GL-era dynamic state. * *

Important Vulkan rule: do not destroy/recreate cached VkPipelines while the current * command buffer may already reference them. Stencil modes are therefore represented through a @@ -259,16 +259,16 @@ public enum VulkanRenderStateBridge { if (attachment == null || attachment.textureView() == null || attachment.textureView().texture() == null) { return 0; } - if (attachment.textureView().texture() instanceof IMsaaTexture texture && texture.combatant$isMsaa()) { - return Math.max(1, texture.combatant$getSamples()); + if (attachment.textureView().texture() instanceof IMsaaTexture texture && texture.lovisual$isMsaa()) { + return Math.max(1, texture.lovisual$getSamples()); } return 1; } public static int samplesFor(@Nullable GpuTextureView view) { if (view == null || view.texture() == null) return 1; - if (view.texture() instanceof IMsaaTexture texture && texture.combatant$isMsaa()) { - return Math.max(1, texture.combatant$getSamples()); + if (view.texture() instanceof IMsaaTexture texture && texture.lovisual$isMsaa()) { + return Math.max(1, texture.lovisual$getSamples()); } return 1; } @@ -329,8 +329,8 @@ public enum VulkanRenderStateBridge { public static boolean pipelineParticipatesInShapeClip(RenderPipeline pipeline) { if (forceDisableStencil()) return false; - if (!(pipeline instanceof IRenderPipeline combatantPipeline)) return false; - ShapeClipRenderPassContract contract = combatantPipeline.combatant$getShapeClipContract(); + if (!(pipeline instanceof IRenderPipeline lovisualPipeline)) return false; + ShapeClipRenderPassContract contract = lovisualPipeline.lovisual$getShapeClipContract(); return contract != null && contract.participates(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/util/VulkanRuntimeGuards.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/util/VulkanRuntimeGuards.java index 74bdb59..105f168 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/util/VulkanRuntimeGuards.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/util/VulkanRuntimeGuards.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,8 +16,8 @@ package dev.loki.lovisual.render.engine.rhi.backend.vulkan.util; public enum VulkanRuntimeGuards { ; - public static final boolean FORCE_DISABLE_VULKAN_DEBUG_LABELS = bool("combatant.vulkan.disableDebugLabels", true); - public static final boolean FORCE_DISABLE_VULKAN_CHECKPOINTS = bool("combatant.vulkan.disableCheckpoints", true); + public static final boolean FORCE_DISABLE_VULKAN_DEBUG_LABELS = bool("lovisual.vulkan.disableDebugLabels", true); + public static final boolean FORCE_DISABLE_VULKAN_CHECKPOINTS = bool("lovisual.vulkan.disableCheckpoints", true); private static boolean bool(String key, boolean fallback) { String value = System.getProperty(key); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/blit/Blaze3dTextureBlitter.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/blit/Blaze3dTextureBlitter.java index 87cc591..986de0c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/blit/Blaze3dTextureBlitter.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/blit/Blaze3dTextureBlitter.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/blit/TextureBlitter.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/blit/TextureBlitter.java index b6e200f..193ba33 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/blit/TextureBlitter.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/blit/TextureBlitter.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/clip/ShapeClipBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/clip/ShapeClipBackend.java index 06f2287..e1ce8d2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/clip/ShapeClipBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/clip/ShapeClipBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/clip/ShapeClipRenderPassContract.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/clip/ShapeClipRenderPassContract.java index 18e0947..02014e5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/clip/ShapeClipRenderPassContract.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/clip/ShapeClipRenderPassContract.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/fullscreen/Blaze3dFullscreenBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/fullscreen/Blaze3dFullscreenBackend.java index 53452e4..4f792d9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/fullscreen/Blaze3dFullscreenBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/fullscreen/Blaze3dFullscreenBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -39,8 +39,8 @@ public final class Blaze3dFullscreenBackend implements FullscreenBackend { indices.putInt(0).putInt(1).putInt(2).putInt(2).putInt(3).putInt(0); indices.flip(); - vertexBuffer = RenderSystem.getDevice().createBuffer(() -> "Combatant Fullscreen Quad VBO", GpuBuffer.USAGE_VERTEX, vertices); - indexBuffer = RenderSystem.getDevice().createBuffer(() -> "Combatant Fullscreen Quad IBO", GpuBuffer.USAGE_INDEX, indices); + vertexBuffer = RenderSystem.getDevice().createBuffer(() -> "LoVisual Fullscreen Quad VBO", GpuBuffer.USAGE_VERTEX, vertices); + indexBuffer = RenderSystem.getDevice().createBuffer(() -> "LoVisual Fullscreen Quad IBO", GpuBuffer.USAGE_INDEX, indices); quad = new GpuMeshHandle(vertexBuffer, indexBuffer, 0L, 0, 6, com.mojang.blaze3d.IndexType.INT, MeshOwnership.PERSISTENT); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/fullscreen/FullscreenBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/fullscreen/FullscreenBackend.java index 01a0ca8..c0c2b1c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/fullscreen/FullscreenBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/fullscreen/FullscreenBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/msaa/MsaaControl.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/msaa/MsaaControl.java index 11953e8..a3df9e8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/msaa/MsaaControl.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/msaa/MsaaControl.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/msaa/SodiumGlMsaaControl.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/msaa/SodiumGlMsaaControl.java index 4092906..4a0edfc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/msaa/SodiumGlMsaaControl.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/msaa/SodiumGlMsaaControl.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -60,7 +60,7 @@ public final class SodiumGlMsaaControl implements MsaaControl { } private static int textureId(GpuTexture texture) { - return texture instanceof IMsaaTexture glTexture ? glTexture.combatant$getGlId() : 0; + return texture instanceof IMsaaTexture glTexture ? glTexture.lovisual$getGlId() : 0; } @Override @@ -120,10 +120,10 @@ public final class SodiumGlMsaaControl implements MsaaControl { throw new IllegalStateException("GL backend disappeared while creating MSAA texture: " + label); } - var texture = GlTextureInvoker.combatant$create(usage, label, format, width, height, 1, 1, glId, backend.combatant$frameBufferCache()); + var texture = GlTextureInvoker.lovisual$create(usage, label, format, width, height, 1, 1, glId, backend.lovisual$frameBufferCache()); registerTexture(glId, actualSamples); if (texture instanceof IMsaaTexture msaa) { - msaa.combatant$setSamples(actualSamples); + msaa.lovisual$setSamples(actualSamples); } return texture; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/BlendPolicy.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/BlendPolicy.java index 601ab32..f725d7b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/BlendPolicy.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/BlendPolicy.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/CullPolicy.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/CullPolicy.java index 7620272..bad9aac 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/CullPolicy.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/CullPolicy.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/DepthPolicy.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/DepthPolicy.java index 839e6e5..cedb60b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/DepthPolicy.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/DepthPolicy.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/FogPolicy.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/FogPolicy.java index ce1d583..85f671f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/FogPolicy.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/FogPolicy.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,10 +10,10 @@ package dev.loki.lovisual.render.engine.rhi.pipeline; public enum FogPolicy { NONE, VANILLA, - COMBATANT, + LOVISUAL, SHADERPACK; public boolean requiresWorldFogUniform() { - return this == VANILLA || this == COMBATANT || this == SHADERPACK; + return this == VANILLA || this == LOVISUAL || this == SHADERPACK; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineDomain.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineDomain.java index 34c22b5..7043735 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineDomain.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineDomain.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineKey.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineKey.java index 79e1d63..03117e2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineKey.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineKey.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,25 +11,25 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import net.minecraft.resources.Identifier; /** - * Stable Combatant pipeline key. Native RenderPipeline identity is backend detail, not policy. + * Stable LoVisual pipeline key. Native RenderPipeline identity is backend detail, not policy. */ public record PipelineKey(String namespace, String path) { public PipelineKey { - namespace = namespace == null || namespace.isBlank() ? "combatant" : namespace; + namespace = namespace == null || namespace.isBlank() ? "lovisual" : namespace; path = path == null ? "unknown" : path; } public static PipelineKey of(String id) { - if (id == null || id.isBlank()) return new PipelineKey("combatant", "unknown"); + if (id == null || id.isBlank()) return new PipelineKey("lovisual", "unknown"); int colon = id.indexOf(':'); if (colon > 0 && colon < id.length() - 1) { return new PipelineKey(id.substring(0, colon), id.substring(colon + 1)); } - return new PipelineKey("combatant", id); + return new PipelineKey("lovisual", id); } public static PipelineKey of(Identifier id) { - if (id == null) return new PipelineKey("combatant", "unknown"); + if (id == null) return new PipelineKey("lovisual", "unknown"); return new PipelineKey(id.getNamespace(), id.getPath()); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineMetadata.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineMetadata.java index 4c63bcf..ae44c5c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineMetadata.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/PipelineMetadata.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/RenderPipelineRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/RenderPipelineRegistry.java index 104ddf9..9b6902b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/RenderPipelineRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/RenderPipelineRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -17,7 +17,7 @@ import java.util.LinkedHashMap; import java.util.Map; /** - * Central metadata registry for all Combatant render pipelines. + * Central metadata registry for all LoVisual render pipelines. */ public final class RenderPipelineRegistry { private static final RenderPipelineRegistry GLOBAL = new RenderPipelineRegistry(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/RenderPipelineSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/RenderPipelineSpec.java index adc1feb..9f42444 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/RenderPipelineSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/RenderPipelineSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/UniformLayoutSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/UniformLayoutSpec.java index 17d8f53..4ae74c5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/UniformLayoutSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/UniformLayoutSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/VertexLayoutSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/VertexLayoutSpec.java index 1c9dbb0..69a6f0f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/VertexLayoutSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/pipeline/VertexLayoutSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FrameResourceRetirementQueue.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FrameResourceRetirementQueue.java index 824123f..8d1ab3f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FrameResourceRetirementQueue.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FrameResourceRetirementQueue.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FramebufferDescriptor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FramebufferDescriptor.java index 85f35ef..1e86bf1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FramebufferDescriptor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FramebufferDescriptor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,7 +20,7 @@ public record FramebufferDescriptor( String owner ) { public FramebufferDescriptor { - name = name == null || name.isBlank() ? "combatant-framebuffer" : name; + name = name == null || name.isBlank() ? "lovisual-framebuffer" : name; width = Math.max(1, width); height = Math.max(1, height); owner = owner == null || owner.isBlank() ? "unknown" : owner; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FramebufferPool.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FramebufferPool.java index 48cddf8..64131f1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FramebufferPool.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/FramebufferPool.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/GlyphAtlasManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/GlyphAtlasManager.java index fe3135f..defe1a4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/GlyphAtlasManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/GlyphAtlasManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/GlyphAtlasPage.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/GlyphAtlasPage.java index 8fc8626..c850b06 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/GlyphAtlasPage.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/GlyphAtlasPage.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/RenderResourceManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/RenderResourceManager.java index e59ca33..0557ef6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/RenderResourceManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/RenderResourceManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import com.mojang.blaze3d.pipeline.TextureTarget; import com.mojang.blaze3d.textures.GpuTexture; /** - * Single lifecycle owner for Combatant render resources. + * Single lifecycle owner for LoVisual render resources. * Stage 11 rule: no subsystem should keep ad-hoc framebuffer/texture pools as the production path. */ public final class RenderResourceManager implements AutoCloseable { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/RenderResourceStatsSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/RenderResourceStatsSnapshot.java index 8a380f3..c9ffdea 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/RenderResourceStatsSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/RenderResourceStatsSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/ResourceLeakTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/ResourceLeakTracker.java index 74b2624..ed78c72 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/ResourceLeakTracker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/ResourceLeakTracker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/SamplerCache.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/SamplerCache.java index 62fe763..57e7961 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/SamplerCache.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/SamplerCache.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/TexturePool.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/TexturePool.java index 352f45b..56de362 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/TexturePool.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/resource/TexturePool.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/scissor/GlobalScissorState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/scissor/GlobalScissorState.java index 603408c..162c3d2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/scissor/GlobalScissorState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/scissor/GlobalScissorState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,7 +10,7 @@ package dev.loki.lovisual.render.engine.rhi.scissor; import com.mojang.blaze3d.systems.RenderPass; /** - * Backend-neutral pending scissor for Combatant immediate/RHI submissions. + * Backend-neutral pending scissor for LoVisual immediate/RHI submissions. * *

The stored rectangle uses the same framebuffer-space convention that * vanilla {@code GuiRenderer} passes to {@link RenderPass#enableScissor}: diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/state/PipelineStateBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/state/PipelineStateBackend.java index 249deb8..7ec0b60 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/state/PipelineStateBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/state/PipelineStateBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/FrameResource.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/FrameResource.java index e774dab..e973513 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/FrameResource.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/FrameResource.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/LegacyUniformFrameResource.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/LegacyUniformFrameResource.java index 1ea2c45..e4a74c8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/LegacyUniformFrameResource.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/LegacyUniformFrameResource.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.engine.rhi.uniform; /** - * Adapter for old DynamicUniformStorage owners while they are migrated into CombatantUniformAllocator. + * Adapter for old DynamicUniformStorage owners while they are migrated into LoVisualUniformAllocator. */ public final class LegacyUniformFrameResource implements FrameResource { private final String name; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/CombatantUniformAllocator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/LoVisualUniformAllocator.java similarity index 94% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/CombatantUniformAllocator.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/LoVisualUniformAllocator.java index ce5b1ce..c0709f6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/CombatantUniformAllocator.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/LoVisualUniformAllocator.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -22,16 +22,16 @@ import java.util.List; import java.util.Map; /** - * Single owner of Combatant dynamic uniform allocation. + * Single owner of LoVisual dynamic uniform allocation. * every *Uniforms class is only a std140 writer. This allocator owns one large dynamic uniform ring, * suballocates aligned slices, rotates once at frame boundary only if any uniform was written, and clears * all current slices centrally. */ -public final class CombatantUniformAllocator implements AutoCloseable { +public final class LoVisualUniformAllocator implements AutoCloseable { private static final int GPU_BUFFER_USAGE_MAP_WRITE = 130; - private static final boolean DEBUG_UNIFORMS = Boolean.getBoolean("combatant.render.debug.uniforms"); + private static final boolean DEBUG_UNIFORMS = Boolean.getBoolean("lovisual.render.debug.uniforms"); private static final int DEFAULT_CAPACITY_BYTES = 1024 * 1024; - private static final boolean STRICT_UNIFORM_READS = Boolean.getBoolean("combatant.rhi.strictUniforms"); + private static final boolean STRICT_UNIFORM_READS = Boolean.getBoolean("lovisual.rhi.strictUniforms"); private final Map streams = new HashMap<>(); private final List oldRings = new ArrayList<>(); @@ -44,7 +44,7 @@ public final class CombatantUniformAllocator implements AutoCloseable { private long frameId; private boolean usedThisFrame; - public CombatantUniformAllocator() { + public LoVisualUniformAllocator() { } private static int align(int value, int alignment) { @@ -222,10 +222,10 @@ public final class CombatantUniformAllocator implements AutoCloseable { alignment = resolveUniformOffsetAlignment(); capacityBytes = Mth.smallestEncompassingPowerOfTwo(align(requiredCapacityBytes, alignment)); if (DEBUG_UNIFORMS) { - DebugLog.error("[CombatantRHI] uniform ring alignment=" + alignment + " capacity=" + capacityBytes + DebugLog.error("[LoVisualRHI] uniform ring alignment=" + alignment + " capacity=" + capacityBytes + " backend=" + RenderSystem.getDevice().getDeviceInfo().backendName()); } - ring = new MappableRingBuffer(() -> "Combatant - Unified Uniform Ring", GPU_BUFFER_USAGE_MAP_WRITE, capacityBytes); + ring = new MappableRingBuffer(() -> "LoVisual - Unified Uniform Ring", GPU_BUFFER_USAGE_MAP_WRITE, capacityBytes); stats.ringCapacityBytes(capacityBytes); } @@ -237,7 +237,7 @@ public final class CombatantUniformAllocator implements AutoCloseable { oldRings.add(ring); capacityBytes = newCapacity; cursorBytes = 0; - ring = new MappableRingBuffer(() -> "Combatant - Unified Uniform Ring", GPU_BUFFER_USAGE_MAP_WRITE, capacityBytes); + ring = new MappableRingBuffer(() -> "LoVisual - Unified Uniform Ring", GPU_BUFFER_USAGE_MAP_WRITE, capacityBytes); stats.ringGrow(); stats.ringCapacityBytes(capacityBytes); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/UniformAllocatorStats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/UniformAllocatorStats.java index aab25ea..ba11b47 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/UniformAllocatorStats.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/UniformAllocatorStats.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/UniformAllocatorStatsSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/UniformAllocatorStatsSnapshot.java index 01f6249..8c2767e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/UniformAllocatorStatsSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/uniform/UniformAllocatorStatsSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dDynamicMeshBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dDynamicMeshBackend.java index 4a18717..7f198ff 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dDynamicMeshBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dDynamicMeshBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -33,10 +33,10 @@ import java.util.List; * - immediate upload is disabled by default and exists only as an explicit emergency switch. */ public final class Blaze3dDynamicMeshBackend implements DynamicMeshBackend { - private static final int DEFAULT_VERTEX_ARENA_BYTES = Integer.getInteger("combatant.rhi.vertexArenaBytes", 32 * 1024 * 1024); - private static final int DEFAULT_INDEX_ARENA_BYTES = Integer.getInteger("combatant.rhi.indexArenaBytes", 8 * 1024 * 1024); - private static final int DEFAULT_PERSISTENT_ARENAS = Integer.getInteger("combatant.rhi.meshArenas", 3); - private static final boolean ALLOW_IMMEDIATE_FALLBACK = Boolean.getBoolean("combatant.rhi.allowImmediateFallback"); + private static final int DEFAULT_VERTEX_ARENA_BYTES = Integer.getInteger("lovisual.rhi.vertexArenaBytes", 32 * 1024 * 1024); + private static final int DEFAULT_INDEX_ARENA_BYTES = Integer.getInteger("lovisual.rhi.indexArenaBytes", 8 * 1024 * 1024); + private static final int DEFAULT_PERSISTENT_ARENAS = Integer.getInteger("lovisual.rhi.meshArenas", 3); + private static final boolean ALLOW_IMMEDIATE_FALLBACK = Boolean.getBoolean("lovisual.rhi.allowImmediateFallback"); private final RhiStats stats; private final List persistentArenas = new ArrayList<>(); @@ -101,7 +101,7 @@ public final class Blaze3dDynamicMeshBackend implements DynamicMeshBackend { int arenaCount = Math.max(2, DEFAULT_PERSISTENT_ARENAS); for (int i = 0; i < arenaCount; i++) { persistentArenas.add(new Blaze3dMeshArena( - "Combatant RHI Dynamic Mesh Arena #" + i, + "LoVisual RHI Dynamic Mesh Arena #" + i, DEFAULT_VERTEX_ARENA_BYTES, DEFAULT_INDEX_ARENA_BYTES, true @@ -146,7 +146,7 @@ public final class Blaze3dDynamicMeshBackend implements DynamicMeshBackend { int vertexCapacity = Math.max(DEFAULT_VERTEX_ARENA_BYTES, align(vertexBytes, 1024 * 1024)); int indexCapacity = Math.max(DEFAULT_INDEX_ARENA_BYTES, align(indexBytes, 256 * 1024)); Blaze3dMeshArena spill = new Blaze3dMeshArena( - "Combatant RHI Dynamic Mesh Spill #" + spillArenaSequence++, + "LoVisual RHI Dynamic Mesh Spill #" + spillArenaSequence++, vertexCapacity, indexCapacity, false diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dFrameFence.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dFrameFence.java index d3fce29..5a61c2d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dFrameFence.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dFrameFence.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dMeshAllocation.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dMeshAllocation.java index 8066bd4..57e63b1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dMeshAllocation.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dMeshAllocation.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dMeshArena.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dMeshArena.java index 11ae2cd..9878dc6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dMeshArena.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/Blaze3dMeshArena.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/DynamicMeshBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/DynamicMeshBackend.java index aa81ea4..4f8ce29 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/DynamicMeshBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/rhi/upload/DynamicMeshBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/shader/CombatantShaderSources.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/shader/LoVisualShaderSources.java similarity index 93% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/shader/CombatantShaderSources.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/shader/LoVisualShaderSources.java index 093d232..08a4fb7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/shader/CombatantShaderSources.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/shader/LoVisualShaderSources.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -23,18 +23,18 @@ import java.util.Optional; import java.util.Set; /** - * Keeps Combatant's RenderPipeline shader source names stable while still feeding Mojang's + * Keeps LoVisual's RenderPipeline shader source names stable while still feeding Mojang's * shader reload/compilation cache with already-preprocessed GLSL source. */ -public enum CombatantShaderSources { +public enum LoVisualShaderSources { ; - public static final String COMBATANT_NAMESPACE = "combatant"; + public static final String LOVISUAL_NAMESPACE = "lovisual"; public static final String SHADER_PREFIX = "shaders/"; public static final String VERT_EXTENSION = ".vert"; public static final String FRAG_EXTENSION = ".frag"; - public static boolean isCombatantExtendedSource(Identifier id) { - return COMBATANT_NAMESPACE.equals(id.getNamespace()) && isExtendedSourcePath(id.getPath()); + public static boolean isLoVisualExtendedSource(Identifier id) { + return LOVISUAL_NAMESPACE.equals(id.getNamespace()) && isExtendedSourcePath(id.getPath()); } public static boolean isShaderSourceOrInclude(Identifier id) { @@ -128,7 +128,7 @@ public enum CombatantShaderSources { } public static String load(ResourceManager resourceManager, Identifier id, Resource resource) { - Map allResources = resourceManager.listResources("shaders", CombatantShaderSources::isShaderSourceOrInclude); + Map allResources = resourceManager.listResources("shaders", LoVisualShaderSources::isShaderSourceOrInclude); GlslPreprocessor processor = createImportProcessor(allResources, id); try (Reader reader = resource.openAsReader()) { String raw = IOUtils.toString(reader); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgColorMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgColorMode.java index 72f010b..ec3fdf1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgColorMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgColorMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgInlineText.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgInlineText.java index faa6ef2..2916765 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgInlineText.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgInlineText.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgMeshBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgMeshBackend.java index 597ca5a..0149ba0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgMeshBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgMeshBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -140,7 +140,7 @@ public enum SvgMeshBackend { } return parsed; } catch (Exception e) { - DebugLog.warn("[Combatant][SVG] Resource load failed %s : %s", id, e.getMessage()); + DebugLog.warn("[LoVisual][SVG] Resource load failed %s : %s", id, e.getMessage()); return null; } } @@ -159,7 +159,7 @@ public enum SvgMeshBackend { } return parsed; } catch (IOException e) { - DebugLog.warn("[Combatant][SVG] File load failed %s : %s", path, e.getMessage()); + DebugLog.warn("[LoVisual][SVG] File load failed %s : %s", path, e.getMessage()); return null; } } @@ -186,7 +186,7 @@ public enum SvgMeshBackend { walk(root, new AffineTransform(), rootStyle, shapes); return new SvgDoc(cacheKey, vb[0], vb[1], vb[2], vb[3], shapes); } catch (Exception e) { - DebugLog.warn("[Combatant][SVG] Parse failed: %s", e.getMessage()); + DebugLog.warn("[LoVisual][SVG] Parse failed: %s", e.getMessage()); return null; } } @@ -352,14 +352,14 @@ public enum SvgMeshBackend { CompiledTexture texture = getOrRasterize(doc, width, height, options); if (texture != null && texture.isReady()) { traceOnce("svg-texture-draw:" + doc.cacheKey + ':' + texture.widthPx + 'x' + texture.heightPx + ':' + texture.scale, - "[Combatant][SVG] GPU texture path active: doc=%s tex=%dx%d logical=%.2fx%.2f scale=%d", + "[LoVisual][SVG] GPU texture path active: doc=%s tex=%dx%d logical=%.2fx%.2f scale=%d", doc.cacheKey, texture.widthPx, texture.heightPx, Math.abs(width), Math.abs(height), texture.scale); renderer.textureQuad(texture.texture.getTextureView(), texture.texture.getSampler(), x, y, width, height, textureTint(options)); return; } traceOnce("svg-texture-fallback:" + doc.cacheKey + ':' + quantize(width, 16.0) + 'x' + quantize(height, 16.0), - "[Combatant][SVG] GPU texture path unavailable, falling back to mesh: doc=%s logical=%.2fx%.2f", + "[LoVisual][SVG] GPU texture path unavailable, falling back to mesh: doc=%s logical=%.2fx%.2f", doc.cacheKey, Math.abs(width), Math.abs(height)); } @@ -405,14 +405,14 @@ public enum SvgMeshBackend { CompiledTexture cached = TEXTURE_CACHE.get(key); if (cached != null) { traceOnce("svg-texture-cache-hit:" + key, - "[Combatant][SVG] Texture cache hit: doc=%s tex=%dx%d scale=%d", + "[LoVisual][SVG] Texture cache hit: doc=%s tex=%dx%d scale=%d", doc.cacheKey, texW, texH, scale); return cached; } } traceOnce("svg-texture-rasterize:" + key, - "[Combatant][SVG] Rasterizing AA texture: doc=%s tex=%dx%d logical=%.2fx%.2f physical=%.2fx%.2f scale=%d", + "[LoVisual][SVG] Rasterizing AA texture: doc=%s tex=%dx%d logical=%.2fx%.2f physical=%.2fx%.2f scale=%d", doc.cacheKey, texW, texH, logicalW, logicalH, physical.width, physical.height, scale); CompiledTexture compiled = rasterizeTexture(doc, texW, texH, options, scale); if (compiled == null) return null; @@ -496,12 +496,12 @@ public enum SvgMeshBackend { Texture texture = uploadTexture(image); if (texture != null) { traceOnce("svg-texture-upload:" + doc.cacheKey + ':' + texW + 'x' + texH + ':' + scale, - "[Combatant][SVG] Uploaded GPU texture: doc=%s tex=%dx%d scale=%d", + "[LoVisual][SVG] Uploaded GPU texture: doc=%s tex=%dx%d scale=%d", doc.cacheKey, texW, texH, scale); } return texture == null ? null : new CompiledTexture(texture, texW, texH, scale); } catch (Throwable t) { - DebugLog.warn("[Combatant][SVG] Texture rasterization failed: %s", t.getMessage()); + DebugLog.warn("[LoVisual][SVG] Texture rasterization failed: %s", t.getMessage()); return null; } } @@ -626,7 +626,7 @@ public enum SvgMeshBackend { } catch (Throwable ignored) { } } - DebugLog.warn("[Combatant][SVG] Texture upload failed: %s", t.getMessage()); + DebugLog.warn("[LoVisual][SVG] Texture upload failed: %s", t.getMessage()); return null; } finally { MemoryUtil.memFree(buffer); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgMsdfRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgMsdfRegistry.java index 0f0c8c8..fa0e947 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgMsdfRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgMsdfRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -153,7 +153,7 @@ public enum SvgMsdfRegistry { image = ImageIO.read(in); if (image == null) return null; } catch (Exception ignored) { - DebugLog.warn("[Combatant][SVG] MSDF texture missing/invalid: %s", pngId); + DebugLog.warn("[LoVisual][SVG] MSDF texture missing/invalid: %s", pngId); return null; } @@ -165,7 +165,7 @@ public enum SvgMsdfRegistry { Texture texture = uploadTexture(image); if (texture == null) { - DebugLog.warn("[Combatant][SVG] MSDF texture upload failed: %s", pngId); + DebugLog.warn("[LoVisual][SVG] MSDF texture upload failed: %s", pngId); return null; } return new Entry(texture, width, height, pxRange); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgPathParser.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgPathParser.java index 4fe93f8..eb8f719 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgPathParser.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgPathParser.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgRegistry.java index ea6a25c..5e4a9fa 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -18,7 +18,7 @@ import java.util.*; public enum SvgRegistry { ; - public static final String DEFAULT_NAMESPACE = "combatant"; + public static final String DEFAULT_NAMESPACE = "lovisual"; public static final String SVG_ROOT = "svg"; private static final Map BY_RELATIVE = new HashMap<>(); @@ -70,7 +70,7 @@ public enum SvgRegistry { BY_BASENAME.remove(conflict); } - DebugLog.renderThread("[Combatant][SVG] Indexed %d svg files (%d basename aliases, %d conflicts)", + DebugLog.renderThread("[LoVisual][SVG] Indexed %d svg files (%d basename aliases, %d conflicts)", BY_RELATIVE.size(), BY_BASENAME.size(), basenameConflicts.size()); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgRenderOptions.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgRenderOptions.java index d076026..4fab530 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgRenderOptions.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgRenderOptions.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgStyle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgStyle.java index 832c489..52c568f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgStyle.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgStyle.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgStyleUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgStyleUtil.java index ff7f3ee..4f41bc4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgStyleUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/svg/SvgStyleUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/BuiltinFontFace.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/BuiltinFontFace.java index a0e0531..1efd208 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/BuiltinFontFace.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/BuiltinFontFace.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/CustomTextRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/CustomTextRenderer.java index 5540c03..68926a8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/CustomTextRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/CustomTextRenderer.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -16,7 +16,7 @@ package dev.loki.lovisual.render.engine.text; import dev.loki.lovisual.render.engine.text.backend.TextPlacementMode; import org.lwjgl.system.MemoryUtil; import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import dev.loki.lovisual.render.helpers.ScissorFunction; @@ -25,7 +25,7 @@ import java.nio.ByteBuffer; public class CustomTextRenderer implements TextRenderer { public static final RenderColor SHADOW_COLOR = new RenderColor(60, 60, 60, 180); public final FontFace fontFace; - private final MeshBuilder mesh = new MeshBuilder(CombatantRenderPipelines.UI_TEXT); + private final MeshBuilder mesh = new MeshBuilder(LoVisualRenderPipelines.UI_TEXT); private GlyphFont[] fonts; private GlyphFont font; private int fontIndex; @@ -410,12 +410,12 @@ public class CustomTextRenderer implements TextRenderer { } if (font.isReady()) { TextRenderSystem.submitGlyphMesh( - liquidGlassText ? "Combatant UI Liquid Glass Text" : "Combatant UI Text", + liquidGlassText ? "LoVisual UI Liquid Glass Text" : "LoVisual UI Text", font, mesh, liquidGlassText - ? (font.isMsdf() ? CombatantRenderPipelines.UI_TEXT_LIQUID_GLASS_MSDF : CombatantRenderPipelines.UI_TEXT_LIQUID_GLASS) - : (font.isMsdf() ? CombatantRenderPipelines.UI_TEXT_MSDF : CombatantRenderPipelines.UI_TEXT), + ? (font.isMsdf() ? LoVisualRenderPipelines.UI_TEXT_LIQUID_GLASS_MSDF : LoVisualRenderPipelines.UI_TEXT_LIQUID_GLASS) + : (font.isMsdf() ? LoVisualRenderPipelines.UI_TEXT_MSDF : LoVisualRenderPipelines.UI_TEXT), TextPlacementMode.UI ); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/EmptyGlyphFont.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/EmptyGlyphFont.java index d3f259b..4663e03 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/EmptyGlyphFont.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/EmptyGlyphFont.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/Font.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/Font.java index d61e677..878c1f5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/Font.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/Font.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontDebugStats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontDebugStats.java index b4f0df3..7668fd8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontDebugStats.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontDebugStats.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontFace.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontFace.java index 41831b4..510ee81 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontFace.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontFace.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontFamily.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontFamily.java index 5bcaf57..f64c9f5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontFamily.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontFamily.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontInfo.java index 1bc07bd..1315cb5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontInfo.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontUtils.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontUtils.java index c123177..aeff417 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontUtils.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/FontUtils.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/Fonts.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/Fonts.java index bca9c57..ed642b3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/Fonts.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/Fonts.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/GlyphFont.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/GlyphFont.java index 777dbec..2d8dda1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/GlyphFont.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/GlyphFont.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/MsdfFont.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/MsdfFont.java index 1ff63b2..47436bc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/MsdfFont.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/MsdfFont.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/SystemFontFace.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/SystemFontFace.java index f60dee8..d3a8890 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/SystemFontFace.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/SystemFontFace.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextBackendPreference.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextBackendPreference.java index 2df4b4d..528a058 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextBackendPreference.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextBackendPreference.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextClipSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextClipSpec.java index 82ab1d1..86b2b62 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextClipSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextClipSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandBuffer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandBuffer.java index ec6026f..a88fdf3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandBuffer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandBuffer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,9 +7,9 @@ package dev.loki.lovisual.render.engine.text; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderFrameContext; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; import dev.loki.lovisual.render.engine.text.backend.TextBackendRouter; import dev.loki.lovisual.render.engine.text.backend.TextDrawCommand; @@ -41,8 +41,8 @@ public final class TextCommandBuffer { public void flush(TextBackendRouter router) { if (commands.isEmpty()) return; - RenderFrameContext context = CombatantRenderSystem.ensureFrameContext(); - CombatantRhi rhi = CombatantRenderSystem.rhi(); + RenderFrameContext context = LoVisualRenderSystem.ensureFrameContext(); + LoVisualRhi rhi = LoVisualRenderSystem.rhi(); for (int i = 0; i < commands.size(); ) { int consumed = Math.max(1, router.drawAdjacent(commands, i, context, rhi)); for (int j = 0; j < consumed && i + j < commands.size(); j++) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandStats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandStats.java index b7b0e55..c826519 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandStats.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandStats.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandStatsSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandStatsSnapshot.java index db0c405..dd4571a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandStatsSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextCommandStatsSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextEffectSpec.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextEffectSpec.java index bedef61..ed85ed0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextEffectSpec.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextEffectSpec.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextGlyphFallback.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextGlyphFallback.java index 8972ef7..1379254 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextGlyphFallback.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextGlyphFallback.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import java.util.Set; /** * Shared codepoint fallback order for procedural text. *

- * Preferred custom renderer stays first. VanillaSymbols is a Combatant atlas/MSDF renderer, + * Preferred custom renderer stays first. VanillaSymbols is a LoVisual atlas/MSDF renderer, * so covered vanilla icons still go through our text mesh pipeline. VanillaTextRenderer is * only the hard fallback for glyphs that are not present in our assets yet. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextRenderSystem.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextRenderSystem.java index 68b77a5..4519f22 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextRenderSystem.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextRenderSystem.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,8 +11,8 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import dev.loki.lovisual.render.engine.text.backend.*; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.AbstractTexture; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.rhi.GpuMeshHandle; import dev.loki.lovisual.render.engine.rhi.RhiDrawCommand; @@ -45,7 +45,7 @@ public enum TextRenderSystem { } public static GlyphAtlasManager glyphAtlases() { - return CombatantRenderSystem.resources().glyphAtlases(); + return LoVisualRenderSystem.resources().glyphAtlases(); } public static void beginFrame() { @@ -81,8 +81,8 @@ public enum TextRenderSystem { // When UI rendering is inside a Renderer2D batch, text becomes an ordered batch entry. // It may merge only with adjacent compatible text runs; it must never be moved across shapes, // items, scissor/marquee boundaries or world/placement-specific text. - boolean liquidGlassText = pipeline == CombatantRenderPipelines.UI_TEXT_LIQUID_GLASS - || pipeline == CombatantRenderPipelines.UI_TEXT_LIQUID_GLASS_MSDF; + boolean liquidGlassText = pipeline == LoVisualRenderPipelines.UI_TEXT_LIQUID_GLASS + || pipeline == LoVisualRenderPipelines.UI_TEXT_LIQUID_GLASS_MSDF; if (placement == null || placement == TextPlacementMode.UI || placement == TextPlacementMode.SCREEN_SPACE) { boolean enqueued = liquidGlassText ? Renderer2D.enqueueLiquidGlassTextMesh(label, font, mesh, pipeline, placement != null ? placement : TextPlacementMode.UI) @@ -117,13 +117,13 @@ public enum TextRenderSystem { int vertexBytes = mesh.getVertexBytes(); int indexBytes = mesh.getIndexBytes(); - GpuMeshHandle handle = CombatantRenderSystem.rhi().dynamicMeshes().upload(mesh); + GpuMeshHandle handle = LoVisualRenderSystem.rhi().dynamicMeshes().upload(mesh); STATS.meshUpload(vertexBytes, indexBytes); STATS.glyphs(Math.max(0, mesh.getVertexCount() / 4)); if (placement != null && placement.world()) STATS.worldPlacement(); STATS.backend(font.isMsdf() ? TextBackendPreference.MSDF : TextBackendPreference.BITMAP_ATLAS); - RhiDrawCommand.Builder command = RhiDrawCommand.builder(label != null ? label : "Combatant Text") + RhiDrawCommand.Builder command = RhiDrawCommand.builder(label != null ? label : "LoVisual Text") .pipeline(pipeline) .colorAttachment(mc.gameRenderer.mainRenderTarget().getColorTextureView()) .mesh(handle) @@ -134,10 +134,10 @@ public enum TextRenderSystem { command.uniform("MsdfText", MsdfTextUniforms.get()); } - CombatantRenderSystem.rhi().drawMesh(command.build()); + LoVisualRenderSystem.rhi().drawMesh(command.build()); } public static RenderPipeline uiPipelineFor(GlyphFont font) { - return font != null && font.isMsdf() ? CombatantRenderPipelines.UI_TEXT_MSDF : CombatantRenderPipelines.UI_TEXT; + return font != null && font.isMsdf() ? LoVisualRenderPipelines.UI_TEXT_MSDF : LoVisualRenderPipelines.UI_TEXT; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextRenderer.java index 423cf9c..d062ef9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/TextRenderer.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/VanillaTextRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/VanillaTextRenderer.java index e68f03d..c58205d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/VanillaTextRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/VanillaTextRenderer.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/WorldTextRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/WorldTextRenderer.java index fffcdf9..9369c38 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/WorldTextRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/WorldTextRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,7 +12,7 @@ import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; import dev.loki.lovisual.render.engine.RenderState; import dev.loki.lovisual.render.engine.color.RenderColor; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import dev.loki.lovisual.render.engine.uniform.impl.MsdfTextUniforms; @@ -62,11 +62,11 @@ public enum WorldTextRenderer { var pipeline = font.isMsdf() ? (effectiveDepth == Renderer3D.DepthMode.NONE - ? CombatantRenderPipelines.WORLD_TEXT_MSDF - : CombatantRenderPipelines.WORLD_TEXT_MSDF_DEPTH) + ? LoVisualRenderPipelines.WORLD_TEXT_MSDF + : LoVisualRenderPipelines.WORLD_TEXT_MSDF_DEPTH) : (effectiveDepth == Renderer3D.DepthMode.NONE - ? CombatantRenderPipelines.WORLD_TEXT - : CombatantRenderPipelines.WORLD_TEXT_DEPTH); + ? LoVisualRenderPipelines.WORLD_TEXT + : LoVisualRenderPipelines.WORLD_TEXT_DEPTH); if (font.isMsdf()) { MsdfUniformKey key = new MsdfUniformKey(font.getPxRange(), font.getAtlasWidth(), font.getAtlasHeight()); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/BitmapAtlasTextBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/BitmapAtlasTextBackend.java index 7fb8a1a..029bd7c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/BitmapAtlasTextBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/BitmapAtlasTextBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.engine.text.backend; import dev.loki.lovisual.render.engine.core.RenderFrameContext; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; import dev.loki.lovisual.render.engine.text.CustomTextRenderer; import dev.loki.lovisual.render.engine.text.TextBackendPreference; import dev.loki.lovisual.render.engine.text.TextCommandStats; @@ -36,7 +36,7 @@ public final class BitmapAtlasTextBackend implements TextBackend { @Override public String id() { - return "combatant_bitmap_atlas_text"; + return "lovisual_bitmap_atlas_text"; } @Override @@ -53,7 +53,7 @@ public final class BitmapAtlasTextBackend implements TextBackend { } @Override - public void draw(TextDrawCommand command, TextPlacementTransform placement, RenderFrameContext context, CombatantRhi rhi) { + public void draw(TextDrawCommand command, TextPlacementTransform placement, RenderFrameContext context, LoVisualRhi rhi) { TextRenderer renderer = command.renderer() != null ? command.renderer() : TextRenderer.get(); boolean wasBuilding = renderer.isBuilding(); if (!wasBuilding) renderer.begin(command.size(), false, command.big()); @@ -65,7 +65,7 @@ public final class BitmapAtlasTextBackend implements TextBackend { } @Override - public void drawBatch(List commands, int start, int end, RenderFrameContext context, CombatantRhi rhi) { + public void drawBatch(List commands, int start, int end, RenderFrameContext context, LoVisualRhi rhi) { if (commands == null || start < 0 || end <= start || start >= commands.size()) return; TextDrawCommand first = commands.get(start); TextRenderer renderer = first.renderer() != null ? first.renderer() : TextRenderer.get(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/GlyphAtlasManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/GlyphAtlasManager.java index 82a2aa2..61abe2e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/GlyphAtlasManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/GlyphAtlasManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/GlyphAtlasPage.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/GlyphAtlasPage.java index 31d84b2..0f536da 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/GlyphAtlasPage.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/GlyphAtlasPage.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/MsdfTextBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/MsdfTextBackend.java index d8d1fa4..eb5bf49 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/MsdfTextBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/MsdfTextBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.engine.text.backend; import dev.loki.lovisual.render.engine.core.RenderFrameContext; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; import dev.loki.lovisual.render.engine.text.CustomTextRenderer; import dev.loki.lovisual.render.engine.text.TextBackendPreference; import dev.loki.lovisual.render.engine.text.TextCommandStats; @@ -32,7 +32,7 @@ public final class MsdfTextBackend implements TextBackend { @Override public String id() { - return "combatant_msdf_text"; + return "lovisual_msdf_text"; } @Override @@ -50,7 +50,7 @@ public final class MsdfTextBackend implements TextBackend { } @Override - public void draw(TextDrawCommand command, TextPlacementTransform placement, RenderFrameContext context, CombatantRhi rhi) { + public void draw(TextDrawCommand command, TextPlacementTransform placement, RenderFrameContext context, LoVisualRhi rhi) { TextRenderer renderer = command.renderer() != null ? command.renderer() : TextRenderer.get(); boolean wasBuilding = renderer.isBuilding(); if (!wasBuilding) renderer.begin(command.size(), false, command.big()); @@ -62,7 +62,7 @@ public final class MsdfTextBackend implements TextBackend { } @Override - public void drawBatch(List commands, int start, int end, RenderFrameContext context, CombatantRhi rhi) { + public void drawBatch(List commands, int start, int end, RenderFrameContext context, LoVisualRhi rhi) { if (commands == null || start < 0 || end <= start || start >= commands.size()) return; TextDrawCommand first = commands.get(start); TextRenderer renderer = first.renderer() != null ? first.renderer() : TextRenderer.get(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextBackend.java index bb8d220..3e65333 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.engine.text.backend; import dev.loki.lovisual.render.engine.core.RenderFrameContext; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; import java.util.List; @@ -21,15 +21,15 @@ public interface TextBackend { return supports(command); } - default void draw(TextDrawCommand command, RenderFrameContext context, CombatantRhi rhi) { + default void draw(TextDrawCommand command, RenderFrameContext context, LoVisualRhi rhi) { draw(command, TextPlacementResolver.resolve(command, context), context, rhi); } - default void drawBatch(List commands, int start, int end, RenderFrameContext context, CombatantRhi rhi) { + default void drawBatch(List commands, int start, int end, RenderFrameContext context, LoVisualRhi rhi) { for (int i = start; i < end; i++) { draw(commands.get(i), context, rhi); } } - void draw(TextDrawCommand command, TextPlacementTransform placement, RenderFrameContext context, CombatantRhi rhi); + void draw(TextDrawCommand command, TextPlacementTransform placement, RenderFrameContext context, LoVisualRhi rhi); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextBackendRouter.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextBackendRouter.java index 0702f00..390b0c0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextBackendRouter.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextBackendRouter.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -9,7 +9,7 @@ package dev.loki.lovisual.render.engine.text.backend; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.text.TextRenderer; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; import dev.loki.lovisual.render.engine.text.TextCommandStats; import java.util.ArrayList; @@ -41,7 +41,7 @@ public final class TextBackendRouter { } } - public void draw(TextDrawCommand command, RenderFrameContext context, CombatantRhi rhi) { + public void draw(TextDrawCommand command, RenderFrameContext context, LoVisualRhi rhi) { if (command == null || command.text() == null || command.text().isEmpty()) return; TextPlacementTransform placement = TextPlacementResolver.resolve(command, context); if (stats != null && placement.world()) stats.worldPlacement(); @@ -51,7 +51,7 @@ public final class TextBackendRouter { } } - public int drawAdjacent(List commands, int start, RenderFrameContext context, CombatantRhi rhi) { + public int drawAdjacent(List commands, int start, RenderFrameContext context, LoVisualRhi rhi) { if (commands == null || start < 0 || start >= commands.size()) return 1; TextDrawCommand first = commands.get(start); if (first == null || first.text() == null || first.text().isEmpty()) return 1; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextDrawCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextDrawCommand.java index 48c3752..f2f2c14 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextDrawCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextDrawCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementMode.java index 777fa6a..5154e44 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementResolver.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementResolver.java index afa659a..158067c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementResolver.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementResolver.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementTransform.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementTransform.java index e4de3ee..bccf31f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementTransform.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextPlacementTransform.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextRenderDomain.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextRenderDomain.java index 6c7c365..32f12ba 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextRenderDomain.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/TextRenderDomain.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/VanillaSodiumTextBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/VanillaSodiumTextBackend.java index ebb3293..97ce360 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/VanillaSodiumTextBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/text/backend/VanillaSodiumTextBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.engine.text.backend; import dev.loki.lovisual.render.engine.core.RenderFrameContext; -import dev.loki.lovisual.render.engine.rhi.CombatantRhi; +import dev.loki.lovisual.render.engine.rhi.LoVisualRhi; import dev.loki.lovisual.render.engine.text.TextBackendPreference; import dev.loki.lovisual.render.engine.text.TextCommandStats; import dev.loki.lovisual.render.engine.text.TextRenderer; @@ -49,7 +49,7 @@ public final class VanillaSodiumTextBackend implements TextBackend { } @Override - public void draw(TextDrawCommand command, TextPlacementTransform placement, RenderFrameContext context, CombatantRhi rhi) { + public void draw(TextDrawCommand command, TextPlacementTransform placement, RenderFrameContext context, LoVisualRhi rhi) { TextRenderer renderer = command.renderer() != null ? command.renderer() : VanillaTextRenderer.INSTANCE; boolean wasBuilding = renderer.isBuilding(); if (!wasBuilding) renderer.begin(command.size(), false, command.big()); @@ -62,7 +62,7 @@ public final class VanillaSodiumTextBackend implements TextBackend { } @Override - public void drawBatch(List commands, int start, int end, RenderFrameContext context, CombatantRhi rhi) { + public void drawBatch(List commands, int start, int end, RenderFrameContext context, LoVisualRhi rhi) { if (commands == null || start < 0 || end <= start || start >= commands.size()) return; TextDrawCommand first = commands.get(start); TextRenderer renderer = first.renderer() != null ? first.renderer() : VanillaTextRenderer.INSTANCE; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/MeshBuilder.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/MeshBuilder.java index f2c9fb8..7c9b27a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/MeshBuilder.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/MeshBuilder.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -45,9 +45,9 @@ import static org.lwjgl.system.MemoryUtil.*; */ public final class MeshBuilder implements AutoCloseable { private static final boolean DEBUG = - FabricLoader.getInstance().isDevelopmentEnvironment() || Boolean.getBoolean("combatant.render.debug"); - private static final int DEFAULT_VERTEX_CAPACITY = Integer.getInteger("combatant.render.mesh.defaultVertices", 4096); - private static final int DEFAULT_INDEX_CAPACITY = Integer.getInteger("combatant.render.mesh.defaultIndices", 8192); + FabricLoader.getInstance().isDevelopmentEnvironment() || Boolean.getBoolean("lovisual.render.debug"); + private static final int DEFAULT_VERTEX_CAPACITY = Integer.getInteger("lovisual.render.mesh.defaultVertices", 4096); + private static final int DEFAULT_INDEX_CAPACITY = Integer.getInteger("lovisual.render.mesh.defaultIndices", 8192); private static final int MAX_BUFFER_BYTES = Integer.MAX_VALUE - 8; private static final FrameStats FRAME_STATS = new FrameStats(); private final VertexFormat format; @@ -522,13 +522,13 @@ public final class MeshBuilder implements AutoCloseable { /** * Emergency compatibility upload. This path is locked after the RHI migration and is not allowed as production - * behavior. Use CombatantRHI.dynamicMeshes().upload(mesh) instead. + * behavior. Use LoVisualRHI.dynamicMeshes().upload(mesh) instead. */ @Deprecated public GpuBuffer getVertexBuffer() { RenderArchitectureGuard.requireAllowed(LegacyRenderPath.IMMEDIATE_MESH_UPLOAD, "MeshBuilder#getVertexBuffer"); return RenderSystem.getDevice().createBuffer( - () -> "combatant-immediate-vertices", + () -> "lovisual-immediate-vertices", GpuBuffer.USAGE_VERTEX | GpuBuffer.USAGE_COPY_DST, vertexBufferView() ); @@ -536,13 +536,13 @@ public final class MeshBuilder implements AutoCloseable { /** * Emergency compatibility upload. This path is locked after the RHI migration and is not allowed as production - * behavior. Use CombatantRHI.dynamicMeshes().upload(mesh) instead. + * behavior. Use LoVisualRHI.dynamicMeshes().upload(mesh) instead. */ @Deprecated public GpuBuffer getIndexBuffer() { RenderArchitectureGuard.requireAllowed(LegacyRenderPath.IMMEDIATE_MESH_UPLOAD, "MeshBuilder#getIndexBuffer"); return RenderSystem.getDevice().createBuffer( - () -> "combatant-immediate-indices", + () -> "lovisual-immediate-indices", GpuBuffer.USAGE_INDEX | GpuBuffer.USAGE_COPY_DST, indexBufferView() ); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/MeshData.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/MeshData.java index 5036621..7d0f70a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/MeshData.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/MeshData.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/DepthOfFieldUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/DepthOfFieldUniforms.java index 01a1bd4..3206728 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/DepthOfFieldUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/DepthOfFieldUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,8 +11,8 @@ import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; import org.joml.Matrix4f; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum DepthOfFieldUniforms { ; @@ -27,7 +27,7 @@ public enum DepthOfFieldUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - DepthOfField UBO"; + private static final String UNIFORM_NAME = "LoVisual - DepthOfField UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 8; public static void update(Matrix4f projection, @@ -66,14 +66,14 @@ public enum DepthOfFieldUniforms { DATA.particlesDepth = particlesDepth ? 1.0f : 0.0f; DATA.weatherDepth = weatherDepth ? 1.0f : 0.0f; DATA.cloudsDepth = cloudsDepth ? 1.0f : 0.0f; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final Matrix4f projection = new Matrix4f(); private int width; private int height; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandGlassUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandGlassUniforms.java index 94dc08d..42580c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandGlassUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandGlassUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; /** * Std140 UBO for first-person hand liquid-glass overlay. @@ -33,7 +33,7 @@ public enum HandGlassUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - HandGlass UBO"; + private static final String UNIFORM_NAME = "LoVisual - HandGlass UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update( @@ -62,14 +62,14 @@ public enum HandGlassUniforms { DATA.reserved3 = reserved3; DATA.reserved4 = reserved4; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private float screenW, screenH, time, edgeWidth; private float tintR, tintG, tintB, alpha; private float strength, refractionPx, hazeStrength, reserved0; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandMetallicUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandMetallicUniforms.java index bef2b83..60b6185 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandMetallicUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandMetallicUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum HandMetallicUniforms { ; @@ -27,7 +27,7 @@ public enum HandMetallicUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - Hand Metallic UBO"; + private static final String UNIFORM_NAME = "LoVisual - Hand Metallic UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update( @@ -67,14 +67,14 @@ public enum HandMetallicUniforms { DATA.shadowStrength = shadowStrength; DATA.edgeWidth = edgeWidth; DATA.prism = prism; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private float baseR, baseG, baseB, fillA; private float highlightR, highlightG, highlightB, highlightA; private float glowR, glowG, glowB, glowA; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandSmokeUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandSmokeUniforms.java index d4ed585..7ad4c1c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandSmokeUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HandSmokeUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum HandSmokeUniforms { ; @@ -26,7 +26,7 @@ public enum HandSmokeUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - Hand Smoke UBO"; + private static final String UNIFORM_NAME = "LoVisual - Hand Smoke UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update( @@ -61,14 +61,14 @@ public enum HandSmokeUniforms { DATA.glowStrength = glowStrength; DATA.shadowStrength = shadowStrength; DATA.density = density; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private float fillR, fillG, fillB, fillA; private float glowR, glowG, glowB, glowA; private float shadowR, shadowG, shadowB, shadowA; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HeatUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HeatUniforms.java index 65393d4..d78afe4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HeatUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/HeatUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum HeatUniforms { ; @@ -28,7 +28,7 @@ public enum HeatUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - HeatFX UBO"; + private static final String UNIFORM_NAME = "LoVisual - HeatFX UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update(float intensity, float distortion, float scale, float speed, @@ -41,14 +41,14 @@ public enum HeatUniforms { DATA.vignetteRadius = vignetteRadius; DATA.vignetteSoftness = vignetteSoftness; DATA.time = time; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private float intensity; private float distortion; private float scale; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MenuBackgroundUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MenuBackgroundUniforms.java index afa7ac9..cf24e7d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MenuBackgroundUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MenuBackgroundUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum MenuBackgroundUniforms { ; @@ -23,7 +23,7 @@ public enum MenuBackgroundUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - MenuBackground UBO"; + private static final String UNIFORM_NAME = "LoVisual - MenuBackground UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update(float width, float height, float time, int accentRgb, int bgRgb) { @@ -41,14 +41,14 @@ public enum MenuBackgroundUniforms { DATA.background[1] = ((bgRgb >>> 8) & 0xFF) / 255f; DATA.background[2] = (bgRgb & 0xFF) / 255f; DATA.background[3] = 1.0f; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final float[] params = new float[4]; private final float[] accent = new float[4]; private final float[] background = new float[4]; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MeshUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MeshUniforms.java index 7f2f478..74f01ad 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MeshUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MeshUniforms.java @@ -1,6 +1,6 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client @@ -13,13 +13,13 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; import org.joml.Matrix4f; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum MeshUniforms { ; @@ -31,7 +31,7 @@ public enum MeshUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - Mesh UBO"; + private static final String UNIFORM_NAME = "LoVisual - Mesh UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update(Matrix4f proj, Matrix4f modelView) { @@ -43,14 +43,14 @@ public enum MeshUniforms { DATA.modelView = modelView; DATA.viewportWidth = Math.max(1.0f, viewportWidth); DATA.viewportHeight = Math.max(1.0f, viewportHeight); - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private Matrix4f proj; private Matrix4f modelView; private float viewportWidth = 1.0f; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MotionBlurUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MotionBlurUniforms.java index 3e3d03f..4b893bd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MotionBlurUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MotionBlurUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum MotionBlurUniforms { ; @@ -24,7 +24,7 @@ public enum MotionBlurUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - MotionBlur UBO"; + private static final String UNIFORM_NAME = "LoVisual - MotionBlur UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 4; public static void update(int width, @@ -51,11 +51,11 @@ public enum MotionBlurUniforms { DATA.historyBlend = clamp01(historyBlend); DATA.historyValid = historyValid ? 1.0f : 0.0f; DATA.historyClamp = clamp01(historyClamp); - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } private static float finiteOrZero(float value) { @@ -68,7 +68,7 @@ public enum MotionBlurUniforms { return Math.min(value, 1.0f); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private int width = 1; private int height = 1; private float velocityXPixels; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MsdfTextUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MsdfTextUniforms.java index 01fb776..d0d0fb0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MsdfTextUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/MsdfTextUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; /** * Std140 UBO for MSDF text rendering. @@ -27,7 +27,7 @@ public enum MsdfTextUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - MSDF Text UBO"; + private static final String UNIFORM_NAME = "LoVisual - MSDF Text UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update(float pxRange, int atlasWidth, int atlasHeight) { @@ -39,14 +39,14 @@ public enum MsdfTextUniforms { DATA.values[2] = safeH; DATA.values[3] = 0f; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final float[] values = new float[4]; @Override diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/PostFXUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/PostFXUniforms.java index 9c261d9..8a3d86a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/PostFXUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/PostFXUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum PostFXUniforms { ; @@ -29,20 +29,20 @@ public enum PostFXUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - PostFX UBO"; + private static final String UNIFORM_NAME = "LoVisual - PostFX UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update(float[] values) { if (values == null || values.length < FLOAT_COUNT) return; System.arraycopy(values, 0, DATA.values, 0, FLOAT_COUNT); - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final float[] values = new float[FLOAT_COUNT]; @Override diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/PostProcessUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/PostProcessUniforms.java index c26d8a5..5b50ffb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/PostProcessUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/PostProcessUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum PostProcessUniforms { ; @@ -24,7 +24,7 @@ public enum PostProcessUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - PostProcess UBO"; + private static final String UNIFORM_NAME = "LoVisual - PostProcess UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update(float strength, float desat, float contrast, float padding) { @@ -32,14 +32,14 @@ public enum PostProcessUniforms { DATA.desat = desat; DATA.contrast = contrast; DATA.padding = padding; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private float strength; private float desat; private float contrast; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspBlurUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspBlurUniforms.java index 37566f0..da41c98 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspBlurUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspBlurUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum ShaderEspBlurUniforms { ; @@ -22,7 +22,7 @@ public enum ShaderEspBlurUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - ShaderESP Blur UBO"; + private static final String UNIFORM_NAME = "LoVisual - ShaderESP Blur UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 64; public static void update(float screenW, float screenH, float radius, float directionX, float directionY) { @@ -40,14 +40,14 @@ public enum ShaderEspBlurUniforms { DATA.direction[2] = 0.0f; DATA.direction[3] = 0.0f; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final float[] texelRadius = new float[4]; private final float[] direction = new float[4]; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspGradientUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspGradientUniforms.java index a3af8ec..538814c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspGradientUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspGradientUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum ShaderEspGradientUniforms { ; @@ -25,7 +25,7 @@ public enum ShaderEspGradientUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - ShaderESP Gradient UBO"; + private static final String UNIFORM_NAME = "LoVisual - ShaderESP Gradient UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 64; public static void update(float x, float y, float width, float height, @@ -55,11 +55,11 @@ public enum ShaderEspGradientUniforms { DATA.color4[2] = 0.0f; DATA.color4[3] = 0.0f; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } private static void putColor(float[] dst, int argb) { @@ -69,7 +69,7 @@ public enum ShaderEspGradientUniforms { dst[3] = ((argb >>> 24) & 0xFF) / 255.0f; } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final float[] rect = new float[4]; private final float[] color1 = new float[4]; private final float[] color2 = new float[4]; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspSmokeUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspSmokeUniforms.java index b278e3f..f40ff4b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspSmokeUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/ShaderEspSmokeUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum ShaderEspSmokeUniforms { ; @@ -26,7 +26,7 @@ public enum ShaderEspSmokeUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - ShaderESP Smoke UBO"; + private static final String UNIFORM_NAME = "LoVisual - ShaderESP Smoke UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update(float x, float y, float width, float height, @@ -52,11 +52,11 @@ public enum ShaderEspSmokeUniforms { putColor(DATA.color1, secondColor); putColor(DATA.color2, thirdColor); - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } private static void putColor(float[] dst, int rgb) { @@ -66,7 +66,7 @@ public enum ShaderEspSmokeUniforms { dst[3] = 1.0f; } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final float[] rect = new float[4]; private final float[] params0 = new float[4]; private final float[] params1 = new float[4]; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/SkySunUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/SkySunUniforms.java index e2d9dac..426b526 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/SkySunUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/SkySunUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum SkySunUniforms { ; @@ -24,7 +24,7 @@ public enum SkySunUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - SkySun UBO"; + private static final String UNIFORM_NAME = "LoVisual - SkySun UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update(float innerRatio, float haloStrength, float coreStrength, float rayStrength) { @@ -32,14 +32,14 @@ public enum SkySunUniforms { DATA.haloStrength = haloStrength; DATA.coreStrength = coreStrength; DATA.rayStrength = rayStrength; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private float innerRatio; private float haloStrength; private float coreStrength; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/SkyboxShaderUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/SkyboxShaderUniforms.java index 0c55243..9152b6e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/SkyboxShaderUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/SkyboxShaderUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum SkyboxShaderUniforms { ; @@ -28,7 +28,7 @@ public enum SkyboxShaderUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - SkyboxShader UBO"; + private static final String UNIFORM_NAME = "LoVisual - SkyboxShader UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; private static final int DEFAULT_LAYER_MASK = (1 << 17) - 1; private static int lastShaderRgb; @@ -161,7 +161,7 @@ public enum SkyboxShaderUniforms { || changed(lastTwinkleStrength, DATA.starStyle[1]) || lastLayerMask != sanitizedLayerMask; - CombatantRenderSystem.uniforms().writeCached(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, + LoVisualRenderSystem.uniforms().writeCached(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, 1, force, DATA); lastShaderRgb = shaderRgb; @@ -210,10 +210,10 @@ public enum SkyboxShaderUniforms { } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final float[] color = new float[4]; private final float[] sky = new float[4]; private final float[] params = new float[4]; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/TextureTintUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/TextureTintUniforms.java index 4e154a7..7c60cd4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/TextureTintUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/TextureTintUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,13 +7,13 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; import net.minecraft.util.Mth; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; public enum TextureTintUniforms { ; @@ -23,7 +23,7 @@ public enum TextureTintUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - TextureTint UBO"; + private static final String UNIFORM_NAME = "LoVisual - TextureTint UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update(int tintRgb, float strength, int mode) { @@ -37,14 +37,14 @@ public enum TextureTintUniforms { DATA.params[2] = 0.0f; DATA.params[3] = 0.0f; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final float[] tint = new float[4]; private final float[] params = new float[4]; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/UIBatchUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/UIBatchUniforms.java index 0bc41e1..fdba3a8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/UIBatchUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/UIBatchUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,13 +7,13 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; import dev.loki.lovisual.render.engine.core.ViewportContext; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; /** * Std140 UBO for batched 2D UI shaders. @@ -28,7 +28,7 @@ public enum UIBatchUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - UI Batch UBO"; + private static final String UNIFORM_NAME = "LoVisual - UI Batch UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 16; public static void update(float framebufferW, float framebufferH) { @@ -46,14 +46,14 @@ public enum UIBatchUniforms { DATA.screen[2] = logicalW; DATA.screen[3] = logicalH; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final float[] screen = new float[4]; @Override diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/UIBlurUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/UIBlurUniforms.java index 09d8324..2a0158e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/UIBlurUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/impl/UIBlurUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,12 +7,12 @@ package dev.loki.lovisual.render.engine.uniform.impl; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.Std140Builder; import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import dev.loki.lovisual.render.engine.rhi.uniform.CombatantUniformAllocator; +import dev.loki.lovisual.render.engine.rhi.uniform.LoVisualUniformAllocator; /** * Std140 UBO for the fullscreen Dual Kawase UI blur pass. @@ -35,7 +35,7 @@ public enum UIBlurUniforms { .get(); private static final Data DATA = new Data(); - private static final String UNIFORM_NAME = "Combatant - UIBlur UBO"; + private static final String UNIFORM_NAME = "LoVisual - UIBlur UBO"; private static final int EXPECTED_WRITES_PER_FRAME = 64; public static void update(float screenW, float screenH, @@ -68,14 +68,14 @@ public enum UIBlurUniforms { DATA.color1[2] = (rgb & 0xFF) / 255f; DATA.color1[3] = 1f; - CombatantRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); + LoVisualRenderSystem.uniforms().write(UNIFORM_NAME, SIZE, EXPECTED_WRITES_PER_FRAME, DATA); } public static GpuBufferSlice get() { - return CombatantRenderSystem.uniforms().current(UNIFORM_NAME); + return LoVisualRenderSystem.uniforms().current(UNIFORM_NAME); } - private static final class Data implements CombatantUniformAllocator.UniformWriter { + private static final class Data implements LoVisualUniformAllocator.UniformWriter { private final float[] inputResolution = new float[4]; private final float[] size = new float[4]; private final float[] location = new float[4]; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/storage/FixedUniformStorage.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/storage/FixedUniformStorage.java index e13a000..f876c72 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/storage/FixedUniformStorage.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/uniform/storage/FixedUniformStorage.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/CombatantVertexFormats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/CombatantVertexFormats.java deleted file mode 100644 index 97e249a..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/CombatantVertexFormats.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on, adapted from, or implemented - * with reference to Meteor Client - * (https://github.com/MeteorDevelopment/meteor-client). - * Copyright (c) Meteor Development. - * - * Licensed under the GNU General Public License v3.0. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.render.engine.vertex; - -import com.mojang.blaze3d.vertex.VertexFormat; - -public enum CombatantVertexFormats { - ; - public static final VertexFormat POS2 = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .build(); - - public static final VertexFormat POS3_TEXTURE_COLOR_PARAMS2 = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS3) - .addAttribute("UV0", CombatantVertexFormatElements.TEXTURE) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Params", CombatantVertexFormatElements.PARAMS) - .addAttribute("Params2", CombatantVertexFormatElements.PARAMS2) - .build(); - - public static final VertexFormat POS2_COLOR = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .build(); - - /** - * World-space wide line vertex. - * Position is the current endpoint, Color is endpoint color, Line packs the opposite endpoint in xyz - * and signed screen-space line width in w. The vertex shader expands the endpoint in clip space. - */ - public static final VertexFormat POS3_COLOR_LINE = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS3) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Line", CombatantVertexFormatElements.PARAMS) - .build(); - - public static final VertexFormat POS2_TEXTURE_COLOR = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("UV0", CombatantVertexFormatElements.TEXTURE) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .build(); - - public static final VertexFormat POS2_COLOR_RECT_PARAMS = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Rect", CombatantVertexFormatElements.RECT) - .addAttribute("Params", CombatantVertexFormatElements.PARAMS) - .build(); - - public static final VertexFormat POS2_COLOR_RECT_PARAMS2 = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Rect", CombatantVertexFormatElements.RECT) - .addAttribute("Params", CombatantVertexFormatElements.PARAMS) - .addAttribute("Params2", CombatantVertexFormatElements.PARAMS2) - .build(); - - public static final VertexFormat POS2_LOCAL_COLOR_RECT_PARAMS = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("Local", CombatantVertexFormatElements.LOCAL) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Rect", CombatantVertexFormatElements.RECT) - .addAttribute("Params", CombatantVertexFormatElements.PARAMS) - .build(); - - public static final VertexFormat POS2_LOCAL_COLOR_RECT_PARAMS2 = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("Local", CombatantVertexFormatElements.LOCAL) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Rect", CombatantVertexFormatElements.RECT) - .addAttribute("Params", CombatantVertexFormatElements.PARAMS) - .addAttribute("Params2", CombatantVertexFormatElements.PARAMS2) - .build(); - - public static final VertexFormat POS2_TEXTURE_COLOR_RECT_PARAMS = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("UV0", CombatantVertexFormatElements.TEXTURE) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Rect", CombatantVertexFormatElements.RECT) - .addAttribute("Params", CombatantVertexFormatElements.PARAMS) - .build(); - - public static final VertexFormat POS2_TEXTURE_LOCAL_COLOR_RECT_PARAMS = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("UV0", CombatantVertexFormatElements.TEXTURE) - .addAttribute("Local", CombatantVertexFormatElements.LOCAL) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Rect", CombatantVertexFormatElements.RECT) - .addAttribute("Params", CombatantVertexFormatElements.PARAMS) - .build(); - - public static final VertexFormat POS2_TEXTURE_LOCAL_COLOR_RECT_PARAMS2 = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("UV0", CombatantVertexFormatElements.TEXTURE) - .addAttribute("Local", CombatantVertexFormatElements.LOCAL) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Rect", CombatantVertexFormatElements.RECT) - .addAttribute("Params", CombatantVertexFormatElements.PARAMS) - .addAttribute("Params2", CombatantVertexFormatElements.PARAMS2) - .build(); - - public static final VertexFormat POS2_TEXTURE_COLOR_RECT_PARAMS2 = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("UV0", CombatantVertexFormatElements.TEXTURE) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Rect", CombatantVertexFormatElements.RECT) - .addAttribute("Params", CombatantVertexFormatElements.PARAMS) - .addAttribute("Params2", CombatantVertexFormatElements.PARAMS2) - .build(); - - public static final VertexFormat POS2_LOCAL_COLOR_RECT_PARAMS5 = VertexFormat.builder(0) - .addAttribute("Position", CombatantVertexFormatElements.POS2) - .addAttribute("Local", CombatantVertexFormatElements.LOCAL) - .addAttribute("Color", CombatantVertexFormatElements.COLOR) - .addAttribute("Rect", CombatantVertexFormatElements.RECT) - .addAttribute("Params", CombatantVertexFormatElements.PARAMS) - .addAttribute("Params2", CombatantVertexFormatElements.PARAMS2) - .addAttribute("Params3", CombatantVertexFormatElements.PARAMS3) - .addAttribute("Params4", CombatantVertexFormatElements.PARAMS4) - .addAttribute("Params5", CombatantVertexFormatElements.PARAMS5) - .build(); - -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/CombatantVertexFormatElements.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/LoVisualVertexFormatElements.java similarity index 89% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/CombatantVertexFormatElements.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/LoVisualVertexFormatElements.java index 2f5a618..ac23ad9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/CombatantVertexFormatElements.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/LoVisualVertexFormatElements.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -9,7 +9,7 @@ package dev.loki.lovisual.render.engine.vertex; import com.mojang.blaze3d.GpuFormat; -public enum CombatantVertexFormatElements { +public enum LoVisualVertexFormatElements { ; public static final GpuFormat POS3 = GpuFormat.RGB32_FLOAT; public static final GpuFormat POS2 = GpuFormat.RG32_FLOAT; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/LoVisualVertexFormats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/LoVisualVertexFormats.java new file mode 100644 index 0000000..e1a44c3 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/vertex/LoVisualVertexFormats.java @@ -0,0 +1,134 @@ +/* + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. + * + * Portions of this file are based on, adapted from, or implemented + * with reference to Meteor Client + * (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + * + * Licensed under the GNU General Public License v3.0. + * See THIRD_PARTY_NOTICES.md for details. + */ + +package dev.loki.lovisual.render.engine.vertex; + +import com.mojang.blaze3d.vertex.VertexFormat; + +public enum LoVisualVertexFormats { + ; + public static final VertexFormat POS2 = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .build(); + + public static final VertexFormat POS3_TEXTURE_COLOR_PARAMS2 = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS3) + .addAttribute("UV0", LoVisualVertexFormatElements.TEXTURE) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Params", LoVisualVertexFormatElements.PARAMS) + .addAttribute("Params2", LoVisualVertexFormatElements.PARAMS2) + .build(); + + public static final VertexFormat POS2_COLOR = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .build(); + + /** + * World-space wide line vertex. + * Position is the current endpoint, Color is endpoint color, Line packs the opposite endpoint in xyz + * and signed screen-space line width in w. The vertex shader expands the endpoint in clip space. + */ + public static final VertexFormat POS3_COLOR_LINE = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS3) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Line", LoVisualVertexFormatElements.PARAMS) + .build(); + + public static final VertexFormat POS2_TEXTURE_COLOR = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("UV0", LoVisualVertexFormatElements.TEXTURE) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .build(); + + public static final VertexFormat POS2_COLOR_RECT_PARAMS = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Rect", LoVisualVertexFormatElements.RECT) + .addAttribute("Params", LoVisualVertexFormatElements.PARAMS) + .build(); + + public static final VertexFormat POS2_COLOR_RECT_PARAMS2 = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Rect", LoVisualVertexFormatElements.RECT) + .addAttribute("Params", LoVisualVertexFormatElements.PARAMS) + .addAttribute("Params2", LoVisualVertexFormatElements.PARAMS2) + .build(); + + public static final VertexFormat POS2_LOCAL_COLOR_RECT_PARAMS = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("Local", LoVisualVertexFormatElements.LOCAL) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Rect", LoVisualVertexFormatElements.RECT) + .addAttribute("Params", LoVisualVertexFormatElements.PARAMS) + .build(); + + public static final VertexFormat POS2_LOCAL_COLOR_RECT_PARAMS2 = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("Local", LoVisualVertexFormatElements.LOCAL) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Rect", LoVisualVertexFormatElements.RECT) + .addAttribute("Params", LoVisualVertexFormatElements.PARAMS) + .addAttribute("Params2", LoVisualVertexFormatElements.PARAMS2) + .build(); + + public static final VertexFormat POS2_TEXTURE_COLOR_RECT_PARAMS = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("UV0", LoVisualVertexFormatElements.TEXTURE) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Rect", LoVisualVertexFormatElements.RECT) + .addAttribute("Params", LoVisualVertexFormatElements.PARAMS) + .build(); + + public static final VertexFormat POS2_TEXTURE_LOCAL_COLOR_RECT_PARAMS = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("UV0", LoVisualVertexFormatElements.TEXTURE) + .addAttribute("Local", LoVisualVertexFormatElements.LOCAL) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Rect", LoVisualVertexFormatElements.RECT) + .addAttribute("Params", LoVisualVertexFormatElements.PARAMS) + .build(); + + public static final VertexFormat POS2_TEXTURE_LOCAL_COLOR_RECT_PARAMS2 = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("UV0", LoVisualVertexFormatElements.TEXTURE) + .addAttribute("Local", LoVisualVertexFormatElements.LOCAL) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Rect", LoVisualVertexFormatElements.RECT) + .addAttribute("Params", LoVisualVertexFormatElements.PARAMS) + .addAttribute("Params2", LoVisualVertexFormatElements.PARAMS2) + .build(); + + public static final VertexFormat POS2_TEXTURE_COLOR_RECT_PARAMS2 = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("UV0", LoVisualVertexFormatElements.TEXTURE) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Rect", LoVisualVertexFormatElements.RECT) + .addAttribute("Params", LoVisualVertexFormatElements.PARAMS) + .addAttribute("Params2", LoVisualVertexFormatElements.PARAMS2) + .build(); + + public static final VertexFormat POS2_LOCAL_COLOR_RECT_PARAMS5 = VertexFormat.builder(0) + .addAttribute("Position", LoVisualVertexFormatElements.POS2) + .addAttribute("Local", LoVisualVertexFormatElements.LOCAL) + .addAttribute("Color", LoVisualVertexFormatElements.COLOR) + .addAttribute("Rect", LoVisualVertexFormatElements.RECT) + .addAttribute("Params", LoVisualVertexFormatElements.PARAMS) + .addAttribute("Params2", LoVisualVertexFormatElements.PARAMS2) + .addAttribute("Params3", LoVisualVertexFormatElements.PARAMS3) + .addAttribute("Params4", LoVisualVertexFormatElements.PARAMS4) + .addAttribute("Params5", LoVisualVertexFormatElements.PARAMS5) + .build(); + +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisualFrame.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisualFrame.java similarity index 85% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisualFrame.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisualFrame.java index 442fc5a..adb731e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisualFrame.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisualFrame.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -12,14 +12,14 @@ import com.mojang.blaze3d.textures.GpuTextureView; /** * Per-frame context shared between future visual passes. */ -public final class CombatantVisualFrame { +public final class LoVisualVisualFrame { private int viewportWidth; private int viewportHeight; private float tickDelta; private GpuTextureView sceneColor; private GpuTextureView depth; - public CombatantVisualFrame begin(int viewportWidth, int viewportHeight, float tickDelta, + public LoVisualVisualFrame begin(int viewportWidth, int viewportHeight, float tickDelta, GpuTextureView sceneColor, GpuTextureView depth) { this.viewportWidth = Math.max(0, viewportWidth); this.viewportHeight = Math.max(0, viewportHeight); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisualPass.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisualPass.java similarity index 67% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisualPass.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisualPass.java index b3cfcba..4397d99 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisualPass.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisualPass.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,10 +14,10 @@ import net.minecraft.server.packs.resources.ResourceManager; /** * Base contract for the custom world visual graph. */ -public interface CombatantVisualPass { +public interface LoVisualVisualPass { Identifier getId(); - CombatantVisualPhase getPhase(); + LoVisualVisualPhase getPhase(); default boolean isEnabled() { return true; @@ -29,10 +29,10 @@ public interface CombatantVisualPass { default void onResourceReload(ResourceManager manager) { } - default void prepareFrame(CombatantVisualFrame frame) { + default void prepareFrame(LoVisualVisualFrame frame) { } - default boolean render(CombatantVisualFrame frame, GpuTextureView src, GpuTextureView dst) { + default boolean render(LoVisualVisualFrame frame, GpuTextureView src, GpuTextureView dst) { return false; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisualPhase.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisualPhase.java similarity index 75% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisualPhase.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisualPhase.java index 2e749b0..14b2408 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisualPhase.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisualPhase.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,7 +10,7 @@ package dev.loki.lovisual.render.engine.visuals; /** * Render graph ordering for the custom world visual stack. */ -public enum CombatantVisualPhase { +public enum LoVisualVisualPhase { PREPARE, SHADOWS, VOLUMETRICS, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisuals.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisuals.java similarity index 78% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisuals.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisuals.java index 09217b9..799a046 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/CombatantVisuals.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/visuals/LoVisualVisuals.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,12 +11,12 @@ import com.mojang.blaze3d.ProjectionType; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.pipeline.TextureTarget; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import net.minecraft.client.Minecraft; import net.minecraft.server.packs.resources.ResourceManager; import org.joml.Matrix4f; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.depth.PreTranslucentDepth; import dev.loki.lovisual.render.engine.postprocess.PostProcessManager; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; @@ -30,12 +30,12 @@ import java.util.Comparator; import java.util.List; /** - * Root registry/runtime for Combatant's world visual stack. + * Root registry/runtime for LoVisual's world visual stack. */ -public enum CombatantVisuals { +public enum LoVisualVisuals { ; - private static final List PASSES = new ArrayList<>(); - private static final CombatantVisualFrame FRAME = new CombatantVisualFrame(); + private static final List PASSES = new ArrayList<>(); + private static final LoVisualVisualFrame FRAME = new LoVisualVisualFrame(); private static TextureTarget ping; private static TextureTarget pong; @@ -46,25 +46,25 @@ public enum CombatantVisuals { public static void init() { if (initialized) return; initialized = true; - DebugLog.renderThread("[Combatant] Visual stack initialized"); + DebugLog.renderThread("[LoVisual] Visual stack initialized"); } - public static void registerPass(CombatantVisualPass pass) { + public static void registerPass(LoVisualVisualPass pass) { if (pass == null || PASSES.contains(pass)) return; PASSES.add(pass); PASSES.sort(Comparator - .comparing(CombatantVisualPass::getPhase) + .comparing(LoVisualVisualPass::getPhase) .thenComparing(passEntry -> passEntry.getId().toString())); if (initialized) { pass.init(); } } - public static List getPasses() { + public static List getPasses() { return Collections.unmodifiableList(PASSES); } - public static CombatantVisualFrame frame() { + public static LoVisualVisualFrame frame() { return FRAME; } @@ -106,7 +106,7 @@ public enum CombatantVisuals { boolean usePing = true; boolean anyApplied = false; - for (CombatantVisualPass pass : PASSES) { + for (LoVisualVisualPass pass : PASSES) { if (pass == null || !pass.isEnabled()) continue; try { pass.prepareFrame(FRAME); @@ -118,7 +118,7 @@ public enum CombatantVisuals { anyApplied = true; } } catch (Throwable t) { - DebugLog.error("[Combatant] Visual pass render failed: " + pass.getId(), t); + DebugLog.error("[LoVisual] Visual pass render failed: " + pass.getId(), t); } } @@ -137,18 +137,18 @@ public enum CombatantVisuals { } private static boolean hasEnabledPasses() { - for (CombatantVisualPass pass : PASSES) { + for (LoVisualVisualPass pass : PASSES) { if (pass != null && pass.isEnabled()) return true; } return false; } public static void onResourceReload(ResourceManager manager) { - for (CombatantVisualPass pass : PASSES) { + for (LoVisualVisualPass pass : PASSES) { try { pass.onResourceReload(manager); } catch (Throwable t) { - DebugLog.error("[Combatant] Visual pass reload failed: " + pass.getId(), t); + DebugLog.error("[LoVisual] Visual pass reload failed: " + pass.getId(), t); } } } @@ -158,8 +158,8 @@ public enum CombatantVisuals { int h = mc.getWindow().getHeight(); if (w <= 0 || h <= 0) return; - ping = CombatantRenderSystem.resources().persistentFramebuffer("lovisual-visuals-ping", w, h, false, "CombatantVisuals"); - pong = CombatantRenderSystem.resources().persistentFramebuffer("lovisual-visuals-pong", w, h, false, "CombatantVisuals"); + ping = LoVisualRenderSystem.resources().persistentFramebuffer("lovisual-visuals-ping", w, h, false, "LoVisualVisuals"); + pong = LoVisualRenderSystem.resources().persistentFramebuffer("lovisual-visuals-pong", w, h, false, "LoVisualVisuals"); bufferW = w; bufferH = h; } @@ -170,9 +170,9 @@ public enum CombatantVisuals { FullScreenRenderer.ensureInit(); PostProcessUniforms.update(0.0f, 0.0f, 0.0f, 0.0f); - FullScreenRenderer.begin("Combatant Fullscreen Pass") + FullScreenRenderer.begin("LoVisual Fullscreen Pass") .attachment(dst) - .pipeline(CombatantRenderPipelines.DAMAGE_TINT) + .pipeline(LoVisualRenderPipelines.DAMAGE_TINT) .uniform("PostProcess", PostProcessUniforms.get()) .sampler("u_Texture", src, PostProcessManager.getSampler()) .end(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldBatcher.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldBatcher.java index aeb4c26..0f333de 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldBatcher.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldBatcher.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,7 +10,7 @@ package dev.loki.lovisual.render.engine.world; import com.mojang.blaze3d.pipeline.RenderPipeline; import net.minecraft.world.phys.Vec3; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.renderer.Renderer3D; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; @@ -72,7 +72,7 @@ public final class WorldBatcher { } private static Vec3 currentCameraAnchor() { - RenderFrameContext ctx = CombatantRenderSystem.currentContext(); + RenderFrameContext ctx = LoVisualRenderSystem.currentContext(); if (ctx != null && ctx.camera() != null && ctx.camera().position() != null) { return ctx.camera().position(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldCommandBuffer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldCommandBuffer.java index b3042d7..279765a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldCommandBuffer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldCommandBuffer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldDrawCommand.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldDrawCommand.java index 3237c92..77bdc58 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldDrawCommand.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldDrawCommand.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldPassCompiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldPassCompiler.java index 2b6c13f..068d737 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldPassCompiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldPassCompiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,7 +16,7 @@ import net.minecraft.client.Minecraft; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import dev.loki.lovisual.mixininterface.IMsaaTexture; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderFrameContext; import dev.loki.lovisual.render.engine.core.policy.DepthProvider; import dev.loki.lovisual.render.engine.depth.PreTranslucentDepth; @@ -31,7 +31,7 @@ import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import java.util.List; /** - * Converts world commands into RHI draw commands and submits them through CombatantRHI. + * Converts world commands into RHI draw commands and submits them through LoVisualRHI. */ public final class WorldPassCompiler { private final WorldRenderStats stats = new WorldRenderStats(); @@ -52,7 +52,7 @@ public final class WorldPassCompiler { public void submit(WorldCommandBuffer buffer, @Nullable RenderTarget framebuffer, @Nullable PoseStack matrices) { if (buffer == null || buffer.size() == 0) return; - RenderFrameContext ctx = CombatantRenderSystem.ensureFrameContext(); + RenderFrameContext ctx = LoVisualRenderSystem.ensureFrameContext(); RenderTarget target = framebuffer != null ? framebuffer : (ctx.framebuffer() != null ? ctx.framebuffer().mainFramebuffer() : null); @@ -110,9 +110,9 @@ public final class WorldPassCompiler { return; } - uploaded = CombatantRenderSystem.rhi().dynamicMeshes().upload(drawMesh); + uploaded = LoVisualRenderSystem.rhi().dynamicMeshes().upload(drawMesh); RenderPipelineSpec spec = RenderPipelineRegistry.global().require(drawPipeline); - RhiDrawCommand.Builder draw = RhiDrawCommand.builder("Combatant Renderer3D World Command") + RhiDrawCommand.Builder draw = RhiDrawCommand.builder("LoVisual Renderer3D World Command") .pipeline(drawPipeline) .pipelineSpec(spec) .colorAttachment(colorView) @@ -125,7 +125,7 @@ public final class WorldPassCompiler { bindWorldPolicy(ctx, spec, draw); command.bindings().applyTo(draw, mc); - CombatantRenderSystem.rhi().drawMesh(draw.build()); + LoVisualRenderSystem.rhi().drawMesh(draw.build()); uploaded = null; stats.submittedCommand(drawMesh.getVertexCount(), drawMesh.getIndicesCount()); } finally { @@ -191,8 +191,8 @@ public final class WorldPassCompiler { private static int samples(GpuTextureView view) { if (view == null || view.texture() == null) return 1; - return view.texture() instanceof IMsaaTexture msaa && msaa.combatant$isMsaa() - ? msaa.combatant$getSamples() + return view.texture() instanceof IMsaaTexture msaa && msaa.lovisual$isMsaa() + ? msaa.lovisual$getSamples() : 1; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldRenderStats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldRenderStats.java index e0607a5..64599f6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldRenderStats.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldRenderStats.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldRenderStatsSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldRenderStatsSnapshot.java index dba6727..a0fab8b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldRenderStatsSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldRenderStatsSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldWideLineMeshCompiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldWideLineMeshCompiler.java index 16b71f1..8f106b4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldWideLineMeshCompiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/engine/world/WorldWideLineMeshCompiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.engine.world; import com.mojang.blaze3d.pipeline.RenderPipeline; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; import java.nio.ByteBuffer; @@ -42,17 +42,17 @@ public enum WorldWideLineMeshCompiler { } public static RenderPipeline widePipeline(RenderPipeline source) { - if (source == CombatantRenderPipelines.WORLD_COLORED_LINES) { - return CombatantRenderPipelines.WORLD_WIDE_COLORED_LINES; + if (source == LoVisualRenderPipelines.WORLD_COLORED_LINES) { + return LoVisualRenderPipelines.WORLD_WIDE_COLORED_LINES; } - if (source == CombatantRenderPipelines.WORLD_COLORED_LINES_DEPTH) { - return CombatantRenderPipelines.WORLD_WIDE_COLORED_LINES_DEPTH; + if (source == LoVisualRenderPipelines.WORLD_COLORED_LINES_DEPTH) { + return LoVisualRenderPipelines.WORLD_WIDE_COLORED_LINES_DEPTH; } - if (source == CombatantRenderPipelines.WORLD_COLORED_LINES_LIQUID_BLEND) { - return CombatantRenderPipelines.WORLD_WIDE_COLORED_LINES_LIQUID_BLEND; + if (source == LoVisualRenderPipelines.WORLD_COLORED_LINES_LIQUID_BLEND) { + return LoVisualRenderPipelines.WORLD_WIDE_COLORED_LINES_LIQUID_BLEND; } - if (source == CombatantRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE) { - return CombatantRenderPipelines.WORLD_WIDE_COLORED_LINES_LIQUID_IGNORE; + if (source == LoVisualRenderPipelines.WORLD_COLORED_LINES_LIQUID_IGNORE) { + return LoVisualRenderPipelines.WORLD_WIDE_COLORED_LINES_LIQUID_IGNORE; } return null; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ClipFunction.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ClipFunction.java index 81ec67f..08ac87d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ClipFunction.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ClipFunction.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -7,7 +7,7 @@ package dev.loki.lovisual.render.helpers; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.renderer.Renderer2D; import dev.loki.lovisual.render.engine.renderer.ui.draw.*; import dev.loki.lovisual.render.engine.renderer.ui.draw.*; @@ -244,7 +244,7 @@ public enum ClipFunction { } private static ShapeClipBackend clipBackend() { - return CombatantRenderSystem.rhi().shapeClip(); + return LoVisualRenderSystem.rhi().shapeClip(); } private static int currentShapeReference() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/EffectIconRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/EffectIconRenderer.java index 03016e8..60e711d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/EffectIconRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/EffectIconRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/GuiSpriteBatch.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/GuiSpriteBatch.java index 7460150..fa446a4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/GuiSpriteBatch.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/GuiSpriteBatch.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/HeadAnchor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/HeadAnchor.java index 4c6a02a..79a40d8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/HeadAnchor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/HeadAnchor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/MatteHudStyle.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/MatteHudStyle.java index 2b1b8d2..f763793 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/MatteHudStyle.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/MatteHudStyle.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/Particle3D.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/Particle3D.java index a603766..b81f008 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/Particle3D.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/Particle3D.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ParticleTextureMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ParticleTextureMode.java index da89a93..88bdd7b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ParticleTextureMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ParticleTextureMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/PlayerHeadRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/PlayerHeadRenderer.java index 0c0388a..56e547d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/PlayerHeadRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/PlayerHeadRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -175,7 +175,7 @@ public enum PlayerHeadRenderer { } if (ctx instanceof IGuiGraphics accessor) { - accessor.combatant$runUnscaled(draw); + accessor.lovisual$runUnscaled(draw); return; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScissorFunction.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScissorFunction.java index 5cb586d..0777cf7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScissorFunction.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScissorFunction.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -160,7 +160,7 @@ public enum ScissorFunction { Renderer2D.flushBatch(Renderer2D.FlushReason.SCISSOR); if (appliedScissor != null) { - ((IGpuDevice) RenderSystem.getDevice()).combatant$popScissor(); + ((IGpuDevice) RenderSystem.getDevice()).lovisual$popScissor(); appliedScissor = null; } @@ -169,7 +169,7 @@ public enum ScissorFunction { throw new IllegalStateException("Attempted to apply empty scissor: " + next); } - ((IGpuDevice) RenderSystem.getDevice()).combatant$pushScissor(next.x, next.y, next.w, next.h); + ((IGpuDevice) RenderSystem.getDevice()).lovisual$pushScissor(next.x, next.y, next.w, next.h); appliedScissor = next; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScreenProjection.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScreenProjection.java index b5a4555..1a8c510 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScreenProjection.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScreenProjection.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,7 +15,7 @@ import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Vector4f; import dev.loki.lovisual.features.module.modules.visuals.AspectRatio; -import dev.loki.lovisual.render.engine.core.CombatantWorldMatrices; +import dev.loki.lovisual.render.engine.core.LoVisualWorldMatrices; /** * Helper for projecting world-space points into screen-space pixels. @@ -40,18 +40,18 @@ public enum ScreenProjection { if (mc == null || mc.player == null || mc.level == null || mc.getWindow() == null) return null; Camera cam = mc.gameRenderer.mainCamera(); - Vec3 camPos = CombatantWorldMatrices.cameraPosition(); + Vec3 camPos = LoVisualWorldMatrices.cameraPosition(); if (camPos == null) { camPos = cam.position(); } - Matrix4f view = CombatantWorldMatrices.positionMatrix(); + Matrix4f view = LoVisualWorldMatrices.positionMatrix(); if (view == null) { TMP_ROT.set(cam.rotation()).conjugate(); view = new Matrix4f().rotate(TMP_ROT); } - Matrix4f proj = CombatantWorldMatrices.frustumProjectionMatrix(); + Matrix4f proj = LoVisualWorldMatrices.frustumProjectionMatrix(); if (proj == null) { proj = currentRawCameraProjection(mc, cam); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScreenSpaceOverlay2D.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScreenSpaceOverlay2D.java index baf5290..52932c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScreenSpaceOverlay2D.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/ScreenSpaceOverlay2D.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SodiumMaterialFlags.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SodiumMaterialFlags.java index 3513dca..448ebfe 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SodiumMaterialFlags.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SodiumMaterialFlags.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SodiumSurfaceFlagContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SodiumSurfaceFlagContext.java index c9b2202..f000623 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SodiumSurfaceFlagContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SodiumSurfaceFlagContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SystemCursor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SystemCursor.java index 0ea4d99..61037da 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SystemCursor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/SystemCursor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.platform.cursor.CursorTypes; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; -import dev.loki.lovisual.render.engine.core.CombatantRenderSystem; +import dev.loki.lovisual.render.engine.core.LoVisualRenderSystem; import dev.loki.lovisual.render.engine.core.RenderFrameContext; public enum SystemCursor { @@ -90,7 +90,7 @@ public enum SystemCursor { } private static long currentRenderFrameId() { - RenderFrameContext context = CombatantRenderSystem.currentContext(); + RenderFrameContext context = LoVisualRenderSystem.currentContext(); return context != null ? context.frameId() : Long.MIN_VALUE; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/TickDelta.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/TickDelta.java index 710616e..a95c2f5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/TickDelta.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/TickDelta.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/TrailPoint.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/TrailPoint.java index e15ba10..348e218 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/TrailPoint.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/helpers/TrailPoint.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityFeature.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityFeature.java index ef71e69..691a9c7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityFeature.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityFeature.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityGuards.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityGuards.java index 1ebe1be..23c8589 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityGuards.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityGuards.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -9,13 +9,13 @@ package dev.loki.lovisual.render.iris; import dev.loki.lovisual.features.module.Modules; import dev.loki.lovisual.features.module.modules.visuals.MotionBlur; -import dev.loki.lovisual.runtime.RuntimeGate; +import dev.loki.lovisual.Lifecycle; public enum IrisCompatibilityGuards { ; public static boolean suppressShaderpackMotionBlur() { - if (!RuntimeGate.canRunShaderBridge()) return false; + if (!Lifecycle.canRunShaderBridge()) return false; MotionBlur module = Modules.get(MotionBlur.class); return IrisRuntime.isShaderpackRendererActive() && IrisRuntime.supports(IrisCompatibilityFeature.MOTION_BLUR_POLICY) @@ -23,8 +23,8 @@ public enum IrisCompatibilityGuards { && module.isActive(); } - public static boolean suppressCombatantTerrainShaderOverrides() { - if (!RuntimeGate.canRunShaderBridge()) return false; + public static boolean suppressLoVisualTerrainShaderOverrides() { + if (!Lifecycle.canRunShaderBridge()) return false; return IrisRuntime.isModLoaded(); } @@ -36,7 +36,7 @@ public enum IrisCompatibilityGuards { } public static boolean deferIrisFinalizationForSecondHandScene() { - if (!RuntimeGate.canRunShaderBridge()) return false; + if (!Lifecycle.canRunShaderBridge()) return false; return IrisRuntime.isShaderpackRendererActive(); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityProfile.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityProfile.java index 80ee06a..19b25a3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityProfile.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityProfile.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityProfiles.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityProfiles.java index ede0773..adebd83 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityProfiles.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCompatibilityProfiles.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisFinalizedSceneRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisFinalizedSceneRenderer.java index 8d4c317..ed327d1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisFinalizedSceneRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisFinalizedSceneRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,5 +10,5 @@ package dev.loki.lovisual.render.iris; import net.minecraft.client.DeltaTracker; public interface IrisFinalizedSceneRenderer { - void combatant$renderAfterIrisFinalization(DeltaTracker tickCounter); + void lovisual$renderAfterIrisFinalization(DeltaTracker tickCounter); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisHandMaskState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisHandMaskState.java index 6174fa0..dc4cb06 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisHandMaskState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisHandMaskState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCombatantFrameHooks.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisLoVisualFrameHooks.java similarity index 88% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCombatantFrameHooks.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisLoVisualFrameHooks.java index 0719d76..a054e12 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisCombatantFrameHooks.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisLoVisualFrameHooks.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import net.minecraft.client.DeltaTracker; import net.minecraft.client.Minecraft; import dev.loki.lovisual.util.logging.DebugLog; -public enum IrisCombatantFrameHooks { +public enum IrisLoVisualFrameHooks { ; private static DeltaTracker currentTickCounter; @@ -60,10 +60,10 @@ public enum IrisCombatantFrameHooks { rendering = true; if (!loggedFinalRender) { loggedFinalRender = true; - DebugLog.info("[IrisCompat] rendering Combatant after Iris final pass"); + DebugLog.info("[IrisCompat] rendering LoVisual after Iris final pass"); } try { - renderer.combatant$renderAfterIrisFinalization(currentTickCounter); + renderer.lovisual$renderAfterIrisFinalization(currentTickCounter); } finally { rendering = false; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntime.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntime.java index f2e66ee..3fb038c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntime.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntime.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -44,17 +44,17 @@ public enum IrisRuntime { return snapshot.modLoaded() && snapshot.apiAvailable() && snapshot.renderingShadowPass(); } - public static void registerCombatantPipelines() { + public static void registerLoVisualPipelines() { if (!FabricLoader.getInstance().isModLoaded("iris")) { return; } try { - IrisRuntimeBridge.registerCombatantPipelines(); + IrisRuntimeBridge.registerLoVisualPipelines(); } catch (LinkageError | RuntimeException t) { if (!loggedApiFailure) { loggedApiFailure = true; - DebugLog.warn("[IrisCompat] Combatant pipeline registration failed: " + t); + DebugLog.warn("[IrisCompat] LoVisual pipeline registration failed: " + t); } } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntimeBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntimeBridge.java index 26b4694..52a89a8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntimeBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntimeBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import net.irisshaders.iris.Iris; import net.irisshaders.iris.api.v0.IrisApi; import net.irisshaders.iris.api.v0.IrisProgram; -import dev.loki.lovisual.render.CombatantEntityRenderTypes; +import dev.loki.lovisual.render.LoVisualEntityRenderTypes; enum IrisRuntimeBridge { ; @@ -36,9 +36,9 @@ enum IrisRuntimeBridge { ); } - static void registerCombatantPipelines() { + static void registerLoVisualPipelines() { IrisApi api = IrisApi.getInstance(); - java.util.List pipelines = CombatantEntityRenderTypes.irisMappedPipelines(); + java.util.List pipelines = LoVisualEntityRenderTypes.irisMappedPipelines(); for (RenderPipeline pipeline : pipelines) { assign(api, pipeline, IrisProgram.ENTITIES_TRANSLUCENT); } @@ -59,7 +59,7 @@ enum IrisRuntimeBridge { return api.getConfig().areShadersEnabled(); } } catch (LinkageError | RuntimeException ignored) { - // Iris can expose a not-yet-initialized config during early Combatant module/config loading. + // Iris can expose a not-yet-initialized config during early LoVisual module/config loading. } return shaderpackInUse; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntimeSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntimeSnapshot.java index a33d0c3..ee6e9bc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntimeSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisRuntimeSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisSceneDepth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisSceneDepth.java index dc953bc..569a72f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisSceneDepth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisSceneDepth.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,7 +13,7 @@ import com.mojang.blaze3d.textures.GpuTextureView; import net.irisshaders.iris.targets.RenderTargets; /** - * Read-only views of the resolved Iris scene depth used by Combatant postprocess passes. + * Read-only views of the resolved Iris scene depth used by LoVisual postprocess passes. */ public enum IrisSceneDepth { ; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisSecondHandScene.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisSecondHandScene.java index 876611e..8cd8c73 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisSecondHandScene.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/IrisSecondHandScene.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/CombatantIrisUniforms.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/LoVisualIrisUniforms.java similarity index 67% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/CombatantIrisUniforms.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/LoVisualIrisUniforms.java index fb65d91..d7b65ec 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/CombatantIrisUniforms.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/LoVisualIrisUniforms.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,32 +20,32 @@ import dev.loki.lovisual.render.engine.RenderState; import dev.loki.lovisual.render.engine.light.LightmapState; import dev.loki.lovisual.util.logging.DebugLog; -public enum CombatantIrisUniforms { +public enum LoVisualIrisUniforms { ; private static boolean loggedRegistration; public static void add(UniformHolder uniforms) { if (!loggedRegistration) { loggedRegistration = true; - DebugLog.renderThread("[IrisPatch] registering Combatant Iris uniforms"); + DebugLog.renderThread("[IrisPatch] registering LoVisual Iris uniforms"); } uniforms - .uniform1b(UniformUpdateFrequency.PER_FRAME, "combatantFullbrightEnabled", CombatantIrisUniforms::fullbrightEnabled) - .uniform1f(UniformUpdateFrequency.PER_FRAME, "combatantFullbrightMinLight", CombatantIrisUniforms::fullbrightMinLight) - .uniform1f(UniformUpdateFrequency.PER_FRAME, "combatantAmbientLight", LightmapState::getAmbient) - .uniform1f(UniformUpdateFrequency.PER_FRAME, "combatantBaseAmbientLight", LightmapState::getBaseAmbient) - .uniform1f(UniformUpdateFrequency.PER_FRAME, "combatantOverrideAmbientLight", CombatantIrisUniforms::overrideAmbient) - .uniform1b(UniformUpdateFrequency.PER_FRAME, "combatantWorldTweaksFogControl", CombatantIrisUniforms::fogControlEnabled) - .uniform1b(UniformUpdateFrequency.PER_FRAME, "combatantWorldTweaksFogModify", CombatantIrisUniforms::fogModifyEnabled) - .uniform1f(UniformUpdateFrequency.PER_FRAME, "combatantWorldTweaksFogStart", CombatantIrisUniforms::fogStart) - .uniform1f(UniformUpdateFrequency.PER_FRAME, "combatantWorldTweaksFogEnd", CombatantIrisUniforms::fogEnd) - .uniform3f(UniformUpdateFrequency.PER_FRAME, "combatantWorldTweaksFogColor", CombatantIrisUniforms::fogColor) - .uniform1i(UniformUpdateFrequency.PER_FRAME, "combatantWorldTweaksFogDisableMask", CombatantIrisUniforms::fogDisableMask) - .uniform1i(UniformUpdateFrequency.PER_FRAME, "combatantEyeInWater", CombatantIrisUniforms::eyeInWater) - .uniform1b(UniformUpdateFrequency.PER_FRAME, "combatantWorldTweaksTimeOverride", CombatantIrisUniforms::timeOverride) - .uniform1i(UniformUpdateFrequency.PER_FRAME, "combatantWorldTweaksTimeTicks", CombatantIrisUniforms::timeTicks) - .uniform1i(UniformUpdateFrequency.PER_FRAME, "combatantWorldTweaksWeatherMode", CombatantIrisUniforms::weatherMode) - .uniform1b(UniformUpdateFrequency.PER_FRAME, "combatantSuppressShaderpackMotionBlur", IrisCompatibilityGuards::suppressShaderpackMotionBlur); + .uniform1b(UniformUpdateFrequency.PER_FRAME, "lovisualFullbrightEnabled", LoVisualIrisUniforms::fullbrightEnabled) + .uniform1f(UniformUpdateFrequency.PER_FRAME, "lovisualFullbrightMinLight", LoVisualIrisUniforms::fullbrightMinLight) + .uniform1f(UniformUpdateFrequency.PER_FRAME, "lovisualAmbientLight", LightmapState::getAmbient) + .uniform1f(UniformUpdateFrequency.PER_FRAME, "lovisualBaseAmbientLight", LightmapState::getBaseAmbient) + .uniform1f(UniformUpdateFrequency.PER_FRAME, "lovisualOverrideAmbientLight", LoVisualIrisUniforms::overrideAmbient) + .uniform1b(UniformUpdateFrequency.PER_FRAME, "lovisualWorldTweaksFogControl", LoVisualIrisUniforms::fogControlEnabled) + .uniform1b(UniformUpdateFrequency.PER_FRAME, "lovisualWorldTweaksFogModify", LoVisualIrisUniforms::fogModifyEnabled) + .uniform1f(UniformUpdateFrequency.PER_FRAME, "lovisualWorldTweaksFogStart", LoVisualIrisUniforms::fogStart) + .uniform1f(UniformUpdateFrequency.PER_FRAME, "lovisualWorldTweaksFogEnd", LoVisualIrisUniforms::fogEnd) + .uniform3f(UniformUpdateFrequency.PER_FRAME, "lovisualWorldTweaksFogColor", LoVisualIrisUniforms::fogColor) + .uniform1i(UniformUpdateFrequency.PER_FRAME, "lovisualWorldTweaksFogDisableMask", LoVisualIrisUniforms::fogDisableMask) + .uniform1i(UniformUpdateFrequency.PER_FRAME, "lovisualEyeInWater", LoVisualIrisUniforms::eyeInWater) + .uniform1b(UniformUpdateFrequency.PER_FRAME, "lovisualWorldTweaksTimeOverride", LoVisualIrisUniforms::timeOverride) + .uniform1i(UniformUpdateFrequency.PER_FRAME, "lovisualWorldTweaksTimeTicks", LoVisualIrisUniforms::timeTicks) + .uniform1i(UniformUpdateFrequency.PER_FRAME, "lovisualWorldTweaksWeatherMode", LoVisualIrisUniforms::weatherMode) + .uniform1b(UniformUpdateFrequency.PER_FRAME, "lovisualSuppressShaderpackMotionBlur", IrisCompatibilityGuards::suppressShaderpackMotionBlur); } private static boolean fullbrightEnabled() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchCompiler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchCompiler.java index efe85ea..45811d6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchCompiler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchCompiler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -127,7 +127,7 @@ public enum ShaderPatchCompiler { } public static CompiledPatch compile(PatchProgram program, ImmutableList source, CompileMode mode, Set stages) throws CompileException { - if (mode == CompileMode.PREFLIGHT && !containsCombatantPayload(source)) { + if (mode == CompileMode.PREFLIGHT && !containsLoVisualPayload(source)) { validateNoSourceExcerpt(program, source); } @@ -572,9 +572,9 @@ public enum ShaderPatchCompiler { return comment >= 0 ? line.substring(0, comment) : line; } - private static boolean containsCombatantPayload(List source) { + private static boolean containsLoVisualPayload(List source) { for (String line : source) { - if (line.contains("combatant") || line.contains("COMBATANT_")) { + if (line.contains("lovisual") || line.contains("LOVISUAL_")) { return true; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchCompilerCli.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchCompilerCli.java index 30b1ef4..4124664 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchCompilerCli.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchCompilerCli.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchEngine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchEngine.java index 1b4669d..8f0e2c1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchEngine.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/iris/patch/ShaderPatchEngine.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -36,7 +36,7 @@ public enum ShaderPatchEngine { /** * Legacy validation session: all repository manifests are visible. Runtime Iris hooks should use - * {@link #newSession(String)} so Combatant does not probe unrelated shaderpacks. + * {@link #newSession(String)} so LoVisual does not probe unrelated shaderpacks. */ public static Session newSession() { Repository repository = repository(); @@ -210,7 +210,7 @@ public enum ShaderPatchEngine { target.marker); return patched; } catch (ShaderPatchCompiler.CompileException e) { - // Do not poison the whole manifest here. Actual source can already contain Combatant-owned + // 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()); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sky/CustomSkyboxRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sky/CustomSkyboxRenderer.java index 9a78b29..5f210ec 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sky/CustomSkyboxRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sky/CustomSkyboxRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -33,9 +33,9 @@ import dev.loki.lovisual.features.module.modules.visuals.ReimaginedVisual; import dev.loki.lovisual.mixins.accessors.GameRendererAccessor; import dev.loki.lovisual.mixins.accessors.LocalPlayerAccessor; import dev.loki.lovisual.render.engine.RenderState; -import dev.loki.lovisual.render.engine.core.CombatantWorldMatrices; +import dev.loki.lovisual.render.engine.core.LoVisualWorldMatrices; import dev.loki.lovisual.render.engine.animation.AnimationUtility; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.renderer.FullScreenRenderer; import dev.loki.lovisual.render.engine.renderer.MeshRenderer; import dev.loki.lovisual.render.engine.uniform.MeshBuilder; @@ -161,7 +161,7 @@ public enum CustomSkyboxRenderer { try { MeshRenderer.begin() .attachments(framebuffer) - .pipeline(CombatantRenderPipelines.WORLD_REIMAGINED_SKYBOX_SHADER) + .pipeline(LoVisualRenderPipelines.WORLD_REIMAGINED_SKYBOX_SHADER) .mesh(FullScreenRenderer.vbo, FullScreenRenderer.ibo) .uniform("Fog", fog) .uniform("SkyboxShader", SkyboxShaderUniforms.get()) @@ -185,7 +185,7 @@ public enum CustomSkyboxRenderer { } private static Matrix4f buildWorldProjection(Minecraft mc, Camera camera, float fov, float tickDelta) { - Matrix4f capturedProjection = CombatantWorldMatrices.renderProjectionMatrix(); + Matrix4f capturedProjection = LoVisualWorldMatrices.renderProjectionMatrix(); if (capturedProjection != null) { return capturedProjection; } @@ -228,8 +228,8 @@ public enum CustomSkyboxRenderer { if (player instanceof LocalPlayerAccessor playerAccessor) { nauseaIntensity = Mth.lerp( tickDelta, - playerAccessor.combatant$getLastNauseaIntensity(), - playerAccessor.combatant$getNauseaIntensity() + playerAccessor.lovisual$getLastNauseaIntensity(), + playerAccessor.lovisual$getNauseaIntensity() ); } @@ -240,7 +240,7 @@ public enum CustomSkyboxRenderer { float scale = 5.0f / (strength * strength + 5.0f) - strength * 0.04f; scale *= scale; Vector3f axis = new Vector3f(0.0f, Mth.SQRT_OF_TWO / 2.0f, Mth.SQRT_OF_TWO / 2.0f); - float angle = (accessor.combatant$getNauseaEffectTime() + tickDelta * accessor.combatant$getNauseaEffectSpeed()) + float angle = (accessor.lovisual$getNauseaEffectTime() + tickDelta * accessor.lovisual$getNauseaEffectSpeed()) * Mth.DEG_TO_RAD; projection.rotate(angle, axis); projection.scale(1.0f / scale, 1.0f, 1.0f); @@ -329,7 +329,7 @@ public enum CustomSkyboxRenderer { float coreStrength = Mth.clamp(1.10f * sunIntensitySetting * rainFade, 0.0f, 2.2f); float rayStrength = 0.0f; - MeshBuilder mesh = new MeshBuilder(CombatantRenderPipelines.WORLD_SKY_SUN); + MeshBuilder mesh = new MeshBuilder(LoVisualRenderPipelines.WORLD_SKY_SUN); mesh.begin(); mesh.ensureQuadCapacity(); int i1 = mesh.vec3(center.x - right.x * radius - up.x * radius, center.y - right.y * radius - up.y * radius, center.z - right.z * radius - up.z * radius) @@ -346,7 +346,7 @@ public enum CustomSkyboxRenderer { SkySunUniforms.update(innerRatio, haloStrength, coreStrength, rayStrength); MeshRenderer.begin() .attachments(framebuffer) - .pipeline(CombatantRenderPipelines.WORLD_SKY_SUN) + .pipeline(LoVisualRenderPipelines.WORLD_SKY_SUN) .mesh(mesh) .uniform("SkySun", SkySunUniforms.get()) .end(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumFrameContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumFrameContext.java index 8351fb8..558192d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumFrameContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumFrameContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.sodium; /** - * Captured Sodium world-renderer state for the current Combatant frame. + * Captured Sodium world-renderer state for the current LoVisual frame. */ public record SodiumFrameContext(boolean available, boolean terrainRenderComplete, diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumRenderBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumRenderBridge.java index 2b4f334..ce47585 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumRenderBridge.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumRenderBridge.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,7 @@ import net.minecraft.world.phys.AABB; import dev.loki.lovisual.render.engine.core.policy.VisibilityQuery; /** - * Single Combatant entry point to Sodium runtime state. + * Single LoVisual entry point to Sodium runtime state. *

* Renderers/modules must not call Sodium internals directly. The only allowed consumers are: * - this bridge; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumSectionVisibilityProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumSectionVisibilityProvider.java index 29c02f5..142e5dc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumSectionVisibilityProvider.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumSectionVisibilityProvider.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumShaderWorkarounds.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumShaderWorkarounds.java index e45c615..5f2957f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumShaderWorkarounds.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumShaderWorkarounds.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,23 +13,23 @@ import dev.loki.lovisual.util.logging.DebugLog; /** * Sodium shader override/workaround registry. *

- * Sodium 26.2 compiles terrain through Mojang RenderPipeline, so Combatant must + * Sodium 26.2 compiles terrain through Mojang RenderPipeline, so LoVisual must * redirect shader identifiers and let vanilla ShaderManager load/preprocess the * .vsh/.fsh resources. Do not read shader source manually here; that bypasses * vanilla defines/import handling and breaks Vulkan parity. */ public final class SodiumShaderWorkarounds { private static final Identifier SODIUM_BLOCK_LAYER_OPAQUE = Identifier.fromNamespaceAndPath("sodium", "blocks/block_layer_opaque"); - private static final Identifier COMBATANT_BLOCK_LAYER_OPAQUE = Identifier.fromNamespaceAndPath("lovisual", "sodium/block_layer_opaque"); + private static final Identifier LOVISUAL_BLOCK_LAYER_OPAQUE = Identifier.fromNamespaceAndPath("lovisual", "sodium/block_layer_opaque"); private long overrideHits; public Identifier overrideShaderIdentifier(Identifier id) { if (id == null) return null; if (SODIUM_BLOCK_LAYER_OPAQUE.equals(id)) { overrideHits++; - DebugLog.infoOnChange("sodium.shader.override.block_layer_opaque", "combatant", - "[SODIUM] Combatant Sodium RenderPipeline shader override applied for %s", id); - return COMBATANT_BLOCK_LAYER_OPAQUE; + DebugLog.infoOnChange("sodium.shader.override.block_layer_opaque", "lovisual", + "[SODIUM] LoVisual Sodium RenderPipeline shader override applied for %s", id); + return LOVISUAL_BLOCK_LAYER_OPAQUE; } return id; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumTerrainInterop.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumTerrainInterop.java index d3e88ef..07479f5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumTerrainInterop.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumTerrainInterop.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -8,7 +8,7 @@ package dev.loki.lovisual.render.sodium; /** - * Central terrain interop state for Sodium mixins and Combatant render code. + * Central terrain interop state for Sodium mixins and LoVisual render code. */ public final class SodiumTerrainInterop { private final SodiumRenderBridge bridge; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumTerrainInteropStatsSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumTerrainInteropStatsSnapshot.java index f14ade5..3b3298b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumTerrainInteropStatsSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumTerrainInteropStatsSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumVisibilityStatsSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumVisibilityStatsSnapshot.java index 428485e..4e3a2ad 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumVisibilityStatsSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/SodiumVisibilityStatsSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantChunkVertexExtension.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantChunkVertexExtension.java deleted file mode 100644 index ee847dd..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantChunkVertexExtension.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.render.sodium.terrain; - -public interface CombatantChunkVertexExtension { - void combatant$setSurfaceFlags(int surfaceFlags); - - int combatant$getSurfaceFlags(); - - void combatant$copyData(CombatantChunkVertexExtension dest); -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantChunkMeshAttributes.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualChunkMeshAttributes.java similarity index 69% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantChunkMeshAttributes.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualChunkMeshAttributes.java index 0f92a47..cb27669 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantChunkMeshAttributes.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualChunkMeshAttributes.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -9,12 +9,12 @@ package dev.loki.lovisual.render.sodium.terrain; /** * Sodium 26.2 uses Mojang VertexFormat/GpuFormat attributes instead of the old - * net.caffeinemc.mods.sodium.client.gl.attribute layer. Keep the Combatant + * net.caffeinemc.mods.sodium.client.gl.attribute layer. Keep the LoVisual * terrain attribute name centralized because Vulkan reflection matches shader * inputs by attribute name. */ -public enum CombatantChunkMeshAttributes { +public enum LoVisualChunkMeshAttributes { ; - public static final String SURFACE_FLAGS = "a_CombatantSurfaceFlags"; + public static final String SURFACE_FLAGS = "a_LoVisualSurfaceFlags"; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantChunkMeshFormats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualChunkMeshFormats.java similarity index 56% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantChunkMeshFormats.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualChunkMeshFormats.java index d9ff4e3..bb4640f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantChunkMeshFormats.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualChunkMeshFormats.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -9,8 +9,8 @@ package dev.loki.lovisual.render.sodium.terrain; import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; -public enum CombatantChunkMeshFormats { +public enum LoVisualChunkMeshFormats { ; - public static final ChunkVertexType SURFACE_FLAGS = new CombatantModelVertexType(); + public static final ChunkVertexType SURFACE_FLAGS = new LoVisualModelVertexType(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualChunkVertexExtension.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualChunkVertexExtension.java new file mode 100644 index 0000000..d954e35 --- /dev/null +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualChunkVertexExtension.java @@ -0,0 +1,16 @@ +/* + * 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.render.sodium.terrain; + +public interface LoVisualChunkVertexExtension { + void lovisual$setSurfaceFlags(int surfaceFlags); + + int lovisual$getSurfaceFlags(); + + void lovisual$copyData(LoVisualChunkVertexExtension dest); +} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantModelVertexType.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualModelVertexType.java similarity index 81% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantModelVertexType.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualModelVertexType.java index 6c3ce24..a576372 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantModelVertexType.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualModelVertexType.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -19,7 +19,7 @@ import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexT * GlVertexFormat/ChunkShaderBindingPoints path is gone. Attribute names must * match the GLSL input names exactly for Vulkan SPIR-V reflection. */ -public final class CombatantModelVertexType implements ChunkVertexType { +public final class LoVisualModelVertexType implements ChunkVertexType { public static final int STRIDE = 24; public static final int SURFACE_FLAGS_OFFSET = 20; @@ -28,7 +28,7 @@ public final class CombatantModelVertexType implements ChunkVertexType { .addAttribute("a_Color", GpuFormat.RGBA8_UNORM) .addAttribute("a_TexCoord", GpuFormat.RG16_UINT) .addAttribute("a_LightAndData", GpuFormat.RGBA8_UINT) - .addAttribute(CombatantChunkMeshAttributes.SURFACE_FLAGS, GpuFormat.R32_UINT) + .addAttribute(LoVisualChunkMeshAttributes.SURFACE_FLAGS, GpuFormat.R32_UINT) .build(); @Override @@ -38,6 +38,6 @@ public final class CombatantModelVertexType implements ChunkVertexType { @Override public ChunkVertexEncoder getEncoder() { - return new CombatantTerrainVertex(STRIDE, SURFACE_FLAGS_OFFSET); + return new LoVisualTerrainVertex(STRIDE, SURFACE_FLAGS_OFFSET); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantTerrainVertex.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualTerrainVertex.java similarity index 93% rename from combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantTerrainVertex.java rename to combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualTerrainVertex.java index 3dbe920..36430c2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/CombatantTerrainVertex.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/render/sodium/terrain/LoVisualTerrainVertex.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * The terrain vertex layout was implemented with reference to Sodium's @@ -17,7 +17,7 @@ import net.minecraft.util.Mth; import org.lwjgl.system.MemoryUtil; // Credit: based on Sodium's CompactChunkVertex packing, with the Iris-style idea of appending extra terrain attributes. -public final class CombatantTerrainVertex implements ChunkVertexEncoder { +public final class LoVisualTerrainVertex implements ChunkVertexEncoder { private static final int POSITION_MAX_VALUE = 1 << 20; private static final int TEXTURE_MAX_VALUE = 1 << 15; private static final float MODEL_ORIGIN = 8.0f; @@ -26,7 +26,7 @@ public final class CombatantTerrainVertex implements ChunkVertexEncoder { private final int stride; private final int surfaceFlagsOffset; - public CombatantTerrainVertex(int stride, int surfaceFlagsOffset) { + public LoVisualTerrainVertex(int stride, int surfaceFlagsOffset) { this.stride = stride; this.surfaceFlagsOffset = surfaceFlagsOffset; } @@ -106,7 +106,7 @@ public final class CombatantTerrainVertex implements ChunkVertexEncoder { MemoryUtil.memPutInt(ptr + 8L, ColorARGB.mulRGB(vertex.color, vertex.ao)); MemoryUtil.memPutInt(ptr + 12L, packTexture(u, v)); MemoryUtil.memPutInt(ptr + 16L, packLightAndData(light, materialBits, sectionIndex)); - MemoryUtil.memPutInt(ptr + this.surfaceFlagsOffset, ((CombatantChunkVertexExtension) vertex).combatant$getSurfaceFlags()); + MemoryUtil.memPutInt(ptr + this.surfaceFlagsOffset, ((LoVisualChunkVertexExtension) vertex).lovisual$getSurfaceFlags()); ptr += this.stride; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/ClientRuntime.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/ClientRuntime.java deleted file mode 100644 index 62ffd76..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/ClientRuntime.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime; - -import dev.loki.lovisual.runtime.loader.*; -import dev.loki.lovisual.runtime.loader.*; -import dev.loki.lovisual.util.logging.DebugLog; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.IntSupplier; - -public enum ClientRuntime { - ; - private static final AtomicReference STATE = - new AtomicReference<>(ClientRuntimeState.BOOTING); - private static final CopyOnWriteArrayList PARTICIPANTS = - new CopyOnWriteArrayList<>(); - private static final CopyOnWriteArrayList RESUME_PARTICIPANTS = - new CopyOnWriteArrayList<>(); - - private static volatile LoaderBridge loaderBridge = new StandardFabricLoaderBridge(); - private static volatile RuntimeSourcePolicy sourcePolicy = new RuntimeGateSourcePolicy(); - private static volatile JarReplacementCoordinator jarReplacementCoordinator = - new PanicOnlyJarReplacementCoordinator(); - private static volatile RuntimeCleanupReport lastCleanupReport; - private static volatile boolean restartRequired; - private static volatile IntSupplier callbackCounter = () -> 0; - private static volatile IntSupplier moduleCounter = () -> 0; - private static volatile IntSupplier addonCounter = () -> 0; - - public static ClientRuntimeState state() { - return STATE.get(); - } - - public static void markActive(String reason) { - while (true) { - ClientRuntimeState current = STATE.get(); - if (current == ClientRuntimeState.JAR_REPLACEMENT_PANIC - || current == ClientRuntimeState.DEAD - || current == ClientRuntimeState.SHUTDOWN_PENDING) { - return; - } - if (STATE.compareAndSet(current, ClientRuntimeState.ACTIVE)) { - DebugLog.info("Runtime state %s -> ACTIVE (%s)", current, safeReason(reason)); - return; - } - } - } - - public static boolean enterSoftPanic(String reason) { - if (!STATE.compareAndSet(ClientRuntimeState.ACTIVE, ClientRuntimeState.SOFT_PANIC)) { - return false; - } - lastCleanupReport = runParticipants(ClientRuntimeState.SOFT_PANIC, safeReason(reason)); - DebugLog.warn("Soft panic entered: %s", lastCleanupReport.summaryLine()); - return true; - } - - public static boolean exitSoftPanic(String reason) { - if (!STATE.compareAndSet(ClientRuntimeState.SOFT_PANIC, ClientRuntimeState.ACTIVE)) { - return false; - } - runResumeParticipants(safeReason(reason)); - DebugLog.info("Soft panic exited (%s)", safeReason(reason)); - return true; - } - - public static boolean toggleSoftPanic(String reason) { - ClientRuntimeState current = STATE.get(); - if (current == ClientRuntimeState.ACTIVE) { - return enterSoftPanic(reason); - } - if (current == ClientRuntimeState.SOFT_PANIC) { - return exitSoftPanic(reason); - } - return false; - } - - public static boolean prepareJarReplacement(String reason) { - ClientRuntimeState current = STATE.get(); - if (current == ClientRuntimeState.JAR_REPLACEMENT_PANIC || current == ClientRuntimeState.DEAD) { - restartRequired = true; - return false; - } - if (current == ClientRuntimeState.SHUTDOWN_PENDING) { - return false; - } - if (!jarReplacementCoordinator.canPrepareReplacement()) { - return false; - } - if (!STATE.compareAndSet(current, ClientRuntimeState.JAR_REPLACEMENT_PANIC)) { - return prepareJarReplacement(reason); - } - - restartRequired = true; - String safeReason = safeReason(reason); - jarReplacementCoordinator.prepareReplacement(safeReason); - lastCleanupReport = runParticipants(ClientRuntimeState.JAR_REPLACEMENT_PANIC, safeReason); - DebugLog.warn("JAR replacement panic entered: %s", lastCleanupReport.summaryLine()); - DebugLog.warn("Client is fully disabled for safe JAR replacement. Restart Minecraft to use the new JAR."); - return true; - } - - public static void requestRestart(String reason) { - restartRequired = true; - DebugLog.warn("Runtime restart requested (%s)", safeReason(reason)); - } - - public static void markDead(String reason) { - STATE.set(ClientRuntimeState.DEAD); - restartRequired = true; - DebugLog.warn("Runtime marked DEAD (%s)", safeReason(reason)); - } - - public static void registerParticipant(RuntimeShutdownParticipant participant) { - if (participant == null) return; - for (RuntimeShutdownParticipant existing : PARTICIPANTS) { - if (existing.id().equals(participant.id())) return; - } - PARTICIPANTS.add(participant); - } - - public static void registerResumeParticipant(RuntimeResumeParticipant participant) { - if (participant == null) return; - for (RuntimeResumeParticipant existing : RESUME_PARTICIPANTS) { - if (existing.id().equals(participant.id())) return; - } - RESUME_PARTICIPANTS.add(participant); - } - - public static RuntimeDiagnostics diagnostics() { - return new RuntimeDiagnostics( - state(), - RuntimeGate.canRunModules(), - RuntimeGate.canRunRender(), - RuntimeGate.canRunHud(), - RuntimeGate.canRunShaderBridge(), - RuntimeGate.isJarReplacementMode(), - restartRequired || jarReplacementCoordinator.requiresRestart(), - safeCount(callbackCounter), - safeCount(moduleCounter), - safeCount(addonCounter), - lastCleanupReport - ); - } - - public static LoaderBridge loaderBridge() { - return loaderBridge; - } - - public static void setLoaderBridge(LoaderBridge bridge) { - if (bridge != null) loaderBridge = bridge; - } - - public static RuntimeSourcePolicy sourcePolicy() { - return sourcePolicy; - } - - public static void setSourcePolicy(RuntimeSourcePolicy policy) { - if (policy != null) sourcePolicy = policy; - } - - public static JarReplacementCoordinator jarReplacementCoordinator() { - return jarReplacementCoordinator; - } - - public static void setJarReplacementCoordinator(JarReplacementCoordinator coordinator) { - if (coordinator != null) jarReplacementCoordinator = coordinator; - } - - public static void setCallbackCounter(IntSupplier counter) { - callbackCounter = counter != null ? counter : () -> 0; - } - - public static void setModuleCounter(IntSupplier counter) { - moduleCounter = counter != null ? counter : () -> 0; - } - - public static void setAddonCounter(IntSupplier counter) { - addonCounter = counter != null ? counter : () -> 0; - } - - private static RuntimeCleanupReport runParticipants(ClientRuntimeState targetState, String reason) { - RuntimeCleanupReport.Builder builder = RuntimeCleanupReport.builder(targetState, reason); - RuntimeShutdownContext context = new RuntimeShutdownContext(targetState, reason, builder); - List participants = new ArrayList<>(PARTICIPANTS); - for (RuntimeShutdownParticipant participant : participants) { - try { - participant.shutdown(context); - context.stopped(participant.id()); - } catch (Throwable t) { - context.failed(participant.id(), t); - DebugLog.error("Runtime shutdown participant failed: %s", t, participant.id()); - } - } - return builder.build(); - } - - private static void runResumeParticipants(String reason) { - for (RuntimeResumeParticipant participant : new ArrayList<>(RESUME_PARTICIPANTS)) { - try { - participant.resume(reason); - } catch (Throwable t) { - DebugLog.error("Runtime resume participant failed: %s", t, participant.id()); - } - } - } - - private static String safeReason(String reason) { - return reason == null || reason.isBlank() ? "unspecified" : reason; - } - - private static int safeCount(IntSupplier supplier) { - try { - return Math.max(0, supplier.getAsInt()); - } catch (Throwable ignored) { - return 0; - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/ClientRuntimeState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/ClientRuntimeState.java deleted file mode 100644 index eb89673..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/ClientRuntimeState.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime; - -public enum ClientRuntimeState { - BOOTING, - ACTIVE, - SOFT_PANIC, - JAR_REPLACEMENT_PANIC, - SHUTDOWN_PENDING, - DEAD -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeCleanupReport.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeCleanupReport.java deleted file mode 100644 index 4b59a2d..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeCleanupReport.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -public final class RuntimeCleanupReport { - private final ClientRuntimeState state; - private final String reason; - private final Map counters; - private final List stoppedSubsystems; - private final List failedSubsystems; - - private RuntimeCleanupReport(ClientRuntimeState state, - String reason, - Map counters, - List stoppedSubsystems, - List failedSubsystems) { - this.state = state; - this.reason = reason; - this.counters = Map.copyOf(counters); - this.stoppedSubsystems = List.copyOf(stoppedSubsystems); - this.failedSubsystems = List.copyOf(failedSubsystems); - } - - static Builder builder(ClientRuntimeState state, String reason) { - return new Builder(state, reason); - } - - public ClientRuntimeState state() { - return state; - } - - public String reason() { - return reason; - } - - public Map counters() { - return counters; - } - - public List stoppedSubsystems() { - return stoppedSubsystems; - } - - public List failedSubsystems() { - return failedSubsystems; - } - - public String summaryLine() { - return "state=" + state - + ", reason=" + reason - + ", counters=" + counters - + ", stopped=" + stoppedSubsystems - + ", failed=" + failedSubsystems; - } - - static final class Builder { - private final ClientRuntimeState state; - private final String reason; - private final Map counters = new LinkedHashMap<>(); - private final List stoppedSubsystems = new ArrayList<>(); - private final List failedSubsystems = new ArrayList<>(); - - private Builder(ClientRuntimeState state, String reason) { - this.state = state; - this.reason = reason == null || reason.isBlank() ? "unspecified" : reason; - } - - void increment(String key, int amount) { - if (key == null || key.isBlank() || amount == 0) return; - counters.merge(key, amount, Integer::sum); - } - - void stopped(String subsystem) { - if (subsystem != null && !subsystem.isBlank()) { - stoppedSubsystems.add(subsystem); - } - } - - void failed(String subsystem, Throwable error) { - String name = subsystem == null || subsystem.isBlank() ? "" : subsystem; - failedSubsystems.add(error == null ? name : name + ": " + error.getClass().getSimpleName()); - } - - RuntimeCleanupReport build() { - return new RuntimeCleanupReport(state, reason, counters, stoppedSubsystems, failedSubsystems); - } - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeDiagnostics.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeDiagnostics.java deleted file mode 100644 index b9e54a8..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeDiagnostics.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime; - -import java.util.ArrayList; -import java.util.List; - -public final class RuntimeDiagnostics { - private final ClientRuntimeState state; - private final boolean canRunModules; - private final boolean canRunRender; - private final boolean canRunHud; - private final boolean canRunShaderBridge; - private final boolean jarReplacementMode; - private final boolean restartRequired; - private final int callbacksRegistered; - private final int modulesRegistered; - private final int addonsActive; - private final RuntimeCleanupReport lastCleanupReport; - - RuntimeDiagnostics(ClientRuntimeState state, - boolean canRunModules, - boolean canRunRender, - boolean canRunHud, - boolean canRunShaderBridge, - boolean jarReplacementMode, - boolean restartRequired, - int callbacksRegistered, - int modulesRegistered, - int addonsActive, - RuntimeCleanupReport lastCleanupReport) { - this.state = state; - this.canRunModules = canRunModules; - this.canRunRender = canRunRender; - this.canRunHud = canRunHud; - this.canRunShaderBridge = canRunShaderBridge; - this.jarReplacementMode = jarReplacementMode; - this.restartRequired = restartRequired; - this.callbacksRegistered = callbacksRegistered; - this.modulesRegistered = modulesRegistered; - this.addonsActive = addonsActive; - this.lastCleanupReport = lastCleanupReport; - } - - public ClientRuntimeState state() { - return state; - } - - public List lines() { - List out = new ArrayList<>(); - out.add("Runtime state: " + state); - out.add("Can run modules: " + canRunModules); - out.add("Can run render: " + canRunRender); - out.add("Can run HUD: " + canRunHud); - out.add("Can run shader bridge: " + canRunShaderBridge); - out.add("Callbacks active: " + callbacksRegistered); - out.add("Modules registered: " + modulesRegistered); - out.add("Addons active: " + addonsActive); - out.add("Jar replacement mode: " + jarReplacementMode); - out.add("Restart required: " + restartRequired); - if (lastCleanupReport != null) { - out.add("Last cleanup: " + lastCleanupReport.summaryLine()); - } - return out; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeGate.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeGate.java deleted file mode 100644 index ce53685..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeGate.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime; - -import dev.loki.lovisual.util.resources.RenderResourceReadiness; - -public enum RuntimeGate { - ; - - public static boolean canRunClientLogic() { - return ClientRuntime.state() == ClientRuntimeState.ACTIVE; - } - - public static boolean canRunRender() { - return canRunClientLogic() && RenderResourceReadiness.isReady(); - } - - public static boolean canRunModules() { - return canRunClientLogic(); - } - - public static boolean canRunHud() { - return canRunClientLogic() && RenderResourceReadiness.isReady(); - } - - public static boolean canRunShaderBridge() { - return canRunClientLogic() && RenderResourceReadiness.isReady(); - } - - public static boolean canRunRuntimeController() { - ClientRuntimeState state = ClientRuntime.state(); - return state == ClientRuntimeState.ACTIVE || state == ClientRuntimeState.SOFT_PANIC; - } - - public static boolean isPanic() { - ClientRuntimeState state = ClientRuntime.state(); - return state == ClientRuntimeState.SOFT_PANIC || state == ClientRuntimeState.JAR_REPLACEMENT_PANIC; - } - - public static boolean isJarReplacementMode() { - return ClientRuntime.state() == ClientRuntimeState.JAR_REPLACEMENT_PANIC - || ClientRuntime.state() == ClientRuntimeState.DEAD; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeResumeParticipant.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeResumeParticipant.java deleted file mode 100644 index b231af1..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeResumeParticipant.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime; - -public interface RuntimeResumeParticipant { - String id(); - - void resume(String reason) throws Exception; -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeShutdownContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeShutdownContext.java deleted file mode 100644 index a94c12b..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeShutdownContext.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime; - -public final class RuntimeShutdownContext { - private final ClientRuntimeState targetState; - private final String reason; - private final RuntimeCleanupReport.Builder report; - - RuntimeShutdownContext(ClientRuntimeState targetState, String reason, RuntimeCleanupReport.Builder report) { - this.targetState = targetState; - this.reason = reason == null || reason.isBlank() ? "unspecified" : reason; - this.report = report; - } - - public ClientRuntimeState targetState() { - return targetState; - } - - public String reason() { - return reason; - } - - public boolean jarReplacement() { - return targetState == ClientRuntimeState.JAR_REPLACEMENT_PANIC; - } - - public void increment(String key, int amount) { - report.increment(key, amount); - } - - public void stopped(String subsystem) { - report.stopped(subsystem); - } - - public void failed(String subsystem, Throwable error) { - report.failed(subsystem, error); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeShutdownParticipant.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeShutdownParticipant.java deleted file mode 100644 index cd39fbf..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/RuntimeShutdownParticipant.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime; - -public interface RuntimeShutdownParticipant { - String id(); - - void shutdown(RuntimeShutdownContext context) throws Exception; -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/JarReplacementCoordinator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/JarReplacementCoordinator.java deleted file mode 100644 index 29fbac4..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/JarReplacementCoordinator.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime.loader; - -public interface JarReplacementCoordinator { - boolean canPrepareReplacement(); - - void prepareReplacement(String reason); - - boolean requiresRestart(); -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/LoaderBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/LoaderBridge.java deleted file mode 100644 index 22b74ce..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/LoaderBridge.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime.loader; - -import java.nio.file.Path; - -public interface LoaderBridge { - boolean isStandardFabric(); - - boolean supportsSafeJarReplacement(); - - Path currentModJarPath(); - - String describeClassSource(String className); - - String describeResourceSource(String resourcePath); -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/PanicOnlyJarReplacementCoordinator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/PanicOnlyJarReplacementCoordinator.java deleted file mode 100644 index f32e96c..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/PanicOnlyJarReplacementCoordinator.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime.loader; - -public final class PanicOnlyJarReplacementCoordinator implements JarReplacementCoordinator { - private volatile boolean restartRequired; - - @Override - public boolean canPrepareReplacement() { - return true; - } - - @Override - public void prepareReplacement(String reason) { - restartRequired = true; - } - - @Override - public boolean requiresRestart() { - return restartRequired; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/RuntimeGateSourcePolicy.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/RuntimeGateSourcePolicy.java deleted file mode 100644 index 7932f04..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/RuntimeGateSourcePolicy.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime.loader; - -import dev.loki.lovisual.runtime.RuntimeGate; - -public final class RuntimeGateSourcePolicy implements RuntimeSourcePolicy { - @Override - public boolean mayLoadClientClass(String className) { - return !RuntimeGate.isJarReplacementMode(); - } - - @Override - public boolean mayLoadClientResource(String resourcePath) { - return !RuntimeGate.isJarReplacementMode(); - } - - @Override - public boolean isJarReplacementLocked() { - return RuntimeGate.isJarReplacementMode(); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/RuntimeSourcePolicy.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/RuntimeSourcePolicy.java deleted file mode 100644 index a63bfbe..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/RuntimeSourcePolicy.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime.loader; - -public interface RuntimeSourcePolicy { - boolean mayLoadClientClass(String className); - - boolean mayLoadClientResource(String resourcePath); - - boolean isJarReplacementLocked(); -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/StandardFabricLoaderBridge.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/StandardFabricLoaderBridge.java deleted file mode 100644 index 2d1b955..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/runtime/loader/StandardFabricLoaderBridge.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.runtime.loader; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import java.net.URL; -import java.nio.file.Path; -import java.util.Optional; - -public final class StandardFabricLoaderBridge implements LoaderBridge { - private static final String[] MOD_IDS = {"simplefullbright", "combatant"}; - - @Override - public boolean isStandardFabric() { - return true; - } - - @Override - public boolean supportsSafeJarReplacement() { - return false; - } - - @Override - public Path currentModJarPath() { - Optional container = currentContainer(); - if (container.isEmpty() || container.get().getRootPaths().isEmpty()) { - return null; - } - return container.get().getRootPaths().get(0); - } - - @Override - public String describeClassSource(String className) { - if (className == null || className.isBlank()) return ""; - String resource = className.replace('.', '/') + ".class"; - URL url = StandardFabricLoaderBridge.class.getClassLoader().getResource(resource); - return url == null ? "" : url.toString(); - } - - @Override - public String describeResourceSource(String resourcePath) { - if (resourcePath == null || resourcePath.isBlank()) return ""; - URL url = StandardFabricLoaderBridge.class.getClassLoader().getResource(resourcePath); - return url == null ? "" : url.toString(); - } - - private Optional currentContainer() { - FabricLoader loader = FabricLoader.getInstance(); - for (String id : MOD_IDS) { - Optional container = loader.getModContainer(id); - if (container.isPresent()) return container; - } - return Optional.empty(); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/FastFps.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/FastFps.java index fdf6266..bd6138d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/FastFps.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/FastFps.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/LegacyHudNotifier.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/LegacyHudNotifier.java index f2515c1..d75baf0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/LegacyHudNotifier.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/LegacyHudNotifier.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/NarratorBlocker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/NarratorBlocker.java index cf9f1c3..9d36632 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/NarratorBlocker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/NarratorBlocker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,7 +11,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.NarratorStatus; import net.minecraft.client.Options; import dev.loki.lovisual.config.MainConfig; -import dev.loki.lovisual.runtime.RuntimeGate; //Да ну нахуй эту залупу блять public enum NarratorBlocker { @@ -20,7 +19,7 @@ public enum NarratorBlocker { private static boolean applying; public static boolean isBlocked() { - return MainConfig.get().isNarratorDisabled() && !RuntimeGate.isPanic(); + return MainConfig.get().isNarratorDisabled(); } public static void enforce(Minecraft client) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/OmniItemUtils.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/OmniItemUtils.java index 223eb92..15264e1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/OmniItemUtils.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/OmniItemUtils.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/AimPointUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/AimPointUtil.java index c0a673d..ea16102 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/AimPointUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/AimPointUtil.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RequestHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RequestHandler.java index 326c6b0..176cd2c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RequestHandler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RequestHandler.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RestrictedSingleUseAction.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RestrictedSingleUseAction.java index 65ed19e..bb549b0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RestrictedSingleUseAction.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RestrictedSingleUseAction.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationManager.java index a66c359..6cf7b0a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationManager.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -73,7 +73,7 @@ public final class RotationManager { public static Rotation getPlayerLastRotation() { LocalPlayer player = player(); if (player instanceof ILocalPlayer access) { - return new Rotation(access.combatant$getLastYaw(), access.combatant$getLastPitch(), true); + return new Rotation(access.lovisual$getLastYaw(), access.lovisual$getLastPitch(), true); } if (player != null) { return new Rotation(player.getYRot(), player.getXRot(), true); @@ -350,7 +350,7 @@ public final class RotationManager { Rotation rotation = getMovementRotation(); if (rotation == null) return; - Vec3 velocity = EntityInvoker.combatant$movementInputToVelocity( + Vec3 velocity = EntityInvoker.lovisual$movementInputToVelocity( event.getMovementInput(), event.getSpeed(), rotation.yaw() diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationTarget.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationTarget.java index c3aac63..ddbe0af 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationTarget.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationTarget.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationUtil.java index 84d1bb3..d69494b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/RotationUtil.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/Rotation.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/Rotation.java index a71750d..f954f6d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/Rotation.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/Rotation.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/RotationDelta.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/RotationDelta.java index 310f9f6..90795a5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/RotationDelta.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/RotationDelta.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/RotationWithVector.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/RotationWithVector.java index 94e7b8a..e06d71a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/RotationWithVector.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/data/RotationWithVector.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/MovementCorrection.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/MovementCorrection.java index 1b4c73e..8e985d8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/MovementCorrection.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/MovementCorrection.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/FailRotationProcessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/FailRotationProcessor.java index c1dc955..cc91376 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/FailRotationProcessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/FailRotationProcessor.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/LazyAimProcessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/LazyAimProcessor.java index 9b1d2c1..3decec5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/LazyAimProcessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/LazyAimProcessor.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/MovingRotationProcessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/MovingRotationProcessor.java index c12be93..0ee4287 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/MovingRotationProcessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/MovingRotationProcessor.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/RotationProcessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/RotationProcessor.java index b155d54..3ec70da 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/RotationProcessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/RotationProcessor.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/ShakeAimProcessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/ShakeAimProcessor.java index ae8321b..0d728c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/ShakeAimProcessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/ShakeAimProcessor.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/SnapAssistAimProcessor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/SnapAssistAimProcessor.java index 9c2f8b3..aa48d1e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/SnapAssistAimProcessor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/SnapAssistAimProcessor.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/AngleSmooth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/AngleSmooth.java index 7cecbab..df2991b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/AngleSmooth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/AngleSmooth.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/FactorAngleSmooth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/FactorAngleSmooth.java index f6d53ed..9092089 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/FactorAngleSmooth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/FactorAngleSmooth.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/NoneAngleSmooth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/NoneAngleSmooth.java index 6c786b7..e17f06e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/NoneAngleSmooth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/NoneAngleSmooth.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/AccelerationAngleSmooth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/AccelerationAngleSmooth.java index bbe54d8..d23c611 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/AccelerationAngleSmooth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/AccelerationAngleSmooth.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/InterpolationAngleSmooth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/InterpolationAngleSmooth.java index 28ba917..2543f9e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/InterpolationAngleSmooth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/InterpolationAngleSmooth.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/LinearAngleSmooth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/LinearAngleSmooth.java index 022a1d2..31ce343 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/LinearAngleSmooth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/LinearAngleSmooth.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SigmoidAngleSmooth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SigmoidAngleSmooth.java index 2dbc695..4324b44 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SigmoidAngleSmooth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SigmoidAngleSmooth.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SmartAngleSmooth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SmartAngleSmooth.java index a564cb6..148f4b7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SmartAngleSmooth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SmartAngleSmooth.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SpookyAngleSmooth.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SpookyAngleSmooth.java index 3e0d9fd..32fcc71 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SpookyAngleSmooth.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/features/processors/anglesmooth/impl/SpookyAngleSmooth.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -17,8 +17,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.KillAura; import dev.loki.lovisual.util.aiming.RotationManager; import dev.loki.lovisual.util.aiming.RotationTarget; import dev.loki.lovisual.util.aiming.data.Rotation; @@ -188,8 +186,7 @@ public final class SpookyAngleSmooth extends AngleSmooth { float totalJitterYaw = currentJitterYaw + circleYaw; float totalJitterPitch = currentJitterPitch + circlePitch; - KillAura aura = Modules.get(KillAura.class); - if ((aura == null || !aura.isEnabled() || entity == null) && AttackPressing.INSTANCE.lastClickPassed() > 800L) { + if (entity == null && AttackPressing.INSTANCE.lastClickPassed() > 800L) { totalJitterYaw *= 0.3f; totalJitterPitch *= 0.3f; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/point/PointInsideBox.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/point/PointInsideBox.java index c2a2565..e398f59 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/point/PointInsideBox.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/point/PointInsideBox.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/point/PointTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/point/PointTracker.java index 1a8c039..4fe9e9a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/point/PointTracker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/point/PointTracker.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/preference/LeastDifferencePreference.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/preference/LeastDifferencePreference.java index a627999..69385c6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/preference/LeastDifferencePreference.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/preference/LeastDifferencePreference.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/preference/RotationPreference.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/preference/RotationPreference.java index 217b908..e7303f0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/preference/RotationPreference.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/preference/RotationPreference.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/raytrace/RotationRaytrace.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/raytrace/RotationRaytrace.java index aeab8d4..9f6b5f3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/raytrace/RotationRaytrace.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/aiming/raytrace/RotationRaytrace.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -28,7 +28,7 @@ import java.util.function.Consumer; /** * Rotation-aware raytracing helpers. *

- * Ported from LiquidBounce (CCBlueX), simplified for Combatant. + * Ported from LiquidBounce (CCBlueX), simplified for LoVisual. */ public enum RotationRaytrace { ; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockDeobfuscationScanner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockDeobfuscationScanner.java index 77ecace..28a8051 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockDeobfuscationScanner.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockDeobfuscationScanner.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockEspSodiumCandidateCollector.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockEspSodiumCandidateCollector.java index ef40ffe..c32f833 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockEspSodiumCandidateCollector.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockEspSodiumCandidateCollector.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockObservationHub.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockObservationHub.java index 242e4c6..89fc9c7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockObservationHub.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockObservationHub.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockOutlineRenderer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockOutlineRenderer.java index e59f341..7f06807 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockOutlineRenderer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockOutlineRenderer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockOutlineShapeMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockOutlineShapeMode.java index 73eb426..d0d2215 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockOutlineShapeMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockOutlineShapeMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockScanContext.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockScanContext.java index 005cae2..2b45e71 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockScanContext.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockScanContext.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockScanMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockScanMode.java index f1c87d5..ae8d2de 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockScanMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockScanMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockSearchUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockSearchUtil.java index 32d5839..c67643c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockSearchUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/BlockSearchUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/RenderSectionBlockScanner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/RenderSectionBlockScanner.java index 8605125..ef025fb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/RenderSectionBlockScanner.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/RenderSectionBlockScanner.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/WorldSectionBlockScanner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/WorldSectionBlockScanner.java index 798644d..08148ea 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/WorldSectionBlockScanner.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/WorldSectionBlockScanner.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/BedBlockUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/BedBlockUtil.java index e8a8478..807f89d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/BedBlockUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/BedBlockUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/BedwarsTeamColorUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/BedwarsTeamColorUtil.java index 6399e05..d530ec8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/BedwarsTeamColorUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/BedwarsTeamColorUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/SelfBedMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/SelfBedMode.java index a209a31..7e98959 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/SelfBedMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/SelfBedMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/SelfBedTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/SelfBedTracker.java index 8944aaf..d1ed089 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/SelfBedTracker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/bed/SelfBedTracker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/placer/BlockPlacer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/placer/BlockPlacer.java deleted file mode 100644 index c3f653a..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/placer/BlockPlacer.java +++ /dev/null @@ -1,486 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.util.block.placer; - -import dev.loki.lovisual.util.screen.ClientScreen; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.block.*; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.events.EventHandler; -import dev.loki.lovisual.events.Events; -import dev.loki.lovisual.events.impl.MovementInputEvent; -import dev.loki.lovisual.events.impl.PostPlayerUpdateEvent; -import dev.loki.lovisual.events.impl.RotationUpdateEvent; -import dev.loki.lovisual.features.module.Module; -import dev.loki.lovisual.util.aiming.RestrictedSingleUseAction; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.RotationTarget; -import dev.loki.lovisual.util.aiming.data.Rotation; -import dev.loki.lovisual.util.aiming.features.MovementCorrection; -import dev.loki.lovisual.util.block.scaffold.ScaffoldPlacementTarget; -import dev.loki.lovisual.util.block.scaffold.ScaffoldTargetFinder; -import dev.loki.lovisual.util.player.inventory.InventorySwap; - -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.BooleanSupplier; -import java.util.function.DoubleSupplier; -import java.util.function.IntSupplier; -import java.util.function.Supplier; - -public final class BlockPlacer { - - private final Minecraft mc = Minecraft.getInstance(); - - private final Module module; - private final Object requester; - private final SlotFinder slotFinder; - private final DoubleSupplier rangeSupplier; - private final DoubleSupplier wallRangeSupplier; - private final IntSupplier cooldownMinSupplier; - private final IntSupplier cooldownMaxSupplier; - private final IntSupplier slotResetDelayMinSupplier; - private final IntSupplier slotResetDelayMaxSupplier; - private final IntSupplier sneakTicksSupplier; - private final BooleanSupplier constructFailResultSupplier; - private final BooleanSupplier ignoreOpenInventorySupplier; - private final BooleanSupplier ignoreUsingItemSupplier; - private final Supplier rotationModeSupplier; - private final Supplier movementCorrectionSupplier; - private final int rotationPriority; - - private final LinkedHashMap blocks = new LinkedHashMap<>(); - private final LinkedHashSet inaccessible = new LinkedHashSet<>(); - - private boolean registered; - private int ticksToWait; - private boolean ranAction; - private int sneakTimes; - private PlacementPlan currentPlacement; - - public BlockPlacer( - Module module, - Object requester, - int rotationPriority, - SlotFinder slotFinder, - DoubleSupplier rangeSupplier, - DoubleSupplier wallRangeSupplier, - IntSupplier cooldownMinSupplier, - IntSupplier cooldownMaxSupplier, - IntSupplier slotResetDelayMinSupplier, - IntSupplier slotResetDelayMaxSupplier, - IntSupplier sneakTicksSupplier, - BooleanSupplier constructFailResultSupplier, - BooleanSupplier ignoreOpenInventorySupplier, - BooleanSupplier ignoreUsingItemSupplier, - Supplier rotationModeSupplier, - Supplier movementCorrectionSupplier - ) { - this.module = module; - this.requester = requester; - this.rotationPriority = rotationPriority; - this.slotFinder = slotFinder; - this.rangeSupplier = rangeSupplier; - this.wallRangeSupplier = wallRangeSupplier; - this.cooldownMinSupplier = cooldownMinSupplier; - this.cooldownMaxSupplier = cooldownMaxSupplier; - this.slotResetDelayMinSupplier = slotResetDelayMinSupplier; - this.slotResetDelayMaxSupplier = slotResetDelayMaxSupplier; - this.sneakTicksSupplier = sneakTicksSupplier; - this.constructFailResultSupplier = constructFailResultSupplier; - this.ignoreOpenInventorySupplier = ignoreOpenInventorySupplier; - this.ignoreUsingItemSupplier = ignoreUsingItemSupplier; - this.rotationModeSupplier = rotationModeSupplier; - this.movementCorrectionSupplier = movementCorrectionSupplier; - } - - private static int randomBetween(int a, int b) { - int min = Math.min(a, b); - int max = Math.max(a, b); - return min == max ? min : ThreadLocalRandom.current().nextInt(min, max + 1); - } - - private static boolean isInteractable(BlockState state) { - if (state == null) { - return false; - } - - Block block = state.getBlock(); - return block instanceof BedBlock - || block instanceof ButtonBlock - || block instanceof LeverBlock - || block instanceof DoorBlock - || block instanceof TrapDoorBlock - || block instanceof FenceGateBlock - || block instanceof ChestBlock - || block instanceof BarrelBlock - || block instanceof EnderChestBlock - || block instanceof CraftingTableBlock - || block instanceof AbstractFurnaceBlock - || block instanceof BrewingStandBlock - || block instanceof EnchantingTableBlock - || block instanceof AnvilBlock - || block instanceof LoomBlock - || block instanceof CartographyTableBlock - || block instanceof SmithingTableBlock - || block instanceof StonecutterBlock - || block instanceof GrindstoneBlock - || block instanceof BeaconBlock - || block instanceof NoteBlock; - } - - public void enable() { - if (registered) { - return; - } - Events.BUS.register(this); - registered = true; - } - - public void disable() { - if (registered) { - Events.BUS.unregister(this); - registered = false; - } - reset(); - InventorySwap.INSTANCE.releaseHotbar(requester); - } - - public void tick() { - if (registered) { - InventorySwap.INSTANCE.tick(); - } - } - - public void update(Iterable positions) { - LinkedHashSet next = new LinkedHashSet<>(); - for (BlockPos pos : positions) { - if (pos != null) { - next.add(pos.immutable()); - } - } - - blocks.entrySet().removeIf(entry -> !next.contains(entry.getKey())); - for (BlockPos pos : next) { - blocks.putIfAbsent(pos, Boolean.FALSE); - } - - if (currentPlacement != null && !next.contains(currentPlacement.pos())) { - currentPlacement = null; - } - } - - public void clear() { - blocks.clear(); - inaccessible.clear(); - currentPlacement = null; - } - - public boolean isDone() { - return blocks.isEmpty(); - } - - public List getQueuedPositions() { - return List.copyOf(blocks.keySet()); - } - - public BlockPos getCurrentPlacementPos() { - return currentPlacement == null ? null : currentPlacement.pos(); - } - - @EventHandler(priority = -20) - private void onRotationUpdate(RotationUpdateEvent event) { - if (event.getType() != RotationUpdateEvent.Type.PRE) { - return; - } - - if (!registered || !module.isEnabled()) { - return; - } - - if (ticksToWait > 0) { - ticksToWait--; - } else if (ranAction) { - ranAction = false; - ticksToWait = randomBetween(cooldownMinSupplier.getAsInt(), cooldownMaxSupplier.getAsInt()); - } - - LocalPlayer player = mc.player; - if (player == null || mc.level == null || mc.gameMode == null) { - currentPlacement = null; - return; - } - - boolean inventoryOpen = !ignoreOpenInventorySupplier.getAsBoolean() && ClientScreen.current() instanceof AbstractContainerScreen; - boolean usingItem = !ignoreUsingItemSupplier.getAsBoolean() && player.isUsingItem(); - if (inventoryOpen || usingItem || blocks.isEmpty()) { - currentPlacement = null; - return; - } - - PlacementSlot slot = slotFinder.find(null); - if (slot == null || slot.stack().isEmpty()) { - currentPlacement = null; - return; - } - - inaccessible.clear(); - currentPlacement = scheduleCurrentPlacement(player, slot.stack()); - if (currentPlacement == null || rotationModeSupplier.get() == RotationMode.NO_ROTATION) { - return; - } - - RotationTarget rotationTarget = new RotationTarget( - currentPlacement.target().getRotation(), - player, - List.of(), - 1, - 4.0f, - false, - movementCorrectionSupplier.get(), - new RestrictedSingleUseAction(() -> { - PlacementPlan plan = currentPlacement; - LocalPlayer currentPlayer = mc.player; - if (plan == null || currentPlayer == null || ticksToWait > 0) { - return; - } - - Rotation currentRotation = RotationManager.INSTANCE.getCurrentRotation(); - if (currentRotation == null) { - return; - } - - BlockHitResult currentHit = traceTarget( - currentPlayer, - currentRotation, - Math.max(rangeSupplier.getAsDouble(), wallRangeSupplier.getAsDouble()) - ); - if (currentHit == null || !plan.target().getInteractedBlockPos().equals(currentHit.getBlockPos())) { - return; - } - - doPlacement(currentPlayer, plan); - }) - ); - RotationManager.INSTANCE.setRotationTarget(rotationTarget, rotationPriority, requester); - } - - @EventHandler - private void onMovementInput(MovementInputEvent event) { - if (!registered || !module.isEnabled()) { - return; - } - - if (sneakTimes > 0) { - sneakTimes--; - event.setSneak(true); - } - } - - @EventHandler - private void onPostPlayerUpdate(PostPlayerUpdateEvent event) { - if (!registered || !module.isEnabled()) { - return; - } - - LocalPlayer player = mc.player; - if (player == null || mc.level == null || mc.gameMode == null || currentPlacement == null || ticksToWait > 0) { - return; - } - - if (rotationModeSupplier.get() != RotationMode.NORMAL) { - doPlacement(player, currentPlacement); - } - } - - private PlacementPlan scheduleCurrentPlacement(LocalPlayer player, ItemStack stack) { - for (Map.Entry entry : blocks.entrySet()) { - BlockPos pos = entry.getKey(); - if (inaccessible.contains(pos) || isBlocked(player, pos)) { - continue; - } - - ScaffoldPlacementTarget target = ScaffoldTargetFinder.findTarget( - player, - pos, - stack, - List.of(BlockPos.ZERO), - null, - wallRangeSupplier.getAsDouble() > 0.0 - ); - if (target == null) { - continue; - } - - if (!canReach(player, target.getInteractedBlockPos(), target.getRotation())) { - inaccessible.add(pos); - continue; - } - - if (isInteractable(player.level().getBlockState(target.getInteractedBlockPos()))) { - sneakTimes = Math.max(0, sneakTicksSupplier.getAsInt() - 1); - } - - return new PlacementPlan(pos, target); - } - - return null; - } - - private boolean isBlocked(LocalPlayer player, BlockPos pos) { - BlockState state = player.level().getBlockState(pos); - if (!state.canBeReplaced()) { - inaccessible.add(pos); - return true; - } - - List entities = player.level().getEntities( - player, - new AABB(pos), - entity -> entity != null && !entity.isRemoved() && !entity.isSpectator() - ); - if (!entities.isEmpty()) { - inaccessible.add(pos); - return true; - } - - return false; - } - - private void doPlacement(LocalPlayer player, PlacementPlan plan) { - currentPlacement = null; - blocks.remove(plan.pos()); - - PlacementSlot slot = slotFinder.find(plan.pos()); - if (slot == null) { - return; - } - - // LB verifies normal placements against the rotation that actually got sent to the server, - // not the raw target rotation we initially planned. - Rotation verificationRotation = RotationManager.INSTANCE.getServerRotation(); - - if (!canReach(player, plan.target().getInteractedBlockPos(), verificationRotation)) { - return; - } - - BlockHitResult hitResult = raytraceTarget( - player, - plan.target().getInteractedBlockPos(), - verificationRotation, - plan.target().getDirection() - ); - if (hitResult == null) { - return; - } - - if (slot.hotbarSlot() >= 0) { - InventorySwap.INSTANCE.leaseHotbar( - requester, - slot.hotbarSlot(), - randomBetween(slotResetDelayMinSupplier.getAsInt(), slotResetDelayMaxSupplier.getAsInt()) - ); - } - - if (slot.stack().getItem() instanceof BlockItem && !player.level().getBlockState(plan.pos()).canBeReplaced()) { - return; - } - - InteractionResult result = mc.gameMode.useItemOn(player, slot.hand(), hitResult); - if (result != null && result.consumesAction()) { - player.swing(slot.hand()); - ranAction = true; - } - } - - private BlockHitResult raytraceTarget(LocalPlayer player, BlockPos interactedPos, Rotation rotation, net.minecraft.core.Direction direction) { - BlockHitResult hitResult = traceTarget(player, rotation, Math.max(rangeSupplier.getAsDouble(), wallRangeSupplier.getAsDouble())); - if (hitResult != null && hitResult.getType() == HitResult.Type.BLOCK && interactedPos.equals(hitResult.getBlockPos())) { - return new BlockHitResult(hitResult.getLocation(), direction, interactedPos, false); - } - - if (constructFailResultSupplier.getAsBoolean()) { - return new BlockHitResult(Vec3.atCenterOf(interactedPos), direction, interactedPos, false); - } - - return null; - } - - private boolean canReach(LocalPlayer player, BlockPos interactedPos, Rotation rotation) { - double wallRange = wallRangeSupplier.getAsDouble(); - if (Vec3.atCenterOf(interactedPos).distanceToSqr(player.getEyePosition()) <= wallRange * wallRange) { - return true; - } - - BlockHitResult hitResult = traceTarget(player, rotation, rangeSupplier.getAsDouble()); - return hitResult != null && interactedPos.equals(hitResult.getBlockPos()); - } - - private BlockHitResult traceTarget(LocalPlayer player, Rotation rotation, double range) { - if (player == null || rotation == null || player.level() == null) { - return null; - } - - Vec3 eyes = player.getEyePosition(); - Vec3 end = eyes.add(rotation.directionVector().scale(range)); - HitResult hitResult = player.level().clip(new ClipContext( - eyes, - end, - ClipContext.Block.OUTLINE, - ClipContext.Fluid.NONE, - player - )); - - return hitResult instanceof BlockHitResult blockHitResult ? blockHitResult : null; - } - - private void reset() { - ticksToWait = 0; - ranAction = false; - sneakTimes = 0; - clear(); - } - - public enum RotationMode { - NORMAL, - NO_ROTATION - } - - @FunctionalInterface - public interface SlotFinder { - PlacementSlot find(BlockPos targetPos); - } - - public record PlacementSlot(int hotbarSlot, InteractionHand hand, ItemStack stack) { - } - - private record PlacementPlan(BlockPos pos, ScaffoldPlacementTarget target) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldBlockItemSelection.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldBlockItemSelection.java deleted file mode 100644 index 1ab92fd..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldBlockItemSelection.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.util.block.scaffold; - -/* - * Adapted from LiquidBounce Scaffold block selection - * (https://github.com/CCBlueX/LiquidBounce). - * Original copyright (c) CCBlueX. - */ - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.EmptyBlockGetter; -import net.minecraft.world.level.block.*; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.Set; - -public enum ScaffoldBlockItemSelection { - ; - - private static final Set DISALLOWED_BLOCKS = Set.of( - Blocks.TNT, - Blocks.COBWEB, - Blocks.NETHER_PORTAL - ); - - public static boolean isValidBlock(ItemStack stack) { - if (stack == null || stack.isEmpty()) return false; - if (!(stack.getItem() instanceof BlockItem blockItem)) return false; - - Block block = blockItem.getBlock(); - BlockState state = block.defaultBlockState(); - - if (block instanceof FallingBlock) return false; - if (DISALLOWED_BLOCKS.contains(block)) return false; - - return !state.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty() - || state.isCollisionShapeFullBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); - } - - public static int findBestHotbarSlot(LocalPlayer player) { - return findBestHotbarSlot(player, 0, -1); - } - - public static int findBestHotbarSlot(LocalPlayer player, int doNotUseBelowCount, int preferredSlot) { - if (player == null) return -1; - - int bestSlot = -1; - int bestScore = Integer.MIN_VALUE; - for (int slot = 0; slot < 9; slot++) { - ItemStack stack = player.getInventory().getItem(slot); - if (!isValidBlock(stack)) continue; - if (stack.getCount() <= doNotUseBelowCount) continue; - - int score = score(stack); - if (slot == preferredSlot) score += 1000; - if (score > bestScore) { - bestScore = score; - bestSlot = slot; - } - } - - return bestSlot; - } - - private static int score(ItemStack stack) { - Block block = ((BlockItem) stack.getItem()).getBlock(); - BlockState state = block.defaultBlockState(); - - int score = 0; - - if (state.isCollisionShapeFullBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO)) score += 50; - if (!(block instanceof SlabBlock) && !(block instanceof StairBlock)) score += 20; - if (block.getFriction() <= 0.6f) score += 10; - if (block.getSpeedFactor() >= 1.0f) score += 10; - if (block.getJumpFactor() >= 1.0f) score += 10; - - return score + Math.min(stack.getCount(), 64); - } - - public static boolean shouldPreferUpperHalf(ItemStack stack) { - if (stack == null || stack.isEmpty() || !(stack.getItem() instanceof BlockItem blockItem)) { - return false; - } - - Block block = blockItem.getBlock(); - return block instanceof SlabBlock || block instanceof StairBlock; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldFacePositionFactory.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldFacePositionFactory.java deleted file mode 100644 index 66ea035..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldFacePositionFactory.java +++ /dev/null @@ -1,546 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.util.block.scaffold; - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.config.values.EnumValue; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.data.Rotation; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -public final class ScaffoldFacePositionFactory { - private static final float YAW_TOLERANCE = 5.0f; - private final LocalPlayer player; - private final Vec3 eyePos; - private final Rotation baseRotation; - private final Mode mode; - private final ScaffoldLine optimalLine; - private final double randomNumber; - public ScaffoldFacePositionFactory( - LocalPlayer player, - Mode mode, - ScaffoldLine optimalLine, - double randomNumber - ) { - this(player, player != null ? player.getEyePosition() : Vec3.ZERO, mode, optimalLine, randomNumber); - } - - public ScaffoldFacePositionFactory( - LocalPlayer player, - Vec3 eyePos, - Mode mode, - ScaffoldLine optimalLine, - double randomNumber - ) { - this.player = player; - this.eyePos = eyePos != null ? eyePos : (player != null ? player.getEyePosition() : Vec3.ZERO); - this.baseRotation = RotationManager.INSTANCE.getServerRotation(); - this.mode = mode; - this.optimalLine = optimalLine; - this.randomNumber = randomNumber; - } - - private static void addUnique(List points, Vec3 point, double eps) { - for (Vec3 existing : points) { - if (existing.distanceToSqr(point) <= eps * eps) { - return; - } - } - points.add(point); - } - - private static LineSegment toSegment(List points) { - if (points.size() < 2) { - return null; - } - return new LineSegment(points.get(0), points.get(1)); - } - - private static double lerp(double start, double end, double delta) { - return start + (end - start) * delta; - } - - private static double clamp(double value, double min, double max) { - return Math.max(min, Math.min(max, value)); - } - - public Vec3 producePoint(Face face) { - return switch (mode) { - case CENTER -> face.center(); - case RANDOM -> trimFace(face).random(randomNumber); - case STABILIZED -> chooseStabilizedPoint(face); - case NEAREST_ROTATION -> aimAtNearestPointToRotationLine(trimFace(face)); - case REVERSE_YAW -> chooseYawPoint(face, 180.0f); - case DIAGONAL_YAW -> chooseYawPoint(face, 75.0f); - case ANGLE_YAW -> chooseYawPoint(face, 45.0f); - case EDGE_POINT -> chooseEdgePoint(face); - }; - } - - private Vec3 chooseYawPoint(Face face, float angle) { - Face trimmedFace = trimFace(face); - if (!hasMovementInput()) { - return aimAtNearestPointToRotationLine(trimmedFace); - } - - YawCandidate positive = findYawCandidate(trimmedFace, Mth.wrapDegrees(player.getYRot() + angle)); - YawCandidate negative = findYawCandidate(trimmedFace, Mth.wrapDegrees(player.getYRot() - angle)); - YawCandidate best = null; - - boolean positiveOk = positive != null && positive.diff <= YAW_TOLERANCE; - boolean negativeOk = negative != null && negative.diff <= YAW_TOLERANCE; - - if (positiveOk && negativeOk) { - best = positive.diff < negative.diff ? positive : negative; - } else if (positiveOk) { - best = positive; - } else if (negativeOk) { - best = negative; - } - - if (best != null && !isYawCandidateConsistent(best.point)) { - best = null; - } - - return best != null ? best.point : aimAtNearestPointToRotationLine(trimmedFace); - } - - private boolean isYawCandidateConsistent(Vec3 point) { - if (point == null) { - return false; - } - - Rotation reference = RotationManager.INSTANCE.getCurrentRotation(); - if (reference == null) { - reference = baseRotation; - } - if (reference == null) { - return true; - } - - Rotation candidateRotation = Rotation.lookingAt(point, eyePos).normalize(); - return reference.angleTo(candidateRotation) <= 100.0f; - } - - private boolean hasMovementInput() { - if (player == null || player.input == null) { - return false; - } - return Math.abs(player.input.getMoveVector().x) > 1.0E-4f - || Math.abs(player.input.getMoveVector().y) > 1.0E-4f; - } - - private YawCandidate findYawCandidate(Face face, float targetYaw) { - LineSegment segment = intersectFaceWithYawPlane(face, targetYaw); - if (segment == null) { - return null; - } - - Vec3 point = closestPointToYaw(segment, targetYaw); - float diff = yawDifference(point, targetYaw); - return new YawCandidate(point, diff); - } - - private LineSegment intersectFaceWithYawPlane(Face face, float targetYaw) { - double yawRad = Math.toRadians(targetYaw); - double dirX = -Math.sin(yawRad); - double dirZ = Math.cos(yawRad); - double a = -dirZ; - double b = dirX; - double c = -(a * eyePos.x + b * eyePos.z); - double eps = 1.0E-7; - - if (Math.abs(face.maxY - face.minY) < eps) { - List points = new ArrayList<>(4); - collectHorizontalPlanePoint(points, face.minX, face, a, b, c, true, eps); - collectHorizontalPlanePoint(points, face.maxX, face, a, b, c, true, eps); - collectHorizontalPlanePoint(points, face.minZ, face, a, b, c, false, eps); - collectHorizontalPlanePoint(points, face.maxZ, face, a, b, c, false, eps); - return toSegment(points); - } - - if (Math.abs(face.maxX - face.minX) < eps) { - if (Math.abs(b) < eps) { - return null; - } - double z = -(a * face.minX + c) / b; - if (z < face.minZ - eps || z > face.maxZ + eps) { - return null; - } - return new LineSegment( - new Vec3(face.minX, face.minY, z), - new Vec3(face.minX, face.maxY, z) - ); - } - - if (Math.abs(face.maxZ - face.minZ) < eps) { - if (Math.abs(a) < eps) { - return null; - } - double x = -(b * face.minZ + c) / a; - if (x < face.minX - eps || x > face.maxX + eps) { - return null; - } - return new LineSegment( - new Vec3(x, face.minY, face.minZ), - new Vec3(x, face.maxY, face.minZ) - ); - } - - return null; - } - - private void collectHorizontalPlanePoint( - List points, - double fixed, - Face face, - double a, - double b, - double c, - boolean fixedX, - double eps - ) { - if (fixedX) { - if (Math.abs(b) < eps) { - return; - } - double z = -(a * fixed + c) / b; - if (z >= face.minZ - eps && z <= face.maxZ + eps) { - addUnique(points, new Vec3(fixed, face.minY, z), eps); - } - return; - } - - if (Math.abs(a) < eps) { - return; - } - double x = -(b * fixed + c) / a; - if (x >= face.minX - eps && x <= face.maxX + eps) { - addUnique(points, new Vec3(x, face.minY, fixed), eps); - } - } - - private Vec3 closestPointToYaw(LineSegment segment, float targetYaw) { - float startYaw = pointYaw(segment.start); - float endYaw = pointYaw(segment.end); - float yawDiff = Mth.wrapDegrees(endYaw - startYaw); - float targetYawDiff = Mth.wrapDegrees(targetYaw - startYaw); - double t = Math.abs(yawDiff) > 1.0E-4f ? targetYawDiff / yawDiff : 0.0; - t = Mth.clamp(t, 0.0, 1.0); - return new Vec3( - lerp(segment.start.x, segment.end.x, t), - lerp(segment.start.y, segment.end.y, t), - lerp(segment.start.z, segment.end.z, t) - ); - } - - private float pointYaw(Vec3 point) { - return Rotation.lookingAt(point, eyePos).normalize().yaw(); - } - - private float yawDifference(Vec3 point, float targetYaw) { - return Math.abs(Mth.wrapDegrees(pointYaw(point) - targetYaw)); - } - - private Face trimFace(Face face) { - return face.trim(0.15); - } - - private Vec3 aimAtNearestPointToRotationLine(Face face) { - Rotation rotation = baseRotation != null ? baseRotation : Rotation.ZERO; - Vec3 direction = rotation.directionVector(); - double eps = 1.0E-7; - - if (Math.abs(face.maxX - face.minX) < eps) { - double t = Math.abs(direction.x) > eps ? (face.minX - eyePos.x) / direction.x : 0.0; - double y = eyePos.y + direction.y * t; - double z = eyePos.z + direction.z * t; - return new Vec3(face.minX, clamp(y, face.minY, face.maxY), clamp(z, face.minZ, face.maxZ)); - } - - if (Math.abs(face.maxY - face.minY) < eps) { - double t = Math.abs(direction.y) > eps ? (face.minY - eyePos.y) / direction.y : 0.0; - double x = eyePos.x + direction.x * t; - double z = eyePos.z + direction.z * t; - return new Vec3(clamp(x, face.minX, face.maxX), face.minY, clamp(z, face.minZ, face.maxZ)); - } - - if (Math.abs(face.maxZ - face.minZ) < eps) { - double t = Math.abs(direction.z) > eps ? (face.minZ - eyePos.z) / direction.z : 0.0; - double x = eyePos.x + direction.x * t; - double y = eyePos.y + direction.y * t; - return new Vec3(clamp(x, face.minX, face.maxX), clamp(y, face.minY, face.maxY), face.minZ); - } - - return face.center(); - } - - private Vec3 chooseStabilizedPoint(Face face) { - Face trimmedFace = trimFace(face); - Face targetFace = getStabilizedTargetFace(trimmedFace); - return aimAtNearestPointToRotationLine(targetFace != null ? targetFace : trimmedFace); - } - - private Face getStabilizedTargetFace(Face face) { - if (optimalLine == null || player == null) { - return null; - } - - Vec3 nearestPointToOptimalLine = optimalLine.getNearestPointTo(player.position()); - Vec3 directionToOptimalLine = player.position().subtract(nearestPointToOptimalLine); - if (directionToOptimalLine.lengthSqr() < 1.0E-7) { - return face; - } - - Vec3 collisionWithFacePlane = intersectFacePlane(new ScaffoldLine(eyePos, optimalLine.direction()), face); - if (collisionWithFacePlane == null) { - return null; - } - - Vec3 b = player.position().add(directionToOptimalLine.normalize().scale(2.0)); - AABB cropBox = new AABB( - Math.min(collisionWithFacePlane.x, b.x), - player.getY() - 2.0, - Math.min(collisionWithFacePlane.z, b.z), - Math.max(collisionWithFacePlane.x, b.x), - player.getY() + 1.0, - Math.max(collisionWithFacePlane.z, b.z) - ); - - Face clampedFace = face.clamp(cropBox); - return clampedFace.area() < 1.0E-4 ? null : clampedFace; - } - - private Vec3 intersectFacePlane(ScaffoldLine line, Face face) { - if (line == null || face == null) { - return null; - } - - Vec3 origin = line.position(); - Vec3 direction = line.direction(); - double eps = 1.0E-7; - - if (Math.abs(face.maxX - face.minX) < eps) { - if (Math.abs(direction.x) < eps) return null; - double t = (face.minX - origin.x) / direction.x; - return new Vec3(face.minX, origin.y + direction.y * t, origin.z + direction.z * t); - } - if (Math.abs(face.maxY - face.minY) < eps) { - if (Math.abs(direction.y) < eps) return null; - double t = (face.minY - origin.y) / direction.y; - return new Vec3(origin.x + direction.x * t, face.minY, origin.z + direction.z * t); - } - if (Math.abs(face.maxZ - face.minZ) < eps) { - if (Math.abs(direction.z) < eps) return null; - double t = (face.minZ - origin.z) / direction.z; - return new Vec3(origin.x + direction.x * t, origin.y + direction.y * t, face.minZ); - } - - return null; - } - - private Vec3 chooseEdgePoint(Face face) { - Face trimmedFace = trimFace(face); - if (!hasMovementInput()) { - return aimAtNearestPointToRotationLine(trimmedFace); - } - - return trimmedFace.edgePoints().stream() - .max(Comparator.comparingDouble(this::edgeDistanceScore)) - .orElseGet(trimmedFace::center); - } - - private double edgeDistanceScore(Vec3 point) { - if (player == null) { - return 0.0; - } - Vec3 localPlayerPos = player.position().subtract(player.blockPosition().getX(), player.blockPosition().getY(), player.blockPosition().getZ()); - return point.distanceToSqr(localPlayerPos); - } - - public enum Mode implements EnumValue.IdProvider { - CENTER("center"), - RANDOM("random"), - STABILIZED("stabilized"), - NEAREST_ROTATION("nearest_rotation"), - REVERSE_YAW("reverse_yaw"), - DIAGONAL_YAW("diagonal_yaw"), - ANGLE_YAW("angle_yaw"), - EDGE_POINT("edge_point"); - - private final String id; - - Mode(String id) { - this.id = id; - } - - @Override - public String id() { - return id; - } - } - - public static final class Face { - private final double minX; - private final double maxX; - private final double minY; - private final double maxY; - private final double minZ; - private final double maxZ; - - public Face(double minX, double maxX, double minY, double maxY, double minZ, double maxZ) { - this.minX = minX; - this.maxX = maxX; - this.minY = minY; - this.maxY = maxY; - this.minZ = minZ; - this.maxZ = maxZ; - } - - public static Face fromBox(AABB box, Direction direction) { - return switch (direction) { - case UP -> new Face(box.minX, box.maxX, box.maxY, box.maxY, box.minZ, box.maxZ); - case DOWN -> new Face(box.minX, box.maxX, box.minY, box.minY, box.minZ, box.maxZ); - case NORTH -> new Face(box.minX, box.maxX, box.minY, box.maxY, box.minZ, box.minZ); - case SOUTH -> new Face(box.minX, box.maxX, box.minY, box.maxY, box.maxZ, box.maxZ); - case EAST -> new Face(box.maxX, box.maxX, box.minY, box.maxY, box.minZ, box.maxZ); - case WEST -> new Face(box.minX, box.minX, box.minY, box.maxY, box.minZ, box.maxZ); - }; - } - - private static double lerp(double min, double max, double delta) { - return min + (max - min) * delta; - } - - public Face trim(double factor) { - double offsetX = (maxX - minX) * factor; - double offsetY = (maxY - minY) * factor; - double offsetZ = (maxZ - minZ) * factor; - - double newMinX = minX + offsetX; - double newMaxX = maxX - offsetX; - double newMinY = minY + offsetY; - double newMaxY = maxY - offsetY; - double newMinZ = minZ + offsetZ; - double newMaxZ = maxZ - offsetZ; - - if (newMinX > newMaxX) newMinX = newMaxX = (minX + maxX) * 0.5; - if (newMinY > newMaxY) newMinY = newMaxY = (minY + maxY) * 0.5; - if (newMinZ > newMaxZ) newMinZ = newMaxZ = (minZ + maxZ) * 0.5; - - return new Face(newMinX, newMaxX, newMinY, newMaxY, newMinZ, newMaxZ); - } - - public Face truncateMinY(double minAllowedY) { - double y = Math.max(minY, minAllowedY); - if (y > maxY) return null; - return new Face(minX, maxX, y, maxY, minZ, maxZ); - } - - public Vec3 center() { - return new Vec3((minX + maxX) * 0.5, (minY + maxY) * 0.5, (minZ + maxZ) * 0.5); - } - - public Face clamp(AABB box) { - double clampedMinX = ScaffoldFacePositionFactory.clamp(minX, box.minX, box.maxX); - double clampedMaxX = ScaffoldFacePositionFactory.clamp(maxX, box.minX, box.maxX); - double clampedMinY = ScaffoldFacePositionFactory.clamp(minY, box.minY, box.maxY); - double clampedMaxY = ScaffoldFacePositionFactory.clamp(maxY, box.minY, box.maxY); - double clampedMinZ = ScaffoldFacePositionFactory.clamp(minZ, box.minZ, box.maxZ); - double clampedMaxZ = ScaffoldFacePositionFactory.clamp(maxZ, box.minZ, box.maxZ); - return new Face( - Math.min(clampedMinX, clampedMaxX), - Math.max(clampedMinX, clampedMaxX), - Math.min(clampedMinY, clampedMaxY), - Math.max(clampedMinY, clampedMaxY), - Math.min(clampedMinZ, clampedMaxZ), - Math.max(clampedMinZ, clampedMaxZ) - ); - } - - private Vec3 random(double randomNumber) { - double t = (Mth.clamp(randomNumber, -1.0, 1.0) + 1.0) * 0.5; - double inv = 1.0 - t; - return new Vec3( - minX * inv + maxX * t, - minY * t + maxY * inv, - minZ * inv + maxZ * t - ); - } - - private List samplePoints() { - List points = new ArrayList<>(27); - double[] samples = {0.0, 0.25, 0.5, 0.75, 1.0}; - - for (double sx : samples) { - for (double sy : samples) { - for (double sz : samples) { - double x = lerp(minX, maxX, sx); - double y = lerp(minY, maxY, sy); - double z = lerp(minZ, maxZ, sz); - points.add(new Vec3(x, y, z)); - } - } - } - - return points; - } - - private List edgePoints() { - List points = new ArrayList<>(8); - double[] xs = {minX, maxX}; - double[] ys = {minY, maxY}; - double[] zs = {minZ, maxZ}; - for (double x : xs) { - for (double y : ys) { - for (double z : zs) { - points.add(new Vec3(x, y, z)); - } - } - } - return points; - } - - public double area() { - double dx = maxX - minX; - double dy = maxY - minY; - double dz = maxZ - minZ; - if (dx <= 1.0E-7) return Math.max(dy, 0.0) * Math.max(dz, 0.0); - if (dy <= 1.0E-7) return Math.max(dx, 0.0) * Math.max(dz, 0.0); - if (dz <= 1.0E-7) return Math.max(dx, 0.0) * Math.max(dy, 0.0); - return 0.0; - } - - public double minY() { - return minY; - } - - public double maxY() { - return maxY; - } - } - - private record LineSegment(Vec3 start, Vec3 end) { - } - - private record YawCandidate(Vec3 point, float diff) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldInteractionTarget.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldInteractionTarget.java deleted file mode 100644 index 743fe0a..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldInteractionTarget.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.util.block.scaffold; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.util.aiming.data.Rotation; - -public final class ScaffoldInteractionTarget { - - private final BlockPos interactedBlockPos; - private final BlockPos targetBlockPos; - private final Direction direction; - private final Vec3 hitVec; - private final double minTargetY; - private final Rotation rotation; - - public ScaffoldInteractionTarget( - BlockPos interactedBlockPos, - BlockPos targetBlockPos, - Direction direction, - Vec3 hitVec, - double minTargetY, - Rotation rotation - ) { - this.interactedBlockPos = interactedBlockPos; - this.targetBlockPos = targetBlockPos; - this.direction = direction; - this.hitVec = hitVec; - this.minTargetY = minTargetY; - this.rotation = rotation; - } - - public BlockPos getInteractedBlockPos() { - return interactedBlockPos; - } - - public BlockPos getTargetBlockPos() { - return targetBlockPos; - } - - public Direction getDirection() { - return direction; - } - - public Vec3 getHitVec() { - return hitVec; - } - - public Rotation getRotation() { - return rotation; - } - - public BlockHitResult toHitResult() { - return new BlockHitResult(hitVec, direction, interactedBlockPos, false); - } - - public boolean matches(BlockHitResult hitResult) { - return hitResult != null - && hitResult.getType() == net.minecraft.world.phys.HitResult.Type.BLOCK - && interactedBlockPos.equals(hitResult.getBlockPos()) - && direction == hitResult.getDirection() - && hitResult.getLocation().y >= minTargetY; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldInteractionTargetFinder.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldInteractionTargetFinder.java deleted file mode 100644 index 2d85cff..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldInteractionTargetFinder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.util.block.scaffold; - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.world.item.ItemStack; - -import java.util.List; - -public enum ScaffoldInteractionTargetFinder { - ; - - public static ScaffoldInteractionTarget findTarget(LocalPlayer player, BlockPos targetPos, ItemStack stack) { - ScaffoldPlacementTarget target = ScaffoldTargetFinder.findTarget( - player, - targetPos, - stack, - List.of(BlockPos.ZERO), - null, - true - ); - if (target == null) { - return null; - } - - return new ScaffoldInteractionTarget( - target.getInteractedBlockPos(), - target.getPlacedBlockPos(), - target.getDirection(), - target.getHitVec(), - target.getHitVec().y, - target.getRotation() - ); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldLine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldLine.java deleted file mode 100644 index 673a4e0..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldLine.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.util.block.scaffold; - -import net.minecraft.world.phys.Vec3; - -public record ScaffoldLine(Vec3 position, Vec3 direction) { - - public ScaffoldLine(Vec3 position, Vec3 direction) { - if (direction == null || direction.lengthSqr() < 1.0E-7) { - throw new IllegalArgumentException("Direction must not be zero."); - } - this.position = position; - this.direction = direction.normalize(); - } - - public static ScaffoldLine fromPoints(Vec3 begin, Vec3 end) { - return new ScaffoldLine(begin, end.subtract(begin)); - } - - public Vec3 getNearestPointTo(Vec3 point) { - Vec3 delta = point.subtract(position); - double t = delta.dot(direction); - return position.add(direction.scale(t)); - } - - public double squaredDistanceTo(Vec3 point) { - return getNearestPointTo(point).distanceToSqr(point); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldMovementPlanner.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldMovementPlanner.java deleted file mode 100644 index 8c27ad7..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldMovementPlanner.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.util.block.scaffold; - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.Vec3; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.List; - -public final class ScaffoldMovementPlanner { - - private static final int MAX_LAST_PLACED_BLOCKS = 4; - private static final double[] OFFSETS_TO_TRY = {0.301, 0.0, -0.301}; - - private final ArrayDeque lastPlacedBlocks = new ArrayDeque<>(MAX_LAST_PLACED_BLOCKS); - private BlockPos lastPosition; - - public ScaffoldLine getOptimalMovementLine(LocalPlayer player, float movementYaw) { - if (player == null) return null; - - Vec3 direction = chooseDirection(movementYaw); - BlockPos blockUnderPlayer = findBlockPlayerStandsOn(player); - if (blockUnderPlayer == null) return null; - - ScaffoldLine lastBlocksLine = fitLineThroughLastPlacedBlocks(); - Vec3 lineBase = Vec3.atCenterOf(blockUnderPlayer); - - if (lastBlocksLine != null && !divergesTooMuchFromDirection(lastBlocksLine, direction)) { - lineBase = lastBlocksLine.position(); - } - - return new ScaffoldLine(new Vec3(lineBase.x, player.getY(), lineBase.z), direction); - } - - public void trackPlacedBlock(BlockPos target) { - if (target == null) return; - if (target.equals(lastPlacedBlocks.peekLast())) return; - - while (lastPlacedBlocks.size() >= MAX_LAST_PLACED_BLOCKS) { - lastPlacedBlocks.removeFirst(); - } - lastPlacedBlocks.addLast(target.immutable()); - } - - public void reset() { - lastPlacedBlocks.clear(); - lastPosition = null; - } - - private boolean divergesTooMuchFromDirection(ScaffoldLine line, Vec3 direction) { - return line.direction().dot(direction.normalize()) < 0.5; - } - - private ScaffoldLine fitLineThroughLastPlacedBlocks() { - if (lastPlacedBlocks.size() < 2) return null; - - BlockPos[] blocks = lastPlacedBlocks.toArray(new BlockPos[0]); - BlockPos last = blocks[blocks.length - 1]; - BlockPos second = blocks[blocks.length - 2]; - if (last == null || second == null || last.equals(second)) return null; - - Vec3 secondCenter = Vec3.atCenterOf(second); - Vec3 lastCenter = Vec3.atCenterOf(last); - Vec3 avg = secondCenter.add(lastCenter).scale(0.5); - Vec3 dir = lastCenter.subtract(secondCenter); - if (dir.lengthSqr() < 1.0E-7) return null; - return new ScaffoldLine(avg, dir); - } - - private BlockPos findBlockPlayerStandsOn(LocalPlayer player) { - List candidates = new ArrayList<>(); - for (double xOffset : OFFSETS_TO_TRY) { - for (double zOffset : OFFSETS_TO_TRY) { - BlockPos pos = BlockPos.containing(player.getX() + xOffset, player.getY() - 1.0, player.getZ() + zOffset); - if (!player.level().getBlockState(pos).getCollisionShape(player.level(), pos).isEmpty()) { - candidates.add(pos.immutable()); - } - } - } - - BlockPos lastPlaced = lastPlacedBlocks.peekLast(); - if (lastPlaced != null && candidates.contains(lastPlaced)) { - return lastPlaced; - } - - if (lastPosition != null && candidates.contains(lastPosition)) { - return lastPosition; - } - - BlockPos candidate = candidates.stream().findFirst().orElse(null); - lastPosition = candidate; - return candidate; - } - - private Vec3 chooseDirection(float currentAngle) { - float currentDirection = currentAngle / 180.0f * 4.0f + 4.0f; - float newDirectionNumber = Math.round(currentDirection); - float newDirectionAngle = Mth.wrapDegrees((newDirectionNumber - 4.0f) / 4.0f * 180.0f + 90.0f); - double radians = Math.toRadians(newDirectionAngle); - return new Vec3(Math.cos(radians), 0.0, Math.sin(radians)); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldMovementPrediction.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldMovementPrediction.java deleted file mode 100644 index 887be8d..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldMovementPrediction.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.util.block.scaffold; - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.EntityDimensions; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -import java.util.*; - -public final class ScaffoldMovementPrediction { - - private static final int MAX_PLACEMENT_OFFSETS = 4; - private final ArrayDeque lastPlacementOffsets = new ArrayDeque<>(); - - private static Vec3 rotateY(Vec3 vec, float angle) { - double sin = Math.sin(angle); - double cos = Math.cos(angle); - double x = vec.x * cos + vec.z * sin; - double z = vec.z * cos - vec.x * sin; - return new Vec3(x, vec.y, z); - } - - private static boolean isCloseToEdge(LocalPlayer player, double distance) { - if (player == null || player.input == null) { - return false; - } - - var move = player.input.getMoveVector(); - double sideways = move.x; - double forward = move.y; - if (Math.abs(forward) < 1.0E-6 && Math.abs(sideways) < 1.0E-6) { - return false; - } - - double rad = Math.toRadians(player.getYRot()); - double sin = Math.sin(rad); - double cos = Math.cos(rad); - double x = sideways * cos - forward * sin; - double z = forward * cos + sideways * sin; - Vec3 input = new Vec3(x, 0.0, z); - if (input.lengthSqr() < 1.0E-6) { - return false; - } - - Vec3 offset = input.normalize().multiply(distance, 0.0, distance); - EntityDimensions dimensions = player.getDimensions(player.getPose()); - AABB hitbox = dimensions.makeBoundingBox(player.position()) - .inflate(-0.05, 0.0, -0.05) - .move(offset.x, -0.55, offset.z); - return !player.level().getBlockCollisions(player, hitbox).iterator().hasNext(); - } - - private static Vec3 findEdgeCollision(LocalPlayer player, Vec3 from, Vec3 to, float allowedDropDown) { - List boundingBoxes = collectCollisionBoundingBoxes(player, from, to, allowedDropDown); - Vec3 currentFrom = from; - - Vec3 lineVec = to.subtract(from); - Vec3 extendedFrom = from.subtract(lineVec.scale(1000.0)); - Vec3 extendedTo = to.add(lineVec.scale(1000.0)); - - List cache = new ArrayList<>(); - while (true) { - cache.clear(); - for (AABB box : boundingBoxes) { - if (box.contains(currentFrom)) { - cache.add(box); - } - } - - if (cache.isEmpty()) { - return currentFrom; - } - - for (AABB box : cache) { - if (box.contains(to)) { - return null; - } - } - - Optional next = cache.stream() - .map(box -> box.clip(extendedFrom, extendedTo).orElse(null)) - .filter(java.util.Objects::nonNull) - .min(Comparator.comparingDouble(hit -> hit.distanceToSqr(to))); - if (next.isEmpty()) { - return null; - } - - currentFrom = next.get(); - boundingBoxes.removeAll(cache); - } - } - - private static List collectCollisionBoundingBoxes( - LocalPlayer player, - Vec3 from, - Vec3 to, - float allowedDropDown - ) { - EntityDimensions dimensions = player.getDimensions(player.getPose()); - AABB fromBox = dimensions.makeBoundingBox(from); - AABB toBox = dimensions.makeBoundingBox(to); - AABB unionBox = fromBox.minmax(toBox); - - BlockPos fromBlockPos = BlockPos.containing( - unionBox.minX - 0.3 - 1.0E-7, - unionBox.minY - allowedDropDown - 1.0E-7, - unionBox.minZ - 0.3 - 1.0E-7 - ); - BlockPos toBlockPos = BlockPos.containing( - unionBox.maxX + 0.3 + 1.0E-7, - unionBox.minY + 1.0E-7, - unionBox.maxZ + 0.3 + 1.0E-7 - ); - - Vec3 lineVec = to.subtract(from); - Vec3 extendedFrom = from.subtract(lineVec.scale(1000.0)); - Vec3 extendedTo = to.add(lineVec.scale(1000.0)); - - List foundBoxes = new ArrayList<>(); - for (int x = fromBlockPos.getX(); x <= toBlockPos.getX(); x++) { - for (int y = fromBlockPos.getY(); y <= toBlockPos.getY(); y++) { - for (int z = fromBlockPos.getZ(); z <= toBlockPos.getZ(); z++) { - BlockPos pos = new BlockPos(x, y, z); - var state = player.level().getBlockState(pos); - var collisionShape = state.getCollisionShape(player.level(), pos); - for (AABB boundingBox : collisionShape.toAabbs()) { - AABB adjustedBox = new AABB( - boundingBox.minX - 0.3, - boundingBox.minY - 1.0, - boundingBox.minZ - 0.3, - boundingBox.maxX + 0.3, - boundingBox.maxY + allowedDropDown + 0.05, - boundingBox.maxZ + 0.3 - ).move(pos); - - if (adjustedBox.clip(extendedFrom, extendedTo).isEmpty()) { - continue; - } - - foundBoxes.add(adjustedBox); - } - } - } - } - - return foundBoxes; - } - - public void reset() { - lastPlacementOffsets.clear(); - } - - public void onPlace(ScaffoldLine optimalLine, Vec3 lastFallOffPosition, Vec3 playerPosition) { - if (optimalLine == null || lastFallOffPosition == null || playerPosition == null) return; - - float lineDirAngle = (float) Math.atan2(optimalLine.direction().z, optimalLine.direction().x); - Vec3 unrotatedOffset = rotateY(playerPosition.subtract(lastFallOffPosition), lineDirAngle); - - lastPlacementOffsets.addLast(unrotatedOffset); - while (lastPlacementOffsets.size() > MAX_PLACEMENT_OFFSETS) { - lastPlacementOffsets.removeFirst(); - } - } - - public Vec3 getPredictedPlacementPos(LocalPlayer player, ScaffoldLine optimalLine) { - if (player == null || optimalLine == null) return null; - if (isCloseToEdge(player, 0.0)) { - return null; - } - - Vec3 fallOffPoint = getFallOffPositionOnLine(player, optimalLine); - if (fallOffPoint == null) return null; - - Vec3 avg = getAveragePlacementOffset(); - if (avg == null) { - return fallOffPoint; - } - - float lineDirAngle = (float) Math.atan2(optimalLine.direction().z, optimalLine.direction().x); - return fallOffPoint.add(rotateY(avg, -lineDirAngle)); - } - - public Vec3 getFallOffPositionOnLine(LocalPlayer player, ScaffoldLine optimalLine) { - if (player == null || optimalLine == null) return null; - - Vec3 nearest = optimalLine.getNearestPointTo(player.position()); - Vec3 fromLine = nearest.add(0.0, -0.1, 0.0); - Vec3 toLine = fromLine.add(optimalLine.direction().normalize().scale(3.0)); - - Vec3 edgeCollision = findEdgeCollision(player, fromLine, toLine, 0.5f); - return edgeCollision != null ? new Vec3(edgeCollision.x, player.getY(), edgeCollision.z) : null; - } - - private Vec3 getAveragePlacementOffset() { - if (lastPlacementOffsets.isEmpty()) return null; - - Vec3 sum = Vec3.ZERO; - for (Vec3 offset : lastPlacementOffsets) { - sum = sum.add(offset); - } - return sum.scale(1.0 / lastPlacementOffsets.size()); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementGate.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementGate.java deleted file mode 100644 index b0b467e..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementGate.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.util.block.scaffold; - -/** - * Owns the two independent pieces of Scaffold timing state. - * Placement cadence must never extend or re-arm an Eagle sneak pulse. - */ -public final class ScaffoldPlacementGate { - private static final long NANOS_PER_SECOND = 1_000_000_000L; - - private long lastSuccessfulPlacementNanos; - private int placementsSinceEaglePulse; - private boolean eaglePulseArmed; - - public ScaffoldPlacementGate() { - reset(); - } - - public void reset() { - lastSuccessfulPlacementNanos = 0L; - placementsSinceEaglePulse = 0; - eaglePulseArmed = true; - } - - public boolean isPlacementReady(long nowNanos, double blocksPerSecond, int extraDelayTicksLeft) { - if (extraDelayTicksLeft > 0) return false; - if (lastSuccessfulPlacementNanos == 0L) return true; - - return nowNanos - lastSuccessfulPlacementNanos >= placementIntervalNanos(blocksPerSecond); - } - - public void recordSuccessfulPlacement(long nowNanos, int blocksToEagle) { - lastSuccessfulPlacementNanos = nowNanos; - placementsSinceEaglePulse++; - - if (placementsSinceEaglePulse > Math.max(0, blocksToEagle)) { - placementsSinceEaglePulse = 0; - eaglePulseArmed = true; - } - } - - public boolean consumeEaglePulse( - boolean eagleEnabled, - boolean closeToEdge, - boolean onlyOnGround, - boolean onGround, - boolean flying, - boolean goingDown - ) { - boolean eligible = eagleEnabled - && closeToEdge - && (!onlyOnGround || onGround) - && !flying - && !goingDown; - if (!eligible || !eaglePulseArmed) return false; - - eaglePulseArmed = false; - return true; - } - - public static boolean shouldSafeWalk( - boolean scaffoldEnabled, - boolean eagleEnabled, - boolean canOperate, - boolean onGround, - boolean flying, - boolean goingDown, - boolean hasBlocks - ) { - return scaffoldEnabled - && eagleEnabled - && canOperate - && onGround - && !flying - && !goingDown - && hasBlocks; - } - - static long placementIntervalNanos(double blocksPerSecond) { - double safeBlocksPerSecond = Math.max(0.1, blocksPerSecond); - return (long) Math.ceil(NANOS_PER_SECOND / safeBlocksPerSecond); - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementTarget.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementTarget.java deleted file mode 100644 index fd45100..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementTarget.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.util.block.scaffold; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import dev.loki.lovisual.util.aiming.data.Rotation; - -public final class ScaffoldPlacementTarget { - - private final BlockPos interactedBlockPos; - private final BlockPos placedBlockPos; - private final Direction direction; - private final Vec3 hitVec; - private final double minPlacementY; - private final Rotation rotation; - - public ScaffoldPlacementTarget( - BlockPos interactedBlockPos, - BlockPos placedBlockPos, - Direction direction, - Vec3 hitVec, - double minPlacementY, - Rotation rotation - ) { - this.interactedBlockPos = interactedBlockPos; - this.placedBlockPos = placedBlockPos; - this.direction = direction; - this.hitVec = hitVec; - this.minPlacementY = minPlacementY; - this.rotation = rotation; - } - - public BlockPos getInteractedBlockPos() { - return interactedBlockPos; - } - - public BlockPos getPlacedBlockPos() { - return placedBlockPos; - } - - public Direction getDirection() { - return direction; - } - - public Vec3 getHitVec() { - return hitVec; - } - - public Rotation getRotation() { - return rotation; - } - - public ScaffoldPlacementTarget withRotation(Rotation newRotation) { - return new ScaffoldPlacementTarget( - interactedBlockPos, - placedBlockPos, - direction, - hitVec, - minPlacementY, - newRotation - ); - } - - public BlockHitResult toHitResult() { - return new BlockHitResult(hitVec, direction, interactedBlockPos, false); - } - - public boolean matches(BlockHitResult hitResult) { - return hitResult != null - && hitResult.getType() == net.minecraft.world.phys.HitResult.Type.BLOCK - && interactedBlockPos.equals(hitResult.getBlockPos()) - && direction == hitResult.getDirection() - && hitResult.getLocation().y >= minPlacementY; - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldTargetFinder.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldTargetFinder.java deleted file mode 100644 index 1f39d0d..0000000 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/block/scaffold/ScaffoldTargetFinder.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. - * - * Portions of this file are based on LiquidBounce - * (https://github.com/CCBlueX/LiquidBounce). - * Copyright (c) 2015-2026 CCBlueX. - * - * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. - * See THIRD_PARTY_NOTICES.md for details. - */ - -package dev.loki.lovisual.util.block.scaffold; - -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.block.SupportType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import net.minecraft.world.phys.shapes.CollisionContext; -import dev.loki.lovisual.util.aiming.RotationManager; -import dev.loki.lovisual.util.aiming.data.Rotation; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -public enum ScaffoldTargetFinder { - ; - - public static ScaffoldPlacementTarget findTarget(LocalPlayer player, BlockPos targetPos, ItemStack stack) { - return findTarget(player, targetPos, stack, List.of(BlockPos.ZERO), null, false, null, null); - } - - public static ScaffoldPlacementTarget findTarget( - LocalPlayer player, - BlockPos targetPos, - ItemStack stack, - List offsets, - Comparator comparator, - boolean considerFacingAwayFaces - ) { - return findTarget(player, targetPos, stack, offsets, comparator, considerFacingAwayFaces, null, null); - } - - public static ScaffoldPlacementTarget findTarget( - LocalPlayer player, - BlockPos targetPos, - ItemStack stack, - List offsets, - Comparator comparator, - boolean considerFacingAwayFaces, - ScaffoldFacePositionFactory facePositionFactory - ) { - return findTarget( - player, - targetPos, - stack, - offsets, - comparator, - considerFacingAwayFaces, - facePositionFactory, - null - ); - } - - public static ScaffoldPlacementTarget findTarget( - LocalPlayer player, - BlockPos targetPos, - ItemStack stack, - List offsets, - Comparator comparator, - boolean considerFacingAwayFaces, - ScaffoldFacePositionFactory facePositionFactory, - Vec3 placementEyePos - ) { - if (player == null || player.level() == null || stack == null || stack.isEmpty()) return null; - if (isBlockSolid(player.level().getBlockState(targetPos), player, targetPos)) { - return null; - } - - Rotation baseRotation = RotationManager.INSTANCE.getServerRotation(); - Vec3 eyePos = placementEyePos != null - ? placementEyePos - : player.position().add(0.0, player.getEyeHeight(player.getPose()), 0.0); - boolean preferUpperHalf = ScaffoldBlockItemSelection.shouldPreferUpperHalf(stack); - List investigationTargets = buildInvestigationTargets(targetPos, offsets, comparator); - - for (BlockPos placementPos : investigationTargets) { - BlockState stateToInvestigate = player.level().getBlockState(placementPos); - if (isBlockSolid(stateToInvestigate, player, placementPos)) { - continue; - } - - TargetMode targetMode = (stateToInvestigate.isAir() || !stateToInvestigate.getFluidState().isEmpty()) - ? TargetMode.PLACE_AT_NEIGHBOR - : TargetMode.REPLACE_EXISTING_BLOCK; - if (targetMode == TargetMode.REPLACE_EXISTING_BLOCK - && !canBeReplacedWith(player, placementPos, stack, stateToInvestigate)) { - continue; - } - - TargetPlan targetPlan = findBestTargetPlan( - player, - placementPos, - targetMode, - eyePos, - baseRotation, - considerFacingAwayFaces - ); - if (targetPlan == null) { - continue; - } - - BlockState supportState = player.level().getBlockState(targetPlan.interactedPos); - var shape = supportState.getShape( - player.level(), - targetPlan.interactedPos, - CollisionContext.of(player) - ); - if (shape.isEmpty()) { - continue; - } - - PointOnFace pointOnFace = findTargetPointOnFace( - shape.toAabbs(), - targetPlan.interactedPos, - targetPlan.direction, - preferUpperHalf, - facePositionFactory - ); - if (pointOnFace == null) { - continue; - } - - Vec3 hitVec = pointOnFace.point; - Rotation rotation = Rotation.lookingAt(hitVec, eyePos).normalize(); - return new ScaffoldPlacementTarget( - targetPlan.interactedPos.immutable(), - placementPos.immutable(), - targetPlan.direction, - hitVec, - pointOnFace.face.minY(), - rotation - ); - } - - return null; - } - - private static TargetPlan findBestTargetPlan( - LocalPlayer player, - BlockPos placementPos, - TargetMode targetMode, - Vec3 eyePos, - Rotation baseRotation, - boolean considerFacingAwayFaces - ) { - TargetPlan bestPlan = null; - float bestAngle = Float.MAX_VALUE; - - for (Direction direction : Direction.values()) { - var world = player.level(); - if (world == null) continue; - - BlockPos interactedPos = switch (targetMode) { - case PLACE_AT_NEIGHBOR -> placementPos.relative(direction.getOpposite()); - case REPLACE_EXISTING_BLOCK -> placementPos; - }; - BlockState supportState = world.getBlockState(interactedPos); - if (targetMode == TargetMode.PLACE_AT_NEIGHBOR && supportState.canBeReplaced()) continue; - - Vec3 targetPositionOnBlock = centerOfFace(interactedPos, direction); - - if (!considerFacingAwayFaces && pointsAwayFromPlayer(eyePos, targetPositionOnBlock, direction)) { - continue; - } - - Rotation targetRotation = Rotation.lookingAt(targetPositionOnBlock, eyePos).normalize(); - float angle = baseRotation.angleTo(targetRotation); - if (angle < bestAngle) { - bestAngle = angle; - bestPlan = new TargetPlan(interactedPos, direction); - } - } - - return bestPlan; - } - - private static PointOnFace findTargetPointOnFace( - List boxes, - BlockPos interactedPos, - Direction direction, - boolean preferUpperHalf, - ScaffoldFacePositionFactory facePositionFactory - ) { - PointOnFace best = null; - double bestDirectionalDistance = Double.NEGATIVE_INFINITY; - double bestY = Double.NEGATIVE_INFINITY; - - for (AABB box : boxes) { - ScaffoldFacePositionFactory.Face face = ScaffoldFacePositionFactory.Face.fromBox(box.move( - interactedPos.getX(), - interactedPos.getY(), - interactedPos.getZ() - ), direction); - - ScaffoldFacePositionFactory.Face searchFace = face; - if (preferUpperHalf && face.maxY() - interactedPos.getY() >= 0.9) { - ScaffoldFacePositionFactory.Face truncated = face.truncateMinY(interactedPos.getY() + 0.6); - if (truncated != null) { - searchFace = truncated; - } - } - - Vec3 point = facePositionFactory != null - ? facePositionFactory.producePoint(searchFace) - : searchFace.center(); - if (point == null) continue; - - double directionalDistance = directionalSupportDistance(point, direction, interactedPos); - if (directionalDistance > bestDirectionalDistance - || (Math.abs(directionalDistance - bestDirectionalDistance) < 1.0E-7 && point.y > bestY)) { - bestDirectionalDistance = directionalDistance; - bestY = point.y; - best = new PointOnFace(face, point); - } - } - - return best; - } - - private static List buildInvestigationTargets(BlockPos targetPos, List offsets, Comparator comparator) { - List candidates = new ArrayList<>(); - if (offsets == null || offsets.isEmpty()) { - candidates.add(targetPos); - } else { - for (BlockPos offset : offsets) { - candidates.add(targetPos.offset(offset)); - } - } - - if (comparator != null) { - candidates.sort((a, b) -> comparator.compare(b, a)); - } - return candidates; - } - - private static boolean isBlockSolid(BlockState state, LocalPlayer player, BlockPos pos) { - return state != null - && player != null - && player.level() != null - && state.isFaceSturdy(player.level(), pos, Direction.UP, SupportType.CENTER); - } - - private static boolean canBeReplacedWith( - LocalPlayer player, - BlockPos pos, - ItemStack stack, - BlockState state - ) { - if (player == null || stack == null || state == null) { - return false; - } - - BlockPlaceContext context = new BlockPlaceContext( - player.level(), - player, - InteractionHand.MAIN_HAND, - stack, - new BlockHitResult(Vec3.atCenterOf(pos), Direction.UP, pos, false) - ); - return state.canBeReplaced(context); - } - - private static boolean pointsAwayFromPlayer(Vec3 eyePos, Vec3 hitVec, Direction direction) { - Vec3 delta = eyePos.subtract(hitVec); - Vec3 normal = new Vec3(direction.getStepX(), direction.getStepY(), direction.getStepZ()); - return delta.normalize().dot(normal) < 0.0; - } - - private static Vec3 centerOfFace(BlockPos pos, Direction side) { - double x = pos.getX() + 0.5 + side.getStepX() * 0.5; - double y = pos.getY() + 0.5 + side.getStepY() * 0.5; - double z = pos.getZ() + 0.5 + side.getStepZ() * 0.5; - return new Vec3(x, y, z); - } - - private static double directionalSupportDistance(Vec3 point, Direction direction) { - return directionalSupportDistance(point, direction, BlockPos.ZERO); - } - - private static double directionalSupportDistance(Vec3 point, Direction direction, BlockPos origin) { - Vec3 centered = point.subtract(origin.getX() + 0.5, origin.getY() + 0.5, origin.getZ() + 0.5); - Vec3 directionVector = new Vec3(direction.getStepX(), direction.getStepY(), direction.getStepZ()); - Vec3 projected = new Vec3( - centered.x * directionVector.x, - centered.y * directionVector.y, - centered.z * directionVector.z - ); - return projected.lengthSqr(); - } - - private enum TargetMode { - PLACE_AT_NEIGHBOR, - REPLACE_EXISTING_BLOCK - } - - private record PointOnFace(ScaffoldFacePositionFactory.Face face, Vec3 point) { - } - - private record TargetPlan(BlockPos interactedPos, Direction direction) { - } -} diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/AttackPressing.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/AttackPressing.java index 5b0455c..4efd799 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/AttackPressing.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/AttackPressing.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/ClickHumanizer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/ClickHumanizer.java index 9103291..8686165 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/ClickHumanizer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/ClickHumanizer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/ClickScheduler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/ClickScheduler.java index 5681c03..ba361f8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/ClickScheduler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/click/ClickScheduler.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/AntiBotTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/AntiBotTracker.java index 539ec60..8ece3d6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/AntiBotTracker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/AntiBotTracker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/AttackUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/AttackUtil.java index a3614ab..7650cc1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/AttackUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/AttackUtil.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -25,9 +25,6 @@ import dev.loki.lovisual.events.Events; import dev.loki.lovisual.events.impl.AttackEntityEvent; import dev.loki.lovisual.features.gui.hud.draggable.impl.TargetHud; import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.AttributeSwap; -import dev.loki.lovisual.features.module.modules.combat.Criticals; -import dev.loki.lovisual.features.module.modules.combat.Hitbox; import dev.loki.lovisual.features.module.modules.combat.RubberHand; import dev.loki.lovisual.features.module.modules.misc.HitSounds; import dev.loki.lovisual.features.module.modules.visuals.HitEffect; @@ -110,18 +107,7 @@ public enum AttackUtil { return false; } - AttributeSwap.QueueResult attributeSwapResult = AttributeSwap.queueAttackResult(target, keepSprint); - if (attributeSwapResult == AttributeSwap.QueueResult.HANDLE) { - return true; - } - if (attributeSwapResult == AttributeSwap.QueueResult.SUPPRESS) { - return false; - } - boolean attacked = performAttack(mc, player, target, keepSprint); - if (attacked) { - AttributeSwap.afterNormalAttackIfActive(target, keepSprint); - } return attacked; } @@ -140,11 +126,6 @@ public enum AttackUtil { LocalPlayer player, LivingEntity target, boolean keepSprint) { - Criticals criticals = Modules.get(Criticals.class); - if (criticals != null && criticals.isEnabled()) { - criticals.beforeAttack(mc, player, target); - } - if (keepSprint) { if (!performKeepSprintAttack(mc, player, target)) { return false; @@ -170,7 +151,7 @@ public enum AttackUtil { LivingEntity target) { if (mc.getConnection() == null) return false; if (mc.gameMode instanceof MultiPlayerGameModeAccessor accessor) { - accessor.combatant$syncSelectedSlot(); + accessor.lovisual$syncSelectedSlot(); } notifyLocalAttack(target); @@ -184,10 +165,6 @@ public enum AttackUtil { if (player != null && Events.BUS.hasListeners(AttackEntityEvent.class)) { Events.BUS.post(new AttackEntityEvent(player, target)); } - Hitbox hitbox = Modules.get(Hitbox.class); - if (hitbox != null) { - hitbox.markHit(target); - } HitSounds hitSounds = Modules.get(HitSounds.class); if (hitSounds != null) { hitSounds.handleHit(target); @@ -240,7 +217,7 @@ public enum AttackUtil { ServerboundPlayerCommandPacket.Action.STOP_SPRINTING )); if (player instanceof LocalPlayerAccessor accessor) { - accessor.combatant$setLastSprinting(false); + accessor.lovisual$setLastSprinting(false); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/CombatRotationModeUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/CombatRotationModeUtil.java index ed36fed..4f526a0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/CombatRotationModeUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/CombatRotationModeUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/CombatStrikeController.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/CombatStrikeController.java index 5679480..768f6f3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/CombatStrikeController.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/CombatStrikeController.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,9 +11,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket; import net.minecraft.world.entity.LivingEntity; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.AttributeSwap; -import dev.loki.lovisual.features.module.modules.movement.Sprint; import dev.loki.lovisual.util.click.AttackPressing; import dev.loki.lovisual.util.click.ClickScheduler; @@ -41,8 +38,7 @@ public final class CombatStrikeController { return false; } int cooldownTicks = legacyProtocol ? 0 : 1; - return AttackPressing.INSTANCE.isCooldownComplete(player, target, legacyProtocol, cooldownTicks) - || (!legacyProtocol && AttributeSwap.shouldBypassAuraCooldownFor(player, target)); + return AttackPressing.INSTANCE.isCooldownComplete(player, target, legacyProtocol, cooldownTicks); } public boolean tryAttack(Minecraft mc, @@ -57,8 +53,7 @@ public final class CombatStrikeController { } int cooldownTicks = legacyProtocol ? 0 : 1; - boolean attributeSwapBypass = !legacyProtocol && AttributeSwap.shouldBypassAuraCooldownFor(mc.player, target); - if (!attributeSwapBypass && !AttackPressing.INSTANCE.isCooldownComplete(mc.player, target, legacyProtocol, cooldownTicks)) { + if (!AttackPressing.INSTANCE.isCooldownComplete(mc.player, target, legacyProtocol, cooldownTicks)) { return false; } @@ -163,12 +158,8 @@ public final class CombatStrikeController { return mode; } - Sprint sprint = Modules.get(Sprint.class); - if (sprint == null || !sprint.isEnabled()) { - return SprintResetMode.LEGIT; - } - - return sprint.resolveCombatResetMode(); + // Sprint module removed; default to legit reset. + return SprintResetMode.LEGIT; } public void executeAttacks(Minecraft mc, LivingEntity target, int clickCount, boolean legacyProtocol) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/LethalStrikeCalculator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/LethalStrikeCalculator.java index 64d16b5..046b039 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/LethalStrikeCalculator.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/LethalStrikeCalculator.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/ProtocolAttackExecutor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/ProtocolAttackExecutor.java index 7c4b9a7..31ddf7f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/ProtocolAttackExecutor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/ProtocolAttackExecutor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/RubberHandUseUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/RubberHandUseUtil.java index 7583861..902fed9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/RubberHandUseUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/RubberHandUseUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/SprintController.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/SprintController.java index b734f38..2bee3c0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/SprintController.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/SprintController.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,8 +14,6 @@ import dev.loki.lovisual.events.EventHandler; import dev.loki.lovisual.events.impl.GameTickEvent; import dev.loki.lovisual.events.impl.PacketEvent; import dev.loki.lovisual.events.impl.SprintControlEvent; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.Sprint; import dev.loki.lovisual.mixins.accessors.LocalPlayerAccessor; /** @@ -95,7 +93,7 @@ public final class SprintController { return false; } - return ((LocalPlayerAccessor) player).combatant$canStartSprinting(); + return ((LocalPlayerAccessor) player).lovisual$canStartSprinting(); } /** @@ -170,19 +168,6 @@ public final class SprintController { return original; } - Sprint sprint = Modules.get(Sprint.class); - if (sprint != null && sprint.isEnabled()) { - if (sprint.shouldSuppressExternalVulcanSprintForControl()) { - return false; - } - if (sprint.shouldAvoidForceSprintForSwimStart(player)) { - return original; - } - if (player.input.hasForwardImpulse()) { - return true; - } - } - if (isSprintInputRequested(player) && player.input.hasForwardImpulse()) { return true; } @@ -212,10 +197,10 @@ public final class SprintController { LocalPlayerAccessor accessor = (LocalPlayerAccessor) player; if (player.isSwimming()) { - return accessor.combatant$shouldStopSwimSprinting(); + return accessor.lovisual$shouldStopSwimSprinting(); } - return accessor.combatant$shouldStopSprinting(); + return accessor.lovisual$shouldStopSprinting(); } public boolean shouldStopSprintingForControl(LocalPlayer player) { @@ -235,8 +220,8 @@ public final class SprintController { } private boolean shouldStopAtHorizontalObstacle() { - Sprint sprint = Modules.get(Sprint.class); - return sprint == null || !sprint.isEnabled() || sprint.isLegitResetMode(); + // Sprint module removed; always stop sprinting at horizontal obstacles. + return true; } @EventHandler(priority = 3000) diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/VulcanReachController.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/VulcanReachController.java index fad9d27..8c8de16 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/VulcanReachController.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/VulcanReachController.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/ClientProtocolVersion.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/ClientProtocolVersion.java index 245d442..db97536 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/ClientProtocolVersion.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/ClientProtocolVersion.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristicSource.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristicSource.java index 3965b87..ecf898d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristicSource.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristicSource.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristics.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristics.java index ec0e4e4..a1a2f09 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristics.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristics.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristicsConfig.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristicsConfig.java index fff7c34..19345a4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristicsConfig.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/CombatProtocolHeuristicsConfig.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/ProtocolUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/ProtocolUtil.java index bf1c8a7..3cb89b5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/ProtocolUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/ProtocolUtil.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/vfp/VfpCompatibility.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/vfp/VfpCompatibility.java index 6580af0..fcfbf13 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/vfp/VfpCompatibility.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/vfp/VfpCompatibility.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/vfp/VfpCompatibility1_8.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/vfp/VfpCompatibility1_8.java index ba70fe0..b4d2c09 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/vfp/VfpCompatibility1_8.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/combat/protocol/vfp/VfpCompatibility1_8.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/EagleUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/EagleUtil.java index c582b59..cb3b624 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/EagleUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/EagleUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/FreecamEntity.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/FreecamEntity.java index 34b9f32..b4e8f26 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/FreecamEntity.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/FreecamEntity.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/BoatSimulationCache.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/BoatSimulationCache.java index c89f35b..d77b71b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/BoatSimulationCache.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/BoatSimulationCache.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/MountedEntityPrediction.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/MountedEntityPrediction.java index 929f82e..bef46f9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/MountedEntityPrediction.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/MountedEntityPrediction.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/PositionExtrapolation.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/PositionExtrapolation.java index bbf2cd7..f7af5ca 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/PositionExtrapolation.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/PositionExtrapolation.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/PositionPredictor.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/PositionPredictor.java index acf7094..69f3115 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/PositionPredictor.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/entity/simulation/PositionPredictor.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/input/KeyManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/input/KeyManager.java index 4eb3b14..4ac9289 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/input/KeyManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/input/KeyManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/input/KeyUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/input/KeyUtil.java index 5334fd1..383fd53 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/input/KeyUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/input/KeyUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantMeta.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantMeta.java index e97b5e5..1e34b37 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantMeta.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantMeta.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantRegistry.java index f2e606b..29b4f12 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantUtil.java index 6237a8c..172f215 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/EnchantUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/FoodUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/FoodUtil.java index 18b27aa..8001f8a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/FoodUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/FoodUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/IllegalItemUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/IllegalItemUtil.java index b05d9d7..48d9cb6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/IllegalItemUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/IllegalItemUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/ItemRarityColorProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/ItemRarityColorProvider.java index 6a0e77e..df67435 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/ItemRarityColorProvider.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/ItemRarityColorProvider.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/RarityColorConfig.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/RarityColorConfig.java index ec35196..fbbced5 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/RarityColorConfig.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/RarityColorConfig.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/RarityColorUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/RarityColorUtil.java index 34727de..f6f60d3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/RarityColorUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/RarityColorUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/TopEnchantUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/TopEnchantUtil.java index 4e87e38..4b0a773 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/TopEnchantUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/item/TopEnchantUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/DebugLog.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/DebugLog.java index cf7bab1..20e47fb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/DebugLog.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/DebugLog.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/DebugMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/DebugMode.java index 6ee65bd..08a1d3f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/DebugMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/DebugMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/ServerDumpUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/ServerDumpUtil.java index aef977a..72d511e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/ServerDumpUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/logging/ServerDumpUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/map/MapPlayersCache.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/map/MapPlayersCache.java index 7b209b4..66d9d5d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/map/MapPlayersCache.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/map/MapPlayersCache.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/IMediaSession.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/IMediaSession.java index 6ebb857..0d2a121 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/IMediaSession.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/IMediaSession.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * @@ -13,7 +13,7 @@ package dev.loki.lovisual.util.media; /** - * Modified Java port for Combatant by dev.loki.lovisual. + * Modified Java port for LoVisual by dev.loki.lovisual. * Based on Redstonecrafter0/MediaPlayerInfo. */ public interface IMediaSession { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaInfo.java index 0343e2f..09d6c2c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaInfo.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * @@ -16,7 +16,7 @@ import java.util.Arrays; import java.util.Objects; /** - * Modified Java port for Combatant by dev.loki.lovisual. + * Modified Java port for LoVisual by dev.loki.lovisual. * Based on Redstonecrafter0/MediaPlayerInfo. */ public record MediaInfo(String title, String artist, byte[] artworkPng, long position, long duration, boolean playing) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaPlayerInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaPlayerInfo.java index 520bb6a..c4f58c2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaPlayerInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaPlayerInfo.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * @@ -20,7 +20,7 @@ import java.util.List; import java.util.Locale; /** - * Modified Java port for Combatant by dev.loki.lovisual. + * Modified Java port for LoVisual by dev.loki.lovisual. * Based on Redstonecrafter0/MediaPlayerInfo. */ public interface MediaPlayerInfo { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaSessionService.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaSessionService.java index 048648e..81ec34a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaSessionService.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/MediaSessionService.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * @@ -83,7 +83,7 @@ public final class MediaSessionService { public synchronized void init() { if (pollingThread != null && pollingThread.isAlive()) return; pollingRunning = true; - pollingThread = new Thread(this::pollMediaSessions, "CombatantMediaInfoPollingThread"); + pollingThread = new Thread(this::pollMediaSessions, "LoVisualMediaInfoPollingThread"); pollingThread.setDaemon(true); pollingThread.start(); } @@ -347,7 +347,7 @@ public final class MediaSessionService { if (mc == null || media == null || media.artworkPng() == null || media.artworkPng().length == 0) return; NativeImage image = getArtworkAsNativeImage(media); if (image == null) return; - DynamicTexture texture = new DynamicTexture(() -> "combatant_media_artwork", image); + DynamicTexture texture = new DynamicTexture(() -> "lovisual_media_artwork", image); mc.getTextureManager().register(ARTWORK_ID, texture); artworkTexture = ARTWORK_ID; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/RepeatMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/RepeatMode.java index 34fcd97..8242ac8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/RepeatMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/RepeatMode.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * @@ -15,7 +15,7 @@ package dev.loki.lovisual.util.media; import java.util.Locale; /** - * Modified Java port for Combatant by dev.loki.lovisual. + * Modified Java port for LoVisual by dev.loki.lovisual. * Based on Redstonecrafter0/MediaPlayerInfo. */ public enum RepeatMode { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/DummyMediaPlayerInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/DummyMediaPlayerInfo.java index a0699a4..339dc0b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/DummyMediaPlayerInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/DummyMediaPlayerInfo.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/LinuxMediaPlayerInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/LinuxMediaPlayerInfo.java index 00590e6..0f77724 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/LinuxMediaPlayerInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/LinuxMediaPlayerInfo.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * @@ -26,7 +26,7 @@ import java.util.ArrayList; import java.util.List; /** - * Modified Java port for Combatant by dev.loki.lovisual. + * Modified Java port for LoVisual by dev.loki.lovisual. * Based on Redstonecrafter0/MediaPlayerInfo. */ public final class LinuxMediaPlayerInfo implements MediaPlayerInfo { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/LinuxMediaSession.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/LinuxMediaSession.java index 4813fc0..6ef044b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/LinuxMediaSession.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/LinuxMediaSession.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * @@ -28,7 +28,7 @@ import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** - * Modified Java port for Combatant by dev.loki.lovisual. + * Modified Java port for LoVisual by dev.loki.lovisual. * Based on Redstonecrafter0/MediaPlayerInfo. */ public final class LinuxMediaSession implements IMediaSession { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/dbus/Player.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/dbus/Player.java index 49eb60b..aa110c0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/dbus/Player.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/linux/dbus/Player.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * @@ -22,7 +22,7 @@ import org.freedesktop.dbus.types.Variant; import java.util.Map; /** - * Modified Java port for Combatant by dev.loki.lovisual. + * Modified Java port for LoVisual by dev.loki.lovisual. * Based on Redstonecrafter0/MediaPlayerInfo. */ @DBusInterfaceName("org.mpris.MediaPlayer2.Player") diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/win/WindowsMediaPlayerInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/win/WindowsMediaPlayerInfo.java index b884789..15d5a17 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/win/WindowsMediaPlayerInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/win/WindowsMediaPlayerInfo.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * @@ -30,7 +30,7 @@ import java.util.List; import java.util.Map; /** - * Modified Java/native port for Combatant by dev.loki.lovisual. + * Modified Java/native port for LoVisual by dev.loki.lovisual. * Based on Redstonecrafter0/MediaPlayerInfo. */ public final class WindowsMediaPlayerInfo implements MediaPlayerInfo { @@ -93,7 +93,7 @@ public final class WindowsMediaPlayerInfo implements MediaPlayerInfo { if (stream == null) { throw new UnsatisfiedLinkError("Missing native resource: " + resource); } - Path dir = Files.createTempDirectory("combatant-mediainfo-"); + Path dir = Files.createTempDirectory("lovisual-mediainfo-"); Path dll = dir.resolve("MediaPlayerInfo.dll"); Files.copy(stream, dll); dll.toFile().deleteOnExit(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/win/WindowsMediaSession.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/win/WindowsMediaSession.java index 0fc26b2..f2cd604 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/win/WindowsMediaSession.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/media/impl/win/WindowsMediaSession.java @@ -1,8 +1,8 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * - * This file belongs to Combatant's MediaPlayerInfo integration, based on + * This file belongs to LoVisual's MediaPlayerInfo integration, based on * https://github.com/Redstonecrafter0/MediaPlayerInfo. * Copyright (c) Redstonecrafter0 and contributors. * @@ -17,7 +17,7 @@ import dev.loki.lovisual.util.media.MediaInfo; import dev.loki.lovisual.util.media.RepeatMode; /** - * Modified Java/native port for Combatant by dev.loki.lovisual. + * Modified Java/native port for LoVisual by dev.loki.lovisual. * Based on Redstonecrafter0/MediaPlayerInfo. */ public final class WindowsMediaSession implements IMediaSession { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/BacktrackController.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/BacktrackController.java index f4bcc41..25376ed 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/BacktrackController.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/BacktrackController.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/BlinkManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/BlinkManager.java index 46bbb41..f9702ad 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/BlinkManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/BlinkManager.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/FakeLagController.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/FakeLagController.java index 59290fb..cba1c1b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/FakeLagController.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/FakeLagController.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/PacketSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/PacketSnapshot.java index 69c39ba..c537ceb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/PacketSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/PacketSnapshot.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/TransferOrigin.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/TransferOrigin.java index dc4d1a8..fb2f5a8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/TransferOrigin.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/network/TransferOrigin.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ElytraRecastUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ElytraRecastUtil.java index 362bc95..7d3d8e9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ElytraRecastUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ElytraRecastUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/EnvironmentMovementController.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/EnvironmentMovementController.java index 5e028e3..f9ace6d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/EnvironmentMovementController.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/EnvironmentMovementController.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,9 +10,6 @@ package dev.loki.lovisual.util.player; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.movement.NoStun; - public enum EnvironmentMovementController { ; @@ -22,34 +19,12 @@ public enum EnvironmentMovementController { private static final float STICKY_VELOCITY_MULTIPLIER = 0.4F; public static Float getSlipperinessOverride(Block block) { - if (block == null) { - return null; - } - - NoStun noStun = Modules.get(NoStun.class); - if (noStun != null) { - Float override = noStun.getSlipperinessOverride(block, vanillaSlipperiness(block)); - if (override != null) { - return override; - } - } - + // NoStun module removed; no slipperiness override remains. return null; } public static Float getVelocityMultiplierOverride(Block block) { - if (block == null) { - return null; - } - - NoStun noStun = Modules.get(NoStun.class); - if (noStun != null) { - Float override = noStun.getVelocityMultiplierOverride(block, vanillaVelocityMultiplier(block)); - if (override != null) { - return override; - } - } - + // NoStun module removed; no velocity multiplier override remains. return null; } @@ -62,11 +37,8 @@ public enum EnvironmentMovementController { } private static boolean isNoStunHoneyEnabled() { - NoStun noStun = Modules.get(NoStun.class); - return noStun != null - && noStun.isEnabled() - && noStun.isFunctionEnabled(NoStun.fnEnvBlocks()) - && noStun.isEnvBlockEnabled(NoStun.envHoney()); + // NoStun module removed; never preserve honey slide. + return false; } private static float vanillaSlipperiness(Block block) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/InteractionUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/InteractionUtil.java index da31fa0..e17a4f3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/InteractionUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/InteractionUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * Portions derived from ThunderHack Recode, copyright (c) 2023-2024 Pan4ur & 06ED. * Upstream: https://github.com/Pan4ur/ThunderHack-Recode @@ -45,7 +45,7 @@ public enum InteractionUtil { public static void sendSequencedPacket(PredictiveAction packetCreator) { Minecraft mc = Minecraft.getInstance(); if (mc == null || mc.level == null || mc.getConnection() == null) return; - BlockStatePredictionHandler pending = ((ClientLevelAccessor) mc.level).combatant$getPendingUpdateManager(); + BlockStatePredictionHandler pending = ((ClientLevelAccessor) mc.level).lovisual$getPendingUpdateManager(); try (BlockStatePredictionHandler pendingUpdateManager = pending.startPredicting()) { int id = pendingUpdateManager.currentSequence(); mc.getConnection().send(packetCreator.predict(id)); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/MovementUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/MovementUtil.java index 6d40960..a6093f8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/MovementUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/MovementUtil.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/NetworkStatsUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/NetworkStatsUtil.java index 527f59c..7aa3bdd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/NetworkStatsUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/NetworkStatsUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerHealthResolver.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerHealthResolver.java index 133b450..e41668f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerHealthResolver.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerHealthResolver.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerSkinResolver.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerSkinResolver.java index fdba420..d0a7827 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerSkinResolver.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerSkinResolver.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerSpeedUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerSpeedUtil.java index e564857..89e90e4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerSpeedUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/PlayerSpeedUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ResetAttackCooldown.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ResetAttackCooldown.java index 54cba6d..27ac08c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ResetAttackCooldown.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ResetAttackCooldown.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ServerFlyUtils.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ServerFlyUtils.java index 95834f5..c80ca52 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ServerFlyUtils.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/ServerFlyUtils.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectAccess.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectAccess.java index 50efce0..2c47532 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectAccess.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectAccess.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectHeuristics.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectHeuristics.java index a02b929..bd97f87 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectHeuristics.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectHeuristics.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -368,7 +368,7 @@ public enum StatusEffectHeuristics { private static int extractColor(ParticleOptions particle) { if (particle instanceof EffectParticleEffectAccessor effect) { - return effect.combatant$getColor() & 0xFFFFFF; + return effect.lovisual$getColor() & 0xFFFFFF; } if (particle instanceof ColorParticleOption tinted) { int r = Math.min(255, Math.max(0, Math.round(tinted.getRed() * 255f))); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectInference.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectInference.java index 0ebccf1..e4389ed 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectInference.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectInference.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectTracker.java index 0c17f54..2891b96 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectTracker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectTracker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectView.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectView.java index 313eeb5..bc07b31 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectView.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/effect/StatusEffectView.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/FireworkUseController.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/FireworkUseController.java index 5a82f4e..2fc2246 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/FireworkUseController.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/FireworkUseController.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -15,9 +15,6 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.projectile.FireworkRocketEntity; import net.minecraft.world.item.Items; -import dev.loki.lovisual.features.module.Modules; -import dev.loki.lovisual.features.module.modules.combat.KillAura; - /** * Shared firework-use path for elytra modules. *

@@ -129,11 +126,7 @@ public final class FireworkUseController { } private boolean isKillAuraAttackWindowBusy() { - KillAura killAura = Modules.get(KillAura.class); - if (killAura == null || !killAura.isEnabled() || killAura.getCurrentTarget() == null) { - return false; - } - - return killAura.willAttackInTicks(0) || killAura.willAttackInTicks(1); + // KillAura module removed; no combat-window blocking remains. + return false; } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventoryActionKind.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventoryActionKind.java index bd69076..62b000a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventoryActionKind.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventoryActionKind.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySearchScope.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySearchScope.java index 0bd7928..5f27724 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySearchScope.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySearchScope.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwap.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwap.java index 6cc160c..7579063 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwap.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwap.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -79,7 +79,7 @@ public final class InventorySwap { if (handler != null && playerInventory != null) { for (Slot slot : handler.slots) { if (slot == null || slot.container != playerInventory) continue; - if (((SlotAccessor) slot).combatant$getIndex() == inventorySlot) { + if (((SlotAccessor) slot).lovisual$getIndex() == inventorySlot) { return slot.index; } } @@ -100,7 +100,7 @@ public final class InventorySwap { int min = Integer.MAX_VALUE; for (Slot slot : handler.slots) { if (slot == null || slot.container != inventory) continue; - int index = ((SlotAccessor) slot).combatant$getIndex(); + int index = ((SlotAccessor) slot).lovisual$getIndex(); if (index >= 9 && index < 36) { min = Math.min(min, slot.index); } @@ -118,7 +118,7 @@ public final class InventorySwap { int min = Integer.MAX_VALUE; for (Slot slot : handler.slots) { if (slot == null || slot.container != inventory) continue; - int index = ((SlotAccessor) slot).combatant$getIndex(); + int index = ((SlotAccessor) slot).lovisual$getIndex(); if (index >= 0 && index < 9) { min = Math.min(min, slot.index); } @@ -343,7 +343,7 @@ public final class InventorySwap { public int clientSelectedSlot() { LocalPlayer player = mc.player; if (player == null) return 0; - return ((PlayerInventoryAccessor) player.getInventory()).combatant$getSelectedSlot(); + return ((PlayerInventoryAccessor) player.getInventory()).lovisual$getSelectedSlot(); } public boolean isHotbarLeased() { @@ -396,7 +396,7 @@ public final class InventorySwap { int current = clientSelectedSlot(); if (current != slot) { - ((PlayerInventoryAccessor) player.getInventory()).combatant$setSelectedSlot(slot); + ((PlayerInventoryAccessor) player.getInventory()).lovisual$setSelectedSlot(slot); } syncInteractionManagerSlot(slot); @@ -979,7 +979,7 @@ public final class InventorySwap { private void syncInteractionManagerSlot(int slot) { if (mc.gameMode instanceof MultiPlayerGameModeAccessor accessor) { - accessor.combatant$setLastSelectedSlot(slot); + accessor.lovisual$setLastSelectedSlot(slot); } } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapMode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapMode.java index b195ba5..b4916fa 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapMode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapMode.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapPolicy.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapPolicy.java index 38f9df0..0818eab 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapPolicy.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapPolicy.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapRequest.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapRequest.java index 5d53100..e059ff7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapRequest.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapRequest.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapVisibility.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapVisibility.java index 22d3dff..893aa54 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapVisibility.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/InventorySwapVisibility.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/SlotResult.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/SlotResult.java index b5a659b..e18c0d4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/SlotResult.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/inventory/SlotResult.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/LocalPlayerSimulation.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/LocalPlayerSimulation.java index d9d65d2..c2970ea 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/LocalPlayerSimulation.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/LocalPlayerSimulation.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/PlayerMovementSimulation.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/PlayerMovementSimulation.java index 172bec7..f27f6e8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/PlayerMovementSimulation.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/PlayerMovementSimulation.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -350,7 +350,7 @@ abstract class PlayerMovementSimulation { } private void updateVelocity(float speed, Vec3 movementInput) { - Vec3 added = EntityInvoker.combatant$movementInputToVelocity(movementInput, speed, yaw); + Vec3 added = EntityInvoker.lovisual$movementInputToVelocity(movementInput, speed, yaw); velocity = velocity.add(added); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/PlayerSimulationCache.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/PlayerSimulationCache.java index 7864828..6079fdb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/PlayerSimulationCache.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/PlayerSimulationCache.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/RemotePlayerObservation.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/RemotePlayerObservation.java index ac15997..8f72488 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/RemotePlayerObservation.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/RemotePlayerObservation.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/RemotePlayerSimulation.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/RemotePlayerSimulation.java index f94979c..2a154a6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/RemotePlayerSimulation.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/RemotePlayerSimulation.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/SimulatedInput.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/SimulatedInput.java index 366d614..a58b40a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/SimulatedInput.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/player/simulation/SimulatedInput.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/CydhranianProjectileAngleCalculator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/CydhranianProjectileAngleCalculator.java index 4bebe10..c05b18d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/CydhranianProjectileAngleCalculator.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/CydhranianProjectileAngleCalculator.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/PointFinding.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/PointFinding.java index d49e1e5..20d935a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/PointFinding.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/PointFinding.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/PolynomialProjectileAngleCalculator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/PolynomialProjectileAngleCalculator.java index 632bdf3..71a24c3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/PolynomialProjectileAngleCalculator.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/PolynomialProjectileAngleCalculator.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileAngleCalculator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileAngleCalculator.java index 5904be7..fc14935 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileAngleCalculator.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileAngleCalculator.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileMath.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileMath.java index 6e0eeaf..ae7b4da 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileMath.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileMath.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectilePredictionUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectilePredictionUtil.java index 6e39f8c..747c36f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectilePredictionUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectilePredictionUtil.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileTarget.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileTarget.java index f8fff7d..0eb30cd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileTarget.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileTarget.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileTargetPointFinder.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileTargetPointFinder.java index 857c84c..7ff04f8 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileTargetPointFinder.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/ProjectileTargetPointFinder.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/SimulatedArrow.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/SimulatedArrow.java index 33faa5f..eff1508 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/SimulatedArrow.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/SimulatedArrow.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/SituationalProjectileAngleCalculator.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/SituationalProjectileAngleCalculator.java index b582db6..a91827a 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/SituationalProjectileAngleCalculator.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/SituationalProjectileAngleCalculator.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryData.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryData.java index 1273c77..da04e87 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryData.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryData.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -92,7 +92,7 @@ public enum TrajectoryData { if (entity instanceof AbstractArrow persistent) { boolean inGround; try { - inGround = ((PersistentProjectileEntityAccessor) persistent).combatant$isInGround(); + inGround = ((PersistentProjectileEntityAccessor) persistent).lovisual$isInGround(); } catch (Throwable ignored) { inGround = false; } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryInfo.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryInfo.java index db756f5..28f13a6 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryInfo.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryInfo.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryType.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryType.java index 044dd88..1cea901 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryType.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/projectile/TrajectoryType.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyBackend.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyBackend.java index f1c4937..d17948f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyBackend.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyBackend.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyConfig.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyConfig.java index 62f9d21..86175ac 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyConfig.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyConfig.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyEntry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyEntry.java index 01cb84c..eccdcca 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyEntry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyEntry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyHandshakeHandler.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyHandshakeHandler.java index f4d124f..55c0ea0 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyHandshakeHandler.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyHandshakeHandler.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyNettyInstaller.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyNettyInstaller.java index 4f95aa4..33dbfa3 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyNettyInstaller.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyNettyInstaller.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,7 +13,7 @@ import io.netty.channel.ChannelPipeline; public enum ProxyNettyInstaller { ; - private static final String HANDLER_NAME = "combatant_proxy"; + private static final String HANDLER_NAME = "lovisual_proxy"; public static void install(ChannelPipeline pipeline) { if (pipeline == null) return; diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyType.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyType.java index 47c004b..8e67aac 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyType.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/proxy/ProxyType.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/CooldownRegistry.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/CooldownRegistry.java index b9081dd..4fb1b3d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/CooldownRegistry.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/CooldownRegistry.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemCooldownRuleProvider.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemCooldownRuleProvider.java index b4269bb..f346c99 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemCooldownRuleProvider.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemCooldownRuleProvider.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemCooldownSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemCooldownSnapshot.java index c9fcc61..ad7e54f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemCooldownSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemCooldownSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemUseCooldowns.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemUseCooldowns.java index bdabde1..f11cc26 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemUseCooldowns.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/ItemUseCooldowns.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpChatParser.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpChatParser.java index cc87e2a..5ba816f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpChatParser.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpChatParser.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpOverlayParser.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpOverlayParser.java index 5a94910..86fe709 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpOverlayParser.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpOverlayParser.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpState.java index d0daf6c..e95226f 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTabParser.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTabParser.java index 5dac8c0..97ed81d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTabParser.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTabParser.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTagSource.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTagSource.java index b8df289..d5efee1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTagSource.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTagSource.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTargetState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTargetState.java index 2294986..ee1211e 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTargetState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTargetState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTargetTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTargetTracker.java index 4965892..9980cbe 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTargetTracker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTargetTracker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTextPatternUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTextPatternUtil.java index 744f853..92247a1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTextPatternUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTextPatternUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTracker.java index dd8bb01..f2debf9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTracker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/PvpTracker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/CooldownManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/CooldownManager.java index 5e83af2..dfcbec7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/CooldownManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/CooldownManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/CooldownsState.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/CooldownsState.java index 235f310..2b867e1 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/CooldownsState.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/CooldownsState.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/PendingUseTracker.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/PendingUseTracker.java index 545076f..43032ff 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/PendingUseTracker.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/client/PendingUseTracker.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/OpponentCooldownManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/OpponentCooldownManager.java index 88fd521..47b07c4 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/OpponentCooldownManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/OpponentCooldownManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/TotemPopCounter.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/TotemPopCounter.java index cd95a58..8b4591b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/TotemPopCounter.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/TotemPopCounter.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/TotemPopSnapshot.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/TotemPopSnapshot.java index 278f470..572eeeb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/TotemPopSnapshot.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/pvp/opponents/TotemPopSnapshot.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/raycast/RaycastUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/raycast/RaycastUtil.java index 2ff5906..d73f34c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/raycast/RaycastUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/raycast/RaycastUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/resources/RenderResourceReadiness.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/resources/RenderResourceReadiness.java index 7de8094..9125dfc 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/resources/RenderResourceReadiness.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/resources/RenderResourceReadiness.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/resources/ResourceReloadHooks.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/resources/ResourceReloadHooks.java index afa9f6f..a4f78de 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/resources/ResourceReloadHooks.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/resources/ResourceReloadHooks.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -13,11 +13,11 @@ import dev.loki.lovisual.features.gui.clickgui.settings.I18nPreflightManager; import net.minecraft.server.packs.resources.ResourceManager; import dev.loki.lovisual.features.module.modules.visuals.NameTags; import dev.loki.lovisual.render.engine.TextureStorage; -import dev.loki.lovisual.render.engine.pipeline.CombatantRenderPipelines; +import dev.loki.lovisual.render.engine.pipeline.LoVisualRenderPipelines; import dev.loki.lovisual.render.engine.prewarm.RenderPrewarmManager; import dev.loki.lovisual.render.engine.svg.SvgRegistry; import dev.loki.lovisual.render.engine.text.Fonts; -import dev.loki.lovisual.render.engine.visuals.CombatantVisuals; +import dev.loki.lovisual.render.engine.visuals.LoVisualVisuals; import dev.loki.lovisual.render.iris.IrisRuntime; import dev.loki.lovisual.util.logging.DebugLog; import dev.loki.lovisual.util.media.MediaSessionService; @@ -46,11 +46,11 @@ public enum ResourceReloadHooks { // Reset dynamic media textures (e.g. artwork) so they re-register. MediaSessionService.get().onResourceReload(); - CombatantVisuals.onResourceReload(manager); + LoVisualVisuals.onResourceReload(manager); try { - IrisRuntime.registerCombatantPipelines(); - CombatantRenderPipelines.precompile(manager); + IrisRuntime.registerLoVisualPipelines(); + LoVisualRenderPipelines.precompile(manager); RenderPrewarmManager.prewarm("shader reload complete"); } catch (Throwable t) { DebugLog.error("[LoVisual] Shader precompile failed after resource reload", t); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/screen/ClientScreen.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/screen/ClientScreen.java index 64148c8..c23dd87 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/screen/ClientScreen.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/screen/ClientScreen.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/screen/ScreenCatalog.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/screen/ScreenCatalog.java index 2a91b71..9de22dd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/screen/ScreenCatalog.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/screen/ScreenCatalog.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on InvMove * (https://github.com/PieKing1215/InvMove). * Copyright (c) PieKing1215 and contributors. * * Original portions remain under LGPLv3. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -34,9 +34,9 @@ import java.util.*; public enum ScreenCatalog { ; - public static final String CLICK_GUI = "combatant:click_gui"; - public static final String CLICK_GUI_EDITOR = "combatant:click_gui_editor"; - public static final String CLICK_GUI_PICKER = "combatant:click_gui_picker"; + public static final String CLICK_GUI = "lovisual:click_gui"; + public static final String CLICK_GUI_EDITOR = "lovisual:click_gui_editor"; + public static final String CLICK_GUI_PICKER = "lovisual:click_gui_picker"; private static final Map KNOWN = new LinkedHashMap<>(); private static final Map DISCOVERED = new LinkedHashMap<>(); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/MicrosoftSessionResult.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/MicrosoftSessionResult.java index 7ae5935..84218e2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/MicrosoftSessionResult.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/MicrosoftSessionResult.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/MinecraftGameConfigHolder.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/MinecraftGameConfigHolder.java index 673b0a5..96c9a24 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/MinecraftGameConfigHolder.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/MinecraftGameConfigHolder.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -10,5 +10,5 @@ package dev.loki.lovisual.util.session; import net.minecraft.client.main.GameConfig; public interface MinecraftGameConfigHolder { - GameConfig combatant$getGameConfig(); + GameConfig lovisual$getGameConfig(); } diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/SessionChanger.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/SessionChanger.java index 26e82bc..99ced1d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/SessionChanger.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/SessionChanger.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -137,7 +137,7 @@ public enum SessionChanger { } deferredPostDisconnectUser = current; - ((MinecraftAccessor) client).combatant$setSession(singleplayerJoinUser); + ((MinecraftAccessor) client).lovisual$setSession(singleplayerJoinUser); DebugLog.config("[SessionChanger] restored singleplayer join user for disconnect: current=%s join=%s", safeName(current), safeName(singleplayerJoinUser)); } @@ -152,7 +152,7 @@ public enum SessionChanger { return; } - ((MinecraftAccessor) client).combatant$setSession(deferred); + ((MinecraftAccessor) client).lovisual$setSession(deferred); deferredPostDisconnectUser = null; singleplayerJoinUser = null; DebugLog.config("[SessionChanger] restored deferred post-disconnect user: %s", safeName(deferred)); @@ -193,14 +193,14 @@ public enum SessionChanger { : YggdrasilAuthenticationService.createOffline(client.getProxy()); Services services = Services.create(authService, client.gameDirectory); - GameConfig original = client instanceof MinecraftGameConfigHolder holder ? holder.combatant$getGameConfig() : null; + GameConfig original = client instanceof MinecraftGameConfigHolder holder ? holder.lovisual$getGameConfig() : null; GameConfig.UserData userData = new GameConfig.UserData(user, client.getProxy()); GameConfig config = original == null ? null : new GameConfig(userData, original.display, original.location, original.game, original.quickPlay); UserApiService apiService = data.online() && config != null - ? MinecraftAccessor.combatant$createUserApiService(authService, config) + ? MinecraftAccessor.lovisual$createUserApiService(authService, config) : UserApiService.OFFLINE; UserApiService.UserProperties properties; @@ -222,23 +222,23 @@ public enum SessionChanger { ProfileKeyPairManager keyPairManager = ProfileKeyPairManager.create(apiService, user, client.gameDirectory.toPath()); ReportingContext reportingContext = ReportingContext.create(ReportEnvironment.local(), apiService); - accessor.combatant$setServices(services); - accessor.combatant$setSession(user); - accessor.combatant$setProfileFuture(profileFuture); - accessor.combatant$setUserApiService(apiService); - accessor.combatant$setUserPropertiesFuture(propertiesFuture); - accessor.combatant$setPlayerSocialManager(socialManager); - RemoteFriendListUpdateHandler oldFriendList = accessor.combatant$getRemoteFriendListUpdateHandler(); + accessor.lovisual$setServices(services); + accessor.lovisual$setSession(user); + accessor.lovisual$setProfileFuture(profileFuture); + accessor.lovisual$setUserApiService(apiService); + accessor.lovisual$setUserPropertiesFuture(propertiesFuture); + accessor.lovisual$setPlayerSocialManager(socialManager); + RemoteFriendListUpdateHandler oldFriendList = accessor.lovisual$getRemoteFriendListUpdateHandler(); if (oldFriendList != null) { oldFriendList.close(); } - accessor.combatant$setRemoteFriendListUpdateHandler(friendList); + accessor.lovisual$setRemoteFriendListUpdateHandler(friendList); if (socialManager.isFriendListEnabled()) { friendList.start(); } - accessor.combatant$setTelemetryManager(telemetryManager); - accessor.combatant$setProfileKeyPairManager(keyPairManager); - accessor.combatant$setReportingContext(reportingContext); + accessor.lovisual$setTelemetryManager(telemetryManager); + accessor.lovisual$setProfileKeyPairManager(keyPairManager); + accessor.lovisual$setReportingContext(reportingContext); client.updateTitle(); } catch (Throwable t) { throw new RuntimeException("Unable to change Minecraft session to: " + data, t); diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/SessionLoginData.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/SessionLoginData.java index 87e79a5..7237e9d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/SessionLoginData.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/SessionLoginData.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -20,7 +20,7 @@ public record SessionLoginData(String name, UUID uuid, String accessToken, boole public static SessionLoginData offline(String name) { String cleanName = name == null ? "" : name.trim(); - return new SessionLoginData(cleanName, offlineUuid(cleanName), "combatant:offline", false); + return new SessionLoginData(cleanName, offlineUuid(cleanName), "lovisual:offline", false); } public static UUID offlineUuid(String name) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/DeviceAuthPendingException.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/DeviceAuthPendingException.java index f48ae51..2c1ad4c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/DeviceAuthPendingException.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/DeviceAuthPendingException.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftAuthException.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftAuthException.java index 30a655f..f2f4c9c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftAuthException.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftAuthException.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -11,11 +11,11 @@ public class MicrosoftAuthException extends RuntimeException { private final String key; public MicrosoftAuthException(String message) { - this(message, null, "combatant.auth.microsoft.error"); + this(message, null, "lovisual.auth.microsoft.error"); } public MicrosoftAuthException(String message, Throwable cause) { - this(message, cause, "combatant.auth.microsoft.error"); + this(message, cause, "lovisual.auth.microsoft.error"); } public MicrosoftAuthException(String message, String key) { @@ -24,7 +24,7 @@ public class MicrosoftAuthException extends RuntimeException { public MicrosoftAuthException(String message, Throwable cause, String key) { super(message + (key == null || key.isBlank() ? "" : " (key: " + key + ")"), cause); - this.key = key == null ? "combatant.auth.microsoft.error" : key; + this.key = key == null ? "lovisual.auth.microsoft.error" : key; } public String key() { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftAuthService.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftAuthService.java index 91498e8..2e69b65 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftAuthService.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftAuthService.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on In-Game Account Switcher * (https://github.com/The-Fireplace-Minecraft-Mods/In-Game-Account-Switcher). * Copyright (c) 2015-2022 The_Fireplace and 2021-2026 VidTu. * * Original portions remain under LGPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ @@ -45,14 +45,14 @@ public final class MicrosoftAuthService { private static final String CLIENT_ID = "54fd49e4-2103-4044-9603-2b028c814ec3"; private static final String USER_AGENT = "LoVisual AltManager"; - private static final Duration TIMEOUT = Duration.ofSeconds(Long.getLong("combatant.microsoftAuth.timeout", 15L)); + private static final Duration TIMEOUT = Duration.ofSeconds(Long.getLong("lovisual.microsoftAuth.timeout", 15L)); private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(new ThreadFactory() { private int index; @Override public synchronized Thread newThread(Runnable runnable) { - Thread thread = new Thread(runnable, "CombatantMicrosoftAuth-" + (++index)); + Thread thread = new Thread(runnable, "LoVisualMicrosoftAuth-" + (++index)); thread.setDaemon(true); return thread; } @@ -162,7 +162,7 @@ public final class MicrosoftAuthService { } } } - throw new MicrosoftAuthException("Microsoft device-code login expired", pending, "combatant.auth.microsoft.expired"); + throw new MicrosoftAuthException("Microsoft device-code login expired", pending, "lovisual.auth.microsoft.expired"); } private static MicrosoftTokens deviceCodeToMicrosoftTokens(String deviceCode) { @@ -188,10 +188,10 @@ public final class MicrosoftAuthService { throw new DeviceAuthPendingException("Microsoft device-code login is still pending"); } if ("authorization_declined".equals(error)) { - throw new MicrosoftAuthException("Microsoft device-code login was cancelled by the user", "combatant.auth.microsoft.cancelled"); + throw new MicrosoftAuthException("Microsoft device-code login was cancelled by the user", "lovisual.auth.microsoft.cancelled"); } if ("expired_token".equals(error)) { - throw new MicrosoftAuthException("Microsoft device-code login expired", "combatant.auth.microsoft.expired"); + throw new MicrosoftAuthException("Microsoft device-code login expired", "lovisual.auth.microsoft.expired"); } } catch (DeviceAuthPendingException | MicrosoftAuthException e) { throw e; @@ -293,7 +293,7 @@ public final class MicrosoftAuthService { .thenApply(response -> { int status = response.statusCode(); if (status == HttpURLConnection.HTTP_NOT_FOUND) { - throw new MicrosoftAuthException("Microsoft account has no Minecraft profile", "combatant.auth.microsoft.no_profile"); + throw new MicrosoftAuthException("Microsoft account has no Minecraft profile", "lovisual.auth.microsoft.no_profile"); } if (status != HttpURLConnection.HTTP_OK) { throw badStatus("fetch Minecraft profile", response); @@ -388,13 +388,13 @@ public final class MicrosoftAuthService { JsonObject json = parseJson(response.body(), "parse XSTS unauthorized response"); long error = MicrosoftJson.number(json, "XErr"); if (error == 2148916233L) { - return new MicrosoftAuthException("Microsoft account has no linked Xbox account", "combatant.auth.microsoft.no_xbox"); + return new MicrosoftAuthException("Microsoft account has no linked Xbox account", "lovisual.auth.microsoft.no_xbox"); } if (error == 2148916235L) { - return new MicrosoftAuthException("Xbox Live is not available for this account region", "combatant.auth.microsoft.xbox_unavailable"); + return new MicrosoftAuthException("Xbox Live is not available for this account region", "lovisual.auth.microsoft.xbox_unavailable"); } if (error == 2148916236L || error == 2148916237L || error == 2148916238L) { - return new MicrosoftAuthException("Microsoft account is not allowed to use Xbox Live for Minecraft", "combatant.auth.microsoft.xbox_adult_required"); + return new MicrosoftAuthException("Microsoft account is not allowed to use Xbox Live for Minecraft", "lovisual.auth.microsoft.xbox_adult_required"); } return new MicrosoftAuthException("Unknown XSTS authorization error: " + error); } catch (MicrosoftAuthException e) { diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftDeviceCode.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftDeviceCode.java index 34310c4..999d4c7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftDeviceCode.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftDeviceCode.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on In-Game Account Switcher * (https://github.com/The-Fireplace-Minecraft-Mods/In-Game-Account-Switcher). * Copyright (c) 2015-2022 The_Fireplace and 2021-2026 VidTu. * * Original portions remain under LGPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftJson.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftJson.java index b23876a..95c0750 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftJson.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftJson.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftTokens.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftTokens.java index 87d655b..620cc81 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftTokens.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MicrosoftTokens.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MinecraftProfile.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MinecraftProfile.java index 6e130d0..9b7aacd 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MinecraftProfile.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/MinecraftProfile.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/XboxToken.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/XboxToken.java index ff1b94d..fa6e5d7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/XboxToken.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/session/microsoft/XboxToken.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/target/TargetManager.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/target/TargetManager.java index 6ec38d8..33713da 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/target/TargetManager.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/target/TargetManager.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/target/TargetingUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/target/TargetingUtil.java index 65aa5f1..430b8f7 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/target/TargetingUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/target/TargetingUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/ChatNameUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/ChatNameUtil.java index 09d6c88..1da2c0b 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/ChatNameUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/ChatNameUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/ClipboardUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/ClipboardUtil.java index d92de74..2614057 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/ClipboardUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/ClipboardUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/LegacyTextUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/LegacyTextUtil.java index e4e5709..9b90556 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/LegacyTextUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/LegacyTextUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextJsonUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextJsonUtil.java index 57c1431..200d954 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextJsonUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextJsonUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextRenderUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextRenderUtil.java index fb647d4..b4a3ee2 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextRenderUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextRenderUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextSelection.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextSelection.java index ef5125f..2377d68 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextSelection.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/text/TextSelection.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/time/Timer.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/time/Timer.java index 7cec187..a95ee3c 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/time/Timer.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/time/Timer.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * Portions derived from ThunderHack Recode, copyright (c) 2023-2024 Pan4ur & 06ED. * Upstream: https://github.com/Pan4ur/ThunderHack-Recode diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/time/TimerController.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/time/TimerController.java index 5836da1..3d4c3ec 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/time/TimerController.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/time/TimerController.java @@ -1,13 +1,13 @@ /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on LiquidBounce * (https://github.com/CCBlueX/LiquidBounce). * Copyright (c) 2015-2026 CCBlueX. * * LiquidBounce portions are licensed under GPLv3-or-later. - * Combatant modifications are licensed under GPLv3. + * LoVisual modifications are licensed under GPLv3. * See THIRD_PARTY_NOTICES.md for details. */ diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/ClickGuiSounds.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/ClickGuiSounds.java index 88ea3b6..ce95b44 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/ClickGuiSounds.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/ClickGuiSounds.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/CustomSoundEngine.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/CustomSoundEngine.java index da60cba..a29f359 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/CustomSoundEngine.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/CustomSoundEngine.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/SourcePool.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/SourcePool.java index 22d4b17..81ebdf9 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/SourcePool.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/SourcePool.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavBufferCache.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavBufferCache.java index d1bf3c1..5407300 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavBufferCache.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavBufferCache.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavData.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavData.java index bb41a3f..3ab6fdb 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavData.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavData.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavDebugStats.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavDebugStats.java index 589952a..b1ea909 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavDebugStats.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavDebugStats.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavLoader.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavLoader.java index 7f31254..988ae27 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavLoader.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavLoader.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavSound.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavSound.java index 509880c..f3e699d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavSound.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavSound.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavSoundHelper.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavSoundHelper.java index 2ec7451..54f8f9d 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavSoundHelper.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/wav/WavSoundHelper.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/world/ExplosionDamageUtil.java b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/world/ExplosionDamageUtil.java index 18fc77e..4dc8d92 100644 --- a/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/world/ExplosionDamageUtil.java +++ b/combatant-client-26.2/src/main/java/dev/loki/lovisual/util/world/ExplosionDamageUtil.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/native/mediainfo/main.cpp b/combatant-client-26.2/src/main/native/mediainfo/main.cpp index 186b361..c883587 100644 --- a/combatant-client-26.2/src/main/native/mediainfo/main.cpp +++ b/combatant-client-26.2/src/main/native/mediainfo/main.cpp @@ -1,4 +1,4 @@ -// Modified native MediaPlayerInfo bridge for Combatant by pivosos2007. +// Modified native MediaPlayerInfo bridge for LoVisual by pivosos2007. // Based on Redstonecrafter0/MediaPlayerInfo. #include "main.h" @@ -121,7 +121,7 @@ static GlobalSystemMediaTransportControlsSession sessionFromObject(JNIEnv* env, return findSessionById(sessionId); } -jint Java_combatant_client_util_media_impl_win_WindowsMediaPlayerInfo_fillSessionSnapshotBuffer(JNIEnv* env, jobject obj, jobject buffer, jint maxSessions) { +jint Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaPlayerInfo_fillSessionSnapshotBuffer(JNIEnv* env, jobject obj, jobject buffer, jint maxSessions) { if (buffer == nullptr || maxSessions <= 0) return 0; auto* base = static_cast(env->GetDirectBufferAddress(buffer)); if (base == nullptr) return 0; @@ -226,7 +226,7 @@ jint Java_combatant_client_util_media_impl_win_WindowsMediaPlayerInfo_fillSessio return count; } -jbyteArray Java_combatant_client_util_media_impl_win_WindowsMediaPlayerInfo_getArtworkPng(JNIEnv* env, jobject obj, jstring sessionId) { +jbyteArray Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaPlayerInfo_getArtworkPng(JNIEnv* env, jobject obj, jstring sessionId) { if (sessionId == nullptr) return env->NewByteArray(0); const char* raw = env->GetStringUTFChars(sessionId, nullptr); std::string id = raw == nullptr ? std::string() : std::string(raw); @@ -258,13 +258,13 @@ jbyteArray Java_combatant_client_util_media_impl_win_WindowsMediaPlayerInfo_getA } } -jobject Java_combatant_client_util_media_impl_win_WindowsMediaPlayerInfo_getMediaSessions(JNIEnv* env, jobject obj) { +jobject Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaPlayerInfo_getMediaSessions(JNIEnv* env, jobject obj) { jclass listClass = env->FindClass("java/util/ArrayList"); jmethodID listConstructor = env->GetMethodID(listClass, "", "(I)V"); jmethodID listAdd = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z"); - jclass mediaSessionClass = env->FindClass("combatant/client/util/media/impl/win/WindowsMediaSession"); - jmethodID mediaSessionConstructor = env->GetMethodID(mediaSessionClass, "", "(Lcombatant/client/util/media/MediaInfo;Ljava/lang/String;Ljava/lang/String;ZZZIZ)V"); - jclass mediaInfoClass = env->FindClass("combatant/client/util/media/MediaInfo"); + jclass mediaSessionClass = env->FindClass("dev/loki/lovisual/util/media/impl/win/WindowsMediaSession"); + jmethodID mediaSessionConstructor = env->GetMethodID(mediaSessionClass, "", "(Ldev/loki/lovisual/util/media/MediaInfo;Ljava/lang/String;Ljava/lang/String;ZZZIZ)V"); + jclass mediaInfoClass = env->FindClass("dev/loki/lovisual/util/media/MediaInfo"); jmethodID mediaInfoConstructor = env->GetMethodID(mediaInfoClass, "", "(Ljava/lang/String;Ljava/lang/String;[BJJZ)V"); auto sessions = getManager().GetSessions(); @@ -382,49 +382,49 @@ jobject Java_combatant_client_util_media_impl_win_WindowsMediaPlayerInfo_getMedi return list; } -void Java_combatant_client_util_media_impl_win_WindowsMediaSession_play(JNIEnv* env, jobject obj) { +void Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_play(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session != nullptr) { session.TryPlayAsync(); } } -void Java_combatant_client_util_media_impl_win_WindowsMediaSession_pause(JNIEnv* env, jobject obj) { +void Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_pause(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session != nullptr) { session.TryPauseAsync(); } } -void Java_combatant_client_util_media_impl_win_WindowsMediaSession_playPause(JNIEnv* env, jobject obj) { +void Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_playPause(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session != nullptr) { session.TryTogglePlayPauseAsync(); } } -void Java_combatant_client_util_media_impl_win_WindowsMediaSession_stop(JNIEnv* env, jobject obj) { +void Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_stop(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session != nullptr) { session.TryStopAsync(); } } -void Java_combatant_client_util_media_impl_win_WindowsMediaSession_next(JNIEnv* env, jobject obj) { +void Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_next(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session != nullptr) { session.TrySkipNextAsync(); } } -void Java_combatant_client_util_media_impl_win_WindowsMediaSession_previous(JNIEnv* env, jobject obj) { +void Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_previous(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session != nullptr) { session.TrySkipPreviousAsync(); } } -jboolean Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSupportsShuffle(JNIEnv* env, jobject obj) { +jboolean Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSupportsShuffle(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session == nullptr) return JNI_FALSE; try { @@ -435,7 +435,7 @@ jboolean Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSup } } -jboolean Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeIsShuffleActive(JNIEnv* env, jobject obj) { +jboolean Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeIsShuffleActive(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session == nullptr) return JNI_FALSE; try { @@ -447,7 +447,7 @@ jboolean Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeIsS } } -void Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSetShuffle(JNIEnv* env, jobject obj, jboolean active) { +void Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSetShuffle(JNIEnv* env, jobject obj, jboolean active) { auto session = sessionFromObject(env, obj); if (session == nullptr) return; try { @@ -456,7 +456,7 @@ void Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSetShuf } } -jboolean Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSupportsRepeat(JNIEnv* env, jobject obj) { +jboolean Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSupportsRepeat(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session == nullptr) return JNI_FALSE; try { @@ -467,7 +467,7 @@ jboolean Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSup } } -jint Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeGetRepeatMode(JNIEnv* env, jobject obj) { +jint Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeGetRepeatMode(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session == nullptr) return 0; try { @@ -487,7 +487,7 @@ jint Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeGetRepe } } -void Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSetRepeatMode(JNIEnv* env, jobject obj, jint mode) { +void Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSetRepeatMode(JNIEnv* env, jobject obj, jint mode) { auto session = sessionFromObject(env, obj); if (session == nullptr) return; try { @@ -503,7 +503,7 @@ void Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSetRepe } } -jboolean Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSupportsSeek(JNIEnv* env, jobject obj) { +jboolean Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSupportsSeek(JNIEnv* env, jobject obj) { auto session = sessionFromObject(env, obj); if (session == nullptr) return JNI_FALSE; try { @@ -514,7 +514,7 @@ jboolean Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSup } } -void Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSeekTo(JNIEnv* env, jobject obj, jlong positionSeconds) { +void Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSeekTo(JNIEnv* env, jobject obj, jlong positionSeconds) { auto session = sessionFromObject(env, obj); if (session == nullptr) return; try { diff --git a/combatant-client-26.2/src/main/native/mediainfo/main.h b/combatant-client-26.2/src/main/native/mediainfo/main.h index a50c622..6824976 100644 --- a/combatant-client-26.2/src/main/native/mediainfo/main.h +++ b/combatant-client-26.2/src/main/native/mediainfo/main.h @@ -1,6 +1,6 @@ #pragma once -// Modified native MediaPlayerInfo bridge for Combatant by pivosos2007. +// Modified native MediaPlayerInfo bridge for LoVisual by pivosos2007. // Based on Redstonecrafter0/MediaPlayerInfo. #include @@ -9,27 +9,27 @@ extern "C" { #endif -JNIEXPORT jobject JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaPlayerInfo_getMediaSessions(JNIEnv* env, jobject obj); -JNIEXPORT jint JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaPlayerInfo_fillSessionSnapshotBuffer(JNIEnv* env, jobject obj, jobject buffer, jint maxSessions); -JNIEXPORT jbyteArray JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaPlayerInfo_getArtworkPng(JNIEnv* env, jobject obj, jstring sessionId); +JNIEXPORT jobject JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaPlayerInfo_getMediaSessions(JNIEnv* env, jobject obj); +JNIEXPORT jint JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaPlayerInfo_fillSessionSnapshotBuffer(JNIEnv* env, jobject obj, jobject buffer, jint maxSessions); +JNIEXPORT jbyteArray JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaPlayerInfo_getArtworkPng(JNIEnv* env, jobject obj, jstring sessionId); -JNIEXPORT void JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_play(JNIEnv* env, jobject obj); -JNIEXPORT void JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_pause(JNIEnv* env, jobject obj); -JNIEXPORT void JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_playPause(JNIEnv* env, jobject obj); -JNIEXPORT void JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_stop(JNIEnv* env, jobject obj); -JNIEXPORT void JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_next(JNIEnv* env, jobject obj); -JNIEXPORT void JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_previous(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_play(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_pause(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_playPause(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_stop(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_next(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_previous(JNIEnv* env, jobject obj); -JNIEXPORT jboolean JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSupportsShuffle(JNIEnv* env, jobject obj); -JNIEXPORT jboolean JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeIsShuffleActive(JNIEnv* env, jobject obj); -JNIEXPORT void JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSetShuffle(JNIEnv* env, jobject obj, jboolean active); +JNIEXPORT jboolean JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSupportsShuffle(JNIEnv* env, jobject obj); +JNIEXPORT jboolean JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeIsShuffleActive(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSetShuffle(JNIEnv* env, jobject obj, jboolean active); -JNIEXPORT jboolean JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSupportsRepeat(JNIEnv* env, jobject obj); -JNIEXPORT jint JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeGetRepeatMode(JNIEnv* env, jobject obj); -JNIEXPORT void JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSetRepeatMode(JNIEnv* env, jobject obj, jint mode); +JNIEXPORT jboolean JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSupportsRepeat(JNIEnv* env, jobject obj); +JNIEXPORT jint JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeGetRepeatMode(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSetRepeatMode(JNIEnv* env, jobject obj, jint mode); -JNIEXPORT jboolean JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSupportsSeek(JNIEnv* env, jobject obj); -JNIEXPORT void JNICALL Java_combatant_client_util_media_impl_win_WindowsMediaSession_nativeSeekTo(JNIEnv* env, jobject obj, jlong positionSeconds); +JNIEXPORT jboolean JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSupportsSeek(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_dev_loki_lovisual_util_media_impl_win_WindowsMediaSession_nativeSeekTo(JNIEnv* env, jobject obj, jlong positionSeconds); #ifdef __cplusplus } diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/lang/en_us.json b/combatant-client-26.2/src/main/resources/assets/lovisual/lang/en_us.json index d81061e..2078b73 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/lang/en_us.json +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/lang/en_us.json @@ -2758,7 +2758,6 @@ "setting.common.potions_scale": "Scale", "setting.common.potions_stroke": "Stroke", "setting.common.potions_text": "Text color", - "setting.common.prepare_jar_replacement": "Prepare Jar Replacement", "setting.common.prepare_rotations": "Prepare Rotations", "setting.common.preset.option.cool": "Cool", "setting.common.preset.option.soft": "Soft", @@ -2830,7 +2829,6 @@ "setting.common.reversal_z_modifier": "Reversal Z Modifier", "setting.common.reverse": "Reverse", "setting.common.rotation_bypass_items": "Rotation Bypass Items", - "setting.common.runtime_diagnostics": "Runtime Diagnostics", "setting.common.scoreboard_text_effect": "Text effect", "setting.common.scoreboard_text_effect.option.flow": "Flow", "setting.common.scoreboard_text_effect.option.mix": "Mix", @@ -3218,7 +3216,6 @@ "command.modules.description": "Lists modules by state or category.", "command.ping.description": "Shows the current server latency.", "command.profiler.description": "Controls rendering and runtime profilers.", - "command.runtime.description": "Shows or changes the client runtime and panic state.", "command.serverinfo.description": "Shows information about the current world or server.", "command.staff.description": "Manages the client staff list.", "command.toggle.description": "Enables, disables, or toggles a module.", diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/lang/ru_ru.json b/combatant-client-26.2/src/main/resources/assets/lovisual/lang/ru_ru.json index b4e44a8..5d21ff9 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/lang/ru_ru.json +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/lang/ru_ru.json @@ -2557,7 +2557,6 @@ "setting.common.potions_scale": "Масштаб", "setting.common.potions_stroke": "Обводка", "setting.common.potions_text": "Цвет текста", - "setting.common.prepare_jar_replacement": "Подготовить замену jar", "setting.common.prepare_rotations": "Подготовить ротации", "setting.common.preset.option.cool": "Холодный", "setting.common.preset.option.soft": "Мягкий", @@ -2629,7 +2628,6 @@ "setting.common.reversal_z_modifier": "Z-модификатор Reversal", "setting.common.reverse": "Обратно", "setting.common.rotation_bypass_items": "Предметы байпаса ротации", - "setting.common.runtime_diagnostics": "Диагностика рантайма", "setting.common.scoreboard_text_effect": "Эффект текста", "setting.common.scoreboard_text_effect.option.flow": "Поток", "setting.common.scoreboard_text_effect.option.mix": "Смешивание", @@ -3008,7 +3006,6 @@ "command.modules.description": "Показывает модули по состоянию или категории.", "command.ping.description": "Показывает текущую задержку до сервера.", "command.profiler.description": "Управляет профилировщиками рендера и среды выполнения.", - "command.runtime.description": "Показывает или изменяет состояние среды клиента и Panic.", "command.serverinfo.description": "Показывает информацию о текущем мире или сервере.", "command.staff.description": "Управляет списком персонала клиента.", "command.toggle.description": "Включает, отключает или переключает модуль.", diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/arc_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/arc_batch.frag index bbfac7b..e7427bc 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/arc_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/arc_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/chamfered_rect_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/chamfered_rect_batch.frag index 01ead75..e91825e 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/chamfered_rect_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/chamfered_rect_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/chamfered_rect_stroke_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/chamfered_rect_stroke_batch.frag index c3562fa..3eb5736 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/chamfered_rect_stroke_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/chamfered_rect_stroke_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/circle_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/circle_batch.frag index 93ce168..bb435b0 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/circle_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/circle_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/core/entity_dither.fsh b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/core/entity_dither.fsh index 4009b54..0694b91 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/core/entity_dither.fsh +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/core/entity_dither.fsh @@ -1,7 +1,7 @@ #version 330 /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -34,12 +34,12 @@ in vec4 overlayColor; #endif in vec2 texCoord0; -in vec3 combatantModelPos; +in vec3 lovisualModelPos; out vec4 fragColor; -const ivec3 COMBATANT_DITHER_MARK = ivec3(1, 0, 1); -const ivec3 COMBATANT_A2C_MARK = ivec3(1, 1, 0); +const ivec3 LOVISUAL_DITHER_MARK = ivec3(1, 0, 1); +const ivec3 LOVISUAL_A2C_MARK = ivec3(1, 1, 0); void main() { vec4 color = texture(Sampler0, texCoord0); @@ -68,10 +68,10 @@ void main() { int shadeGByte = int(floor(clamp(shadeColor.g, 0.0, 1.0) * 255.0 + 0.5)); int shadeBByte = int(floor(clamp(shadeColor.b, 0.0, 1.0) * 255.0 + 0.5)); ivec3 mark = ivec3(shadeRByte & 1, shadeGByte & 1, shadeBByte & 1); - bool combatantDitherFade = shadeAlphaByte < 255 && all(equal(mark, COMBATANT_DITHER_MARK)); - bool combatantA2CFade = shadeAlphaByte < 255 && all(equal(mark, COMBATANT_A2C_MARK)); + bool lovisualDitherFade = shadeAlphaByte < 255 && all(equal(mark, LOVISUAL_DITHER_MARK)); + bool lovisualA2CFade = shadeAlphaByte < 255 && all(equal(mark, LOVISUAL_A2C_MARK)); - if (combatantDitherFade || combatantA2CFade) { + if (lovisualDitherFade || lovisualA2CFade) { float fadeAlpha = float(shadeAlphaByte) / 255.0; shadeColor.r = float(shadeRByte & 254) / 255.0; shadeColor.g = float(shadeGByte & 254) / 255.0; diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/core/entity_dither.vsh b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/core/entity_dither.vsh index a50ccb7..cbbce47 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/core/entity_dither.vsh +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/core/entity_dither.vsh @@ -1,7 +1,7 @@ #version 330 /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -49,7 +49,7 @@ out vec4 overlayColor; #endif out vec2 texCoord0; -out vec3 combatantModelPos; +out vec3 lovisualModelPos; void main() { gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); @@ -80,5 +80,5 @@ void main() { texCoord0 = (TextureMat * vec4(UV0, 0.0, 1.0)).xy; #endif - combatantModelPos = Position; + lovisualModelPos = Position; } diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/damage_tint.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/damage_tint.frag index 5228371..a4f67ca 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/damage_tint.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/damage_tint.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/damage_tint.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/damage_tint.vert index 23b6ea1..a4bcf15 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/damage_tint.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/damage_tint.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/depth_of_field.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/depth_of_field.frag index f8ec5e9..212d444 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/depth_of_field.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/depth_of_field.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/gui_texture_lookup.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/gui_texture_lookup.frag index ab433da..967c0f8 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/gui_texture_lookup.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/gui_texture_lookup.frag @@ -1,7 +1,7 @@ #version 150 /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_glass.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_glass.frag index 1c8b6a4..eb89a78 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_glass.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_glass.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_metallic.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_metallic.frag index 1eb5c8e..3636ce7 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_metallic.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_metallic.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_smoke.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_smoke.frag index 96f5dbf..78be648 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_smoke.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/hand_smoke.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/heat_fx.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/heat_fx.frag index 238616b..236e5bc 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/heat_fx.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/heat_fx.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/common.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/common.patch index 9c4e60f..504b1e3 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/common.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/common.patch @@ -2,5 +2,5 @@ @require_define SHADER_STYLE @insert_after_define SHADER_STYLE - #define COMBATANT_POST_EFFECT_OWNERSHIP + #define LOVISUAL_POST_EFFECT_OWNERSHIP @end diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/composite1.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/composite1.patch index be4e69e..0fcd432 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/composite1.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/composite1.patch @@ -12,61 +12,61 @@ @require_hash dff672ad281b811a955db023bb9ca21cea88e2d6d92aa2c80be8184f5c71b0ed @insert_zone declarations -#ifndef COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -#define COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -uniform bool combatantWorldTweaksFogControl; -uniform bool combatantWorldTweaksFogModify; -uniform float combatantWorldTweaksFogStart; -uniform float combatantWorldTweaksFogEnd; -uniform vec3 combatantWorldTweaksFogColor; -uniform int combatantWorldTweaksFogDisableMask; +#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +uniform bool lovisualWorldTweaksFogControl; +uniform bool lovisualWorldTweaksFogModify; +uniform float lovisualWorldTweaksFogStart; +uniform float lovisualWorldTweaksFogEnd; +uniform vec3 lovisualWorldTweaksFogColor; +uniform int lovisualWorldTweaksFogDisableMask; #endif -#ifndef COMBATANT_FULLBRIGHT_UNIFORMS_DECLARED -#define COMBATANT_FULLBRIGHT_UNIFORMS_DECLARED -uniform bool combatantFullbrightEnabled; -uniform float combatantFullbrightMinLight; -uniform float combatantOverrideAmbientLight; +#ifndef LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED +#define LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED +uniform bool lovisualFullbrightEnabled; +uniform float lovisualFullbrightMinLight; +uniform float lovisualOverrideAmbientLight; #endif -float combatantComposite1FogAmount(float distanceToCamera, float sceneDepth) { - float combatantFogRange = max(combatantWorldTweaksFogEnd - combatantWorldTweaksFogStart, 1.0); - float combatantFog = smoothstep(0.0, 1.0, clamp((distanceToCamera - combatantWorldTweaksFogStart) / combatantFogRange, 0.0, 1.0)); - if (sceneDepth >= 0.999999) combatantFog *= 0.16; - return combatantFog; +float lovisualComposite1FogAmount(float distanceToCamera, float sceneDepth) { + float lovisualFogRange = max(lovisualWorldTweaksFogEnd - lovisualWorldTweaksFogStart, 1.0); + float lovisualFog = smoothstep(0.0, 1.0, clamp((distanceToCamera - lovisualWorldTweaksFogStart) / lovisualFogRange, 0.0, 1.0)); + if (sceneDepth >= 0.999999) lovisualFog *= 0.16; + return lovisualFog; } -void combatantComposite1ApplyFog(inout vec3 value, float distanceToCamera, float sceneDepth) { - value = mix(value, combatantWorldTweaksFogColor, combatantComposite1FogAmount(distanceToCamera, sceneDepth)); +void lovisualComposite1ApplyFog(inout vec3 value, float distanceToCamera, float sceneDepth) { + value = mix(value, lovisualWorldTweaksFogColor, lovisualComposite1FogAmount(distanceToCamera, sceneDepth)); } @end @insert_before_ident screenPos1 1 - if (combatantWorldTweaksFogControl && combatantWorldTweaksFogModify && isEyeInWater != 1 && z0 != z1) { - combatantComposite1ApplyFog(color, lViewPos, z0); // combatantComposite1TranslucentFog + if (lovisualWorldTweaksFogControl && lovisualWorldTweaksFogModify && isEyeInWater != 1 && z0 != z1) { + lovisualComposite1ApplyFog(color, lViewPos, z0); // lovisualComposite1TranslucentFog } @end @insert_after_hash 76c77fdbcc40f9aa86445f791963258aff2e988af8357d2ef56eff81e2e5ef3c 3 - float combatantUnderwaterFullbright = max( - combatantFullbrightEnabled ? clamp(combatantFullbrightMinLight, 0.0, 1.0) : 0.0, - clamp(combatantOverrideAmbientLight, 0.0, 1.0) + float lovisualUnderwaterFullbright = max( + lovisualFullbrightEnabled ? clamp(lovisualFullbrightMinLight, 0.0, 1.0) : 0.0, + clamp(lovisualOverrideAmbientLight, 0.0, 1.0) ); - bool combatantCustomUnderwaterFog = combatantWorldTweaksFogControl && combatantWorldTweaksFogModify; - bool combatantDisableUnderwaterFog = combatantWorldTweaksFogControl && (combatantWorldTweaksFogDisableMask & 1) != 0; - vec3 combatantUnderwaterBaseMult = vec3(0.97, 0.985, 1.0); - vec3 combatantUnderwaterMult = mix(combatantUnderwaterBaseMult * 0.98, vec3(1.0), combatantUnderwaterFullbright); + bool lovisualCustomUnderwaterFog = lovisualWorldTweaksFogControl && lovisualWorldTweaksFogModify; + bool lovisualDisableUnderwaterFog = lovisualWorldTweaksFogControl && (lovisualWorldTweaksFogDisableMask & 1) != 0; + vec3 lovisualUnderwaterBaseMult = vec3(0.97, 0.985, 1.0); + vec3 lovisualUnderwaterMult = mix(lovisualUnderwaterBaseMult * 0.98, vec3(1.0), lovisualUnderwaterFullbright); - if (combatantCustomUnderwaterFog) { - combatantComposite1ApplyFog(color, lViewPos, z0); - } else if (!combatantDisableUnderwaterFog) { + if (lovisualCustomUnderwaterFog) { + lovisualComposite1ApplyFog(color, lViewPos, z0); + } else if (!lovisualDisableUnderwaterFog) { if (z0 == 1.0) { - float combatantUnderwaterFogTint = 0.08 * (1.0 - combatantUnderwaterFullbright); - color.rgb = mix(color.rgb, waterFogColor, combatantUnderwaterFogTint); + float lovisualUnderwaterFogTint = 0.08 * (1.0 - lovisualUnderwaterFullbright); + color.rgb = mix(color.rgb, waterFogColor, lovisualUnderwaterFogTint); } - color.rgb *= combatantUnderwaterMult; - volumetricEffect.rgb *= mix(vec3(0.94), vec3(1.0), combatantUnderwaterFullbright); + color.rgb *= lovisualUnderwaterMult; + volumetricEffect.rgb *= mix(vec3(0.94), vec3(1.0), lovisualUnderwaterFullbright); } @end @@ -76,8 +76,8 @@ void combatantComposite1ApplyFog(inout vec3 value, float distanceToCamera, float @remove_line_hash 52e964df49ed95ee9b9458b2ddeb2de3f5228d52fdb3e090e96af0283baa9afa @insert_before_hash dff672ad281b811a955db023bb9ca21cea88e2d6d92aa2c80be8184f5c71b0ed - if (!combatantCustomUnderwaterFog && !combatantDisableUnderwaterFog) { - lightFog *= combatantUnderwaterMult; + if (!lovisualCustomUnderwaterFog && !lovisualDisableUnderwaterFog) { + lightFog *= lovisualUnderwaterMult; } @end @@ -85,8 +85,8 @@ void combatantComposite1ApplyFog(inout vec3 value, float distanceToCamera, float @insert_before_hash 44a431424820bc74930238e468887efc59a07ea3a6af1ccb8c26998124810aad color *= ( - combatantWorldTweaksFogControl - && (combatantWorldTweaksFogModify || (isEyeInWater == 1 && (combatantWorldTweaksFogDisableMask & 1) != 0)) + lovisualWorldTweaksFogControl + && (lovisualWorldTweaksFogModify || (isEyeInWater == 1 && (lovisualWorldTweaksFogDisableMask & 1) != 0)) ) ? 1.0 : GetBloomFog(lViewPos); @end diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/composite4.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/composite4.patch index c32eb06..0c0e838 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/composite4.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/composite4.patch @@ -6,25 +6,25 @@ @require_uniform depthtex0 @insert_zone declarations -uniform bool combatantSuppressShaderpackMotionBlur; +uniform bool lovisualSuppressShaderpackMotionBlur; @end @replace_line_hash f0b1efea375e99f7eb451fbe3c21fe59d260c1eb9c034c7522b8f269690edef6 - float combatantMotionCenterDepth = texture2D(depthtex0, texCoord).r; - float combatantMotionCenterCloudDepth = texelFetch(colortex5, texelCoord, 0).a; - if (z <= 0.56 || z >= 0.999 || combatantMotionCenterDepth <= 0.001 || combatantMotionCenterDepth >= 0.999 || combatantMotionCenterCloudDepth != 1.0) { + float lovisualMotionCenterDepth = texture2D(depthtex0, texCoord).r; + float lovisualMotionCenterCloudDepth = texelFetch(colortex5, texelCoord, 0).a; + if (z <= 0.56 || z >= 0.999 || lovisualMotionCenterDepth <= 0.001 || lovisualMotionCenterDepth >= 0.999 || lovisualMotionCenterCloudDepth != 1.0) { @end @insert_after_hash e5016804e90f4ce2655161db06f0b0b48b92bf5e158f841c226a26ea3d2e5857 - if (combatantSuppressShaderpackMotionBlur) velocity = vec2(0.0); + if (lovisualSuppressShaderpackMotionBlur) velocity = vec2(0.0); @end @insert_after_hash cdfeb6b2c575899a59b37a61d41eefae85abd6cbce3ba90ed0263aefcdcf0b52 - ivec2 combatantMotionTapTexel = ivec2(coordb * (vec2(viewWidth, viewHeight) - vec2(1.0))); - float combatantMotionTapDepth = texelFetch(depthtex0, combatantMotionTapTexel, 0).r; - float combatantMotionTapCloudDepth = texelFetch(colortex5, combatantMotionTapTexel, 0).a; - if (combatantMotionTapDepth <= 0.001 || combatantMotionTapDepth >= 0.999 || combatantMotionTapCloudDepth != 1.0) continue; + ivec2 lovisualMotionTapTexel = ivec2(coordb * (vec2(viewWidth, viewHeight) - vec2(1.0))); + float lovisualMotionTapDepth = texelFetch(depthtex0, lovisualMotionTapTexel, 0).r; + float lovisualMotionTapCloudDepth = texelFetch(colortex5, lovisualMotionTapTexel, 0).a; + if (lovisualMotionTapDepth <= 0.001 || lovisualMotionTapDepth >= 0.999 || lovisualMotionTapCloudDepth != 1.0) continue; @end @replace_line_hash 86fc0536f7fd9675a50ca4155385b1f297ad36187ab856d5bad191927040cb62 diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/deferred1.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/deferred1.patch index d92e721..dd59f16 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/deferred1.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/deferred1.patch @@ -5,21 +5,21 @@ @require_ident z0 @insert_zone declarations -#ifndef COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -#define COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -uniform bool combatantWorldTweaksFogControl; -uniform bool combatantWorldTweaksFogModify; -uniform float combatantWorldTweaksFogStart; -uniform float combatantWorldTweaksFogEnd; -uniform vec3 combatantWorldTweaksFogColor; -uniform int combatantWorldTweaksFogDisableMask; +#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +uniform bool lovisualWorldTweaksFogControl; +uniform bool lovisualWorldTweaksFogModify; +uniform float lovisualWorldTweaksFogStart; +uniform float lovisualWorldTweaksFogEnd; +uniform vec3 lovisualWorldTweaksFogColor; +uniform int lovisualWorldTweaksFogDisableMask; #endif @end @insert_before_drawbuffers 1 - if (combatantWorldTweaksFogControl && combatantWorldTweaksFogModify && isEyeInWater != 1) { - combatantApplyWorldTweaksFog(color, lViewPos, z0); + if (lovisualWorldTweaksFogControl && lovisualWorldTweaksFogModify && isEyeInWater != 1) { + lovisualApplyWorldTweaksFog(color, lViewPos, z0); } @end diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/fog.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/fog.patch index 8799954..bdafed6 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/fog.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/fog.patch @@ -5,52 +5,52 @@ @require_ident isEyeInWater @insert_before_function DoFog -#ifndef COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -#define COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -uniform bool combatantWorldTweaksFogControl; -uniform bool combatantWorldTweaksFogModify; -uniform float combatantWorldTweaksFogStart; -uniform float combatantWorldTweaksFogEnd; -uniform vec3 combatantWorldTweaksFogColor; -uniform int combatantWorldTweaksFogDisableMask; +#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +uniform bool lovisualWorldTweaksFogControl; +uniform bool lovisualWorldTweaksFogModify; +uniform float lovisualWorldTweaksFogStart; +uniform float lovisualWorldTweaksFogEnd; +uniform vec3 lovisualWorldTweaksFogColor; +uniform int lovisualWorldTweaksFogDisableMask; #endif -bool combatantDisableComplementaryFog() { - if (!combatantWorldTweaksFogControl) return false; - if (combatantWorldTweaksFogModify) return true; - if (isEyeInWater == 1 && (combatantWorldTweaksFogDisableMask & 1) != 0) return true; - if (isEyeInWater == 2 && (combatantWorldTweaksFogDisableMask & 2) != 0) return true; - if (isEyeInWater == 3 && (combatantWorldTweaksFogDisableMask & 4) != 0) return true; +bool lovisualDisableComplementaryFog() { + if (!lovisualWorldTweaksFogControl) return false; + if (lovisualWorldTweaksFogModify) return true; + if (isEyeInWater == 1 && (lovisualWorldTweaksFogDisableMask & 1) != 0) return true; + if (isEyeInWater == 2 && (lovisualWorldTweaksFogDisableMask & 2) != 0) return true; + if (isEyeInWater == 3 && (lovisualWorldTweaksFogDisableMask & 4) != 0) return true; #ifdef OVERWORLD - if ((combatantWorldTweaksFogDisableMask & 8) != 0) return true; + if ((lovisualWorldTweaksFogDisableMask & 8) != 0) return true; #endif #ifdef NETHER - if ((combatantWorldTweaksFogDisableMask & 16) != 0) return true; + if ((lovisualWorldTweaksFogDisableMask & 16) != 0) return true; #endif #ifdef END - if ((combatantWorldTweaksFogDisableMask & 32) != 0) return true; + if ((lovisualWorldTweaksFogDisableMask & 32) != 0) return true; #endif - return (combatantWorldTweaksFogDisableMask & 192) != 0; + return (lovisualWorldTweaksFogDisableMask & 192) != 0; } -void combatantApplyWorldTweaksFog(inout vec3 color, float lViewPos, float sceneDepth) { - float combatantFogRange = max(combatantWorldTweaksFogEnd - combatantWorldTweaksFogStart, 1.0); - float combatantFogDistance = min(lViewPos, combatantWorldTweaksFogEnd); - float combatantFog = smoothstep(0.0, 1.0, clamp((combatantFogDistance - combatantWorldTweaksFogStart) / combatantFogRange, 0.0, 1.0)); - if (sceneDepth >= 0.999999) combatantFog *= 0.16; - color = mix(color, combatantWorldTweaksFogColor, combatantFog); +void lovisualApplyWorldTweaksFog(inout vec3 color, float lViewPos, float sceneDepth) { + float lovisualFogRange = max(lovisualWorldTweaksFogEnd - lovisualWorldTweaksFogStart, 1.0); + float lovisualFogDistance = min(lViewPos, lovisualWorldTweaksFogEnd); + float lovisualFog = smoothstep(0.0, 1.0, clamp((lovisualFogDistance - lovisualWorldTweaksFogStart) / lovisualFogRange, 0.0, 1.0)); + if (sceneDepth >= 0.999999) lovisualFog *= 0.16; + color = mix(color, lovisualWorldTweaksFogColor, lovisualFog); } -void combatantApplyWorldTweaksFog(inout vec4 color, float lViewPos, float sceneDepth) { - float combatantFogRange = max(combatantWorldTweaksFogEnd - combatantWorldTweaksFogStart, 1.0); - float combatantFogDistance = min(lViewPos, combatantWorldTweaksFogEnd); - float combatantFog = smoothstep(0.0, 1.0, clamp((combatantFogDistance - combatantWorldTweaksFogStart) / combatantFogRange, 0.0, 1.0)); - if (sceneDepth >= 0.999999) combatantFog *= 0.16; - color.rgb = mix(color.rgb, combatantWorldTweaksFogColor, combatantFog); +void lovisualApplyWorldTweaksFog(inout vec4 color, float lViewPos, float sceneDepth) { + float lovisualFogRange = max(lovisualWorldTweaksFogEnd - lovisualWorldTweaksFogStart, 1.0); + float lovisualFogDistance = min(lViewPos, lovisualWorldTweaksFogEnd); + float lovisualFog = smoothstep(0.0, 1.0, clamp((lovisualFogDistance - lovisualWorldTweaksFogStart) / lovisualFogRange, 0.0, 1.0)); + if (sceneDepth >= 0.999999) lovisualFog *= 0.16; + color.rgb = mix(color.rgb, lovisualWorldTweaksFogColor, lovisualFog); } @end @insert_after_function_open DoFog - if (combatantDisableComplementaryFog()) return; + if (lovisualDisableComplementaryFog()) return; @end diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/lighting.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/lighting.patch index 709e200..24c244a 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/lighting.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/lighting.patch @@ -7,34 +7,34 @@ @require_hash 6f70f1b5528262776dcef7ec3997df09c8b9af515db2744743e26480b0dac711 @insert_before_function DoLighting -#ifndef COMBATANT_FULLBRIGHT_UNIFORMS_DECLARED -#define COMBATANT_FULLBRIGHT_UNIFORMS_DECLARED -uniform bool combatantFullbrightEnabled; -uniform float combatantFullbrightMinLight; -uniform float combatantOverrideAmbientLight; +#ifndef LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED +#define LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED +uniform bool lovisualFullbrightEnabled; +uniform float lovisualFullbrightMinLight; +uniform float lovisualOverrideAmbientLight; #endif @end @insert_after_function_open DoLighting - float combatantFullbrightStrength = combatantFullbrightEnabled ? clamp(combatantFullbrightMinLight, 0.0, 1.0) : 0.0; - float combatantAmbientOverrideStrength = clamp(combatantOverrideAmbientLight, 0.0, 1.0); - float combatantEffectiveLightStrength = max(combatantFullbrightStrength, combatantAmbientOverrideStrength); - if (combatantEffectiveLightStrength > 0.0) { - lightmap = max(lightmap, vec2(combatantEffectiveLightStrength)); + float lovisualFullbrightStrength = lovisualFullbrightEnabled ? clamp(lovisualFullbrightMinLight, 0.0, 1.0) : 0.0; + float lovisualAmbientOverrideStrength = clamp(lovisualOverrideAmbientLight, 0.0, 1.0); + float lovisualEffectiveLightStrength = max(lovisualFullbrightStrength, lovisualAmbientOverrideStrength); + if (lovisualEffectiveLightStrength > 0.0) { + lightmap = max(lightmap, vec2(lovisualEffectiveLightStrength)); } @end @insert_after_hash 198c38564559ab224c3616a2a7b4a8947fa62d2e7a970103017b95fd06b94b22 - if (combatantEffectiveLightStrength > 0.0) { - minLighting = max(minLighting, vec3(pow2(combatantEffectiveLightStrength))); + if (lovisualEffectiveLightStrength > 0.0) { + minLighting = max(minLighting, vec3(pow2(lovisualEffectiveLightStrength))); } @end @insert_before_hash 6f70f1b5528262776dcef7ec3997df09c8b9af515db2744743e26480b0dac711 - float combatantDarknessLightFactor = mix(darknessLightFactor, 0.0, combatantEffectiveLightStrength); - color.rgb *= pow2(1.0 - combatantDarknessLightFactor); + float lovisualDarknessLightFactor = mix(darknessLightFactor, 0.0, lovisualEffectiveLightStrength); + color.rgb *= pow2(1.0 - lovisualDarknessLightFactor); @end @remove_line_hash 6f70f1b5528262776dcef7ec3997df09c8b9af515db2744743e26480b0dac711 diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/manifest.json b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/manifest.json index 2087234..2646124 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/manifest.json +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/manifest.json @@ -26,43 +26,43 @@ "underwater_fog", "shaderpack_motion_blur_suppression" ], - "notes": "Runtime application is gated by active Iris shaderpack name first, then by structural probes compiled against the loaded expanded GLSL. Patch payload remains Combatant-owned; exact SHA-256 anchors are reserved for dangerous line-level mutations. Stage gating is intentionally not used for expanded include targets; fragment-only composite logic avoids new shaderpack uniforms in declaration payload." + "notes": "Runtime application is gated by active Iris shaderpack name first, then by structural probes compiled against the loaded expanded GLSL. Patch payload remains LoVisual-owned; exact SHA-256 anchors are reserved for dangerous line-level mutations. Stage gating is intentionally not used for expanded include targets; fragment-only composite logic avoids new shaderpack uniforms in declaration payload." }, "targets": [ { "path": "/lib/common.glsl", "patch": "common.patch", - "marker": "COMBATANT_POST_EFFECT_OWNERSHIP" + "marker": "LOVISUAL_POST_EFFECT_OWNERSHIP" }, { "path": "/lib/lighting/mainLighting.glsl", "patch": "lighting.patch", - "marker": "combatantFullbrightStrength" + "marker": "lovisualFullbrightStrength" }, { "path": "/lib/atmospherics/fog/mainFog.glsl", "patch": "fog.patch", - "marker": "combatantApplyWorldTweaksFog" + "marker": "lovisualApplyWorldTweaksFog" }, { "path": "/program/deferred1.glsl", "patch": "deferred1.patch", - "marker": "combatantApplyWorldTweaksFog(color, lViewPos, z0)" + "marker": "lovisualApplyWorldTweaksFog(color, lViewPos, z0)" }, { "path": "/program/composite1.glsl", "patch": "composite1.patch", - "marker": "combatantComposite1TranslucentFog" + "marker": "lovisualComposite1TranslucentFog" }, { "path": "/program/composite4.glsl", "patch": "composite4.patch", - "marker": "combatantSuppressShaderpackMotionBlur" + "marker": "lovisualSuppressShaderpackMotionBlur" }, { "path": "/program/gbuffers_water.glsl", "patch": "water.patch", - "marker": "combatantWaterSurfaceFog" + "marker": "lovisualWaterSurfaceFog" } ] } diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/water.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/water.patch index de2713b..8a9d668 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/water.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/water.patch @@ -6,23 +6,23 @@ @require_hash 98a8ecbdc8e127052fe7c968dc602301791bb3069ced369c924e1ff7d3e04f92 @insert_zone declarations -#ifndef COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -#define COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -uniform bool combatantWorldTweaksFogControl; -uniform bool combatantWorldTweaksFogModify; -uniform float combatantWorldTweaksFogStart; -uniform float combatantWorldTweaksFogEnd; -uniform vec3 combatantWorldTweaksFogColor; -uniform int combatantWorldTweaksFogDisableMask; +#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +uniform bool lovisualWorldTweaksFogControl; +uniform bool lovisualWorldTweaksFogModify; +uniform float lovisualWorldTweaksFogStart; +uniform float lovisualWorldTweaksFogEnd; +uniform vec3 lovisualWorldTweaksFogColor; +uniform int lovisualWorldTweaksFogDisableMask; #endif @end @insert_after_hash 98a8ecbdc8e127052fe7c968dc602301791bb3069ced369c924e1ff7d3e04f92 - if (combatantWorldTweaksFogControl && combatantWorldTweaksFogModify) { - float combatantWaterSurfaceFogRange = max(combatantWorldTweaksFogEnd - combatantWorldTweaksFogStart, 1.0); - float combatantWaterSurfaceFog = smoothstep(0.0, 1.0, clamp((lViewPos - combatantWorldTweaksFogStart) / combatantWaterSurfaceFogRange, 0.0, 1.0)); - color.a = mix(color.a, 1.0, combatantWaterSurfaceFog); - translucentMult.rgb = mix(translucentMult.rgb, vec3(0.0), combatantWaterSurfaceFog); - } // combatantWaterSurfaceFog + if (lovisualWorldTweaksFogControl && lovisualWorldTweaksFogModify) { + float lovisualWaterSurfaceFogRange = max(lovisualWorldTweaksFogEnd - lovisualWorldTweaksFogStart, 1.0); + float lovisualWaterSurfaceFog = smoothstep(0.0, 1.0, clamp((lViewPos - lovisualWorldTweaksFogStart) / lovisualWaterSurfaceFogRange, 0.0, 1.0)); + color.a = mix(color.a, 1.0, lovisualWaterSurfaceFog); + translucentMult.rgb = mix(translucentMult.rgb, vec3(0.0), lovisualWaterSurfaceFog); + } // lovisualWaterSurfaceFog @end diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/c0_vl.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/c0_vl.patch index b3f469d..9eefc1d 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/c0_vl.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/c0_vl.patch @@ -6,46 +6,46 @@ @require_hash 04c1c600e2564adc886777a68521ea4876b7ff06ece947d48590eed71b959168 @insert_zone declarations -#ifndef COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -#define COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -uniform bool combatantWorldTweaksFogControl; -uniform bool combatantWorldTweaksFogModify; -uniform float combatantWorldTweaksFogStart; -uniform float combatantWorldTweaksFogEnd; -uniform vec3 combatantWorldTweaksFogColor; -uniform int combatantWorldTweaksFogDisableMask; +#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +uniform bool lovisualWorldTweaksFogControl; +uniform bool lovisualWorldTweaksFogModify; +uniform float lovisualWorldTweaksFogStart; +uniform float lovisualWorldTweaksFogEnd; +uniform vec3 lovisualWorldTweaksFogColor; +uniform int lovisualWorldTweaksFogDisableMask; #endif -bool combatantPhotonSuppressDefaultAirFog() { - if (!combatantWorldTweaksFogControl) return false; - if (combatantWorldTweaksFogModify) return true; +bool lovisualPhotonSuppressDefaultAirFog() { + if (!lovisualWorldTweaksFogControl) return false; + if (lovisualWorldTweaksFogModify) return true; #if defined WORLD_OVERWORLD - return (combatantWorldTweaksFogDisableMask & 200) != 0; + return (lovisualWorldTweaksFogDisableMask & 200) != 0; #elif defined WORLD_NETHER - return (combatantWorldTweaksFogDisableMask & 16) != 0; + return (lovisualWorldTweaksFogDisableMask & 16) != 0; #elif defined WORLD_END - return (combatantWorldTweaksFogDisableMask & 32) != 0; + return (lovisualWorldTweaksFogDisableMask & 32) != 0; #else return false; #endif } -void combatantPhotonSoftenWaterFog(inout mat2x3 waterFog) { - if (!combatantWorldTweaksFogControl) return; - float visibility = combatantWorldTweaksFogModify || (combatantWorldTweaksFogDisableMask & 1) != 0 ? 1.0 : 0.78; +void lovisualPhotonSoftenWaterFog(inout mat2x3 waterFog) { + if (!lovisualWorldTweaksFogControl) return; + float visibility = lovisualWorldTweaksFogModify || (lovisualWorldTweaksFogDisableMask & 1) != 0 ? 1.0 : 0.78; waterFog[0] *= 1.0 - 0.88 * visibility; waterFog[1] = mix(waterFog[1], vec3(1.0), visibility); -} // combatantPhotonSoftenWaterFog +} // lovisualPhotonSoftenWaterFog @end @insert_before_hash edca557442dab12ad7e45ab3d92af16882dac5dbe47803ecda08ea07dcf82d25 - if (combatantPhotonSuppressDefaultAirFog()) { + if (lovisualPhotonSuppressDefaultAirFog()) { fog = mat2x3(vec3(0.0), vec3(1.0)); } @end @insert_before_hash 04c1c600e2564adc886777a68521ea4876b7ff06ece947d48590eed71b959168 - combatantPhotonSoftenWaterFog(water_fog); + lovisualPhotonSoftenWaterFog(water_fog); @end diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/c1_blend_layers.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/c1_blend_layers.patch index 778eb73..7b63a26 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/c1_blend_layers.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/c1_blend_layers.patch @@ -6,32 +6,32 @@ @require_hash be5ef0bea5057e7d62bad71bec7721dc0048bffd6e941be27511a801bbe48a0a @insert_zone declarations -#ifndef COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -#define COMBATANT_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED -uniform bool combatantWorldTweaksFogControl; -uniform bool combatantWorldTweaksFogModify; -uniform float combatantWorldTweaksFogStart; -uniform float combatantWorldTweaksFogEnd; -uniform vec3 combatantWorldTweaksFogColor; -uniform int combatantWorldTweaksFogDisableMask; +#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED +uniform bool lovisualWorldTweaksFogControl; +uniform bool lovisualWorldTweaksFogModify; +uniform float lovisualWorldTweaksFogStart; +uniform float lovisualWorldTweaksFogEnd; +uniform vec3 lovisualWorldTweaksFogColor; +uniform int lovisualWorldTweaksFogDisableMask; #endif -float combatantPhotonWorldTweaksFogAmount(float distanceToCamera, bool sky) { - float fogRange = max(combatantWorldTweaksFogEnd - combatantWorldTweaksFogStart, 1.0); - float fogDistance = min(distanceToCamera, combatantWorldTweaksFogEnd); - float fog = smoothstep(0.0, 1.0, clamp((fogDistance - combatantWorldTweaksFogStart) / fogRange, 0.0, 1.0)); +float lovisualPhotonWorldTweaksFogAmount(float distanceToCamera, bool sky) { + float fogRange = max(lovisualWorldTweaksFogEnd - lovisualWorldTweaksFogStart, 1.0); + float fogDistance = min(distanceToCamera, lovisualWorldTweaksFogEnd); + float fog = smoothstep(0.0, 1.0, clamp((fogDistance - lovisualWorldTweaksFogStart) / fogRange, 0.0, 1.0)); if (sky) fog *= 0.16; return fog; } -void combatantPhotonApplyWorldTweaksFog(inout vec3 color, float distanceToCamera, bool sky) { - color = mix(color, combatantWorldTweaksFogColor, combatantPhotonWorldTweaksFogAmount(distanceToCamera, sky)); -} // combatantPhotonApplyWorldTweaksFog +void lovisualPhotonApplyWorldTweaksFog(inout vec3 color, float distanceToCamera, bool sky) { + color = mix(color, lovisualWorldTweaksFogColor, lovisualPhotonWorldTweaksFogAmount(distanceToCamera, sky)); +} // lovisualPhotonApplyWorldTweaksFog @end @insert_after_hash be5ef0bea5057e7d62bad71bec7721dc0048bffd6e941be27511a801bbe48a0a - if (combatantWorldTweaksFogControl && combatantWorldTweaksFogModify) { - combatantPhotonApplyWorldTweaksFog(fragment_color, view_distance, is_sky); + if (lovisualWorldTweaksFogControl && lovisualWorldTweaksFogModify) { + lovisualPhotonApplyWorldTweaksFog(fragment_color, view_distance, is_sky); } @end diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/lighting.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/lighting.patch index 8f0628a..cc27c5f 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/lighting.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/lighting.patch @@ -6,25 +6,25 @@ @require_ident nightVision @insert_before_function get_diffuse_lighting -#ifndef COMBATANT_FULLBRIGHT_UNIFORMS_DECLARED -#define COMBATANT_FULLBRIGHT_UNIFORMS_DECLARED -uniform bool combatantFullbrightEnabled; -uniform float combatantFullbrightMinLight; -uniform float combatantOverrideAmbientLight; +#ifndef LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED +#define LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED +uniform bool lovisualFullbrightEnabled; +uniform float lovisualFullbrightMinLight; +uniform float lovisualOverrideAmbientLight; #endif @end @insert_after_function_open get_diffuse_lighting - float combatantPhotonFullbrightStrength = max( - combatantFullbrightEnabled ? clamp(combatantFullbrightMinLight, 0.0, 1.0) : 0.0, - clamp(combatantOverrideAmbientLight, 0.0, 1.0) + float lovisualPhotonFullbrightStrength = max( + lovisualFullbrightEnabled ? clamp(lovisualFullbrightMinLight, 0.0, 1.0) : 0.0, + clamp(lovisualOverrideAmbientLight, 0.0, 1.0) ); - if (combatantPhotonFullbrightStrength > 0.0) { - light_levels = max(light_levels, vec2(combatantPhotonFullbrightStrength)); - ao = max(ao, combatantPhotonFullbrightStrength); - float combatantPhotonFullbrightSquared = combatantPhotonFullbrightStrength * combatantPhotonFullbrightStrength; - shadows = max(shadows, vec3(combatantPhotonFullbrightSquared)); + if (lovisualPhotonFullbrightStrength > 0.0) { + light_levels = max(light_levels, vec2(lovisualPhotonFullbrightStrength)); + ao = max(ao, lovisualPhotonFullbrightStrength); + float lovisualPhotonFullbrightSquared = lovisualPhotonFullbrightStrength * lovisualPhotonFullbrightStrength; + shadows = max(shadows, vec3(lovisualPhotonFullbrightSquared)); sss_depth = max(sss_depth, 0.0); } diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/manifest.json b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/manifest.json index 45582ac..953099b 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/manifest.json +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/manifest.json @@ -30,22 +30,22 @@ { "path": "/program/c0_vl.fsh", "patch": "c0_vl.patch", - "marker": "combatantPhotonSoftenWaterFog" + "marker": "lovisualPhotonSoftenWaterFog" }, { "path": "/program/c1_blend_layers.fsh", "patch": "c1_blend_layers.patch", - "marker": "combatantPhotonApplyWorldTweaksFog" + "marker": "lovisualPhotonApplyWorldTweaksFog" }, { "path": "/include/lighting/diffuse_lighting.glsl", "patch": "lighting.patch", - "marker": "combatantPhotonFullbrightStrength" + "marker": "lovisualPhotonFullbrightStrength" }, { "path": "/program/c16_motion_blur.fsh", "patch": "motion_blur.patch", - "marker": "combatantSuppressShaderpackMotionBlur" + "marker": "lovisualSuppressShaderpackMotionBlur" } ] } diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/motion_blur.patch b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/motion_blur.patch index 213994d..0db6548 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/motion_blur.patch +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/iris-patches/photon/v1_3b/motion_blur.patch @@ -4,13 +4,13 @@ @require_uniform colortex0 @insert_zone declarations -uniform bool combatantSuppressShaderpackMotionBlur; +uniform bool lovisualSuppressShaderpackMotionBlur; uniform sampler2D colortex11; @end @insert_after_function_open main - if (combatantSuppressShaderpackMotionBlur) { + if (lovisualSuppressShaderpackMotionBlur) { scene_color = texelFetch(colortex0, ivec2(gl_FragCoord.xy), 0).rgb; return; } @@ -18,21 +18,21 @@ uniform sampler2D colortex11; @end @insert_before_hash c457646c5b8fbc05a6af08576060fa8407243f144aebaaa1f8568fbe317487ef - float combatantMotionCloudTransmittance = texelFetch(colortex11, view_texel, 0).a; - if (depth <= 0.001 || depth >= 0.999 || combatantMotionCloudTransmittance != 1.0) { - vec3 combatantMotionSkyColor = texelFetch(colortex0, texel, 0).rgb; - scene_color = combatantMotionSkyColor; + float lovisualMotionCloudTransmittance = texelFetch(colortex11, view_texel, 0).a; + if (depth <= 0.001 || depth >= 0.999 || lovisualMotionCloudTransmittance != 1.0) { + vec3 lovisualMotionSkyColor = texelFetch(colortex0, texel, 0).rgb; + scene_color = lovisualMotionSkyColor; return; } @end @replace_line_hash e1d6d7148b22846d3dcffd3f701a78cf65a444ada7151311a22452724f264ae3 - float combatantMotionTapCloudTransmittance = texelFetch(colortex11, view_tap, 0).a; - float weight = (clamp01(pos) == pos && depth > max(hand_depth, 0.001) && depth < 0.999 && combatantMotionTapCloudTransmittance == 1.0) ? 1.0 : 0.0; + float lovisualMotionTapCloudTransmittance = texelFetch(colortex11, view_tap, 0).a; + float weight = (clamp01(pos) == pos && depth > max(hand_depth, 0.001) && depth < 0.999 && lovisualMotionTapCloudTransmittance == 1.0) ? 1.0 : 0.0; @end @replace_line_hash 482cbf201e7d21c755826f352cf8b8dc5726687bfe3c0aae9debda2b7603e694 - vec3 combatantMotionFallbackColor = texelFetch(colortex0, texel, 0).rgb; - scene_color = weight_sum > 0.0 ? color_sum * rcp(weight_sum) : combatantMotionFallbackColor; + vec3 lovisualMotionFallbackColor = texelFetch(colortex0, texel, 0).rgb; + scene_color = weight_sum > 0.0 ? color_sum * rcp(weight_sum) : lovisualMotionFallbackColor; @end diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/menu_background_aurora.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/menu_background_aurora.frag index 7955b51..3aae3b6 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/menu_background_aurora.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/menu_background_aurora.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/menu_background_waves.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/menu_background_waves.frag index 0547e8d..f2d5aa9 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/menu_background_waves.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/menu_background_waves.frag @@ -2,13 +2,13 @@ /* -This file is part of the Combatant Client distribution. +This file is part of the LoVisual Client distribution. Copyright (c) 2026 pivosos2007. The original wave effect was based on a shader published on ShaderToy. The original shader link and author attribution were not preserved. -This implementation has since been substantially modified for Combatant. +This implementation has since been substantially modified for LoVisual. Licensed under the GNU General Public License v3.0. */ diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/metallic.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/metallic.frag index bbda76f..38e8919 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/metallic.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/metallic.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/motion_blur.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/motion_blur.frag index fdaf616..f89af03 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/motion_blur.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/motion_blur.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/orbiz_ring_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/orbiz_ring_batch.frag index 0238566..987594d 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/orbiz_ring_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/orbiz_ring_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/portal_rift.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/portal_rift.frag index a86955d..b705116 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/portal_rift.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/portal_rift.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color.frag index 1dc327a..4435401 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color.frag @@ -1,8 +1,8 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color.vert index 5a7ed69..3f2b6d0 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color.vert @@ -1,8 +1,8 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_fog.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_fog.frag index 1b30ddd..be3bdc7 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_fog.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_fog.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_fog.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_fog.vert index 581d42b..b29aff1 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_fog.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_fog.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_rect_params.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_rect_params.vert index 17defb7..348598d 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_rect_params.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_rect_params.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_rect_params2.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_rect_params2.vert index 7786021..d65fdac 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_rect_params2.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_rect_params2.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_skybox_shader.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_skybox_shader.vert index abb8475..4e30ac6 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_skybox_shader.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_color_skybox_shader.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params.vert index f53f3bc..c7fb53b 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params2.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params2.vert index 5abe70e..d201f81 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params2.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params2.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params5.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params5.vert index 04848f3..33d6ebb 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params5.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params5.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params5_generic.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params5_generic.vert index 36ec30b..de7dd4f 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params5_generic.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_local_color_rect_params5_generic.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color.frag index e7007fc..64c3b4f 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color.frag @@ -1,8 +1,8 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color.vert index 84e8cf6..8ee53c1 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color.vert @@ -1,8 +1,8 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_params2.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_params2.vert index 04cd341..c48eb02 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_params2.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_params2.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_rect_params.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_rect_params.vert index c0817c3..2bfa500 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_rect_params.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_rect_params.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_rect_params2.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_rect_params2.vert index 187fe65..f68c4fd 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_rect_params2.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_rect_params2.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog.frag index e513e21..cd65d80 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog.vert index 0e385f0..ac94acf 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog_additive.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog_additive.frag index b0b0972..0c4e4ba 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog_additive.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_sky_fog_additive.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_tint.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_tint.frag index 19fd4db..5e0b5fb 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_tint.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_color_tint.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_local_color_rect_params.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_local_color_rect_params.vert index bef2f66..83ad6a4 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_local_color_rect_params.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_local_color_rect_params.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_local_color_rect_params2.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_local_color_rect_params2.vert index c88ea44..e52b90a 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_local_color_rect_params2.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/pos_tex_local_color_rect_params2.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/post_fx.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/post_fx.frag index e1f510f..93f3c84 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/post_fx.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/post_fx.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/radial_glow_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/radial_glow_batch.frag index 63198b6..13149a2 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/radial_glow_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/radial_glow_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/reimagined_skybox.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/reimagined_skybox.frag index 8d13857..cb897c0 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/reimagined_skybox.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/reimagined_skybox.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_batch.frag index 7e04fa4..d8356ec 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_corners_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_corners_batch.frag index 67f8ea1..a4b827d 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_corners_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_corners_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_glow_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_glow_batch.frag index f8f7f31..4cc279f 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_glow_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_glow_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_shadow_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_shadow_batch.frag index a1323cc..b163706 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_shadow_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_shadow_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_soft_shadow_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_soft_shadow_batch.frag index 2810427..1822937 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_soft_shadow_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_soft_shadow_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_angular_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_angular_batch.frag index 35af839..1ce2c5e 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_angular_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_angular_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_batch.frag index 6b25a1f..194fea9 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_corners_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_corners_batch.frag index af923b2..bddd6eb 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_corners_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_stroke_corners_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_tex_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_tex_batch.frag index ad87f78..a019583 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_tex_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_tex_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_tex_mask_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_tex_mask_batch.frag index cd89606..c761dcd 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_tex_mask_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/rounded_rect_tex_mask_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_gradient.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_gradient.frag index 56030e0..0820b23 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_gradient.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_gradient.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_shadow.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_shadow.frag index f77f3f6..771e7e4 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_shadow.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_shadow.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_smoke.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_smoke.frag index 6002e30..46f0a3b 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_smoke.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/shader_esp_smoke.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sky_sun.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sky_sun.frag index 8bce5e8..387e867 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sky_sun.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sky_sun.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sleep_overlay.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sleep_overlay.frag index 5e84b66..0344be3 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sleep_overlay.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sleep_overlay.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sodium/block_layer_opaque.fsh b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sodium/block_layer_opaque.fsh index edb2be8..29c8fdf 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sodium/block_layer_opaque.fsh +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sodium/block_layer_opaque.fsh @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -16,13 +16,13 @@ in vec2 v_TexCoord; in vec2 v_FragDistance; in float fadeFactor; in float v_ViewDistance; -flat in uint v_CombatantSurfaceFlags; +flat in uint v_LoVisualSurfaceFlags; uniform sampler2D u_BlockTex; out vec4 fragColor; -const uint COMBATANT_SURFACE_SOFT_FADE = 1u << 0u; +const uint LOVISUAL_SURFACE_SOFT_FADE = 1u << 0u; vec4 sampleNearest(sampler2D source, vec2 uv, vec2 pixelSize, vec2 du, vec2 dv, vec2 texelScreenSize) { vec2 uvTexelCoords = uv / pixelSize; @@ -83,7 +83,7 @@ void main() { vec4 color = u_UseRGSS ? sampleRGSS(u_BlockTex, v_TexCoord, u_TexelSize) : sampleNearest(u_BlockTex, v_TexCoord, u_TexelSize); color *= v_Color; - if ((v_CombatantSurfaceFlags & COMBATANT_SURFACE_SOFT_FADE) != 0u) { + if ((v_LoVisualSurfaceFlags & LOVISUAL_SURFACE_SOFT_FADE) != 0u) { float obstructionAlpha = smoothstep(0.18, 0.85, v_ViewDistance); color.a *= obstructionAlpha; } diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sodium/block_layer_opaque.vsh b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sodium/block_layer_opaque.vsh index bb55d67..5c8ab6e 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sodium/block_layer_opaque.vsh +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/sodium/block_layer_opaque.vsh @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -14,7 +14,7 @@ out vec4 v_Color; out vec2 v_TexCoord; out float v_ViewDistance; -flat out uint v_CombatantSurfaceFlags; +flat out uint v_LoVisualSurfaceFlags; #ifdef USE_FOG out vec2 v_FragDistance; @@ -37,29 +37,29 @@ uniform uint u_RegionID; uniform sampler2D u_LightTex; -layout(location = 4) in uint a_CombatantSurfaceFlags; +layout(location = 4) in uint a_LoVisualSurfaceFlags; -const uint COMBATANT_SURFACE_WAVY_VEGETATION = 1u << 1u; -const uint COMBATANT_SURFACE_WAVY_VEGETATION_FREE = 1u << 2u; -const uint COMBATANT_WAVE_LOCAL_Y_SHIFT = 8u; -const uint COMBATANT_WAVE_LOCAL_Y_MASK = 15u; -const uint COMBATANT_WAVE_ROOTED_HORIZONTAL_SHIFT = 12u; -const uint COMBATANT_WAVE_ROOTED_VERTICAL_SHIFT = 16u; -const uint COMBATANT_WAVE_FREE_HORIZONTAL_SHIFT = 20u; -const uint COMBATANT_WAVE_FREE_VERTICAL_SHIFT = 24u; -const uint COMBATANT_WAVE_SPEED_SHIFT = 28u; -const uint COMBATANT_WAVE_SETTING_MASK = 15u; +const uint LOVISUAL_SURFACE_WAVY_VEGETATION = 1u << 1u; +const uint LOVISUAL_SURFACE_WAVY_VEGETATION_FREE = 1u << 2u; +const uint LOVISUAL_WAVE_LOCAL_Y_SHIFT = 8u; +const uint LOVISUAL_WAVE_LOCAL_Y_MASK = 15u; +const uint LOVISUAL_WAVE_ROOTED_HORIZONTAL_SHIFT = 12u; +const uint LOVISUAL_WAVE_ROOTED_VERTICAL_SHIFT = 16u; +const uint LOVISUAL_WAVE_FREE_HORIZONTAL_SHIFT = 20u; +const uint LOVISUAL_WAVE_FREE_VERTICAL_SHIFT = 24u; +const uint LOVISUAL_WAVE_SPEED_SHIFT = 28u; +const uint LOVISUAL_WAVE_SETTING_MASK = 15u; -float combatant_decode_wave_setting(uint flags, uint shift) { - return float((flags >> shift) & COMBATANT_WAVE_SETTING_MASK) * (3.0 / 15.0); +float lovisual_decode_wave_setting(uint flags, uint shift) { + return float((flags >> shift) & LOVISUAL_WAVE_SETTING_MASK) * (3.0 / 15.0); } -vec3 combatant_apply_wavy_vegetation(vec3 position, uint flags) { - if ((flags & COMBATANT_SURFACE_WAVY_VEGETATION) == 0u) { +vec3 lovisual_apply_wavy_vegetation(vec3 position, uint flags) { + if ((flags & LOVISUAL_SURFACE_WAVY_VEGETATION) == 0u) { return position; } - float speed = combatant_decode_wave_setting(flags, COMBATANT_WAVE_SPEED_SHIFT); + float speed = lovisual_decode_wave_setting(flags, LOVISUAL_WAVE_SPEED_SHIFT); if (speed <= 0.0001) { return position; } @@ -68,19 +68,19 @@ vec3 combatant_apply_wavy_vegetation(vec3 position, uint flags) { float pi2wt = 150.796447372 * speed * frameTimeCounter; float magnitude = abs(sin(dot(vec4(frameTimeCounter * speed, position), vec4(1.0, 0.005, 0.005, 0.005))) * 0.5 + 0.72) * 0.013; - if ((flags & COMBATANT_SURFACE_WAVY_VEGETATION_FREE) != 0u) { - float horizontal = combatant_decode_wave_setting(flags, COMBATANT_WAVE_FREE_HORIZONTAL_SHIFT); - float vertical = combatant_decode_wave_setting(flags, COMBATANT_WAVE_FREE_VERTICAL_SHIFT); + if ((flags & LOVISUAL_SURFACE_WAVY_VEGETATION_FREE) != 0u) { + float horizontal = lovisual_decode_wave_setting(flags, LOVISUAL_WAVE_FREE_HORIZONTAL_SHIFT); + float vertical = lovisual_decode_wave_setting(flags, LOVISUAL_WAVE_FREE_VERTICAL_SHIFT); vec3 move = sin(pi2wt * vec3(0.0063, 0.0224, 0.0015) * 1.5 - position) * magnitude; return position + vec3(move.x * horizontal, move.y * vertical, move.z * horizontal) * 5.0; } - float horizontal = combatant_decode_wave_setting(flags, COMBATANT_WAVE_ROOTED_HORIZONTAL_SHIFT); - float vertical = combatant_decode_wave_setting(flags, COMBATANT_WAVE_ROOTED_VERTICAL_SHIFT); + float horizontal = lovisual_decode_wave_setting(flags, LOVISUAL_WAVE_ROOTED_HORIZONTAL_SHIFT); + float vertical = lovisual_decode_wave_setting(flags, LOVISUAL_WAVE_ROOTED_VERTICAL_SHIFT); vec2 move2 = (sin(pi2wt * vec2(0.0063, 0.0015) * 4.0 - position.xz + position.y * 0.05) + 0.1) * magnitude; float move2y = -length(move2); vec3 offset = vec3(move2.x * horizontal, move2y * vertical, move2.y * horizontal) * 5.0; - float base = float((flags >> COMBATANT_WAVE_LOCAL_Y_SHIFT) & COMBATANT_WAVE_LOCAL_Y_MASK) / float(COMBATANT_WAVE_LOCAL_Y_MASK); + float base = float((flags >> LOVISUAL_WAVE_LOCAL_Y_SHIFT) & LOVISUAL_WAVE_LOCAL_Y_MASK) / float(LOVISUAL_WAVE_LOCAL_Y_MASK); return position + offset * base; } @@ -97,7 +97,7 @@ void main() { vec3 translation = u_RegionOffset + _get_draw_translation(_draw_id); vec3 position = _vert_position + translation; - position = combatant_apply_wavy_vegetation(position, a_CombatantSurfaceFlags); + position = lovisual_apply_wavy_vegetation(position, a_LoVisualSurfaceFlags); vec4 viewPosition = u_ModelViewMatrix * vec4(position, 1.0); #ifdef USE_FOG @@ -114,5 +114,5 @@ void main() { v_Color = _vert_color * texture(u_LightTex, _vert_tex_light_coord); v_TexCoord = (_vert_tex_diffuse_coord_bias * u_TexCoordShrink) + _vert_tex_diffuse_coord; v_ViewDistance = length(viewPosition.xyz); - v_CombatantSurfaceFlags = a_CombatantSurfaceFlags; + v_LoVisualSurfaceFlags = a_LoVisualSurfaceFlags; } diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/svg_msdf.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/svg_msdf.frag index 65e646b..bc935d8 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/svg_msdf.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/svg_msdf.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text.frag index 9d56b61..0c7e094 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text.frag @@ -1,8 +1,8 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text.vert index 84e8cf6..8ee53c1 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text.vert @@ -1,8 +1,8 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. - * Combatant modifications copyright (c) 2026 pivosos2007. + * This file is part of the LoVisual Client distribution. + * LoVisual modifications copyright (c) 2026 pivosos2007. * * Portions of this file are based on, adapted from, or implemented * with reference to Meteor Client diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_liquid_glass.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_liquid_glass.frag index dc16e39..a4838b8 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_liquid_glass.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_liquid_glass.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_liquid_glass_msdf.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_liquid_glass_msdf.frag index 016c5bf..7b04c87 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_liquid_glass_msdf.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_liquid_glass_msdf.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_msdf.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_msdf.frag index 040223f..96937ba 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_msdf.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/text_msdf.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur.frag index 59dc2db..41c4678 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur_batch.frag index a2ee9a1..22f509c 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur_batch_corners.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur_batch_corners.frag index 2094f6b..4f87c61 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur_batch_corners.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_blur_batch_corners.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_liquid_glass_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_liquid_glass_batch.frag index b238b18..0b972fd 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_liquid_glass_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_liquid_glass_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_rounded_fill_smoke_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_rounded_fill_smoke_batch.frag index d990ff5..2093260 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_rounded_fill_smoke_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_rounded_fill_smoke_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_shape_batch.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_shape_batch.frag index 83c0ff0..6da2709 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_shape_batch.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/ui_shape_batch.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/wide_line.vert b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/wide_line.vert index 0c587b1..ccbdd06 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/wide_line.vert +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/wide_line.vert @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/world_decal_sdf.frag b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/world_decal_sdf.frag index 3893cc6..f2eb87e 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/world_decal_sdf.frag +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/shaders/world_decal_sdf.frag @@ -1,7 +1,7 @@ #version 330 core /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/textures/particles/firefly.png b/combatant-client-26.2/src/main/resources/assets/lovisual/textures/particles/firefly.png new file mode 100644 index 0000000000000000000000000000000000000000..15a0a42b8a441bc79d74515a50b0a9c34e182218 GIT binary patch literal 19384 zcmcGV_gj+R|HlDwR+^fn;Zr{wgj-1@(XSJ+Q+@xNchu!#wJQjM zdqoJ<6d@6}VkMqW!upF*#8>1Qu>rp;GJn#E=Ru9m?8k!`flj-~HSL)3CcHN>h;KH&T=jR$<%HyA!D%7@shYGjc^Pn|UenoJ%PSibu&ExG|)p7a8s?RN|q^S)5PNrx@7zMbk?w3&GZ;L4#@Cj4yU&v-i_ zR%lhLryl#|PQ%m-P8=%ufbiQsCMOPBR8(Z%OJ}ji=?t)U<-;6-yq7(9X%m+LWN(iG zOlE)=Fjhqhe=Y1qNZB#h+yNhs%KjWCgO)cIL=T<2493*?A6=C`pO0hZ2JE#E-P6e? z#TZ-?YhhubW2(>i+fYP>ARXJn>NUg8Su`WhpIbGWIz&)^r1l)DHCD)=#37M4ROBa_ zOlFU{@Oh5es_T)=X;ha;}r3u`+*^X zPEuzE^{Wk8H}(o72S14Xex!;{E;KP~X#QgGgW)O{&%wpVRiyGBHymRy7|u?EWTP$XvlW4c%2`Y-89vR|b~@GSI`XW;Kty98b(5Hi>=@`IhoR zB+XwHFs=zKP-VL1Pzru*kLqEqF9RYbcCy)a=-`Yj$XvVVjEvK2^B%IY!%w5KxnA%R zjX$&57>T0#s&&`TkAFbNINr+zRz-WwOvo6>C9M2_e$Bo}6iTOk>c<-YzO31< zv7O>>C^MyBt09Cz7NyF^$C zk!i1#in5Bn2bwoUW&YA)t`>G-Yi6lM7)+V}4Wpb%C(=`k;wvigogo6%xW0{aJ;%F( zcfD)AC58lpwNjMTph`W8nSeIuMRg70B}17EHUF@-z8$@PSg?Bbr^(0aU$yW08G+7I z!FSQ7^5Rz)Bc$+eEQ@cJ{f6?VOit-?@BHRnIG#3KV}Vz>HDQDTy& zZ*vE3#ni00O*3ZPwf4ywyR6u!cs~LA(hhd2j&~d+?1$7*>#MB=3KbhOSE{|Jq$PyE z8YQYV4PrQZ<;e-pqOszj6!?^>b&g0PrcNe7QS+Xc*rmwRIh)AL!ZXgRCn2kWVBINv zW_CmXNsSen3bPRQbItW*W!)HzkT5AI?!1lx<~jUnDx?1fK>|OxCn!xZSk_5dlkX;k z@SfQn-p3jODOfWwu%7_UVuPGhn7HqX!0q*QeZg27)fJ-zUlJXEjQ`y~081&YHgAp1 zt_{(*u^3fi3S_I4OFgL){ie-Wn@XmPNfS;fVxoRPhP76Q`=X81CA25k>O+gnDue@` z(~dg5rniMvuh*W+0;mi&3r7qZMd=#N&+G;orZzM*r0JVXds^v4MQC4Qm#k74L~1@WQRbQ7amxmt`VnL5XS#qOoZB%CxQiP<&*T|@nq*P%mO>0RtXL`vx=y+ z030U_Juvrbw+^hVd5jV}BCOn;a?f*6Y1)JiT;kVb#WEUjE^><)dc2~8U*sqQIFrg zt*A4*hEiLL@<)imNG`FiKlZ>veUTFzi&%l|WOJP^e_<>J^DU#qFi#>fI$DeDU?ZmL zmV0DegmQUHZbHXy$mn$Ag8p97_t~gaUY69AV?*_AWf~o}$07Q&aWh9QCi*IfXo`CM z*ag={`=+xvF(3oUcxmf%!xDsitjiZeASS)~k2eRLhtA4*%kH2~d@3@MBNA&dbv?&7yA|)@%a2B51f8TZ&0E z_2|M6MFk0gS{K4^fx1{3T!n2**4f9>ZvIyEHC+4LP zwml?<>fLbp_6MQ3qjG!Qr~|)Y0*`Vf{Dt~S7+xjoZGH+ZZYYb!A?^P%vC-lmR&Y3TX7EJ>whLM#%b<8YUZmFRM&DC?Vv{~Bvjo|8Nq9VKOiN%Ab&q|#^$-0$oe<_ZX ztf-j&OIC6HYRxq?eGlgs1#d#(KbM9>6&X*&EYTlYXd!C%gWQ|4Y%-zQJ3U)IA{IHO zjVRW-#zGk!N~fp~Zq~|-MJs?$r&o!y=FOccw9=4DDAHN|nVXku$s2u^rWZ#K^DVD% zk}UV*EHLX6LM z>WvS_M6G}GoS|*=_I5(R>t{(_+g@D?d#?8=&d;-(SDBH}nIkoEmE5E6bGh`jNgrFSzB1 z>f1(T!-ATyll-hyy^1N{2*wLciK6d>IS_UF?<$Yf*aBVt0N6I|?Sv$%LJ%016+Yt(+To!Pt~$u2&N;3g8u4CVH+-!0b)7Isx%hIA*;V+*V=; zi=T+=4O1L`r$oZopz^{5~byWf1{e zcA8c*g~q;UBd*}_c$7^9=G>K&gj(fME$=!-FVBMCO7lnW7g|grdN`O5LiB6E5@2sE z{pUO&gn2Gn`Zl?rr;NM|0FHKs1y z))&LwS@($lZ;oPR@ouoSwXLlvBg?dTw*v*YAfFRFsj3kQA+SSf-@>c^3A7Ly$p`6a z0L>}_an^iZ%><`J3S33#;R&XlYe=*$9g$RwteRbzyuX{_ODm~;2m0a>6(`sJ#|RKL z{Yp46@SzDuG_m#aR%3aU^94ZfhP$&!46kQB(2C>M(279<@wMJpnk#i~37BM|~xGZ=D~ zsRJd@t?=_g(Y9R_uyY6W{#gQxDr!-mAHscPKwB5J)jXsjB%x|`yTxym*a8%N+F9bG zzGDWA(g`;JUx{zg>~nOWY82iFr}Y{QP9Iw`<cSEZ*G zV!MLf?I^db#6Hr0(fj-O7v-k$!X-w3f=a$)qB#(zoMPZ>tWN)$5z-tws`b9vJ4zC?boIPfY)`c9_je&S zPBVy&<%QwXo1Bl!+9H&?{jk7br8@?!rihJGZChoL)1~IExU7We(8qNHnlHOGY~c3B z^MwF+Nyq}`0&vo=1*HOv|7gpt&;j481bxll7j1ZLhD?SQd8KrWM!3s$b8mGQ@4_}> zB$S_sOkzd^yHv2T66grrKG1wg3&T#|i|p~OPyUdPy!uXN%a$S8%&4?g8qoLIK3Al` zA5o0?C~PCv?c)l+;Tpt~Ei1xIpzgB6?88o|92|^ER*Zc>^i*x@q zQmWC>%(HZ<;t5PMJ*9cwFGvfg0qjQ?89${BzF)dNnQP%3{|sGqcw6^1&2z>NU@AfB z!VM-QTLnA>na}=vpd9T<_<4tJFIbZ2MRa6cypkyrI!)tZii#Xf+u9x)XRxUYg7+kZ zUE=U$RK~Mi#LA${yZY>Eh|!|){xdeF9@Ci4U9)iq(c<1Wy_sX!@s`{Epi6A|E9OMU z)iT+c)@A|YCm;<;o7;n53-;TXK6;OeNN4zF?4CR@a)`&4M>z>BTvCGXiMnsBH%qMe zOp&xg)V$T$ZfRq$T3cFTGDOa7_iE@h*`Mq9^!~id>;SuQD&nC`AoHN|0Yas-!uaEj zk%gn+4cW4#1yYFm1fv++V%!mbNT_68F+9|YV6H4T?^$rLIewADz=&^KiKI{!_RPB& zMbI7&i^WQpJ7OD^vljh+`GlzG>SR}anqHb|s~^kAj*?RXy~EY)ZaAp?C_>Px`j$bDXWX72JJZlFA8`a{2uMo>V9x;%0;}n zOtU2Ro?u2QVQcxcLn6V8p)kAAipqIA9j+|>#b+;?!6jm#SN|f|uO;R$B*~o1@P#s{ z-`VLT$!=-6?{O$&kFQ&A!COy*WSQHj)F3IE^X~IQ?p%}OkYtD9Q|QzxU<8iT#RC?v zjiFp}z-p`d@`JM8(RuD0;7V3gZ>j#NXf3HmQJ~8wNj&Z;oZ2~m1eXDjhisIHf9Yke z8`2nBx69KIqE@*)n1ADB6cTw9jw_QOM68dqv;PriA;4{4yg)59wS&0^QcCbp{gkUQ^FneEok{?iXA>u~U6+ZU+R5T0O*KcStDaZ{b>;z0{>1MKGf}m%2?d?bxhZy(rie>uSf#_1Sa?*JSRAbBsr<)BdLDeLzj zn+KH1@G#J-@EgUz%xdvCrHyHLKzE3{6ThcGII32!0T%vbgVq7LdSa4-a->8EEFvAd zxYVl&QuYQHgFy(8`&Qq1^}tUD#HGkv;cJB`U{M|5sIaa4XEW~l%OZiS+(&-d`vMsQ z?26@Unv_Lw#$Te|I%N*6GN|#ZiD-sV=gJC5wTP?4pMmW;N`~^c3ltWA2kO$z6Ch{5 z$a3L_DNn2>K(3UY%!1D4q66(@d!qwsk&nsW#aSdR|JRRrs)Np%qVFvRST_uE!iIs{0-}w3ub$AwGm4RlkMb<~I zsV5CE5uQ1*^r`(nMYwv7D9Jo<#-VtELpsL7rPT}WZHTU{5BUkCv1OQNYK~|GKDc7x z_Xu-HjBU;N!M)`*I1V2TY5GF?VGLjtob{Hjb?cJtIs-~&o7G1U3@HU*)Aty{%I6uG z@3xMVMDK9;>_SuAnZaZika&SG&Vd(#5;9Zt-VN~{28T#%}A3@7>$8a z@${8ILwQ(S!f!K;G4S@GVlBJTi?10~GMn=AzhIzhc$Y`7*Ud@n3Qw~55oo0hCn|aJAi(jHXqg?%uBls!L+ll1Ogc*r zlp!LrMS5%y&YoQ`MK$|^QYd2gxasDFFXgFttp2zdVL?<)aat6?tctB z9Pv_MkaFwwp<}Ky>5xB<82tLXlob&ueMMu55yBAmep~`X{qnquq_KOQQAP2eTfDoZJ^fQK0 zxuS%gse5rDj)z-$0Jb=9pP0cmtyx_3H9~girImhCtdEWG#t8O&cGq zU!)%Tu$%3hxjVbFvooJf?X6S)k+I7i3g47R2Sl(d4bAb?s9`2m7e}(t|&$0#_w>pndm$?!#vCB?M8&YH~u4%Thg+Zrv=F6I0D*siBqL3 z6Q3t0%*68uS6_=?pZR}tj{ZP~z{*q)9T zS9#8<8@U9pcx=|+Q&}zHw)?}KpqwvxS{WsvJri~ZTVL{lpLitQr=ajK;MdgBF6Wck_0ad@<~{}}g*>OO zfEK3mMv~76uUj?BdPUm8O*p%3pBpH{bik>wj?lcUsNoy9_-Ke$ODZmxRb?C?16XJ~U!xOyk>}1Pg~& zmvAh&rt)S_Z{6ywxsAfTjq9ng8a=HJ8ySi>V!rRpM#^CcOZ%eSfd{8;xyi-gyHfw{ zzJdCE2)=*n6Q%^@gsC*EnlUwM_j(O}RVsc<|AXcdEvzUeHR#I#^ply{V=71VpSG#Z z5L8XD>a)VOw5ZEEhV$heAhQWFY7QzQP?x^c02+@5o)>a50o#~)t(1LN4?LGLPL#V00Q=!zUubbm>-~<6 zkgKOeEor}w)$N~+t0y;%o;N;;`lTKf<&ns;`D*Ed3AXp@&~^l5gDU}rvYB07h6BC3 zaZm$bM=AGlL^H%N9&5YkD%z3mbL)xMIo0AN!+DR^TBSX%reMadnVC+GL$KFnEWK1fb?patbay*#jbmI>*~0Vm^z20OI1&1aVLZsQP-64eqw~s}Yo#6W z&m{r;LRgEoV+8sy_xSa_yn%{(QhqQwWdsZG`nVF|WHT1L8UfK|`=BthJJPxyf`fHT zx9F&sfWD!u58D_#(>m(3s6!J2?P#m~L|DU*V%4s{h=PNh*41g3_Gc(dRk(&P6cB!h z6oYt=bel^?jp$U5Ep@cBCc*+LOi?Ho9XX^@-ObjNhxtdGbBW@H5WHSX_}Yew-;4j+ z`(~+0&8|0L$O}Dpo{Aa^0I^anCgQeKMbVvGuCreki8VSR+l>nPQfKSU=ixT z->(M{N-j<4Lw(LeSqDvB@;(A>umaKKN`DuFigY(9qmb&%_XxN{P3Wq&eFS1}fx~Ol zp?aZ1qKU;Y=PMm%LrfVZA`nMcb{qmR{rsvgN>eNamkM|8>5lzZ|e(E6fv#L~CAfHB!jM zW0bigj=LwW9LuQRQS!ny7uah8APWU^&55Vf=B1Ji$DzH;yW1XQ(U?)HKRoF>!vj;j z1!esddL#X%-_oR0@1VQjz5Fresg|l#5?8kIl-)O&@5D=W*o$KLW+d;W><&ucYdR-C z7!13Vp&R!EmHO3%`U?VIcBnIPS_mYTN}_mlCfCP8!BK# ziauIB14kadkGdoOCC)z`BML#@=p2B6$P6bhi!dyGZ1LHcbb@Iv)%eo;XiEB%)!hGH zueuneMbWF4Z`>ldk_7`*20!uLr%xlliN{5^i&^U%?_d|y|6$GjXkiu~(@G00!v>lt zthVw)gp{Mj%YI~>^<9OHq#`iHrc2h^`*&EmvWPGIJklPjdJP$wbE}B3v{v%Yk6m~V z$KB+*37#QVbnluhtAKTxDrZl)xT{6(!JUVQX0}wI8v=>WreO&a4r4nz+M8K^wgQg? z_v+fm&GsqU!EPuudL9V@I$pkS^id$0Fc)-!6RIG5f}Oe6#QH=NZRQr4Nz}Xf*s>gD zl%<${StHkESY9`F`yTH`114$SAA5tLwC4zmmjuKeo>8DewP;>8tD?rW5EtCKXl^1n zxak)$Et*|S@BM71D5d+`JcaQoolQE1yRd5R_{pSiO(8yIqYA_M9lKyy+BWHS8oVA? zV==%PQ%-n(5N&sajyceu0**l=*gIpVxfNSP)6jDWa(u*PWz5>;7B4){&8z64xqz+~ zzqa@56^)ZZKRvkT8IN*xi(;2cRWir9XFIK~JMMp^!@~ppEam6y-+6Y_90v6ZDaV_3 z-p_<*VyGL15{Xk>0>bnmsC*zybV2L_e?66Z23^|Nvt~$Wq!)&HsyV4x;ySX)MX42e z8C=#h@B7^s0OY_xdg+_JfPdUi8uzSI_Q6&MQd9CXKmWD0S8Zi}-Jcx0UhW#b@IpNvtHo_wW^9-#EC~f&65#@xEeAO} zJL&+`V)iA2Vy&G;j;;W?S_0R`_&YksasCfUz0qudjAd=tD2_vws9Rl{#VRj0stunQ zMBi0Jx;T%wNNh=r+S-1(CPwJ<>ea3R_}&i;{A8_?@CB z^)6ilQQ?ItH$LXxX(S^!Ve4d!Q9AC-UqkwgG=*z**7INH)(V*7{lS&3R(M@l=@}GV zIqc+D3M^Dao@?B0g`|`r9}HqWfN5hNg@ShJtir9Gs5AMJR~N@7Vv!#HDD6G9uu(G~ z)PTZE7gpi3lV;d2|NZD{-1@mZqy@qk0!%NS%0JL{h}pYGeVOLrmq;xTZdMsJF{)r2 z`&lrL)-mFEb(YhcSCQrwHH&r8Z3~LS=dQ7Tw--D+uW`93m)_y^-PYg1pZ4g2ae7Jz z(Qfku&c&SazzFS@`79^zWn!7#vTK)gWV7*}X*${2jO1O!i8^)-@bz=RwY$_vYfy#z zB^MIQP4-pMC07LKX0rs3S%IsBngV;>Ek2i(4U+}t>@DBK6`J)iK37RveC`$4F`0V> z*Z6SFgF6Ad^P|c|V72@q#3AQ_3Z7@N25)?JU$fi^2HW& z7%=~=Of`RWHU|nvjW`ke za5hr9pYCbqw(+ahYxi9Lxm{;$%UGzxUkx}!#a9l{Cm+}8pRp)iuhXYpcO@J7j!1q_ z9rvS@~lrNsFwPA-ICgs`?rbe!v*h?QxqmlOw#r=4p%O z^laAYwmxnBeU#r(w|M5A3q*8Ot4v0f@M}*8hq3HmStVo7vYx(T-eWw^ie7Td4YJBP!zA1EEEFo5)WGMXPovN`F}D9tNET%_w;(Jd%FSF_dfUQgV{&q#ZQZhjl5~Q{9^J-@Nkp!M}*)>4gfq@xp|?Ly#>w*38%n-ALj{&7(TttG+e)AIZL zFz1KAv<)J_ zUBa_R?#@j{ZI2$jeHU}w8|9@&$|dUl(wv_D3R-onnGd3iLXDf=N?9@ z4_~8~PB!SHhtLjGokE##6B;u2!PFy962=30*W1ANJE2AfDtBes>R`0P-7IQj8V` <5FjC%Hj_6d@9kq z^5j8bZ}nox5br@g)aOXPVBRM`W53j|5hYsi9@&05val1CG(mT~peW97;+b{(Ni;Bh zJ;p;F3%x$o)MT?gUU(o(_nNM4lKos?rTYoT+<34|94f;Eyq%xcKEF>l`q_Tq-F5#| zBRxpE&V};4^PluX4v@@ZelV*wix`4tT5)x)1#h0bHWYazgquMdT~dsVTSr>5TdsnmRd%ezeM^9!eJew98wT!75Pc^K+zYS(b=)Tlq#W{o39sZdc$IMomI5Z zwktPU9m8s9_nZCZl+72IoIk#mjnOB*IKGL#=`5$nLWy=FtL_tA>NP_&aFb4y5e=U? zjB{o0Kw9bSj5aDD`UzEwP!eK{9g?&Oi^Y$HwDu!}iHkd=)*7j9qwgD*)$dOXTdB+( z7FKCMjM3ABT4qY#aMqP1n;^A_6-^_+gl(pFnC)WqoEv9vgVY-QAmAK8OZ1;VEQ#W; zVKxbhuR%^@Cws#x%^kxa>#BN)SSp}~P*kKvWa+AWO{DFr=%!s%YG|um4ctDGruluO zp1+eTb3fy*i!Ce6=FB-8tmt=E^pCJY({d}MVvrfuiDBfYUTq z8B1G4k<*(Vo3WRtU7NntBw;inu4J#osR!n)ni$A!7lzA#@_ua8DfzDo|5Y4Wy1Cgr z>UBFLz&f*d0sG*l@za&+-q01>*!&ukI=OA!tjwz4%8e#QO@I~}G5f7-zJ9lx;B zW-ZW~c|KKSPhMj5?#dubY+8HP&$-dVajA|tD-}Kpp&)uQvrUp`fNwMNe77JxV*sM$ z>dPk$w=QeeMcZR4ponB|q0iajad%KhgbDzAfz#v#^Jc%XA3QDps$Fyc^q|FqRkU_a zZYr;L6Z7n+Hi@rkL9vO!Qgx<+c&5Xp znVXBy9Bf(yv7PUvkR_dkxg&U=xrH-~zH#!_iMxV-Ys8D}gfr;*oF${m2Qh2oMtv`b zxpu9Fp{^irzrg&iSPDC+lc|!h!Q#VG+`S#<)f~bIi$FtyUjtyRKt zpgQEQY90oph(+94z}>_Xo213yr8Kboeht*;A&mImmlX@hGw0VSR#I+|Faq1*6N)Ok zvF!00V%KHt)SBdx1c)JoGr+Z`KQDslEYy!Vd-_|!F*(C$xOl_on+n}=W&u^aiWuat zCqwuqtJdx73p!iRy~;k1 z2L3TwzAaY#{LHYPaLgFcb$Nin9n9=vv|Od0`=58{8>=FM1axxtW}Dae4>9XABu&rp zh;3;E=&N4U=Sw#> zbUK_d!?!#^8(*rD0L>NPI69L7%Fm6^z+R6_4GK+btFspjj6Kp+z5fPXT`%LF4Z!rD zCx*J&6JD|@(d?IL{h26U!Z(&#dXCA(Dx;N3(jr-7>f=!bKJSo^>+~|{qrB@M#FU)8 z7TjD)if27|s0LE#Vf1C)x@w#D()zR=uiJ3*Q@Km>${_q!R5eDZ7|nUBx%E`_ZxEJo z9FT=J?-toR3yAdWeO>6$^^`6;r#L4oB zj=bBk{&oF-0_AB{F-}6rjDCSYGMmkgjEdR;qzM=Ro5ci0g2`RTk!uR7HfCGHVWA9e zhm@n0qS+UcHDWbo@-me4H z^#ey$L%v=)kQXB4R4ODT8CnDdo|n|M?Bz5=)zP8m>1%Gr+b~-QDE6~Ft2BC(`zPXs zu-Oq~^uwOL0c~4==yJC8JKS2b!fsCDaok^DX4u>$ z@L9mP@aPxfpFl&gu<;{B_8W1xUSs#`D~-&Qje4yY$)NdENdzdD&G)K_FYXxM`OB8N zI^VXrUo&_vLh4!8lc|s0lm}wo;r(jq_KD20D(-~G3$Vq@KQ~8*TRQ|PgPHfWQtusgZ1JpSVM8^q&Rb8 z$z{VhW0_&n8TPZerLN9-FU@t%=vKt!=m((2lC<9ZiA^-03!b$#%qFdb&#tWax3sj# z7h(=2EtV#2St$u?CASL)i3u1|L=1CRH@IBdKicAqX&I%*6^ngyxq8Iyt4>to+-6p; zgJR6q|HN{O!Cq_Q(bmW_GmeKYSnG2iX_dZoNt>DR0p(dyd`@iM6r8g?&?w#VpGsqo zG5WPZD>&x662S2Gn@Sww>yRYoIMS|598Po$eRc;`Qld`ANi+(5U_Alu#ml!ad#BFsDRx# z)__-n7#ujs5a8Z7&MH1aaKqEoS{!Crg<>|~!Iyyezfw)i-f7mKo##-D+I%lFuj=_( zt#-C;SBpI|T;30+ru${X+>sM^0N2bXe20DRp!1eoWm^1qzz=p*c>cXX9ZvFczxr8Fc532E2LWM_c z70C@*XN#f&h4G26*9-4l%eD$L{fb@R-Pi^7S7cr*^xDJs$MCBJQ7hOtGLi0|m1 z)ZY7gQs3C@=mIF5mbKt96s?FB=wqapWYRHKmVtE+51{M|DP4V)7#pxD^d-Um&T6xa z=yn8aS0j#2@QR9yH0gqvoz%;V z_EU#!Y)^UAsi5b~3Pns`X_{^D;H;l$a{Qa#<3DyP>jN{3D zJ8_SrpA|2u{k??~eSlX=)4-!NUAMAX*2uOBy!4J|2c2#Jj18=t)nJaU?KxQdJ|0lx zFWl0#>>C91+#IYj5v|~e@69Ds!$ykI*%L}MK;HKfm9^Ir$k-XOpC|z{D(hoRkY3eN zvAIRCUuUz%#>VthZD_ke&|Isx(IZNj+}`yaBgxNL8;T5}N}g~oM8M#tFa-dISTKKB zdU68|W2*O;*l$t4?A8by+#FY>EXrrkGFsFtPJjI)k(EO6u`pBUyfp%`U<|~)-$N*c zfiu3L7bmv;ShQk>2*K>J8i_O<;t2h*lS<}WGyCORiW&wDf3-^Q!8B^q@3}tm+Kl)b z3&Tz5fYfyOTDo2j5fnaa_WqktLSk2Cb^^Wq68~rgp|!OoQ9zp%a?U2y|AdKK8dmX4 z!Ew23$K#~|?0~~Uko#{euv|Fg3U^}NGj^yBN5ftKRe~}vIRQXHZydbYQE+ad6(zQl z;gV@CRLOjN2Y~?e;MkweUO%^e2aMGL-`;~`9Rj=G+no!%jHY&N8&LB+Y4#MB@BqeW z)=a{Ct7eG0?$r*p^EZz&6aw2im!Y1v@JkUf(XB zU)%ZnV)6aagRsVB_*$Dim9!DALfeeu`yxc^Wq|REvk~%(Oyjqxd7mq zEKB&H3_Y@QZ!!*l87c3s0DvchIT{C}YR6EhNfJ-GV9)$!Nhm)#LkM%mj!0s7!NBOV#iBJeEwhbl1qAHG2=SCi?(O_kf zVh$HiI#O{Vo618e7N_ea^YZ40n?MGwOOhGkbCaNOT4ff`Q7JTS<@z~Ov^ zBT&A#k;Q6|(h{5{x1yR_RXET#hJ+HYPKUDtD$H)gP#lf}Sv_^?Qr?Q+lF@g%3^(U0 zvt}z*x<^piVLrPz!lgmw1k4DauZO)R55lAnEZ++Ej3#LOj=219jo;ocPh?NrWyuyT ztLmM!Ut?x;IIGN_@V&Y zqo03jb0+RqI%Hl1HB{NYN#D1ng%7DF+lo#@gjchf^KXs1Mep+AKpJnsdb2do;Xyp% zmp~@%NX9Tn*VH?Twed)xA$C;BvL-xA5&g%q*Dh477^$cLOw~(kX-(|5bd*?TYsyfR z|J4^|_3>TI5v_o`N>rw^) zV{!9|AXwE5pSy;1HZg^~J)=A*Z3MaW8da6^_T1(;%7b-SCF)IE~$OZt$>u@D&!#HPEDd0eT0o_&30v2hw*cGH1 zwqquV?ix=mt%_{PWbfHm3H&c*DC#i=TXl8%zn>c1}%^SL?avWr2s!o zN}Ys}*EjlOPUo%Rd!+|WFAtuv&sY#V{?$71TiNPRMC5x_KaLn}O$b^0+Mg`;hHUiY&@f4gEjJRc(8G z=1c0>9cTwgGCmrqsW5sG3s1Ppz6&Fil#kWPh2Shi9||)q~F2>8*f*p0s`UPdE>1g1pI}#azGbK zE-PX+x)6ycl;X8=G!F%4GJ`6DX4g@!GW}AY#%lAWE!M57m~TOntsGh2jP${i+Y(mu z8kY`h^mOsGy0@WbkKz{H1CF(?_#59?6}U9(oX~bO1Hwn_F1@WkvBQ}A(O$iBHqQ)V zqYU$A8n)~MR*uG;nyL_B?Zr803gO#21u$5xqEOywstn#cZ#lK`>=7!HXMUg@m@g<9`BX z{rV_VeqX?HW;~E^KhLjEf-2` z7Y zCucKQ8GBhI8DQhb(8IztefQ*i{^@m!^0C(bnbgs9*I$v2P)@RAb-Rb_NFY;eVP?{U zr#99st5w8XH2u8_TDvTB4o|-61jv?J%|LsH5tkGV)K;9{>HOfCpP{TQ5g4qwS$i5{ zHc)VoMcKR`VGR)XL~hSNCNCs_7Ll}I#V`Ma1V6c>>((c`m+i8@?s{(@qBWIh;QyTL=9o= zlbRK0L!Pi!d|VpaP|rW909i7T$*{3tlbFt8wv*1mPV}mlIM6f<4L;LJZh!BZxK4kh z>iXmwA=g2-EF}q1PRf; zkr{LowM1tn*DhRa!xx+?z^xS2h`oJX|J+5;3TrOE3Sbt9jLJTuks8!;DzsrLw%VAP zinsW;FFG`pS_o)7oiMoh3Q>L=Rhd45E#zmaI@jZ&{s{7LN{f{^Of7OpuQPdB{k}`d zk63L+6m}6+gizzSmm3QS=R6yUc=*zV07K1$*wU!j;Vrl9>2vglQXkPrBY9p zP|mm3r3GD0t9O%#|HuHHo$5nmIg1o;)%rVvD!iPP*aQgROCe;9pRotyo%Y}NN68om zwqa;jM=M?|L;yNv)k`|sl$#p$DY0d3c2lgwy!42#u~#hAKed36_uyRZ_HNoghS{x(CMqlli|f~h2J zjJ>?LzUO%vbz`$^tC_~yIymC^pt1v&%CDERShptI3|9H0fpsrCfTkJbuI}L{pu~_-TLi}z?6@KMPBR@62fX2cW)^%n#vWw57%f6riZUdGZ?h^<9`s;*K-ocM>b`Lu z(IjnFq3lq7bmZ5*4uF|6cB-p$|DF~Z7t6XEfdzE_Unlqe&34iT06d9k!@Fo}6>m{A zYQ?o$RcYL}tD)G2P)kLtC?zdH-GcC1+pcX@r9}|CtJTIOByNpLqPo2(qSXBsRktdM zAgN1|_uF&czu^6K=FFU#dCr+RGiRPpQ8ftfPqp^uzAwT`Ol&0cp`}OV6FzM%-T|^g zp$EcA@^SO3Bi6G^F`j7RA)>y1vag_J(D>bfbI@?Z+{UQ8QJqW~{5$fcA374T!}G~g zLo~J4GIlC;iYbLb@`*M&eO1|aehLw3@z$cHTC<_;pyeAN|Cd}MdBVHWSGrb?KCm56 z{&f460T_JZCuty97o4QU?{CL|Sr(zG#g^-vKX;G>!?X6SS@)iOiQrUP<0Y!HW9cw( zpJ{Er2%VyYd8bZr0t2xM&A1R>QA)H!#e? zx_vJ6-E-D3+{a}#dvCpOW7?ZhuVf4!6=Z8KX3!*uXLI*u)?h$7-NBD3dvEgBk`|t+ zD+#wvA{S|yn*}u}RG&lh{jF@c#J=&8_Fjiu&aWe}TKofc$%zlvUs8MjH1i*Ir>!rv zC-pS4cqBo>Q%`04wD4Ri@B?yuke%9m_zds^^d&XhA;ws3si7&ms)P_h4C)l`L&tpc^P_i3?x)1yJ#vY&u7$=PqQGeQDMg5Q?0r}v(6FRrto=X9HvGP)@yTD zuD%aA&jQNCsf-@=G>esibhXp{cI09I)g8jrN6Wyy&gXLw$ zI^wp{TgQv?XgDkl=}}{sVe)#k^1o!FF2Cam4XVoAu0kp z8flKozQ61%p%i*6rXeZRaK{IrS8rxOcOMB%93I5dEXkW%<$BZ3pOsz)OzDHiU z1d{XQuhJga00C@$cvoYwsq8Y|UrEEjR}TmOE3|FWqWMVA%=)%TK)_@KM0&kI#yIQ& zVuH)MfO}htJLxt*(NL(F(;sBN{C7!3%9GynWqQiKmG3vt&|DRUI^mMlFBEtcT6z0Z zGGbP5R4MBnao}U=DlTqo&0S;+S>F*}`$~)#`=I%+4`kLH+8u0w7fYX?NN}qzNJ8Qi zexr4CEM7XJd?@K+9VXr|B(OSlJI_dM5mdw8X)GU}dFvFMOW2JxcWIi+^!sNgJp;NE zfy#JPo}ML5f@uA%H(~mx^BE}mP8Bo=qcHZEvF|Aydrt&Ky<*XzVF^5whPMp8&Z9ir z-$|Rr&!0au*r)rIeU!UAGX}8~#C(QlXbMtO)mt+VBlo4s5Up8)yMA)8q%O1@%_S&= zmdXbD;OlMHp*ohQy)J=TOnCxgz7sA0;-o2IvhQeNvOIl=Y{xm(qP=H>abX)?|Cz4J zpu_M(ww#W16>#2py4I%#gvkSuLSthb9ivc_yRene{~c%?jpZ-U5!!fy!Fw&a>@LJ} zCn#|}b?;GP*TBt7kkGHbZogJChDH@^ZxeJC+`p`00s@Lu5go;A#&t&~@MBDVe;$ilS(czlvkey1LDZaT+}^G~`B7=Ar~>^a>u zNpjn%PLNuIW1GJk?}rLrYh+snBtFXT^(Gc}6BL2q35Y2v$hC>%Y9;eRAcg0an`B)| zhcuafcVN6GZFnzdFx?#77Y^lzz1h~)m!^@cS{CF|f{QTa{)R;Q)-|==M64O|+@Abe zGvHBJ)8xroO0KuTk2X{RSAeqP9f>9Sja`QdJ8RwJYYR7tszVle!W`$^&Y72i%dJ!j z?9Y;vAOl-Yu+e518NS+Wk937RxFj9yLJirzT8f*hQ$gT#tDB`G&m?jmfE93J5L_VB zUNhXhpTh^z7>KnZ7e&b;mV&IHhL)qwy(2XBl)8$zuf)@?_}=@=s&zBp=e9oD?x z$>)_TXj;rGHhcn_Y^uV*AbB{~kh7++NNiyBOU+sQsz=ld9IT(+RoD%r6}!oUiSwI2 zsx#Hxbhz;D8W&psS=%2jK@=sRz_z54q1rjkkp6}b7XOG#3=5N2D}JYx=@c0C-LHVf zA#Q2Io_*gMg<}M)^7pS8C~<2QR-)Jym^~NUBNOgwAi?J|J#$PzIFk7X=&!Ov2Zg1yx?@r3bcLo6%jt=21Z{HbVn{tw6V<#b} z1{@T+5pH~tC)$DNXzLj3;StP!H*s@^C7o=t<6Xz zf%~Vekn%yw)ao*Kx+l1DBu(SP#nED-M*Sha<8?p^x=-{gXse`_rPf7M-R>*Y2UjPj zQ6D`yKw@(jbo%JM!}PH|yL14fnGP}Wkc~bg;s@BF?s0>d(*^wjw`SFkr5|jas`~@P z#(!gn9yxDmSRK7C*Hz-4sO}>z1=SO6tvG>p(PCb&ylRa?PVD_K6h&Ns_xsgR=O-fASbFeh{;AYSZ1eQSpO6EZLtJu<=K(0{NBh|L8CI)(A?}G!e)%<5}Rte}= z0K7%>-U8BVdUkAVWxm0I*6aPR*N=5BAzA+gjZqaJ literal 0 HcmV?d00001 diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/actions.d.ts b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/actions.d.ts index 1a452bc..af9c1d4 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/actions.d.ts +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/actions.d.ts @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/assets.d.ts b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/assets.d.ts index 35ce99f..00719e1 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/assets.d.ts +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/assets.d.ts @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/clickgui/settings_panel.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/clickgui/settings_panel.js index 25bc2b8..75ad9a0 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/clickgui/settings_panel.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/clickgui/settings_panel.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/clickgui/theme_preview.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/clickgui/theme_preview.js index bfab908..3a45441 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/clickgui/theme_preview.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/clickgui/theme_preview.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/compact_stat.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/compact_stat.js index 8b37843..bb9ab44 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/compact_stat.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/compact_stat.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/inventory_panel.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/inventory_panel.js index 7e2c45b..3437156 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/inventory_panel.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/inventory_panel.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/itemizer.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/itemizer.js index 53d02a1..8335c89 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/itemizer.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/itemizer.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/list_panel.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/list_panel.js index 6cadc48..8569f0a 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/list_panel.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/list_panel.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/panel_base.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/panel_base.js index e8235da..4e7147f 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/panel_base.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/panel_base.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/triangulator.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/triangulator.js index 349ce72..fc82eb2 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/triangulator.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/draggable/triangulator.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/custom_health_bar.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/custom_health_bar.js index 594653e..18e1d7b 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/custom_health_bar.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/custom_health_bar.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/dynamic_island.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/dynamic_island.js index 445545c..9a374e7 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/dynamic_island.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/dynamic_island.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/tooltip_panel.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/tooltip_panel.js index f5eae6f..0f27c8f 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/tooltip_panel.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/hud/static/tooltip_panel.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/runtime.d.ts b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/runtime.d.ts index 2841381..d219db4 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/runtime.d.ts +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/runtime.d.ts @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/theme.d.ts b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/theme.d.ts index 1da0f0a..1cb82c1 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/theme.d.ts +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/theme.d.ts @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/ui.d.ts b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/ui.d.ts index 3805e8a..bd0de5b 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/ui.d.ts +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/ui.d.ts @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/ui.js b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/ui.js index 7e545b3..3094208 100644 --- a/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/ui.js +++ b/combatant-client-26.2/src/main/resources/assets/lovisual/ui/api/ui.js @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/command/CommandDiscoveryTest.java b/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/command/CommandDiscoveryTest.java index 5b25e1d..7582573 100644 --- a/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/command/CommandDiscoveryTest.java +++ b/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/command/CommandDiscoveryTest.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. @@ -19,13 +19,14 @@ class CommandDiscoveryTest { void discoversAnnotatedProductionCommandsWithoutManualRegistration() { List commands = CommandManager.getCommands(); - assertTrue(commands.size() >= 18); + assertTrue(commands.size() >= 15); assertNotNull(CommandManager.find("help")); assertNotNull(CommandManager.find("friend")); assertNotNull(CommandManager.find("coords")); assertNull(CommandManager.find("clear")); assertNull(CommandManager.find("say")); assertNull(CommandManager.find("profiler")); + assertNull(CommandManager.find("runtime")); HashSet ids = new HashSet<>(); for (ClientCommand command : commands) { diff --git a/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/command/impl/XaeroWaypointCommandTest.java b/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/command/impl/XaeroWaypointCommandTest.java index ac60b05..6bb69c7 100644 --- a/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/command/impl/XaeroWaypointCommandTest.java +++ b/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/command/impl/XaeroWaypointCommandTest.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/module/modules/player/NoInteractTest.java b/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/module/modules/player/NoInteractTest.java index 8fe4c4a..aa035e7 100644 --- a/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/module/modules/player/NoInteractTest.java +++ b/combatant-client-26.2/src/test/java/dev/loki/lovisual/features/module/modules/player/NoInteractTest.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/test/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetUiScriptEngineTest.java b/combatant-client-26.2/src/test/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetUiScriptEngineTest.java index 237bca2..5062a2e 100644 --- a/combatant-client-26.2/src/test/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetUiScriptEngineTest.java +++ b/combatant-client-26.2/src/test/java/dev/loki/lovisual/render/engine/renderer/ui/runtime/script/JavetUiScriptEngineTest.java @@ -1,5 +1,5 @@ /* - * This file is part of the Combatant Client distribution. + * This file is part of the LoVisual Client distribution. * Copyright (c) 2026 pivosos2007. * * Licensed under the GNU General Public License v3.0. diff --git a/combatant-client-26.2/src/test/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementGateTest.java b/combatant-client-26.2/src/test/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementGateTest.java deleted file mode 100644 index 76a4433..0000000 --- a/combatant-client-26.2/src/test/java/dev/loki/lovisual/util/block/scaffold/ScaffoldPlacementGateTest.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * This file is part of the Combatant Client distribution. - * Copyright (c) 2026 pivosos2007. - * - * Licensed under the GNU General Public License v3.0. - */ - -package dev.loki.lovisual.util.block.scaffold; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.junit.jupiter.params.provider.ValueSource; - -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -final class ScaffoldPlacementGateTest { - private static final long START = 10_000_000_000L; - - @Test - void eagleIsExactlyOneTickInsteadOfAContinuousHold() { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - - assertTrue(consumeEligiblePulse(gate)); - assertFalse(consumeEligiblePulse(gate)); - assertFalse(consumeEligiblePulse(gate)); - } - - @Test - void leavingTheEdgeDoesNotConsumeTheArmedPulse() { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - - assertFalse(gate.consumeEaglePulse(true, false, false, true, false, false)); - assertTrue(consumeEligiblePulse(gate)); - assertFalse(consumeEligiblePulse(gate)); - } - - @Test - void blocksToEagleZeroRearmsOnlyAfterAPlacedBlock() { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - - assertTrue(consumeEligiblePulse(gate)); - assertFalse(consumeEligiblePulse(gate)); - - gate.recordSuccessfulPlacement(START, 0); - - assertTrue(consumeEligiblePulse(gate)); - assertFalse(consumeEligiblePulse(gate)); - } - - @Test - void blocksToEagleTwoPulsesOnceEveryThreeSuccessfulBlocks() { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - assertTrue(consumeEligiblePulse(gate)); - - gate.recordSuccessfulPlacement(START, 2); - assertFalse(consumeEligiblePulse(gate)); - gate.recordSuccessfulPlacement(START + 1, 2); - assertFalse(consumeEligiblePulse(gate)); - gate.recordSuccessfulPlacement(START + 2, 2); - assertTrue(consumeEligiblePulse(gate)); - assertFalse(consumeEligiblePulse(gate)); - } - - @Test - void sixBlocksPerSecondUsesAnExactNanosecondGate() { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - gate.recordSuccessfulPlacement(START, 0); - - assertFalse(gate.isPlacementReady(START + 166_666_666L, 6.0, 0)); - assertTrue(gate.isPlacementReady(START + 166_666_667L, 6.0, 0)); - } - - @Test - void extraTickDelayAndSpeedGateMustBothBeReady() { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - gate.recordSuccessfulPlacement(START, 0); - - assertFalse(gate.isPlacementReady(START + 1_000_000_000L, 6.0, 1)); - assertTrue(gate.isPlacementReady(START + 1_000_000_000L, 6.0, 0)); - } - - @Test - void cadenceNeverExtendsOrRearmsEagle() { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - assertTrue(consumeEligiblePulse(gate)); - - assertTrue(gate.isPlacementReady(START, 20.0, 0)); - assertTrue(gate.isPlacementReady(START + 60_000_000_000L, 1.0, 0)); - assertFalse(consumeEligiblePulse(gate)); - } - - @ParameterizedTest(name = "failed placement at {0} blocks/s") - @ValueSource(doubles = {1.0, 3.8, 6.0, 10.0, 20.0}) - void failedPlacementsAtAnySpeedCannotRearmEagle(double blocksPerSecond) { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - assertTrue(consumeEligiblePulse(gate)); - - // A failed placement does not call recordSuccessfulPlacement. Neither elapsed time nor - // another placement attempt is allowed to turn the one-tick pulse into a hold. - assertTrue(gate.isPlacementReady(START, blocksPerSecond, 0)); - assertFalse(consumeEligiblePulse(gate)); - assertTrue(gate.isPlacementReady(START + 60_000_000_000L, blocksPerSecond, 0)); - assertFalse(consumeEligiblePulse(gate)); - } - - @Test - void resetClearsCadenceAndArmsOneFreshEaglePulse() { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - consumeEligiblePulse(gate); - gate.recordSuccessfulPlacement(START, 20); - - gate.reset(); - - assertTrue(gate.isPlacementReady(START, 1.0, 0)); - assertTrue(consumeEligiblePulse(gate)); - assertFalse(consumeEligiblePulse(gate)); - } - - @ParameterizedTest(name = "pulse eligibility mask {0}") - @MethodSource("allPulseEligibilityCombinations") - void everyEagleEligibilityCombinationIsHandled( - int mask, - boolean eagleEnabled, - boolean closeToEdge, - boolean onlyOnGround, - boolean onGround, - boolean flying, - boolean goingDown - ) { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - boolean expected = eagleEnabled - && closeToEdge - && (!onlyOnGround || onGround) - && !flying - && !goingDown; - - assertTrue( - gate.consumeEaglePulse( - eagleEnabled, - closeToEdge, - onlyOnGround, - onGround, - flying, - goingDown - ) == expected, - "unexpected first-tick decision for mask " + mask - ); - - if (expected) { - assertFalse(consumeEligiblePulse(gate), "eligible pulse must last exactly one tick"); - } else { - assertTrue(consumeEligiblePulse(gate), "an ineligible tick must not consume the armed pulse"); - assertFalse(consumeEligiblePulse(gate)); - } - } - - @ParameterizedTest(name = "safe-walk eligibility mask {0}") - @MethodSource("allSafeWalkCombinations") - void everySafeWalkCombinationIsHandled( - int mask, - boolean scaffoldEnabled, - boolean eagleEnabled, - boolean canOperate, - boolean onGround, - boolean flying, - boolean goingDown, - boolean hasBlocks - ) { - boolean expected = scaffoldEnabled - && eagleEnabled - && canOperate - && onGround - && !flying - && !goingDown - && hasBlocks; - - assertTrue( - ScaffoldPlacementGate.shouldSafeWalk( - scaffoldEnabled, - eagleEnabled, - canOperate, - onGround, - flying, - goingDown, - hasBlocks - ) == expected, - "unexpected edge-clipping decision for mask " + mask - ); - } - - @ParameterizedTest(name = "blocks_to_eagle={0}") - @ValueSource(ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}) - void everyBlocksToEagleSettingRearmsAtItsExactBoundary(int blocksToEagle) { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - assertTrue(consumeEligiblePulse(gate)); - - for (int placement = 1; placement <= blocksToEagle; placement++) { - gate.recordSuccessfulPlacement(START + placement, blocksToEagle); - assertFalse(consumeEligiblePulse(gate), "rearmed too early at placement " + placement); - } - - gate.recordSuccessfulPlacement(START + blocksToEagle + 1L, blocksToEagle); - assertTrue(consumeEligiblePulse(gate), "did not rearm at the configured boundary"); - assertFalse(consumeEligiblePulse(gate), "boundary pulse lasted more than one tick"); - } - - @Test - void everyShortInterleavingOfEdgeTicksFailuresAndSuccessfulPlacementsMatchesTheModel() { - int sequenceLength = 7; - int actionCount = 4; - int sequenceCount = (int) Math.pow(actionCount, sequenceLength); - - for (int blocksToEagle = 0; blocksToEagle <= 10; blocksToEagle++) { - for (int encodedSequence = 0; encodedSequence < sequenceCount; encodedSequence++) { - ScaffoldPlacementGate gate = new ScaffoldPlacementGate(); - boolean expectedArmed = true; - int expectedPlacements = 0; - int actions = encodedSequence; - - for (int step = 0; step < sequenceLength; step++) { - int action = actions % actionCount; - actions /= actionCount; - - switch (action) { - case 0 -> { // Eligible edge tick. - boolean actual = consumeEligiblePulse(gate); - assertTrue( - actual == expectedArmed, - sequenceMessage(blocksToEagle, encodedSequence, step, action) - ); - expectedArmed = false; - } - case 1 -> { // Away from the edge: must not consume the pulse. - assertFalse( - gate.consumeEaglePulse(true, false, false, true, false, false), - sequenceMessage(blocksToEagle, encodedSequence, step, action) - ); - } - case 2 -> { // A real accepted placement is the only re-arm source. - gate.recordSuccessfulPlacement(START + step + 1L, blocksToEagle); - expectedPlacements++; - if (expectedPlacements > blocksToEagle) { - expectedPlacements = 0; - expectedArmed = true; - } - } - case 3 -> { // Eagle disabled: another non-consuming failed tick. - assertFalse( - gate.consumeEaglePulse(false, true, false, true, false, false), - sequenceMessage(blocksToEagle, encodedSequence, step, action) - ); - } - default -> throw new AssertionError("unknown action " + action); - } - } - } - } - } - - private static boolean consumeEligiblePulse(ScaffoldPlacementGate gate) { - return gate.consumeEaglePulse(true, true, false, true, false, false); - } - - private static Stream allPulseEligibilityCombinations() { - return IntStream.range(0, 64).mapToObj(mask -> Arguments.of( - mask, - bit(mask, 0), - bit(mask, 1), - bit(mask, 2), - bit(mask, 3), - bit(mask, 4), - bit(mask, 5) - )); - } - - private static Stream allSafeWalkCombinations() { - return IntStream.range(0, 128).mapToObj(mask -> Arguments.of( - mask, - bit(mask, 0), - bit(mask, 1), - bit(mask, 2), - bit(mask, 3), - bit(mask, 4), - bit(mask, 5), - bit(mask, 6) - )); - } - - private static boolean bit(int value, int index) { - return (value & (1 << index)) != 0; - } - - private static String sequenceMessage(int blocksToEagle, int sequence, int step, int action) { - return "blocksToEagle=" + blocksToEagle - + ", sequence=" + sequence - + ", step=" + step - + ", action=" + action; - } -} diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/CommandEncoderDiagnosticsMixin.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/CommandEncoderDiagnosticsMixin.java index 76ef77f..2e31748 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/CommandEncoderDiagnosticsMixin.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/CommandEncoderDiagnosticsMixin.java @@ -15,7 +15,7 @@ import dev.loki.lovisual.render.engine.rhi.backend.vulkan.debug.VulkanCrashDiagn @Mixin(CommandEncoder.class) public abstract class CommandEncoderDiagnosticsMixin { @Unique - private static boolean combatant$isVulkanBackend() { + private static boolean lovisual$isVulkanBackend() { try { if (RenderSystem.getDevice() == null || RenderSystem.getDevice().getDeviceInfo() == null) return false; String backendName = RenderSystem.getDevice().getDeviceInfo().backendName(); @@ -26,7 +26,7 @@ public abstract class CommandEncoderDiagnosticsMixin { } @Unique - private static String combatant$label(RenderPassDescriptor descriptor) { + private static String lovisual$label(RenderPassDescriptor descriptor) { if (descriptor == null || descriptor.label() == null) return ""; try { String label = descriptor.label().get(); @@ -37,55 +37,55 @@ public abstract class CommandEncoderDiagnosticsMixin { } @Inject(method = "createRenderPass(Lcom/mojang/blaze3d/systems/RenderPassDescriptor;)Lcom/mojang/blaze3d/systems/RenderPass;", at = @At("HEAD")) - private void combatant$wrapperCreateHead(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { - if (!combatant$isVulkanBackend()) return; + private void lovisual$wrapperCreateHead(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { + if (!lovisual$isVulkanBackend()) return; VulkanCrashDiagnostics.breadcrumbQuiet("commandencoder.wrapper.create.head", - "label", combatant$label(descriptor), + "label", lovisual$label(descriptor), "colors", descriptor == null || descriptor.colorAttachments() == null ? -1 : descriptor.colorAttachments().size(), "depth", descriptor != null && descriptor.depthAttachment() != null); } @Inject(method = "createRenderPass(Lcom/mojang/blaze3d/systems/RenderPassDescriptor;)Lcom/mojang/blaze3d/systems/RenderPass;", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/CommandEncoderBackend;createRenderPass(Lcom/mojang/blaze3d/systems/RenderPassDescriptor;)Lcom/mojang/blaze3d/systems/RenderPassBackend;", shift = At.Shift.BEFORE)) - private void combatant$backendCreateBefore(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { - if (!combatant$isVulkanBackend()) return; - VulkanCrashDiagnostics.breadcrumbQuiet("commandencoder.wrapper.backend.create.before", "label", combatant$label(descriptor)); + private void lovisual$backendCreateBefore(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { + if (!lovisual$isVulkanBackend()) return; + VulkanCrashDiagnostics.breadcrumbQuiet("commandencoder.wrapper.backend.create.before", "label", lovisual$label(descriptor)); } @Inject(method = "createRenderPass(Lcom/mojang/blaze3d/systems/RenderPassDescriptor;)Lcom/mojang/blaze3d/systems/RenderPass;", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/CommandEncoderBackend;createRenderPass(Lcom/mojang/blaze3d/systems/RenderPassDescriptor;)Lcom/mojang/blaze3d/systems/RenderPassBackend;", shift = At.Shift.AFTER)) - private void combatant$backendCreateAfter(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { - if (!combatant$isVulkanBackend()) return; - VulkanCrashDiagnostics.breadcrumbQuiet("commandencoder.wrapper.backend.create.after", "label", combatant$label(descriptor)); + private void lovisual$backendCreateAfter(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { + if (!lovisual$isVulkanBackend()) return; + VulkanCrashDiagnostics.breadcrumbQuiet("commandencoder.wrapper.backend.create.after", "label", lovisual$label(descriptor)); } @Inject(method = "createRenderPass(Lcom/mojang/blaze3d/systems/RenderPassDescriptor;)Lcom/mojang/blaze3d/systems/RenderPass;", at = @At("RETURN")) - private void combatant$wrapperCreateReturn(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { - if (!combatant$isVulkanBackend()) return; + private void lovisual$wrapperCreateReturn(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { + if (!lovisual$isVulkanBackend()) return; VulkanCrashDiagnostics.breadcrumbQuiet("commandencoder.wrapper.create.return", - "label", combatant$label(descriptor), + "label", lovisual$label(descriptor), "pass", cir.getReturnValue() == null ? "" : cir.getReturnValue().getClass().getName()); } @Inject(method = "submitRenderPass", at = @At("HEAD")) - private void combatant$wrapperSubmitHead(CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; + private void lovisual$wrapperSubmitHead(CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; VulkanCrashDiagnostics.breadcrumbQuiet("commandencoder.wrapper.submit.head"); } @Inject(method = "submitRenderPass", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/CommandEncoderBackend;submitRenderPass()V", shift = At.Shift.BEFORE)) - private void combatant$backendSubmitBefore(CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; + private void lovisual$backendSubmitBefore(CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; VulkanCrashDiagnostics.breadcrumbQuiet("commandencoder.wrapper.backend.submit.before"); } @Inject(method = "submitRenderPass", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/CommandEncoderBackend;submitRenderPass()V", shift = At.Shift.AFTER)) - private void combatant$backendSubmitAfter(CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; + private void lovisual$backendSubmitAfter(CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; VulkanCrashDiagnostics.breadcrumbQuiet("commandencoder.wrapper.backend.submit.after"); } @Inject(method = "submitRenderPass", at = @At("TAIL")) - private void combatant$wrapperSubmitTail(CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; + private void lovisual$wrapperSubmitTail(CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; VulkanCrashDiagnostics.breadcrumbQuiet("commandencoder.wrapper.submit.tail"); } } diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/RenderPassWrapperDiagnosticsMixin.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/RenderPassWrapperDiagnosticsMixin.java index bf381d2..0d0432d 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/RenderPassWrapperDiagnosticsMixin.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/RenderPassWrapperDiagnosticsMixin.java @@ -13,7 +13,7 @@ import dev.loki.lovisual.render.engine.rhi.backend.vulkan.debug.VulkanCrashDiagn @Mixin(RenderPass.class) public abstract class RenderPassWrapperDiagnosticsMixin { @Unique - private static boolean combatant$isVulkanBackend() { + private static boolean lovisual$isVulkanBackend() { try { if (RenderSystem.getDevice() == null || RenderSystem.getDevice().getDeviceInfo() == null) return false; String backendName = RenderSystem.getDevice().getDeviceInfo().backendName(); @@ -24,7 +24,7 @@ public abstract class RenderPassWrapperDiagnosticsMixin { } @Unique - private static String combatant$pipelineId(RenderPipeline pipeline) { + private static String lovisual$pipelineId(RenderPipeline pipeline) { if (pipeline == null) return ""; try { return String.valueOf(pipeline.getLocation()); @@ -34,50 +34,50 @@ public abstract class RenderPassWrapperDiagnosticsMixin { } @Inject(method = "setPipeline", at = @At("HEAD")) - private void combatant$setPipelineHead(RenderPipeline pipeline, CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; - VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.wrapper.setpipeline.head", "pipeline", combatant$pipelineId(pipeline)); + private void lovisual$setPipelineHead(RenderPipeline pipeline, CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; + VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.wrapper.setpipeline.head", "pipeline", lovisual$pipelineId(pipeline)); } @Inject( method = "setPipeline", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderPassBackend;setPipeline(Lcom/mojang/blaze3d/pipeline/RenderPipeline;)V", shift = At.Shift.BEFORE) ) - private void combatant$backendSetPipelineBefore(RenderPipeline pipeline, CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; - VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.wrapper.backend.setpipeline.before", "pipeline", combatant$pipelineId(pipeline)); + private void lovisual$backendSetPipelineBefore(RenderPipeline pipeline, CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; + VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.wrapper.backend.setpipeline.before", "pipeline", lovisual$pipelineId(pipeline)); } @Inject( method = "setPipeline", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderPassBackend;setPipeline(Lcom/mojang/blaze3d/pipeline/RenderPipeline;)V", shift = At.Shift.AFTER) ) - private void combatant$backendSetPipelineAfter(RenderPipeline pipeline, CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; - VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.wrapper.backend.setpipeline.after", "pipeline", combatant$pipelineId(pipeline)); + private void lovisual$backendSetPipelineAfter(RenderPipeline pipeline, CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; + VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.wrapper.backend.setpipeline.after", "pipeline", lovisual$pipelineId(pipeline)); } @Inject(method = "close", at = @At("HEAD")) - private void combatant$closeHead(CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; + private void lovisual$closeHead(CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.wrapper.close.head"); } @Inject(method = "close", at = @At(value = "INVOKE", target = "Ljava/lang/Runnable;run()V", shift = At.Shift.BEFORE)) - private void combatant$closeOnFinishBefore(CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; + private void lovisual$closeOnFinishBefore(CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.wrapper.close.onfinish.before"); } @Inject(method = "close", at = @At(value = "INVOKE", target = "Ljava/lang/Runnable;run()V", shift = At.Shift.AFTER)) - private void combatant$closeOnFinishAfter(CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; + private void lovisual$closeOnFinishAfter(CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.wrapper.close.onfinish.after"); } @Inject(method = "close", at = @At("TAIL")) - private void combatant$closeTail(CallbackInfo ci) { - if (!combatant$isVulkanBackend()) return; + private void lovisual$closeTail(CallbackInfo ci) { + if (!lovisual$isVulkanBackend()) return; VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.wrapper.close.tail"); } } diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanBackendMixin.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanBackendMixin.java index 989e167..5192671 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanBackendMixin.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanBackendMixin.java @@ -10,7 +10,7 @@ import dev.loki.lovisual.render.engine.rhi.backend.vulkan.debug.VulkanCrashDiagn @Mixin(VulkanBackend.class) public abstract class VulkanBackendMixin { @ModifyVariable(method = "createDevice", at = @At("HEAD"), argsOnly = true) - private GpuDebugOptions combatant$forceDebugOptions(GpuDebugOptions options) { + private GpuDebugOptions lovisual$forceDebugOptions(GpuDebugOptions options) { return VulkanCrashDiagnostics.forceDebugOptions(options); } } diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanCheckpointDiagnosticsMixin.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanCheckpointDiagnosticsMixin.java index ef89809..cbc19d2 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanCheckpointDiagnosticsMixin.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanCheckpointDiagnosticsMixin.java @@ -14,7 +14,7 @@ import java.util.function.Supplier; @Mixin(targets = "com.mojang.blaze3d.vulkan.checkpoints.AbstractCheckpointStorage") public abstract class VulkanCheckpointDiagnosticsMixin { @Inject(method = "recordCheckpoint(Lorg/lwjgl/vulkan/VkCommandBuffer;Lcom/mojang/blaze3d/vulkan/checkpoints/CheckpointExtension$CheckpointType;Ljava/util/function/Supplier;)V", at = @At("HEAD")) - private void combatant$logCheckpoint(VkCommandBuffer commandBuffer, + private void lovisual$logCheckpoint(VkCommandBuffer commandBuffer, CheckpointExtension.CheckpointType type, Supplier label, CallbackInfo ci) { diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanCommandEncoderDiagnosticsMixin.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanCommandEncoderDiagnosticsMixin.java index 089b639..7deac09 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanCommandEncoderDiagnosticsMixin.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanCommandEncoderDiagnosticsMixin.java @@ -17,7 +17,7 @@ import dev.loki.lovisual.render.engine.rhi.backend.vulkan.util.VulkanRenderState @Mixin(VulkanCommandEncoder.class) public abstract class VulkanCommandEncoderDiagnosticsMixin { @Inject(method = "createRenderPass", at = @At("HEAD")) - private void combatant$renderPassCreateHead(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { + private void lovisual$renderPassCreateHead(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.create.head", "colors", descriptor == null || descriptor.colorAttachments() == null ? -1 : descriptor.colorAttachments().size(), "depth", descriptor != null && descriptor.depthAttachment() != null, @@ -29,7 +29,7 @@ public abstract class VulkanCommandEncoderDiagnosticsMixin { method = "createRenderPass", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/KHRDynamicRendering;vkCmdBeginRenderingKHR(Lorg/lwjgl/vulkan/VkCommandBuffer;Lorg/lwjgl/vulkan/VkRenderingInfo;)V", shift = At.Shift.BEFORE) ) - private void combatant$beforeBeginRendering(RenderPassDescriptor descriptor, + private void lovisual$beforeBeginRendering(RenderPassDescriptor descriptor, CallbackInfoReturnable cir, @Local VkRenderingInfo renderingInfo) { int colorResolves = 0; @@ -55,19 +55,19 @@ public abstract class VulkanCommandEncoderDiagnosticsMixin { method = "createRenderPass", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/KHRDynamicRendering;vkCmdBeginRenderingKHR(Lorg/lwjgl/vulkan/VkCommandBuffer;Lorg/lwjgl/vulkan/VkRenderingInfo;)V", shift = At.Shift.AFTER) ) - private void combatant$afterBeginRendering(RenderPassDescriptor descriptor, + private void lovisual$afterBeginRendering(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.beginrendering.after"); } @Inject(method = "createRenderPass", at = @At("RETURN")) - private void combatant$renderPassCreated(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { + private void lovisual$renderPassCreated(RenderPassDescriptor descriptor, CallbackInfoReturnable cir) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.create.return", "backend", cir.getReturnValue() == null ? "" : cir.getReturnValue().getClass().getName()); } @Inject(method = "submitRenderPass", at = @At("HEAD")) - private void combatant$submitVulkanRenderPassHead(CallbackInfo ci) { + private void lovisual$submitVulkanRenderPassHead(CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.submit.head"); } @@ -75,7 +75,7 @@ public abstract class VulkanCommandEncoderDiagnosticsMixin { method = "submitRenderPass", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/KHRDynamicRendering;vkCmdEndRenderingKHR(Lorg/lwjgl/vulkan/VkCommandBuffer;)V", shift = At.Shift.BEFORE) ) - private void combatant$beforeEndRendering(CallbackInfo ci) { + private void lovisual$beforeEndRendering(CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.endrendering.before"); } @@ -83,12 +83,12 @@ public abstract class VulkanCommandEncoderDiagnosticsMixin { method = "submitRenderPass", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/KHRDynamicRendering;vkCmdEndRenderingKHR(Lorg/lwjgl/vulkan/VkCommandBuffer;)V", shift = At.Shift.AFTER) ) - private void combatant$afterEndRendering(CallbackInfo ci) { + private void lovisual$afterEndRendering(CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.endrendering.after"); } @Inject(method = "submitRenderPass", at = @At("TAIL")) - private void combatant$submitVulkanRenderPassTail(CallbackInfo ci) { + private void lovisual$submitVulkanRenderPassTail(CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.submit.tail"); } } diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanDebugMessageMixin.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanDebugMessageMixin.java index 63142aa..2c9682a 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanDebugMessageMixin.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanDebugMessageMixin.java @@ -9,7 +9,7 @@ import dev.loki.lovisual.render.engine.rhi.backend.vulkan.debug.VulkanCrashDiagn @Mixin(targets = "com.mojang.blaze3d.vulkan.VulkanDebug$Enabled") public abstract class VulkanDebugMessageMixin { @Inject(method = "onDebugMessage", at = @At("HEAD")) - private void combatant$captureDriverDebugMessage(int severity, + private void lovisual$captureDriverDebugMessage(int severity, int type, long callbackData, long userData, diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanDeviceDiagnosticsMixin.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanDeviceDiagnosticsMixin.java index 05eb4e8..99ae705 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanDeviceDiagnosticsMixin.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanDeviceDiagnosticsMixin.java @@ -17,7 +17,7 @@ import java.util.Set; @Mixin(VulkanDevice.class) public abstract class VulkanDeviceDiagnosticsMixin { @Inject(method = "", at = @At("RETURN")) - private void combatant$dumpVulkanDevice(ShaderSource shaderSource, + private void lovisual$dumpVulkanDevice(ShaderSource shaderSource, VulkanInstance instance, VulkanPhysicalDevice physicalDevice, Set enabledExtensions, diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanQueueSubmissionMixin.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanQueueSubmissionMixin.java index 50270e6..71547c2 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanQueueSubmissionMixin.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanQueueSubmissionMixin.java @@ -14,7 +14,7 @@ public abstract class VulkanQueueSubmissionMixin { method = "close", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/KHRSynchronization2;vkQueueSubmit2KHR(Lorg/lwjgl/vulkan/VkQueue;Lorg/lwjgl/vulkan/VkSubmitInfo2$Buffer;J)I") ) - private int combatant$diagnoseQueueSubmit(VkQueue queue, VkSubmitInfo2.Buffer submits, long fence) { + private int lovisual$diagnoseQueueSubmit(VkQueue queue, VkSubmitInfo2.Buffer submits, long fence) { int submitCount = submits == null ? -1 : submits.remaining(); VulkanCrashDiagnostics.breadcrumbQuiet("queue.submit.before", "submits", submitCount, "fence", fence); int result = KHRSynchronization2.vkQueueSubmit2KHR(queue, submits, fence); diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanRenderPassDiagnosticsMixin.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanRenderPassDiagnosticsMixin.java index 7791393..15f33d2 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanRenderPassDiagnosticsMixin.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanRenderPassDiagnosticsMixin.java @@ -27,7 +27,7 @@ import java.util.function.Supplier; public abstract class VulkanRenderPassDiagnosticsMixin { @Inject(method = "", at = @At("HEAD")) - private static void combatant$ctorHead(VulkanDevice device, + private static void lovisual$ctorHead(VulkanDevice device, VulkanCommandEncoder encoder, VkCommandBuffer commandBuffer, CheckpointExtension.CheckpointStorage checkpointStorage, @@ -46,7 +46,7 @@ public abstract class VulkanRenderPassDiagnosticsMixin { } @Inject(method = "", at = @At("TAIL")) - private void combatant$ctorTail(VulkanDevice device, + private void lovisual$ctorTail(VulkanDevice device, VulkanCommandEncoder encoder, VkCommandBuffer commandBuffer, CheckpointExtension.CheckpointStorage checkpointStorage, @@ -63,7 +63,7 @@ public abstract class VulkanRenderPassDiagnosticsMixin { @Inject(method = "setPipeline", at = @At("HEAD")) - private void combatant$setPipelineHead(RenderPipeline pipeline, CallbackInfo ci) { + private void lovisual$setPipelineHead(RenderPipeline pipeline, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.setpipeline.head", "pipeline", pipelineId(pipeline)); } @@ -71,7 +71,7 @@ public abstract class VulkanRenderPassDiagnosticsMixin { method = "setPipeline", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vulkan/VulkanDevice;getOrCompilePipeline(Lcom/mojang/blaze3d/pipeline/RenderPipeline;)Lcom/mojang/blaze3d/vulkan/VulkanRenderPipeline;", shift = At.Shift.BEFORE) ) - private void combatant$compilePipelineBefore(RenderPipeline pipeline, CallbackInfo ci) { + private void lovisual$compilePipelineBefore(RenderPipeline pipeline, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.pipeline.get.before", "pipeline", pipelineId(pipeline)); } @@ -79,7 +79,7 @@ public abstract class VulkanRenderPassDiagnosticsMixin { method = "setPipeline", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vulkan/VulkanDevice;getOrCompilePipeline(Lcom/mojang/blaze3d/pipeline/RenderPipeline;)Lcom/mojang/blaze3d/vulkan/VulkanRenderPipeline;", shift = At.Shift.AFTER) ) - private void combatant$compilePipelineAfter(RenderPipeline pipeline, CallbackInfo ci) { + private void lovisual$compilePipelineAfter(RenderPipeline pipeline, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.pipeline.get.after", "pipeline", pipelineId(pipeline)); } @@ -87,7 +87,7 @@ public abstract class VulkanRenderPassDiagnosticsMixin { method = "setPipeline", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VK12;vkCmdBindPipeline(Lorg/lwjgl/vulkan/VkCommandBuffer;IJ)V", shift = At.Shift.BEFORE) ) - private void combatant$bindPipelineBefore(RenderPipeline pipeline, CallbackInfo ci) { + private void lovisual$bindPipelineBefore(RenderPipeline pipeline, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.bindpipeline.before", "pipeline", pipelineId(pipeline)); } @@ -95,47 +95,47 @@ public abstract class VulkanRenderPassDiagnosticsMixin { method = "setPipeline", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VK12;vkCmdBindPipeline(Lorg/lwjgl/vulkan/VkCommandBuffer;IJ)V", shift = At.Shift.AFTER) ) - private void combatant$bindPipelineAfter(RenderPipeline pipeline, CallbackInfo ci) { + private void lovisual$bindPipelineAfter(RenderPipeline pipeline, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.bindpipeline.after", "pipeline", pipelineId(pipeline)); } @Inject(method = "setPipeline", at = @At("TAIL")) - private void combatant$setPipelineTail(RenderPipeline pipeline, CallbackInfo ci) { + private void lovisual$setPipelineTail(RenderPipeline pipeline, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.setpipeline.tail", "pipeline", pipelineId(pipeline)); } @Inject(method = "bindTexture", at = @At("HEAD")) - private void combatant$bindTextureHead(String name, GpuTextureView view, GpuSampler sampler, CallbackInfo ci) { + private void lovisual$bindTextureHead(String name, GpuTextureView view, GpuSampler sampler, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.bindtexture.head", "name", name, "view", objectText(view), "sampler", objectText(sampler)); } @Inject(method = "setUniform(Ljava/lang/String;Lcom/mojang/blaze3d/buffers/GpuBufferSlice;)V", at = @At("HEAD")) - private void combatant$setUniformSliceHead(String name, GpuBufferSlice slice, CallbackInfo ci) { + private void lovisual$setUniformSliceHead(String name, GpuBufferSlice slice, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.uniform.slice.head", "name", name, "slice", sliceText(slice)); } @Inject(method = "setUniform(Ljava/lang/String;Lcom/mojang/blaze3d/buffers/GpuBuffer;)V", at = @At("HEAD")) - private void combatant$setUniformBufferHead(String name, GpuBuffer buffer, CallbackInfo ci) { + private void lovisual$setUniformBufferHead(String name, GpuBuffer buffer, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.uniform.buffer.head", "name", name, "buffer", bufferText(buffer)); } @Inject(method = "enableScissor", at = @At("HEAD")) - private void combatant$enableScissorHead(int x, int y, int width, int height, CallbackInfo ci) { + private void lovisual$enableScissorHead(int x, int y, int width, int height, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.scissor.enable.head", "rect", x + "," + y + " " + width + "x" + height); } @Inject(method = "setVertexBuffer", at = @At("HEAD")) - private void combatant$vertexBufferHead(int slot, GpuBufferSlice slice, CallbackInfo ci) { + private void lovisual$vertexBufferHead(int slot, GpuBufferSlice slice, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.vertexbuffer.head", "slot", slot, "slice", sliceText(slice)); } @Inject(method = "setIndexBuffer", at = @At("HEAD")) - private void combatant$indexBufferHead(GpuBuffer buffer, IndexType indexType, CallbackInfo ci) { + private void lovisual$indexBufferHead(GpuBuffer buffer, IndexType indexType, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.indexbuffer.head", "buffer", bufferText(buffer), "type", indexType); } @Inject(method = "pushDescriptors", at = @At("HEAD")) - private void combatant$pushDescriptorsHead(CallbackInfo ci) { + private void lovisual$pushDescriptorsHead(CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.pushdescriptors.head"); } @@ -143,7 +143,7 @@ public abstract class VulkanRenderPassDiagnosticsMixin { method = "pushDescriptors", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/KHRPushDescriptor;vkCmdPushDescriptorSetKHR(Lorg/lwjgl/vulkan/VkCommandBuffer;IJILorg/lwjgl/vulkan/VkWriteDescriptorSet$Buffer;)V", shift = At.Shift.BEFORE) ) - private void combatant$pushDescriptorsNativeBefore(CallbackInfo ci) { + private void lovisual$pushDescriptorsNativeBefore(CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.pushdescriptors.native.before"); } @@ -151,17 +151,17 @@ public abstract class VulkanRenderPassDiagnosticsMixin { method = "pushDescriptors", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/KHRPushDescriptor;vkCmdPushDescriptorSetKHR(Lorg/lwjgl/vulkan/VkCommandBuffer;IJILorg/lwjgl/vulkan/VkWriteDescriptorSet$Buffer;)V", shift = At.Shift.AFTER) ) - private void combatant$pushDescriptorsNativeAfter(CallbackInfo ci) { + private void lovisual$pushDescriptorsNativeAfter(CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.pushdescriptors.native.after"); } @Inject(method = "pushDescriptors", at = @At("TAIL")) - private void combatant$pushDescriptorsTail(CallbackInfo ci) { + private void lovisual$pushDescriptorsTail(CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbQuiet("renderpass.pushdescriptors.tail"); } @Inject(method = "drawIndexed", at = @At("HEAD")) - private void combatant$drawIndexedHead(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance, CallbackInfo ci) { + private void lovisual$drawIndexedHead(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbDraw("renderpass.drawindexed.head", "indices", indexCount, "instances", instanceCount, @@ -174,7 +174,7 @@ public abstract class VulkanRenderPassDiagnosticsMixin { method = "drawIndexed", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VK12;vkCmdDrawIndexed(Lorg/lwjgl/vulkan/VkCommandBuffer;IIIII)V", shift = At.Shift.BEFORE) ) - private void combatant$drawIndexedNativeBefore(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance, CallbackInfo ci) { + private void lovisual$drawIndexedNativeBefore(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbDraw("renderpass.drawindexed.native.before", "indices", indexCount); } @@ -182,12 +182,12 @@ public abstract class VulkanRenderPassDiagnosticsMixin { method = "drawIndexed", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VK12;vkCmdDrawIndexed(Lorg/lwjgl/vulkan/VkCommandBuffer;IIIII)V", shift = At.Shift.AFTER) ) - private void combatant$drawIndexedNativeAfter(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance, CallbackInfo ci) { + private void lovisual$drawIndexedNativeAfter(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbDraw("renderpass.drawindexed.native.after", "indices", indexCount); } @Inject(method = "draw", at = @At("HEAD")) - private void combatant$drawHead(int vertexCount, int instanceCount, int firstVertex, int firstInstance, CallbackInfo ci) { + private void lovisual$drawHead(int vertexCount, int instanceCount, int firstVertex, int firstInstance, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbDraw("renderpass.draw.head", "vertices", vertexCount, "instances", instanceCount, @@ -199,7 +199,7 @@ public abstract class VulkanRenderPassDiagnosticsMixin { method = "draw", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VK12;vkCmdDraw(Lorg/lwjgl/vulkan/VkCommandBuffer;IIII)V", shift = At.Shift.BEFORE) ) - private void combatant$drawNativeBefore(int vertexCount, int instanceCount, int firstVertex, int firstInstance, CallbackInfo ci) { + private void lovisual$drawNativeBefore(int vertexCount, int instanceCount, int firstVertex, int firstInstance, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbDraw("renderpass.draw.native.before", "vertices", vertexCount); } @@ -207,27 +207,27 @@ public abstract class VulkanRenderPassDiagnosticsMixin { method = "draw", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VK12;vkCmdDraw(Lorg/lwjgl/vulkan/VkCommandBuffer;IIII)V", shift = At.Shift.AFTER) ) - private void combatant$drawNativeAfter(int vertexCount, int instanceCount, int firstVertex, int firstInstance, CallbackInfo ci) { + private void lovisual$drawNativeAfter(int vertexCount, int instanceCount, int firstVertex, int firstInstance, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbDraw("renderpass.draw.native.after", "vertices", vertexCount); } @Inject(method = "multiDraw(Ljava/nio/IntBuffer;III)V", at = @At("HEAD")) - private void combatant$multiDrawHead(IntBuffer buffer, int firstInstance, int drawCount, int stride, CallbackInfo ci) { + private void lovisual$multiDrawHead(IntBuffer buffer, int firstInstance, int drawCount, int stride, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbDraw("renderpass.multidraw.head", "draws", drawCount, "stride", stride, "remaining", buffer == null ? -1 : buffer.remaining()); } @Inject(method = "multiDrawIndexed(Ljava/nio/IntBuffer;III)V", at = @At("HEAD")) - private void combatant$multiDrawIndexedHead(IntBuffer buffer, int firstInstance, int drawCount, int stride, CallbackInfo ci) { + private void lovisual$multiDrawIndexedHead(IntBuffer buffer, int firstInstance, int drawCount, int stride, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbDraw("renderpass.multidrawindexed.head", "draws", drawCount, "stride", stride, "remaining", buffer == null ? -1 : buffer.remaining()); } @Inject(method = "multiDrawIndexed(Lorg/lwjgl/PointerBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;I)V", at = @At("HEAD")) - private void combatant$multiDrawIndexedPointerHead(PointerBuffer firstIndex, IntBuffer indexCount, IntBuffer baseVertex, int drawCount, CallbackInfo ci) { + private void lovisual$multiDrawIndexedPointerHead(PointerBuffer firstIndex, IntBuffer indexCount, IntBuffer baseVertex, int drawCount, CallbackInfo ci) { VulkanCrashDiagnostics.breadcrumbDraw("renderpass.multidrawindexed.pointer.head", "draws", drawCount); } @Inject(method = "drawMultipleIndexed", at = @At("HEAD")) - private void combatant$drawMultipleIndexedHead(Collection> draws, + private void lovisual$drawMultipleIndexedHead(Collection> draws, GpuBuffer indexBuffer, IndexType indexType, Collection dynamicUniforms, diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanRenderPipelineDiagnosticsMixin.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanRenderPipelineDiagnosticsMixin.java index 3c79351..f33fda4 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanRenderPipelineDiagnosticsMixin.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/mixins/VulkanRenderPipelineDiagnosticsMixin.java @@ -20,7 +20,7 @@ public abstract class VulkanRenderPipelineDiagnosticsMixin { method = "compile", at = @At(value = "INVOKE", target = "Lorg/lwjgl/vulkan/VK12;vkCreateGraphicsPipelines(Lorg/lwjgl/vulkan/VkDevice;JLorg/lwjgl/vulkan/VkGraphicsPipelineCreateInfo$Buffer;Lorg/lwjgl/vulkan/VkAllocationCallbacks;Ljava/nio/LongBuffer;)I", ordinal = 0, shift = At.Shift.BEFORE) ) - private static void combatant$logPipelineCompile(VulkanDevice device, + private static void lovisual$logPipelineCompile(VulkanDevice device, VulkanBindGroupLayout layout, RenderPipeline pipeline, long vertexModule, diff --git a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/debug/VulkanCrashDiagnostics.java b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/debug/VulkanCrashDiagnostics.java index 826c138..2a1a2e5 100644 --- a/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/debug/VulkanCrashDiagnostics.java +++ b/combatant-client-26.2/src/vulkanDebug/java/dev/loki/lovisual/render/engine/rhi/backend/vulkan/debug/VulkanCrashDiagnostics.java @@ -26,18 +26,18 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** - * Opt-in Vulkan diagnostics. Compiled only when Gradle property combatantVulkanDebug=true is used. + * Opt-in Vulkan diagnostics. Compiled only when Gradle property lovisualVulkanDebug=true is used. */ public enum VulkanCrashDiagnostics { ; - public static final boolean FORCE_DRIVER_DEBUG = bool("combatant.vulkan.debug.forceDriverDebug", true); - public static final boolean VERBOSE_DRAW_EVENTS = bool("combatant.vulkan.debug.verboseDraw", false); - public static final long MAX_FILE_BYTES = longProp("combatant.vulkan.debug.maxBytes", 8L * 1024L * 1024L); - public static final int MAX_EVENT_LINES = intProp("combatant.vulkan.debug.maxEventLines", 256); + public static final boolean FORCE_DRIVER_DEBUG = bool("lovisual.vulkan.debug.forceDriverDebug", true); + public static final boolean VERBOSE_DRAW_EVENTS = bool("lovisual.vulkan.debug.verboseDraw", false); + public static final long MAX_FILE_BYTES = longProp("lovisual.vulkan.debug.maxBytes", 8L * 1024L * 1024L); + public static final int MAX_EVENT_LINES = intProp("lovisual.vulkan.debug.maxEventLines", 256); - private static final Logger LOGGER = LoggerFactory.getLogger("Combatant/VulkanDiag"); - private static final String DIAGNOSTIC_FILE_NAME = "combatant-vulkan-diagnostics.log"; + private static final Logger LOGGER = LoggerFactory.getLogger("LoVisual/VulkanDiag"); + private static final String DIAGNOSTIC_FILE_NAME = "lovisual-vulkan-diagnostics.log"; private static final Object FILE_LOCK = new Object(); private static final ConcurrentHashMap EVENT_COUNTS = new ConcurrentHashMap<>(); private static final AtomicLong WRITTEN_BYTES = new AtomicLong(); @@ -60,7 +60,7 @@ public enum VulkanCrashDiagnostics { "labelsForcedOff", VulkanRuntimeGuards.FORCE_DISABLE_VULKAN_DEBUG_LABELS, "validationOriginally", validationOriginally, "validationEnabled", validation); - LOGGER.warn("[Combatant/VulkanDiag] forcing Vulkan debug utils + validation layers: {}", forced); + LOGGER.warn("[LoVisual/VulkanDiag] forcing Vulkan debug utils + validation layers: {}", forced); return forced; } @@ -259,9 +259,9 @@ public enum VulkanCrashDiagnostics { Path parent = log.getParent(); if (parent != null) Files.createDirectories(parent); if (!headerWritten) { - String header = "=== Combatant Vulkan diagnostics ===\n" + + String header = "=== LoVisual Vulkan diagnostics ===\n" + "modId=simplefullbright\n" + - "entrypoint=dev.loki.lovisual.Combatant\n" + + "entrypoint=dev.loki.lovisual.LoVisual\n" + "path=" + log.toAbsolutePath() + '\n' + "stencil=runtime-failsafe-only" + '\n' + "msaa=config-and-capability-controlled" + '\n' + diff --git a/launcher/Cargo.lock b/launcher/Cargo.lock new file mode 100644 index 0000000..58d32f7 --- /dev/null +++ b/launcher/Cargo.lock @@ -0,0 +1,6855 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ab_glyph" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" + +[[package]] +name = "accesskit" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b7f7f85a7e5f68090000ed7622545829afd484d210358702ae4cb97dd0c320" +dependencies = [ + "uuid", +] + +[[package]] +name = "accesskit_atspi_common" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023da0e5097f46df7092d5280b02efb9bbf8d93298daeced42652463e357d636" +dependencies = [ + "accesskit", + "accesskit_consumer", + "atspi-common", + "phf", + "serde", + "zvariant", +] + +[[package]] +name = "accesskit_consumer" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d10a236f96f87d70732e44520046785431ef01d5bcd6b041317bfadd2f88245" +dependencies = [ + "accesskit", + "hashbrown 0.16.1", +] + +[[package]] +name = "accesskit_ios" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "750c4e9f6ce888dfe8a10c0f1b5ceb646a7854fd46579d74919219d1bb314083" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.16.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-ui-kit 0.2.2", +] + +[[package]] +name = "accesskit_macos" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce02dc63b43f0c9296af9ac946312a2dc8814427d7a64d2d600971dac55b6076" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.16.1", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "accesskit_unix" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e156ed3802e35eefe894ef2671bc6c889303d8a7e110b5e1b48f504b91362f" +dependencies = [ + "accesskit", + "accesskit_atspi_common", + "async-channel", + "async-executor", + "async-task", + "atspi", + "futures-lite", + "futures-util", + "serde", + "zbus", +] + +[[package]] +name = "accesskit_windows" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "106c2b961215864d1c2e703ee63269c25c4e80a577ffb2c1017b9c17dcdf83a1" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.16.1", + "static_assertions", + "windows", + "windows-core", +] + +[[package]] +name = "accesskit_winit" +version = "0.33.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5b41e63a69f36d9f1f41e70464c7e5f72eee485ef26aab19f0b4f86e6c0a84c" +dependencies = [ + "accesskit", + "accesskit_ios", + "accesskit_macos", + "accesskit_unix", + "accesskit_windows", + "raw-window-handle", + "winit", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "aligned" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" +dependencies = [ + "as-slice", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android-activity" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" +dependencies = [ + "android-properties", + "bitflags 2.13.1", + "cc", + "jni", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror 2.0.19", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "annotate-snippets" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f211a51805bc641f3ad5b7664c77d2547af685cc33b4cd8d31964027a46f13f1" +dependencies = [ + "anstyle", + "memchr", + "unicode-width", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix 1.1.4", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix 1.1.4", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "async-signal" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 1.1.4", + "signal-hook-registry", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atspi" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77886257be21c9cd89a4ae7e64860c6f0eefca799bb79127913052bd0eefb3d" +dependencies = [ + "atspi-common", + "atspi-proxies", +] + +[[package]] +name = "atspi-common" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c5617155740c98003016429ad13fe43ce7a77b007479350a9f8bf95a29f63d" +dependencies = [ + "enumflags2", + "serde", + "static_assertions", + "zbus", + "zbus-lockstep", + "zbus-lockstep-macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "atspi-proxies" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2230e48787ed3eb4088996eab66a32ca20c0b67bbd4fd6cdfe79f04f1f04c9fc" +dependencies = [ + "atspi-common", + "serde", + "zbus", +] + +[[package]] +name = "auto_enums" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3091d68264354f211516b91dce6f71046e444fab1867716035f736667243affb" +dependencies = [ + "derive_utils", + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "av-scenechange" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" +dependencies = [ + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey 0.1.1", + "rayon", + "thiserror 2.0.19", + "v_frame", + "y4m", +] + +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom 8.0.0", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "aws-lc-rs" +version = "1.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00bdb5da18dac48ca2cc7cd4a98e533e8635a58e2361d13a1a4ee3888e0d72f1" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43103168cc76fe62678a375e722fc9cb3a0146159ac5828bc4f0dfd755c2224c" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", + "pkg-config", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "serde", + "unty", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.13.1", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.3", + "shlex 1.3.0", + "syn 2.0.119", +] + +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bitstream-io" +version = "4.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f" +dependencies = [ + "no_std_io2", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2 0.6.4", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "borsh" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88b7ea17d208c4193f2c1e6de3c35fe71f98c96982d5ced308bdcc749ff6e1f" +dependencies = [ + "bytes", + "cfg_aliases", +] + +[[package]] +name = "built" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0e531d93d39c34eef561e929e8a7f86d77a5af08aac4f6d6e39976c51858e9" + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65693059b6b9c588b9f62fed1cedbf0a8b805631457ea162d68f0de186f3de5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.13.1", + "log", + "polling", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", +] + +[[package]] +name = "calloop" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" +dependencies = [ + "bitflags 2.13.1", + "polling", + "rustix 1.1.4", + "slab", + "tracing", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop 0.13.0", + "rustix 0.38.44", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" +dependencies = [ + "calloop 0.14.4", + "rustix 1.1.4", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "cc" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex 2.0.1", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clang-sys" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clipboard-win" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" +dependencies = [ + "error-code", +] + +[[package]] +name = "clru" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197fd99cb113a8d5d9b6376f3aa817f32c1078f2343b714fff7d2ca44fdf67d5" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-field-offset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9713489fbc45a2d113f58d17448c73115d533ed27fd2f2d0e5e5c69663eaf19b" +dependencies = [ + "const-field-offset-macro", + "field-offset", +] + +[[package]] +name = "const-field-offset-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b5dc851b7ea80cc4f69aa28632385ffd3e0f88014d53db3f2e5a781896ca783" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "copypasta" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e6811e17f81fe246ef2bc553f76b6ee6ab41a694845df1d37e52a92b7bbd38a" +dependencies = [ + "clipboard-win", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "smithay-clipboard", + "x11-clipboard", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "libc", +] + +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-channel" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "ctor" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83cf0d42651b16c6dfe68685716d18480d18a9c39c62d76e8cf3eb6ed5d8bcbf" +dependencies = [ + "dtor", +] + +[[package]] +name = "cursor-icon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" + +[[package]] +name = "data-url" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", + "unicode-xid", +] + +[[package]] +name = "derive_utils" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc05a5d33db20c784f873e84934ad94bb209a090987ac5f62fede2c178234f23" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "dlib" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" + +[[package]] +name = "drm" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" +dependencies = [ + "bitflags 2.13.1", + "bytemuck", + "drm-ffi", + "drm-fourcc", + "libc", + "rustix 0.38.44", +] + +[[package]] +name = "drm-ffi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51a91c9b32ac4e8105dec255e849e0d66e27d7c34d184364fb93e469db08f690" +dependencies = [ + "drm-sys", + "rustix 1.1.4", +] + +[[package]] +name = "drm-fourcc" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" + +[[package]] +name = "drm-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8e1361066d91f5ffccff060a3c3be9c3ecde15be2959c1937595f7a82a9f8" +dependencies = [ + "libc", + "linux-raw-sys 0.9.4", +] + +[[package]] +name = "dtor" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edf234dd1594d6dd434a8fb8cada51ddbbc593e40e4a01556a0b31c62da2775b" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" + +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "euclid" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" +dependencies = [ + "num-traits", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "exr" +version = "1.74.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711fe42c9964295e01ee3fba3f9fe0e1d24b98886950d68efe81b1c76e21adf3" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "num-complex", + "pulp", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "fax" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "femtovg" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43d05da42e81724c16d34a150fb7fda53d3f786e5a94673ee526ff8602f0f6a" +dependencies = [ + "bitflags 2.13.1", + "bytemuck", + "fnv", + "glow", + "imgref", + "itertools 0.14.0", + "log", + "rgb", + "slotmap", + "swash", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixed_decimal" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79c3c892f121fff406e5dd6b28c1b30096b95111c30701a899d4f2b18da6d1bd" +dependencies = [ + "displaydoc", + "smallvec", + "writeable", +] + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "font-types" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b38ad915f6dadd993ced50848a8291a543bd41ca62bc10740d5e64e2ab4cfd7" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "font-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a7299a780854a6d391be2ae1c8521c9368471b559dbfd6a8dbd9f407eaff100" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontdb" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" +dependencies = [ + "log", + "slotmap", + "tinyvec", + "ttf-parser", +] + +[[package]] +name = "fontique" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "274fa4f0f0a926ae182c7c076c078cce8a38471d15e61a102a02cac984be9813" +dependencies = [ + "hashbrown 0.17.1", + "linebender_resource_handle", + "memmap2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-text", + "objc2-foundation 0.3.2", + "parlance", + "read-fonts 0.39.2", + "roxmltree", + "smallvec", + "windows", + "windows-core", + "yeslogic-fontconfig-sys", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" + +[[package]] +name = "futures-executor" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "futures-sink" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" + +[[package]] +name = "futures-task" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" + +[[package]] +name = "futures-util" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gbm" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce852e998d3ca5e4a97014fb31c940dc5ef344ec7d364984525fd11e8a547e6a" +dependencies = [ + "bitflags 2.13.1", + "drm", + "drm-fourcc", + "gbm-sys", + "libc", +] + +[[package]] +name = "gbm-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13a5f2acc785d8fb6bf6b7ab6bfb0ef5dad4f4d97e8e70bb8e470722312f76f" +dependencies = [ + "libc", +] + +[[package]] +name = "gethostname" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +dependencies = [ + "rustix 1.1.4", + "windows-link", +] + +[[package]] +name = "getopts" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "glow" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29038e1c483364cc6bb3cf78feee1816002e127c331a1eec55a4d202b9e1adb5" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12124de845cacfebedff80e877bb37b5b75c34c5a4c89e47e1cdd67fb6041325" +dependencies = [ + "bitflags 2.13.1", + "cfg_aliases", + "cgl", + "dispatch2", + "glutin_egl_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "libloading", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "once_cell", + "raw-window-handle", + "wayland-sys", + "windows-sys 0.52.0", + "x11-dl", +] + +[[package]] +name = "glutin-winit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85edca7075f8fc728f28cb8fbb111a96c3b89e930574369e3e9c27eb75d3788f" +dependencies = [ + "cfg_aliases", + "glutin", + "raw-window-handle", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4680ba6195f424febdc3ba46e7a42a0e58743f2edb115297b86d7f8ecc02d2" +dependencies = [ + "gl_generator", + "windows-sys 0.52.0", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7bb2938045a88b612499fbcba375a77198e01306f52272e692f8c1f3751185" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "grid" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b40ca9252762c466af32d0b1002e91e4e1bc5398f77455e55474deb466355ff5" + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "harfrust" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d12c7c642d4ce8c2e784b4751a6634bd89583912265add4a679a8882d123fbcd" +dependencies = [ + "bitflags 2.13.1", + "bytemuck", + "read-fonts 0.39.2", + "smallvec", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "htmlparser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ce8546b993eaf241d69ded33b1be6d205dd9857ec879d9d18bd05d3676e144" + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "i-slint-backend-linuxkms" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68e76f2b13846ca54bba6b8eb3b5454b26879ad987396d0a2d8abedc31a6c469" +dependencies = [ + "bytemuck", + "calloop 0.14.4", + "cfg_aliases", + "drm", + "gbm", + "glutin", + "i-slint-common", + "i-slint-core", + "i-slint-renderer-femtovg", + "i-slint-renderer-software", + "input", + "memmap2", + "nix", + "raw-window-handle", + "xkbcommon", +] + +[[package]] +name = "i-slint-backend-selector" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2247a4590a02a466b2f4916cc789dfe66247f6af826f00eb84a2685259a45c1c" +dependencies = [ + "cfg-if", + "cfg_aliases", + "i-slint-backend-linuxkms", + "i-slint-backend-testing", + "i-slint-backend-winit", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "i-slint-renderer-femtovg", +] + +[[package]] +name = "i-slint-backend-testing" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521e901e3d47ab829c0ef500c63155776208707cd93259e6a7803ed627fa2786" +dependencies = [ + "cfg_aliases", + "i-slint-common", + "i-slint-core", + "i-slint-renderer-software", + "vtable", +] + +[[package]] +name = "i-slint-backend-winit" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27c7e8f53418d3017362465367b6612b6e439a68097d627d1b91c94b885f0a6" +dependencies = [ + "accesskit", + "accesskit_winit", + "block2 0.6.2", + "bytemuck", + "cfg-if", + "cfg_aliases", + "copypasta", + "derive_more", + "futures", + "glutin", + "glutin-winit", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "i-slint-renderer-femtovg", + "i-slint-renderer-skia", + "i-slint-renderer-software", + "imgref", + "lyon_path", + "muda", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", + "objc2-ui-kit 0.3.2", + "pin-weak", + "raw-window-handle", + "rgb", + "scoped-tls-hkt", + "scopeguard", + "softbuffer", + "strum", + "vtable", + "wasm-bindgen", + "web-sys", + "webbrowser", + "windows", + "winit", + "zbus", +] + +[[package]] +name = "i-slint-common" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e63f8ea55ba21e44567ae67d2b01a4f5d09bb1fab693b1e6c79d96bef9e456" +dependencies = [ + "derive_more", + "fontique", + "htmlparser", + "icu_decimal", + "icu_locale_core", + "icu_provider", + "pulldown-cmark", + "resvg", + "skrifa 0.42.1", +] + +[[package]] +name = "i-slint-compiler" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ea275b15a425c7f2f77481151e1f5f8f1ea83feae580273090ef6b9e192218" +dependencies = [ + "annotate-snippets", + "by_address", + "data-url", + "derive_more", + "i-slint-common", + "icu_normalizer", + "image", + "itertools 0.14.0", + "linked_hash_set", + "lyon_extra", + "lyon_path", + "num_enum", + "proc-macro2", + "quote", + "rayon", + "resvg", + "rowan", + "rspolib", + "skrifa 0.42.1", + "smol_str 0.3.6", + "strum", + "swash", + "typed-index-collections", + "unicode-segmentation", + "url", +] + +[[package]] +name = "i-slint-core" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e407dc2bd5385dcbdd9c1cf927213d2e4bacda667545abf8839c60f8290f754" +dependencies = [ + "async-channel", + "auto_enums", + "bitflags 2.13.1", + "cfg-if", + "chrono", + "clru", + "const-field-offset", + "derive_more", + "euclid", + "i-slint-common", + "i-slint-core-macros", + "icu_normalizer", + "image", + "ksni", + "lyon_algorithms", + "lyon_extra", + "lyon_geom", + "lyon_path", + "num-traits", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", + "once_cell", + "parley", + "pin-project", + "pin-weak", + "portable-atomic", + "raw-window-handle", + "resvg", + "rgb", + "scopeguard", + "skrifa 0.42.1", + "slab", + "strum", + "swash", + "sys-locale", + "taffy", + "unicode-linebreak", + "unicode-script", + "unicode-segmentation", + "vtable", + "wasm-bindgen", + "web-sys", + "web-time", + "windows", +] + +[[package]] +name = "i-slint-core-macros" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a842640da4c4d0909d25cc5a51e1f9cde02bd48f7fdfa94df10d595d4e3c80a" +dependencies = [ + "quote", + "serde_json", + "syn 2.0.119", +] + +[[package]] +name = "i-slint-renderer-femtovg" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78d0d99a18d66738b684758fe8460743a0aa0f64a96e05940942231a340085b1" +dependencies = [ + "cfg-if", + "const-field-offset", + "derive_more", + "femtovg", + "glow", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "imgref", + "lyon_path", + "pin-weak", + "rgb", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "i-slint-renderer-skia" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b6eed7f3f0a9a3d3ca6e8b9d4ca233371d989351fdb2a7ab88ec368b99e7b57" +dependencies = [ + "bytemuck", + "cfg-if", + "cfg_aliases", + "clru", + "const-field-offset", + "derive_more", + "glow", + "glutin", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "lyon_path", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", + "objc2-quartz-core 0.3.2", + "pin-weak", + "raw-window-handle", + "raw-window-metal", + "read-fonts 0.39.2", + "scoped-tls-hkt", + "skia-safe", + "softbuffer", + "unicode-segmentation", + "vtable", + "windows", + "write-fonts", +] + +[[package]] +name = "i-slint-renderer-software" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73496f164f8e471877c35e0fadb996dcc674922712abd9c2be2cbe80c58859bd" +dependencies = [ + "bytemuck", + "clru", + "derive_more", + "euclid", + "i-slint-common", + "i-slint-core", + "integer-sqrt", + "lyon_path", + "num-traits", + "skrifa 0.42.1", + "swash", + "zeno", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_decimal" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "288247df2e32aa776ac54fdd64de552149ac43cb840f2761811f0e8d09719dd4" +dependencies = [ + "displaydoc", + "fixed_decimal", + "icu_decimal_data", + "icu_locale", + "icu_locale_core", + "icu_plurals", + "icu_provider", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_decimal_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f14a5ca9e8af29eef62064f269078424283d90dbaffeac5225addf62aaabc22" + +[[package]] +name = "icu_locale" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a396343c7208121dc86e35623d3dfe19814a7613cfd14964994cdc9c9a2e26" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locale_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fdcc9ac77c6d74ff5cf6e65ef3181d6af32003b16fce3a77fb451d2f695993" + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_plurals" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a50023f1d49ad5c4333380328a0d4a19e4b9d6d842ec06639affd5ba47c8103" +dependencies = [ + "fixed_decimal", + "icu_locale", + "icu_plurals_data", + "icu_provider", + "zerovec", +] + +[[package]] +name = "icu_plurals_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8485497155dc865f901decb93ecc20d3e467df67bfeceb91e3ba34e2b11e8e1d" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_segmenter" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0794db0b1a86193ac9c48768d0e6c52c54448e0870ad87907d456ee0dac964" +dependencies = [ + "icu_collections", + "icu_locale", + "icu_provider", + "icu_segmenter_data", + "potential_utf", + "utf8_iter", + "zerovec", +] + +[[package]] +name = "icu_segmenter_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a2c462a4d927d512f5f882a033ddd62f33a05bb9f230d98f736ac3dc85938f" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imagesize" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" + +[[package]] +name = "imgref" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89194689a993ab15268672e99e7b0e19da2da3268ac682e8f02d29d4d1434cd7" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "input" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9793345a65d71317763a33066b5d8351f8760dde8d4930fe9e39b5f14a7959d" +dependencies = [ + "bitflags 2.13.1", + "input-sys", + "libc", + "log", + "udev", +] + +[[package]] +name = "input-sys" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eee07d8e02bd95bf52b2e642cf13d33701b94c6e4b04fbf1d1fb07e9cb19e7" + +[[package]] +name = "integer-sqrt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" +dependencies = [ + "num-traits", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.19", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.13.1", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "ksni" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "814b44c24cd2cb236c3b8a41c7f08237b452a8e76ecaa81f1cec40b5b678215b" +dependencies = [ + "async-executor", + "async-io", + "async-lock", + "futures-channel", + "futures-lite", + "futures-util", + "pastey 0.2.3", + "serde", + "task-local", + "zbus", +] + +[[package]] +name = "kurbo" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2" +dependencies = [ + "arrayvec", + "euclid", + "polycool", + "smallvec", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lebe" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +dependencies = [ + "bitflags 2.13.1", + "libc", + "plain", + "redox_syscall 0.9.1", +] + +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "linebender_resource_handle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linked_hash_set" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "lovisual-launcher" +version = "0.1.0" +dependencies = [ + "anyhow", + "dirs", + "reqwest", + "serde", + "serde_json", + "slint", + "slint-build", + "tokio", +] + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "lyon_algorithms" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8575c0d003ae459399623c4def180c63b77f343b1a7fee64f249b349e7699a31" +dependencies = [ + "lyon_path", + "num-traits", +] + +[[package]] +name = "lyon_extra" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7755f08423275157ad1680aaecc9ccb7e0cc633da3240fea2d1522935cc15c72" +dependencies = [ + "lyon_path", + "thiserror 2.0.19", +] + +[[package]] +name = "lyon_geom" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4336502e29e32af93cf2dad2214ed6003c17ceb5bd499df77b1de663b9042b92" +dependencies = [ + "arrayvec", + "euclid", + "num-traits", +] + +[[package]] +name = "lyon_path" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c463f9c428b7fc5ec885dcd39ce4aa61e29111d0e33483f6f98c74e89d8621e" +dependencies = [ + "lyon_geom", + "num-traits", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "muda" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878" +dependencies = [ + "crossbeam-channel", + "dpi", + "keyboard-types", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "once_cell", + "png", + "thiserror 2.0.19", + "windows-sys 0.61.2", +] + +[[package]] +name = "natord" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c" + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.13.1", + "jni-sys 0.3.1", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.13.1", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "no_std_io2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418abd1b6d34fbf6cae440dc874771b0525a604428704c76e48b29a5e67b8003" +dependencies = [ + "memchr", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "bytemuck", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data 0.2.2", + "objc2-core-image 0.2.2", + "objc2-foundation 0.2.2", + "objc2-quartz-core 0.2.2", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.13.1", + "block2 0.6.2", + "libc", + "objc2 0.6.4", + "objc2-cloud-kit 0.3.2", + "objc2-core-data 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image 0.3.2", + "objc2-core-text", + "objc2-core-video", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.1", + "dispatch2", + "objc2 0.6.4", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.13.1", + "dispatch2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-contacts", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-core-video" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-io-surface", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "dispatch", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.13.1", + "block2 0.6.2", + "objc2 0.6.4", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-metal" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.13.1", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-cloud-kit 0.2.2", + "objc2-core-data 0.2.2", + "objc2-core-image 0.2.2", + "objc2-core-location", + "objc2-foundation 0.2.2", + "objc2-link-presentation", + "objc2-quartz-core 0.2.2", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.13.1", + "block2 0.6.2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.13.1", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +dependencies = [ + "critical-section", + "portable-atomic", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "orbclient" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" +dependencies = [ + "libc", + "libredox", +] + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "parlance" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6937eda350acc1a5d05872c3cbf99fe78619c269096e2be3d4a350058639d5" + +[[package]] +name = "parley" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1cfcf399c774719fb1fa51bc6b91e86bdf003b03202a0902f1827ba6750746" +dependencies = [ + "fontique", + "harfrust", + "hashbrown 0.17.1", + "icu_normalizer", + "icu_properties", + "icu_segmenter", + "linebender_resource_handle", + "parlance", + "parley_data", + "skrifa 0.42.1", +] + +[[package]] +name = "parley_data" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1d3755e2cc12c0625b0cd2f2773c6a37dd11d1531940c945ade4aeb78f2b145" +dependencies = [ + "icu_properties", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + +[[package]] +name = "pastey" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pin-weak" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b330c9d1b92dfe68442ca20b009c717d5f0b1e3cf4965e62f704c3c6e95a1305" + +[[package]] +name = "piper" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.1", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.5.2", + "pin-project-lite", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "polycool" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "portable-atomic" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" +dependencies = [ + "critical-section", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pulldown-cmark" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e" +dependencies = [ + "bitflags 2.13.1", + "getopts", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + +[[package]] +name = "pulldown-cmark-escape" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" + +[[package]] +name = "pulp" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046aa45b989642ec2e4717c8e72d677b13edd831a4d3b6cf37d9a3e54912496a" +dependencies = [ + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "paste", + "pulp-wasm-simd-flag", + "raw-cpuid", + "reborrow", + "version_check", +] + +[[package]] +name = "pulp-wasm-simd-flag" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8f70e07b9c3962945a74e59ca1c511bba65b6419468acc217c457d93f3c740" + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.3", + "rustls", + "socket2", + "thiserror 2.0.19", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.2", + "rand_pcg", + "ring", + "rustc-hash 2.1.3", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.19", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + +[[package]] +name = "rav1e" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" +dependencies = [ + "aligned-vec", + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av-scenechange", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.14.0", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "paste", + "profiling", + "rand 0.9.5", + "rand_chacha", + "simd_helpers", + "thiserror 2.0.19", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "raw-window-metal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" +dependencies = [ + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", +] + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "read-fonts" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4ed38b89c2c77ff968c524145ad65fb010f38af5c7a224b53b81d47ac2daa81" +dependencies = [ + "bytemuck", + "font-types 0.11.3", +] + +[[package]] +name = "read-fonts" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046a7d674daf459825b32f5062056d6882db0d2f5a479fbd76ccfc870ac18709" +dependencies = [ + "bytemuck", + "font-types 0.12.2", + "once_cell", +] + +[[package]] +name = "reborrow" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "redox_syscall" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07507be7b4a5f9f26eeb41eeaebb1f5a7ff29dfb29739facc21d35bf8b11c21e" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.19", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +dependencies = [ + "base64", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "resvg" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be183ad6a216aa96f33e4c8033b0988b8b3ea6fd2359d19af5bac4643fd8e81" +dependencies = [ + "gif", + "image-webp", + "log", + "pico-args", + "rgb", + "svgtypes", + "tiny-skia 0.12.0", + "usvg", + "zune-jpeg", +] + +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rowan" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21" +dependencies = [ + "countme", + "hashbrown 0.14.5", + "rustc-hash 1.1.0", + "text-size", +] + +[[package]] +name = "roxmltree" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" +dependencies = [ + "memchr", +] + +[[package]] +name = "rspolib" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fda9a7796aff63a7b1b39ccc93fffaaf65e20042984b4843041a49ca4677535" +dependencies = [ + "lazy_static", + "natord", + "snafu", + "unicode-linebreak", + "unicode-width", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.13.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.1", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "rustybuzz" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" +dependencies = [ + "bitflags 2.13.1", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scoped-tls-hkt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9603871ffe5df3ac39cb624790c296dbd47a400d202f56bf3e414045099524d" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sctk-adwaita" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit 0.19.2", + "tiny-skia 0.11.4", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.13.1", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "skia-bindings" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2d1c3ebd697c0cbded0145e9204a38fa6b268446051b7196d0a096414ea7f3" +dependencies = [ + "bindgen", + "cc", + "flate2", + "heck", + "pkg-config", + "regex", + "serde_json", + "tar", + "toml", +] + +[[package]] +name = "skia-safe" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f512ac418a64194842dd05566320805dad1c957c521039db2486fd6368865bc" +dependencies = [ + "bitflags 2.13.1", + "skia-bindings", + "windows", +] + +[[package]] +name = "skrifa" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c34617370ae968efb7161bb2beb517d9084659aae19e24b89e3db25b46e4564" +dependencies = [ + "bytemuck", + "read-fonts 0.39.2", +] + +[[package]] +name = "skrifa" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819ab7d62b1d3e72d9d9dea5650bac30424f9111364bb94928dbf5ecad1baa68" +dependencies = [ + "bytemuck", + "read-fonts 0.41.0", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slint" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce12038f57f8f3a423564b0c9301a2ab3fda4246e4cbadd6b97acf9124bdc315" +dependencies = [ + "const-field-offset", + "i-slint-backend-selector", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "i-slint-renderer-femtovg", + "i-slint-renderer-software", + "num-traits", + "once_cell", + "pin-weak", + "slint-macros", + "unicode-segmentation", + "vtable", +] + +[[package]] +name = "slint-build" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76684c11441f775b10bbc7b0e6b3016a39f17efdd659ffca112f17cfd6bdaed1" +dependencies = [ + "derive_more", + "fontique", + "i-slint-compiler", + "spin_on", + "toml_edit", +] + +[[package]] +name = "slint-macros" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2a763e72e1e53c496f571d36327e777da1eb0d9e58fceb83890c2a83ee7223" +dependencies = [ + "i-slint-compiler", + "proc-macro2", + "quote", + "spin_on", +] + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.13.1", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 0.38.44", + "thiserror 1.0.69", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-client-toolkit" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" +dependencies = [ + "bitflags 2.13.1", + "calloop 0.14.4", + "calloop-wayland-source 0.4.1", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 1.1.4", + "thiserror 2.0.19", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-experimental", + "wayland-protocols-misc", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-clipboard" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226" +dependencies = [ + "libc", + "smithay-client-toolkit 0.20.0", + "wayland-backend", +] + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "smol_str" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523" +dependencies = [ + "borsh", + "serde_core", +] + +[[package]] +name = "snafu" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "softbuffer" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" +dependencies = [ + "as-raw-xcb-connection", + "bytemuck", + "fastrand", + "js-sys", + "memmap2", + "ndk", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", + "raw-window-handle", + "redox_syscall 0.5.18", + "rustix 1.1.4", + "tiny-xlib", + "tracing", + "wasm-bindgen", + "wayland-backend", + "wayland-client", + "wayland-sys", + "web-sys", + "windows-sys 0.61.2", + "x11rb", +] + +[[package]] +name = "spin_on" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076e103ed41b9864aa838287efe5f4e3a7a0362dd00671ae62a212e5e4612da2" +dependencies = [ + "pin-utils", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + +[[package]] +name = "strum" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "svgtypes" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d" +dependencies = [ + "kurbo", + "siphasher", +] + +[[package]] +name = "swash" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2499c2d826531388872b2268718aed907a39bd785ab0dcfe57fab26283f92e" +dependencies = [ + "skrifa 0.44.0", + "yazi", + "zeno", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "sys-locale" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" +dependencies = [ + "js-sys", + "libc", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "taffy" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aea22054047c16c3f34d3ac473a2170be1424b1115b2a3adcf28cfb067c88859" +dependencies = [ + "arrayvec", + "grid", + "serde", + "slotmap", +] + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "task-local" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2972044a9e5e448a506a7ff6f0d03b566d8ef4cd6918a58fc59835a0f8666626" +dependencies = [ + "pin-project-lite", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "text-size" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" +dependencies = [ + "thiserror-impl 2.0.19", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "tiny-skia-path 0.11.4", +] + +[[package]] +name = "tiny-skia" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47ffee5eaaf5527f630fb0e356b90ebdec84d5d18d937c5e440350f88c5a91ea" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path 0.12.0", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tiny-skia-path" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tiny-xlib" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90a0ca3ee6a69f2ad28fd11621a4c3f03b371f366be500b64df260c4ffbafb4" +dependencies = [ + "as-raw-xcb-connection", + "ctor", + "libloading", + "pkg-config", + "tracing", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "serde_core", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "toml" +version = "1.1.4+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.13+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.13.1", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +dependencies = [ + "core_maths", +] + +[[package]] +name = "typed-index-collections" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "898160f1dfd383b4e92e17f0512a7d62f3c51c44937b23b6ffc3a1614a8eaccd" +dependencies = [ + "bincode", + "serde", +] + +[[package]] +name = "udev" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4e37e9ea4401fc841ff54b9ddfc9be1079b1e89434c1a6a865dd68980f7e9f" +dependencies = [ + "io-lifetimes", + "libc", + "libudev-sys", + "pkg-config", +] + +[[package]] +name = "uds_windows" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" +dependencies = [ + "memoffset", + "tempfile", + "windows-sys 0.61.2", +] + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" + +[[package]] +name = "unicode-ccc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-script" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "usvg" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d46cf96c5f498d36b7a9693bc6a7075c0bb9303189d61b2249b0dc3d309c07de" +dependencies = [ + "base64", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree", + "rustybuzz", + "simplecss", + "siphasher", + "strict-num", + "svgtypes", + "tiny-skia-path 0.12.0", + "ttf-parser", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" +dependencies = [ + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vtable" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea953f65593feb5287b022b83c35046d1ff49c7417b6f5851a079d8a231fe31" +dependencies = [ + "const-field-offset", + "portable-atomic", + "stable_deref_trait", + "vtable-macro", +] + +[[package]] +name = "vtable-macro" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "482a37f9777480673d3a99c80ac2edc69f92382230440946855fa27ebc47cba6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wayland-backend" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016ccf01d1c58b6f8999612813e17c9b2390f7d70671428869913310f83f54b8" +dependencies = [ + "cc", + "downcast-rs", + "rustix 1.1.4", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073" +dependencies = [ + "bitflags 2.13.1", + "rustix 1.1.4", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.13.1", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d" +dependencies = [ + "rustix 1.1.4", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-experimental" +version = "20250721.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-misc" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" +dependencies = [ + "bitflags 2.13.1", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338e30461b3a2b67d70eb30a6d89f8e0c93a833e07d2ae89085cd070c4a00ac0" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef62a3d5f7b2411119a11b6f62570dbff91d7105e011a20fb83fbf8f5761c40f" +dependencies = [ + "jni", + "log", + "ndk-context", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", + "url", + "web-sys", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winit" +version = "0.30.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.13.1", + "block2 0.5.1", + "bytemuck", + "calloop 0.13.0", + "cfg_aliases", + "concurrent-queue", + "core-foundation 0.9.4", + "core-graphics", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "memmap2", + "ndk", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "objc2-ui-kit 0.2.2", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix 0.38.44", + "sctk-adwaita", + "smithay-client-toolkit 0.19.2", + "smol_str 0.2.2", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "write-fonts" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb731d4c4d93eacc69a1ad2f270f905788a98e4a3438267bcafbe08d3431c8d8" +dependencies = [ + "font-types 0.11.3", + "indexmap", + "kurbo", + "log", + "read-fonts 0.39.2", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "x11-clipboard" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662d74b3d77e396b8e5beb00b9cad6a9eccf40b2ef68cc858784b14c41d535a3" +dependencies = [ + "libc", + "x11rb", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading", + "once_cell", + "rustix 1.1.4", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix 1.1.4", +] + +[[package]] +name = "xcursor" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "163b33ed8786455e2fa5d72f554057ce3f3182425434f756cd39c99839d88e23" + +[[package]] +name = "xkbcommon" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a974f48060a14e95705c01f24ad9c3345022f4d97441b8a36beb7ed5c4a02d" +dependencies = [ + "libc", + "memmap2", + "xkeysym", +] + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.13.1", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xml-rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "y4m" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" + +[[package]] +name = "yazi" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" + +[[package]] +name = "yeslogic-fontconfig-sys" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8b8abf912b9a29ff112e1671c97c33636903d13a69712037190e6805af4f76" +dependencies = [ + "dlib", + "once_cell", + "pkg-config", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zbus" +version = "5.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe18fb60dc696039e738717b76eaea21e7a4489bbb1885020b43c94236d7e98a" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "libc", + "ordered-stream", + "rustix 1.1.4", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "uuid", + "windows-sys 0.61.2", + "winnow", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus-lockstep" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6998de05217a084b7578728a9443d04ea4cd80f2a0839b8d78770b76ccd45863" +dependencies = [ + "zbus_xml", + "zvariant", +] + +[[package]] +name = "zbus-lockstep-macros" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10da05367f3a7b7553c8cdf8fa91aee6b64afebe32b51c95177957efc47ca3a0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "zbus-lockstep", + "zbus_xml", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe96480bed92df2b442a1a30df364e12d08eed03aeb061f2b8dc6afb2be91119" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e" +dependencies = [ + "serde", + "winnow", + "zvariant", +] + +[[package]] +name = "zbus_xml" +version = "5.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1586c021a01ca0a9216dcd874e546382e156a5cbab5fab6cb5f10087e22682a" +dependencies = [ + "serde", + "winnow", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zeno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" + +[[package]] +name = "zerocopy" +version = "0.8.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] + +[[package]] +name = "zvariant" +version = "5.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee2a0bcd2a907786a456fff45aaaaf54c9ba5f50b71ae9ec1a4edd200c94911" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38a708216a18780796770bfe3f4739c7c83a3e8f789b755534bbbc06e4e23e12" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90cb9383f9b45290407a1258b202d3f8f01db719eb60b4e4055c6375af4fc7c7" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.119", + "winnow", +] diff --git a/launcher/Cargo.toml b/launcher/Cargo.toml new file mode 100644 index 0000000..92b4576 --- /dev/null +++ b/launcher/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "lovisual-launcher" +version = "0.1.0" +edition = "2024" +rust-version = "1.85" +description = "LoVisual launcher: login, dashboard, Minecraft launch" +license = "GPL-3.0" + +[dependencies] +slint = "1.17" +tokio = { version = "1.53", features = ["full"] } +reqwest = { version = "0.13", features = ["json", "rustls"], default-features = false } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +anyhow = "1" +dirs = "6" + +[build-dependencies] +slint-build = "1.17" + +[lints.rust] +dead_code = "deny" + +[lints.clippy] +correctness = "deny" +suspicious = "deny" +style = "deny" +complexity = "deny" +perf = "deny" + +[profile.release] +opt-level = 3 +lto = "fat" +codegen-units = 1 +panic = "abort" +strip = true diff --git a/launcher/TODO.md b/launcher/TODO.md new file mode 100644 index 0000000..8539b7a --- /dev/null +++ b/launcher/TODO.md @@ -0,0 +1,37 @@ +# LoVisual Launcher (Rust + Slint) + +## Правила (ОБЯЗАТЕЛЬНЫЕ, нарушение = откат) +- **KISS / DRY / SOLID** — простая структура, без оверинжиниринга +- **Макс. 200 строк на файл** — превышение = разбить на модули +- **Макс. 3 файла на папку** — больше = новая подпапка по смыслу +- **Обязательное прохождение:** `cargo fmt` + `cargo clippy --all-targets` (ноль ошибок) + `cargo test` +- **Запрещено `#[allow(dead_code)]`** — мёртвый код удаляется, не прячется +- **unsafe запрещён в нашем коде** (сгенерированный Slint-код — исключение, его не трогаем) +- **Без пустышек** — модуль создаётся только с рабочей реализацией +- **Каждый этап компилируется** — перед переходом к следующему + +--- + +## Сделано +- [x] Каркас: main.rs + api/ (health check в фоне) +- [x] Окно логина (Slint): логин/пароль/статус +- [x] Rust 2024 edition, актуальные версии пакетов +- [x] Фоновая проверка `/health` бэкенда, статус в UI + +--- + +## Фаза 1: API клиент (`src/api/`) +- [ ] `auth.rs` — login/register (reqwest, таймауты, rename_all) +- [ ] `profile.rs` — get/update/playtime/version check +- [ ] Версия лаунчера читается из Cargo.toml (не хардкод) + +## Фаза 2: Экраны (Slint) +- [ ] login — реальный логин/регистрация через backend +- [ ] dashboard — профиль, playtime, version check +- [ ] settings — кастомная команда запуска (ЧИТАЕТСЯ на Play, не stale) + +## Фаза 3: Launch +- [ ] `src/launch/mod.rs` — запуск Minecraft (команда из настроек, защита от пустой строки) +- [ ] `src/session/mod.rs` — save_session только при логине, удалять при logout + +### Проверка после каждой фазы: `cargo fmt && cargo clippy --all-targets && cargo test` diff --git a/launcher/build.rs b/launcher/build.rs new file mode 100644 index 0000000..af79a75 --- /dev/null +++ b/launcher/build.rs @@ -0,0 +1,3 @@ +fn main() { + slint_build::compile("ui/main.slint").expect("failed to compile slint ui"); +} diff --git a/launcher/src/api/mod.rs b/launcher/src/api/mod.rs new file mode 100644 index 0000000..3122623 --- /dev/null +++ b/launcher/src/api/mod.rs @@ -0,0 +1,35 @@ +//! Minimal client for the LoVisual backend API. + +use anyhow::Context as _; +use serde::Deserialize; + +/// Default backend base URL for local development. +pub const DEFAULT_API_URL: &str = "http://127.0.0.1:8765"; + +/// Health response from `GET /health`. +#[derive(Debug, Deserialize)] +pub struct Health { + pub status: String, + pub version: String, +} + +/// Fetch backend health status. +pub async fn health(base_url: &str) -> anyhow::Result { + let client = reqwest::Client::builder() + .timeout(std::time::Duration::from_secs(5)) + .build() + .context("failed to build http client")?; + + let url = format!("{}/health", base_url.trim_end_matches('/')); + let response = client + .get(&url) + .send() + .await + .context("health request failed")?; + response + .error_for_status() + .context("health returned error status")? + .json() + .await + .context("invalid health response") +} diff --git a/launcher/src/main.rs b/launcher/src/main.rs new file mode 100644 index 0000000..d8e3ba6 --- /dev/null +++ b/launcher/src/main.rs @@ -0,0 +1,52 @@ +//! LoVisual launcher entry point. + +mod api; + +slint::include_modules!(); + +use slint::ComponentHandle; + +fn main() -> Result<(), slint::PlatformError> { + let ui = MainWindow::new()?; + + spawn_backend_status_check(ui.as_weak()); + + let weak = ui.as_weak(); + ui.on_login(move || { + let ui = weak.unwrap(); + let login = ui.get_login_input().trim().to_string(); + let password = ui.get_password_input().trim().to_string(); + + if login.is_empty() || password.is_empty() { + ui.set_status("Заполните логин и пароль".into()); + return; + } + + // TODO: auth against backend, save session, transition to dashboard. + ui.set_status(format!("Вход выполнен как {login}").into()); + }); + + ui.run() +} + +/// Ping backend health in background and surface the result in the UI. +fn spawn_backend_status_check(weak: slint::Weak) { + std::thread::spawn(move || { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .expect("failed to build tokio runtime"); + + let status = runtime.block_on(api::health(api::DEFAULT_API_URL)); + let message = match status { + Ok(health) => format!("Backend v{}: {}", health.version, health.status), + Err(error) => format!("Backend недоступен: {error}"), + }; + + let _ = slint::invoke_from_event_loop(move || { + if let Some(ui) = weak.upgrade() { + ui.set_status(message.clone().into()); + } + }); + }); +} diff --git a/launcher/ui/main.slint b/launcher/ui/main.slint new file mode 100644 index 0000000..7d238bb --- /dev/null +++ b/launcher/ui/main.slint @@ -0,0 +1,63 @@ +import { VerticalBox, LineEdit, Button } from "std-widgets.slint"; + +export component MainWindow inherits Window { + title: "LoVisual Launcher"; + width: 480px; + height: 320px; + + in-out property status: "Disconnected"; + + VerticalBox { + spacing: 12px; + padding: 24px; + + Text { + text: "LoVisual Launcher"; + font-size: 28px; + font-weight: 700; + horizontal-alignment: center; + color: #00bfff; + } + + Text { + text: "Войдите в аккаунт, чтобы запустить Minecraft"; + font-size: 13px; + horizontal-alignment: center; + color: #9aa0a6; + } + + VerticalBox { + spacing: 8px; + + Text { text: "Логин"; } + LineEdit { + text <=> login-input; + placeholder-text: "username or email"; + } + + Text { text: "Пароль"; } + LineEdit { + text <=> password-input; + input-type: InputType.password; + placeholder-text: "••••••••"; + } + } + + Button { + text: "Войти"; + primary: true; + clicked => root.login(); + } + + Text { + text: status; + horizontal-alignment: center; + color: #ff6b6b; + font-size: 12px; + } + } + + callback login(); + in-out property login-input: ""; + in-out property password-input: ""; +}