From 0042590aa6b47da9b3656d016c8ff39df2c253d2 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 02:57:35 -0500 Subject: [PATCH] Move many mods to Deprecated folder, fix spelling --- .../AASBufferFix/AASBufferFix.csproj | 0 .../AASBufferFix/AASBufferHelper.cs | 0 .../AASBufferFix/HarmonyPatches.cs | 0 .../AASBufferFix/Main.cs | 0 .../AASBufferFix/Properties/AssemblyInfo.cs | 0 .../AASBufferFix/README.md | 0 .../AASBufferFix/Utils.cs | 0 .../AASBufferFix/format.json | 0 .../AASDefaultProfileFix.csproj | 0 .../AASDefaultProfileFix}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../AASDefaultProfileFix}/README.md | 0 .../AASDefaultProfileFix}/format.json | 0 .../AlternateIKSystem.csproj | 0 .../AlternateIKSystem/HarmonyPatches.cs | 0 .../AlternateIKSystem/IK/BodyControl.cs | 0 .../AlternateIKSystem/IK/IKCalibrator.cs | 0 .../IK/IKHandlers/IKHandler.cs | 0 .../IK/IKHandlers/IKHandlerDesktop.cs | 0 .../IK/IKHandlers/IKHandlerHalfBody.cs | 0 .../AlternateIKSystem/IK/IKManager.cs | 0 .../AlternateIKSystem/IK/MusclePoses.cs | 0 .../IK/Tracking/SteamVRTrackerManager.cs | 0 .../IK/VRIKHelpers/VRIKLocomotionData.cs | 0 .../IK/VRIKHelpers/VRIKUtils.cs | 0 .../WeightManipulators/BodyParts/BodyPart.cs | 0 .../DeviceControlManipulator.cs | 0 .../Interface/IWeightManipulator.cs | 0 .../TrackingControlManipulator.cs | 0 .../WeightManipulatorManager.cs | 0 .../Integrations/BTKUIAddon.cs | 0 .../AlternateIKSystem/LICENSE.txt | 0 .../AlternateIKSystem/Main.cs | 0 .../AlternateIKSystem/ModSettings.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../AlternateIKSystem/README.md | 0 .../AlternateIKSystem/format.json | 0 .../AutoSyncTransforms}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../AutoSyncTransforms}/README.md | 0 .../WhereAmIPointing.csproj | 0 .../AutoSyncTransforms}/format.json | 0 .../AvatarScaleMod}/AvatarScaleMod.csproj | 0 .../AvatarScaling/AvatarScaleManager.cs | 4 +- .../AvatarScaling/Components/BaseScaler.cs | 0 .../AvatarScaling/Components/LocalScaler.cs | 5 +- .../AvatarScaling/Components/NetworkScaler.cs | 0 .../AvatarScaling/Events/AvatarScaleEvents.cs | 0 .../AvatarScaling/ScaledComponents.cs | 0 .../AvatarScaleMod}/HarmonyPatches.cs | 0 .../AvatarScaleMod}/Input/DebugKeybinds.cs | 0 .../AvatarScaleMod}/Input/ScaleReconizer.cs | 0 .../Integrations/BTKUI/BtkUiAddon.cs | 55 +- .../BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs | 9 +- .../BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs | 9 +- .../BTKUI/BtkUiAddon_CAT_DebugOptions.cs | 9 +- ...BtkUiAddon_CAT_UniversalScalingSettings.cs | 31 +- .../BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs | 35 +- .../Integrations/BTKUI/BtkUiAddon_Utils.cs | 77 +++ .../AvatarScaleMod}/Main.cs | 0 .../AvatarScaleMod}/ModSettings.cs | 0 .../AvatarScaleMod}/Networking/ModNetwork.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../AvatarScaleMod}/README.md | 0 .../AvatarScaleMod}/Scripts.cs | 9 +- .../AvatarScaleMod}/format.json | 0 .../resources/ASM_Icon_AvatarHeightConfig.png | Bin .../resources/ASM_Icon_AvatarHeightCopy.png | Bin .../AvatarScaleMod}/resources/menu.js | 0 .../BadAnimatorFix/BadAnimatorFix.csproj | 0 .../BadAnimatorFix/BadAnimatorFixManager.cs | 0 .../BadAnimatorFix/BadAnimatorFixer.cs | 0 .../BadAnimatorFix/HarmonyPatches.cs | 0 .../BadAnimatorFix/Main.cs | 0 .../BadAnimatorFix/Properties/AssemblyInfo.cs | 0 .../BadAnimatorFix/format.json | 0 .../Blackout/AssetHandler.cs | 0 .../Blackout/Blackout.csproj | 0 .../Blackout/BlackoutController.cs | 0 .../Blackout/HarmonyPatches.cs | 0 .../Blackout/Integrations/BTKUIAddon.cs | 0 .../Integrations/UIExpansionKitAddon.cs | 0 .../Blackout/Main.cs | 0 .../Blackout/Properties/AssemblyInfo.cs | 0 .../Blackout/Resource1.Designer.cs | 0 .../Blackout/Resource1.resx | 0 .../Blackout/format.json | 0 .../resources/blackout_controller.asset | Bin .../BullshitWatcher}/BullshitWatcher.csproj | 0 .../BullshitWatcher}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../CVRGizmos}/CVRGizmoManager.cs | 29 +- .../CVRGizmos}/CVRGizmos.csproj | 0 .../CVRAdvancedAvatarSettingsPointer.cs | 0 .../CVRAdvancedAvatarSettingsTrigger.cs | 0 .../CVRGizmos}/GizmoTypes/CVRAvatar.cs | 0 .../GizmoTypes/CVRAvatarPickupMarker.cs | 0 .../GizmoTypes/CVRDistanceConstrain.cs | 0 .../CVRGizmos}/GizmoTypes/CVRDistanceLod.cs | 0 .../CVRGizmos}/GizmoTypes/CVRGizmoBase.cs | 0 .../GizmoTypes/CVRHapticAreaChest.cs | 0 .../CVRGizmos}/GizmoTypes/CVRHapticZone.cs | 0 .../CVRGizmos}/GizmoTypes/CVRPointer.cs | 0 .../GizmoTypes/CVRSpawnableTrigger.cs | 0 .../GizmoTypes/CVRToggleStateTrigger.cs | 0 .../GizmoTypes/Unity_BoxCollider.cs | 0 .../GizmoTypes/Unity_CapsuleCollider.cs | 0 .../GizmoTypes/Unity_SphereCollider.cs | 0 {CVRGizmos => .Deprecated/CVRGizmos}/Main.cs | 0 .../CVRGizmos/Popcron.Gizmos/Constants.cs | 7 + .../CVRGizmos}/Popcron.Gizmos/Drawer.cs | 23 +- .../Popcron.Gizmos/Drawers/CubeDrawer.cs | 15 +- .../Popcron.Gizmos/Drawers/LineDrawer.cs | 18 + .../Popcron.Gizmos/Drawers/PolygonDrawer.cs | 15 +- .../Popcron.Gizmos/Drawers/SquareDrawer.cs | 15 +- .../CVRGizmos/Popcron.Gizmos/Element.cs | 11 + .../CVRGizmos}/Popcron.Gizmos/Gizmos.cs | 363 ++++++----- .../Popcron.Gizmos/GizmosInstance.cs | 0 .../CVRGizmos}/Popcron.Gizmos/LICENSE.md | 0 .../CVRGizmos}/Properties/AssemblyInfo.cs | 0 .../CVRGizmos}/format.json | 0 .../CameraExperiments.csproj | 0 .Deprecated/CameraExperiments/Main.cs | 170 ++++++ .../Properties/AssemblyInfo.cs | 32 + .Deprecated/CameraExperiments/README.md | 14 + .Deprecated/CameraExperiments/format.json | 23 + .../CameraFixes/CameraFixes.csproj | 0 .../CameraFixes/HarmonyPatches.cs | 0 .../CameraFixes/Main.cs | 0 .../CameraFixes/Properties/AssemblyInfo.cs | 0 .../CameraFixes/format.json | 0 .../ClearHudNotifications.csproj | 0 .../ClearHudNotifications/HarmonyPatches.cs | 0 .../ClearHudNotifications/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ClearHudNotifications/format.json | 0 .../ControlToUnlockMouse.csproj | 6 + .Deprecated/ControlToUnlockMouse/Main.cs | 308 ++++++++++ .../Properties/AssemblyInfo.cs | 32 + .../ControlToUnlockMouse}/README.md | 0 .../ControlToUnlockMouse}/format.json | 0 .../ControllerFreeze/ControllerFreeze.csproj | 0 .../ControllerFreeze/HarmonyPatches.cs | 0 .../ControllerFreeze/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ControllerFreeze/README.md | 0 .../ControllerFreeze/format.json | 0 .../DesktopVRIK/DesktopVRIK.csproj | 0 .../DesktopVRIK/HarmonyPatches.cs | 0 .../DesktopVRIK/IK/IKCalibrator.cs | 0 .../DesktopVRIK/IK/IKHandlers/IKHandler.cs | 0 .../IK/IKHandlers/IKHandlerDesktop.cs | 0 .../DesktopVRIK/IK/IKManager.cs | 0 .../DesktopVRIK/IK/MusclePoses.cs | 0 .../IK/VRIKHelpers/VRIKLocomotionData.cs | 0 .../DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs | 0 .../DesktopVRIK/Integrations/AMTAddon.cs | 0 .../DesktopVRIK/Integrations/BTKUIAddon.cs | 0 .../DesktopVRIK/Main.cs | 0 .../DesktopVRIK/ModSettings.cs | 0 .../DesktopVRIK/Properties/AssemblyInfo.cs | 0 .../DesktopVRIK/README.md | 0 .../DesktopVRIK/format.json | 0 .../DesktopVRSwitch/DesktopVRSwitch.csproj | 0 .../DesktopVRSwitch/HarmonyPatches.cs | 0 .../Integrations/BTKUIAddon.cs | 0 .../DesktopVRSwitch/Main.cs | 0 .../DesktopVRSwitch/ModSettings.cs | 0 .../DestroySteamVRInstancesImmediate.cs | 0 .../Patches/ReferenceCameraPatch.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../DesktopVRSwitch/README.md | 0 .../DesktopVRSwitch/Utils.cs | 0 .../DesktopVRSwitch/VRModeSwitchDebugger.cs | 0 .../DesktopVRSwitch/VRModeSwitchManager.cs | 0 .../CVRGestureRecognizerTracker.cs | 0 .../VRModeTrackers/CVRInputManagerTracker.cs | 0 .../VRModeTrackers/CVRPickupObjectTracker.cs | 0 .../VRModeTrackers/CVRWorldTracker.cs | 0 .../CVR_InteractableManagerTracker.cs | 0 .../VRModeTrackers/CVR_MenuManagerTracker.cs | 0 .../CameraFacingObjectTracker.cs | 0 .../VRModeTrackers/CheckVRTracker.cs | 0 .../VRModeTrackers/CohtmlHudTracker.cs | 0 .../VRModeTrackers/HudOperationsTracker.cs | 0 .../VRModeTrackers/IKSystemTracker.cs | 0 .../VRModeTrackers/MetaPortTracker.cs | 0 .../VRModeTrackers/MovementSystemTracker.cs | 0 .../VRModeTrackers/PlayerSetupTracker.cs | 0 .../VRModeTrackers/PortableCameraTracker.cs | 0 .../VRModeTrackers/VRModeTracker.cs | 0 .../VRModeTrackers/ViewManagerTracker.cs | 0 .../DesktopVRSwitch/XRHandler.cs | 0 .../DesktopVRSwitch/format.json | 0 .../DropPropTweak}/DropPropTweak.csproj | 0 .../DropPropTweak}/Main.cs | 2 - .../DropPropTweak}/Properties/AssemblyInfo.cs | 0 .../DropPropTweak}/README.md | 0 .../DropPropTweak}/format.json | 0 .../EzCurls/EzCurls.csproj | 0 .../InputModules/InputModuleCurlAdjuster.cs | 0 .../EzCurls/Main.cs | 0 .../EzCurls/ModSettings.cs | 0 .../EzCurls/Properties/AssemblyInfo.cs | 0 .../EzCurls/README.md | 0 .../EzCurls/format.json | 0 .../EzGrab/EzGrab.csproj | 0 .../EzGrab/Main.cs | 0 .../EzGrab/Properties/AssemblyInfo.cs | 0 .../EzGrab/format.json | 0 .../FOVAdjustment}/FOVAdjustment.csproj | 0 .../FOVAdjustment}/Main.cs | 6 +- .../FOVAdjustment}/Properties/AssemblyInfo.cs | 0 .../FOVAdjustment}/README.md | 0 .../FOVAdjustment}/format.json | 0 .../FuckCohtmlResourceHandler.csproj | 0 .../HarmonyPatches.cs | 0 .../FuckCohtmlResourceHandler/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../FuckCohtmlResourceHandler/README.md | 0 .../FuckCohtmlResourceHandler/format.json | 0 .../FuckMLA/FuckMLA.csproj | 0 .../FuckMLA/HarmonyPatches.cs | 0 .../FuckMLA/Main.cs | 0 .../FuckMLA/Properties/AssemblyInfo.cs | 0 .../FuckMLA/format.json | 0 .../FuckMagicaCloth2/FuckMagicaCloth2.csproj | 0 .Deprecated/FuckMagicaCloth2/Main.cs | 49 ++ .../Properties/AssemblyInfo.cs | 30 + .../FuckMagicaCloth2}/README.md | 0 .Deprecated/FuckMagicaCloth2/format.json | 24 + .../FuckMetrics/FuckMetrics.csproj | 0 .../FuckMetrics/HarmonyPatches.cs | 0 .../FuckMetrics/Main.cs | 0 .../FuckMetrics/ManagedLibs/.keep | 0 .../FuckMetrics/Properties/AssemblyInfo.cs | 0 .../FuckMetrics/format.json | 0 .../FuckOffUICamera/CohtmlRenderForwarder.cs | 35 ++ .../FuckOffUICamera/CommandBufferManager.cs | 144 +++++ .../FuckOffUICamera/FuckOffUICamera.csproj | 0 .Deprecated/FuckOffUICamera/Main.cs | 73 +++ .../Properties/AssemblyInfo.cs | 18 +- .Deprecated/FuckOffUICamera/README.md | 14 + .Deprecated/FuckOffUICamera/format.json | 23 + .../FuckVivox/FuckVivox.csproj | 0 .../FuckVivox/HarmonyPatches.cs | 0 .../FuckVivox/Main.cs | 0 .../FuckVivox/Properties/AssemblyInfo.cs | 0 .../FuckVivox/VivoxHelpers.cs | 0 .../FuckVivox/WindowFocusManager.cs | 0 .../FuckVivox/format.json | 0 .../GestureLock}/GestureLock.csproj | 0 .../GestureLock}/HarmonyPatches.cs | 0 .../GestureLock}/Main.cs | 0 .../GestureLock}/Properties/AssemblyInfo.cs | 0 .../GestureLock}/README.md | 0 .../GestureLock}/format.json | 0 .../HeadBobbingFix/HarmonyPatches.cs | 0 .../HeadBobbingFix/HeadBobbingFix.csproj | 0 .../HeadBobbingFix/Main.cs | 0 .../HeadBobbingFix/Properties/AssemblyInfo.cs | 0 .../HeadBobbingFix/README.md | 0 .../HeadBobbingFix/format.json | 0 .../HeadLookLockingInputFix.csproj | 0 .../HeadLookLockingInputFix/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../HeadLookLockingInputFix/README.md | 0 .../HeadLookLockingInputFix/format.json | 0 .../IKAdjustments/HarmonyPatches.cs | 0 .../IKAdjustments/IKAdjuster.cs | 0 .../IKAdjustments/IKAdjustments.csproj | 0 .../IKAdjustments/Integrations/BTKUIAddon.cs | 0 .../IKAdjustments/Main.cs | 0 .../IKAdjustments/Properties/AssemblyInfo.cs | 0 .../IKFixes/HarmonyPatches.cs | 0 .../IKFixes/IKFixes.csproj | 0 .../IKFixes/Integrations/UIExKitAddon.cs | 0 .../IKFixes/Main.cs | 0 .../IKFixes/Properties/AssemblyInfo.cs | 0 .../IKFixes/README.md | 0 .../IKFixes/format.json | 0 .../IKSimulatedRootAngleFix.csproj | 0 .../IKSimulatedRootAngleFix}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .Deprecated/IKSimulatedRootAngleFix/README.md | 14 + .../IKSimulatedRootAngleFix}/format.json | 0 .../InteractionTest/AutoArmIK.cs | 0 .../ColliderTest/AvatarColliderStruct.cs | 0 .../ColliderTest/AvatarColliders.cs | 0 .../ColliderTest/LineColliderTest.cs | 0 .../InteractionTest/GrabbableAvatar.cs | 0 .../InteractionTest/GrabbingAvatar.cs | 0 .../InteractionTest/HarmonyPatches.cs | 0 .../InteractionTest/InteractionTest.csproj | 0 .../InteractionTest/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../InteractionTest/README.md | 0 .../InteractionTest}/format.json | 0 .../JumpPatch/HarmonyPatches.cs | 0 .../JumpPatch/JumpPatch.csproj | 0 .../JumpPatch/Main.cs | 0 .../JumpPatch/Properties/AssemblyInfo.cs | 0 .../JumpPatch/format.json | 0 .../LateInitComponentHelperHack.csproj | 0 .../LateInitComponentHelperHack/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../LateInitComponentHelperHack/format.json | 0 .../Components/CameraCallbackLogger.cs | 0 .../Components/FaceMirror.cs | 100 +++ .../Components/FakeMultiPassHack.cs | 0 .../Integrations/BtkUiAddon.cs | 0 .../LegacyContentMitigation.csproj | 0 .../LegacyContentMitigation}/Main.cs | 0 .../LegacyContentMitigation/ModSettings.cs | 52 ++ .../LegacyContentMitigation}/Patches.cs | 4 + .../Properties/AssemblyInfo.cs | 0 .../LegacyContentMitigation}/README.md | 0 .../LegacyContentMitigation}/format.json | 4 +- .../MenuScalePatch/HarmonyPatches.cs | 0 .../MenuScalePatch/Helpers/MainMenuHelper.cs | 0 .../MenuScalePatch/Helpers/QuickMenuHelper.cs | 0 .../MenuScalePatch/MSP_Menus.cs | 0 .../MenuScalePatch/Main.cs | 0 .../MenuScalePatch/MenuScalePatch.csproj | 0 .../MenuScalePatch/Properties/AssemblyInfo.cs | 0 .../MenuScalePatch/README.md | 0 .../MenuScalePatch/format.json | 0 .../MoreMenuOptions/Main.cs | 0 .../MoreMenuOptions/ModSettings.cs | 0 .../MoreMenuOptions/MoreMenuOptions.csproj | 0 .../Properties/AssemblyInfo.cs | 0 .../MoreMenuOptions/README.md | 0 .../MoreMenuOptions/format.json | 0 .../Components/NAKPointerTracker.cs | 0 .../CustomComponents.csproj | 0 .../NAK.CustomComponents/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../NAK.CustomComponents/format.json | 0 {Nevermind => .Deprecated/Nevermind}/Main.cs | 0 .../Nevermind}/Nevermind.csproj | 0 .../Nevermind}/Properties/AssemblyInfo.cs | 0 .../Nevermind}/README.md | 0 .../Nevermind}/format.json | 0 .../NoDepthOnlyFlat/Main.cs | 0 .../NoDepthOnlyFlat/NoDepthOnlyFlat.csproj | 0 .../Properties/AssemblyInfo.cs | 0 .../NoDepthOnlyFlat/README.md | 0 .../NoDepthOnlyFlat/format.json | 0 .../PickupPushPull/HarmonyPatches.cs | 0 .../InputModules/PickupPushPull_Module.cs | 0 .../PickupPushPull/Main.cs | 0 .../PickupPushPull/PickupPushPull.csproj | 0 .../PickupPushPull/Properties/AssemblyInfo.cs | 0 .../PickupPushPull/format.json | 0 .../PlaySpaceScaleFix/HarmonyPatches.cs | 0 .../PlaySpaceScaleFix/Main.cs | 0 .../PlaySpaceScaleFix.csproj | 0 .../Properties/AssemblyInfo.cs | 0 .../PlaySpaceScaleFix/README.md | 0 .../PlaySpaceScaleFix/format.json | 0 .../ReconnectionSystemFix}/Main.cs | 0 .../ReconnectionSystemFix}/Patches.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ReconnectionSystemFix}/README.md | 0 .../ReconnectionSystemFix.csproj | 6 + .../ReconnectionSystemFix}/format.json | 0 .../Main.cs | 43 ++ .../Properties/AssemblyInfo.cs | 30 + .../README.md | 14 + ...vatarDisablingCameraOnFirstFrameFix.csproj | 6 + .../format.json | 24 + .../SearchWithSpacesFix}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .Deprecated/SearchWithSpacesFix/README.md | 14 + .../SearchWithSpacesFix.csproj | 2 + .Deprecated/SearchWithSpacesFix/format.json | 23 + .../ShadowCloneFallback}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ShadowCloneFallback}/README.md | 0 .../ShadowCloneFallback.csproj | 0 .../ShadowCloneFallback}/format.json | 0 .../SmartReticle}/Main.cs | 0 .../SmartReticle}/Properties/AssemblyInfo.cs | 0 .../SmartReticle}/README.md | 0 .Deprecated/SmartReticle/SmartReticle.csproj | 6 + .../SmartReticle}/format.json | 0 .../StopClosingMyMenuOnWorldLoad}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../StopClosingMyMenuOnWorldLoad}/README.md | 0 .../StopClosingMyMenuOnWorldLoad.csproj | 0 .../StopClosingMyMenuOnWorldLoad}/format.json | 0 .../Interaction/CVRPlayerHand.cs | 42 ++ .../CVRPlayerInteractionManager.cs | 214 +++++++ .../Components/CVRCanvasWrapper.cs | 121 ++++ .../RaycastImpl/CVRPlayerRaycaster.cs | 385 ++++++++++++ .../RaycastImpl/CVRPlayerRaycasterMouse.cs | 13 + .../CVRPlayerRaycasterTransform.cs | 10 + .../RaycastImpl/CVRRaycastResult.cs | 38 ++ .../Interaction/RaycastImpl/RaycastDebug.cs | 312 ++++++++++ .Deprecated/SuperAwesomeMod/Main.cs | 81 +++ .../Properties/AssemblyInfo.cs | 32 + .Deprecated/SuperAwesomeMod/README.md | 54 ++ .../SuperAwesomeMod/SuperAwesomeMod.csproj | 9 +- .Deprecated/SuperAwesomeMod/format.json | 24 + .../SwitchToDesktopOnSteamVRExit/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../SwitchToDesktopOnSteamVRExit/README.md | 0 .../SwitchToDesktopOnSteamVRExit.csproj | 0 .../SwitchToDesktopOnSteamVRExit/format.json | 0 .../TrackedControllerFix/HarmonyPatches.cs | 0 .../TrackedControllerFix/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../TrackedControllerFix/README.md | 0 .../TrackedControllerFix.csproj | 0 .../TrackedControllerFixer.cs | 0 .../TrackedControllerFix/format.json | 0 .../TrackedPointFix/HarmonyPatches.cs | 0 .../TrackedPointFix/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../TrackedPointFix/README.md | 0 .../TrackedPointFix/TrackedPointFix.csproj | 0 .../TrackedPointFix/format.json | 0 .../VisualCloneFix}/Main.cs | 0 .Deprecated/VisualCloneFix/Patches.cs | 157 +++++ .../Properties/AssemblyInfo.cs | 0 .../VisualCloneFix}/README.md | 0 .../VisualCloneFix}/VisualCloneFix.csproj | 0 .../VisualCloneFix}/format.json | 0 .Deprecated/WhereAmIPointing/Main.cs | 106 ++++ .../Properties/AssemblyInfo.cs | 32 + .Deprecated/WhereAmIPointing/README.md | 14 + .../WhereAmIPointing/WhereAmIPointing.csproj | 6 + .Deprecated/WhereAmIPointing/format.json | 23 + .gitignore | 3 + ASTExtension/Integrations/BTKUI/BtkUiAddon.cs | 63 +- .../AvatarClone/AvatarClone.API.cs | 68 --- .../AvatarClone/AvatarClone.Clones.cs | 103 ---- .../AvatarClone/AvatarClone.Exclusion.cs | 141 ----- .../AvatarClone/AvatarClone.Exclusions.cs | 229 +++++++ .../AvatarClone/AvatarClone.Fields.cs | 67 -- .../AvatarClone/AvatarClone.Init.cs | 360 ++++++++--- .../AvatarClone/AvatarClone.MagicaSupport.cs | 34 -- .../AvatarClone/AvatarClone.RenderState.cs | 212 +++++++ .../AvatarClone/AvatarClone.StateSync.cs | 156 +++++ .../AvatarClone/AvatarClone.Update.cs | 181 ------ .../AvatarClone/AvatarClone.Util.cs | 75 ++- AvatarCloneTest/AvatarClone/AvatarClone.cs | 233 +++---- .../FPRExclusion/AvatarCloneExclusion.cs | 15 +- AvatarCloneTest/Main.cs | 31 +- AvatarCloneTest/Patches.cs | 69 +-- AvatarCloneTest/Properties/AssemblyInfo.cs | 2 +- .../Integrations/BTKUI/BtkUiAddon_Utils.cs | 78 --- .../BetterContentLoading.csproj | 15 + .../BetterDownloadManager.cs | 210 +++++++ .../BetterContentLoading/DownloadInfo.cs | 63 ++ .../BetterContentLoading/DownloadProcessor.cs | 152 +++++ .../DownloadQueue/AvatarDownloadQueue.cs | 83 +++ .../DownloadQueue/ContentDownloadQueueBase.cs | 177 ++++++ .../DownloadQueue/PropDownloadQueue.cs | 81 +++ .../DownloadQueue/WorldDownloadQueue.cs | 66 ++ .../BetterContentLoading/DownloadState.cs | 26 + .../Util/ThreadingHelper.cs | 109 ++++ .../DownloadManager/DownloadManager.Core.cs | 237 ++++++++ .../DownloadManager.Helpers.cs | 58 ++ .../DownloadManager.Priority.cs | 38 ++ .../DownloadManager/DownloadTask.Main.cs | 33 + .../DownloadManager/DownloadTask.Priority.cs | 6 + .../ConcurrentPriorityQueue.cs | 43 ++ .../DownloadManager.Bandwidth.cs | 24 + .../DownloadManager2/DownloadManager.Core.cs | 126 ++++ .../DownloadManager.Helpers.cs | 58 ++ .../DownloadManager.Priority.cs | 47 ++ .../DownloadManager.Processing.cs | 144 +++++ .../DownloadManager2/DownloadManager.Queue.cs | 80 +++ .../DownloadManager2/DownloadTask2.cs | 62 ++ .../Main.cs | 17 +- BetterContentLoading/ModSettings.cs | 31 + BetterContentLoading/Patches.cs | 71 +++ .../Properties/AssemblyInfo.cs | 33 + BetterContentLoading/README.md | 14 + BetterContentLoading/format.json | 23 + CVRGizmos/Popcron.Gizmos/Constants.cs | 8 - .../Popcron.Gizmos/Drawers/LineDrawer.cs | 19 - CVRGizmos/Popcron.Gizmos/Element.cs | 12 - .../CVRLuaClientBehaviourExtensions.cs | 6 +- CustomRichPresence/CustomRichPresence.csproj | 11 + CustomRichPresence/Main.cs | 123 ++++ .../Properties/AssemblyInfo.cs | 18 +- CustomRichPresence/README.md | 14 + CustomRichPresence/format.json | 23 + CustomSpawnPoint/SpawnPointManager.cs | 127 ++-- .../Components/InteractionTracker.cs | 213 ------- InteractionTest/ModSettings.cs | 7 - InteractionTest/Patches.cs | 17 - InteractionTest/README.md | 52 -- InteractionTest/format.json | 23 - LegacyContentMitigation/ModSettings.cs | 24 - .../SyncedBehaviour/PickupableBehaviour.cs | 161 ----- .../SyncedBehaviour/PickupableObject.cs | 72 --- LuaTTS/Main.cs | 31 +- LuaTTS/Patches.cs | 10 +- NAK_CVR_Mods.sln | 84 +++ .../BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs | 67 +- OriginShift/Integrations/BTKUI/BtkuiAddon.cs | 43 +- .../Integrations/BTKUI/BtkuiAddon_Utils.cs | 41 +- .../Components/OriginShiftController.cs | 75 ++- .../Receivers/OriginShiftEventReceiver.cs | 62 +- .../OriginShiftParticleSystemReceiver.cs | 41 +- .../Receivers/OriginShiftRigidbodyReceiver.cs | 33 +- .../OriginShiftTrailRendererReceiver.cs | 41 +- .../Receivers/OriginShiftTransformReceiver.cs | 27 +- .../OriginShiftOcclusionCullingDisabler.cs | 39 +- .../OriginShift/Player/OriginShiftMonitor.cs | 51 +- OriginShift/Patches.cs | 1 + PhysicsGunMod/Components/ObjectSyncBridge.cs | 92 --- .../PhysicsGunInteractionBehavior.cs | 572 ------------------ PhysicsGunMod/HarmonyPatches.cs | 20 - PhysicsGunMod/Main.cs | 43 -- PhysicsGunMod/ModSettings.cs | 12 - PhysicsGunMod/PhysicsGunMod.csproj | 37 -- PhysicsGunMod/README.md | 28 - PhysicsGunMod/format.json | 23 - PlayerColorsAPI/Main.cs | 44 ++ .../Patches.cs | 0 PlayerColorsAPI/PlayerColorsAPI.csproj | 6 + PlayerColorsAPI/Properties/AssemblyInfo.cs | 32 + PlayerColorsAPI/README.md | 18 + PlayerColorsAPI/format.json | 23 + Portals/format.json | 1 - References.Items.props | 28 +- SmootherRay/Main.cs | 4 + SmootherRay/Properties/AssemblyInfo.cs | 2 +- SmootherRay/SmootherRayer.cs | 4 + .../Stickers/Networking/ModNetwork.Inbound.cs | 9 +- .../Stickers/StickerSystem.PlayerCallbacks.cs | 4 +- .../StickerSystem.StickerLifecycle.cs | 2 +- ThirdPerson/CameraLogic.cs | 4 +- ThirdPerson/Patches.cs | 5 - ThirdPerson/Properties/AssemblyInfo.cs | 2 +- 539 files changed, 7475 insertions(+), 3120 deletions(-) rename {.DepricatedMods => .Deprecated}/AASBufferFix/AASBufferFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/AASBufferHelper.cs (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/Utils.cs (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/format.json (100%) rename {AASDefaultProfileFix => .Deprecated/AASDefaultProfileFix}/AASDefaultProfileFix.csproj (100%) rename {AASDefaultProfileFix => .Deprecated/AASDefaultProfileFix}/Main.cs (100%) rename {AASDefaultProfileFix => .Deprecated/AASDefaultProfileFix}/Properties/AssemblyInfo.cs (100%) rename {AASDefaultProfileFix => .Deprecated/AASDefaultProfileFix}/README.md (100%) rename {AASDefaultProfileFix => .Deprecated/AASDefaultProfileFix}/format.json (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/AlternateIKSystem.csproj (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/BodyControl.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/IKCalibrator.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/IKHandlers/IKHandler.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/IKManager.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/MusclePoses.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/Tracking/SteamVRTrackerManager.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/WeightManipulators/BodyParts/BodyPart.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/WeightManipulators/DeviceControlManipulator.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/WeightManipulators/Interface/IWeightManipulator.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/WeightManipulators/TrackingControlManipulator.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/WeightManipulators/WeightManipulatorManager.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/Integrations/BTKUIAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/LICENSE.txt (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/ModSettings.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/README.md (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/format.json (100%) rename {WhereAmIPointing => .Deprecated/AutoSyncTransforms}/Main.cs (100%) rename {WhereAmIPointing => .Deprecated/AutoSyncTransforms}/Properties/AssemblyInfo.cs (100%) rename {WhereAmIPointing => .Deprecated/AutoSyncTransforms}/README.md (100%) rename {WhereAmIPointing => .Deprecated/AutoSyncTransforms}/WhereAmIPointing.csproj (100%) rename {WhereAmIPointing => .Deprecated/AutoSyncTransforms}/format.json (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaleMod.csproj (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/AvatarScaleManager.cs (99%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/Components/BaseScaler.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/Components/LocalScaler.cs (94%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/Components/NetworkScaler.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/Events/AvatarScaleEvents.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/ScaledComponents.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/HarmonyPatches.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Input/DebugKeybinds.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Input/ScaleReconizer.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon.cs (71%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs (76%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs (83%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs (71%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs (83%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs (76%) create mode 100644 .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Main.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/ModSettings.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Networking/ModNetwork.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Properties/AssemblyInfo.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/README.md (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Scripts.cs (83%) rename {.DepricatedMods/InteractionTest => .Deprecated/AvatarScaleMod}/format.json (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/resources/ASM_Icon_AvatarHeightConfig.png (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/resources/ASM_Icon_AvatarHeightCopy.png (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/resources/menu.js (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/BadAnimatorFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/BadAnimatorFixManager.cs (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/BadAnimatorFixer.cs (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/format.json (100%) rename {.DepricatedMods => .Deprecated}/Blackout/AssetHandler.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Blackout.csproj (100%) rename {.DepricatedMods => .Deprecated}/Blackout/BlackoutController.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Integrations/BTKUIAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Integrations/UIExpansionKitAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Resource1.Designer.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Resource1.resx (100%) rename {.DepricatedMods => .Deprecated}/Blackout/format.json (100%) rename {.DepricatedMods => .Deprecated}/Blackout/resources/blackout_controller.asset (100%) rename {BullshitWatcher => .Deprecated/BullshitWatcher}/BullshitWatcher.csproj (100%) rename {BullshitWatcher => .Deprecated/BullshitWatcher}/Main.cs (100%) rename {BullshitWatcher => .Deprecated/BullshitWatcher}/Properties/AssemblyInfo.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/CVRGizmoManager.cs (76%) rename {CVRGizmos => .Deprecated/CVRGizmos}/CVRGizmos.csproj (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRAdvancedAvatarSettingsPointer.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRAdvancedAvatarSettingsTrigger.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRAvatar.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRAvatarPickupMarker.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRDistanceConstrain.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRDistanceLod.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRGizmoBase.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRHapticAreaChest.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRHapticZone.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRPointer.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRSpawnableTrigger.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRToggleStateTrigger.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/Unity_BoxCollider.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/Unity_CapsuleCollider.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/Unity_SphereCollider.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Main.cs (100%) create mode 100644 .Deprecated/CVRGizmos/Popcron.Gizmos/Constants.cs rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/Drawer.cs (86%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/Drawers/CubeDrawer.cs (93%) create mode 100644 .Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/Drawers/PolygonDrawer.cs (84%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/Drawers/SquareDrawer.cs (89%) create mode 100644 .Deprecated/CVRGizmos/Popcron.Gizmos/Element.cs rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/Gizmos.cs (52%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/GizmosInstance.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/LICENSE.md (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Properties/AssemblyInfo.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/format.json (100%) rename SmartReticle/SmartReticle.csproj => .Deprecated/CameraExperiments/CameraExperiments.csproj (100%) create mode 100644 .Deprecated/CameraExperiments/Main.cs create mode 100644 .Deprecated/CameraExperiments/Properties/AssemblyInfo.cs create mode 100644 .Deprecated/CameraExperiments/README.md create mode 100644 .Deprecated/CameraExperiments/format.json rename {.DepricatedMods => .Deprecated}/CameraFixes/CameraFixes.csproj (100%) rename {.DepricatedMods => .Deprecated}/CameraFixes/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/CameraFixes/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/CameraFixes/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/CameraFixes/format.json (100%) rename {.DepricatedMods => .Deprecated}/ClearHudNotifications/ClearHudNotifications.csproj (100%) rename {.DepricatedMods => .Deprecated}/ClearHudNotifications/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/ClearHudNotifications/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/ClearHudNotifications/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/ClearHudNotifications/format.json (100%) create mode 100644 .Deprecated/ControlToUnlockMouse/ControlToUnlockMouse.csproj create mode 100644 .Deprecated/ControlToUnlockMouse/Main.cs create mode 100644 .Deprecated/ControlToUnlockMouse/Properties/AssemblyInfo.cs rename {SearchWithSpacesFix => .Deprecated/ControlToUnlockMouse}/README.md (100%) rename {SearchWithSpacesFix => .Deprecated/ControlToUnlockMouse}/format.json (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/ControllerFreeze.csproj (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/README.md (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/format.json (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/DesktopVRIK.csproj (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/IKCalibrator.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/IKHandlers/IKHandler.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/IKHandlers/IKHandlerDesktop.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/IKManager.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/MusclePoses.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/VRIKHelpers/VRIKLocomotionData.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/Integrations/AMTAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/Integrations/BTKUIAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/ModSettings.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/README.md (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/format.json (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/DesktopVRSwitch.csproj (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Integrations/BTKUIAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/ModSettings.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Patches/DestroySteamVRInstancesImmediate.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/README.md (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Utils.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeSwitchDebugger.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeSwitchManager.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVRGestureRecognizerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVRInputManagerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVRPickupObjectTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVRWorldTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVR_InteractableManagerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVR_MenuManagerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CameraFacingObjectTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CheckVRTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CohtmlHudTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/HudOperationsTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/IKSystemTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/MetaPortTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/MovementSystemTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/PlayerSetupTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/PortableCameraTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/VRModeTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/ViewManagerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/XRHandler.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/format.json (100%) rename {DropPropTweak => .Deprecated/DropPropTweak}/DropPropTweak.csproj (100%) rename {DropPropTweak => .Deprecated/DropPropTweak}/Main.cs (99%) rename {DropPropTweak => .Deprecated/DropPropTweak}/Properties/AssemblyInfo.cs (100%) rename {DropPropTweak => .Deprecated/DropPropTweak}/README.md (100%) rename {DropPropTweak => .Deprecated/DropPropTweak}/format.json (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/EzCurls.csproj (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/InputModules/InputModuleCurlAdjuster.cs (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/ModSettings.cs (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/README.md (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/format.json (100%) rename {.DepricatedMods => .Deprecated}/EzGrab/EzGrab.csproj (100%) rename {.DepricatedMods => .Deprecated}/EzGrab/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/EzGrab/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/EzGrab/format.json (100%) rename {FOVAdjustment => .Deprecated/FOVAdjustment}/FOVAdjustment.csproj (100%) rename {FOVAdjustment => .Deprecated/FOVAdjustment}/Main.cs (94%) rename {FOVAdjustment => .Deprecated/FOVAdjustment}/Properties/AssemblyInfo.cs (100%) rename {FOVAdjustment => .Deprecated/FOVAdjustment}/README.md (100%) rename {FOVAdjustment => .Deprecated/FOVAdjustment}/format.json (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/FuckCohtmlResourceHandler.csproj (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/README.md (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/format.json (100%) rename {.DepricatedMods => .Deprecated}/FuckMLA/FuckMLA.csproj (100%) rename {.DepricatedMods => .Deprecated}/FuckMLA/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMLA/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMLA/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMLA/format.json (100%) rename .DepricatedMods/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj => .Deprecated/FuckMagicaCloth2/FuckMagicaCloth2.csproj (100%) create mode 100644 .Deprecated/FuckMagicaCloth2/Main.cs create mode 100644 .Deprecated/FuckMagicaCloth2/Properties/AssemblyInfo.cs rename {IKSimulatedRootAngleFix => .Deprecated/FuckMagicaCloth2}/README.md (100%) create mode 100644 .Deprecated/FuckMagicaCloth2/format.json rename {.DepricatedMods => .Deprecated}/FuckMetrics/FuckMetrics.csproj (100%) rename {.DepricatedMods => .Deprecated}/FuckMetrics/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMetrics/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMetrics/ManagedLibs/.keep (100%) rename {.DepricatedMods => .Deprecated}/FuckMetrics/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMetrics/format.json (100%) create mode 100644 .Deprecated/FuckOffUICamera/CohtmlRenderForwarder.cs create mode 100644 .Deprecated/FuckOffUICamera/CommandBufferManager.cs rename .DepricatedMods/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj => .Deprecated/FuckOffUICamera/FuckOffUICamera.csproj (100%) create mode 100644 .Deprecated/FuckOffUICamera/Main.cs rename {PhysicsGunMod => .Deprecated/FuckOffUICamera}/Properties/AssemblyInfo.cs (67%) create mode 100644 .Deprecated/FuckOffUICamera/README.md create mode 100644 .Deprecated/FuckOffUICamera/format.json rename {.DepricatedMods => .Deprecated}/FuckVivox/FuckVivox.csproj (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/VivoxHelpers.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/WindowFocusManager.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/format.json (100%) rename {GestureLock => .Deprecated/GestureLock}/GestureLock.csproj (100%) rename {GestureLock => .Deprecated/GestureLock}/HarmonyPatches.cs (100%) rename {GestureLock => .Deprecated/GestureLock}/Main.cs (100%) rename {GestureLock => .Deprecated/GestureLock}/Properties/AssemblyInfo.cs (100%) rename {GestureLock => .Deprecated/GestureLock}/README.md (100%) rename {GestureLock => .Deprecated/GestureLock}/format.json (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/HeadBobbingFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/format.json (100%) rename ReconnectionSystemFix/ReconnectionSystemFix.csproj => .Deprecated/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/HeadLookLockingInputFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/HeadLookLockingInputFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/HeadLookLockingInputFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/HeadLookLockingInputFix/format.json (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/IKAdjuster.cs (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/IKAdjustments.csproj (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/Integrations/BTKUIAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/IKFixes.csproj (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/Integrations/UIExKitAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/README.md (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/format.json (100%) rename {IKSimulatedRootAngleFix => .Deprecated/IKSimulatedRootAngleFix}/IKSimulatedRootAngleFix.csproj (100%) rename {IKSimulatedRootAngleFix => .Deprecated/IKSimulatedRootAngleFix}/Main.cs (100%) rename {IKSimulatedRootAngleFix => .Deprecated/IKSimulatedRootAngleFix}/Properties/AssemblyInfo.cs (100%) create mode 100644 .Deprecated/IKSimulatedRootAngleFix/README.md rename {IKSimulatedRootAngleFix => .Deprecated/IKSimulatedRootAngleFix}/format.json (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/AutoArmIK.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/ColliderTest/AvatarColliderStruct.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/ColliderTest/AvatarColliders.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/ColliderTest/LineColliderTest.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/GrabbableAvatar.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/GrabbingAvatar.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/InteractionTest.csproj (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/README.md (100%) rename {AvatarScaleMod => .Deprecated/InteractionTest}/format.json (100%) rename {.DepricatedMods => .Deprecated}/JumpPatch/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/JumpPatch/JumpPatch.csproj (100%) rename {.DepricatedMods => .Deprecated}/JumpPatch/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/JumpPatch/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/JumpPatch/format.json (100%) rename {.DepricatedMods => .Deprecated}/LateInitComponentHelperHack/LateInitComponentHelperHack.csproj (100%) rename {.DepricatedMods => .Deprecated}/LateInitComponentHelperHack/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/LateInitComponentHelperHack/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/LateInitComponentHelperHack/format.json (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Components/CameraCallbackLogger.cs (100%) create mode 100644 .Deprecated/LegacyContentMitigation/Components/FaceMirror.cs rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Components/FakeMultiPassHack.cs (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Integrations/BtkUiAddon.cs (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/LegacyContentMitigation.csproj (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Main.cs (100%) create mode 100644 .Deprecated/LegacyContentMitigation/ModSettings.cs rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Patches.cs (97%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Properties/AssemblyInfo.cs (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/README.md (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/format.json (96%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/Helpers/MainMenuHelper.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/Helpers/QuickMenuHelper.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/MSP_Menus.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/MenuScalePatch.csproj (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/README.md (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/format.json (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/ModSettings.cs (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/MoreMenuOptions.csproj (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/README.md (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/format.json (100%) rename {.DepricatedMods => .Deprecated}/NAK.CustomComponents/Components/NAKPointerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/NAK.CustomComponents/CustomComponents.csproj (100%) rename {.DepricatedMods => .Deprecated}/NAK.CustomComponents/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/NAK.CustomComponents/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/NAK.CustomComponents/format.json (100%) rename {Nevermind => .Deprecated/Nevermind}/Main.cs (100%) rename {Nevermind => .Deprecated/Nevermind}/Nevermind.csproj (100%) rename {Nevermind => .Deprecated/Nevermind}/Properties/AssemblyInfo.cs (100%) rename {Nevermind => .Deprecated/Nevermind}/README.md (100%) rename {Nevermind => .Deprecated/Nevermind}/format.json (100%) rename {.DepricatedMods => .Deprecated}/NoDepthOnlyFlat/Main.cs (100%) rename SearchWithSpacesFix/SearchWithSpacesFix.csproj => .Deprecated/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj (100%) rename {.DepricatedMods => .Deprecated}/NoDepthOnlyFlat/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/NoDepthOnlyFlat/README.md (100%) rename {.DepricatedMods => .Deprecated}/NoDepthOnlyFlat/format.json (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/InputModules/PickupPushPull_Module.cs (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/PickupPushPull.csproj (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/format.json (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/PlaySpaceScaleFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/format.json (100%) rename {ReconnectionSystemFix => .Deprecated/ReconnectionSystemFix}/Main.cs (100%) rename {ReconnectionSystemFix => .Deprecated/ReconnectionSystemFix}/Patches.cs (100%) rename {ReconnectionSystemFix => .Deprecated/ReconnectionSystemFix}/Properties/AssemblyInfo.cs (100%) rename {ReconnectionSystemFix => .Deprecated/ReconnectionSystemFix}/README.md (100%) create mode 100644 .Deprecated/ReconnectionSystemFix/ReconnectionSystemFix.csproj rename {ReconnectionSystemFix => .Deprecated/ReconnectionSystemFix}/format.json (100%) create mode 100644 .Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Main.cs create mode 100644 .Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Properties/AssemblyInfo.cs create mode 100644 .Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/README.md create mode 100644 .Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/RemoteAvatarDisablingCameraOnFirstFrameFix.csproj create mode 100644 .Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/format.json rename {SearchWithSpacesFix => .Deprecated/SearchWithSpacesFix}/Main.cs (100%) rename {SearchWithSpacesFix => .Deprecated/SearchWithSpacesFix}/Properties/AssemblyInfo.cs (100%) create mode 100644 .Deprecated/SearchWithSpacesFix/README.md create mode 100644 .Deprecated/SearchWithSpacesFix/SearchWithSpacesFix.csproj create mode 100644 .Deprecated/SearchWithSpacesFix/format.json rename {ShadowCloneFallback => .Deprecated/ShadowCloneFallback}/Main.cs (100%) rename {ShadowCloneFallback => .Deprecated/ShadowCloneFallback}/Properties/AssemblyInfo.cs (100%) rename {ShadowCloneFallback => .Deprecated/ShadowCloneFallback}/README.md (100%) rename {ShadowCloneFallback => .Deprecated/ShadowCloneFallback}/ShadowCloneFallback.csproj (100%) rename {ShadowCloneFallback => .Deprecated/ShadowCloneFallback}/format.json (100%) rename {SmartReticle => .Deprecated/SmartReticle}/Main.cs (100%) rename {SmartReticle => .Deprecated/SmartReticle}/Properties/AssemblyInfo.cs (100%) rename {SmartReticle => .Deprecated/SmartReticle}/README.md (100%) create mode 100644 .Deprecated/SmartReticle/SmartReticle.csproj rename {SmartReticle => .Deprecated/SmartReticle}/format.json (100%) rename {StopClosingMyMenuOnWorldLoad => .Deprecated/StopClosingMyMenuOnWorldLoad}/Main.cs (100%) rename {StopClosingMyMenuOnWorldLoad => .Deprecated/StopClosingMyMenuOnWorldLoad}/Properties/AssemblyInfo.cs (100%) rename {StopClosingMyMenuOnWorldLoad => .Deprecated/StopClosingMyMenuOnWorldLoad}/README.md (100%) rename {StopClosingMyMenuOnWorldLoad => .Deprecated/StopClosingMyMenuOnWorldLoad}/StopClosingMyMenuOnWorldLoad.csproj (100%) rename {StopClosingMyMenuOnWorldLoad => .Deprecated/StopClosingMyMenuOnWorldLoad}/format.json (100%) create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs create mode 100644 .Deprecated/SuperAwesomeMod/Main.cs create mode 100644 .Deprecated/SuperAwesomeMod/Properties/AssemblyInfo.cs create mode 100644 .Deprecated/SuperAwesomeMod/README.md rename InteractionTest/InteractionTest.csproj => .Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj (52%) create mode 100644 .Deprecated/SuperAwesomeMod/format.json rename {.DepricatedMods => .Deprecated}/SwitchToDesktopOnSteamVRExit/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/SwitchToDesktopOnSteamVRExit/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/SwitchToDesktopOnSteamVRExit/README.md (100%) rename {.DepricatedMods => .Deprecated}/SwitchToDesktopOnSteamVRExit/SwitchToDesktopOnSteamVRExit.csproj (100%) rename {.DepricatedMods => .Deprecated}/SwitchToDesktopOnSteamVRExit/format.json (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/TrackedControllerFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/TrackedControllerFixer.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/format.json (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/TrackedPointFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/format.json (100%) rename {VisualCloneFix => .Deprecated/VisualCloneFix}/Main.cs (100%) create mode 100644 .Deprecated/VisualCloneFix/Patches.cs rename {VisualCloneFix => .Deprecated/VisualCloneFix}/Properties/AssemblyInfo.cs (100%) rename {VisualCloneFix => .Deprecated/VisualCloneFix}/README.md (100%) rename {VisualCloneFix => .Deprecated/VisualCloneFix}/VisualCloneFix.csproj (100%) rename {VisualCloneFix => .Deprecated/VisualCloneFix}/format.json (100%) create mode 100644 .Deprecated/WhereAmIPointing/Main.cs create mode 100644 .Deprecated/WhereAmIPointing/Properties/AssemblyInfo.cs create mode 100644 .Deprecated/WhereAmIPointing/README.md create mode 100644 .Deprecated/WhereAmIPointing/WhereAmIPointing.csproj create mode 100644 .Deprecated/WhereAmIPointing/format.json delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.API.cs delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Update.cs delete mode 100644 AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs create mode 100644 BetterContentLoading/BetterContentLoading.csproj create mode 100644 BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadInfo.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadProcessor.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadState.cs create mode 100644 BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs create mode 100644 BetterContentLoading/DownloadManager/DownloadManager.Core.cs create mode 100644 BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs create mode 100644 BetterContentLoading/DownloadManager/DownloadManager.Priority.cs create mode 100644 BetterContentLoading/DownloadManager/DownloadTask.Main.cs create mode 100644 BetterContentLoading/DownloadManager/DownloadTask.Priority.cs create mode 100644 BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Core.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadTask2.cs rename {InteractionTest => BetterContentLoading}/Main.cs (68%) create mode 100644 BetterContentLoading/ModSettings.cs create mode 100644 BetterContentLoading/Patches.cs create mode 100644 BetterContentLoading/Properties/AssemblyInfo.cs create mode 100644 BetterContentLoading/README.md create mode 100644 BetterContentLoading/format.json delete mode 100644 CVRGizmos/Popcron.Gizmos/Constants.cs delete mode 100644 CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs delete mode 100644 CVRGizmos/Popcron.Gizmos/Element.cs create mode 100644 CustomRichPresence/CustomRichPresence.csproj create mode 100644 CustomRichPresence/Main.cs rename {InteractionTest => CustomRichPresence}/Properties/AssemblyInfo.cs (65%) create mode 100644 CustomRichPresence/README.md create mode 100644 CustomRichPresence/format.json delete mode 100644 InteractionTest/Components/InteractionTracker.cs delete mode 100644 InteractionTest/ModSettings.cs delete mode 100644 InteractionTest/Patches.cs delete mode 100644 InteractionTest/README.md delete mode 100644 InteractionTest/format.json delete mode 100644 LegacyContentMitigation/ModSettings.cs delete mode 100644 LuaNetworkVariables/SyncedBehaviour/PickupableBehaviour.cs delete mode 100644 LuaNetworkVariables/SyncedBehaviour/PickupableObject.cs delete mode 100644 PhysicsGunMod/Components/ObjectSyncBridge.cs delete mode 100644 PhysicsGunMod/Components/PhysicsGunInteractionBehavior.cs delete mode 100644 PhysicsGunMod/HarmonyPatches.cs delete mode 100644 PhysicsGunMod/Main.cs delete mode 100644 PhysicsGunMod/ModSettings.cs delete mode 100644 PhysicsGunMod/PhysicsGunMod.csproj delete mode 100644 PhysicsGunMod/README.md delete mode 100644 PhysicsGunMod/format.json create mode 100644 PlayerColorsAPI/Main.cs rename {VisualCloneFix => PlayerColorsAPI}/Patches.cs (100%) create mode 100644 PlayerColorsAPI/PlayerColorsAPI.csproj create mode 100644 PlayerColorsAPI/Properties/AssemblyInfo.cs create mode 100644 PlayerColorsAPI/README.md create mode 100644 PlayerColorsAPI/format.json delete mode 100644 Portals/format.json diff --git a/.DepricatedMods/AASBufferFix/AASBufferFix.csproj b/.Deprecated/AASBufferFix/AASBufferFix.csproj similarity index 100% rename from .DepricatedMods/AASBufferFix/AASBufferFix.csproj rename to .Deprecated/AASBufferFix/AASBufferFix.csproj diff --git a/.DepricatedMods/AASBufferFix/AASBufferHelper.cs b/.Deprecated/AASBufferFix/AASBufferHelper.cs similarity index 100% rename from .DepricatedMods/AASBufferFix/AASBufferHelper.cs rename to .Deprecated/AASBufferFix/AASBufferHelper.cs diff --git a/.DepricatedMods/AASBufferFix/HarmonyPatches.cs b/.Deprecated/AASBufferFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/AASBufferFix/HarmonyPatches.cs rename to .Deprecated/AASBufferFix/HarmonyPatches.cs diff --git a/.DepricatedMods/AASBufferFix/Main.cs b/.Deprecated/AASBufferFix/Main.cs similarity index 100% rename from .DepricatedMods/AASBufferFix/Main.cs rename to .Deprecated/AASBufferFix/Main.cs diff --git a/.DepricatedMods/AASBufferFix/Properties/AssemblyInfo.cs b/.Deprecated/AASBufferFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/AASBufferFix/Properties/AssemblyInfo.cs rename to .Deprecated/AASBufferFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/AASBufferFix/README.md b/.Deprecated/AASBufferFix/README.md similarity index 100% rename from .DepricatedMods/AASBufferFix/README.md rename to .Deprecated/AASBufferFix/README.md diff --git a/.DepricatedMods/AASBufferFix/Utils.cs b/.Deprecated/AASBufferFix/Utils.cs similarity index 100% rename from .DepricatedMods/AASBufferFix/Utils.cs rename to .Deprecated/AASBufferFix/Utils.cs diff --git a/.DepricatedMods/AASBufferFix/format.json b/.Deprecated/AASBufferFix/format.json similarity index 100% rename from .DepricatedMods/AASBufferFix/format.json rename to .Deprecated/AASBufferFix/format.json diff --git a/AASDefaultProfileFix/AASDefaultProfileFix.csproj b/.Deprecated/AASDefaultProfileFix/AASDefaultProfileFix.csproj similarity index 100% rename from AASDefaultProfileFix/AASDefaultProfileFix.csproj rename to .Deprecated/AASDefaultProfileFix/AASDefaultProfileFix.csproj diff --git a/AASDefaultProfileFix/Main.cs b/.Deprecated/AASDefaultProfileFix/Main.cs similarity index 100% rename from AASDefaultProfileFix/Main.cs rename to .Deprecated/AASDefaultProfileFix/Main.cs diff --git a/AASDefaultProfileFix/Properties/AssemblyInfo.cs b/.Deprecated/AASDefaultProfileFix/Properties/AssemblyInfo.cs similarity index 100% rename from AASDefaultProfileFix/Properties/AssemblyInfo.cs rename to .Deprecated/AASDefaultProfileFix/Properties/AssemblyInfo.cs diff --git a/AASDefaultProfileFix/README.md b/.Deprecated/AASDefaultProfileFix/README.md similarity index 100% rename from AASDefaultProfileFix/README.md rename to .Deprecated/AASDefaultProfileFix/README.md diff --git a/AASDefaultProfileFix/format.json b/.Deprecated/AASDefaultProfileFix/format.json similarity index 100% rename from AASDefaultProfileFix/format.json rename to .Deprecated/AASDefaultProfileFix/format.json diff --git a/.DepricatedMods/AlternateIKSystem/AlternateIKSystem.csproj b/.Deprecated/AlternateIKSystem/AlternateIKSystem.csproj similarity index 100% rename from .DepricatedMods/AlternateIKSystem/AlternateIKSystem.csproj rename to .Deprecated/AlternateIKSystem/AlternateIKSystem.csproj diff --git a/.DepricatedMods/AlternateIKSystem/HarmonyPatches.cs b/.Deprecated/AlternateIKSystem/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/HarmonyPatches.cs rename to .Deprecated/AlternateIKSystem/HarmonyPatches.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/BodyControl.cs b/.Deprecated/AlternateIKSystem/IK/BodyControl.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/BodyControl.cs rename to .Deprecated/AlternateIKSystem/IK/BodyControl.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/IKCalibrator.cs b/.Deprecated/AlternateIKSystem/IK/IKCalibrator.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/IKCalibrator.cs rename to .Deprecated/AlternateIKSystem/IK/IKCalibrator.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandler.cs b/.Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandler.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandler.cs rename to .Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandler.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs b/.Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs rename to .Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs b/.Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs rename to .Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/IKManager.cs b/.Deprecated/AlternateIKSystem/IK/IKManager.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/IKManager.cs rename to .Deprecated/AlternateIKSystem/IK/IKManager.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/MusclePoses.cs b/.Deprecated/AlternateIKSystem/IK/MusclePoses.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/MusclePoses.cs rename to .Deprecated/AlternateIKSystem/IK/MusclePoses.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/Tracking/SteamVRTrackerManager.cs b/.Deprecated/AlternateIKSystem/IK/Tracking/SteamVRTrackerManager.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/Tracking/SteamVRTrackerManager.cs rename to .Deprecated/AlternateIKSystem/IK/Tracking/SteamVRTrackerManager.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs b/.Deprecated/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs rename to .Deprecated/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs b/.Deprecated/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs rename to .Deprecated/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/WeightManipulators/BodyParts/BodyPart.cs b/.Deprecated/AlternateIKSystem/IK/WeightManipulators/BodyParts/BodyPart.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/WeightManipulators/BodyParts/BodyPart.cs rename to .Deprecated/AlternateIKSystem/IK/WeightManipulators/BodyParts/BodyPart.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/WeightManipulators/DeviceControlManipulator.cs b/.Deprecated/AlternateIKSystem/IK/WeightManipulators/DeviceControlManipulator.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/WeightManipulators/DeviceControlManipulator.cs rename to .Deprecated/AlternateIKSystem/IK/WeightManipulators/DeviceControlManipulator.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/WeightManipulators/Interface/IWeightManipulator.cs b/.Deprecated/AlternateIKSystem/IK/WeightManipulators/Interface/IWeightManipulator.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/WeightManipulators/Interface/IWeightManipulator.cs rename to .Deprecated/AlternateIKSystem/IK/WeightManipulators/Interface/IWeightManipulator.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/WeightManipulators/TrackingControlManipulator.cs b/.Deprecated/AlternateIKSystem/IK/WeightManipulators/TrackingControlManipulator.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/WeightManipulators/TrackingControlManipulator.cs rename to .Deprecated/AlternateIKSystem/IK/WeightManipulators/TrackingControlManipulator.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/WeightManipulators/WeightManipulatorManager.cs b/.Deprecated/AlternateIKSystem/IK/WeightManipulators/WeightManipulatorManager.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/WeightManipulators/WeightManipulatorManager.cs rename to .Deprecated/AlternateIKSystem/IK/WeightManipulators/WeightManipulatorManager.cs diff --git a/.DepricatedMods/AlternateIKSystem/Integrations/BTKUIAddon.cs b/.Deprecated/AlternateIKSystem/Integrations/BTKUIAddon.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/Integrations/BTKUIAddon.cs rename to .Deprecated/AlternateIKSystem/Integrations/BTKUIAddon.cs diff --git a/.DepricatedMods/AlternateIKSystem/LICENSE.txt b/.Deprecated/AlternateIKSystem/LICENSE.txt similarity index 100% rename from .DepricatedMods/AlternateIKSystem/LICENSE.txt rename to .Deprecated/AlternateIKSystem/LICENSE.txt diff --git a/.DepricatedMods/AlternateIKSystem/Main.cs b/.Deprecated/AlternateIKSystem/Main.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/Main.cs rename to .Deprecated/AlternateIKSystem/Main.cs diff --git a/.DepricatedMods/AlternateIKSystem/ModSettings.cs b/.Deprecated/AlternateIKSystem/ModSettings.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/ModSettings.cs rename to .Deprecated/AlternateIKSystem/ModSettings.cs diff --git a/.DepricatedMods/AlternateIKSystem/Properties/AssemblyInfo.cs b/.Deprecated/AlternateIKSystem/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/Properties/AssemblyInfo.cs rename to .Deprecated/AlternateIKSystem/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/AlternateIKSystem/README.md b/.Deprecated/AlternateIKSystem/README.md similarity index 100% rename from .DepricatedMods/AlternateIKSystem/README.md rename to .Deprecated/AlternateIKSystem/README.md diff --git a/.DepricatedMods/AlternateIKSystem/format.json b/.Deprecated/AlternateIKSystem/format.json similarity index 100% rename from .DepricatedMods/AlternateIKSystem/format.json rename to .Deprecated/AlternateIKSystem/format.json diff --git a/WhereAmIPointing/Main.cs b/.Deprecated/AutoSyncTransforms/Main.cs similarity index 100% rename from WhereAmIPointing/Main.cs rename to .Deprecated/AutoSyncTransforms/Main.cs diff --git a/WhereAmIPointing/Properties/AssemblyInfo.cs b/.Deprecated/AutoSyncTransforms/Properties/AssemblyInfo.cs similarity index 100% rename from WhereAmIPointing/Properties/AssemblyInfo.cs rename to .Deprecated/AutoSyncTransforms/Properties/AssemblyInfo.cs diff --git a/WhereAmIPointing/README.md b/.Deprecated/AutoSyncTransforms/README.md similarity index 100% rename from WhereAmIPointing/README.md rename to .Deprecated/AutoSyncTransforms/README.md diff --git a/WhereAmIPointing/WhereAmIPointing.csproj b/.Deprecated/AutoSyncTransforms/WhereAmIPointing.csproj similarity index 100% rename from WhereAmIPointing/WhereAmIPointing.csproj rename to .Deprecated/AutoSyncTransforms/WhereAmIPointing.csproj diff --git a/WhereAmIPointing/format.json b/.Deprecated/AutoSyncTransforms/format.json similarity index 100% rename from WhereAmIPointing/format.json rename to .Deprecated/AutoSyncTransforms/format.json diff --git a/AvatarScaleMod/AvatarScaleMod.csproj b/.Deprecated/AvatarScaleMod/AvatarScaleMod.csproj similarity index 100% rename from AvatarScaleMod/AvatarScaleMod.csproj rename to .Deprecated/AvatarScaleMod/AvatarScaleMod.csproj diff --git a/AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs similarity index 99% rename from AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs index 38d6a9a..f3c1da4 100644 --- a/AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs +++ b/.Deprecated/AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs @@ -211,7 +211,7 @@ public class AvatarScaleManager : MonoBehaviour public float GetHeight() { if (_localAvatarScaler == null) - return PlayerAvatarPoint.defaultAvatarHeight; + return PlayerAvatarPoint.DefaultAvatarHeight; if (!_localAvatarScaler.IsForcingHeight()) return PlayerSetup.Instance.GetAvatarHeight(); @@ -222,7 +222,7 @@ public class AvatarScaleManager : MonoBehaviour public float GetAnimationClipHeight() { if (_localAvatarScaler == null) - return PlayerAvatarPoint.defaultAvatarHeight; + return PlayerAvatarPoint.DefaultAvatarHeight; if (!_localAvatarScaler.IsForcingHeight()) return PlayerSetup.Instance.GetAvatarHeight(); diff --git a/AvatarScaleMod/AvatarScaling/Components/BaseScaler.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/Components/BaseScaler.cs similarity index 100% rename from AvatarScaleMod/AvatarScaling/Components/BaseScaler.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/Components/BaseScaler.cs diff --git a/AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs similarity index 94% rename from AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs index e6d79f4..7a076d8 100644 --- a/AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs +++ b/.Deprecated/AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs @@ -1,4 +1,5 @@ -using ABI_RC.Core.Player; +using ABI_RC.Core; +using ABI_RC.Core.Player; using ABI_RC.Core.UI; using NAK.AvatarScaleMod.AvatarScaling; using UnityEngine; @@ -72,7 +73,7 @@ public class LocalScaler : BaseScaler } // animation scale changed, record it! - Vector3 scaleDifference = PlayerSetup.DivideVectors(localScale - _initialScale, _initialScale); + Vector3 scaleDifference = CVRTools.DivideVectors(localScale - _initialScale, _initialScale); _animatedScaleFactor = scaleDifference.y; _animatedHeight = (_initialHeight * _animatedScaleFactor) + _initialHeight; _animatedScale = localScale; diff --git a/AvatarScaleMod/AvatarScaling/Components/NetworkScaler.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/Components/NetworkScaler.cs similarity index 100% rename from AvatarScaleMod/AvatarScaling/Components/NetworkScaler.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/Components/NetworkScaler.cs diff --git a/AvatarScaleMod/AvatarScaling/Events/AvatarScaleEvents.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/Events/AvatarScaleEvents.cs similarity index 100% rename from AvatarScaleMod/AvatarScaling/Events/AvatarScaleEvents.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/Events/AvatarScaleEvents.cs diff --git a/AvatarScaleMod/AvatarScaling/ScaledComponents.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/ScaledComponents.cs similarity index 100% rename from AvatarScaleMod/AvatarScaling/ScaledComponents.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/ScaledComponents.cs diff --git a/AvatarScaleMod/HarmonyPatches.cs b/.Deprecated/AvatarScaleMod/HarmonyPatches.cs similarity index 100% rename from AvatarScaleMod/HarmonyPatches.cs rename to .Deprecated/AvatarScaleMod/HarmonyPatches.cs diff --git a/AvatarScaleMod/Input/DebugKeybinds.cs b/.Deprecated/AvatarScaleMod/Input/DebugKeybinds.cs similarity index 100% rename from AvatarScaleMod/Input/DebugKeybinds.cs rename to .Deprecated/AvatarScaleMod/Input/DebugKeybinds.cs diff --git a/AvatarScaleMod/Input/ScaleReconizer.cs b/.Deprecated/AvatarScaleMod/Input/ScaleReconizer.cs similarity index 100% rename from AvatarScaleMod/Input/ScaleReconizer.cs rename to .Deprecated/AvatarScaleMod/Input/ScaleReconizer.cs diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs similarity index 71% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs index 09a5ff4..acf9fab 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs @@ -3,32 +3,32 @@ using BTKUILib; using BTKUILib.UIObjects; using NAK.AvatarScaleMod.AvatarScaling; -namespace NAK.AvatarScaleMod.Integrations -{ - public static partial class BtkUiAddon - { - private static Page _asmRootPage; - private static string _rootPageElementID; +namespace NAK.AvatarScaleMod.Integrations; - public static void Initialize() - { +public static partial class BtkUiAddon +{ + private static Page _asmRootPage; + private static string _rootPageElementID; + + public static void Initialize() + { Prepare_Icons(); Setup_AvatarScaleModTab(); Setup_PlayerSelectPage(); } - #region Initialization + #region Initialization - private static void Prepare_Icons() - { + private static void Prepare_Icons() + { QuickMenuAPI.PrepareIcon(ModSettings.ModName, "ASM_Icon_AvatarHeightConfig", GetIconStream("ASM_Icon_AvatarHeightConfig.png")); QuickMenuAPI.PrepareIcon(ModSettings.ModName, "ASM_Icon_AvatarHeightCopy", GetIconStream("ASM_Icon_AvatarHeightCopy.png")); } - private static void Setup_AvatarScaleModTab() - { + private static void Setup_AvatarScaleModTab() + { _asmRootPage = new Page(ModSettings.ModName, ModSettings.ASM_SettingsCategory, true, "ASM_Icon_AvatarHeightConfig") { MenuTitle = ModSettings.ASM_SettingsCategory, @@ -54,18 +54,18 @@ namespace NAK.AvatarScaleMod.Integrations Setup_DebugOptionsCategory(_asmRootPage); } - #endregion + #endregion - #region Player Count Display + #region Player Count Display - private static void OnWorldLeave() - => UpdatePlayerCountDisplay(); + private static void OnWorldLeave() + => UpdatePlayerCountDisplay(); - private static void OnUserJoinLeave(CVRPlayerEntity _) - => UpdatePlayerCountDisplay(); + private static void OnUserJoinLeave(CVRPlayerEntity _) + => UpdatePlayerCountDisplay(); - private static void UpdatePlayerCountDisplay() - { + private static void UpdatePlayerCountDisplay() + { if (_asmRootPage == null) return; @@ -74,14 +74,14 @@ namespace NAK.AvatarScaleMod.Integrations _asmRootPage.MenuSubtitle = $"Everything Avatar Scaling! :: ({modUserCount}/{playerCount} players using ASM)"; } - #endregion + #endregion - #region Double-Click Reset Height + #region Double-Click Reset Height - private static DateTime lastTime = DateTime.Now; + private static DateTime lastTime = DateTime.Now; - private static void OnTabChange(string newTab, string previousTab) - { + private static void OnTabChange(string newTab, string previousTab) + { if (newTab == _rootPageElementID) { UpdatePlayerCountDisplay(); @@ -95,6 +95,5 @@ namespace NAK.AvatarScaleMod.Integrations lastTime = DateTime.Now; } - #endregion - } + #endregion } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs similarity index 76% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs index 875668c..9ddc1c2 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs @@ -1,11 +1,11 @@ using BTKUILib.UIObjects; -namespace NAK.AvatarScaleMod.Integrations +namespace NAK.AvatarScaleMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon + private static void Setup_AvatarScaleModCategory(Page page) { - private static void Setup_AvatarScaleModCategory(Page page) - { Category avScaleModCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_ASM_SettingsCategory); AddMelonToggle(ref avScaleModCategory, ModSettings.EntryScaleGestureEnabled); @@ -13,5 +13,4 @@ namespace NAK.AvatarScaleMod.Integrations AddMelonToggle(ref avScaleModCategory, ModSettings.EntryPersistentHeight); AddMelonToggle(ref avScaleModCategory, ModSettings.EntryPersistThroughRestart); } - } } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs similarity index 83% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs index 2eb6c57..d3820df 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs @@ -1,12 +1,12 @@ using BTKUILib.UIObjects; using BTKUILib.UIObjects.Components; -namespace NAK.AvatarScaleMod.Integrations +namespace NAK.AvatarScaleMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon + private static void Setup_AvatarScaleToolCategory(Page page) { - private static void Setup_AvatarScaleToolCategory(Page page) - { Category avScaleToolCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_AST_SettingsCategory); AddMelonStringInput(ref avScaleToolCategory, ModSettings.EntryASTScaleParameter, "icon"); @@ -19,5 +19,4 @@ namespace NAK.AvatarScaleMod.Integrations ModSettings.EntryASTMaxHeight.ResetToDefault(); }; } - } } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs similarity index 71% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs index b05dd94..088aafd 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs @@ -1,16 +1,15 @@ using BTKUILib.UIObjects; -namespace NAK.AvatarScaleMod.Integrations +namespace NAK.AvatarScaleMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon + private static void Setup_DebugOptionsCategory(Page page) { - private static void Setup_DebugOptionsCategory(Page page) - { Category debugCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_DEBUG_SettingsCategory); AddMelonToggle(ref debugCategory, ModSettings.Debug_NetworkInbound); AddMelonToggle(ref debugCategory, ModSettings.Debug_NetworkOutbound); AddMelonToggle(ref debugCategory, ModSettings.Debug_ComponentSearchTime); } - } } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs similarity index 83% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs index 216fa48..1437582 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs @@ -4,14 +4,14 @@ using BTKUILib.UIObjects.Components; using NAK.AvatarScaleMod.AvatarScaling; using System.Collections.Generic; // Added for list support -namespace NAK.AvatarScaleMod.Integrations -{ - public static partial class BtkUiAddon - { - private static readonly List USM_QmUiElements = new(); +namespace NAK.AvatarScaleMod.Integrations; - private static void Setup_UniversalScalingSettings(Page page) - { +public static partial class BtkUiAddon +{ + private static readonly List USM_QmUiElements = new(); + + private static void Setup_UniversalScalingSettings(Page page) + { Category uniScalingCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_USM_SettingsCategory); SliderFloat scaleSlider = AddMelonSlider(ref uniScalingCategory, ModSettings.EntryHiddenAvatarHeight, AvatarScaleManager.DefaultMinHeight, AvatarScaleManager.DefaultMaxHeight); @@ -52,24 +52,23 @@ namespace NAK.AvatarScaleMod.Integrations ModSettings.EntryUseUniversalScaling.OnEntryValueChanged.Subscribe((_, newValue) => OnUniversalScalingChanged(newValue)); } - private static void OnUniversalScalingChanged(bool value) - { + private static void OnUniversalScalingChanged(bool value) + { foreach (QMUIElement uiElement in USM_QmUiElements) uiElement.Disabled = !value; } - #region Slider Events + #region Slider Events - private static void OnAvatarHeightSliderChanged(float height) - { + private static void OnAvatarHeightSliderChanged(float height) + { AvatarScaleManager.Instance.SetTargetHeight(height); } - private static void OnAvatarHeightSliderReset() - { + private static void OnAvatarHeightSliderReset() + { AvatarScaleManager.Instance.Setting_UniversalScaling = false; } - #endregion - } + #endregion } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs similarity index 76% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs index c83796d..ab54a69 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs @@ -3,15 +3,15 @@ using BTKUILib.UIObjects; using BTKUILib.UIObjects.Components; using NAK.AvatarScaleMod.AvatarScaling; -namespace NAK.AvatarScaleMod.Integrations +namespace NAK.AvatarScaleMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon - { - private static Button _playerHasModElement; - private static string _selectedPlayer; + private static Button _playerHasModElement; + private static string _selectedPlayer; - private static void Setup_PlayerSelectPage() - { + private static void Setup_PlayerSelectPage() + { QuickMenuAPI.OnPlayerSelected += OnPlayerSelected; Category category = QuickMenuAPI.PlayerSelectPage.AddCategory(ModSettings.ASM_SettingsCategory, ModSettings.ModName); @@ -22,27 +22,27 @@ namespace NAK.AvatarScaleMod.Integrations button.OnPress += OnCopyPlayerHeight; } - #region QM Events + #region QM Events - private static void OnPlayerSelected(string _, string id) - { + private static void OnPlayerSelected(string _, string id) + { _selectedPlayer = id; UpdatePlayerHasModIcon(); } - private static void OnCopyPlayerHeight() - { + private static void OnCopyPlayerHeight() + { float networkHeight = AvatarScaleManager.Instance.GetNetworkHeight(_selectedPlayer); if (networkHeight < 0) return; AvatarScaleManager.Instance.SetTargetHeight(networkHeight); } - #endregion + #endregion - #region Private Methods + #region Private Methods - private static void UpdatePlayerHasModIcon() - { + private static void UpdatePlayerHasModIcon() + { if (_playerHasModElement == null) return; @@ -60,6 +60,5 @@ namespace NAK.AvatarScaleMod.Integrations } } - #endregion - } + #endregion } \ No newline at end of file diff --git a/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs new file mode 100644 index 0000000..9c9eb20 --- /dev/null +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs @@ -0,0 +1,77 @@ +using System.Reflection; +using BTKUILib; +using BTKUILib.UIObjects; +using BTKUILib.UIObjects.Components; +using MelonLoader; +using UnityEngine; + +namespace NAK.AvatarScaleMod.Integrations; + +public static partial class BtkUiAddon +{ + #region Melon Preference Helpers + + private static ToggleButton AddMelonToggle(ref Category category, MelonPreferences_Entry entry) + { + ToggleButton toggle = category.AddToggle(entry.DisplayName, entry.Description, entry.Value); + toggle.OnValueUpdated += b => entry.Value = b; + return toggle; + } + + private static SliderFloat AddMelonSlider(ref Category category, MelonPreferences_Entry entry, float min, + float max, int decimalPlaces = 2, bool allowReset = true) + { + SliderFloat slider = category.AddSlider(entry.DisplayName, entry.Description, + Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset); + slider.OnValueUpdated += f => entry.Value = f; + return slider; + } + + private static Button AddMelonStringInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) + { + Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); + button.OnPress += () => QuickMenuAPI.OpenKeyboard(entry.Value, s => entry.Value = s); + return button; + } + + private static Button AddMelonNumberInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) + { + Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); + button.OnPress += () => QuickMenuAPI.OpenNumberInput(entry.DisplayName, entry.Value, f => entry.Value = f); + return button; + } + + // private static SliderFloat AddMelonSlider(ref Page page, MelonPreferences_Entry entry, float min, float max, int decimalPlaces = 2, bool allowReset = true) + // { + // SliderFloat slider = page.AddSlider(entry.DisplayName, entry.Description, Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset); + // slider.OnValueUpdated += f => entry.Value = f; + // return slider; + // } + + /// + /// Helper method to create a category that saves its collapsed state to a MelonPreferences entry. + /// + /// + /// + /// + /// + private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry entry, bool showHeader = true) + { + Category category = page.AddCategory(entry.DisplayName, showHeader, true, entry.Value); + category.OnCollapse += b => entry.Value = b; + return category; + } + + #endregion + + #region Icon Utils + + private static Stream GetIconStream(string iconName) + { + Assembly assembly = Assembly.GetExecutingAssembly(); + string assemblyName = assembly.GetName().Name; + return assembly.GetManifestResourceStream($"{assemblyName}.resources.{iconName}"); + } + + #endregion +} \ No newline at end of file diff --git a/AvatarScaleMod/Main.cs b/.Deprecated/AvatarScaleMod/Main.cs similarity index 100% rename from AvatarScaleMod/Main.cs rename to .Deprecated/AvatarScaleMod/Main.cs diff --git a/AvatarScaleMod/ModSettings.cs b/.Deprecated/AvatarScaleMod/ModSettings.cs similarity index 100% rename from AvatarScaleMod/ModSettings.cs rename to .Deprecated/AvatarScaleMod/ModSettings.cs diff --git a/AvatarScaleMod/Networking/ModNetwork.cs b/.Deprecated/AvatarScaleMod/Networking/ModNetwork.cs similarity index 100% rename from AvatarScaleMod/Networking/ModNetwork.cs rename to .Deprecated/AvatarScaleMod/Networking/ModNetwork.cs diff --git a/AvatarScaleMod/Properties/AssemblyInfo.cs b/.Deprecated/AvatarScaleMod/Properties/AssemblyInfo.cs similarity index 100% rename from AvatarScaleMod/Properties/AssemblyInfo.cs rename to .Deprecated/AvatarScaleMod/Properties/AssemblyInfo.cs diff --git a/AvatarScaleMod/README.md b/.Deprecated/AvatarScaleMod/README.md similarity index 100% rename from AvatarScaleMod/README.md rename to .Deprecated/AvatarScaleMod/README.md diff --git a/AvatarScaleMod/Scripts.cs b/.Deprecated/AvatarScaleMod/Scripts.cs similarity index 83% rename from AvatarScaleMod/Scripts.cs rename to .Deprecated/AvatarScaleMod/Scripts.cs index 5980b65..16d7319 100644 --- a/AvatarScaleMod/Scripts.cs +++ b/.Deprecated/AvatarScaleMod/Scripts.cs @@ -3,12 +3,12 @@ using System.IO; using System.Reflection; // https://github.com/SDraw/ml_mods_cvr/blob/master/ml_amt/Scripts.cs -namespace NAK.AvatarScaleMod +namespace NAK.AvatarScaleMod; + +static class Scripts { - static class Scripts + public static string GetEmbeddedScript(string p_name) { - public static string GetEmbeddedScript(string p_name) - { string l_result = ""; Assembly l_assembly = Assembly.GetExecutingAssembly(); string l_assemblyName = l_assembly.GetName().Name; @@ -23,5 +23,4 @@ namespace NAK.AvatarScaleMod return l_result; } - } } \ No newline at end of file diff --git a/.DepricatedMods/InteractionTest/format.json b/.Deprecated/AvatarScaleMod/format.json similarity index 100% rename from .DepricatedMods/InteractionTest/format.json rename to .Deprecated/AvatarScaleMod/format.json diff --git a/AvatarScaleMod/resources/ASM_Icon_AvatarHeightConfig.png b/.Deprecated/AvatarScaleMod/resources/ASM_Icon_AvatarHeightConfig.png similarity index 100% rename from AvatarScaleMod/resources/ASM_Icon_AvatarHeightConfig.png rename to .Deprecated/AvatarScaleMod/resources/ASM_Icon_AvatarHeightConfig.png diff --git a/AvatarScaleMod/resources/ASM_Icon_AvatarHeightCopy.png b/.Deprecated/AvatarScaleMod/resources/ASM_Icon_AvatarHeightCopy.png similarity index 100% rename from AvatarScaleMod/resources/ASM_Icon_AvatarHeightCopy.png rename to .Deprecated/AvatarScaleMod/resources/ASM_Icon_AvatarHeightCopy.png diff --git a/AvatarScaleMod/resources/menu.js b/.Deprecated/AvatarScaleMod/resources/menu.js similarity index 100% rename from AvatarScaleMod/resources/menu.js rename to .Deprecated/AvatarScaleMod/resources/menu.js diff --git a/.DepricatedMods/BadAnimatorFix/BadAnimatorFix.csproj b/.Deprecated/BadAnimatorFix/BadAnimatorFix.csproj similarity index 100% rename from .DepricatedMods/BadAnimatorFix/BadAnimatorFix.csproj rename to .Deprecated/BadAnimatorFix/BadAnimatorFix.csproj diff --git a/.DepricatedMods/BadAnimatorFix/BadAnimatorFixManager.cs b/.Deprecated/BadAnimatorFix/BadAnimatorFixManager.cs similarity index 100% rename from .DepricatedMods/BadAnimatorFix/BadAnimatorFixManager.cs rename to .Deprecated/BadAnimatorFix/BadAnimatorFixManager.cs diff --git a/.DepricatedMods/BadAnimatorFix/BadAnimatorFixer.cs b/.Deprecated/BadAnimatorFix/BadAnimatorFixer.cs similarity index 100% rename from .DepricatedMods/BadAnimatorFix/BadAnimatorFixer.cs rename to .Deprecated/BadAnimatorFix/BadAnimatorFixer.cs diff --git a/.DepricatedMods/BadAnimatorFix/HarmonyPatches.cs b/.Deprecated/BadAnimatorFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/BadAnimatorFix/HarmonyPatches.cs rename to .Deprecated/BadAnimatorFix/HarmonyPatches.cs diff --git a/.DepricatedMods/BadAnimatorFix/Main.cs b/.Deprecated/BadAnimatorFix/Main.cs similarity index 100% rename from .DepricatedMods/BadAnimatorFix/Main.cs rename to .Deprecated/BadAnimatorFix/Main.cs diff --git a/.DepricatedMods/BadAnimatorFix/Properties/AssemblyInfo.cs b/.Deprecated/BadAnimatorFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/BadAnimatorFix/Properties/AssemblyInfo.cs rename to .Deprecated/BadAnimatorFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/BadAnimatorFix/format.json b/.Deprecated/BadAnimatorFix/format.json similarity index 100% rename from .DepricatedMods/BadAnimatorFix/format.json rename to .Deprecated/BadAnimatorFix/format.json diff --git a/.DepricatedMods/Blackout/AssetHandler.cs b/.Deprecated/Blackout/AssetHandler.cs similarity index 100% rename from .DepricatedMods/Blackout/AssetHandler.cs rename to .Deprecated/Blackout/AssetHandler.cs diff --git a/.DepricatedMods/Blackout/Blackout.csproj b/.Deprecated/Blackout/Blackout.csproj similarity index 100% rename from .DepricatedMods/Blackout/Blackout.csproj rename to .Deprecated/Blackout/Blackout.csproj diff --git a/.DepricatedMods/Blackout/BlackoutController.cs b/.Deprecated/Blackout/BlackoutController.cs similarity index 100% rename from .DepricatedMods/Blackout/BlackoutController.cs rename to .Deprecated/Blackout/BlackoutController.cs diff --git a/.DepricatedMods/Blackout/HarmonyPatches.cs b/.Deprecated/Blackout/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/Blackout/HarmonyPatches.cs rename to .Deprecated/Blackout/HarmonyPatches.cs diff --git a/.DepricatedMods/Blackout/Integrations/BTKUIAddon.cs b/.Deprecated/Blackout/Integrations/BTKUIAddon.cs similarity index 100% rename from .DepricatedMods/Blackout/Integrations/BTKUIAddon.cs rename to .Deprecated/Blackout/Integrations/BTKUIAddon.cs diff --git a/.DepricatedMods/Blackout/Integrations/UIExpansionKitAddon.cs b/.Deprecated/Blackout/Integrations/UIExpansionKitAddon.cs similarity index 100% rename from .DepricatedMods/Blackout/Integrations/UIExpansionKitAddon.cs rename to .Deprecated/Blackout/Integrations/UIExpansionKitAddon.cs diff --git a/.DepricatedMods/Blackout/Main.cs b/.Deprecated/Blackout/Main.cs similarity index 100% rename from .DepricatedMods/Blackout/Main.cs rename to .Deprecated/Blackout/Main.cs diff --git a/.DepricatedMods/Blackout/Properties/AssemblyInfo.cs b/.Deprecated/Blackout/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/Blackout/Properties/AssemblyInfo.cs rename to .Deprecated/Blackout/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/Blackout/Resource1.Designer.cs b/.Deprecated/Blackout/Resource1.Designer.cs similarity index 100% rename from .DepricatedMods/Blackout/Resource1.Designer.cs rename to .Deprecated/Blackout/Resource1.Designer.cs diff --git a/.DepricatedMods/Blackout/Resource1.resx b/.Deprecated/Blackout/Resource1.resx similarity index 100% rename from .DepricatedMods/Blackout/Resource1.resx rename to .Deprecated/Blackout/Resource1.resx diff --git a/.DepricatedMods/Blackout/format.json b/.Deprecated/Blackout/format.json similarity index 100% rename from .DepricatedMods/Blackout/format.json rename to .Deprecated/Blackout/format.json diff --git a/.DepricatedMods/Blackout/resources/blackout_controller.asset b/.Deprecated/Blackout/resources/blackout_controller.asset similarity index 100% rename from .DepricatedMods/Blackout/resources/blackout_controller.asset rename to .Deprecated/Blackout/resources/blackout_controller.asset diff --git a/BullshitWatcher/BullshitWatcher.csproj b/.Deprecated/BullshitWatcher/BullshitWatcher.csproj similarity index 100% rename from BullshitWatcher/BullshitWatcher.csproj rename to .Deprecated/BullshitWatcher/BullshitWatcher.csproj diff --git a/BullshitWatcher/Main.cs b/.Deprecated/BullshitWatcher/Main.cs similarity index 100% rename from BullshitWatcher/Main.cs rename to .Deprecated/BullshitWatcher/Main.cs diff --git a/BullshitWatcher/Properties/AssemblyInfo.cs b/.Deprecated/BullshitWatcher/Properties/AssemblyInfo.cs similarity index 100% rename from BullshitWatcher/Properties/AssemblyInfo.cs rename to .Deprecated/BullshitWatcher/Properties/AssemblyInfo.cs diff --git a/CVRGizmos/CVRGizmoManager.cs b/.Deprecated/CVRGizmos/CVRGizmoManager.cs similarity index 76% rename from CVRGizmos/CVRGizmoManager.cs rename to .Deprecated/CVRGizmos/CVRGizmoManager.cs index fd03eb0..b1d55b5 100644 --- a/CVRGizmos/CVRGizmoManager.cs +++ b/.Deprecated/CVRGizmos/CVRGizmoManager.cs @@ -2,18 +2,18 @@ using UnityEngine; using Gizmos = Popcron.Gizmos; -namespace NAK.CVRGizmos +namespace NAK.CVRGizmos; + +public class CVRGizmoManager : MonoBehaviour { - public class CVRGizmoManager : MonoBehaviour - { - public static CVRGizmoManager Instance; + public static CVRGizmoManager Instance; - public bool g_enabled = false; - public bool g_localOnly = false; + public bool g_enabled = false; + public bool g_localOnly = false; - public MonoBehaviour[] managed; + public MonoBehaviour[] managed; - public System.Type[] GizmoTypes = { + public System.Type[] GizmoTypes = { typeof(CVRGizmos_Pointer), typeof(CVRGizmos_AdvancedAvatarSettingsTrigger), typeof(CVRGizmos_SpawnableTrigger), @@ -30,8 +30,8 @@ namespace NAK.CVRGizmos typeof(CVRGizmos_CapsuleCollider), }; - private void Start() - { + private void Start() + { CVRGizmoManager.Instance = this; managed = new MonoBehaviour[GizmoTypes.Count()]; for (int i = 0; i < GizmoTypes.Count(); i++) @@ -40,8 +40,8 @@ namespace NAK.CVRGizmos } } - public void EnableGizmos(bool able) - { + public void EnableGizmos(bool able) + { for (int i = 0; i < GizmoTypes.Count(); i++) { managed[i].enabled = able; @@ -50,12 +50,11 @@ namespace NAK.CVRGizmos RefreshGizmos(); } - public void RefreshGizmos() - { + public void RefreshGizmos() + { for (int i = 0; i < GizmoTypes.Count(); i++) { managed[i].Invoke("CacheGizmos", 0f); } } - } } \ No newline at end of file diff --git a/CVRGizmos/CVRGizmos.csproj b/.Deprecated/CVRGizmos/CVRGizmos.csproj similarity index 100% rename from CVRGizmos/CVRGizmos.csproj rename to .Deprecated/CVRGizmos/CVRGizmos.csproj diff --git a/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsPointer.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsPointer.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsPointer.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsPointer.cs diff --git a/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsTrigger.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsTrigger.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsTrigger.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsTrigger.cs diff --git a/CVRGizmos/GizmoTypes/CVRAvatar.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRAvatar.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRAvatar.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRAvatar.cs diff --git a/CVRGizmos/GizmoTypes/CVRAvatarPickupMarker.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRAvatarPickupMarker.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRAvatarPickupMarker.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRAvatarPickupMarker.cs diff --git a/CVRGizmos/GizmoTypes/CVRDistanceConstrain.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRDistanceConstrain.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRDistanceConstrain.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRDistanceConstrain.cs diff --git a/CVRGizmos/GizmoTypes/CVRDistanceLod.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRDistanceLod.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRDistanceLod.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRDistanceLod.cs diff --git a/CVRGizmos/GizmoTypes/CVRGizmoBase.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRGizmoBase.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRGizmoBase.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRGizmoBase.cs diff --git a/CVRGizmos/GizmoTypes/CVRHapticAreaChest.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRHapticAreaChest.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRHapticAreaChest.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRHapticAreaChest.cs diff --git a/CVRGizmos/GizmoTypes/CVRHapticZone.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRHapticZone.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRHapticZone.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRHapticZone.cs diff --git a/CVRGizmos/GizmoTypes/CVRPointer.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRPointer.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRPointer.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRPointer.cs diff --git a/CVRGizmos/GizmoTypes/CVRSpawnableTrigger.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRSpawnableTrigger.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRSpawnableTrigger.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRSpawnableTrigger.cs diff --git a/CVRGizmos/GizmoTypes/CVRToggleStateTrigger.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRToggleStateTrigger.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRToggleStateTrigger.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRToggleStateTrigger.cs diff --git a/CVRGizmos/GizmoTypes/Unity_BoxCollider.cs b/.Deprecated/CVRGizmos/GizmoTypes/Unity_BoxCollider.cs similarity index 100% rename from CVRGizmos/GizmoTypes/Unity_BoxCollider.cs rename to .Deprecated/CVRGizmos/GizmoTypes/Unity_BoxCollider.cs diff --git a/CVRGizmos/GizmoTypes/Unity_CapsuleCollider.cs b/.Deprecated/CVRGizmos/GizmoTypes/Unity_CapsuleCollider.cs similarity index 100% rename from CVRGizmos/GizmoTypes/Unity_CapsuleCollider.cs rename to .Deprecated/CVRGizmos/GizmoTypes/Unity_CapsuleCollider.cs diff --git a/CVRGizmos/GizmoTypes/Unity_SphereCollider.cs b/.Deprecated/CVRGizmos/GizmoTypes/Unity_SphereCollider.cs similarity index 100% rename from CVRGizmos/GizmoTypes/Unity_SphereCollider.cs rename to .Deprecated/CVRGizmos/GizmoTypes/Unity_SphereCollider.cs diff --git a/CVRGizmos/Main.cs b/.Deprecated/CVRGizmos/Main.cs similarity index 100% rename from CVRGizmos/Main.cs rename to .Deprecated/CVRGizmos/Main.cs diff --git a/.Deprecated/CVRGizmos/Popcron.Gizmos/Constants.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Constants.cs new file mode 100644 index 0000000..56f8ef4 --- /dev/null +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Constants.cs @@ -0,0 +1,7 @@ +namespace Popcron; + +public class Constants +{ + public const string UniqueIdentifier = "Popcron.Gizmos"; + public const string EnabledKey = UniqueIdentifier + ".Enabled"; +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Drawer.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawer.cs similarity index 86% rename from CVRGizmos/Popcron.Gizmos/Drawer.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/Drawer.cs index 8e42ae8..729445f 100644 --- a/CVRGizmos/Popcron.Gizmos/Drawer.cs +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawer.cs @@ -1,21 +1,21 @@ using System.Reflection; using UnityEngine; -namespace Popcron +namespace Popcron; + +public abstract class Drawer { - public abstract class Drawer + private static Dictionary typeToDrawer = null; + + public abstract int Draw(ref Vector3[] buffer, params object[] args); + + public Drawer() { - private static Dictionary typeToDrawer = null; - - public abstract int Draw(ref Vector3[] buffer, params object[] args); - - public Drawer() - { } - public static Drawer Get() where T : class - { + public static Drawer Get() where T : class + { //find all drawers if (typeToDrawer == null) { @@ -64,5 +64,4 @@ namespace Popcron return null; } } - } -} +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs similarity index 93% rename from CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs index 478a0b6..78ab2bf 100644 --- a/CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs @@ -1,16 +1,16 @@ using UnityEngine; -namespace Popcron +namespace Popcron; + +public class CubeDrawer : Drawer { - public class CubeDrawer : Drawer + public CubeDrawer() { - public CubeDrawer() - { } - public override int Draw(ref Vector3[] buffer, params object[] values) - { + public override int Draw(ref Vector3[] buffer, params object[] values) + { Vector3 position = (Vector3)values[0]; Quaternion rotation = (Quaternion)values[1]; Vector3 size = (Vector3)values[2]; @@ -92,5 +92,4 @@ namespace Popcron return 24; } - } -} +} \ No newline at end of file diff --git a/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs new file mode 100644 index 0000000..0f17498 --- /dev/null +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +namespace Popcron; + +public class LineDrawer : Drawer +{ + public LineDrawer() + { + + } + + public override int Draw(ref Vector3[] buffer, params object[] args) + { + buffer[0] = (Vector3)args[0]; + buffer[1] = (Vector3)args[1]; + return 2; + } +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs similarity index 84% rename from CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs index ad3b1b2..ab66d29 100644 --- a/CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs @@ -1,16 +1,16 @@ using UnityEngine; -namespace Popcron +namespace Popcron; + +public class PolygonDrawer : Drawer { - public class PolygonDrawer : Drawer + public PolygonDrawer() { - public PolygonDrawer() - { } - public override int Draw(ref Vector3[] buffer, params object[] values) - { + public override int Draw(ref Vector3[] buffer, params object[] values) + { Vector3 position = (Vector3)values[0]; int points = (int)values[1]; float radius = (float)values[2]; @@ -36,5 +36,4 @@ namespace Popcron return points * 2; } - } -} +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs similarity index 89% rename from CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs index c46160a..7b0643d 100644 --- a/CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs @@ -1,16 +1,16 @@ using UnityEngine; -namespace Popcron +namespace Popcron; + +public class SquareDrawer : Drawer { - public class SquareDrawer : Drawer + public SquareDrawer() { - public SquareDrawer() - { } - public override int Draw(ref Vector3[] buffer, params object[] values) - { + public override int Draw(ref Vector3[] buffer, params object[] values) + { Vector2 position = default; if (values[0] is Vector2 p2) { @@ -68,5 +68,4 @@ namespace Popcron return 8; } - } -} +} \ No newline at end of file diff --git a/.Deprecated/CVRGizmos/Popcron.Gizmos/Element.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Element.cs new file mode 100644 index 0000000..1ea97d5 --- /dev/null +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Element.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +namespace Popcron; + +internal class Element +{ + public Vector3[] points = { }; + public Color color = Color.white; + public bool dashed = false; + public Matrix4x4 matrix = Matrix4x4.identity; +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Gizmos.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Gizmos.cs similarity index 52% rename from CVRGizmos/Popcron.Gizmos/Gizmos.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/Gizmos.cs index a897991..cf86940 100644 --- a/CVRGizmos/Popcron.Gizmos/Gizmos.cs +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Gizmos.cs @@ -1,29 +1,29 @@ using UnityEngine; -namespace Popcron +namespace Popcron; + +public class Gizmos { - public class Gizmos + private static string _prefsKey = null; + private static int? _bufferSize = null; + private static bool? _enabled = null; + private static float? _dashGap = null; + private static bool? _cull = null; + private static int? _pass = null; + private static Vector3? _offset = null; + + private static Vector3[] buffer = new Vector3[BufferSize]; + + /// + /// By default, it will always render to scene view camera and the main camera. + /// Subscribing to this allows you to whitelist your custom cameras. + /// + public static Func CameraFilter = cam => false; + + private static string PrefsKey { - private static string _prefsKey = null; - private static int? _bufferSize = null; - private static bool? _enabled = null; - private static float? _dashGap = null; - private static bool? _cull = null; - private static int? _pass = null; - private static Vector3? _offset = null; - - private static Vector3[] buffer = new Vector3[BufferSize]; - - /// - /// By default, it will always render to scene view camera and the main camera. - /// Subscribing to this allows you to whitelist your custom cameras. - /// - public static Func CameraFilter = cam => false; - - private static string PrefsKey + get { - get - { if (string.IsNullOrEmpty(_prefsKey)) { _prefsKey = $"{SystemInfo.deviceUniqueIdentifier}.{Application.companyName}.{Application.productName}.{Constants.UniqueIdentifier}"; @@ -31,34 +31,34 @@ namespace Popcron return _prefsKey; } - } + } - /// - /// The matrix to use. - /// - public static Matrix4x4 Matrix - { - get => GizmosInstance.Matrix; - set => GizmosInstance.Matrix = value; - } + /// + /// The matrix to use. + /// + public static Matrix4x4 Matrix + { + get => GizmosInstance.Matrix; + set => GizmosInstance.Matrix = value; + } - /// - /// The matrix to use. - /// - public static Color Color - { - get => GizmosInstance.Color; - set => GizmosInstance.Color = value; - } + /// + /// The matrix to use. + /// + public static Color Color + { + get => GizmosInstance.Color; + set => GizmosInstance.Color = value; + } - /// - /// The size of the total gizmos buffer. - /// Default is 4096. - /// - public static int BufferSize + /// + /// The size of the total gizmos buffer. + /// Default is 4096. + /// + public static int BufferSize + { + get { - get - { if (_bufferSize == null) { _bufferSize = PlayerPrefs.GetInt($"{PrefsKey}.BufferSize", 4096); @@ -66,8 +66,8 @@ namespace Popcron return _bufferSize.Value; } - set - { + set + { value = Mathf.Clamp(value, 0, int.MaxValue); if (_bufferSize != value) { @@ -78,15 +78,15 @@ namespace Popcron buffer = new Vector3[value]; } } - } + } - /// - /// Toggles wether the gizmos could be drawn or not. - /// - public static bool Enabled + /// + /// Toggles wether the gizmos could be drawn or not. + /// + public static bool Enabled + { + get { - get - { if (_enabled == null) { _enabled = PlayerPrefs.GetInt($"{PrefsKey}.Enabled", 1) == 1; @@ -94,24 +94,24 @@ namespace Popcron return _enabled.Value; } - set - { + set + { if (_enabled != value) { _enabled = value; PlayerPrefs.SetInt($"{PrefsKey}.Enabled", value ? 1 : 0); } } - } + } - /// - /// The size of the gap when drawing dashed elements. - /// Default gap size is 0.1 - /// - public static float DashGap + /// + /// The size of the gap when drawing dashed elements. + /// Default gap size is 0.1 + /// + public static float DashGap + { + get { - get - { if (_dashGap == null) { _dashGap = PlayerPrefs.GetFloat($"{PrefsKey}.DashGap", 0.1f); @@ -119,46 +119,46 @@ namespace Popcron return _dashGap.Value; } - set - { + set + { if (_dashGap != value) { _dashGap = value; PlayerPrefs.SetFloat($"{PrefsKey}.DashGap", value); } } - } + } - [Obsolete("This property is obsolete. Use FrustumCulling instead.", false)] - public static bool Cull + [Obsolete("This property is obsolete. Use FrustumCulling instead.", false)] + public static bool Cull + { + get { - get - { return FrustumCulling; } - set - { + set + { FrustumCulling = value; } - } + } - [Obsolete("This property is obsolete. Subscribe to CameraFilter predicate instead and return true for your custom camera.", false)] - public static Camera Camera + [Obsolete("This property is obsolete. Subscribe to CameraFilter predicate instead and return true for your custom camera.", false)] + public static Camera Camera + { + get => null; + set { - get => null; - set - { } - } + } - /// - /// Should the camera not draw elements that are not visible? - /// - public static bool FrustumCulling + /// + /// Should the camera not draw elements that are not visible? + /// + public static bool FrustumCulling + { + get { - get - { if (_cull == null) { _cull = PlayerPrefs.GetInt($"{PrefsKey}.FrustumCulling", 1) == 1; @@ -166,32 +166,32 @@ namespace Popcron return _cull.Value; } - set - { + set + { if (_cull != value) { _cull = value; PlayerPrefs.SetInt($"{PrefsKey}.FrustumCulling", value ? 1 : 0); } } - } + } - /// - /// The material being used to render. - /// - public static Material Material - { - get => GizmosInstance.Material; - set => GizmosInstance.Material = value; - } + /// + /// The material being used to render. + /// + public static Material Material + { + get => GizmosInstance.Material; + set => GizmosInstance.Material = value; + } - /// - /// Rendering pass to activate. - /// - public static int Pass + /// + /// Rendering pass to activate. + /// + public static int Pass + { + get { - get - { if (_pass == null) { _pass = PlayerPrefs.GetInt($"{PrefsKey}.Pass", 0); @@ -199,23 +199,23 @@ namespace Popcron return _pass.Value; } - set - { + set + { if (_pass != value) { _pass = value; PlayerPrefs.SetInt($"{PrefsKey}.Pass", value); } } - } + } - /// - /// Global offset for all points. Default is (0, 0, 0). - /// - public static Vector3 Offset + /// + /// Global offset for all points. Default is (0, 0, 0). + /// + public static Vector3 Offset + { + get { - get - { const string Delim = ","; if (_offset == null) { @@ -235,8 +235,8 @@ namespace Popcron return _offset.Value; } - set - { + set + { const string Delim = ","; if (_offset != value) { @@ -244,13 +244,13 @@ namespace Popcron PlayerPrefs.SetString($"{PrefsKey}.Offset", value.x + Delim + value.y + Delim + value.y); } } - } + } - /// - /// Draws an element onto the screen. - /// - public static void Draw(Color? color, bool dashed, params object[] args) where T : Drawer - { + /// + /// Draws an element onto the screen. + /// + public static void Draw(Color? color, bool dashed, params object[] args) where T : Drawer + { if (!Enabled) { return; @@ -268,11 +268,11 @@ namespace Popcron } } - /// - /// Draws an array of lines. Useful for things like paths. - /// - public static void Lines(Vector3[] lines, Color? color = null, bool dashed = false) - { + /// + /// Draws an array of lines. Useful for things like paths. + /// + public static void Lines(Vector3[] lines, Color? color = null, bool dashed = false) + { if (!Enabled) { return; @@ -281,69 +281,69 @@ namespace Popcron GizmosInstance.Submit(lines, color, dashed); } - /// - /// Draw line in world space. - /// - public static void Line(Vector3 a, Vector3 b, Color? color = null, bool dashed = false) - { + /// + /// Draw line in world space. + /// + public static void Line(Vector3 a, Vector3 b, Color? color = null, bool dashed = false) + { Draw(color, dashed, a, b); } - /// - /// Draw square in world space. - /// - public static void Square(Vector2 position, Vector2 size, Color? color = null, bool dashed = false) - { + /// + /// Draw square in world space. + /// + public static void Square(Vector2 position, Vector2 size, Color? color = null, bool dashed = false) + { Square(position, Quaternion.identity, size, color, dashed); } - /// - /// Draw square in world space with float diameter parameter. - /// - public static void Square(Vector2 position, float diameter, Color? color = null, bool dashed = false) - { + /// + /// Draw square in world space with float diameter parameter. + /// + public static void Square(Vector2 position, float diameter, Color? color = null, bool dashed = false) + { Square(position, Quaternion.identity, Vector2.one * diameter, color, dashed); } - /// - /// Draw square in world space with a rotation parameter. - /// - public static void Square(Vector2 position, Quaternion rotation, Vector2 size, Color? color = null, bool dashed = false) - { + /// + /// Draw square in world space with a rotation parameter. + /// + public static void Square(Vector2 position, Quaternion rotation, Vector2 size, Color? color = null, bool dashed = false) + { Draw(color, dashed, position, rotation, size); } - /// - /// Draws a cube in world space. - /// - public static void Cube(Vector3 position, Quaternion rotation, Vector3 size, Color? color = null, bool dashed = false) - { + /// + /// Draws a cube in world space. + /// + public static void Cube(Vector3 position, Quaternion rotation, Vector3 size, Color? color = null, bool dashed = false) + { Draw(color, dashed, position, rotation, size); } - /// - /// Draws a rectangle in screen space. - /// - public static void Rect(Rect rect, Camera camera, Color? color = null, bool dashed = false) - { + /// + /// Draws a rectangle in screen space. + /// + public static void Rect(Rect rect, Camera camera, Color? color = null, bool dashed = false) + { rect.y = Screen.height - rect.y; Vector2 corner = camera.ScreenToWorldPoint(new Vector2(rect.x, rect.y - rect.height)); Draw(color, dashed, corner + rect.size * 0.5f, Quaternion.identity, rect.size); } - /// - /// Draws a representation of a bounding box. - /// - public static void Bounds(Bounds bounds, Color? color = null, bool dashed = false) - { + /// + /// Draws a representation of a bounding box. + /// + public static void Bounds(Bounds bounds, Color? color = null, bool dashed = false) + { Draw(color, dashed, bounds.center, Quaternion.identity, bounds.size); } - /// - /// Draws a cone similar to the one that spot lights draw. - /// - public static void Cone(Vector3 position, Quaternion rotation, float length, float angle, Color? color = null, bool dashed = false, int pointsCount = 16) - { + /// + /// Draws a cone similar to the one that spot lights draw. + /// + public static void Cone(Vector3 position, Quaternion rotation, float length, float angle, Color? color = null, bool dashed = false, int pointsCount = 16) + { //draw the end of the cone float endAngle = Mathf.Tan(angle * 0.5f * Mathf.Deg2Rad) * length; Vector3 forward = rotation * Vector3.forward; @@ -360,34 +360,33 @@ namespace Popcron } } - /// - /// Draws a sphere at position with specified radius. - /// - public static void Sphere(Vector3 position, float radius, Color? color = null, bool dashed = false, int pointsCount = 16) - { + /// + /// Draws a sphere at position with specified radius. + /// + public static void Sphere(Vector3 position, float radius, Color? color = null, bool dashed = false, int pointsCount = 16) + { float offset = 0f; Draw(color, dashed, position, pointsCount, radius, offset, Quaternion.Euler(0f, 0f, 0f)); Draw(color, dashed, position, pointsCount, radius, offset, Quaternion.Euler(90f, 0f, 0f)); Draw(color, dashed, position, pointsCount, radius, offset, Quaternion.Euler(0f, 90f, 90f)); } - /// - /// Draws a circle in world space and billboards towards the camera. - /// - public static void Circle(Vector3 position, float radius, Camera camera, Color? color = null, bool dashed = false, int pointsCount = 16) - { + /// + /// Draws a circle in world space and billboards towards the camera. + /// + public static void Circle(Vector3 position, float radius, Camera camera, Color? color = null, bool dashed = false, int pointsCount = 16) + { float offset = 0f; Quaternion rotation = Quaternion.LookRotation(position - camera.transform.position); Draw(color, dashed, position, pointsCount, radius, offset, rotation); } - /// - /// Draws a circle in world space with a specified rotation. - /// - public static void Circle(Vector3 position, float radius, Quaternion rotation, Color? color = null, bool dashed = false, int pointsCount = 16) - { + /// + /// Draws a circle in world space with a specified rotation. + /// + public static void Circle(Vector3 position, float radius, Quaternion rotation, Color? color = null, bool dashed = false, int pointsCount = 16) + { float offset = 0f; Draw(color, dashed, position, pointsCount, radius, offset, rotation); } - } -} +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/GizmosInstance.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/GizmosInstance.cs similarity index 100% rename from CVRGizmos/Popcron.Gizmos/GizmosInstance.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/GizmosInstance.cs diff --git a/CVRGizmos/Popcron.Gizmos/LICENSE.md b/.Deprecated/CVRGizmos/Popcron.Gizmos/LICENSE.md similarity index 100% rename from CVRGizmos/Popcron.Gizmos/LICENSE.md rename to .Deprecated/CVRGizmos/Popcron.Gizmos/LICENSE.md diff --git a/CVRGizmos/Properties/AssemblyInfo.cs b/.Deprecated/CVRGizmos/Properties/AssemblyInfo.cs similarity index 100% rename from CVRGizmos/Properties/AssemblyInfo.cs rename to .Deprecated/CVRGizmos/Properties/AssemblyInfo.cs diff --git a/CVRGizmos/format.json b/.Deprecated/CVRGizmos/format.json similarity index 100% rename from CVRGizmos/format.json rename to .Deprecated/CVRGizmos/format.json diff --git a/SmartReticle/SmartReticle.csproj b/.Deprecated/CameraExperiments/CameraExperiments.csproj similarity index 100% rename from SmartReticle/SmartReticle.csproj rename to .Deprecated/CameraExperiments/CameraExperiments.csproj diff --git a/.Deprecated/CameraExperiments/Main.cs b/.Deprecated/CameraExperiments/Main.cs new file mode 100644 index 0000000..51035fd --- /dev/null +++ b/.Deprecated/CameraExperiments/Main.cs @@ -0,0 +1,170 @@ +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using HarmonyLib; +using MagicaCloth2; +using MelonLoader; +using Unity.Burst; +using Unity.Collections; +using Unity.Jobs; +using UnityEngine; + +namespace NAK.WhereAmIPointing; + +public class WhereAmIPointingMod : MelonMod +{ + #region Melon Preferences + + // cannot disable because then id need extra logic to reset the alpha :) + // private const string SettingsCategory = nameof(WhereAmIPointingMod); + // + // private static readonly MelonPreferences_Category Category = + // MelonPreferences.CreateCategory(SettingsCategory); + // + // private static readonly MelonPreferences_Entry Entry_Enabled = + // Category.CreateEntry("enabled", true, display_name: "Enabled",description: "Toggle WhereAmIPointingMod entirely."); + + #endregion Melon Preferences + + public override void OnInitializeMelon() + { + ApplyPatches(typeof(TransformManager_Patches)); + } + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } + + internal static class TransformManager_Patches + { + // Patch for EnableTransform(DataChunk, bool) + [HarmonyPrefix] + [HarmonyPatch(typeof(TransformManager), nameof(TransformManager.EnableTransform), new[] { typeof(DataChunk), typeof(bool) })] + private static bool OnEnableTransformChunk(TransformManager __instance, DataChunk c, bool sw, ref NativeArray ___flagArray) + { + try + { + // Enhanced validation + if (!__instance.IsValid()) + return false; + + if (___flagArray == null || !___flagArray.IsCreated) + { + Debug.LogWarning("[MagicaCloth2] EnableTransform failed: Flag array is invalid or disposed"); + return false; + } + + if (!c.IsValid || c.startIndex < 0 || c.startIndex + c.dataLength > ___flagArray.Length) + { + Debug.LogWarning($"[MagicaCloth2] EnableTransform failed: Invalid chunk parameters. Start: {c.startIndex}, Length: {c.dataLength}, Array Length: {___flagArray.Length}"); + return false; + } + + // Create and run the job with additional safety + SafeEnableTransformJob job = new() + { + chunk = c, + sw = sw, + flagList = ___flagArray, + maxLength = ___flagArray.Length + }; + + try + { + job.Run(); + } + catch (Exception ex) + { + Debug.LogError($"[MagicaCloth2] Error in EnableTransform job execution: {ex.Message}"); + return false; + } + + return false; // Prevent original method execution + } + catch (Exception ex) + { + Debug.LogError($"[MagicaCloth2] Critical error in EnableTransform patch: {ex.Message}"); + return false; + } + } + + // Patch for EnableTransform(int, bool) + [HarmonyPrefix] + [HarmonyPatch(typeof(TransformManager), nameof(TransformManager.EnableTransform), new[] { typeof(int), typeof(bool) })] + private static bool OnEnableTransformIndex(TransformManager __instance, int index, bool sw, ref NativeArray ___flagArray) + { + try + { + // Enhanced validation + if (!__instance.IsValid()) + return false; + + if (___flagArray == null || !___flagArray.IsCreated) + { + Debug.LogWarning("[MagicaCloth2] EnableTransform failed: Flag array is invalid or disposed"); + return false; + } + + if (index < 0 || index >= ___flagArray.Length) + { + Debug.LogWarning($"[MagicaCloth2] EnableTransform failed: Index {index} out of range [0, {___flagArray.Length})"); + return false; + } + + // Safely modify the flag + var flag = ___flagArray[index]; + if (flag.Value == 0) + return false; + + flag.SetFlag(TransformManager.Flag_Enable, sw); + ___flagArray[index] = flag; + + return false; // Prevent original method execution + } + catch (Exception ex) + { + Debug.LogError($"[MagicaCloth2] Critical error in EnableTransform patch: {ex.Message}"); + return false; + } + } + + [BurstCompile] + private struct SafeEnableTransformJob : IJob + { + public DataChunk chunk; + public bool sw; + public NativeArray flagList; + [ReadOnly] public int maxLength; + + public void Execute() + { + // Additional bounds checking + if (chunk.startIndex < 0 || chunk.startIndex + chunk.dataLength > maxLength) + return; + + for (int i = 0; i < chunk.dataLength; i++) + { + int index = chunk.startIndex + i; + if (index >= maxLength) + break; + + ExBitFlag8 flag = flagList[index]; + if (flag.Value == 0) + continue; + + flag.SetFlag(TransformManager.Flag_Enable, sw); + flagList[index] = flag; + } + } + } + } +} \ No newline at end of file diff --git a/.Deprecated/CameraExperiments/Properties/AssemblyInfo.cs b/.Deprecated/CameraExperiments/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..48c359f --- /dev/null +++ b/.Deprecated/CameraExperiments/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using NAK.WhereAmIPointing.Properties; +using MelonLoader; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.WhereAmIPointing))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.WhereAmIPointing))] + +[assembly: MelonInfo( + typeof(NAK.WhereAmIPointing.WhereAmIPointingMod), + nameof(NAK.WhereAmIPointing), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.WhereAmIPointing.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.1"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/CameraExperiments/README.md b/.Deprecated/CameraExperiments/README.md new file mode 100644 index 0000000..c78a56a --- /dev/null +++ b/.Deprecated/CameraExperiments/README.md @@ -0,0 +1,14 @@ +# WhereAmIPointing + +Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/.Deprecated/CameraExperiments/format.json b/.Deprecated/CameraExperiments/format.json new file mode 100644 index 0000000..654911a --- /dev/null +++ b/.Deprecated/CameraExperiments/format.json @@ -0,0 +1,23 @@ +{ + "_id": 234, + "name": "WhereAmIPointing", + "modversion": "1.0.1", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction.", + "searchtags": [ + "controller", + "ray", + "line", + "tomato" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r40/WhereAmIPointing.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing/", + "changelog": "- Fixed line renderer alpha not being reset when the menu is closed.", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.DepricatedMods/CameraFixes/CameraFixes.csproj b/.Deprecated/CameraFixes/CameraFixes.csproj similarity index 100% rename from .DepricatedMods/CameraFixes/CameraFixes.csproj rename to .Deprecated/CameraFixes/CameraFixes.csproj diff --git a/.DepricatedMods/CameraFixes/HarmonyPatches.cs b/.Deprecated/CameraFixes/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/CameraFixes/HarmonyPatches.cs rename to .Deprecated/CameraFixes/HarmonyPatches.cs diff --git a/.DepricatedMods/CameraFixes/Main.cs b/.Deprecated/CameraFixes/Main.cs similarity index 100% rename from .DepricatedMods/CameraFixes/Main.cs rename to .Deprecated/CameraFixes/Main.cs diff --git a/.DepricatedMods/CameraFixes/Properties/AssemblyInfo.cs b/.Deprecated/CameraFixes/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/CameraFixes/Properties/AssemblyInfo.cs rename to .Deprecated/CameraFixes/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/CameraFixes/format.json b/.Deprecated/CameraFixes/format.json similarity index 100% rename from .DepricatedMods/CameraFixes/format.json rename to .Deprecated/CameraFixes/format.json diff --git a/.DepricatedMods/ClearHudNotifications/ClearHudNotifications.csproj b/.Deprecated/ClearHudNotifications/ClearHudNotifications.csproj similarity index 100% rename from .DepricatedMods/ClearHudNotifications/ClearHudNotifications.csproj rename to .Deprecated/ClearHudNotifications/ClearHudNotifications.csproj diff --git a/.DepricatedMods/ClearHudNotifications/HarmonyPatches.cs b/.Deprecated/ClearHudNotifications/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/ClearHudNotifications/HarmonyPatches.cs rename to .Deprecated/ClearHudNotifications/HarmonyPatches.cs diff --git a/.DepricatedMods/ClearHudNotifications/Main.cs b/.Deprecated/ClearHudNotifications/Main.cs similarity index 100% rename from .DepricatedMods/ClearHudNotifications/Main.cs rename to .Deprecated/ClearHudNotifications/Main.cs diff --git a/.DepricatedMods/ClearHudNotifications/Properties/AssemblyInfo.cs b/.Deprecated/ClearHudNotifications/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/ClearHudNotifications/Properties/AssemblyInfo.cs rename to .Deprecated/ClearHudNotifications/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/ClearHudNotifications/format.json b/.Deprecated/ClearHudNotifications/format.json similarity index 100% rename from .DepricatedMods/ClearHudNotifications/format.json rename to .Deprecated/ClearHudNotifications/format.json diff --git a/.Deprecated/ControlToUnlockMouse/ControlToUnlockMouse.csproj b/.Deprecated/ControlToUnlockMouse/ControlToUnlockMouse.csproj new file mode 100644 index 0000000..0f08b56 --- /dev/null +++ b/.Deprecated/ControlToUnlockMouse/ControlToUnlockMouse.csproj @@ -0,0 +1,6 @@ + + + + SpawnableReceiveOwnChanges + + diff --git a/.Deprecated/ControlToUnlockMouse/Main.cs b/.Deprecated/ControlToUnlockMouse/Main.cs new file mode 100644 index 0000000..4ca9845 --- /dev/null +++ b/.Deprecated/ControlToUnlockMouse/Main.cs @@ -0,0 +1,308 @@ +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.InteractionSystem.Base; +using ABI_RC.Core.Player; +using System.Reflection; +using cohtml.Net; +using HarmonyLib; +using UnityEngine; +using MelonLoader; +using Object = UnityEngine.Object; + +namespace NAK.ControlToUnlockMouse; + +public class ControlToUnlockMouseMod : MelonMod +{ + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(ControlToUnlockMouseMod)); + + internal static readonly MelonPreferences_Entry EntryOriginPivotPoint = + Category.CreateEntry("no_rotate_pivot_point", NoRotatePivotPoint.Pickupable, + "NoRotation Pickupable Pivot Point", "The pivot point to use when no rotation object is grabbed."); + + public enum NoRotatePivotPoint + { + Pickupable, + AvatarHead, + AvatarChest, + AvatarClosestShoulder, + } + + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.Awake), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnPlayerSetupAwake), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(CVR_MenuManager).GetMethod(nameof(CVR_MenuManager.Start), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnMenuManagerStart), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(ControllerRay).GetMethod(nameof(ControllerRay.HandleUnityUI), + BindingFlags.NonPublic | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnControllerRayHandleUnityUIDirectAndIndirect), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(ControllerRay).GetMethod(nameof(ControllerRay.HandleIndirectUnityUI), + BindingFlags.NonPublic | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnControllerRayHandleUnityUIDirectAndIndirect), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(ControllerRay).GetMethod(nameof(ControllerRay.LateUpdate), + BindingFlags.NonPublic | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnPreControllerRayLateUpdate), + BindingFlags.NonPublic | BindingFlags.Static)), + postfix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnPostControllerRayLateUpdate), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + } + + private static void OnPlayerSetupAwake(PlayerSetup __instance) + { + // Get original fields + LayerMask layerMask = __instance.desktopRay.generalMask; + + // Destroy the existing desktop ray + Object.Destroy(__instance.desktopRay); + + // Get the desktop camera + Camera desktopCam = __instance.desktopCam; + + // Create a new child object under the desktop camera for the ray + GameObject rayObject = new("DesktopRay") + { + transform = + { + parent = desktopCam.transform, + localPosition = Vector3.zero, + localRotation = Quaternion.identity + } + }; + + // Add ControllerRay component + ControllerRay newRay = rayObject.AddComponent(); + newRay.isDesktopRay = true; + newRay.isInteractionRay = true; + newRay.RayDirection = Vector3.forward; + newRay.generalMask = layerMask; + newRay.hand = CVRHand.Right; // Important to even work + newRay.attachmentDistance = 0f; + newRay.currentAttachmentDistance = 0f; + + // Assign new ray to desktopRay field + __instance.desktopRay = newRay; + + // Add our custom controller script + DesktopRayController rayController = rayObject.AddComponent(); + rayController.controllerRay = newRay; + rayController.desktopCamera = desktopCam; + } + + private static void OnMenuManagerStart(CVR_MenuManager __instance) + { + __instance.desktopControllerRay = PlayerSetup.Instance.desktopRay; + } + + private static bool OnControllerRayHandleUnityUIDirectAndIndirect(ControllerRay __instance) + { + return !__instance.isDesktopRay || Cursor.lockState == CursorLockMode.Locked; + } + + private static void OnPreControllerRayLateUpdate(ControllerRay __instance, ref bool __state) + { + if (!__instance.isDesktopRay) + return; + + ViewManager menu = ViewManager.Instance; + __state = menu._gameMenuOpen; + + if (!__state) menu._gameMenuOpen = Cursor.lockState != CursorLockMode.Locked; + } + + private static void OnPostControllerRayLateUpdate(ControllerRay __instance, ref bool __state) + { + if (!__instance.isDesktopRay) return; + ViewManager.Instance._gameMenuOpen = __state; + } +} + +public class DesktopRayController : MonoBehaviour +{ + internal ControllerRay controllerRay; + internal Camera desktopCamera; + + private void Update() + { + // Toggle desktop mouse mode based on Control key state + if (Input.GetKeyDown(KeyCode.LeftControl)) + { + if (!ViewManager.Instance.IsAnyMenuOpen) RootLogic.CursorLock(false); + } + + if (Input.GetKeyUp(KeyCode.LeftControl)) + { + if (!ViewManager.Instance.IsAnyMenuOpen) RootLogic.CursorLock(true); + } + + Transform rayRoot = controllerRay.transform; + Transform rayDirection = controllerRay.rayDirectionTransform; + Transform attachment = controllerRay.attachmentPoint; + Camera cam = desktopCamera; + + if (Cursor.lockState == CursorLockMode.Locked) + { + // Reset local position when unlocked + rayRoot.localPosition = Vector3.zero; + rayRoot.localRotation = Quaternion.identity; + + // Reset local position and rotation when locked + rayDirection.localPosition = new Vector3(0f, 0f, 0.001f); + rayDirection.localRotation = Quaternion.identity; + } + else + { + bool isAnyMenuOpen = ViewManager.Instance.IsAnyMenuOpen; + Pickupable grabbedObject = controllerRay.grabbedObject; + + // Only do when not holding an origin object + Vector3 screenPos = new(Input.mousePosition.x, Input.mousePosition.y); + + if (isAnyMenuOpen) + { + // Center the ray + rayRoot.localPosition = Vector3.zero; + } + else if (grabbedObject && !grabbedObject.IsObjectRotationAllowed) + { + // Specialized movement of ray around pickupable pivot + Vector3 pivotPoint = grabbedObject.transform.position; + Vector3 pivotPointCenter = grabbedObject.RootTransform.position; + + PlayerSetup playerSetup = PlayerSetup.Instance; + if (playerSetup != null && playerSetup._animator != null && playerSetup._animator.isHuman) + { + Animator animator = playerSetup._animator; + switch (ControlToUnlockMouseMod.EntryOriginPivotPoint.Value) + { + case ControlToUnlockMouseMod.NoRotatePivotPoint.AvatarHead: + { + Transform headBone = animator.GetBoneTransform(HumanBodyBones.Head); + if (headBone != null) pivotPoint = headBone.position; + break; + } + case ControlToUnlockMouseMod.NoRotatePivotPoint.AvatarChest: + { + if (playerSetup._avatar != null) + { + Transform chestBone = animator.GetBoneTransform(HumanBodyBones.Chest); + if (chestBone != null) pivotPoint = chestBone.position; + } + break; + } + case ControlToUnlockMouseMod.NoRotatePivotPoint.AvatarClosestShoulder: + { + if (playerSetup._avatar != null) + { + Transform leftShoulder = animator.GetBoneTransform(HumanBodyBones.LeftShoulder); + Transform rightShoulder = animator.GetBoneTransform(HumanBodyBones.RightShoulder); + if (leftShoulder != null || rightShoulder != null) + { + if (leftShoulder != null && rightShoulder != null) + { + pivotPoint = Vector3.Distance(leftShoulder.position, pivotPoint) < Vector3.Distance(rightShoulder.position, pivotPoint) + ? leftShoulder.position + : rightShoulder.position; + } + else if (leftShoulder != null) + { + pivotPoint = leftShoulder.position; + } + else + { + pivotPoint = rightShoulder.position; + } + } + } + break; + } + case ControlToUnlockMouseMod.NoRotatePivotPoint.Pickupable: + default: + break; + } + } + + // Get local position of pivotPoint relative to rayRoot + // This is shit but i cant wrap my head around the proper way to compute this lol + Vector3 localPivotPoint = rayRoot.InverseTransformPoint(pivotPoint); + Vector3 localPivotPointCenter = rayRoot.InverseTransformPoint(pivotPointCenter); + localPivotPoint.x = localPivotPointCenter.x; // Maintain local X + localPivotPoint.y = localPivotPointCenter.y; // Maintain local Y + + // Compute target world position based on the mouse and attachment distance. + screenPos.z = 10f; + Vector3 targetWorldPos = cam.ScreenToWorldPoint(screenPos); + + // Desired direction from the pivot point (grabbed object) to the target world position. + Vector3 directionToTarget = targetWorldPos - rayRoot.TransformPoint(localPivotPoint);; + + if (directionToTarget.sqrMagnitude < 1e-6f) + directionToTarget = rayRoot.forward; // Fallback if mouse is centered + + // Calculate the target rotation for rayRoot. + Quaternion targetRotation = Quaternion.LookRotation(directionToTarget, cam.transform.up); + + // Get the current local offset of the grabbed object relative to rayRoot. + Vector3 localPickupOffset = rayRoot.InverseTransformPoint(pivotPoint); + + // Compute the new rayRoot position to keep the grabbed object (child) at pivotPoint. + Vector3 newRayRootPos = pivotPoint - (targetRotation * localPickupOffset); + + // Apply the new rotation and position. + rayRoot.rotation = targetRotation; + rayRoot.position = newRayRootPos; + } + else + { + float distance; + if (grabbedObject) + { + // This position is calculated basically same way as below in BasePickupHandler, + // but not determined by ray hit + distance = attachment.localPosition.z; + } + else + { + // Compute distance forward from ray + Vector3 localOffset = rayRoot.InverseTransformPoint(controllerRay._hit.point); + distance = localOffset.z; + } + + screenPos.z = distance; + + // Compute world position from where mouse is on screen + Vector3 worldPos = cam.ScreenToWorldPoint(screenPos); + + // Normal movement of ray + Vector3 newLocalPos = rayRoot.parent.InverseTransformPoint(worldPos); + newLocalPos.z = rayRoot.localPosition.z; // Maintain local Z + rayRoot.localPosition = newLocalPos; + } + + // Compute mouse ray in world space + Ray mouseRay = cam.ScreenPointToRay(Input.mousePosition); + rayDirection.position = mouseRay.origin; + rayDirection.rotation = Quaternion.LookRotation(mouseRay.direction, cam.transform.up); + } + } +} \ No newline at end of file diff --git a/.Deprecated/ControlToUnlockMouse/Properties/AssemblyInfo.cs b/.Deprecated/ControlToUnlockMouse/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9e54143 --- /dev/null +++ b/.Deprecated/ControlToUnlockMouse/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.ControlToUnlockMouse.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.ControlToUnlockMouse))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.ControlToUnlockMouse))] + +[assembly: MelonInfo( + typeof(NAK.ControlToUnlockMouse.ControlToUnlockMouseMod), + nameof(NAK.ControlToUnlockMouse), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ControlToUnlockMouse" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.ControlToUnlockMouse.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/SearchWithSpacesFix/README.md b/.Deprecated/ControlToUnlockMouse/README.md similarity index 100% rename from SearchWithSpacesFix/README.md rename to .Deprecated/ControlToUnlockMouse/README.md diff --git a/SearchWithSpacesFix/format.json b/.Deprecated/ControlToUnlockMouse/format.json similarity index 100% rename from SearchWithSpacesFix/format.json rename to .Deprecated/ControlToUnlockMouse/format.json diff --git a/.DepricatedMods/ControllerFreeze/ControllerFreeze.csproj b/.Deprecated/ControllerFreeze/ControllerFreeze.csproj similarity index 100% rename from .DepricatedMods/ControllerFreeze/ControllerFreeze.csproj rename to .Deprecated/ControllerFreeze/ControllerFreeze.csproj diff --git a/.DepricatedMods/ControllerFreeze/HarmonyPatches.cs b/.Deprecated/ControllerFreeze/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/ControllerFreeze/HarmonyPatches.cs rename to .Deprecated/ControllerFreeze/HarmonyPatches.cs diff --git a/.DepricatedMods/ControllerFreeze/Main.cs b/.Deprecated/ControllerFreeze/Main.cs similarity index 100% rename from .DepricatedMods/ControllerFreeze/Main.cs rename to .Deprecated/ControllerFreeze/Main.cs diff --git a/.DepricatedMods/ControllerFreeze/Properties/AssemblyInfo.cs b/.Deprecated/ControllerFreeze/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/ControllerFreeze/Properties/AssemblyInfo.cs rename to .Deprecated/ControllerFreeze/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/ControllerFreeze/README.md b/.Deprecated/ControllerFreeze/README.md similarity index 100% rename from .DepricatedMods/ControllerFreeze/README.md rename to .Deprecated/ControllerFreeze/README.md diff --git a/.DepricatedMods/ControllerFreeze/format.json b/.Deprecated/ControllerFreeze/format.json similarity index 100% rename from .DepricatedMods/ControllerFreeze/format.json rename to .Deprecated/ControllerFreeze/format.json diff --git a/.DepricatedMods/DesktopVRIK/DesktopVRIK.csproj b/.Deprecated/DesktopVRIK/DesktopVRIK.csproj similarity index 100% rename from .DepricatedMods/DesktopVRIK/DesktopVRIK.csproj rename to .Deprecated/DesktopVRIK/DesktopVRIK.csproj diff --git a/.DepricatedMods/DesktopVRIK/HarmonyPatches.cs b/.Deprecated/DesktopVRIK/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/HarmonyPatches.cs rename to .Deprecated/DesktopVRIK/HarmonyPatches.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/IKCalibrator.cs b/.Deprecated/DesktopVRIK/IK/IKCalibrator.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/IKCalibrator.cs rename to .Deprecated/DesktopVRIK/IK/IKCalibrator.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/IKHandlers/IKHandler.cs b/.Deprecated/DesktopVRIK/IK/IKHandlers/IKHandler.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/IKHandlers/IKHandler.cs rename to .Deprecated/DesktopVRIK/IK/IKHandlers/IKHandler.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/IKHandlers/IKHandlerDesktop.cs b/.Deprecated/DesktopVRIK/IK/IKHandlers/IKHandlerDesktop.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/IKHandlers/IKHandlerDesktop.cs rename to .Deprecated/DesktopVRIK/IK/IKHandlers/IKHandlerDesktop.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/IKManager.cs b/.Deprecated/DesktopVRIK/IK/IKManager.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/IKManager.cs rename to .Deprecated/DesktopVRIK/IK/IKManager.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/MusclePoses.cs b/.Deprecated/DesktopVRIK/IK/MusclePoses.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/MusclePoses.cs rename to .Deprecated/DesktopVRIK/IK/MusclePoses.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/VRIKHelpers/VRIKLocomotionData.cs b/.Deprecated/DesktopVRIK/IK/VRIKHelpers/VRIKLocomotionData.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/VRIKHelpers/VRIKLocomotionData.cs rename to .Deprecated/DesktopVRIK/IK/VRIKHelpers/VRIKLocomotionData.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs b/.Deprecated/DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs rename to .Deprecated/DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs diff --git a/.DepricatedMods/DesktopVRIK/Integrations/AMTAddon.cs b/.Deprecated/DesktopVRIK/Integrations/AMTAddon.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/Integrations/AMTAddon.cs rename to .Deprecated/DesktopVRIK/Integrations/AMTAddon.cs diff --git a/.DepricatedMods/DesktopVRIK/Integrations/BTKUIAddon.cs b/.Deprecated/DesktopVRIK/Integrations/BTKUIAddon.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/Integrations/BTKUIAddon.cs rename to .Deprecated/DesktopVRIK/Integrations/BTKUIAddon.cs diff --git a/.DepricatedMods/DesktopVRIK/Main.cs b/.Deprecated/DesktopVRIK/Main.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/Main.cs rename to .Deprecated/DesktopVRIK/Main.cs diff --git a/.DepricatedMods/DesktopVRIK/ModSettings.cs b/.Deprecated/DesktopVRIK/ModSettings.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/ModSettings.cs rename to .Deprecated/DesktopVRIK/ModSettings.cs diff --git a/.DepricatedMods/DesktopVRIK/Properties/AssemblyInfo.cs b/.Deprecated/DesktopVRIK/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/Properties/AssemblyInfo.cs rename to .Deprecated/DesktopVRIK/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/DesktopVRIK/README.md b/.Deprecated/DesktopVRIK/README.md similarity index 100% rename from .DepricatedMods/DesktopVRIK/README.md rename to .Deprecated/DesktopVRIK/README.md diff --git a/.DepricatedMods/DesktopVRIK/format.json b/.Deprecated/DesktopVRIK/format.json similarity index 100% rename from .DepricatedMods/DesktopVRIK/format.json rename to .Deprecated/DesktopVRIK/format.json diff --git a/.DepricatedMods/DesktopVRSwitch/DesktopVRSwitch.csproj b/.Deprecated/DesktopVRSwitch/DesktopVRSwitch.csproj similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/DesktopVRSwitch.csproj rename to .Deprecated/DesktopVRSwitch/DesktopVRSwitch.csproj diff --git a/.DepricatedMods/DesktopVRSwitch/HarmonyPatches.cs b/.Deprecated/DesktopVRSwitch/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/HarmonyPatches.cs rename to .Deprecated/DesktopVRSwitch/HarmonyPatches.cs diff --git a/.DepricatedMods/DesktopVRSwitch/Integrations/BTKUIAddon.cs b/.Deprecated/DesktopVRSwitch/Integrations/BTKUIAddon.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Integrations/BTKUIAddon.cs rename to .Deprecated/DesktopVRSwitch/Integrations/BTKUIAddon.cs diff --git a/.DepricatedMods/DesktopVRSwitch/Main.cs b/.Deprecated/DesktopVRSwitch/Main.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Main.cs rename to .Deprecated/DesktopVRSwitch/Main.cs diff --git a/.DepricatedMods/DesktopVRSwitch/ModSettings.cs b/.Deprecated/DesktopVRSwitch/ModSettings.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/ModSettings.cs rename to .Deprecated/DesktopVRSwitch/ModSettings.cs diff --git a/.DepricatedMods/DesktopVRSwitch/Patches/DestroySteamVRInstancesImmediate.cs b/.Deprecated/DesktopVRSwitch/Patches/DestroySteamVRInstancesImmediate.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Patches/DestroySteamVRInstancesImmediate.cs rename to .Deprecated/DesktopVRSwitch/Patches/DestroySteamVRInstancesImmediate.cs diff --git a/.DepricatedMods/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs b/.Deprecated/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs rename to .Deprecated/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs diff --git a/.DepricatedMods/DesktopVRSwitch/Properties/AssemblyInfo.cs b/.Deprecated/DesktopVRSwitch/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Properties/AssemblyInfo.cs rename to .Deprecated/DesktopVRSwitch/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/DesktopVRSwitch/README.md b/.Deprecated/DesktopVRSwitch/README.md similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/README.md rename to .Deprecated/DesktopVRSwitch/README.md diff --git a/.DepricatedMods/DesktopVRSwitch/Utils.cs b/.Deprecated/DesktopVRSwitch/Utils.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Utils.cs rename to .Deprecated/DesktopVRSwitch/Utils.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeSwitchDebugger.cs b/.Deprecated/DesktopVRSwitch/VRModeSwitchDebugger.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeSwitchDebugger.cs rename to .Deprecated/DesktopVRSwitch/VRModeSwitchDebugger.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeSwitchManager.cs b/.Deprecated/DesktopVRSwitch/VRModeSwitchManager.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeSwitchManager.cs rename to .Deprecated/DesktopVRSwitch/VRModeSwitchManager.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRGestureRecognizerTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVRGestureRecognizerTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRGestureRecognizerTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVRGestureRecognizerTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRInputManagerTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVRInputManagerTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRInputManagerTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVRInputManagerTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRPickupObjectTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVRPickupObjectTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRPickupObjectTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVRPickupObjectTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRWorldTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVRWorldTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRWorldTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVRWorldTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVR_InteractableManagerTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVR_InteractableManagerTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVR_InteractableManagerTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVR_InteractableManagerTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVR_MenuManagerTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVR_MenuManagerTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVR_MenuManagerTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVR_MenuManagerTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CameraFacingObjectTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CameraFacingObjectTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CameraFacingObjectTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CameraFacingObjectTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CheckVRTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CheckVRTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CheckVRTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CheckVRTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CohtmlHudTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CohtmlHudTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CohtmlHudTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CohtmlHudTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/HudOperationsTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/HudOperationsTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/HudOperationsTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/HudOperationsTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/IKSystemTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/IKSystemTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/IKSystemTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/IKSystemTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/MetaPortTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/MetaPortTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/MetaPortTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/MetaPortTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/MovementSystemTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/MovementSystemTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/MovementSystemTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/MovementSystemTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/PlayerSetupTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/PlayerSetupTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/PlayerSetupTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/PlayerSetupTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/PortableCameraTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/PortableCameraTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/PortableCameraTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/PortableCameraTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/VRModeTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/VRModeTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/VRModeTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/VRModeTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/ViewManagerTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/ViewManagerTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/ViewManagerTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/ViewManagerTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/XRHandler.cs b/.Deprecated/DesktopVRSwitch/XRHandler.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/XRHandler.cs rename to .Deprecated/DesktopVRSwitch/XRHandler.cs diff --git a/.DepricatedMods/DesktopVRSwitch/format.json b/.Deprecated/DesktopVRSwitch/format.json similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/format.json rename to .Deprecated/DesktopVRSwitch/format.json diff --git a/DropPropTweak/DropPropTweak.csproj b/.Deprecated/DropPropTweak/DropPropTweak.csproj similarity index 100% rename from DropPropTweak/DropPropTweak.csproj rename to .Deprecated/DropPropTweak/DropPropTweak.csproj diff --git a/DropPropTweak/Main.cs b/.Deprecated/DropPropTweak/Main.cs similarity index 99% rename from DropPropTweak/Main.cs rename to .Deprecated/DropPropTweak/Main.cs index 023ce21..b72f652 100644 --- a/DropPropTweak/Main.cs +++ b/.Deprecated/DropPropTweak/Main.cs @@ -44,6 +44,4 @@ public class DropPropTweakMod : MelonMod __instance.CharacterController.gravity = ogGravity; // restore gravity return false; } - - } \ No newline at end of file diff --git a/DropPropTweak/Properties/AssemblyInfo.cs b/.Deprecated/DropPropTweak/Properties/AssemblyInfo.cs similarity index 100% rename from DropPropTweak/Properties/AssemblyInfo.cs rename to .Deprecated/DropPropTweak/Properties/AssemblyInfo.cs diff --git a/DropPropTweak/README.md b/.Deprecated/DropPropTweak/README.md similarity index 100% rename from DropPropTweak/README.md rename to .Deprecated/DropPropTweak/README.md diff --git a/DropPropTweak/format.json b/.Deprecated/DropPropTweak/format.json similarity index 100% rename from DropPropTweak/format.json rename to .Deprecated/DropPropTweak/format.json diff --git a/.DepricatedMods/EzCurls/EzCurls.csproj b/.Deprecated/EzCurls/EzCurls.csproj similarity index 100% rename from .DepricatedMods/EzCurls/EzCurls.csproj rename to .Deprecated/EzCurls/EzCurls.csproj diff --git a/.DepricatedMods/EzCurls/InputModules/InputModuleCurlAdjuster.cs b/.Deprecated/EzCurls/InputModules/InputModuleCurlAdjuster.cs similarity index 100% rename from .DepricatedMods/EzCurls/InputModules/InputModuleCurlAdjuster.cs rename to .Deprecated/EzCurls/InputModules/InputModuleCurlAdjuster.cs diff --git a/.DepricatedMods/EzCurls/Main.cs b/.Deprecated/EzCurls/Main.cs similarity index 100% rename from .DepricatedMods/EzCurls/Main.cs rename to .Deprecated/EzCurls/Main.cs diff --git a/.DepricatedMods/EzCurls/ModSettings.cs b/.Deprecated/EzCurls/ModSettings.cs similarity index 100% rename from .DepricatedMods/EzCurls/ModSettings.cs rename to .Deprecated/EzCurls/ModSettings.cs diff --git a/.DepricatedMods/EzCurls/Properties/AssemblyInfo.cs b/.Deprecated/EzCurls/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/EzCurls/Properties/AssemblyInfo.cs rename to .Deprecated/EzCurls/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/EzCurls/README.md b/.Deprecated/EzCurls/README.md similarity index 100% rename from .DepricatedMods/EzCurls/README.md rename to .Deprecated/EzCurls/README.md diff --git a/.DepricatedMods/EzCurls/format.json b/.Deprecated/EzCurls/format.json similarity index 100% rename from .DepricatedMods/EzCurls/format.json rename to .Deprecated/EzCurls/format.json diff --git a/.DepricatedMods/EzGrab/EzGrab.csproj b/.Deprecated/EzGrab/EzGrab.csproj similarity index 100% rename from .DepricatedMods/EzGrab/EzGrab.csproj rename to .Deprecated/EzGrab/EzGrab.csproj diff --git a/.DepricatedMods/EzGrab/Main.cs b/.Deprecated/EzGrab/Main.cs similarity index 100% rename from .DepricatedMods/EzGrab/Main.cs rename to .Deprecated/EzGrab/Main.cs diff --git a/.DepricatedMods/EzGrab/Properties/AssemblyInfo.cs b/.Deprecated/EzGrab/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/EzGrab/Properties/AssemblyInfo.cs rename to .Deprecated/EzGrab/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/EzGrab/format.json b/.Deprecated/EzGrab/format.json similarity index 100% rename from .DepricatedMods/EzGrab/format.json rename to .Deprecated/EzGrab/format.json diff --git a/FOVAdjustment/FOVAdjustment.csproj b/.Deprecated/FOVAdjustment/FOVAdjustment.csproj similarity index 100% rename from FOVAdjustment/FOVAdjustment.csproj rename to .Deprecated/FOVAdjustment/FOVAdjustment.csproj diff --git a/FOVAdjustment/Main.cs b/.Deprecated/FOVAdjustment/Main.cs similarity index 94% rename from FOVAdjustment/Main.cs rename to .Deprecated/FOVAdjustment/Main.cs index a593ab0..bafb6ae 100644 --- a/FOVAdjustment/Main.cs +++ b/.Deprecated/FOVAdjustment/Main.cs @@ -55,10 +55,10 @@ public class FOVAdjustment : MelonMod private static void UpdateDesktopCameraControllerFov(float value) { - if (CVRWorld.Instance != null && Mathf.Approximately(CVRWorld.Instance.fov, 60f)) - { + // if (CVRWorld.Instance != null && Mathf.Approximately(CVRWorld.Instance.fov, 60f)) + // { CVR_DesktopCameraController.defaultFov = Mathf.Clamp(value, 60f, 120f); CVR_DesktopCameraController.zoomFov = CVR_DesktopCameraController.defaultFov * 0.5f; - } + //} } } \ No newline at end of file diff --git a/FOVAdjustment/Properties/AssemblyInfo.cs b/.Deprecated/FOVAdjustment/Properties/AssemblyInfo.cs similarity index 100% rename from FOVAdjustment/Properties/AssemblyInfo.cs rename to .Deprecated/FOVAdjustment/Properties/AssemblyInfo.cs diff --git a/FOVAdjustment/README.md b/.Deprecated/FOVAdjustment/README.md similarity index 100% rename from FOVAdjustment/README.md rename to .Deprecated/FOVAdjustment/README.md diff --git a/FOVAdjustment/format.json b/.Deprecated/FOVAdjustment/format.json similarity index 100% rename from FOVAdjustment/format.json rename to .Deprecated/FOVAdjustment/format.json diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/FuckCohtmlResourceHandler.csproj b/.Deprecated/FuckCohtmlResourceHandler/FuckCohtmlResourceHandler.csproj similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/FuckCohtmlResourceHandler.csproj rename to .Deprecated/FuckCohtmlResourceHandler/FuckCohtmlResourceHandler.csproj diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/HarmonyPatches.cs b/.Deprecated/FuckCohtmlResourceHandler/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/HarmonyPatches.cs rename to .Deprecated/FuckCohtmlResourceHandler/HarmonyPatches.cs diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/Main.cs b/.Deprecated/FuckCohtmlResourceHandler/Main.cs similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/Main.cs rename to .Deprecated/FuckCohtmlResourceHandler/Main.cs diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/Properties/AssemblyInfo.cs b/.Deprecated/FuckCohtmlResourceHandler/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/Properties/AssemblyInfo.cs rename to .Deprecated/FuckCohtmlResourceHandler/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/README.md b/.Deprecated/FuckCohtmlResourceHandler/README.md similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/README.md rename to .Deprecated/FuckCohtmlResourceHandler/README.md diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/format.json b/.Deprecated/FuckCohtmlResourceHandler/format.json similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/format.json rename to .Deprecated/FuckCohtmlResourceHandler/format.json diff --git a/.DepricatedMods/FuckMLA/FuckMLA.csproj b/.Deprecated/FuckMLA/FuckMLA.csproj similarity index 100% rename from .DepricatedMods/FuckMLA/FuckMLA.csproj rename to .Deprecated/FuckMLA/FuckMLA.csproj diff --git a/.DepricatedMods/FuckMLA/HarmonyPatches.cs b/.Deprecated/FuckMLA/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/FuckMLA/HarmonyPatches.cs rename to .Deprecated/FuckMLA/HarmonyPatches.cs diff --git a/.DepricatedMods/FuckMLA/Main.cs b/.Deprecated/FuckMLA/Main.cs similarity index 100% rename from .DepricatedMods/FuckMLA/Main.cs rename to .Deprecated/FuckMLA/Main.cs diff --git a/.DepricatedMods/FuckMLA/Properties/AssemblyInfo.cs b/.Deprecated/FuckMLA/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/FuckMLA/Properties/AssemblyInfo.cs rename to .Deprecated/FuckMLA/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/FuckMLA/format.json b/.Deprecated/FuckMLA/format.json similarity index 100% rename from .DepricatedMods/FuckMLA/format.json rename to .Deprecated/FuckMLA/format.json diff --git a/.DepricatedMods/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj b/.Deprecated/FuckMagicaCloth2/FuckMagicaCloth2.csproj similarity index 100% rename from .DepricatedMods/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj rename to .Deprecated/FuckMagicaCloth2/FuckMagicaCloth2.csproj diff --git a/.Deprecated/FuckMagicaCloth2/Main.cs b/.Deprecated/FuckMagicaCloth2/Main.cs new file mode 100644 index 0000000..2b1421d --- /dev/null +++ b/.Deprecated/FuckMagicaCloth2/Main.cs @@ -0,0 +1,49 @@ +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using HarmonyLib; +using MagicaCloth2; +using MelonLoader; +using Unity.Burst; +using Unity.Collections; +using Unity.Jobs; +using Unity.Mathematics; +using UnityEngine; +using UnityEngine.Jobs; + +namespace NAK.FuckOffMagicaCloth2; + +public class FuckOffMagicaCloth2Mod : MelonMod +{ + private static MelonLogger.Instance Logger; + + public override void OnInitializeMelon() + { + Logger = LoggerInstance; + ApplyPatches(typeof(MagicaCloth_Patches)); + } + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } + + internal static class MagicaCloth_Patches + { + [HarmonyPrefix] + [HarmonyPatch(typeof(MagicaCloth2.MagicaCloth), nameof(MagicaCloth2.MagicaCloth.Awake))] + private static void MagicaCloth_Awake_Prefix(MagicaCloth2.MagicaCloth __instance) + { + __instance.SerializeData.selfCollisionConstraint.selfMode = SelfCollisionConstraint.SelfCollisionMode.None; + __instance.SerializeData.selfCollisionConstraint.syncMode = SelfCollisionConstraint.SelfCollisionMode.None; + } + } +} \ No newline at end of file diff --git a/.Deprecated/FuckMagicaCloth2/Properties/AssemblyInfo.cs b/.Deprecated/FuckMagicaCloth2/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..91ab089 --- /dev/null +++ b/.Deprecated/FuckMagicaCloth2/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using MelonLoader; +using NAK.FuckOffMagicaCloth2.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.FuckOffMagicaCloth2))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.FuckOffMagicaCloth2))] + +[assembly: MelonInfo( + typeof(NAK.FuckOffMagicaCloth2.FuckOffMagicaCloth2Mod), + nameof(NAK.FuckOffMagicaCloth2), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckOffMagicaCloth2" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: HarmonyDontPatchAll] + +namespace NAK.FuckOffMagicaCloth2.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.1"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/IKSimulatedRootAngleFix/README.md b/.Deprecated/FuckMagicaCloth2/README.md similarity index 100% rename from IKSimulatedRootAngleFix/README.md rename to .Deprecated/FuckMagicaCloth2/README.md diff --git a/.Deprecated/FuckMagicaCloth2/format.json b/.Deprecated/FuckMagicaCloth2/format.json new file mode 100644 index 0000000..ddf506b --- /dev/null +++ b/.Deprecated/FuckMagicaCloth2/format.json @@ -0,0 +1,24 @@ +{ + "_id": -1, + "name": "AASDefaultProfileFix", + "modversion": "1.0.0", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes the Default AAS profile not being applied when loading into an avatar without a profile selected.\n\nBy default, the game will not apply anything and the avatar will default to the state found within the Controller parameters.", + "searchtags": [ + "aas", + "profile", + "default", + "fix", + "meow" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r33/AASDefaultProfileFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AASDefaultProfileFix/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.DepricatedMods/FuckMetrics/FuckMetrics.csproj b/.Deprecated/FuckMetrics/FuckMetrics.csproj similarity index 100% rename from .DepricatedMods/FuckMetrics/FuckMetrics.csproj rename to .Deprecated/FuckMetrics/FuckMetrics.csproj diff --git a/.DepricatedMods/FuckMetrics/HarmonyPatches.cs b/.Deprecated/FuckMetrics/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/FuckMetrics/HarmonyPatches.cs rename to .Deprecated/FuckMetrics/HarmonyPatches.cs diff --git a/.DepricatedMods/FuckMetrics/Main.cs b/.Deprecated/FuckMetrics/Main.cs similarity index 100% rename from .DepricatedMods/FuckMetrics/Main.cs rename to .Deprecated/FuckMetrics/Main.cs diff --git a/.DepricatedMods/FuckMetrics/ManagedLibs/.keep b/.Deprecated/FuckMetrics/ManagedLibs/.keep similarity index 100% rename from .DepricatedMods/FuckMetrics/ManagedLibs/.keep rename to .Deprecated/FuckMetrics/ManagedLibs/.keep diff --git a/.DepricatedMods/FuckMetrics/Properties/AssemblyInfo.cs b/.Deprecated/FuckMetrics/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/FuckMetrics/Properties/AssemblyInfo.cs rename to .Deprecated/FuckMetrics/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/FuckMetrics/format.json b/.Deprecated/FuckMetrics/format.json similarity index 100% rename from .DepricatedMods/FuckMetrics/format.json rename to .Deprecated/FuckMetrics/format.json diff --git a/.Deprecated/FuckOffUICamera/CohtmlRenderForwarder.cs b/.Deprecated/FuckOffUICamera/CohtmlRenderForwarder.cs new file mode 100644 index 0000000..5f5dd2a --- /dev/null +++ b/.Deprecated/FuckOffUICamera/CohtmlRenderForwarder.cs @@ -0,0 +1,35 @@ +using ABI_RC.Core.UI; +using UnityEngine; + +namespace NAK.FuckOffUICamera; + +[RequireComponent(typeof(Camera))] +public class CohtmlRenderForwarder : MonoBehaviour +{ + #region Private Variables + + private CohtmlControlledView[] controlledViews; + + #endregion Private Variables + + #region Unity Events + + private void OnPreRender() + { + if (controlledViews == null) return; + foreach (CohtmlControlledView view in controlledViews) + if (view) view.OnPreRender(); + } + + #endregion Unity Events + + #region Public Methods + + public static void Setup(Camera camera, params CohtmlControlledView[] views) + { + CohtmlRenderForwarder forwarder = camera.gameObject.AddComponent(); + forwarder.controlledViews = views; + } + + #endregion Public Methods +} \ No newline at end of file diff --git a/.Deprecated/FuckOffUICamera/CommandBufferManager.cs b/.Deprecated/FuckOffUICamera/CommandBufferManager.cs new file mode 100644 index 0000000..aa76f1f --- /dev/null +++ b/.Deprecated/FuckOffUICamera/CommandBufferManager.cs @@ -0,0 +1,144 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.Rendering; + +namespace NAK.FuckOffUICamera; + +public class CommandBufferManager : MonoBehaviour +{ + #region Private Variables + + private CommandBuffer commandBuffer; + private Camera targetCamera; + private Renderer[] targetRenderers; + private bool[] rendererEnabledStates; + private const string CommandBufferName = "CustomRenderPass"; + private bool _didSetup; + + #endregion Private Variables + + #region Unity Events + + private IEnumerator Start() + { + yield return new WaitForSeconds(2f); // I have no idea why this needs to be delayed + _didSetup = true; + OnEnable(); + } + + private void OnEnable() + { + if (!_didSetup) return; + if (targetCamera == null || targetRenderers == null) + return; + + SetupEnabledStateCollection(); + SetupCommandBuffer(); + } + + private void OnDisable() + { + CleanupCommandBuffer(); + } + + private void LateUpdate() + { + if (targetRenderers == null + || rendererEnabledStates == null) + return; + + bool needsRebuild = false; + + // Check if any renderer enabled states have changed + int targetRenderersLength = targetRenderers.Length; + for (int i = 0; i < targetRenderersLength; i++) + { + if (targetRenderers[i] == null) continue; + + bool currentState = targetRenderers[i].enabled && targetRenderers[i].gameObject.activeInHierarchy; + if (currentState == rendererEnabledStates[i]) + continue; + + rendererEnabledStates[i] = currentState; + needsRebuild = true; + } + + if (needsRebuild) RebuildCommandBuffer(); + } + + #endregion Unity Events + + #region Public Methods + + public static void Setup(Camera camera, params Renderer[] renderers) + { + CommandBufferManager manager = camera.gameObject.AddComponent(); + manager.targetCamera = camera; + manager.targetRenderers = renderers; + } + + #endregion Public Methods + + #region Private Methods + + private void SetupEnabledStateCollection() + { + if (rendererEnabledStates != null) + Array.Resize(ref rendererEnabledStates, targetRenderers.Length); + else + rendererEnabledStates = new bool[targetRenderers.Length]; + } + + private void SetupCommandBuffer() + { + commandBuffer = new CommandBuffer(); + commandBuffer.name = CommandBufferName; + + // Set render target and clear depth + commandBuffer.SetRenderTarget(new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget, + 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices)); + + commandBuffer.ClearRenderTarget(true, false, Color.clear); + + for (int i = 0; i < targetRenderers.Length; i++) + { + Renderer renderer = targetRenderers[i]; + if (renderer == null || !rendererEnabledStates[i]) + continue; + + commandBuffer.DrawRenderer(renderer, renderer.sharedMaterial); + renderer.forceRenderingOff = true; + } + + targetCamera.AddCommandBuffer(CameraEvent.AfterImageEffects, commandBuffer); + + Debug.Log($"Command buffer setup for {targetCamera.name} with {targetRenderers.Length} renderers."); + } + + private void RebuildCommandBuffer() + { + CleanupCommandBuffer(); + SetupCommandBuffer(); + } + + private void CleanupCommandBuffer() + { + if (targetCamera == null || commandBuffer == null) + return; + + // Re-enable normal rendering for all renderers + if (targetRenderers != null) + { + foreach (Renderer renderer in targetRenderers) + { + if (renderer != null) + renderer.forceRenderingOff = false; + } + } + + targetCamera.RemoveCommandBuffer(CameraEvent.AfterImageEffects, commandBuffer); + commandBuffer = null; + } + + #endregion Private Methods +} \ No newline at end of file diff --git a/.DepricatedMods/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj b/.Deprecated/FuckOffUICamera/FuckOffUICamera.csproj similarity index 100% rename from .DepricatedMods/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj rename to .Deprecated/FuckOffUICamera/FuckOffUICamera.csproj diff --git a/.Deprecated/FuckOffUICamera/Main.cs b/.Deprecated/FuckOffUICamera/Main.cs new file mode 100644 index 0000000..e4c9092 --- /dev/null +++ b/.Deprecated/FuckOffUICamera/Main.cs @@ -0,0 +1,73 @@ +using System.Reflection; +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.UI; +using HarmonyLib; +using MelonLoader; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace NAK.FuckOffUICamera; + +public class FuckOffUICameraMod : MelonMod +{ + private static MelonLogger.Instance Logger; + + public override void OnInitializeMelon() + { + Logger = LoggerInstance; + } + + public override void OnSceneWasLoaded(int buildIndex, string sceneName) + { + if (buildIndex != 2) return; + if (_isInitialized) return; + SetupShittyMod(); + _isInitialized = true; + } + + private bool _isInitialized; + + private static void SetupShittyMod() + { + // Find all renderers under Cohtml object + GameObject cohtml = GameObject.Find("Cohtml"); + if (cohtml == null) + { + Logger.Error("Cohtml object not found!"); + return; + } + + // Find all CohtmlControlledView objects + var allMenuCohtml = Object.FindObjectsOfType(includeInactive: true); + var allUiInternalRenderers = Object.FindObjectsOfType(includeInactive: true) + .Where(x => x.gameObject.layer == CVRLayers.UIInternal) + .ToArray(); + + //var allMenuRenderers = cohtml.GetComponentsInChildren(true); + + // Add hud renderer to the list of renderers + Renderer hudRenderer = CohtmlHud.Instance.GetComponent(); + // Array.Resize(ref allMenuRenderers, allMenuRenderers.Length + 1); + // allMenuRenderers[^1] = hudRenderer; + + // Fix shader on the hud renderer + Material material = hudRenderer.sharedMaterial; + material.shader = Shader.Find("Alpha Blend Interactive/MenuFX"); + + // Setup command buffer manager for desktop camera + CommandBufferManager.Setup(PlayerSetup.Instance.desktopCam, allUiInternalRenderers); + CohtmlRenderForwarder.Setup(PlayerSetup.Instance.desktopCam, allMenuCohtml); + + // Setup command buffer manager for vr camera + CommandBufferManager.Setup(PlayerSetup.Instance.vrCam, allUiInternalRenderers); + CohtmlRenderForwarder.Setup(PlayerSetup.Instance.vrCam, allMenuCohtml); + + // Disable the ui cameras + PlayerSetup.Instance.desktopUiCam.gameObject.SetActive(false); + PlayerSetup.Instance.vrUiCam.gameObject.SetActive(false); + + Logger.Msg("Disabled UI cameras and setup command buffer manager for Cohtml renderers."); + } +} \ No newline at end of file diff --git a/PhysicsGunMod/Properties/AssemblyInfo.cs b/.Deprecated/FuckOffUICamera/Properties/AssemblyInfo.cs similarity index 67% rename from PhysicsGunMod/Properties/AssemblyInfo.cs rename to .Deprecated/FuckOffUICamera/Properties/AssemblyInfo.cs index df4ffd2..b7a9e9f 100644 --- a/PhysicsGunMod/Properties/AssemblyInfo.cs +++ b/.Deprecated/FuckOffUICamera/Properties/AssemblyInfo.cs @@ -1,30 +1,30 @@ using MelonLoader; -using NAK.PhysicsGunMod.Properties; +using NAK.FuckOffUICamera.Properties; using System.Reflection; [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.PhysicsGunMod))] +[assembly: AssemblyTitle(nameof(NAK.FuckOffUICamera))] [assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.PhysicsGunMod))] +[assembly: AssemblyProduct(nameof(NAK.FuckOffUICamera))] [assembly: MelonInfo( - typeof(NAK.PhysicsGunMod.PhysicsGunMod), - nameof(NAK.PhysicsGunMod), + typeof(NAK.FuckOffUICamera.FuckOffUICameraMod), + nameof(NAK.FuckOffUICamera), AssemblyInfoParams.Version, AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PhysicsGunMod" + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckOffUICamera" )] [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 241, 200, 82)] -[assembly: MelonAuthorColor(255, 114, 17, 25)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] -namespace NAK.PhysicsGunMod.Properties; +namespace NAK.FuckOffUICamera.Properties; internal static class AssemblyInfoParams { public const string Version = "1.0.0"; diff --git a/.Deprecated/FuckOffUICamera/README.md b/.Deprecated/FuckOffUICamera/README.md new file mode 100644 index 0000000..1c4c5bc --- /dev/null +++ b/.Deprecated/FuckOffUICamera/README.md @@ -0,0 +1,14 @@ +# SearchWithSpacesFix + +Fixes search terms that use spaces. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/.Deprecated/FuckOffUICamera/format.json b/.Deprecated/FuckOffUICamera/format.json new file mode 100644 index 0000000..f8950ca --- /dev/null +++ b/.Deprecated/FuckOffUICamera/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "SearchWithSpacesFix", + "modversion": "1.0.0", + "gameversion": "2024r177", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes search terms that include spaces.", + "searchtags": [ + "search", + "spaces", + "fix", + "meow" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r42/SearchWithSpacesFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SearchWithSpacesFix/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.DepricatedMods/FuckVivox/FuckVivox.csproj b/.Deprecated/FuckVivox/FuckVivox.csproj similarity index 100% rename from .DepricatedMods/FuckVivox/FuckVivox.csproj rename to .Deprecated/FuckVivox/FuckVivox.csproj diff --git a/.DepricatedMods/FuckVivox/HarmonyPatches.cs b/.Deprecated/FuckVivox/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/FuckVivox/HarmonyPatches.cs rename to .Deprecated/FuckVivox/HarmonyPatches.cs diff --git a/.DepricatedMods/FuckVivox/Main.cs b/.Deprecated/FuckVivox/Main.cs similarity index 100% rename from .DepricatedMods/FuckVivox/Main.cs rename to .Deprecated/FuckVivox/Main.cs diff --git a/.DepricatedMods/FuckVivox/Properties/AssemblyInfo.cs b/.Deprecated/FuckVivox/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/FuckVivox/Properties/AssemblyInfo.cs rename to .Deprecated/FuckVivox/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/FuckVivox/VivoxHelpers.cs b/.Deprecated/FuckVivox/VivoxHelpers.cs similarity index 100% rename from .DepricatedMods/FuckVivox/VivoxHelpers.cs rename to .Deprecated/FuckVivox/VivoxHelpers.cs diff --git a/.DepricatedMods/FuckVivox/WindowFocusManager.cs b/.Deprecated/FuckVivox/WindowFocusManager.cs similarity index 100% rename from .DepricatedMods/FuckVivox/WindowFocusManager.cs rename to .Deprecated/FuckVivox/WindowFocusManager.cs diff --git a/.DepricatedMods/FuckVivox/format.json b/.Deprecated/FuckVivox/format.json similarity index 100% rename from .DepricatedMods/FuckVivox/format.json rename to .Deprecated/FuckVivox/format.json diff --git a/GestureLock/GestureLock.csproj b/.Deprecated/GestureLock/GestureLock.csproj similarity index 100% rename from GestureLock/GestureLock.csproj rename to .Deprecated/GestureLock/GestureLock.csproj diff --git a/GestureLock/HarmonyPatches.cs b/.Deprecated/GestureLock/HarmonyPatches.cs similarity index 100% rename from GestureLock/HarmonyPatches.cs rename to .Deprecated/GestureLock/HarmonyPatches.cs diff --git a/GestureLock/Main.cs b/.Deprecated/GestureLock/Main.cs similarity index 100% rename from GestureLock/Main.cs rename to .Deprecated/GestureLock/Main.cs diff --git a/GestureLock/Properties/AssemblyInfo.cs b/.Deprecated/GestureLock/Properties/AssemblyInfo.cs similarity index 100% rename from GestureLock/Properties/AssemblyInfo.cs rename to .Deprecated/GestureLock/Properties/AssemblyInfo.cs diff --git a/GestureLock/README.md b/.Deprecated/GestureLock/README.md similarity index 100% rename from GestureLock/README.md rename to .Deprecated/GestureLock/README.md diff --git a/GestureLock/format.json b/.Deprecated/GestureLock/format.json similarity index 100% rename from GestureLock/format.json rename to .Deprecated/GestureLock/format.json diff --git a/.DepricatedMods/HeadBobbingFix/HarmonyPatches.cs b/.Deprecated/HeadBobbingFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/HeadBobbingFix/HarmonyPatches.cs rename to .Deprecated/HeadBobbingFix/HarmonyPatches.cs diff --git a/.DepricatedMods/HeadBobbingFix/HeadBobbingFix.csproj b/.Deprecated/HeadBobbingFix/HeadBobbingFix.csproj similarity index 100% rename from .DepricatedMods/HeadBobbingFix/HeadBobbingFix.csproj rename to .Deprecated/HeadBobbingFix/HeadBobbingFix.csproj diff --git a/.DepricatedMods/HeadBobbingFix/Main.cs b/.Deprecated/HeadBobbingFix/Main.cs similarity index 100% rename from .DepricatedMods/HeadBobbingFix/Main.cs rename to .Deprecated/HeadBobbingFix/Main.cs diff --git a/.DepricatedMods/HeadBobbingFix/Properties/AssemblyInfo.cs b/.Deprecated/HeadBobbingFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/HeadBobbingFix/Properties/AssemblyInfo.cs rename to .Deprecated/HeadBobbingFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/HeadBobbingFix/README.md b/.Deprecated/HeadBobbingFix/README.md similarity index 100% rename from .DepricatedMods/HeadBobbingFix/README.md rename to .Deprecated/HeadBobbingFix/README.md diff --git a/.DepricatedMods/HeadBobbingFix/format.json b/.Deprecated/HeadBobbingFix/format.json similarity index 100% rename from .DepricatedMods/HeadBobbingFix/format.json rename to .Deprecated/HeadBobbingFix/format.json diff --git a/ReconnectionSystemFix/ReconnectionSystemFix.csproj b/.Deprecated/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj similarity index 100% rename from ReconnectionSystemFix/ReconnectionSystemFix.csproj rename to .Deprecated/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj diff --git a/.DepricatedMods/HeadLookLockingInputFix/Main.cs b/.Deprecated/HeadLookLockingInputFix/Main.cs similarity index 100% rename from .DepricatedMods/HeadLookLockingInputFix/Main.cs rename to .Deprecated/HeadLookLockingInputFix/Main.cs diff --git a/.DepricatedMods/HeadLookLockingInputFix/Properties/AssemblyInfo.cs b/.Deprecated/HeadLookLockingInputFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/HeadLookLockingInputFix/Properties/AssemblyInfo.cs rename to .Deprecated/HeadLookLockingInputFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/HeadLookLockingInputFix/README.md b/.Deprecated/HeadLookLockingInputFix/README.md similarity index 100% rename from .DepricatedMods/HeadLookLockingInputFix/README.md rename to .Deprecated/HeadLookLockingInputFix/README.md diff --git a/.DepricatedMods/HeadLookLockingInputFix/format.json b/.Deprecated/HeadLookLockingInputFix/format.json similarity index 100% rename from .DepricatedMods/HeadLookLockingInputFix/format.json rename to .Deprecated/HeadLookLockingInputFix/format.json diff --git a/.DepricatedMods/IKAdjustments/HarmonyPatches.cs b/.Deprecated/IKAdjustments/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/IKAdjustments/HarmonyPatches.cs rename to .Deprecated/IKAdjustments/HarmonyPatches.cs diff --git a/.DepricatedMods/IKAdjustments/IKAdjuster.cs b/.Deprecated/IKAdjustments/IKAdjuster.cs similarity index 100% rename from .DepricatedMods/IKAdjustments/IKAdjuster.cs rename to .Deprecated/IKAdjustments/IKAdjuster.cs diff --git a/.DepricatedMods/IKAdjustments/IKAdjustments.csproj b/.Deprecated/IKAdjustments/IKAdjustments.csproj similarity index 100% rename from .DepricatedMods/IKAdjustments/IKAdjustments.csproj rename to .Deprecated/IKAdjustments/IKAdjustments.csproj diff --git a/.DepricatedMods/IKAdjustments/Integrations/BTKUIAddon.cs b/.Deprecated/IKAdjustments/Integrations/BTKUIAddon.cs similarity index 100% rename from .DepricatedMods/IKAdjustments/Integrations/BTKUIAddon.cs rename to .Deprecated/IKAdjustments/Integrations/BTKUIAddon.cs diff --git a/.DepricatedMods/IKAdjustments/Main.cs b/.Deprecated/IKAdjustments/Main.cs similarity index 100% rename from .DepricatedMods/IKAdjustments/Main.cs rename to .Deprecated/IKAdjustments/Main.cs diff --git a/.DepricatedMods/IKAdjustments/Properties/AssemblyInfo.cs b/.Deprecated/IKAdjustments/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/IKAdjustments/Properties/AssemblyInfo.cs rename to .Deprecated/IKAdjustments/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/IKFixes/HarmonyPatches.cs b/.Deprecated/IKFixes/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/IKFixes/HarmonyPatches.cs rename to .Deprecated/IKFixes/HarmonyPatches.cs diff --git a/.DepricatedMods/IKFixes/IKFixes.csproj b/.Deprecated/IKFixes/IKFixes.csproj similarity index 100% rename from .DepricatedMods/IKFixes/IKFixes.csproj rename to .Deprecated/IKFixes/IKFixes.csproj diff --git a/.DepricatedMods/IKFixes/Integrations/UIExKitAddon.cs b/.Deprecated/IKFixes/Integrations/UIExKitAddon.cs similarity index 100% rename from .DepricatedMods/IKFixes/Integrations/UIExKitAddon.cs rename to .Deprecated/IKFixes/Integrations/UIExKitAddon.cs diff --git a/.DepricatedMods/IKFixes/Main.cs b/.Deprecated/IKFixes/Main.cs similarity index 100% rename from .DepricatedMods/IKFixes/Main.cs rename to .Deprecated/IKFixes/Main.cs diff --git a/.DepricatedMods/IKFixes/Properties/AssemblyInfo.cs b/.Deprecated/IKFixes/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/IKFixes/Properties/AssemblyInfo.cs rename to .Deprecated/IKFixes/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/IKFixes/README.md b/.Deprecated/IKFixes/README.md similarity index 100% rename from .DepricatedMods/IKFixes/README.md rename to .Deprecated/IKFixes/README.md diff --git a/.DepricatedMods/IKFixes/format.json b/.Deprecated/IKFixes/format.json similarity index 100% rename from .DepricatedMods/IKFixes/format.json rename to .Deprecated/IKFixes/format.json diff --git a/IKSimulatedRootAngleFix/IKSimulatedRootAngleFix.csproj b/.Deprecated/IKSimulatedRootAngleFix/IKSimulatedRootAngleFix.csproj similarity index 100% rename from IKSimulatedRootAngleFix/IKSimulatedRootAngleFix.csproj rename to .Deprecated/IKSimulatedRootAngleFix/IKSimulatedRootAngleFix.csproj diff --git a/IKSimulatedRootAngleFix/Main.cs b/.Deprecated/IKSimulatedRootAngleFix/Main.cs similarity index 100% rename from IKSimulatedRootAngleFix/Main.cs rename to .Deprecated/IKSimulatedRootAngleFix/Main.cs diff --git a/IKSimulatedRootAngleFix/Properties/AssemblyInfo.cs b/.Deprecated/IKSimulatedRootAngleFix/Properties/AssemblyInfo.cs similarity index 100% rename from IKSimulatedRootAngleFix/Properties/AssemblyInfo.cs rename to .Deprecated/IKSimulatedRootAngleFix/Properties/AssemblyInfo.cs diff --git a/.Deprecated/IKSimulatedRootAngleFix/README.md b/.Deprecated/IKSimulatedRootAngleFix/README.md new file mode 100644 index 0000000..8a46af2 --- /dev/null +++ b/.Deprecated/IKSimulatedRootAngleFix/README.md @@ -0,0 +1,14 @@ +# IKSimulatedRootAngleFix + +Fixes a small issue with Desktop & HalfBody root angle being incorrectly calculated while on rotating Movement Parents. If you've ever noticed your body/feet insisting on facing opposite of the direction you are rotating, this fixes that. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/IKSimulatedRootAngleFix/format.json b/.Deprecated/IKSimulatedRootAngleFix/format.json similarity index 100% rename from IKSimulatedRootAngleFix/format.json rename to .Deprecated/IKSimulatedRootAngleFix/format.json diff --git a/.DepricatedMods/InteractionTest/AutoArmIK.cs b/.Deprecated/InteractionTest/AutoArmIK.cs similarity index 100% rename from .DepricatedMods/InteractionTest/AutoArmIK.cs rename to .Deprecated/InteractionTest/AutoArmIK.cs diff --git a/.DepricatedMods/InteractionTest/ColliderTest/AvatarColliderStruct.cs b/.Deprecated/InteractionTest/ColliderTest/AvatarColliderStruct.cs similarity index 100% rename from .DepricatedMods/InteractionTest/ColliderTest/AvatarColliderStruct.cs rename to .Deprecated/InteractionTest/ColliderTest/AvatarColliderStruct.cs diff --git a/.DepricatedMods/InteractionTest/ColliderTest/AvatarColliders.cs b/.Deprecated/InteractionTest/ColliderTest/AvatarColliders.cs similarity index 100% rename from .DepricatedMods/InteractionTest/ColliderTest/AvatarColliders.cs rename to .Deprecated/InteractionTest/ColliderTest/AvatarColliders.cs diff --git a/.DepricatedMods/InteractionTest/ColliderTest/LineColliderTest.cs b/.Deprecated/InteractionTest/ColliderTest/LineColliderTest.cs similarity index 100% rename from .DepricatedMods/InteractionTest/ColliderTest/LineColliderTest.cs rename to .Deprecated/InteractionTest/ColliderTest/LineColliderTest.cs diff --git a/.DepricatedMods/InteractionTest/GrabbableAvatar.cs b/.Deprecated/InteractionTest/GrabbableAvatar.cs similarity index 100% rename from .DepricatedMods/InteractionTest/GrabbableAvatar.cs rename to .Deprecated/InteractionTest/GrabbableAvatar.cs diff --git a/.DepricatedMods/InteractionTest/GrabbingAvatar.cs b/.Deprecated/InteractionTest/GrabbingAvatar.cs similarity index 100% rename from .DepricatedMods/InteractionTest/GrabbingAvatar.cs rename to .Deprecated/InteractionTest/GrabbingAvatar.cs diff --git a/.DepricatedMods/InteractionTest/HarmonyPatches.cs b/.Deprecated/InteractionTest/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/InteractionTest/HarmonyPatches.cs rename to .Deprecated/InteractionTest/HarmonyPatches.cs diff --git a/.DepricatedMods/InteractionTest/InteractionTest.csproj b/.Deprecated/InteractionTest/InteractionTest.csproj similarity index 100% rename from .DepricatedMods/InteractionTest/InteractionTest.csproj rename to .Deprecated/InteractionTest/InteractionTest.csproj diff --git a/.DepricatedMods/InteractionTest/Main.cs b/.Deprecated/InteractionTest/Main.cs similarity index 100% rename from .DepricatedMods/InteractionTest/Main.cs rename to .Deprecated/InteractionTest/Main.cs diff --git a/.DepricatedMods/InteractionTest/Properties/AssemblyInfo.cs b/.Deprecated/InteractionTest/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/InteractionTest/Properties/AssemblyInfo.cs rename to .Deprecated/InteractionTest/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/InteractionTest/README.md b/.Deprecated/InteractionTest/README.md similarity index 100% rename from .DepricatedMods/InteractionTest/README.md rename to .Deprecated/InteractionTest/README.md diff --git a/AvatarScaleMod/format.json b/.Deprecated/InteractionTest/format.json similarity index 100% rename from AvatarScaleMod/format.json rename to .Deprecated/InteractionTest/format.json diff --git a/.DepricatedMods/JumpPatch/HarmonyPatches.cs b/.Deprecated/JumpPatch/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/JumpPatch/HarmonyPatches.cs rename to .Deprecated/JumpPatch/HarmonyPatches.cs diff --git a/.DepricatedMods/JumpPatch/JumpPatch.csproj b/.Deprecated/JumpPatch/JumpPatch.csproj similarity index 100% rename from .DepricatedMods/JumpPatch/JumpPatch.csproj rename to .Deprecated/JumpPatch/JumpPatch.csproj diff --git a/.DepricatedMods/JumpPatch/Main.cs b/.Deprecated/JumpPatch/Main.cs similarity index 100% rename from .DepricatedMods/JumpPatch/Main.cs rename to .Deprecated/JumpPatch/Main.cs diff --git a/.DepricatedMods/JumpPatch/Properties/AssemblyInfo.cs b/.Deprecated/JumpPatch/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/JumpPatch/Properties/AssemblyInfo.cs rename to .Deprecated/JumpPatch/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/JumpPatch/format.json b/.Deprecated/JumpPatch/format.json similarity index 100% rename from .DepricatedMods/JumpPatch/format.json rename to .Deprecated/JumpPatch/format.json diff --git a/.DepricatedMods/LateInitComponentHelperHack/LateInitComponentHelperHack.csproj b/.Deprecated/LateInitComponentHelperHack/LateInitComponentHelperHack.csproj similarity index 100% rename from .DepricatedMods/LateInitComponentHelperHack/LateInitComponentHelperHack.csproj rename to .Deprecated/LateInitComponentHelperHack/LateInitComponentHelperHack.csproj diff --git a/.DepricatedMods/LateInitComponentHelperHack/Main.cs b/.Deprecated/LateInitComponentHelperHack/Main.cs similarity index 100% rename from .DepricatedMods/LateInitComponentHelperHack/Main.cs rename to .Deprecated/LateInitComponentHelperHack/Main.cs diff --git a/.DepricatedMods/LateInitComponentHelperHack/Properties/AssemblyInfo.cs b/.Deprecated/LateInitComponentHelperHack/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/LateInitComponentHelperHack/Properties/AssemblyInfo.cs rename to .Deprecated/LateInitComponentHelperHack/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/LateInitComponentHelperHack/format.json b/.Deprecated/LateInitComponentHelperHack/format.json similarity index 100% rename from .DepricatedMods/LateInitComponentHelperHack/format.json rename to .Deprecated/LateInitComponentHelperHack/format.json diff --git a/LegacyContentMitigation/Components/CameraCallbackLogger.cs b/.Deprecated/LegacyContentMitigation/Components/CameraCallbackLogger.cs similarity index 100% rename from LegacyContentMitigation/Components/CameraCallbackLogger.cs rename to .Deprecated/LegacyContentMitigation/Components/CameraCallbackLogger.cs diff --git a/.Deprecated/LegacyContentMitigation/Components/FaceMirror.cs b/.Deprecated/LegacyContentMitigation/Components/FaceMirror.cs new file mode 100644 index 0000000..65f3e3b --- /dev/null +++ b/.Deprecated/LegacyContentMitigation/Components/FaceMirror.cs @@ -0,0 +1,100 @@ +using ABI_RC.Core; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using NAK.LegacyContentMitigation; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.XR; + +namespace LegacyContentMitigation.Components; + +public class FaceMirror : MonoBehaviour +{ + private Camera _parentCamera; + private Camera _camera; + public Rect shiftRect; + private CommandBuffer _viewportBuffer; + + private void Start() { + _parentCamera = GetComponent(); + _camera = new GameObject("Face Mirror").AddComponent(); + _camera.transform.parent = transform; + _camera.CopyFrom(_parentCamera); + _camera.ResetReplacementShader(); + _camera.depth = 99; + _camera.clearFlags = CameraClearFlags.Depth; + _camera.transform.position += transform.forward * 0.5f; + _camera.transform.rotation *= Quaternion.Euler(0, 180, 0); + + // View only CVRLayers.PlayerLocal + _camera.cullingMask = 1 << CVRLayers.PlayerLocal; + + // Create and cache the command buffer + _viewportBuffer = new CommandBuffer(); + _viewportBuffer.SetViewport(shiftRect); + + _camera.AddCommandBuffer(CameraEvent.BeforeDepthTexture, _viewportBuffer); + _camera.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, _viewportBuffer); + _camera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _viewportBuffer); + _camera.AddCommandBuffer(CameraEvent.BeforeImageEffects, _viewportBuffer); + } + + private void Update() + { + if (ModSettings.EntryUseFaceMirror.Value == false) + { + _camera.enabled = false; + return; + } + _camera.enabled = true; + + // Update camera distance + _camera.transform.localPosition = Vector3.forward * ModSettings.EntryFaceMirrorDistance.Value; + + // Get the display resolution based on VR status + int displayWidth, displayHeight; + if (MetaPort.Instance.isUsingVr) + { + displayWidth = XRSettings.eyeTextureWidth; + displayHeight = XRSettings.eyeTextureHeight; + } + else + { + displayWidth = Screen.width; + displayHeight = Screen.height; + } + + // Calculate pixel sizes first + float pixelSizeX = ModSettings.EntryFaceMirrorSizeX.Value * displayWidth; + float pixelSizeY = ModSettings.EntryFaceMirrorSizeY.Value * displayHeight; + + // Calculate offsets from center + float pixelOffsetX = (ModSettings.EntryFaceMirrorOffsetX.Value * displayWidth) - (pixelSizeX * 0.5f) + (displayWidth * 0.5f); + float pixelOffsetY = (ModSettings.EntryFaceMirrorOffsetY.Value * displayHeight) - (pixelSizeY * 0.5f) + (displayHeight * 0.5f); + + _camera.transform.localScale = Vector3.one * ModSettings.EntryFaceMirrorCameraScale.Value; + + Vector3 playerup = PlayerSetup.Instance.transform.up; + Vector3 cameraForward = _parentCamera.transform.forward; + + // Check if playerup and cameraForward are nearly aligned + if (Mathf.Abs(Vector3.Dot(playerup, cameraForward)) <= Mathf.Epsilon) { + playerup = -_parentCamera.transform.forward; + cameraForward = _parentCamera.transform.up; + } + + _camera.transform.rotation = Quaternion.LookRotation(-cameraForward, playerup); + + // Create viewport rect with pixel values + shiftRect = new Rect( + pixelOffsetX, + pixelOffsetY, + pixelSizeX, + pixelSizeY + ); + + // Update the cached buffer's viewport + _viewportBuffer.Clear(); + _viewportBuffer.SetViewport(shiftRect); + } +} \ No newline at end of file diff --git a/LegacyContentMitigation/Components/FakeMultiPassHack.cs b/.Deprecated/LegacyContentMitigation/Components/FakeMultiPassHack.cs similarity index 100% rename from LegacyContentMitigation/Components/FakeMultiPassHack.cs rename to .Deprecated/LegacyContentMitigation/Components/FakeMultiPassHack.cs diff --git a/LegacyContentMitigation/Integrations/BtkUiAddon.cs b/.Deprecated/LegacyContentMitigation/Integrations/BtkUiAddon.cs similarity index 100% rename from LegacyContentMitigation/Integrations/BtkUiAddon.cs rename to .Deprecated/LegacyContentMitigation/Integrations/BtkUiAddon.cs diff --git a/LegacyContentMitigation/LegacyContentMitigation.csproj b/.Deprecated/LegacyContentMitigation/LegacyContentMitigation.csproj similarity index 100% rename from LegacyContentMitigation/LegacyContentMitigation.csproj rename to .Deprecated/LegacyContentMitigation/LegacyContentMitigation.csproj diff --git a/LegacyContentMitigation/Main.cs b/.Deprecated/LegacyContentMitigation/Main.cs similarity index 100% rename from LegacyContentMitigation/Main.cs rename to .Deprecated/LegacyContentMitigation/Main.cs diff --git a/.Deprecated/LegacyContentMitigation/ModSettings.cs b/.Deprecated/LegacyContentMitigation/ModSettings.cs new file mode 100644 index 0000000..a20c93d --- /dev/null +++ b/.Deprecated/LegacyContentMitigation/ModSettings.cs @@ -0,0 +1,52 @@ +using MelonLoader; + +namespace NAK.LegacyContentMitigation; + +internal static class ModSettings +{ + #region Constants + + internal const string ModName = nameof(LegacyContentMitigation); + internal const string LCM_SettingsCategory = "Legacy Content Mitigation"; + + #endregion Constants + + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(ModName); + + internal static readonly MelonPreferences_Entry EntryAutoForLegacyWorlds = + Category.CreateEntry("auto_for_legacy_worlds", true, + "Auto For Legacy Worlds", description: "Should Legacy View be auto enabled for detected Legacy worlds?"); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorDistance = + Category.CreateEntry("face_mirror_distance", 0.5f, + "Face Mirror Distance", description: "Distance from the camera to place the face mirror."); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorOffsetX = + Category.CreateEntry("face_mirror_offset_x", 0f, + "Face Mirror Offset X", description: "Offset the face mirror on the X axis."); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorOffsetY = + Category.CreateEntry("face_mirror_offset_y", 0f, + "Face Mirror Offset Y", description: "Offset the face mirror on the Y axis."); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorSizeX = + Category.CreateEntry("face_mirror_size_x", 0.5f, + "Face Mirror Size X", description: "Size of the face mirror on the X axis."); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorSizeY = + Category.CreateEntry("face_mirror_size_y", 0.5f, + "Face Mirror Size Y", description: "Size of the face mirror on the Y axis."); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorCameraScale = + Category.CreateEntry("face_mirror_camera_scale", 1f, + "Face Mirror Camera Scale", description: "Scale of the face mirror camera."); + + internal static readonly MelonPreferences_Entry EntryUseFaceMirror = + Category.CreateEntry("use_face_mirror", true, + "Use Face Mirror", description: "Should the face mirror be used?"); + + #endregion Melon Preferences +} \ No newline at end of file diff --git a/LegacyContentMitigation/Patches.cs b/.Deprecated/LegacyContentMitigation/Patches.cs similarity index 97% rename from LegacyContentMitigation/Patches.cs rename to .Deprecated/LegacyContentMitigation/Patches.cs index 2b151e8..a389282 100644 --- a/LegacyContentMitigation/Patches.cs +++ b/.Deprecated/LegacyContentMitigation/Patches.cs @@ -9,6 +9,7 @@ using ABI.CCK.Components; using cohtml; using cohtml.Net; using HarmonyLib; +using LegacyContentMitigation.Components; using UnityEngine; using UnityEngine.Rendering.PostProcessing; using UnityEngine.SceneManagement; @@ -21,6 +22,9 @@ internal static class PlayerSetup_Patches [HarmonyPatch(typeof(PlayerSetup), nameof(PlayerSetup.Start))] private static void Postfix_PlayerSetup_Start(ref PlayerSetup __instance) { + __instance.vrCam.AddComponentIfMissing(); + __instance.desktopCam.AddComponentIfMissing(); + FakeMultiPassHack.Instance = __instance.vrCam.AddComponentIfMissing(); FakeMultiPassHack.Instance.enabled = ModSettings.EntryAutoForLegacyWorlds.Value; } diff --git a/LegacyContentMitigation/Properties/AssemblyInfo.cs b/.Deprecated/LegacyContentMitigation/Properties/AssemblyInfo.cs similarity index 100% rename from LegacyContentMitigation/Properties/AssemblyInfo.cs rename to .Deprecated/LegacyContentMitigation/Properties/AssemblyInfo.cs diff --git a/LegacyContentMitigation/README.md b/.Deprecated/LegacyContentMitigation/README.md similarity index 100% rename from LegacyContentMitigation/README.md rename to .Deprecated/LegacyContentMitigation/README.md diff --git a/LegacyContentMitigation/format.json b/.Deprecated/LegacyContentMitigation/format.json similarity index 96% rename from LegacyContentMitigation/format.json rename to .Deprecated/LegacyContentMitigation/format.json index 480d0fb..e801124 100644 --- a/LegacyContentMitigation/format.json +++ b/.Deprecated/LegacyContentMitigation/format.json @@ -1,7 +1,7 @@ { - "_id": -1, + "_id": 247, "name": "LegacyContentMitigation", - "modversion": "1.0.1", + "modversion": "1.0.2", "gameversion": "2024r177", "loaderversion": "0.6.1", "modtype": "Mod", diff --git a/.DepricatedMods/MenuScalePatch/HarmonyPatches.cs b/.Deprecated/MenuScalePatch/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/HarmonyPatches.cs rename to .Deprecated/MenuScalePatch/HarmonyPatches.cs diff --git a/.DepricatedMods/MenuScalePatch/Helpers/MainMenuHelper.cs b/.Deprecated/MenuScalePatch/Helpers/MainMenuHelper.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/Helpers/MainMenuHelper.cs rename to .Deprecated/MenuScalePatch/Helpers/MainMenuHelper.cs diff --git a/.DepricatedMods/MenuScalePatch/Helpers/QuickMenuHelper.cs b/.Deprecated/MenuScalePatch/Helpers/QuickMenuHelper.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/Helpers/QuickMenuHelper.cs rename to .Deprecated/MenuScalePatch/Helpers/QuickMenuHelper.cs diff --git a/.DepricatedMods/MenuScalePatch/MSP_Menus.cs b/.Deprecated/MenuScalePatch/MSP_Menus.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/MSP_Menus.cs rename to .Deprecated/MenuScalePatch/MSP_Menus.cs diff --git a/.DepricatedMods/MenuScalePatch/Main.cs b/.Deprecated/MenuScalePatch/Main.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/Main.cs rename to .Deprecated/MenuScalePatch/Main.cs diff --git a/.DepricatedMods/MenuScalePatch/MenuScalePatch.csproj b/.Deprecated/MenuScalePatch/MenuScalePatch.csproj similarity index 100% rename from .DepricatedMods/MenuScalePatch/MenuScalePatch.csproj rename to .Deprecated/MenuScalePatch/MenuScalePatch.csproj diff --git a/.DepricatedMods/MenuScalePatch/Properties/AssemblyInfo.cs b/.Deprecated/MenuScalePatch/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/Properties/AssemblyInfo.cs rename to .Deprecated/MenuScalePatch/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/MenuScalePatch/README.md b/.Deprecated/MenuScalePatch/README.md similarity index 100% rename from .DepricatedMods/MenuScalePatch/README.md rename to .Deprecated/MenuScalePatch/README.md diff --git a/.DepricatedMods/MenuScalePatch/format.json b/.Deprecated/MenuScalePatch/format.json similarity index 100% rename from .DepricatedMods/MenuScalePatch/format.json rename to .Deprecated/MenuScalePatch/format.json diff --git a/.DepricatedMods/MoreMenuOptions/Main.cs b/.Deprecated/MoreMenuOptions/Main.cs similarity index 100% rename from .DepricatedMods/MoreMenuOptions/Main.cs rename to .Deprecated/MoreMenuOptions/Main.cs diff --git a/.DepricatedMods/MoreMenuOptions/ModSettings.cs b/.Deprecated/MoreMenuOptions/ModSettings.cs similarity index 100% rename from .DepricatedMods/MoreMenuOptions/ModSettings.cs rename to .Deprecated/MoreMenuOptions/ModSettings.cs diff --git a/.DepricatedMods/MoreMenuOptions/MoreMenuOptions.csproj b/.Deprecated/MoreMenuOptions/MoreMenuOptions.csproj similarity index 100% rename from .DepricatedMods/MoreMenuOptions/MoreMenuOptions.csproj rename to .Deprecated/MoreMenuOptions/MoreMenuOptions.csproj diff --git a/.DepricatedMods/MoreMenuOptions/Properties/AssemblyInfo.cs b/.Deprecated/MoreMenuOptions/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/MoreMenuOptions/Properties/AssemblyInfo.cs rename to .Deprecated/MoreMenuOptions/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/MoreMenuOptions/README.md b/.Deprecated/MoreMenuOptions/README.md similarity index 100% rename from .DepricatedMods/MoreMenuOptions/README.md rename to .Deprecated/MoreMenuOptions/README.md diff --git a/.DepricatedMods/MoreMenuOptions/format.json b/.Deprecated/MoreMenuOptions/format.json similarity index 100% rename from .DepricatedMods/MoreMenuOptions/format.json rename to .Deprecated/MoreMenuOptions/format.json diff --git a/.DepricatedMods/NAK.CustomComponents/Components/NAKPointerTracker.cs b/.Deprecated/NAK.CustomComponents/Components/NAKPointerTracker.cs similarity index 100% rename from .DepricatedMods/NAK.CustomComponents/Components/NAKPointerTracker.cs rename to .Deprecated/NAK.CustomComponents/Components/NAKPointerTracker.cs diff --git a/.DepricatedMods/NAK.CustomComponents/CustomComponents.csproj b/.Deprecated/NAK.CustomComponents/CustomComponents.csproj similarity index 100% rename from .DepricatedMods/NAK.CustomComponents/CustomComponents.csproj rename to .Deprecated/NAK.CustomComponents/CustomComponents.csproj diff --git a/.DepricatedMods/NAK.CustomComponents/Main.cs b/.Deprecated/NAK.CustomComponents/Main.cs similarity index 100% rename from .DepricatedMods/NAK.CustomComponents/Main.cs rename to .Deprecated/NAK.CustomComponents/Main.cs diff --git a/.DepricatedMods/NAK.CustomComponents/Properties/AssemblyInfo.cs b/.Deprecated/NAK.CustomComponents/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/NAK.CustomComponents/Properties/AssemblyInfo.cs rename to .Deprecated/NAK.CustomComponents/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/NAK.CustomComponents/format.json b/.Deprecated/NAK.CustomComponents/format.json similarity index 100% rename from .DepricatedMods/NAK.CustomComponents/format.json rename to .Deprecated/NAK.CustomComponents/format.json diff --git a/Nevermind/Main.cs b/.Deprecated/Nevermind/Main.cs similarity index 100% rename from Nevermind/Main.cs rename to .Deprecated/Nevermind/Main.cs diff --git a/Nevermind/Nevermind.csproj b/.Deprecated/Nevermind/Nevermind.csproj similarity index 100% rename from Nevermind/Nevermind.csproj rename to .Deprecated/Nevermind/Nevermind.csproj diff --git a/Nevermind/Properties/AssemblyInfo.cs b/.Deprecated/Nevermind/Properties/AssemblyInfo.cs similarity index 100% rename from Nevermind/Properties/AssemblyInfo.cs rename to .Deprecated/Nevermind/Properties/AssemblyInfo.cs diff --git a/Nevermind/README.md b/.Deprecated/Nevermind/README.md similarity index 100% rename from Nevermind/README.md rename to .Deprecated/Nevermind/README.md diff --git a/Nevermind/format.json b/.Deprecated/Nevermind/format.json similarity index 100% rename from Nevermind/format.json rename to .Deprecated/Nevermind/format.json diff --git a/.DepricatedMods/NoDepthOnlyFlat/Main.cs b/.Deprecated/NoDepthOnlyFlat/Main.cs similarity index 100% rename from .DepricatedMods/NoDepthOnlyFlat/Main.cs rename to .Deprecated/NoDepthOnlyFlat/Main.cs diff --git a/SearchWithSpacesFix/SearchWithSpacesFix.csproj b/.Deprecated/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj similarity index 100% rename from SearchWithSpacesFix/SearchWithSpacesFix.csproj rename to .Deprecated/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj diff --git a/.DepricatedMods/NoDepthOnlyFlat/Properties/AssemblyInfo.cs b/.Deprecated/NoDepthOnlyFlat/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/NoDepthOnlyFlat/Properties/AssemblyInfo.cs rename to .Deprecated/NoDepthOnlyFlat/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/NoDepthOnlyFlat/README.md b/.Deprecated/NoDepthOnlyFlat/README.md similarity index 100% rename from .DepricatedMods/NoDepthOnlyFlat/README.md rename to .Deprecated/NoDepthOnlyFlat/README.md diff --git a/.DepricatedMods/NoDepthOnlyFlat/format.json b/.Deprecated/NoDepthOnlyFlat/format.json similarity index 100% rename from .DepricatedMods/NoDepthOnlyFlat/format.json rename to .Deprecated/NoDepthOnlyFlat/format.json diff --git a/.DepricatedMods/PickupPushPull/HarmonyPatches.cs b/.Deprecated/PickupPushPull/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/PickupPushPull/HarmonyPatches.cs rename to .Deprecated/PickupPushPull/HarmonyPatches.cs diff --git a/.DepricatedMods/PickupPushPull/InputModules/PickupPushPull_Module.cs b/.Deprecated/PickupPushPull/InputModules/PickupPushPull_Module.cs similarity index 100% rename from .DepricatedMods/PickupPushPull/InputModules/PickupPushPull_Module.cs rename to .Deprecated/PickupPushPull/InputModules/PickupPushPull_Module.cs diff --git a/.DepricatedMods/PickupPushPull/Main.cs b/.Deprecated/PickupPushPull/Main.cs similarity index 100% rename from .DepricatedMods/PickupPushPull/Main.cs rename to .Deprecated/PickupPushPull/Main.cs diff --git a/.DepricatedMods/PickupPushPull/PickupPushPull.csproj b/.Deprecated/PickupPushPull/PickupPushPull.csproj similarity index 100% rename from .DepricatedMods/PickupPushPull/PickupPushPull.csproj rename to .Deprecated/PickupPushPull/PickupPushPull.csproj diff --git a/.DepricatedMods/PickupPushPull/Properties/AssemblyInfo.cs b/.Deprecated/PickupPushPull/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/PickupPushPull/Properties/AssemblyInfo.cs rename to .Deprecated/PickupPushPull/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/PickupPushPull/format.json b/.Deprecated/PickupPushPull/format.json similarity index 100% rename from .DepricatedMods/PickupPushPull/format.json rename to .Deprecated/PickupPushPull/format.json diff --git a/.DepricatedMods/PlaySpaceScaleFix/HarmonyPatches.cs b/.Deprecated/PlaySpaceScaleFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/HarmonyPatches.cs rename to .Deprecated/PlaySpaceScaleFix/HarmonyPatches.cs diff --git a/.DepricatedMods/PlaySpaceScaleFix/Main.cs b/.Deprecated/PlaySpaceScaleFix/Main.cs similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/Main.cs rename to .Deprecated/PlaySpaceScaleFix/Main.cs diff --git a/.DepricatedMods/PlaySpaceScaleFix/PlaySpaceScaleFix.csproj b/.Deprecated/PlaySpaceScaleFix/PlaySpaceScaleFix.csproj similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/PlaySpaceScaleFix.csproj rename to .Deprecated/PlaySpaceScaleFix/PlaySpaceScaleFix.csproj diff --git a/.DepricatedMods/PlaySpaceScaleFix/Properties/AssemblyInfo.cs b/.Deprecated/PlaySpaceScaleFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/Properties/AssemblyInfo.cs rename to .Deprecated/PlaySpaceScaleFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/PlaySpaceScaleFix/README.md b/.Deprecated/PlaySpaceScaleFix/README.md similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/README.md rename to .Deprecated/PlaySpaceScaleFix/README.md diff --git a/.DepricatedMods/PlaySpaceScaleFix/format.json b/.Deprecated/PlaySpaceScaleFix/format.json similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/format.json rename to .Deprecated/PlaySpaceScaleFix/format.json diff --git a/ReconnectionSystemFix/Main.cs b/.Deprecated/ReconnectionSystemFix/Main.cs similarity index 100% rename from ReconnectionSystemFix/Main.cs rename to .Deprecated/ReconnectionSystemFix/Main.cs diff --git a/ReconnectionSystemFix/Patches.cs b/.Deprecated/ReconnectionSystemFix/Patches.cs similarity index 100% rename from ReconnectionSystemFix/Patches.cs rename to .Deprecated/ReconnectionSystemFix/Patches.cs diff --git a/ReconnectionSystemFix/Properties/AssemblyInfo.cs b/.Deprecated/ReconnectionSystemFix/Properties/AssemblyInfo.cs similarity index 100% rename from ReconnectionSystemFix/Properties/AssemblyInfo.cs rename to .Deprecated/ReconnectionSystemFix/Properties/AssemblyInfo.cs diff --git a/ReconnectionSystemFix/README.md b/.Deprecated/ReconnectionSystemFix/README.md similarity index 100% rename from ReconnectionSystemFix/README.md rename to .Deprecated/ReconnectionSystemFix/README.md diff --git a/.Deprecated/ReconnectionSystemFix/ReconnectionSystemFix.csproj b/.Deprecated/ReconnectionSystemFix/ReconnectionSystemFix.csproj new file mode 100644 index 0000000..bec5b03 --- /dev/null +++ b/.Deprecated/ReconnectionSystemFix/ReconnectionSystemFix.csproj @@ -0,0 +1,6 @@ + + + + LoadedObjectHack + + diff --git a/ReconnectionSystemFix/format.json b/.Deprecated/ReconnectionSystemFix/format.json similarity index 100% rename from ReconnectionSystemFix/format.json rename to .Deprecated/ReconnectionSystemFix/format.json diff --git a/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Main.cs b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Main.cs new file mode 100644 index 0000000..7687ea6 --- /dev/null +++ b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Main.cs @@ -0,0 +1,43 @@ +using System.Reflection; +using ABI_RC.Core.Player; +using HarmonyLib; +using MelonLoader; +using UnityEngine; + +namespace NAK.RemoteAvatarDisablingCameraOnFirstFrameFix; + +public class RemoteAvatarDisablingCameraOnFirstFrameFixMod : MelonMod +{ + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(PuppetMaster).GetMethod(nameof(PuppetMaster.AvatarInstantiated), + BindingFlags.Public | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(RemoteAvatarDisablingCameraOnFirstFrameFixMod).GetMethod(nameof(OnPuppetMasterAvatarInstantiated), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + } + + private static void OnPuppetMasterAvatarInstantiated(PuppetMaster __instance) + { + if (__instance._animator == null) return; + + __instance._animator.WriteDefaultValues(); + __instance._animator.keepAnimatorStateOnDisable = false; + __instance._animator.writeDefaultValuesOnDisable = false; + } + + // private static void OnPuppetMasterAvatarInstantiated(PuppetMaster __instance) + // { + // if (__instance._animator == null) return; + // + // // Set culling mode to always animate + // __instance._animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; + // + // // Update the animator to force it to do the first frame + // __instance._animator.Update(0f); + // + // // Set culling mode back to cull update transforms + // __instance._animator.cullingMode = AnimatorCullingMode.CullUpdateTransforms; + // } +} \ No newline at end of file diff --git a/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Properties/AssemblyInfo.cs b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9f70d66 --- /dev/null +++ b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using MelonLoader; +using NAK.RemoteAvatarDisablingCameraOnFirstFrameFix.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.RemoteAvatarDisablingCameraOnFirstFrameFix))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.RemoteAvatarDisablingCameraOnFirstFrameFix))] + +[assembly: MelonInfo( + typeof(NAK.RemoteAvatarDisablingCameraOnFirstFrameFix.RemoteAvatarDisablingCameraOnFirstFrameFixMod), + nameof(NAK.RemoteAvatarDisablingCameraOnFirstFrameFix), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RemoteAvatarDisablingCameraOnFirstFrameFix" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: HarmonyDontPatchAll] + +namespace NAK.RemoteAvatarDisablingCameraOnFirstFrameFix.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/README.md b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/README.md new file mode 100644 index 0000000..8a46af2 --- /dev/null +++ b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/README.md @@ -0,0 +1,14 @@ +# IKSimulatedRootAngleFix + +Fixes a small issue with Desktop & HalfBody root angle being incorrectly calculated while on rotating Movement Parents. If you've ever noticed your body/feet insisting on facing opposite of the direction you are rotating, this fixes that. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/RemoteAvatarDisablingCameraOnFirstFrameFix.csproj b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/RemoteAvatarDisablingCameraOnFirstFrameFix.csproj new file mode 100644 index 0000000..bec5b03 --- /dev/null +++ b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/RemoteAvatarDisablingCameraOnFirstFrameFix.csproj @@ -0,0 +1,6 @@ + + + + LoadedObjectHack + + diff --git a/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/format.json b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/format.json new file mode 100644 index 0000000..ddf506b --- /dev/null +++ b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/format.json @@ -0,0 +1,24 @@ +{ + "_id": -1, + "name": "AASDefaultProfileFix", + "modversion": "1.0.0", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes the Default AAS profile not being applied when loading into an avatar without a profile selected.\n\nBy default, the game will not apply anything and the avatar will default to the state found within the Controller parameters.", + "searchtags": [ + "aas", + "profile", + "default", + "fix", + "meow" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r33/AASDefaultProfileFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AASDefaultProfileFix/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/SearchWithSpacesFix/Main.cs b/.Deprecated/SearchWithSpacesFix/Main.cs similarity index 100% rename from SearchWithSpacesFix/Main.cs rename to .Deprecated/SearchWithSpacesFix/Main.cs diff --git a/SearchWithSpacesFix/Properties/AssemblyInfo.cs b/.Deprecated/SearchWithSpacesFix/Properties/AssemblyInfo.cs similarity index 100% rename from SearchWithSpacesFix/Properties/AssemblyInfo.cs rename to .Deprecated/SearchWithSpacesFix/Properties/AssemblyInfo.cs diff --git a/.Deprecated/SearchWithSpacesFix/README.md b/.Deprecated/SearchWithSpacesFix/README.md new file mode 100644 index 0000000..1c4c5bc --- /dev/null +++ b/.Deprecated/SearchWithSpacesFix/README.md @@ -0,0 +1,14 @@ +# SearchWithSpacesFix + +Fixes search terms that use spaces. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/.Deprecated/SearchWithSpacesFix/SearchWithSpacesFix.csproj b/.Deprecated/SearchWithSpacesFix/SearchWithSpacesFix.csproj new file mode 100644 index 0000000..e94f9dc --- /dev/null +++ b/.Deprecated/SearchWithSpacesFix/SearchWithSpacesFix.csproj @@ -0,0 +1,2 @@ + + diff --git a/.Deprecated/SearchWithSpacesFix/format.json b/.Deprecated/SearchWithSpacesFix/format.json new file mode 100644 index 0000000..f8950ca --- /dev/null +++ b/.Deprecated/SearchWithSpacesFix/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "SearchWithSpacesFix", + "modversion": "1.0.0", + "gameversion": "2024r177", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes search terms that include spaces.", + "searchtags": [ + "search", + "spaces", + "fix", + "meow" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r42/SearchWithSpacesFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SearchWithSpacesFix/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/ShadowCloneFallback/Main.cs b/.Deprecated/ShadowCloneFallback/Main.cs similarity index 100% rename from ShadowCloneFallback/Main.cs rename to .Deprecated/ShadowCloneFallback/Main.cs diff --git a/ShadowCloneFallback/Properties/AssemblyInfo.cs b/.Deprecated/ShadowCloneFallback/Properties/AssemblyInfo.cs similarity index 100% rename from ShadowCloneFallback/Properties/AssemblyInfo.cs rename to .Deprecated/ShadowCloneFallback/Properties/AssemblyInfo.cs diff --git a/ShadowCloneFallback/README.md b/.Deprecated/ShadowCloneFallback/README.md similarity index 100% rename from ShadowCloneFallback/README.md rename to .Deprecated/ShadowCloneFallback/README.md diff --git a/ShadowCloneFallback/ShadowCloneFallback.csproj b/.Deprecated/ShadowCloneFallback/ShadowCloneFallback.csproj similarity index 100% rename from ShadowCloneFallback/ShadowCloneFallback.csproj rename to .Deprecated/ShadowCloneFallback/ShadowCloneFallback.csproj diff --git a/ShadowCloneFallback/format.json b/.Deprecated/ShadowCloneFallback/format.json similarity index 100% rename from ShadowCloneFallback/format.json rename to .Deprecated/ShadowCloneFallback/format.json diff --git a/SmartReticle/Main.cs b/.Deprecated/SmartReticle/Main.cs similarity index 100% rename from SmartReticle/Main.cs rename to .Deprecated/SmartReticle/Main.cs diff --git a/SmartReticle/Properties/AssemblyInfo.cs b/.Deprecated/SmartReticle/Properties/AssemblyInfo.cs similarity index 100% rename from SmartReticle/Properties/AssemblyInfo.cs rename to .Deprecated/SmartReticle/Properties/AssemblyInfo.cs diff --git a/SmartReticle/README.md b/.Deprecated/SmartReticle/README.md similarity index 100% rename from SmartReticle/README.md rename to .Deprecated/SmartReticle/README.md diff --git a/.Deprecated/SmartReticle/SmartReticle.csproj b/.Deprecated/SmartReticle/SmartReticle.csproj new file mode 100644 index 0000000..728edb7 --- /dev/null +++ b/.Deprecated/SmartReticle/SmartReticle.csproj @@ -0,0 +1,6 @@ + + + + net48 + + diff --git a/SmartReticle/format.json b/.Deprecated/SmartReticle/format.json similarity index 100% rename from SmartReticle/format.json rename to .Deprecated/SmartReticle/format.json diff --git a/StopClosingMyMenuOnWorldLoad/Main.cs b/.Deprecated/StopClosingMyMenuOnWorldLoad/Main.cs similarity index 100% rename from StopClosingMyMenuOnWorldLoad/Main.cs rename to .Deprecated/StopClosingMyMenuOnWorldLoad/Main.cs diff --git a/StopClosingMyMenuOnWorldLoad/Properties/AssemblyInfo.cs b/.Deprecated/StopClosingMyMenuOnWorldLoad/Properties/AssemblyInfo.cs similarity index 100% rename from StopClosingMyMenuOnWorldLoad/Properties/AssemblyInfo.cs rename to .Deprecated/StopClosingMyMenuOnWorldLoad/Properties/AssemblyInfo.cs diff --git a/StopClosingMyMenuOnWorldLoad/README.md b/.Deprecated/StopClosingMyMenuOnWorldLoad/README.md similarity index 100% rename from StopClosingMyMenuOnWorldLoad/README.md rename to .Deprecated/StopClosingMyMenuOnWorldLoad/README.md diff --git a/StopClosingMyMenuOnWorldLoad/StopClosingMyMenuOnWorldLoad.csproj b/.Deprecated/StopClosingMyMenuOnWorldLoad/StopClosingMyMenuOnWorldLoad.csproj similarity index 100% rename from StopClosingMyMenuOnWorldLoad/StopClosingMyMenuOnWorldLoad.csproj rename to .Deprecated/StopClosingMyMenuOnWorldLoad/StopClosingMyMenuOnWorldLoad.csproj diff --git a/StopClosingMyMenuOnWorldLoad/format.json b/.Deprecated/StopClosingMyMenuOnWorldLoad/format.json similarity index 100% rename from StopClosingMyMenuOnWorldLoad/format.json rename to .Deprecated/StopClosingMyMenuOnWorldLoad/format.json diff --git a/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs new file mode 100644 index 0000000..949b638 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs @@ -0,0 +1,42 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.InteractionSystem.Base; +using ABI_RC.Systems.InputManagement; +using UnityEngine; +using UnityEngine.Serialization; + +namespace ABI_RC.Core.Player.Interaction +{ + public class CVRPlayerHand : MonoBehaviour + { + #region Fields + + [SerializeField] + private CVRHand _hand; + + // Pickup rig + [SerializeField] private Transform rayDirection; + [SerializeField] private Transform _attachmentPoint; + [SerializeField] private Transform _pivotPoint; + [SerializeField] private VelocityTracker _velocityTracker; + + // Pickup state + private bool _isHoldingObject; + private Pickupable _heldPickupable; + private Pickupable _proximityPickupable; + + #endregion Fields + + #region Unity Events + + + #endregion Unity Events + + #region Private Methods + + #endregion Private Methods + + #region Public Methods + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs new file mode 100644 index 0000000..2c0d56e --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs @@ -0,0 +1,214 @@ +using ABI_RC.Core.Player.Interaction.RaycastImpl; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.InputManagement; +using UnityEngine; + +namespace ABI_RC.Core.Player.Interaction +{ + public class CVRPlayerInteractionManager : MonoBehaviour + { + #region Singleton + + public static CVRPlayerInteractionManager Instance { get; private set; } + + #endregion Singleton + + #region Serialized Fields + + [Header("Hand Components")] + [SerializeField] private CVRPlayerHand handVrLeft; + [SerializeField] private CVRPlayerHand handVrRight; + [SerializeField] private CVRPlayerHand handDesktopRight; // Desktop does not have a left hand + + [Header("Raycast Transforms")] + [SerializeField] private Transform raycastTransformVrRight; + [SerializeField] private Transform raycastTransformVrLeft; + [SerializeField] private Transform raycastTransformDesktopRight; + + [Header("Settings")] + [SerializeField] private bool interactionEnabled = true; + [SerializeField] private LayerMask interactionLayerMask = -1; // Default to all layers, will be filtered + + #endregion Serialized Fields + + #region Properties + + private CVRPlayerHand _rightHand; + private CVRPlayerHand _leftHand; + + private CVRPlayerRaycaster _rightRaycaster; + private CVRPlayerRaycaster _leftRaycaster; + + private CVRRaycastResult _rightRaycastResult; + private CVRRaycastResult _leftRaycastResult; + + // Input handler + private CVRPlayerInputHandler _inputHandler; + + // Interaction flags + public bool InteractionEnabled + { + get => interactionEnabled; + set => interactionEnabled = value; + } + + #endregion Properties + + #region Unity Events + + private void Awake() + { + if (Instance != null && Instance != this) + { + Destroy(gameObject); + return; + } + Instance = this; + + // Create the input handler + _inputHandler = gameObject.AddComponent(); + } + + private void Start() + { + // Setup interaction for current device mode + SetupInteractionForDeviceMode(); + + // Listen for VR mode changes + MetaPort.Instance.onVRModeSwitch.AddListener(SetupInteractionForDeviceMode); + } + + private void Update() + { + if (!interactionEnabled) + return; + + // Process right hand + if (_rightRaycaster != null) + { + // Determine raycast flags based on current mode + CVRPlayerRaycaster.RaycastFlags flags = DetermineRaycastFlags(_rightHand); + + // Get raycast results + _rightRaycastResult = _rightRaycaster.GetRaycastResults(flags); + + // Process input based on raycast results + _inputHandler.ProcessInput(CVRHand.Right, _rightRaycastResult); + } + + // Process left hand (if available) + if (_leftRaycaster != null) + { + // Determine raycast flags based on current mode + CVRPlayerRaycaster.RaycastFlags flags = DetermineRaycastFlags(_leftHand); + + // Get raycast results + _leftRaycastResult = _leftRaycaster.GetRaycastResults(flags); + + // Process input based on raycast results + _inputHandler.ProcessInput(CVRHand.Left, _leftRaycastResult); + } + } + + private void OnDestroy() + { + // Clean up event listener + if (MetaPort.Instance != null) + MetaPort.Instance.onVRModeSwitch.RemoveListener(SetupInteractionForDeviceMode); + } + + #endregion Unity Events + + #region Public Methods + + /// + /// Register a custom tool mode + /// + public void RegisterCustomToolMode(System.Action callback) + { + _inputHandler.RegisterCustomTool(callback); + } + + /// + /// Unregister the current custom tool mode + /// + public void UnregisterCustomToolMode() + { + _inputHandler.UnregisterCustomTool(); + } + + /// + /// Set the interaction mode + /// + public void SetInteractionMode(CVRPlayerInputHandler.InteractionMode mode) + { + _inputHandler.SetInteractionMode(mode); + } + + /// + /// Get the raycast result for a specific hand + /// + public CVRRaycastResult GetRaycastResult(CVRHand hand) + { + return hand == CVRHand.Left ? _leftRaycastResult : _rightRaycastResult; + } + + #endregion Public Methods + + #region Private Methods + + private void SetupInteractionForDeviceMode() + { + bool isVr = MetaPort.Instance.isUsingVr; + + if (isVr) + { + // VR mode + _rightHand = handVrRight; + _leftHand = handVrLeft; + + // VR uses the controller transform for raycasting + _rightRaycaster = new CVRPlayerRaycasterTransform(raycastTransformVrRight); + _leftRaycaster = new CVRPlayerRaycasterTransform(raycastTransformVrLeft); + } + else + { + // Desktop mode + _rightHand = handDesktopRight; + _leftHand = null; + + // Desktop uses the mouse position for raycasting when unlocked + Camera desktopCamera = PlayerSetup.Instance.desktopCam; + _rightRaycaster = new CVRPlayerRaycasterMouse(raycastTransformDesktopRight, desktopCamera); + _leftRaycaster = null; + } + + // Set the layer mask for raycasters + if (_rightRaycaster != null) + _rightRaycaster.SetLayerMask(interactionLayerMask); + + if (_leftRaycaster != null) + _leftRaycaster.SetLayerMask(interactionLayerMask); + } + + private static CVRPlayerRaycaster.RaycastFlags DetermineRaycastFlags(CVRPlayerHand hand) + { + // Default to all flags + CVRPlayerRaycaster.RaycastFlags flags = CVRPlayerRaycaster.RaycastFlags.All; + + // Check if hand is holding a pickup + if (hand != null && hand.IsHoldingObject) + { + // When holding an object, only check for COHTML interaction + flags = CVRPlayerRaycaster.RaycastFlags.CohtmlInteract; + } + + // Could add more conditional flag adjustments here based on the current mode + // For example, in a teleport tool mode, you might only want world hits + + return flags; + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs b/.Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs new file mode 100644 index 0000000..2ec46bd --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs @@ -0,0 +1,121 @@ +using ABI_RC.Core.Base; +using ABI_RC.Core.Player; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace NAK.SuperAwesomeMod.Components +{ + public class CVRCanvasWrapper : MonoBehaviour + { + public bool IsInteractable = true; + public float MaxInteractDistance = 10f; + + private Canvas _canvas; + private GraphicRaycaster _graphicsRaycaster; + private static readonly List _raycastResults = new(); + private static readonly PointerEventData _pointerEventData = new(EventSystem.current); + + private static Selectable _workingSelectable; + private Camera _camera; + private RectTransform _rectTransform; + + #region Unity Events + + private void Awake() + { + if (!TryGetComponent(out _canvas) + || _canvas.renderMode != RenderMode.WorldSpace) + { + IsInteractable = false; + return; + } + + _rectTransform = _canvas.GetComponent(); + } + + private void Start() + { + _graphicsRaycaster = _canvas.gameObject.AddComponent(); + _camera = PlayerSetup.Instance.activeCam; + _canvas.worldCamera = _camera; + } + + #endregion Unity Events + + #region Public Methods + + public bool GetGraphicsHit(Ray worldRay, out RaycastResult result) + { + result = default; + + if (!IsInteractable || _camera == null) return false; + + // Get the plane of the canvas + Plane canvasPlane = new(transform.forward, transform.position); + + // Find where the ray intersects the canvas plane + if (!canvasPlane.Raycast(worldRay, out float distance)) + return false; + + // Get the world point of intersection + Vector3 worldHitPoint = worldRay.origin + worldRay.direction * distance; + + // Check if hit point is within max interaction distance + if (Vector3.Distance(worldRay.origin, worldHitPoint) > MaxInteractDistance) + return false; + + // Check if hit point is within canvas bounds + Vector3 localHitPoint = transform.InverseTransformPoint(worldHitPoint); + Rect canvasRect = _rectTransform.rect; + if (!canvasRect.Contains(new Vector2(localHitPoint.x, localHitPoint.y))) + return false; + + // Convert world hit point to screen space + Vector2 screenPoint = _camera.WorldToScreenPoint(worldHitPoint); + + // Update pointer event data + _pointerEventData.position = screenPoint; + _pointerEventData.delta = Vector2.zero; + + // Clear previous results and perform raycast + _raycastResults.Clear(); + _graphicsRaycaster.Raycast(_pointerEventData, _raycastResults); + + // Early out if no hits + if (_raycastResults.Count == 0) + { + //Debug.Log($"No hits on canvas {_canvas.name}"); + return false; + } + + // Find first valid interactive UI element + foreach (RaycastResult hit in _raycastResults) + { + if (!hit.isValid) + { + //Debug.Log($"Invalid hit on canvas {_canvas.name}"); + continue; + } + + // Check if the hit object has a Selectable component and is interactable + GameObject hitObject = hit.gameObject; + if (!hitObject.TryGetComponent(out _workingSelectable) + || !_workingSelectable.interactable) + { + //Debug.Log($"Non-interactable hit on canvas {_canvas.name} - {hitObject.name}"); + continue; + } + + //Debug.Log($"Hit on canvas {_canvas.name} with {hitObject.name}"); + + result = hit; + return true; + } + + return false; + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs new file mode 100644 index 0000000..aa4205a --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs @@ -0,0 +1,385 @@ +using ABI_RC.Core.InteractionSystem.Base; +using ABI_RC.Core.UI; +using ABI.CCK.Components; +using NAK.SuperAwesomeMod.Components; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace ABI_RC.Core.Player.Interaction.RaycastImpl +{ + public abstract class CVRPlayerRaycaster + { + #region Enums + + [Flags] + public enum RaycastFlags + { + None = 0, + TelepathicCandidate = 1 << 0, + ProximityInteract = 1 << 1, + RayInteract = 1 << 2, + CohtmlInteract = 1 << 3, + All = ~0 + } + + #endregion Enums + + #region Constants + + private const float MAX_RAYCAST_DISTANCE = 100f; // Max distance you can raycast + private const float RAYCAST_SPHERE_RADIUS = 0.1f; // Radius of the proximity sphere + private const float TELEPATHIC_SPHERE_RADIUS = 0.3f; // Radius of the telepathic sphere + private const float MAX_TELEPATHIC_DISTANCE = 20f; // Max distance for telepathic grab + private const int MAX_RAYCAST_HITS = 100; // Hit buffer size, high due to triggers, which we use lots in CCK + + // Global setting is Collide, but better to be explicit about what we need + private const QueryTriggerInteraction _triggerInteraction = QueryTriggerInteraction.Collide; + + // Layers that are reserved for other purposes or illegal to interact with + private const int RESERVED_OR_ILLEGAL_LAYERS = (1 << CVRLayers.IgnoreRaycast) + | (1 << CVRLayers.MirrorReflection) + | (1 << CVRLayers.PlayerLocal); + + #endregion Constants + + #region Static Fields + + private static readonly RaycastHit[] _hits = new RaycastHit[MAX_RAYCAST_HITS]; + private static readonly Comparer _hitsComparer = Comparer.Create((hit1, hit2) => + { + bool isUI1 = hit1.collider.gameObject.layer == CVRLayers.UIInternal; + bool isUI2 = hit2.collider.gameObject.layer == CVRLayers.UIInternal; + + // Prioritize UIInternal hits + if (isUI1 && !isUI2) return -1; // UIInternal comes first + if (!isUI1 && isUI2) return 1; // Non-UIInternal comes after + + // If both are UIInternal or both are not, sort by distance + return hit1.distance.CompareTo(hit2.distance); + }); + + private static readonly LayerMask _telepathicLayerMask = 1 << CVRLayers.MirrorReflection; + + // Working variables to avoid repeated allocations + private static Collider _workingCollider; + private static GameObject _workingGameObject; + private static Pickupable _workingPickupable; + private static Interactable _workingInteractable; + private static Selectable _workingSelectable; + private static ICanvasElement _workingCanvasElement; + + #endregion Static Fields + + #region Private Fields + + private LayerMask _layerMask; // Default to no layers so we know if we fucked up + + #endregion Private Fields + + #region Constructor + + protected CVRPlayerRaycaster(Transform rayOrigin) => _rayOrigin = rayOrigin; + protected readonly Transform _rayOrigin; + + #endregion Constructor + + #region Public Methods + + public void SetLayerMask(LayerMask layerMask) + { + layerMask &= ~RESERVED_OR_ILLEGAL_LAYERS; + _layerMask = layerMask; + } + + public CVRRaycastResult GetRaycastResults(RaycastFlags flags = RaycastFlags.All) + { + // Early out if we don't want to do anything + if (flags == RaycastFlags.None) return default; + + Ray ray = GetRayFromImpl(); + CVRRaycastResult result = new(); + + // Always check COHTML first + if ((flags & RaycastFlags.CohtmlInteract) != 0 + && TryProcessCohtmlHit(ray, ref result)) + return result; + + // Check if there are pickups or interactables in immediate proximity + if ((flags & RaycastFlags.ProximityInteract) != 0) + { + ProcessProximityHits(ray, ref result); // TODO: Offset origin to center of palm based on hand type + if (result.isProximityHit) + return result; + } + + // Check for regular raycast hits + if ((flags & RaycastFlags.RayInteract) != 0) + ProcessRaycastHits(ray, ref result); + + // If we hit something, check for telepathic grab candidates at the hit point + if ((flags & RaycastFlags.TelepathicCandidate) != 0 && result.hit.collider) + ProcessTelepathicGrabCandidate(result.hit.point, ref result); + + return result; + } + + #endregion Public Methods + + #region Private Methods + + private static bool TryProcessCohtmlHit(Ray ray, ref CVRRaycastResult result) + { + CohtmlControlledView hitView = CohtmlViewInputHandler.Instance.RayToView(ray, + out float _, out Vector2 hitCoords); + if (hitView == null) return false; + + result.hitCohtml = true; + result.hitCohtmlView = hitView; + result.hitCohtmlCoords = hitCoords; + + // Manually check for pickups & interactables on the hit view (future-proofing for menu grabbing) + if (hitView.TryGetComponent(out _workingInteractable)) result.hitInteractable = _workingInteractable; + if (hitView.TryGetComponent(out _workingPickupable)) result.hitPickupable = _workingPickupable; + + return true; + } + + private void ProcessProximityHits(Ray ray, ref CVRRaycastResult result) + { + int proximityHits = Physics.SphereCastNonAlloc( + ray.origin, + RAYCAST_SPHERE_RADIUS, + Vector3.up, + _hits, + 0.001f, + _layerMask, + _triggerInteraction + ); + + if (proximityHits <= 0) return; + + Array.Sort(_hits, 0, proximityHits, _hitsComparer); + + for (int i = 0; i < proximityHits; i++) + { + RaycastHit hit = _hits[i]; + _workingCollider = hit.collider; + _workingGameObject = _workingCollider.gameObject; + + // Skip things behind the ray origin + if (Vector3.Dot(ray.direction, hit.point - ray.origin) < 0) + continue; + + // Check for interactables & pickupables in proximity + if (!TryProcessInteractables(hit, ref result)) + continue; + + result.isProximityHit = true; + break; + } + } + + private void ProcessRaycastHits(Ray ray, ref CVRRaycastResult result) + { + // Get all hits including triggers, sorted by UI Internal layer & distance + int hitCount = Physics.RaycastNonAlloc(ray, + _hits, + MAX_RAYCAST_DISTANCE, + _layerMask, + _triggerInteraction); + + if (hitCount <= 0) return; + + Array.Sort(_hits, 0, hitCount, _hitsComparer); + + for (int i = 0; i < hitCount; i++) + { + RaycastHit hit = _hits[i]; + _workingCollider = hit.collider; + _workingGameObject = _workingCollider.gameObject; + + // Special case where we only get the closest water hit position. + // As the array is sorted by distance, we only need to check if we didn't hit water yet. + if (!result.hitWater) TryProcessFluidVolume(hit, ref result); + + // Check for hits in order of priority + + if (TryProcessSelectable(hit, ref result)) + break; // Hit a Unity UI Selectable (Button, Slider, etc.) + + if (TryProcessCanvasElement(hit, ref result)) + break; // Hit a Unity UI Canvas Element (ScrollRect, idk what else yet) + + if (TryProcessInteractables(hit, ref result)) + break; // Hit an in-range Interactable or Pickup + + if (TryProcessWorldHit(hit, ref result)) + break; // Hit a non-trigger collider (world, end of ray) + } + } + + private void ProcessTelepathicGrabCandidate(Vector3 hitPoint, ref CVRRaycastResult result) + { + // If we already hit a pickupable, we don't need to check for telepathic grab candidates + if (result.hitPickupable) + { + result.hasTelepathicGrabCandidate = true; + result.telepathicPickupable = result.hitPickupable; + result.telepathicGrabPoint = hitPoint; + return; + } + + // If the hit distance is too far, don't bother checking for telepathic grab candidates + if (Vector3.Distance(hitPoint, _rayOrigin.position) > MAX_TELEPATHIC_DISTANCE) + return; + + // Check for mirror reflection triggers in a sphere around the hit point + int telepathicHits = Physics.SphereCastNonAlloc( + hitPoint, + TELEPATHIC_SPHERE_RADIUS, + Vector3.up, + _hits, + 0.001f, + _telepathicLayerMask, + QueryTriggerInteraction.Collide + ); + + if (telepathicHits <= 0) return; + + // Look for pickupable objects near our hit point + var nearestDistance = float.MaxValue; + for (int i = 0; i < telepathicHits; i++) + { + RaycastHit hit = _hits[i]; + _workingCollider = hit.collider; + // _workingGameObject = _workingCollider.gameObject; + + Transform parentTransform = _workingCollider.transform.parent; + if (!parentTransform + || !parentTransform.TryGetComponent(out _workingPickupable) + || !_workingPickupable.CanPickup) + continue; + + var distance = Vector3.Distance(hitPoint, hit.point); + if (!(distance < nearestDistance)) + continue; + + result.hasTelepathicGrabCandidate = true; + result.telepathicPickupable = _workingPickupable; + result.telepathicGrabPoint = hitPoint; + nearestDistance = distance; + } + } + + private static bool TryProcessSelectable(RaycastHit hit, ref CVRRaycastResult result) + { + if (!_workingGameObject.TryGetComponent(out _workingSelectable)) + return false; + + result.hitUnityUi = true; + result.hitSelectable = _workingSelectable; + result.hit = hit; + return true; + } + + private static bool TryProcessCanvasElement(RaycastHit hit, ref CVRRaycastResult result) + { + if (!_workingGameObject.TryGetComponent(out _workingCanvasElement)) + return false; + + result.hitUnityUi = true; + result.hitCanvasElement = _workingCanvasElement; + result.hit = hit; + return true; + } + + private static void TryProcessFluidVolume(RaycastHit hit, ref CVRRaycastResult result) + { + if (_workingGameObject.layer != CVRLayers.Water) return; + + result.hitWater = true; + result.waterHit = hit; + } + + private static bool TryProcessInteractables(RaycastHit hit, ref CVRRaycastResult result) + { + bool hitValidComponent = false; + + if (_workingGameObject.TryGetComponent(out _workingInteractable) + && _workingInteractable.CanInteract + && IsCVRInteractableWithinRange(_workingInteractable, hit)) + { + result.hitInteractable = _workingInteractable; + hitValidComponent = true; + } + if (_workingGameObject.TryGetComponent(out _workingPickupable) + && _workingPickupable.CanPickup + && IsCVRPickupableWithinRange(_workingPickupable, hit)) + { + result.hitPickupable = _workingPickupable; + hitValidComponent = true; + } + + if (!hitValidComponent) + return false; + + result.hit = hit; + return true; + } + + private static bool TryProcessWorldHit(RaycastHit hit, ref CVRRaycastResult result) + { + if (_workingCollider.isTrigger) + return false; + + result.hitWorld = true; + result.hit = hit; + return true; + } + + #endregion Private Methods + + #region Protected Methods + + protected abstract Ray GetRayFromImpl(); + + #endregion Protected Methods + + #region Utility Because Original Methods Are Broken + + private static bool IsCVRInteractableWithinRange(Interactable interactable, RaycastHit hit) + { + if (interactable is not CVRInteractable cvrInteractable) + return true; + + foreach (CVRInteractableAction action in cvrInteractable.actions) + { + if (action.actionType + is not (CVRInteractableAction.ActionRegister.OnInteractDown + or CVRInteractableAction.ActionRegister.OnInteractUp + or CVRInteractableAction.ActionRegister.OnInputDown + or CVRInteractableAction.ActionRegister.OnInputUp)) + continue; + + float maxDistance = action.floatVal; + if (Mathf.Approximately(maxDistance, 0f) + || hit.distance <= maxDistance) + return true; // Interactable is within range + } + return false; + } + + private static bool IsCVRPickupableWithinRange(Pickupable pickupable, RaycastHit hit) + { + return hit.distance <= pickupable.MaxGrabDistance; + } + + private static bool IsCVRCanvasWrapperWithinRange(CVRCanvasWrapper canvasWrapper, RaycastHit hit) + { + return hit.distance <= canvasWrapper.MaxInteractDistance; + } + + #endregion Utility Because Original Methods Are Broken + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs new file mode 100644 index 0000000..5f5e638 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace ABI_RC.Core.Player.Interaction.RaycastImpl +{ + public class CVRPlayerRaycasterMouse : CVRPlayerRaycaster + { + private readonly Camera _camera; + public CVRPlayerRaycasterMouse(Transform rayOrigin, Camera camera) : base(rayOrigin) { _camera = camera; } + protected override Ray GetRayFromImpl() => Cursor.lockState == CursorLockMode.Locked + ? new Ray(_camera.transform.position, _camera.transform.forward) + : _camera.ScreenPointToRay(Input.mousePosition); + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs new file mode 100644 index 0000000..cc62dab --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace ABI_RC.Core.Player.Interaction.RaycastImpl +{ + public class CVRPlayerRaycasterTransform : CVRPlayerRaycaster + { + public CVRPlayerRaycasterTransform(Transform rayOrigin) : base(rayOrigin) { } + protected override Ray GetRayFromImpl() => new(_rayOrigin.position, _rayOrigin.forward); + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs new file mode 100644 index 0000000..6165354 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs @@ -0,0 +1,38 @@ +using ABI_RC.Core.InteractionSystem.Base; +using ABI_RC.Core.UI; +using NAK.SuperAwesomeMod.Components; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace ABI_RC.Core.Player.Interaction.RaycastImpl +{ + public struct CVRRaycastResult + { + // Hit flags + public bool hitWorld; // Any non-specific collision + public bool hitWater; // Hit a fluid volume + public bool hitCohtml; // Specifically hit a COHTML view (Main/Quick Menu) + public bool isProximityHit; // Hit was from proximity sphere check + public bool hitUnityUi; // Hit a canvas + + // Main raycast hit info + public RaycastHit hit; + public RaycastHit? waterHit; // Only valid if hitWater is true + + // Specific hit components + public Pickupable hitPickupable; + public Interactable hitInteractable; + public Selectable hitSelectable; + public ICanvasElement hitCanvasElement; + + // COHTML specific results + public CohtmlControlledView hitCohtmlView; + public Vector2 hitCohtmlCoords; + + // Telepathic pickup + public bool hasTelepathicGrabCandidate; + public Pickupable telepathicPickupable; + public Vector3 telepathicGrabPoint; + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs new file mode 100644 index 0000000..5000f89 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs @@ -0,0 +1,312 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace ABI_RC.Core.Player.Interaction.RaycastImpl +{ +public class CVRRaycastDebugManager : MonoBehaviour +{ + #region Singleton + + private static CVRRaycastDebugManager _instance; + public static CVRRaycastDebugManager Instance => _instance; + + public static void Initialize(Camera camera) + { + if (_instance != null) return; + + var go = new GameObject("RaycastDebugManager"); + _instance = go.AddComponent(); + DontDestroyOnLoad(go); + + _instance.Setup(camera); + } + + #endregion + + #region Private Fields + + private CVRPlayerRaycasterMouse _raycaster; + private CVRRaycastResult _lastResult; + private System.Diagnostics.Stopwatch _stopwatch; + + // Performance tracking + private const int ROLLING_AVERAGE_SAMPLES = 60; // 1 second at 60fps + private readonly float[] _timeHistory = new float[ROLLING_AVERAGE_SAMPLES]; + private int _currentSampleIndex; + private float _lastRaycastTime; + private float _minRaycastTime = float.MaxValue; + private float _maxRaycastTime; + private float _rollingAverageTime; + private bool _historyFilled; + + private const int DEBUG_PANEL_WIDTH = 300; + private const int DEBUG_PANEL_MARGIN = 10; + private const float MOUSE_CURSOR_SIZE = 24f; + private const float CURSOR_OFFSET = MOUSE_CURSOR_SIZE / 2f; + + private GUIStyle _labelStyle; + private GUIStyle _headerStyle; + private GUIStyle _boxStyle; + + private static readonly Color32 TIMING_COLOR = new(255, 255, 150, 255); // Yellow + private static readonly Color32 COHTML_COLOR = new(150, 255, 150, 255); // Green + private static readonly Color32 UI_COLOR = new(150, 150, 255, 255); // Blue + private static readonly Color32 UNITY_UI_COLOR = new(255, 200, 150, 255); // Orange + private static readonly Color32 INTERACT_COLOR = new(255, 150, 150, 255); // Red + private static readonly Color32 WATER_COLOR = new(150, 255, 255, 255); // Cyan + private static readonly Color32 TELEPATHIC_COLOR = new(255, 150, 255, 255);// Purple + private static readonly Color32 SELECTABLE_COLOR = new(200, 150, 255, 255);// Light Purple + + #endregion + + #region Setup + + private void Setup(Camera camera) + { + _raycaster = new CVRPlayerRaycasterMouse(transform, camera); + _raycaster.SetLayerMask(Physics.DefaultRaycastLayers); + _stopwatch = new System.Diagnostics.Stopwatch(); + } + + #endregion + + #region MonoBehaviour + + private void Update() + { + _stopwatch.Restart(); + _lastResult = _raycaster.GetRaycastResults(); + _stopwatch.Stop(); + + UpdatePerformanceMetrics(); + } + + private void UpdatePerformanceMetrics() + { + // Calculate current frame time + _lastRaycastTime = _stopwatch.ElapsedTicks / (float)System.TimeSpan.TicksPerMillisecond; + + // Update min/max + _minRaycastTime = Mathf.Min(_minRaycastTime, _lastRaycastTime); + _maxRaycastTime = Mathf.Max(_maxRaycastTime, _lastRaycastTime); + + // Update rolling average + _timeHistory[_currentSampleIndex] = _lastRaycastTime; + + // Calculate rolling average based on filled samples + float sum = 0f; + int sampleCount = _historyFilled ? ROLLING_AVERAGE_SAMPLES : _currentSampleIndex + 1; + + for (int i = 0; i < sampleCount; i++) + sum += _timeHistory[i]; + + _rollingAverageTime = sum / sampleCount; + + // Update index for next frame + _currentSampleIndex = (_currentSampleIndex + 1) % ROLLING_AVERAGE_SAMPLES; + if (_currentSampleIndex == 0) + _historyFilled = true; + } + + private void OnGUI() + { + InitializeStyles(); + DrawDebugPanel(); + } + + #endregion + + #region Drawing Methods + + private void InitializeStyles() + { + if (_labelStyle != null) return; + + _labelStyle = new GUIStyle + { + normal = { textColor = Color.white }, + fontSize = 12, + padding = new RectOffset(5, 5, 2, 2), + margin = new RectOffset(5, 5, 0, 0) + }; + + _headerStyle = new GUIStyle + { + normal = { textColor = Color.white }, + fontSize = 14, + fontStyle = FontStyle.Bold, + padding = new RectOffset(5, 5, 5, 5), + margin = new RectOffset(5, 5, 5, 5) + }; + + _boxStyle = new GUIStyle(GUI.skin.box) + { + padding = new RectOffset(10, 10, 5, 5), + margin = new RectOffset(5, 5, 5, 5) + }; + } + + private void DrawDebugPanel() + { + var rect = new Rect( + Screen.width - DEBUG_PANEL_WIDTH - DEBUG_PANEL_MARGIN, + DEBUG_PANEL_MARGIN, + DEBUG_PANEL_WIDTH, + Screen.height - (DEBUG_PANEL_MARGIN * 2) + ); + + GUI.Box(rect, ""); + GUILayout.BeginArea(rect); + + GUI.backgroundColor = Color.black; + GUILayout.Label("Raycast Debug Info", _headerStyle); + + DrawPerformanceSection(); + DrawCohtmlSection(); + DrawUnityUISection(); + DrawSelectableSection(); + DrawInteractionSection(); + DrawWaterSection(); + DrawTelepathicSection(); + DrawWorldHitSection(); + + GUILayout.EndArea(); + } + + private void DrawPerformanceSection() + { + GUI.backgroundColor = TIMING_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("Performance", _headerStyle); + DrawLabel("Last Raycast", $"{_lastRaycastTime:F3} ms"); + DrawLabel("Average (1s)", $"{_rollingAverageTime:F3} ms"); + DrawLabel("Min", $"{_minRaycastTime:F3} ms"); + DrawLabel("Max", $"{_maxRaycastTime:F3} ms"); + GUILayout.EndVertical(); + } + + private void DrawCohtmlSection() + { + if (!_lastResult.hitCohtml) return; + + GUI.backgroundColor = COHTML_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("COHTML Hit", _headerStyle); + DrawLabel("View", _lastResult.hitCohtmlView.name); + DrawLabel("Coords", _lastResult.hitCohtmlCoords.ToString()); + GUILayout.EndVertical(); + } + + private void DrawUnityUISection() + { + if (!_lastResult.hitUnityUi || _lastResult.hitCanvasElement == null) return; + + GUI.backgroundColor = UNITY_UI_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("Unity UI Hit", _headerStyle); + + var canvasElement = _lastResult.hitCanvasElement; + var gameObject = canvasElement as MonoBehaviour; + + DrawLabel("Canvas Element", gameObject != null ? gameObject.name : "Unknown"); + DrawLabel("Element Type", canvasElement.GetType().Name); + + if (gameObject != null) + { + DrawLabel("GameObject", gameObject.gameObject.name); + + if (gameObject.transform.parent != null) + DrawLabel("Parent", gameObject.transform.parent.name); + } + + GUILayout.EndVertical(); + } + + private void DrawSelectableSection() + { + if (_lastResult.hitSelectable == null) return; + + GUI.backgroundColor = SELECTABLE_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("UI Selectable", _headerStyle); + DrawLabel("Selectable", _lastResult.hitSelectable.name); + DrawLabel("Selectable Type", _lastResult.hitSelectable.GetType().Name); + DrawLabel("Is Interactable", _lastResult.hitSelectable.interactable.ToString()); + DrawLabel("Navigation Mode", _lastResult.hitSelectable.navigation.mode.ToString()); + + if (_lastResult.hitSelectable is Toggle toggle) + DrawLabel("Toggle State", toggle.isOn.ToString()); + else if (_lastResult.hitSelectable is Slider slider) + DrawLabel("Slider Value", slider.value.ToString("F2")); + else if (_lastResult.hitSelectable is Scrollbar scrollbar) + DrawLabel("Scrollbar Value", scrollbar.value.ToString("F2")); + + GUILayout.EndVertical(); + } + + private void DrawInteractionSection() + { + if (!_lastResult.hitPickupable && !_lastResult.hitInteractable) return; + + GUI.backgroundColor = INTERACT_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("Interaction", _headerStyle); + if (_lastResult.hitPickupable) + DrawLabel("Pickupable", _lastResult.hitPickupable.name); + if (_lastResult.hitInteractable) + DrawLabel("Interactable", _lastResult.hitInteractable.name); + DrawLabel("Is Proximity", _lastResult.isProximityHit.ToString()); + GUILayout.EndVertical(); + } + + private void DrawWaterSection() + { + if (!_lastResult.hitWater || !_lastResult.waterHit.HasValue) return; + + GUI.backgroundColor = WATER_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("Water Surface", _headerStyle); + DrawLabel("Hit Point", _lastResult.waterHit.Value.point.ToString("F2")); + DrawLabel("Surface Normal", _lastResult.waterHit.Value.normal.ToString("F2")); + GUILayout.EndVertical(); + } + + private void DrawTelepathicSection() + { + if (!_lastResult.hasTelepathicGrabCandidate) return; + + GUI.backgroundColor = TELEPATHIC_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("Telepathic Grab", _headerStyle); + DrawLabel("Target", _lastResult.telepathicPickupable.name); + DrawLabel("Grab Point", _lastResult.telepathicGrabPoint.ToString("F2")); + GUILayout.EndVertical(); + } + + private void DrawWorldHitSection() + { + if (_lastResult.hitCohtml || + _lastResult.hitPickupable || + _lastResult.hitInteractable || + _lastResult.hitUnityUi || + !_lastResult.hitWorld || + _lastResult.hit.collider == null) return; + + GUI.backgroundColor = Color.grey; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("World Hit", _headerStyle); + DrawLabel("Object", _lastResult.hit.collider.name); + DrawLabel("Distance", _lastResult.hit.distance.ToString("F2")); + DrawLabel("Point", _lastResult.hit.point.ToString("F2")); + GUILayout.EndVertical(); + } + + private void DrawLabel(string label, string value) + { + GUILayout.Label($"{label}: {value}", _labelStyle); + } + + #endregion +} +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Main.cs b/.Deprecated/SuperAwesomeMod/Main.cs new file mode 100644 index 0000000..5c410f2 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Main.cs @@ -0,0 +1,81 @@ +using System.Reflection; +using ABI_RC.Core.Base.Jobs; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Player.Interaction.RaycastImpl; +using ABI_RC.Core.Util.AssetFiltering; +using ABI.CCK.Components; +using HarmonyLib; +using MelonLoader; +using NAK.SuperAwesomeMod.Components; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace NAK.SuperAwesomeMod; + +public class SuperAwesomeModMod : MelonMod +{ + #region Melon Events + + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.Start), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(SuperAwesomeModMod).GetMethod(nameof(OnPlayerSetupStart), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(SceneLoaded).GetMethod(nameof(SceneLoaded.FilterWorldComponent), + BindingFlags.NonPublic | BindingFlags.Static), + postfix: new HarmonyMethod(typeof(SuperAwesomeModMod).GetMethod(nameof(OnShitLoaded), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + // patch SharedFilter.ProcessCanvas + HarmonyInstance.Patch( + typeof(SharedFilter).GetMethod(nameof(SharedFilter.ProcessCanvas), + BindingFlags.Public | BindingFlags.Static), + postfix: new HarmonyMethod(typeof(SuperAwesomeModMod).GetMethod(nameof(OnProcessCanvas), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + LoggerInstance.Msg("SuperAwesomeModMod! OnInitializeMelon! :D"); + } + + public override void OnApplicationQuit() + { + LoggerInstance.Msg("SuperAwesomeModMod! OnApplicationQuit! D:"); + } + + #endregion Melon Events + + private static void OnPlayerSetupStart() + { + CVRRaycastDebugManager.Initialize(PlayerSetup.Instance.desktopCam); + } + + private static void OnShitLoaded(Component c, List asyncTasks = null, Scene? scene = null) + { + if (c == null) + return; + + if (c.gameObject == null) + return; + + if (c.gameObject.scene.buildIndex > 0) + return; + + if ((scene != null) + && (c.gameObject.scene != scene)) + return; + + if (c is Canvas canvas) canvas.gameObject.AddComponent(); + } + + private static void OnProcessCanvas(string collectionId, Canvas canvas) + { + canvas.gameObject.AddComponent(); + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Properties/AssemblyInfo.cs b/.Deprecated/SuperAwesomeMod/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f1590e2 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.SuperAwesomeMod.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.SuperAwesomeMod))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.SuperAwesomeMod))] + +[assembly: MelonInfo( + typeof(NAK.SuperAwesomeMod.SuperAwesomeModMod), + nameof(NAK.SuperAwesomeMod), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SuperAwesomeMod" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.SuperAwesomeMod.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/README.md b/.Deprecated/SuperAwesomeMod/README.md new file mode 100644 index 0000000..399e70a --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/README.md @@ -0,0 +1,54 @@ +# ASTExtension + +Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): +- VR Gesture to scale +- Persistent height +- Copy height from others + +Best used with Avatar Scale Tool, but will attempt to work with found scaling setups. +Requires already having Avatar Scaling on the avatar. This is **not** Universal Scaling. + +## Supported Setups + +ASTExtension will attempt to work with the following setups: + +**Parameter Names:** +- AvatarScale +- Scale +- Scaler +- Scale/Scale +- Height +- LoliModifier +- AvatarSize +- Size +- SizeScale +- Scaling + +These parameter names are not case sensitive and have been gathered from polling the community for common parameter names. + +Assuming the parameter is a float, ASTExtension will attempt to use it as the height parameter. Will automatically calibrate to the height range of the found parameter, assuming the scaling animation is in a blend tree / state using motion time & is linear. The scaling animation state **must be active** at time of avatar load. + +The max value ASTExtension will drive the parameter to is 100. As the mod is having to guess the max height, it may not be accurate if the max height is not capped at a multiple of 10. + +Examples: +- `AvatarScale` - 0 to 1 (slider) + - This is the default setup for Avatar Scale Tool and will work perfectly. +- `Scale` - 0 to 100 (input single) + - This will also work perfectly as the max height is a multiple of 10. +- `Height` - 0 to 2 (input single) + - This will not work properly. The max value to drive the parameter to is not a multiple of 10, and as such ASTExtension will believe the parameter range is 0 to 1. +- `BurntToast` - 0 to 10 (input single) + - This will not work properly. The parameter name is not recognized by ASTExtension. + +If your setup is theoretically supported but not working, it is likely the scaling animation is not linear or has loop enabled if using Motion Time, making the first and last frame identical height. In this case, you will need to fix your animation clip curves / blend tree to be linear &|| not loop, or use Avatar Scale Tool to generate a new scaling animation. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/InteractionTest/InteractionTest.csproj b/.Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj similarity index 52% rename from InteractionTest/InteractionTest.csproj rename to .Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj index 1b7a95f..fa113da 100644 --- a/InteractionTest/InteractionTest.csproj +++ b/.Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj @@ -1,13 +1,12 @@ + + ASTExtension + ..\.ManagedLibs\BTKUILib.dll + False - - - - - diff --git a/.Deprecated/SuperAwesomeMod/format.json b/.Deprecated/SuperAwesomeMod/format.json new file mode 100644 index 0000000..5ad14ea --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/format.json @@ -0,0 +1,24 @@ +{ + "_id": 223, + "name": "ASTExtension", + "modversion": "1.0.2", + "gameversion": "2025r178", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool):\n- VR Gesture to scale\n- Persistent height\n- Copy height from others\n\nBest used with Avatar Scale Tool, but will attempt to work with found scaling setups.\nRequires already having Avatar Scaling on the avatar. This is **not** Universal Scaling.", + "searchtags": [ + "tool", + "scaling", + "height", + "extension", + "avatar" + ], + "requirements": [ + "BTKUILib" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r45/ASTExtension.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ASTExtension/", + "changelog": "- Fixes for 2025r178", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.DepricatedMods/SwitchToDesktopOnSteamVRExit/Main.cs b/.Deprecated/SwitchToDesktopOnSteamVRExit/Main.cs similarity index 100% rename from .DepricatedMods/SwitchToDesktopOnSteamVRExit/Main.cs rename to .Deprecated/SwitchToDesktopOnSteamVRExit/Main.cs diff --git a/.DepricatedMods/SwitchToDesktopOnSteamVRExit/Properties/AssemblyInfo.cs b/.Deprecated/SwitchToDesktopOnSteamVRExit/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/SwitchToDesktopOnSteamVRExit/Properties/AssemblyInfo.cs rename to .Deprecated/SwitchToDesktopOnSteamVRExit/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/SwitchToDesktopOnSteamVRExit/README.md b/.Deprecated/SwitchToDesktopOnSteamVRExit/README.md similarity index 100% rename from .DepricatedMods/SwitchToDesktopOnSteamVRExit/README.md rename to .Deprecated/SwitchToDesktopOnSteamVRExit/README.md diff --git a/.DepricatedMods/SwitchToDesktopOnSteamVRExit/SwitchToDesktopOnSteamVRExit.csproj b/.Deprecated/SwitchToDesktopOnSteamVRExit/SwitchToDesktopOnSteamVRExit.csproj similarity index 100% rename from .DepricatedMods/SwitchToDesktopOnSteamVRExit/SwitchToDesktopOnSteamVRExit.csproj rename to .Deprecated/SwitchToDesktopOnSteamVRExit/SwitchToDesktopOnSteamVRExit.csproj diff --git a/.DepricatedMods/SwitchToDesktopOnSteamVRExit/format.json b/.Deprecated/SwitchToDesktopOnSteamVRExit/format.json similarity index 100% rename from .DepricatedMods/SwitchToDesktopOnSteamVRExit/format.json rename to .Deprecated/SwitchToDesktopOnSteamVRExit/format.json diff --git a/.DepricatedMods/TrackedControllerFix/HarmonyPatches.cs b/.Deprecated/TrackedControllerFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/TrackedControllerFix/HarmonyPatches.cs rename to .Deprecated/TrackedControllerFix/HarmonyPatches.cs diff --git a/.DepricatedMods/TrackedControllerFix/Main.cs b/.Deprecated/TrackedControllerFix/Main.cs similarity index 100% rename from .DepricatedMods/TrackedControllerFix/Main.cs rename to .Deprecated/TrackedControllerFix/Main.cs diff --git a/.DepricatedMods/TrackedControllerFix/Properties/AssemblyInfo.cs b/.Deprecated/TrackedControllerFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/TrackedControllerFix/Properties/AssemblyInfo.cs rename to .Deprecated/TrackedControllerFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/TrackedControllerFix/README.md b/.Deprecated/TrackedControllerFix/README.md similarity index 100% rename from .DepricatedMods/TrackedControllerFix/README.md rename to .Deprecated/TrackedControllerFix/README.md diff --git a/.DepricatedMods/TrackedControllerFix/TrackedControllerFix.csproj b/.Deprecated/TrackedControllerFix/TrackedControllerFix.csproj similarity index 100% rename from .DepricatedMods/TrackedControllerFix/TrackedControllerFix.csproj rename to .Deprecated/TrackedControllerFix/TrackedControllerFix.csproj diff --git a/.DepricatedMods/TrackedControllerFix/TrackedControllerFixer.cs b/.Deprecated/TrackedControllerFix/TrackedControllerFixer.cs similarity index 100% rename from .DepricatedMods/TrackedControllerFix/TrackedControllerFixer.cs rename to .Deprecated/TrackedControllerFix/TrackedControllerFixer.cs diff --git a/.DepricatedMods/TrackedControllerFix/format.json b/.Deprecated/TrackedControllerFix/format.json similarity index 100% rename from .DepricatedMods/TrackedControllerFix/format.json rename to .Deprecated/TrackedControllerFix/format.json diff --git a/.DepricatedMods/TrackedPointFix/HarmonyPatches.cs b/.Deprecated/TrackedPointFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/TrackedPointFix/HarmonyPatches.cs rename to .Deprecated/TrackedPointFix/HarmonyPatches.cs diff --git a/.DepricatedMods/TrackedPointFix/Main.cs b/.Deprecated/TrackedPointFix/Main.cs similarity index 100% rename from .DepricatedMods/TrackedPointFix/Main.cs rename to .Deprecated/TrackedPointFix/Main.cs diff --git a/.DepricatedMods/TrackedPointFix/Properties/AssemblyInfo.cs b/.Deprecated/TrackedPointFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/TrackedPointFix/Properties/AssemblyInfo.cs rename to .Deprecated/TrackedPointFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/TrackedPointFix/README.md b/.Deprecated/TrackedPointFix/README.md similarity index 100% rename from .DepricatedMods/TrackedPointFix/README.md rename to .Deprecated/TrackedPointFix/README.md diff --git a/.DepricatedMods/TrackedPointFix/TrackedPointFix.csproj b/.Deprecated/TrackedPointFix/TrackedPointFix.csproj similarity index 100% rename from .DepricatedMods/TrackedPointFix/TrackedPointFix.csproj rename to .Deprecated/TrackedPointFix/TrackedPointFix.csproj diff --git a/.DepricatedMods/TrackedPointFix/format.json b/.Deprecated/TrackedPointFix/format.json similarity index 100% rename from .DepricatedMods/TrackedPointFix/format.json rename to .Deprecated/TrackedPointFix/format.json diff --git a/VisualCloneFix/Main.cs b/.Deprecated/VisualCloneFix/Main.cs similarity index 100% rename from VisualCloneFix/Main.cs rename to .Deprecated/VisualCloneFix/Main.cs diff --git a/.Deprecated/VisualCloneFix/Patches.cs b/.Deprecated/VisualCloneFix/Patches.cs new file mode 100644 index 0000000..d1fb84b --- /dev/null +++ b/.Deprecated/VisualCloneFix/Patches.cs @@ -0,0 +1,157 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using ABI_RC.Core.Player.LocalClone; +using ABI_RC.Core.Player.TransformHider; +using ABI.CCK.Components; +using HarmonyLib; +using UnityEngine; +using Debug = UnityEngine.Debug; + +namespace NAK.VisualCloneFix; + +public static class Patches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(TransformHiderUtils), nameof(TransformHiderUtils.SetupAvatar))] + private static bool OnSetupAvatar(GameObject avatar) + { + if (!VisualCloneFixMod.EntryUseVisualClone.Value) return true; + LocalCloneHelper.SetupAvatar(avatar); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(LocalCloneHelper), nameof(LocalCloneHelper.CollectTransformToExclusionMap))] + private static bool CollectTransformToExclusionMap( + Component root, Transform headBone, + ref Dictionary __result) + { + // add an fpr exclusion to the head bone + if (!headBone.TryGetComponent(out FPRExclusion headExclusion)) + { + headExclusion = headBone.gameObject.AddComponent(); + headExclusion.isShown = false; // default to hidden + headExclusion.target = headBone; + } + + MeshHiderExclusion headExclusionBehaviour = new(); + headExclusion.behaviour = headExclusionBehaviour; + headExclusionBehaviour.id = 1; // head bone is always 1 + + // get all FPRExclusions + var fprExclusions = root.GetComponentsInChildren(true); + + // get all valid exclusion targets, and destroy invalid exclusions + Dictionary exclusionTargets = new(); + + int nextId = 2; + foreach (FPRExclusion exclusion in fprExclusions) + { + if (exclusion.target == null + || exclusionTargets.ContainsKey(exclusion.target) + || !exclusion.target.gameObject.scene.IsValid()) + continue; // invalid exclusion + + if (exclusion.behaviour == null) // head exclusion is already created + { + MeshHiderExclusion meshHiderExclusion = new(); + exclusion.behaviour = meshHiderExclusion; + meshHiderExclusion.id = nextId++; + } + + // first to add wins + exclusionTargets.TryAdd(exclusion.target, exclusion); + } + + // process each FPRExclusion (recursive) + int exclusionCount = exclusionTargets.Values.Count; + for (var index = 0; index < exclusionCount; index++) + { + FPRExclusion exclusion = exclusionTargets.Values.ElementAt(index); + ProcessExclusion(exclusion, exclusion.target); + exclusion.UpdateExclusions(); // initial state + } + + __result = exclusionTargets; + return false; + + void ProcessExclusion(FPRExclusion exclusion, Transform transform) + { + if (exclusionTargets.ContainsKey(transform) + && exclusionTargets[transform] != exclusion) return; // found other exclusion root + + exclusionTargets.TryAdd(transform, exclusion); // add to the dictionary (yes its wasteful) + foreach (Transform child in transform) + ProcessExclusion(exclusion, child); // process children + } + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SkinnedLocalClone), nameof(SkinnedLocalClone.FindExclusionVertList))] + private static bool FindExclusionVertList( + SkinnedMeshRenderer renderer, IReadOnlyDictionary exclusions, + ref int[] __result) + { + // Start the stopwatch + Stopwatch stopwatch = new(); + stopwatch.Start(); + + var boneWeights = renderer.sharedMesh.boneWeights; + var bones = renderer.bones; + int boneCount = bones.Length; + + bool[] boneHasExclusion = new bool[boneCount]; + + // Populate the weights array + for (int i = 0; i < boneCount; i++) + { + Transform bone = bones[i]; + if (bone == null) continue; + if (exclusions.ContainsKey(bone)) + boneHasExclusion[i] = true; + } + + const float minWeightThreshold = 0.2f; + + int[] vertexIndices = new int[renderer.sharedMesh.vertexCount]; + + // Check bone weights and add vertex to exclusion list if needed + for (int i = 0; i < boneWeights.Length; i++) + { + BoneWeight weight = boneWeights[i]; + Transform bone; + + if (boneHasExclusion[weight.boneIndex0] && weight.weight0 > minWeightThreshold) + bone = bones[weight.boneIndex0]; + else if (boneHasExclusion[weight.boneIndex1] && weight.weight1 > minWeightThreshold) + bone = bones[weight.boneIndex1]; + else if (boneHasExclusion[weight.boneIndex2] && weight.weight2 > minWeightThreshold) + bone = bones[weight.boneIndex2]; + else if (boneHasExclusion[weight.boneIndex3] && weight.weight3 > minWeightThreshold) + bone = bones[weight.boneIndex3]; + else continue; + + if (exclusions.TryGetValue(bone, out FPRExclusion exclusion)) + vertexIndices[i] = ((MeshHiderExclusion)(exclusion.behaviour)).id; + } + + // Stop the stopwatch + stopwatch.Stop(); + + // Log the execution time + Debug.Log($"FindExclusionVertList execution time: {stopwatch.ElapsedMilliseconds} ms"); + + __result = vertexIndices; + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(MeshHiderExclusion), nameof(MeshHiderExclusion.UpdateExclusions))] + private static bool OnUpdateExclusions(bool isShown, bool shrinkToZero, ref int ___id) + { + if (isShown) LocalCloneManager.cullingMask &= ~(1 << ___id); + else LocalCloneManager.cullingMask |= 1 << ___id; + return false; + } +} \ No newline at end of file diff --git a/VisualCloneFix/Properties/AssemblyInfo.cs b/.Deprecated/VisualCloneFix/Properties/AssemblyInfo.cs similarity index 100% rename from VisualCloneFix/Properties/AssemblyInfo.cs rename to .Deprecated/VisualCloneFix/Properties/AssemblyInfo.cs diff --git a/VisualCloneFix/README.md b/.Deprecated/VisualCloneFix/README.md similarity index 100% rename from VisualCloneFix/README.md rename to .Deprecated/VisualCloneFix/README.md diff --git a/VisualCloneFix/VisualCloneFix.csproj b/.Deprecated/VisualCloneFix/VisualCloneFix.csproj similarity index 100% rename from VisualCloneFix/VisualCloneFix.csproj rename to .Deprecated/VisualCloneFix/VisualCloneFix.csproj diff --git a/VisualCloneFix/format.json b/.Deprecated/VisualCloneFix/format.json similarity index 100% rename from VisualCloneFix/format.json rename to .Deprecated/VisualCloneFix/format.json diff --git a/.Deprecated/WhereAmIPointing/Main.cs b/.Deprecated/WhereAmIPointing/Main.cs new file mode 100644 index 0000000..24529b4 --- /dev/null +++ b/.Deprecated/WhereAmIPointing/Main.cs @@ -0,0 +1,106 @@ +using ABI_RC.Core.InteractionSystem; +using HarmonyLib; +using MelonLoader; +using UnityEngine; + +namespace NAK.WhereAmIPointing; + +public class WhereAmIPointingMod : MelonMod +{ + #region Melon Preferences + + // cannot disable because then id need extra logic to reset the alpha :) + // private const string SettingsCategory = nameof(WhereAmIPointingMod); + // + // private static readonly MelonPreferences_Category Category = + // MelonPreferences.CreateCategory(SettingsCategory); + // + // private static readonly MelonPreferences_Entry Entry_Enabled = + // Category.CreateEntry("enabled", true, display_name: "Enabled",description: "Toggle WhereAmIPointingMod entirely."); + + #endregion Melon Preferences + + public override void OnInitializeMelon() + { + ApplyPatches(typeof(ControllerRay_Patches)); + } + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } + + #region Patches + + private static class ControllerRay_Patches + { + private const float ORIGINAL_ALPHA = 0.502f; + private const float INTERACTION_ALPHA = 0.1f; + private const float RAY_LENGTH = 1000f; // game normally raycasts to PositiveInfinity... -_- + + [HarmonyPostfix] + [HarmonyPatch(typeof(ControllerRay), nameof(ControllerRay.LateUpdate))] + private static void Postfix_ControllerRay_LateUpdate(ref ControllerRay __instance) + { + if (__instance.isDesktopRay + || !__instance.enabled + || !__instance.IsTracking() + || !__instance.lineRenderer) + return; + + UpdateLineRendererAlpha(__instance); + + if (__instance.lineRenderer.enabled + || !ShouldOverrideLineRenderer(__instance)) + return; + + UpdateLineRendererPosition(__instance); + } + + private static void UpdateLineRendererAlpha(ControllerRay instance) + { + Material material = instance.lineRenderer.material; + Color color = material.color; + + bool anyMenuOpen = ViewManager.Instance.IsAnyMenuOpen; + float targetAlpha = (!anyMenuOpen || instance.uiActive) ? ORIGINAL_ALPHA : INTERACTION_ALPHA; + if (!(Math.Abs(color.a - targetAlpha) > float.Epsilon)) + return; + + color.a = targetAlpha; + material.color = color; + } + + private static bool ShouldOverrideLineRenderer(ControllerRay instance) + { + if (!ViewManager.Instance.IsAnyMenuOpen) + return false; + + if (CVR_MenuManager.Instance.IsQuickMenuOpen + && instance.hand == CVR_MenuManager.Instance.SelectedQuickMenuHand) + return false; + + return true; + } + + private static void UpdateLineRendererPosition(ControllerRay instance) + { + Vector3 rayOrigin = instance.rayDirectionTransform.position; + Vector3 rayEnd = rayOrigin + instance.rayDirectionTransform.forward * RAY_LENGTH; + + instance.lineRenderer.SetPosition(0, instance.lineRenderer.transform.InverseTransformPoint(rayOrigin)); + instance.lineRenderer.SetPosition(1, instance.lineRenderer.transform.InverseTransformPoint(rayEnd)); + instance.lineRenderer.enabled = true; + } + } + + #endregion Patches +} \ No newline at end of file diff --git a/.Deprecated/WhereAmIPointing/Properties/AssemblyInfo.cs b/.Deprecated/WhereAmIPointing/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..48c359f --- /dev/null +++ b/.Deprecated/WhereAmIPointing/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using NAK.WhereAmIPointing.Properties; +using MelonLoader; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.WhereAmIPointing))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.WhereAmIPointing))] + +[assembly: MelonInfo( + typeof(NAK.WhereAmIPointing.WhereAmIPointingMod), + nameof(NAK.WhereAmIPointing), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.WhereAmIPointing.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.1"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/WhereAmIPointing/README.md b/.Deprecated/WhereAmIPointing/README.md new file mode 100644 index 0000000..c78a56a --- /dev/null +++ b/.Deprecated/WhereAmIPointing/README.md @@ -0,0 +1,14 @@ +# WhereAmIPointing + +Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/.Deprecated/WhereAmIPointing/WhereAmIPointing.csproj b/.Deprecated/WhereAmIPointing/WhereAmIPointing.csproj new file mode 100644 index 0000000..728edb7 --- /dev/null +++ b/.Deprecated/WhereAmIPointing/WhereAmIPointing.csproj @@ -0,0 +1,6 @@ + + + + net48 + + diff --git a/.Deprecated/WhereAmIPointing/format.json b/.Deprecated/WhereAmIPointing/format.json new file mode 100644 index 0000000..654911a --- /dev/null +++ b/.Deprecated/WhereAmIPointing/format.json @@ -0,0 +1,23 @@ +{ + "_id": 234, + "name": "WhereAmIPointing", + "modversion": "1.0.1", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction.", + "searchtags": [ + "controller", + "ray", + "line", + "tomato" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r40/WhereAmIPointing.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing/", + "changelog": "- Fixed line renderer alpha not being reset when the menu is closed.", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7a3e958..2abd364 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ ## ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore +# NAK +.Experimental/ + # Nstrip & ManagedLibs stuff NStrip.exe .ManagedLibs/*.dll diff --git a/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs b/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs index cbb7534..e0e294a 100644 --- a/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs +++ b/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs @@ -1,7 +1,9 @@ using ABI_RC.Core.Player; +using ABI_RC.Core.Util.AnimatorManager; using BTKUILib; using BTKUILib.UIObjects; using BTKUILib.UIObjects.Components; +using UnityEngine; namespace NAK.ASTExtension.Integrations; @@ -29,6 +31,9 @@ public static partial class BtkUiAddon Category category = QuickMenuAPI.PlayerSelectPage.AddCategory(ASTExtensionMod.ModName, ASTExtensionMod.ModName); Button button = category.AddButton("Copy Height", "ASM_Icon_AvatarHeightCopy", "Copy selected players Eye Height."); button.OnPress += OnCopyPlayerHeight; + + Button button2 = category.AddButton("Copy AAS", string.Empty, "Copy selected players AAS."); + button2.OnPress += OnCopyPlayerAAS; } private static void OnPlayerSelected(string _, string id) @@ -38,18 +43,56 @@ public static partial class BtkUiAddon private static void OnCopyPlayerHeight() { - if (string.IsNullOrEmpty(_selectedPlayer)) - return; - - if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(_selectedPlayer, out PuppetMaster player)) - return; - - if (player._avatar == null) - return; + if (string.IsNullOrEmpty(_selectedPlayer)) + return; + + if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(_selectedPlayer, out PuppetMaster player)) + return; + + if (player._avatar == null) + return; - float height = player.netIkController.GetRemoteHeight(); - ASTExtensionMod.Instance.SetAvatarHeight(height); + float height = player.netIkController.GetRemoteHeight(); + ASTExtensionMod.Instance.SetAvatarHeight(height); + } + + private static void OnCopyPlayerAAS() + { + if (string.IsNullOrEmpty(_selectedPlayer)) + return; + + if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(_selectedPlayer, out PuppetMaster player)) + return; + + AvatarAnimatorManager localAnimator = PlayerSetup.Instance.animatorManager; + AvatarAnimatorManager remoteAnimator = player.animatorManager; + if (!localAnimator.IsInitialized + || !remoteAnimator.IsInitialized) + return; + + // Copy AAS + foreach ((var parameterName, CVRAnimatorManager.ParamDef paramDef) in remoteAnimator.Parameters) + { + switch (paramDef.type) + { + case AnimatorControllerParameterType.Trigger: + case AnimatorControllerParameterType.Bool: + remoteAnimator.GetParameter(parameterName, out bool value); + localAnimator.SetParameter(parameterName, value); + break; + case AnimatorControllerParameterType.Float: + remoteAnimator.GetParameter(parameterName, out float value2); + localAnimator.SetParameter(parameterName, value2); + break; + case AnimatorControllerParameterType.Int: + remoteAnimator.GetParameter(parameterName, out int value3); + localAnimator.SetParameter(parameterName, value3); + break; + } } + + } + #endregion Player Select Page } \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.API.cs b/AvatarCloneTest/AvatarClone/AvatarClone.API.cs deleted file mode 100644 index 89835bd..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.API.cs +++ /dev/null @@ -1,68 +0,0 @@ -using UnityEngine; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - #region Public API Methods - - /// - /// Sets whether the specific renderer requires additional runtime checks when copying to the clone. - /// For example, Magica Cloth modifies the sharedMesh & bones of the renderer at runtime. This is not needed - /// for most renderers, so copying for all renderers would be inefficient. - /// - public void SetRendererNeedsAdditionalChecks(Renderer rend, bool needsChecks) - { - switch (rend) - { - case MeshRenderer meshRenderer: - { - int index = _standardRenderers.IndexOf(meshRenderer); - if (index == -1) return; - - if (needsChecks && !_standardRenderersNeedingChecks.Contains(index)) - { - int insertIndex = _standardRenderersNeedingChecks.Count; - _standardRenderersNeedingChecks.Add(index); - _cachedSharedMeshes.Insert(insertIndex, null); - } - else if (!needsChecks) - { - int removeIndex = _standardRenderersNeedingChecks.IndexOf(index); - if (removeIndex != -1) - { - _standardRenderersNeedingChecks.RemoveAt(removeIndex); - _cachedSharedMeshes.RemoveAt(removeIndex); - } - } - return; - } - case SkinnedMeshRenderer skinnedRenderer: - { - int index = _skinnedRenderers.IndexOf(skinnedRenderer); - if (index == -1) return; - - if (needsChecks && !_skinnedRenderersNeedingChecks.Contains(index)) - { - int insertIndex = _skinnedRenderersNeedingChecks.Count; - _skinnedRenderersNeedingChecks.Add(index); - _cachedSharedMeshes.Insert(_standardRenderersNeedingChecks.Count + insertIndex, null); - _cachedSkinnedBoneCounts.Add(0); - } - else if (!needsChecks) - { - int removeIndex = _skinnedRenderersNeedingChecks.IndexOf(index); - if (removeIndex != -1) - { - _skinnedRenderersNeedingChecks.RemoveAt(removeIndex); - _cachedSharedMeshes.RemoveAt(_standardRenderersNeedingChecks.Count + removeIndex); - _cachedSkinnedBoneCounts.RemoveAt(removeIndex); - } - } - break; - } - } - } - - #endregion Public API Methods -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs deleted file mode 100644 index 8fb54ec..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs +++ /dev/null @@ -1,103 +0,0 @@ -using ABI_RC.Core; -using UnityEngine; -using UnityEngine.Rendering; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - #region Clone Creation - - private void CreateClones() - { - int standardCount = _standardRenderers.Count; - _standardClones = new List(standardCount); - _standardCloneFilters = new List(standardCount); - for (int i = 0; i < standardCount; i++) CreateStandardClone(i); - - int skinnedCount = _skinnedRenderers.Count; - _skinnedClones = new List(skinnedCount); - for (int i = 0; i < skinnedCount; i++) CreateSkinnedClone(i); - } - - private void CreateStandardClone(int index) - { - MeshRenderer sourceRenderer = _standardRenderers[index]; - MeshFilter sourceFilter = _standardFilters[index]; - - GameObject go = new(sourceRenderer.name + "_VisualClone") - { - layer = CVRLayers.PlayerClone - }; - - go.transform.SetParent(sourceRenderer.transform, false); - //go.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); - - MeshRenderer cloneRenderer = go.AddComponent(); - MeshFilter cloneFilter = go.AddComponent(); - - // Initial setup - cloneRenderer.sharedMaterials = sourceRenderer.sharedMaterials; - cloneRenderer.shadowCastingMode = ShadowCastingMode.Off; - cloneRenderer.probeAnchor = sourceRenderer.probeAnchor; - cloneRenderer.localBounds = new Bounds(Vector3.zero, Vector3.positiveInfinity); - cloneFilter.sharedMesh = sourceFilter.sharedMesh; - - // Optimizations to enforce - cloneRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; - cloneRenderer.allowOcclusionWhenDynamic = false; - - // Optimizations to enforce - sourceRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; - sourceRenderer.allowOcclusionWhenDynamic = false; - - _standardClones.Add(cloneRenderer); - _standardCloneFilters.Add(cloneFilter); - } - - private void CreateSkinnedClone(int index) - { - SkinnedMeshRenderer source = _skinnedRenderers[index]; - - GameObject go = new(source.name + "_VisualClone") - { - layer = CVRLayers.PlayerClone - }; - - go.transform.SetParent(source.transform, false); - //go.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); - - SkinnedMeshRenderer clone = go.AddComponent(); - - // Initial setup - clone.sharedMaterials = source.sharedMaterials; - clone.shadowCastingMode = ShadowCastingMode.Off; - clone.probeAnchor = source.probeAnchor; - clone.localBounds = new Bounds(Vector3.zero, Vector3.positiveInfinity); - clone.sharedMesh = source.sharedMesh; - clone.rootBone = source.rootBone; - clone.bones = source.bones; - clone.quality = source.quality; - clone.updateWhenOffscreen = source.updateWhenOffscreen; - - // Optimizations to enforce - clone.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; - clone.allowOcclusionWhenDynamic = false; - clone.updateWhenOffscreen = false; - clone.skinnedMotionVectors = false; - clone.forceMatrixRecalculationPerRender = false; - clone.quality = SkinQuality.Bone4; - - // Optimizations to enforce - source.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; - source.allowOcclusionWhenDynamic = false; - source.updateWhenOffscreen = false; - source.skinnedMotionVectors = false; - source.forceMatrixRecalculationPerRender = false; - source.quality = SkinQuality.Bone4; - - _skinnedClones.Add(clone); - } - - #endregion Clone Creation -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs deleted file mode 100644 index d5136e3..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs +++ /dev/null @@ -1,141 +0,0 @@ -using ABI.CCK.Components; -using UnityEngine; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - private readonly Dictionary> _exclusionDirectRenderers = new(); - private readonly Dictionary> _exclusionControlledBones = new(); - - private void InitializeExclusions() - { - // Add head exclusion for humanoid avatars if not present - var animator = GetComponent(); - if (animator != null && animator.isHuman) - { - var headBone = animator.GetBoneTransform(HumanBodyBones.Head); - if (headBone != null && headBone.GetComponent() == null) - { - var exclusion = headBone.gameObject.AddComponent(); - exclusion.isShown = false; - exclusion.target = headBone; - exclusion.shrinkToZero = true; - } - } - - // Process existing exclusions bottom-up - var exclusions = GetComponentsInChildren(true); - - for (int i = exclusions.Length - 1; i >= 0; i--) - { - var exclusion = exclusions[i]; - if (exclusion.target == null) - exclusion.target = exclusion.transform; - - // Skip invalid exclusions or already processed targets - if (exclusion.target == null || _exclusionDirectRenderers.ContainsKey(exclusion.target)) - { - Destroy(exclusion); - continue; - } - - // Initialize data for this exclusion - _exclusionDirectRenderers[exclusion.target] = new HashSet(); - _exclusionControlledBones[exclusion.target] = new HashSet(); - - // Set up our behaviour - exclusion.behaviour = new AvatarCloneExclusion(this, exclusion.target); - - // Collect affected renderers and bones - CollectExclusionData(exclusion.target); - - // Initial update - exclusion.UpdateExclusions(); - } - } - - private void CollectExclusionData(Transform target) - { - var stack = new Stack(); - stack.Push(target); - - while (stack.Count > 0) - { - var current = stack.Pop(); - - // Skip if this transform belongs to another exclusion - if (current != target && current.GetComponent() != null) - continue; - - _exclusionControlledBones[target].Add(current); - - // Add renderers that will need their clone visibility toggled - foreach (var renderer in current.GetComponents()) - { - // Find corresponding clone renderer - if (renderer is MeshRenderer meshRenderer) - { - int index = _standardRenderers.IndexOf(meshRenderer); - if (index != -1) - _exclusionDirectRenderers[target].Add(_standardClones[index]); - } - else if (renderer is SkinnedMeshRenderer skinnedRenderer) - { - int index = _skinnedRenderers.IndexOf(skinnedRenderer); - if (index != -1) - _exclusionDirectRenderers[target].Add(_skinnedClones[index]); - } - } - - // Add children to stack - foreach (Transform child in current) - { - stack.Push(child); - } - } - } - - public void HandleExclusionUpdate(Transform target, Transform shrinkBone, bool isShown) - { - if (!_exclusionDirectRenderers.TryGetValue(target, out var directCloneRenderers) || - !_exclusionControlledBones.TryGetValue(target, out var controlledBones)) - return; - - // Handle direct clone renderers - foreach (var cloneRenderer in directCloneRenderers) - { - cloneRenderer.enabled = isShown; - } - - // Update bone references in clone renderers - int cloneCount = _skinnedClones.Count; - var cloneRenderers = _skinnedClones; - var sourceRenderers = _skinnedRenderers; - - for (int i = 0; i < cloneCount; i++) - { - var clone = cloneRenderers[i]; - var source = sourceRenderers[i]; - var sourceBones = source.bones; - var cloneBones = clone.bones; - int boneCount = cloneBones.Length; - bool needsUpdate = false; - - for (int j = 0; j < boneCount; j++) - { - // Check if this bone is in our controlled set - if (controlledBones.Contains(sourceBones[j])) - { - cloneBones[j] = isShown ? sourceBones[j] : shrinkBone; - needsUpdate = true; - } - } - - if (needsUpdate) - { - clone.bones = cloneBones; - } - } - } -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs new file mode 100644 index 0000000..cedbcdd --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs @@ -0,0 +1,229 @@ +using ABI.CCK.Components; +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region Exclusions + + private FPRExclusion[] _exclusions; + + private void AddExclusionToHeadIfNeeded() + { + if (!TryGetComponent(out Animator animator) + || !animator.isHuman + || !animator.avatar + || !animator.avatar.isValid) + return; + + Transform head = animator.GetBoneTransform(HumanBodyBones.Head); + if (!head) + return; + + GameObject headGo = head.gameObject; + if (headGo.TryGetComponent(out FPRExclusion exclusion)) + return; + + exclusion = headGo.AddComponent(); + exclusion.target = head; + exclusion.isShown = false; + } + + private void InitializeExclusions() + { + _exclusions = GetComponentsInChildren(true); + var exclusionRoots = new Dictionary(_exclusions.Length); + + // **1. Precompute Exclusions** + foreach (FPRExclusion exclusion in _exclusions) + { + Transform target = exclusion.target ??= exclusion.transform; + if (exclusionRoots.ContainsKey(target) || !target.gameObject.scene.IsValid()) + continue; + + AvatarCloneExclusion behaviour = new AvatarCloneExclusion(this, target); + exclusion.behaviour = behaviour; + exclusionRoots.Add(target, behaviour); + } + + // Process Exclusion Transforms + Renderer ourRenderer; + + void ProcessTransformHierarchy(Transform current, Transform root, AvatarCloneExclusion behaviour) + { + if (exclusionRoots.ContainsKey(current) && current != root) return; + + behaviour.affectedTransforms.Add(current); + if (current.TryGetComponent(out ourRenderer)) + behaviour.affectedRenderers.Add(ourRenderer); + + for (int i = 0; i < current.childCount; i++) + { + Transform child = current.GetChild(i); + if (!exclusionRoots.ContainsKey(child)) + ProcessTransformHierarchy(child, root, behaviour); + } + } + + foreach (var entry in exclusionRoots) + { + Transform rootTransform = entry.Key; + AvatarCloneExclusion behaviour = entry.Value; + ProcessTransformHierarchy(rootTransform, rootTransform, behaviour); + behaviour.affectedTransformSet = new HashSet(behaviour.affectedTransforms); + } + + // ------------------------------ + // **OPTIMIZED EXCLUSION BONE MAPPING** + // ------------------------------ + + Dictionary.ValueCollection exclusionBehaviours = exclusionRoots.Values; + int skinnedCount = _skinnedClones.Count; + + // **2. Precompute Bone-to-Exclusion Mapping** + int estimatedBoneCount = skinnedCount * 20; // Estimated bones per skinned mesh + var boneToExclusion = new Dictionary>(estimatedBoneCount); + + foreach (AvatarCloneExclusion behaviour in exclusionBehaviours) + { + foreach (Transform bone in behaviour.affectedTransformSet) + { + if (!boneToExclusion.TryGetValue(bone, out var list)) + { + list = new List(2); + boneToExclusion[bone] = list; + } + list.Add(behaviour); + } + } + + // **3. Process Skinned Mesh Renderers** + for (int s = 0; s < skinnedCount; s++) + { + SkinnedMeshRenderer source = _skinnedRenderers[s]; + var bones = source.bones; // Cache bones array + + SkinnedMeshRenderer smr = _skinnedClones[s]; + int boneCount = bones.Length; + + for (int i = 0; i < boneCount; i++) + { + Transform bone = bones[i]; + + // **Skip if the bone isn't mapped to exclusions** + if (!bone // Skip null bones + || !boneToExclusion.TryGetValue(bone, out var behaviours)) + continue; + + // **Avoid redundant dictionary lookups** + for (int j = 0; j < behaviours.Count; j++) + { + AvatarCloneExclusion behaviour = behaviours[j]; + + if (!behaviour.skinnedToBoneIndex.TryGetValue(smr, out var indices)) + { + indices = new List(4); + behaviour.skinnedToBoneIndex[smr] = indices; + } + + indices.Add(i); + } + } + } + + ApplyInitialExclusionState(); + } + + public void ApplyInitialExclusionState() + { + foreach (FPRExclusion exclusion in _exclusions) + { + exclusion._wasShown = exclusion.isShown; + if (!exclusion.isShown) exclusion.UpdateExclusions(); + } + } + + public void HandleExclusionUpdate(AvatarCloneExclusion exclusion, bool isShown) + { +#if ENABLE_PROFILER + s_UpdateExclusions.Begin(); +#endif + + // **1. Update Renderer Visibility** + foreach (Renderer renderer in exclusion.affectedRenderers) + { + if (renderer is SkinnedMeshRenderer skinned) + { + int index = _skinnedRenderers.IndexOf(skinned); + if (index >= 0) _skinnedClones[index].gameObject.SetActive(isShown); + } + else if (renderer is MeshRenderer mesh) + { + int index = _meshRenderers.IndexOf(mesh); + if (index >= 0) + { + if (Setting_CloneMeshRenderers) + { + _meshClones[index].gameObject.SetActive(isShown); + } + else + { + // Other renderer (never cloned) - update shadow casting state + _sourceShouldBeHiddenFromFPR[index] = !isShown; // When hidden, use for shadows + } + } + } + else if (renderer) + { + int index = _otherRenderers.IndexOf(renderer); + if (index >= 0) + { + int shadowIndex = index + (Setting_CloneMeshRenderers ? _meshRenderers.Count : 0); + _sourceShouldBeHiddenFromFPR[shadowIndex] = !isShown; // When hidden, use for shadows + } + } + } + + // **2. Update Bone References in Skinned Mesh Renderers** + UpdateSkinnedMeshBones(exclusion, exclusion._shrinkBone, isShown); + +#if ENABLE_PROFILER + s_UpdateExclusions.End(); +#endif + } + + private void UpdateSkinnedMeshBones(AvatarCloneExclusion exclusion, Transform shrinkBone, bool isShown) + { +#if ENABLE_PROFILER + s_HandleBoneUpdates.Begin(); +#endif + + foreach (var smrEntry in exclusion.skinnedToBoneIndex) + { + SkinnedMeshRenderer smr = smrEntry.Key; + var indices = smrEntry.Value; + bool needsUpdate = false; + + var parentBones = smr.transform.parent.GetComponent().bones; + var cloneBones = smr.bones; + Array.Resize(ref cloneBones, parentBones.Length); + + // Only modify our bones, other exclusions may have modified others + for (int i = 0; i < indices.Count; i++) + { + int index = indices[i]; + if (!isShown) cloneBones[index] = shrinkBone; + else cloneBones[index] = parentBones[index]; + needsUpdate = true; + } + if (needsUpdate) smr.bones = cloneBones; + } + +#if ENABLE_PROFILER + s_HandleBoneUpdates.End(); +#endif + } + + #endregion Exclusions +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs deleted file mode 100644 index 0ba69b0..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs +++ /dev/null @@ -1,67 +0,0 @@ -using UnityEngine; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - #region Profile Markers -//#if UNITY_EDITOR - private static readonly UnityEngine.Profiling.CustomSampler s_CopyMaterials = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.CopyMaterials"); - private static readonly UnityEngine.Profiling.CustomSampler s_CopyBlendShapes = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.CopyBlendShapes"); - private static readonly UnityEngine.Profiling.CustomSampler s_CopyMeshes = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.CopyMeshes"); - - private static readonly UnityEngine.Profiling.CustomSampler s_MyOnPreRender = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.MyOnPreRender"); - private static readonly UnityEngine.Profiling.CustomSampler s_SetShadowsOnly = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.SetShadowsOnly"); - private static readonly UnityEngine.Profiling.CustomSampler s_UndoShadowsOnly = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.UndoShadowsOnly"); - private static readonly UnityEngine.Profiling.CustomSampler s_SetUiCulling = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.SetUiCulling"); - private static readonly UnityEngine.Profiling.CustomSampler s_UndoUiCulling = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.UndoUiCulling"); - -//#endif - #endregion Profile Markers - - #region Source Renderers - private List _standardRenderers; - private List _standardFilters; - private List _skinnedRenderers; - private List _allSourceRenderers; // For shadow casting only - #endregion Source Renderers - - #region Clone Renderers - private List _standardClones; - private List _standardCloneFilters; - private List _skinnedClones; - #endregion Clone Renderers - - #region Dynamic Check Lists - private List _standardRenderersNeedingChecks; // Stores indices into _standardRenderers - private List _skinnedRenderersNeedingChecks; // Stores indices into _skinnedRenderers - private List _cachedSkinnedBoneCounts; // So we don't copy the bones unless they've changed - private List _cachedSharedMeshes; // So we don't copy the mesh unless it's changed - #endregion Dynamic Check Lists - - #region Material Data - private List _localMaterials; - private List _cullingMaterials; - private List _mainMaterials; - private MaterialPropertyBlock _propertyBlock; - #endregion Material Data - - #region Blend Shape Data - private List> _blendShapeWeights; - #endregion Blend Shape Data - - #region Shadow and UI Culling Settings - private bool _uiCullingActive; - private bool _shadowsOnlyActive; - private bool[] _originallyHadShadows; - private bool[] _originallyWasEnabled; - #endregion Shadow and UI Culling Settings -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs index 41bd84b..f02fe9b 100644 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs @@ -1,5 +1,6 @@ using ABI_RC.Core.Player.ShadowClone; using UnityEngine; +using UnityEngine.Rendering; namespace NAK.AvatarCloneTest; @@ -9,120 +10,295 @@ public partial class AvatarClone private void InitializeCollections() { - _standardRenderers = new List(); - _standardFilters = new List(); +#if ENABLE_PROFILER + s_InitializeData.Begin(); +#endif + + // Initialize source collections _skinnedRenderers = new List(); - _allSourceRenderers = new List(); + _blendShapeWeights = new List>(); - _standardClones = new List(); - _standardCloneFilters = new List(); + _meshRenderers = new List(); + _meshFilters = new List(); + + _otherRenderers = new List(); + + // Initialize clone collections _skinnedClones = new List(); + _skinnedCloneMaterials = new List(); + _skinnedCloneCullingMaterials = new List(); - _standardRenderersNeedingChecks = new List(); - _skinnedRenderersNeedingChecks = new List(); - _cachedSkinnedBoneCounts = new List(); - _cachedSharedMeshes = new List(); + if (Setting_CloneMeshRenderers) + { + _meshClones = new List(); + _meshCloneFilters = new List(); + _meshCloneMaterials = new List(); + _meshCloneCullingMaterials = new List(); + } - _localMaterials = new List(); - _cullingMaterials = new List(); - _mainMaterials = new List(); + // Initialize shared resources + _materialWorkingList = new List(); _propertyBlock = new MaterialPropertyBlock(); - _blendShapeWeights = new List>(); +#if ENABLE_PROFILER + s_InitializeData.End(); +#endif } - private void InitializeRenderers() + private void CollectRenderers() { - var renderers = GetComponentsInChildren(true); + #if ENABLE_PROFILER + s_InitializeData.Begin(); + #endif - // Pre-size lists based on found renderers - // _standardRenderers.Capacity = renderers.Length; - // _standardFilters.Capacity = renderers.Length; - // _skinnedRenderers.Capacity = renderers.Length; - // _allSourceRenderers.Capacity = renderers.Length; - - // Sort renderers into their respective lists - foreach (Renderer render in renderers) + var renderers = GetComponentsInChildren(true); + var currentIndex = 0; + var nonCloned = 0; + + // Single pass: directly categorize renderers + foreach (Renderer renderer in renderers) { - _allSourceRenderers.Add(render); - - switch (render) + switch (renderer) { - case MeshRenderer meshRenderer: - { - MeshFilter filter = meshRenderer.GetComponent(); + case SkinnedMeshRenderer skinned when skinned.sharedMesh != null: + AddSkinnedRenderer(skinned); + currentIndex++; + break; + + case MeshRenderer mesh: + MeshFilter filter = mesh.GetComponent(); if (filter != null && filter.sharedMesh != null) { - _standardRenderers.Add(meshRenderer); - _standardFilters.Add(filter); + if (Setting_CloneMeshRenderers) + { + AddMeshRenderer(mesh, filter); + } + else + { + AddMeshRenderer(mesh, filter); + nonCloned++; + } + currentIndex++; } break; - } - case SkinnedMeshRenderer skinnedRenderer: - { - if (skinnedRenderer.sharedMesh != null) _skinnedRenderers.Add(skinnedRenderer); + + default: + AddOtherRenderer(renderer); + currentIndex++; + nonCloned++; break; - } } } - } - - private void SetupMaterialsAndBlendShapes() - { - // Cache counts - int standardCount = _standardRenderers.Count; - int skinnedCount = _skinnedRenderers.Count; - var standardRenderers = _standardRenderers; - var skinnedRenderers = _skinnedRenderers; - var localMats = _localMaterials; - var cullingMats = _cullingMaterials; - var blendWeights = _blendShapeWeights; - // Setup standard renderer materials - for (int i = 0; i < standardCount; i++) - { - MeshRenderer render = standardRenderers[i]; - int matCount = render.sharedMaterials.Length; - - // Local materials array - var localMatArray = new Material[matCount]; - for (int j = 0; j < matCount; j++) localMatArray[j] = render.sharedMaterials[j]; - localMats.Add(localMatArray); - - // Culling materials array - var cullingMatArray = new Material[matCount]; - for (int j = 0; j < matCount; j++) cullingMatArray[j] = ShadowCloneUtils.cullingMaterial; - cullingMats.Add(cullingMatArray); - } - - // Setup skinned renderer materials and blend shapes - for (int i = 0; i < skinnedCount; i++) - { - SkinnedMeshRenderer render = skinnedRenderers[i]; - int matCount = render.sharedMaterials.Length; - - // Local materials array - var localMatArray = new Material[matCount]; - for (int j = 0; j < matCount; j++) localMatArray[j] = render.sharedMaterials[j]; - localMats.Add(localMatArray); - - // Culling materials array - var cullingMatArray = new Material[matCount]; - for (int j = 0; j < matCount; j++) cullingMatArray[j] = ShadowCloneUtils.cullingMaterial; - cullingMats.Add(cullingMatArray); - - // Blend shape weights - int blendShapeCount = render.sharedMesh.blendShapeCount; - var weights = new List(blendShapeCount); - for (int j = 0; j < blendShapeCount; j++) weights.Add(0f); - blendWeights.Add(weights); - } - - // Initialize renderer state arrays - int totalRenderers = _allSourceRenderers.Count; - _originallyHadShadows = new bool[totalRenderers]; - _originallyWasEnabled = new bool[totalRenderers]; + _rendererActiveStates = new bool[currentIndex]; + _originalShadowCastingMode = new ShadowCastingMode[currentIndex]; + _sourceShouldBeHiddenFromFPR = new bool[nonCloned]; + + #if ENABLE_PROFILER + s_InitializeData.End(); + #endif } + private void AddSkinnedRenderer(SkinnedMeshRenderer renderer) + { +#if ENABLE_PROFILER + s_AddRenderer.Begin(); +#endif + + _skinnedRenderers.Add(renderer); + + // Clone materials array for clone renderer + var materials = renderer.sharedMaterials; + var cloneMaterials = new Material[materials.Length]; + for (int i = 0; i < materials.Length; i++) cloneMaterials[i] = materials[i]; + _skinnedCloneMaterials.Add(cloneMaterials); + + // Cache culling materials + var cullingMaterialArray = new Material[materials.Length]; +#if !UNITY_EDITOR + for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = ShadowCloneUtils.cullingMaterial; +#else + for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = cullingMaterial; +#endif + _skinnedCloneCullingMaterials.Add(cullingMaterialArray); + + // Cache blend shape weights + var weights = new List(renderer.sharedMesh.blendShapeCount); + for (int i = 0; i < renderer.sharedMesh.blendShapeCount; i++) weights.Add(0f); + _blendShapeWeights.Add(weights); + +#if ENABLE_PROFILER + s_AddRenderer.End(); +#endif + } + + private void AddMeshRenderer(MeshRenderer renderer, MeshFilter filter) + { +#if ENABLE_PROFILER + s_AddRenderer.Begin(); +#endif + + _meshRenderers.Add(renderer); + _meshFilters.Add(filter); + + if (!Setting_CloneMeshRenderers) return; + + // Clone materials array for clone renderer + var materials = renderer.sharedMaterials; + var cloneMaterials = new Material[materials.Length]; + for (int i = 0; i < materials.Length; i++) cloneMaterials[i] = materials[i]; + _meshCloneMaterials.Add(cloneMaterials); + + // Cache culling materials + var cullingMaterialArray = new Material[materials.Length]; +#if !UNITY_EDITOR + for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = ShadowCloneUtils.cullingMaterial; +#else + for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = cullingMaterial; +#endif + _meshCloneCullingMaterials.Add(cullingMaterialArray); + +#if ENABLE_PROFILER + s_AddRenderer.End(); +#endif + } + + private void AddOtherRenderer(Renderer renderer) + { +#if ENABLE_PROFILER + s_AddRenderer.Begin(); +#endif + _otherRenderers.Add(renderer); +#if ENABLE_PROFILER + s_AddRenderer.End(); +#endif + } + + private void CreateClones() + { +#if ENABLE_PROFILER + s_InitializeData.Begin(); +#endif + + // Always create skinned mesh clones + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++) + { + CreateSkinnedClone(i); + } + + // Optionally create mesh clones + if (Setting_CloneMeshRenderers) + { + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++) + { + CreateMeshClone(i); + } + } + +#if ENABLE_PROFILER + s_InitializeData.End(); +#endif + } + + private void CreateSkinnedClone(int index) + { +#if ENABLE_PROFILER + s_CreateClone.Begin(); +#endif + + SkinnedMeshRenderer source = _skinnedRenderers[index]; + + GameObject clone = new(source.name + "_Clone") + { + layer = CLONE_LAYER + }; + + clone.transform.SetParent(source.transform, false); + + SkinnedMeshRenderer cloneRenderer = clone.AddComponent(); + + // Basic setup + cloneRenderer.sharedMaterials = _skinnedCloneMaterials[index]; + cloneRenderer.shadowCastingMode = ShadowCastingMode.Off; + cloneRenderer.probeAnchor = source.probeAnchor; + cloneRenderer.sharedMesh = source.sharedMesh; + cloneRenderer.rootBone = source.rootBone; + cloneRenderer.bones = source.bones; + +#if !UNITY_EDITOR + cloneRenderer.localBounds = new Bounds(source.localBounds.center, source.localBounds.size * 2f); +#endif + + // Quality settings + cloneRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + cloneRenderer.allowOcclusionWhenDynamic = false; + cloneRenderer.updateWhenOffscreen = false; + cloneRenderer.skinnedMotionVectors = false; + cloneRenderer.forceMatrixRecalculationPerRender = false; + cloneRenderer.quality = SkinQuality.Bone4; + + source.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + source.allowOcclusionWhenDynamic = false; + source.updateWhenOffscreen = false; + source.skinnedMotionVectors = false; + source.forceMatrixRecalculationPerRender = false; + source.quality = SkinQuality.Bone4; + + // Add to clone list + _skinnedClones.Add(cloneRenderer); + +#if ENABLE_PROFILER + s_CreateClone.End(); +#endif + } + + private void CreateMeshClone(int index) + { +#if ENABLE_PROFILER + s_CreateClone.Begin(); +#endif + + MeshRenderer source = _meshRenderers[index]; + MeshFilter sourceFilter = _meshFilters[index]; + + GameObject clone = new(source.name + "_Clone") + { + layer = CLONE_LAYER + }; + + clone.transform.SetParent(source.transform, false); + + MeshRenderer cloneRenderer = clone.AddComponent(); + MeshFilter cloneFilter = clone.AddComponent(); + + // Basic setup + cloneRenderer.sharedMaterials = _meshCloneMaterials[index]; + cloneRenderer.shadowCastingMode = ShadowCastingMode.Off; + cloneRenderer.probeAnchor = source.probeAnchor; + +#if !UNITY_EDITOR + cloneRenderer.localBounds = new Bounds(source.localBounds.center, source.localBounds.size * 2f); +#endif + + cloneFilter.sharedMesh = sourceFilter.sharedMesh; + + // Quality settings + cloneRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + cloneRenderer.allowOcclusionWhenDynamic = false; + + source.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + source.allowOcclusionWhenDynamic = false; + + // Add to clone lists + _meshClones.Add(cloneRenderer); + _meshCloneFilters.Add(cloneFilter); + +#if ENABLE_PROFILER + s_CreateClone.End(); +#endif + } + #endregion Initialization } \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs b/AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs deleted file mode 100644 index 7ae5855..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs +++ /dev/null @@ -1,34 +0,0 @@ -using MagicaCloth; -using MagicaCloth2; -using UnityEngine; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - #region Magica Cloth Support - - private void SetupMagicaClothSupport() - { - var magicaCloths1 = GetComponentsInChildren(true); - foreach (MagicaRenderDeformer magicaCloth in magicaCloths1) - { - // Get the renderer on the same object - Renderer renderer = magicaCloth.gameObject.GetComponent(); - SetRendererNeedsAdditionalChecks(renderer, true); - } - - var magicaCloths2 = GetComponentsInChildren(true); - foreach (MagicaCloth2.MagicaCloth magicaCloth in magicaCloths2) - { - if (magicaCloth.serializeData.clothType != ClothProcess.ClothType.MeshCloth) - continue; // Only matters for cloth physics - - // Set the affected renderers as requiring extra checks - var renderers = magicaCloth.serializeData.sourceRenderers; - foreach (Renderer renderer in renderers) SetRendererNeedsAdditionalChecks(renderer, true); - } - } - - #endregion Magica Cloth Support -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs b/AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs new file mode 100644 index 0000000..40c1df7 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs @@ -0,0 +1,212 @@ +using UnityEngine; +using UnityEngine.Rendering; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region Render State Management + + private void MyOnPreCull(Camera cam) + { +#if UNITY_EDITOR + // Scene & Preview cameras are not needed + if (cam.cameraType != CameraType.Game) + return; +#endif + +#if ENABLE_PROFILER + s_PreCullUpdate.Begin(); +#endif + + bool isOurUiCamera = IsUIInternalCamera(cam); + bool rendersOurPlayerLayer = CameraRendersPlayerLocalLayer(cam); + bool rendersOurCloneLayer = CameraRendersPlayerCloneLayer(cam); + + bool rendersBothPlayerLayers = rendersOurPlayerLayer && rendersOurCloneLayer; + + // Handle shadow casting when camera renders both layers + if (!_sourcesSetForShadowCasting + && rendersBothPlayerLayers) + { + ConfigureSourceShadowCasting(true); + _sourcesSetForShadowCasting = true; + } + else if (_sourcesSetForShadowCasting && !rendersBothPlayerLayers) + { + ConfigureSourceShadowCasting(false); + _sourcesSetForShadowCasting = false; + } + + // Handle UI culling for clone layer + if (!_clonesSetForUiCulling + && isOurUiCamera && rendersOurCloneLayer) + { + ConfigureCloneUICulling(true); + _clonesSetForUiCulling = true; + } + else if (_clonesSetForUiCulling) + { + ConfigureCloneUICulling(false); + _clonesSetForUiCulling = false; + } + +#if ENABLE_PROFILER + s_PreCullUpdate.End(); +#endif + } + + private void ConfigureSourceShadowCasting(bool setSourcesToShadowCast) + { +#if ENABLE_PROFILER + s_ConfigureShadowCasting.Begin(); +#endif + + int currentIndex = 0; + int shadowArrayIndex = 0; + + // Handle skinned mesh renderers (always have clones) + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) continue; + + SkinnedMeshRenderer source = _skinnedRenderers[i]; + + if (setSourcesToShadowCast) + { + ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode; + if (originalMode == ShadowCastingMode.Off) + source.forceRenderingOff = true; + else + source.shadowCastingMode = ShadowCastingMode.ShadowsOnly; + } + else + { + source.shadowCastingMode = _originalShadowCastingMode[currentIndex]; + source.forceRenderingOff = false; + } + } + + // Handle mesh renderers based on clone setting + if (Setting_CloneMeshRenderers) + { + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) continue; + + MeshRenderer source = _meshRenderers[i]; + + if (setSourcesToShadowCast) + { + ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode; + if (originalMode == ShadowCastingMode.Off) + source.forceRenderingOff = true; + else + source.shadowCastingMode = ShadowCastingMode.ShadowsOnly; + } + else + { + source.shadowCastingMode = _originalShadowCastingMode[currentIndex]; + source.forceRenderingOff = false; + } + } + } + else + { + // When not cloned, mesh renderers use the shadow casting array + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++, shadowArrayIndex++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) continue; + if (!_sourceShouldBeHiddenFromFPR[shadowArrayIndex]) continue; + + MeshRenderer source = _meshRenderers[i]; + + if (setSourcesToShadowCast) + { + ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode; + if (originalMode == ShadowCastingMode.Off) + source.forceRenderingOff = true; + else + source.shadowCastingMode = ShadowCastingMode.ShadowsOnly; + } + else + { + source.shadowCastingMode = _originalShadowCastingMode[currentIndex]; + source.forceRenderingOff = false; + } + } + } + + // Handle other renderers (never cloned) + int otherCount = _otherRenderers.Count; + for (int i = 0; i < otherCount; i++, shadowArrayIndex++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) continue; + if (!_sourceShouldBeHiddenFromFPR[shadowArrayIndex]) continue; + + Renderer source = _otherRenderers[i]; + + if (setSourcesToShadowCast) + { + ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode; + if (originalMode == ShadowCastingMode.Off) + source.forceRenderingOff = true; + else + source.shadowCastingMode = ShadowCastingMode.ShadowsOnly; + } + else + { + source.shadowCastingMode = _originalShadowCastingMode[currentIndex]; + source.forceRenderingOff = false; + } + } + +#if ENABLE_PROFILER + s_ConfigureShadowCasting.End(); +#endif + } + + private void ConfigureCloneUICulling(bool enableCulling) + { +#if ENABLE_PROFILER + s_ConfigureUICulling.Begin(); +#endif + + // Set the materials to our culling materials + int currentIndex = 0; + + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) + continue; + + _skinnedClones[i].sharedMaterials = enableCulling ? + _skinnedCloneCullingMaterials[i] : + _skinnedCloneMaterials[i]; + } + + if (Setting_CloneMeshRenderers) + { + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) + continue; + + _meshClones[i].sharedMaterials = enableCulling ? + _meshCloneCullingMaterials[i] : + _meshCloneMaterials[i]; + } + } + +#if ENABLE_PROFILER + s_ConfigureUICulling.End(); +#endif + } + + #endregion Render State Management +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs b/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs new file mode 100644 index 0000000..eb70282 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs @@ -0,0 +1,156 @@ +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region State Syncing + + private void SyncEnabledState() + { +#if ENABLE_PROFILER + s_CopyEnabledState.Begin(); +#endif + + int currentIndex = 0; + + // Update skinned mesh renderers + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++, currentIndex++) + { + SkinnedMeshRenderer source = _skinnedRenderers[i]; + _skinnedClones[i].enabled = _rendererActiveStates[currentIndex] = IsRendererActive(source); + } + + // Update mesh renderers + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++, currentIndex++) + { + MeshRenderer source = _meshRenderers[i]; + if (Setting_CloneMeshRenderers) _meshClones[i].enabled = _rendererActiveStates[currentIndex] = IsRendererActive(source); + else _rendererActiveStates[currentIndex] = IsRendererActive(source); + } + + // Update other renderers + int otherCount = _otherRenderers.Count; + for (int i = 0; i < otherCount; i++, currentIndex++) + { + Renderer source = _otherRenderers[i]; + _rendererActiveStates[currentIndex] = IsRendererActive(source); + } + +#if ENABLE_PROFILER + s_CopyEnabledState.End(); +#endif + } + + private void SyncMaterials() + { +#if ENABLE_PROFILER + s_CopyMaterials.Begin(); +#endif + int currentIndex = 0; + + // Sync skinned mesh materials + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) + continue; + + CopyMaterialsAndProperties( + _skinnedRenderers[i], + _skinnedClones[i], + _propertyBlock, + _materialWorkingList, + _skinnedCloneMaterials[i]); + } + + // Sync mesh materials if enabled + if (Setting_CloneMeshRenderers) + { + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) + continue; + + CopyMaterialsAndProperties( + _meshRenderers[i], + _meshClones[i], + _propertyBlock, + _materialWorkingList, + _meshCloneMaterials[i]); + } + } + +#if ENABLE_PROFILER + s_CopyMaterials.End(); +#endif + } + + private void SyncBlendShapes() + { +#if ENABLE_PROFILER + s_CopyBlendShapes.Begin(); +#endif + + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++) + { + SkinnedMeshRenderer source = _skinnedRenderers[i]; + if (!_rendererActiveStates[i]) + continue; + + CopyBlendShapes( + source, + _skinnedClones[i], + _blendShapeWeights[i]); + } + +#if ENABLE_PROFILER + s_CopyBlendShapes.End(); +#endif + } + + private static void CopyMaterialsAndProperties( + Renderer source, + Renderer clone, + MaterialPropertyBlock propertyBlock, + List workingList, + Material[] cloneMaterials) + { + source.GetSharedMaterials(workingList); + + int matCount = workingList.Count; + bool hasChanged = false; + + for (int i = 0; i < matCount; i++) + { + if (ReferenceEquals(workingList[i], cloneMaterials[i])) continue; + cloneMaterials[i] = workingList[i]; + hasChanged = true; + } + if (hasChanged) clone.sharedMaterials = cloneMaterials; + + source.GetPropertyBlock(propertyBlock); + clone.SetPropertyBlock(propertyBlock); + } + + private static void CopyBlendShapes( + SkinnedMeshRenderer source, + SkinnedMeshRenderer clone, + List weights) + { + int weightCount = weights.Count; + for (int i = 0; i < weightCount; i++) + { + float weight = source.GetBlendShapeWeight(i); + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (weight == weights[i]) continue; // Halves the work + clone.SetBlendShapeWeight(i, weights[i] = weight); + } + } + + #endregion State Syncing +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Update.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Update.cs deleted file mode 100644 index 42cef73..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Update.cs +++ /dev/null @@ -1,181 +0,0 @@ -using UnityEngine; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - #region Update Methods - - private void UpdateStandardRenderers() - { - int count = _standardRenderers.Count; - var sourceRenderers = _standardRenderers; - var cloneRenderers = _standardClones; - var localMats = _localMaterials; - - for (int i = 0; i < count; i++) - { - if (!IsRendererValid(sourceRenderers[i])) continue; - CopyMaterialsAndProperties( - sourceRenderers[i], - cloneRenderers[i], - _propertyBlock, - _mainMaterials, - localMats[i]); - } - } - - private void UpdateSkinnedRenderers() - { - int standardCount = _standardRenderers.Count; - int count = _skinnedRenderers.Count; - var sourceRenderers = _skinnedRenderers; - var cloneRenderers = _skinnedClones; - var localMats = _localMaterials; - var blendWeights = _blendShapeWeights; - - for (int i = 0; i < count; i++) - { - SkinnedMeshRenderer source = sourceRenderers[i]; - if (!IsRendererValid(source)) continue; - - SkinnedMeshRenderer clone = cloneRenderers[i]; - CopyMaterialsAndProperties( - source, - clone, - _propertyBlock, - _mainMaterials, - localMats[i + standardCount]); - - CopyBlendShapes(source, clone, blendWeights[i]); - } - } - - private void UpdateStandardRenderersWithChecks() - { - s_CopyMeshes.Begin(); - - var cloneFilters = _standardCloneFilters; - var sourceFilters = _standardFilters; - var cachedMeshes = _cachedSharedMeshes; - var checkIndices = _standardRenderersNeedingChecks; - int checkCount = checkIndices.Count; - - while (cachedMeshes.Count < checkCount) cachedMeshes.Add(null); - - for (int i = 0; i < checkCount; i++) - { - int rendererIndex = checkIndices[i]; - Mesh newMesh = sourceFilters[rendererIndex].sharedMesh; - if (ReferenceEquals(newMesh, cachedMeshes[i])) continue; - cloneFilters[rendererIndex].sharedMesh = newMesh; // expensive & allocates - cachedMeshes[i] = newMesh; - } - - s_CopyMeshes.End(); - } - - private void UpdateSkinnedRenderersWithChecks() - { - s_CopyMeshes.Begin(); - - var sourceRenderers = _skinnedRenderers; - var cloneRenderers = _skinnedClones; - var cachedMeshes = _cachedSharedMeshes; - var cachedBoneCounts = _cachedSkinnedBoneCounts; - var checkIndices = _skinnedRenderersNeedingChecks; - int checkCount = checkIndices.Count; - int meshOffset = _standardRenderersNeedingChecks.Count; - - // Ensure cache lists are properly sized - while (cachedMeshes.Count < meshOffset + checkCount) cachedMeshes.Add(null); - while (cachedBoneCounts.Count < checkCount) cachedBoneCounts.Add(0); - - for (int i = 0; i < checkCount; i++) - { - int rendererIndex = checkIndices[i]; - SkinnedMeshRenderer source = sourceRenderers[rendererIndex]; - SkinnedMeshRenderer clone = cloneRenderers[rendererIndex]; - - // Check mesh changes - Mesh newMesh = source.sharedMesh; // expensive & allocates - if (!ReferenceEquals(newMesh, cachedMeshes[meshOffset + i])) - { - clone.sharedMesh = newMesh; - cachedMeshes[meshOffset + i] = newMesh; - } - - // Check bone changes - var sourceBones = source.bones; - int newBoneCount = sourceBones.Length; - int oldBoneCount = cachedBoneCounts[i]; - if (newBoneCount == oldBoneCount) - continue; - - var cloneBones = clone.bones; // expensive & allocates - if (newBoneCount > oldBoneCount) - { - // Resize array and copy only the new bones (Magica Cloth appends bones when enabling Mesh Cloth) - Array.Resize(ref cloneBones, newBoneCount); - for (int boneIndex = oldBoneCount; boneIndex < newBoneCount; boneIndex++) - cloneBones[boneIndex] = sourceBones[boneIndex]; - clone.bones = cloneBones; - } - else - { - // If shrinking, just set the whole array - clone.bones = sourceBones; - } - - cachedBoneCounts[i] = newBoneCount; - } - - s_CopyMeshes.End(); - } - - private static void CopyMaterialsAndProperties( - Renderer source, Renderer clone, - MaterialPropertyBlock propertyBlock, - List mainMaterials, - Material[] localMaterials) - { - s_CopyMaterials.Begin(); - - source.GetSharedMaterials(mainMaterials); - - int matCount = mainMaterials.Count; - bool hasChanged = false; - for (var i = 0; i < matCount; i++) - { - if (ReferenceEquals(mainMaterials[i], localMaterials[i])) continue; - localMaterials[i] = mainMaterials[i]; - hasChanged = true; - } - if (hasChanged) clone.sharedMaterials = localMaterials; - - source.GetPropertyBlock(propertyBlock); - clone.SetPropertyBlock(propertyBlock); - - s_CopyMaterials.End(); - } - - private static void CopyBlendShapes( - SkinnedMeshRenderer source, - SkinnedMeshRenderer target, - List blendShapeWeights) - { - s_CopyBlendShapes.Begin(); - - int weightCount = blendShapeWeights.Count; - for (var i = 0; i < weightCount; i++) - { - var weight = source.GetBlendShapeWeight(i); - // ReSharper disable once CompareOfFloatsByEqualityOperator - if (weight == blendShapeWeights[i]) continue; // Halves the work - target.SetBlendShapeWeight(i, blendShapeWeights[i] = weight); - } - - s_CopyBlendShapes.End(); - } - #endregion Update Methods -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs index c6fb033..63f0d45 100644 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs @@ -1,20 +1,81 @@ -using ABI_RC.Core; -using ABI_RC.Core.Player; +using ABI_RC.Core.Player; +using MagicaCloth; +using MagicaCloth2; using UnityEngine; namespace NAK.AvatarCloneTest; public partial class AvatarClone { + #region Utilities + + private static bool IsRendererActive(Renderer renderer) + => renderer && renderer.enabled && renderer.gameObject.activeInHierarchy; + private static bool CameraRendersPlayerLocalLayer(Camera cam) - => (cam.cullingMask & (1 << CVRLayers.PlayerLocal)) != 0; + => (cam.cullingMask & (1 << LOCAL_LAYER)) != 0; private static bool CameraRendersPlayerCloneLayer(Camera cam) - => (cam.cullingMask & (1 << CVRLayers.PlayerClone)) != 0; - + => (cam.cullingMask & (1 << CLONE_LAYER)) != 0; + private static bool IsUIInternalCamera(Camera cam) +#if !UNITY_EDITOR => cam == PlayerSetup.Instance.activeUiCam; +#else + => cam.gameObject.layer == 15; +#endif - private static bool IsRendererValid(Renderer renderer) - => renderer && renderer.gameObject.activeInHierarchy; + #endregion Utilities + + #region Magica Cloth Support + + private void SetupMagicaClothSupport() + { + var magicaCloths1 = GetComponentsInChildren(true); + foreach (BaseCloth magicaCloth1 in magicaCloths1) + magicaCloth1.SetCullingMode(PhysicsTeam.TeamCullingMode.Off); + + var magicaCloths2 = base.GetComponentsInChildren(true); + foreach (MagicaCloth2.MagicaCloth magicaCloth2 in magicaCloths2) + magicaCloth2.serializeData.cullingSettings.cameraCullingMode = CullingSettings.CameraCullingMode.AnimatorLinkage; + } + + public void OnMagicaClothMeshSwapped(Renderer render, Mesh newMesh) + { + switch (render) + { + case MeshRenderer mesh: + { + int index = _meshRenderers.IndexOf(mesh); + if (index != -1) _meshCloneFilters[index].sharedMesh = newMesh; + break; + } + case SkinnedMeshRenderer skinned: + { + int index = _skinnedRenderers.IndexOf(skinned); + if (index != -1) + { + // Copy the mesh + _skinnedClones[index].sharedMesh = newMesh; + + // Copy appended bones if count is different + var cloneBones = _skinnedClones[index].bones; // alloc + var sourceBones = skinned.bones; // alloc + + int cloneBoneCount = cloneBones.Length; + int sourceBoneCount = sourceBones.Length; + if (cloneBoneCount != sourceBoneCount) + { + // Copy the new bones only + Array.Resize(ref cloneBones, sourceBoneCount); + for (int i = cloneBoneCount; i < sourceBoneCount; i++) cloneBones[i] = sourceBones[i]; + _skinnedClones[index].bones = cloneBones; + } + } + break; + } + } + } + + #endregion Magica Cloth Support } \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.cs b/AvatarCloneTest/AvatarClone/AvatarClone.cs index 88c8112..ed15ec1 100644 --- a/AvatarCloneTest/AvatarClone/AvatarClone.cs +++ b/AvatarCloneTest/AvatarClone/AvatarClone.cs @@ -1,3 +1,4 @@ +using NAK.AvatarCloneTest; using UnityEngine; using UnityEngine.Rendering; @@ -5,130 +6,142 @@ namespace NAK.AvatarCloneTest; public partial class AvatarClone : MonoBehaviour { + #region Constants + + private const int LOCAL_LAYER = 8; + private const int CLONE_LAYER = 9; + + #endregion Constants + + #region Profiler Markers + +#if ENABLE_PROFILER + private static readonly ProfilerMarker s_CopyEnabledState = new($"{nameof(AvatarClone)}.{nameof(SyncEnabledState)}"); + private static readonly ProfilerMarker s_CopyMaterials = new($"{nameof(AvatarClone)}.{nameof(CopyMaterialsAndProperties)}"); + private static readonly ProfilerMarker s_CopyBlendShapes = new($"{nameof(AvatarClone)}.{nameof(CopyBlendShapes)}"); + private static readonly ProfilerMarker s_InitializeData = new($"{nameof(AvatarClone)}.Initialize"); + private static readonly ProfilerMarker s_UpdateExclusions = new($"{nameof(AvatarClone)}.{nameof(HandleExclusionUpdate)}"); + private static readonly ProfilerMarker s_CollectExclusionData = new($"{nameof(AvatarClone)}.{nameof(CollectExclusionData)}"); + private static readonly ProfilerMarker s_HandleBoneUpdates = new($"{nameof(AvatarClone)}.{nameof(UpdateSkinnedMeshBones)}"); + private static readonly ProfilerMarker s_PreCullUpdate = new($"{nameof(AvatarClone)}.{nameof(MyOnPreCull)}"); + private static readonly ProfilerMarker s_ConfigureShadowCasting = new($"{nameof(AvatarClone)}.{nameof(ConfigureSourceShadowCasting)}"); + private static readonly ProfilerMarker s_ConfigureUICulling = new($"{nameof(AvatarClone)}.{nameof(ConfigureCloneUICulling)}"); + private static readonly ProfilerMarker s_AddRenderer = new($"{nameof(AvatarClone)}.AddRenderer"); + private static readonly ProfilerMarker s_CreateClone = new($"{nameof(AvatarClone)}.CreateClone"); +#endif + + #endregion Profiler Markers + + #region Settings + + public bool Setting_CloneMeshRenderers; + public bool Setting_CopyMaterials = true; + public bool Setting_CopyBlendShapes = true; + + #endregion Settings + + #region Source Collections - Cloned Renderers + + // Skinned mesh renderers (always cloned) + private List _skinnedRenderers; + private List> _blendShapeWeights; + + // Mesh renderers (optionally cloned) + private List _meshRenderers; + private List _meshFilters; + + #endregion Source Collections - Cloned Renderers + + #region Source Collections - Non-Cloned Renderers + + // All other renderers (never cloned) + private List _otherRenderers; + + // True if source renderer should hide. False if source renderer should show. + // Only used for non-cloned renderers (MeshRenderers and other Renderers). + private bool[] _sourceShouldBeHiddenFromFPR; + // Three states: On, ShadowsOnly, Off + private ShadowCastingMode[] _originalShadowCastingMode; + + #endregion Source Collections - Non-Cloned Renderers + + #region Clone Collections + + // Skinned mesh clones + private List _skinnedClones; + private List _skinnedCloneMaterials; + private List _skinnedCloneCullingMaterials; + + // Mesh clones (optional) + private List _meshClones; + private List _meshCloneFilters; + private List _meshCloneMaterials; + private List _meshCloneCullingMaterials; + + #endregion Clone Collections + + #region Shared Resources + + private List _materialWorkingList; // Used for GetSharedMaterials + private MaterialPropertyBlock _propertyBlock; + + #endregion Shared Resources + + #region State + + private bool _sourcesSetForShadowCasting; + private bool _clonesSetForUiCulling; + private bool[] _rendererActiveStates; + + #endregion State + #region Unity Events private void Start() { - InitializeCollections(); - InitializeRenderers(); - SetupMaterialsAndBlendShapes(); - CreateClones(); + Setting_CloneMeshRenderers = AvatarCloneTestMod.EntryCloneMeshRenderers.Value; + InitializeCollections(); + CollectRenderers(); + CreateClones(); + AddExclusionToHeadIfNeeded(); InitializeExclusions(); SetupMagicaClothSupport(); - Camera.onPreCull += MyOnPreRender; - } + // bool animatesClone = transform.Find("[ExplicitlyAnimatesVisualClones]") != null; + // Setting_CopyMaterials = !animatesClone; + // Setting_CopyBlendShapes = !animatesClone; + // Animator animator = GetComponent(); + // if (animator && animatesClone) animator.Rebind(); - private void OnDestroy() - { - Camera.onPreCull -= MyOnPreRender; - } - - private void LateUpdate() - { - // Update all renderers with basic properties (Materials & BlendShapes) - UpdateStandardRenderers(); - UpdateSkinnedRenderers(); - - // Additional pass for renderers needing extra checks (Shared Mesh & Bone Changes) - UpdateStandardRenderersWithChecks(); - UpdateSkinnedRenderersWithChecks(); + // Likely a Unity bug with where we can touch shadowCastingMode & forceRenderingOff +#if !UNITY_EDITOR + Camera.onPreCull += MyOnPreCull; +#else + Camera.onPreRender += MyOnPreCull; +#endif } - private void MyOnPreRender(Camera cam) + private void LateUpdate() { - s_MyOnPreRender.Begin(); + SyncEnabledState(); - bool isOurUiCamera = IsUIInternalCamera(cam); - bool rendersOurPlayerLayer = CameraRendersPlayerLocalLayer(cam); - bool rendersOurCloneLayer = CameraRendersPlayerCloneLayer(cam); + if (Setting_CopyMaterials && AvatarCloneTestMod.EntryCopyMaterials.Value) + SyncMaterials(); - // Renders both player layers. - // PlayerLocal will now act as a shadow caster, while PlayerClone will act as the actual head-hidden renderer. - bool rendersBothPlayerLayers = rendersOurPlayerLayer && rendersOurCloneLayer; - if (!_shadowsOnlyActive && rendersBothPlayerLayers) - { - s_SetShadowsOnly.Begin(); - - int sourceCount = _allSourceRenderers.Count; - var sourceRenderers = _allSourceRenderers; - for (int i = 0; i < sourceCount; i++) - { - Renderer renderer = sourceRenderers[i]; - if (!IsRendererValid(renderer)) continue; - - bool shouldRender = renderer.shadowCastingMode != ShadowCastingMode.Off; - _originallyWasEnabled[i] = renderer.enabled; - _originallyHadShadows[i] = shouldRender; - renderer.shadowCastingMode = ShadowCastingMode.ShadowsOnly; - if (renderer.forceRenderingOff == shouldRender) renderer.forceRenderingOff = !shouldRender; // TODO: Eval if check is needed - } - _shadowsOnlyActive = true; - - s_SetShadowsOnly.End(); - } - else if (_shadowsOnlyActive && !rendersBothPlayerLayers) - { - s_UndoShadowsOnly.Begin(); - - int sourceCount = _allSourceRenderers.Count; - var sourceRenderers = _allSourceRenderers; - for (int i = 0; i < sourceCount; i++) - { - Renderer renderer = sourceRenderers[i]; - if (!IsRendererValid(renderer)) continue; - - renderer.shadowCastingMode = _originallyHadShadows[i] ? ShadowCastingMode.On : ShadowCastingMode.Off; - if (renderer.forceRenderingOff == _originallyWasEnabled[i]) renderer.forceRenderingOff = !_originallyWasEnabled[i]; // TODO: Eval if check is needed - } - _shadowsOnlyActive = false; - - s_UndoShadowsOnly.End(); - } - - // Handle UI culling material changes - if (isOurUiCamera && !_uiCullingActive && rendersOurCloneLayer) - { - s_SetUiCulling.Begin(); - - int standardCount = _standardRenderers.Count; - var standardClones = _standardClones; - var cullingMaterials = _cullingMaterials; - for (int i = 0; i < standardCount; i++) - standardClones[i].sharedMaterials = cullingMaterials[i]; - - int skinnedCount = _skinnedRenderers.Count; - var skinnedClones = _skinnedClones; - for (int i = 0; i < skinnedCount; i++) - skinnedClones[i].sharedMaterials = cullingMaterials[i + standardCount]; - - _uiCullingActive = true; - - s_SetUiCulling.End(); - } - else if (!isOurUiCamera && _uiCullingActive) - { - s_UndoUiCulling.Begin(); - - int standardCount = _standardRenderers.Count; - var standardClones = _standardClones; - var localMaterials = _localMaterials; - for (int i = 0; i < standardCount; i++) - standardClones[i].sharedMaterials = localMaterials[i]; - - int skinnedCount = _skinnedRenderers.Count; - var skinnedClones = _skinnedClones; - for (int i = 0; i < skinnedCount; i++) - skinnedClones[i].sharedMaterials = localMaterials[i + standardCount]; - - _uiCullingActive = false; - - s_UndoUiCulling.End(); - } - - s_MyOnPreRender.End(); + if (Setting_CopyBlendShapes && AvatarCloneTestMod.EntryCopyBlendShapes.Value) + SyncBlendShapes(); } - + + private void OnDestroy() + { + // Likely a Unity bug with where we can touch shadowCastingMode & forceRenderingOff +#if !UNITY_EDITOR + Camera.onPreCull -= MyOnPreCull; +#else + Camera.onPreRender -= MyOnPreCull; +#endif + } + #endregion Unity Events } \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs b/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs index 5681761..4f38900 100644 --- a/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs +++ b/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs @@ -5,9 +5,14 @@ namespace NAK.AvatarCloneTest; public class AvatarCloneExclusion : IExclusionBehaviour { + public readonly Dictionary> skinnedToBoneIndex = new(); + public readonly List affectedTransforms = new(); + public readonly List affectedRenderers = new(); + public HashSet affectedTransformSet = new(); + private readonly AvatarClone _cloneSystem; private readonly Transform _target; - private Transform _shrinkBone; + internal Transform _shrinkBone; public bool isImmuneToGlobalState { get; set; } @@ -19,20 +24,16 @@ public class AvatarCloneExclusion : IExclusionBehaviour public void UpdateExclusions(bool isShown, bool shrinkToZero) { - Debug.Log($"[AvatarClone2] Updating exclusion for {_target.name}: isShown={isShown}, shrinkToZero={shrinkToZero}"); - if (_shrinkBone == null) { // Create shrink bone parented directly to target _shrinkBone = new GameObject($"{_target.name}_Shrink").transform; _shrinkBone.SetParent(_target, false); - Debug.Log($"[AvatarClone2] Created shrink bone for {_target.name}"); } - // Set scale based on shrink mode _shrinkBone.localScale = shrinkToZero ? Vector3.zero : Vector3.positiveInfinity; - // Let the clone system handle the update - _cloneSystem.HandleExclusionUpdate(_target, _shrinkBone, isShown); + // Replace the bone references with the shrink bone for the indicies we modify + _cloneSystem.HandleExclusionUpdate(this, isShown); } } \ No newline at end of file diff --git a/AvatarCloneTest/Main.cs b/AvatarCloneTest/Main.cs index 21a34bf..3bb4f09 100644 --- a/AvatarCloneTest/Main.cs +++ b/AvatarCloneTest/Main.cs @@ -1,4 +1,6 @@ using ABI_RC.Core; +using ABI_RC.Core.EventSystem; +using ABI_RC.Core.Savior; using MelonLoader; using UnityEngine; @@ -15,17 +17,17 @@ public class AvatarCloneTestMod : MelonMod Category.CreateEntry("use_avatar_clone_test", true, "Use Avatar Clone", description: "Uses the Avatar Clone setup for the local avatar."); - // internal static readonly MelonPreferences_Entry EntryCopyBlendShapes = - // Category.CreateEntry("copy_blend_shapes", true, - // "Copy Blend Shapes", description: "Copies the blend shapes from the original avatar to the clone."); - // - // internal static readonly MelonPreferences_Entry EntryCopyMaterials = - // Category.CreateEntry("copy_materials", true, - // "Copy Materials", description: "Copies the materials from the original avatar to the clone."); - // - // internal static readonly MelonPreferences_Entry EntryCopyMeshes = - // Category.CreateEntry("copy_meshes", true, - // "Copy Meshes", description: "Copies the meshes from the original avatar to the clone."); + internal static readonly MelonPreferences_Entry EntryCloneMeshRenderers = + Category.CreateEntry("clone_mesh_renderers", false, + "Clone Mesh Renderers", description: "Clones the mesh renderers from the original avatar to the clone."); + + internal static readonly MelonPreferences_Entry EntryCopyBlendShapes = + Category.CreateEntry("copy_blend_shapes", true, + "Copy Blend Shapes", description: "Copies the blend shapes from the original avatar to the clone."); + + internal static readonly MelonPreferences_Entry EntryCopyMaterials = + Category.CreateEntry("copy_materials", true, + "Copy Materials", description: "Copies the materials from the original avatar to the clone."); #endregion Melon Preferences @@ -49,6 +51,13 @@ public class AvatarCloneTestMod : MelonMod } } } + + // if pressing ctrl + r, reload avatar + if (Input.GetKey(KeyCode.LeftControl) && Input.GetKeyDown(KeyCode.R)) + { + var player = MetaPort.Instance.currentAvatarGuid; + AssetManagement.Instance.LoadLocalAvatar(player); + } } #endregion Melon Events diff --git a/AvatarCloneTest/Patches.cs b/AvatarCloneTest/Patches.cs index b4cec17..ecd64c5 100644 --- a/AvatarCloneTest/Patches.cs +++ b/AvatarCloneTest/Patches.cs @@ -18,70 +18,5 @@ public static class Patches avatar.AddComponent(); return false; } - - // [HarmonyPostfix] - // [HarmonyPatch(typeof(FPRExclusion), nameof(FPRExclusion.UpdateExclusions))] - // private static void OnUpdateExclusions(ref FPRExclusion __instance) - // { - // AvatarClone clone = PlayerSetup.Instance._avatar.GetComponent(); - // if (clone == null) return; - // clone.SetBoneChainVisibility(__instance.target, !__instance.isShown, !__instance.shrinkToZero); - // } - - [HarmonyPostfix] - [HarmonyPatch(typeof(CVRMirror), nameof(CVRMirror.Start))] - private static void OnMirrorStart(CVRMirror __instance) - { - if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) - return; - - // Don't reflect the player clone layer - __instance.m_ReflectLayers &= ~(1 << CVRLayers.PlayerClone); - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(PlayerSetup), nameof(PlayerSetup.Update))] - private static void OnTransformHiderManagerUpdate(PlayerSetup __instance) - { - if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) - return; - - if (MetaPort.Instance.settings.GetSettingsBool("ExperimentalAvatarOverrenderUI")) - __instance.activeUiCam.cullingMask |= 1 << CVRLayers.PlayerClone; - else - __instance.activeUiCam.cullingMask &= ~(1 << CVRLayers.PlayerClone); - } - - private static bool _wasDebugInPortableCamera; - - [HarmonyPostfix] - [HarmonyPatch(typeof(PortableCamera), nameof(PortableCamera.Update))] - private static void OnPortableCameraUpdate(ref PortableCamera __instance) - { - if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) - { - // Show both PlayerLocal and PlayerClone - __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerLocal; - __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerClone; - return; - } - - if (TransformHiderManager.s_DebugInPortableCamera == _wasDebugInPortableCamera) - return; - - if (TransformHiderManager.s_DebugInPortableCamera) - { - // Hide PlayerLocal, show PlayerClone - __instance.cameraComponent.cullingMask &= ~(1 << CVRLayers.PlayerLocal); - __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerClone; - } - else - { - // Show PlayerLocal, hide PlayerClone - __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerLocal; - __instance.cameraComponent.cullingMask &= ~(1 << CVRLayers.PlayerClone); - } - - _wasDebugInPortableCamera = TransformHiderManager.s_DebugInPortableCamera; - } -} \ No newline at end of file +} + \ No newline at end of file diff --git a/AvatarCloneTest/Properties/AssemblyInfo.cs b/AvatarCloneTest/Properties/AssemblyInfo.cs index 3334b28..84f8de2 100644 --- a/AvatarCloneTest/Properties/AssemblyInfo.cs +++ b/AvatarCloneTest/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.AvatarCloneTest.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs b/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs deleted file mode 100644 index 473dc45..0000000 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Reflection; -using BTKUILib; -using BTKUILib.UIObjects; -using BTKUILib.UIObjects.Components; -using MelonLoader; -using UnityEngine; - -namespace NAK.AvatarScaleMod.Integrations -{ - public static partial class BtkUiAddon - { - #region Melon Preference Helpers - - private static ToggleButton AddMelonToggle(ref Category category, MelonPreferences_Entry entry) - { - ToggleButton toggle = category.AddToggle(entry.DisplayName, entry.Description, entry.Value); - toggle.OnValueUpdated += b => entry.Value = b; - return toggle; - } - - private static SliderFloat AddMelonSlider(ref Category category, MelonPreferences_Entry entry, float min, - float max, int decimalPlaces = 2, bool allowReset = true) - { - SliderFloat slider = category.AddSlider(entry.DisplayName, entry.Description, - Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset); - slider.OnValueUpdated += f => entry.Value = f; - return slider; - } - - private static Button AddMelonStringInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) - { - Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); - button.OnPress += () => QuickMenuAPI.OpenKeyboard(entry.Value, s => entry.Value = s); - return button; - } - - private static Button AddMelonNumberInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) - { - Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); - button.OnPress += () => QuickMenuAPI.OpenNumberInput(entry.DisplayName, entry.Value, f => entry.Value = f); - return button; - } - - // private static SliderFloat AddMelonSlider(ref Page page, MelonPreferences_Entry entry, float min, float max, int decimalPlaces = 2, bool allowReset = true) - // { - // SliderFloat slider = page.AddSlider(entry.DisplayName, entry.Description, Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset); - // slider.OnValueUpdated += f => entry.Value = f; - // return slider; - // } - - /// - /// Helper method to create a category that saves its collapsed state to a MelonPreferences entry. - /// - /// - /// - /// - /// - private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry entry, bool showHeader = true) - { - Category category = page.AddCategory(entry.DisplayName, showHeader, true, entry.Value); - category.OnCollapse += b => entry.Value = b; - return category; - } - - #endregion - - #region Icon Utils - - private static Stream GetIconStream(string iconName) - { - Assembly assembly = Assembly.GetExecutingAssembly(); - string assemblyName = assembly.GetName().Name; - return assembly.GetManifestResourceStream($"{assemblyName}.resources.{iconName}"); - } - - #endregion - } -} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading.csproj b/BetterContentLoading/BetterContentLoading.csproj new file mode 100644 index 0000000..67cef19 --- /dev/null +++ b/BetterContentLoading/BetterContentLoading.csproj @@ -0,0 +1,15 @@ + + + + net48 + NAK.BetterContentLoading + + + + ..\.ManagedLibs\BTKUILib.dll + + + ..\.ManagedLibs\TheClapper.dll + + + diff --git a/BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs b/BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs new file mode 100644 index 0000000..749483f --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs @@ -0,0 +1,210 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Networking.IO.Instancing; +using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core.Util; +using ABI_RC.Systems.GameEventSystem; +using NAK.BetterContentLoading.Queue; +using UnityEngine; + +namespace NAK.BetterContentLoading; + +// Download world -> connect to instance -> receive all Avatar data +// -> initial connection to instance -> receive all props data + +// We receive Prop download data only after we have connected to the instance. Avatar data we seem to receive +// prior to our initial connection event firing. + +public class BetterDownloadManager +{ + #region Singleton + + private static BetterDownloadManager _instance; + public static BetterDownloadManager Instance => _instance ??= new BetterDownloadManager(); + + #endregion Singleton + + #region Constructor + + private BetterDownloadManager() + { + _downloadProcessor = new DownloadProcessor(); + + _worldQueue = new WorldDownloadQueue(this); // Only one world at a time + _avatarQueue = new AvatarDownloadQueue(this); // Up to 3 avatars at once + _propQueue = new PropDownloadQueue(this); // Up to 2 props at once + + // Set to 100MBs by default + MaxDownloadBandwidth = 100 * 1024 * 1024; + + CVRGameEventSystem.Instance.OnConnected.AddListener(_ => + { + if (!Instances.IsReconnecting) OnInitialConnectionToInstance(); + }); + } + + #endregion Constructor + + #region Settings + + /// Log debug messages + public bool IsDebugEnabled { get; set; } = true; + + /// Prioritize friends first in download queue + public bool PrioritizeFriends { get; set; } = true; + + /// Prioritize content closest to player first in download queue + public bool PrioritizeDistance { get; set; } = true; + public float PriorityDownloadDistance { get; set; } = 25f; + + public int MaxDownloadBandwidth + { + get => _downloadProcessor.MaxDownloadBandwidth; + set => _downloadProcessor.MaxDownloadBandwidth = value; + } + + #endregion Settings + + private readonly DownloadProcessor _downloadProcessor; + + private readonly AvatarDownloadQueue _avatarQueue; + private readonly PropDownloadQueue _propQueue; + private readonly WorldDownloadQueue _worldQueue; + + #region Game Events + + private void OnInitialConnectionToInstance() + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg("Initial connection established."); + // await few seconds before chewing through the download queue, to allow for download priorities to be set + // once we have received most of the data from the server + } + + #endregion Game Events + + #region Public Queue Methods + + public void QueueAvatarDownload( + in DownloadInfo info, + string playerId, + CVRLoadingAvatarController loadingController) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing Avatar Download:\n{info.GetLogString()}\n" + + $"PlayerId: {playerId}\n" + + $"LoadingController: {loadingController}"); + } + + _avatarQueue.QueueDownload(in info, playerId); + } + + /// + /// Queues a prop download. + /// + /// The download info. + /// The instance ID for the prop. + /// The user who spawned the prop. + public void QueuePropDownload( + in DownloadInfo info, + string instanceId, + string spawnerId) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing Prop Download:\n{info.GetLogString()}\n" + + $"InstanceId: {instanceId}\n" + + $"SpawnerId: {spawnerId}"); + } + + _propQueue.QueueDownload(in info, instanceId, spawnerId); + } + + /// + /// Queues a world download. + /// + /// Download info. + /// Whether to load into this world once downloaded. + /// Whether the home world is requested. + public void QueueWorldDownload( + in DownloadInfo info, + bool joinOnComplete, + bool isHomeRequested) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing World Download:\n{info.GetLogString()}\n" + + $"JoinOnComplete: {joinOnComplete}\n" + + $"IsHomeRequested: {isHomeRequested}"); + } + + _worldQueue.QueueDownload(in info, joinOnComplete, isHomeRequested); + } + + #endregion Public Queue Methods + + #region Internal Methods + + internal Task ProcessDownload(DownloadInfo info, Action progressCallback = null) + { + return _downloadProcessor.ProcessDownload(info); + } + + #endregion Internal Methods + + #region Private Helper Methods + + internal static bool TryGetPlayerEntity(string playerId, out CVRPlayerEntity playerEntity) + { + CVRPlayerEntity player = CVRPlayerManager.Instance.NetworkPlayers.Find(p => p.Uuid == playerId); + if (player == null) + { + // BetterContentLoadingMod.Logger.Error($"Player entity not found for ID: {playerId}"); + playerEntity = null; + return false; + } + playerEntity = player; + return true; + } + + internal static bool TryGetPropData(string instanceId, out CVRSyncHelper.PropData propData) + { + CVRSyncHelper.PropData prop = CVRSyncHelper.Props.Find(p => p.InstanceId == instanceId); + if (prop == null) + { + // BetterContentLoadingMod.Logger.Error($"Prop data not found for ID: {instanceId}"); + propData = null; + return false; + } + propData = prop; + return true; + } + + internal static bool IsPlayerLocal(string playerId) + { + return playerId == MetaPort.Instance.ownerId; + } + + internal static bool IsPlayerFriend(string playerId) + { + return Friends.FriendsWith(playerId); + } + + internal bool IsPlayerWithinPriorityDistance(CVRPlayerEntity player) + { + if (player.PuppetMaster == null) return false; + return player.PuppetMaster.animatorManager.DistanceTo < PriorityDownloadDistance; + } + + internal bool IsPropWithinPriorityDistance(CVRSyncHelper.PropData prop) + { + Vector3 propPosition = new(prop.PositionX, prop.PositionY, prop.PositionZ); + return Vector3.Distance(propPosition, PlayerSetup.Instance.GetPlayerPosition()) < PriorityDownloadDistance; + } + + #endregion Private Helper Methods +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadInfo.cs b/BetterContentLoading/BetterContentLoading/DownloadInfo.cs new file mode 100644 index 0000000..038f6bf --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadInfo.cs @@ -0,0 +1,63 @@ +using System.Security.Cryptography; +using System.Text; +using ABI_RC.Core.Networking.API.Responses; + +namespace NAK.BetterContentLoading; + +public readonly struct DownloadInfo +{ + public readonly string AssetId; + public readonly string AssetUrl; + public readonly string FileId; + public readonly long FileSize; + public readonly string FileKey; + public readonly string FileHash; + public readonly int CompatibilityVersion; + public readonly int EncryptionAlgorithm; + public readonly UgcTagsData TagsData; + + public readonly string DownloadId; + + public DownloadInfo( + string assetId, string assetUrl, string fileId, + long fileSize, string fileKey, string fileHash, + int compatibilityVersion, int encryptionAlgorithm, + UgcTagsData tagsData) + { + AssetId = assetId + "meow"; + AssetUrl = assetUrl; + FileId = fileId; + FileSize = fileSize; + FileKey = fileKey; + FileHash = fileHash; + CompatibilityVersion = compatibilityVersion; + EncryptionAlgorithm = encryptionAlgorithm; + TagsData = tagsData; + + using SHA256 sha = SHA256.Create(); + StringBuilder sb = new(); + sb.Append(assetId) + .Append('|').Append(assetUrl) + .Append('|').Append(fileId) + .Append('|').Append(fileSize) + .Append('|').Append(fileKey) + .Append('|').Append(fileHash) + .Append('|').Append(compatibilityVersion) + .Append('|').Append(encryptionAlgorithm); + + var bytes = Encoding.UTF8.GetBytes(sb.ToString()); + var hash = sha.ComputeHash(bytes); + DownloadId = Convert.ToBase64String(hash); + } + + public string GetLogString() => + $"AssetId: {AssetId}\n" + + $"DownloadId: {DownloadId}\n" + + $"AssetUrl: {AssetUrl}\n" + + $"FileId: {FileId}\n" + + $"FileSize: {FileSize}\n" + + $"FileKey: {FileKey}\n" + + $"FileHash: {FileHash}\n" + + $"CompatibilityVersion: {CompatibilityVersion}\n" + + $"EncryptionAlgorithm: {EncryptionAlgorithm}"; +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadProcessor.cs b/BetterContentLoading/BetterContentLoading/DownloadProcessor.cs new file mode 100644 index 0000000..e77acdc --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadProcessor.cs @@ -0,0 +1,152 @@ +using System.Net.Http; +using ABI_RC.Core; +using ABI_RC.Core.IO.AssetManagement; + +namespace NAK.BetterContentLoading; + +public class DownloadProcessor +{ + private readonly HttpClient _client = new(); + private readonly SemaphoreSlim _bandwidthSemaphore = new(1); + private long _bytesReadLastSecond; + + private int _maxDownloadBandwidth = 10 * 1024 * 1024; // Default 10MB/s + private const int MinBufferSize = 16384; // 16KB min buffer + private const long ThrottleThreshold = 25 * 1024 * 1024; // 25MB threshold for throttling + private const long KnownSizeDifference = 1000; // API reported size is 1000 bytes larger than actual content + + public int MaxDownloadBandwidth + { + get => _maxDownloadBandwidth; + set => _maxDownloadBandwidth = Math.Max(1024 * 1024, value); + } + + private int ActiveDownloads { get; set; } + private int CurrentBandwidthPerDownload => MaxDownloadBandwidth / Math.Max(1, ActiveDownloads); + + public int GetProgress(string downloadId) => _downloadProgress.GetValueOrDefault(downloadId, 0); + private readonly Dictionary _downloadProgress = new(); + + public async Task ProcessDownload(DownloadInfo downloadInfo) + { + try + { + if (await CacheManager.Instance.IsCachedFileUpToDate( + downloadInfo.AssetId, + downloadInfo.FileId, + downloadInfo.FileHash)) + return true; + + var filePath = CacheManager.Instance.GetCachePath(downloadInfo.AssetId, downloadInfo.FileId); + if (!CVRTools.HasEnoughDiskSpace(filePath, downloadInfo.FileSize)) + { + BetterContentLoadingMod.Logger.Error($"Not enough disk space to download {downloadInfo.AssetId}"); + return false; + } + + CacheManager.Instance.EnsureCacheDirectoryExists(downloadInfo.AssetId); + + bool success = false; + Exception lastException = null; + + for (int attempt = 0; attempt <= 1; attempt++) + { + try + { + if (attempt > 0) + await Task.Delay(1000); + + success = await DownloadWithBandwidthLimit(downloadInfo, filePath); + if (success) break; + } + catch (Exception ex) + { + lastException = ex; + } + } + + if (!success && lastException != null) + BetterContentLoadingMod.Logger.Error($"Failed to download {downloadInfo.AssetId}: {lastException}"); + + _downloadProgress.Remove(downloadInfo.DownloadId); + return success; + } + catch (Exception ex) + { + BetterContentLoadingMod.Logger.Error($"Error processing download for {downloadInfo.AssetId}: {ex}"); + _downloadProgress.Remove(downloadInfo.DownloadId); + return false; + } + } + + private async Task DownloadWithBandwidthLimit(DownloadInfo downloadInfo, string filePath) + { + await _bandwidthSemaphore.WaitAsync(); + try { ActiveDownloads++; } + finally { _bandwidthSemaphore.Release(); } + + string tempFilePath = filePath + ".download"; + try + { + using var response = await _client.GetAsync(downloadInfo.AssetUrl, HttpCompletionOption.ResponseHeadersRead); + if (!response.IsSuccessStatusCode) + return false; + + var expectedContentSize = downloadInfo.FileSize - KnownSizeDifference; + using var stream = await response.Content.ReadAsStreamAsync(); + using var fileStream = File.Open(tempFilePath, FileMode.Create); + + var isEligibleForThrottle = downloadInfo.FileSize >= ThrottleThreshold; + var totalBytesRead = 0L; + byte[] buffer = null; + + while (true) + { + var lengthToRead = isEligibleForThrottle ? MinBufferSize : CurrentBandwidthPerDownload; + if (buffer == null || lengthToRead != buffer.Length) + buffer = new byte[lengthToRead]; + + var bytesRead = await stream.ReadAsync(buffer, 0, lengthToRead); + if (bytesRead == 0) break; + + if (isEligibleForThrottle) + Interlocked.Add(ref _bytesReadLastSecond, bytesRead); + + fileStream.Write(buffer, 0, bytesRead); + totalBytesRead += bytesRead; + + var progress = (int)(((float)totalBytesRead / expectedContentSize) * 100f); + _downloadProgress[downloadInfo.DownloadId] = Math.Clamp(progress, 0, 100); + } + + fileStream.Flush(); + + var fileInfo = new FileInfo(tempFilePath); + if (fileInfo.Length != expectedContentSize) + return false; + + if (File.Exists(filePath)) + File.Delete(filePath); + File.Move(tempFilePath, filePath); + + CacheManager.Instance.QueuePrune(); + return true; + } + finally + { + await _bandwidthSemaphore.WaitAsync(); + try { ActiveDownloads--; } + finally { _bandwidthSemaphore.Release(); } + + try + { + if (File.Exists(tempFilePath)) + File.Delete(tempFilePath); + } + catch + { + // Ignore cleanup errors + } + } + } +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs new file mode 100644 index 0000000..60060c5 --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs @@ -0,0 +1,83 @@ +namespace NAK.BetterContentLoading.Queue; + +public class AvatarDownloadQueue : ContentDownloadQueueBase +{ + public AvatarDownloadQueue(BetterDownloadManager manager) : base(manager, 3) { } + + public void QueueDownload(in DownloadInfo info, string playerId, Action onComplete = null) + { + float priority = CalculateAvatarPriority(in info, playerId); + QueueDownload(in info, playerId, priority, onComplete); + } + + protected override async Task ProcessDownload(DownloadInfo info) + { + await base.ProcessDownload(info); + } + + protected override void OnDownloadProgress(string downloadId, float progress) + { + if (DownloadOwners.TryGetValue(downloadId, out var owners)) + { + foreach (var playerId in owners) + { + if (BetterDownloadManager.IsPlayerLocal(playerId)) + { + // Update loading progress on local player + BetterContentLoadingMod.Logger.Msg($"Progress for local player ({playerId}): {progress:P}"); + continue; + } + if (BetterDownloadManager.TryGetPlayerEntity(playerId, out var player)) + { + // Update loading progress on avatar controller if needed + BetterContentLoadingMod.Logger.Msg($"Progress for {player.Username} ({playerId}): {progress:P}"); + } + } + } + } + + protected override float RecalculatePriority(string downloadId) + { + if (!DownloadOwners.TryGetValue(downloadId, out var owners)) + return float.MaxValue; + + float lowestPriority = float.MaxValue; + DownloadInfo? downloadInfo = null; + + // Find the queue item to get the DownloadInfo + var queueItem = Queue.Find(x => x.Info.DownloadId == downloadId); + if (queueItem.Info.AssetId != null) + downloadInfo = queueItem.Info; + + if (downloadInfo == null) + return lowestPriority; + + // Calculate priority for each owner and use the lowest (highest priority) value + foreach (var playerId in owners) + { + var priority = CalculateAvatarPriority(downloadInfo.Value, playerId); + lowestPriority = Math.Min(lowestPriority, priority); + } + + return lowestPriority; + } + + private float CalculateAvatarPriority(in DownloadInfo info, string playerId) + { + float priority = info.FileSize; + + if (BetterDownloadManager.IsPlayerLocal(playerId)) + return 0f; + + if (!BetterDownloadManager.TryGetPlayerEntity(playerId, out var player)) + return priority; + + if (Manager.PrioritizeFriends && BetterDownloadManager.IsPlayerFriend(playerId)) + priority *= 0.5f; + + if (Manager.PrioritizeDistance && Manager.IsPlayerWithinPriorityDistance(player)) + priority *= 0.75f; + + return priority; + } +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs new file mode 100644 index 0000000..66e366b --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs @@ -0,0 +1,177 @@ +namespace NAK.BetterContentLoading.Queue; + +public abstract class ContentDownloadQueueBase +{ + protected readonly struct QueueItem + { + public readonly DownloadInfo Info; + public readonly float Priority; + public readonly Action OnComplete; // Callback with (downloadId, ownerId) + + public QueueItem(DownloadInfo info, float priority, Action onComplete) + { + Info = info; + Priority = priority; + OnComplete = onComplete; + } + } + + protected readonly List Queue = new(); + private readonly HashSet ActiveDownloads = new(); // By DownloadId + protected readonly Dictionary> DownloadOwners = new(); // DownloadId -> Set of OwnerIds + private readonly SemaphoreSlim DownloadSemaphore; + protected readonly BetterDownloadManager Manager; + + protected ContentDownloadQueueBase(BetterDownloadManager manager, int maxParallelDownloads) + { + Manager = manager; + DownloadSemaphore = new SemaphoreSlim(maxParallelDownloads); + } + + protected void QueueDownload(in DownloadInfo info, string ownerId, float priority, Action onComplete) + { + if (Manager.IsDebugEnabled) + BetterContentLoadingMod.Logger.Msg($"Attempting to queue download for {info.AssetId} (DownloadId: {info.DownloadId})"); + + // Add to owners tracking + if (!DownloadOwners.TryGetValue(info.DownloadId, out var owners)) + { + owners = new HashSet(); + DownloadOwners[info.DownloadId] = owners; + } + owners.Add(ownerId); + + // If already downloading, just add the owner and callback + if (ActiveDownloads.Contains(info.DownloadId)) + { + if (Manager.IsDebugEnabled) + BetterContentLoadingMod.Logger.Msg($"Already downloading {info.DownloadId}, added owner {ownerId}"); + return; + } + + DownloadInfo downloadInfo = info; + var existingIndex = Queue.FindIndex(x => x.Info.DownloadId == downloadInfo.DownloadId); + if (existingIndex >= 0) + { + // Update priority if needed based on new owner + var newPriority = RecalculatePriority(info.DownloadId); + Queue[existingIndex] = new QueueItem(info, newPriority, onComplete); + SortQueue(); + return; + } + + Queue.Add(new QueueItem(info, priority, onComplete)); + SortQueue(); + TryStartNextDownload(); + } + + public void RemoveOwner(string downloadId, string ownerId) + { + if (!DownloadOwners.TryGetValue(downloadId, out var owners)) + return; + + owners.Remove(ownerId); + + if (owners.Count == 0) + { + // No more owners, cancel the download + DownloadOwners.Remove(downloadId); + CancelDownload(downloadId); + } + else if (!ActiveDownloads.Contains(downloadId)) + { + // Still has owners and is queued, recalculate priority + var existingIndex = Queue.FindIndex(x => x.Info.DownloadId == downloadId); + if (existingIndex >= 0) + { + var item = Queue[existingIndex]; + var newPriority = RecalculatePriority(downloadId); + Queue[existingIndex] = new QueueItem(item.Info, newPriority, item.OnComplete); + SortQueue(); + } + } + } + + protected virtual async void TryStartNextDownload() + { + try + { + if (Queue.Count == 0) return; + + await DownloadSemaphore.WaitAsync(); + + if (Queue.Count > 0) + { + var item = Queue[0]; + Queue.RemoveAt(0); + + // Double check we still have owners before starting download + if (!DownloadOwners.TryGetValue(item.Info.DownloadId, out var owners) || owners.Count == 0) + { + DownloadSemaphore.Release(); + TryStartNextDownload(); + return; + } + + ActiveDownloads.Add(item.Info.DownloadId); + + try + { + await ProcessDownload(item.Info); + BetterContentLoadingMod.Logger.Msg($"Download completed for {item.Info.DownloadId}"); + + // Notify all owners of completion + if (DownloadOwners.TryGetValue(item.Info.DownloadId, out owners)) + { + foreach (var owner in owners) + { + item.OnComplete?.Invoke(item.Info.DownloadId, owner); + } + } + } + catch (Exception ex) + { + if (Manager.IsDebugEnabled) + BetterContentLoadingMod.Logger.Error($"Download failed for {item.Info.DownloadId}: {ex}"); + } + finally + { + ActiveDownloads.Remove(item.Info.DownloadId); + DownloadSemaphore.Release(); + TryStartNextDownload(); + } + } + else + { + DownloadSemaphore.Release(); + } + } + catch (Exception e) + { + BetterContentLoadingMod.Logger.Error($"Error in TryStartNextDownload: {e}"); + } + } + + protected virtual async Task ProcessDownload(DownloadInfo info) + { + bool success = await Manager.ProcessDownload(info); + + if (!success) + throw new Exception($"Failed to download {info.AssetId}"); + } + + protected abstract void OnDownloadProgress(string downloadId, float progress); + + protected abstract float RecalculatePriority(string downloadId); + + protected virtual void SortQueue() + { + Queue.Sort((a, b) => a.Priority.CompareTo(b.Priority)); + } + + protected virtual void CancelDownload(string downloadId) + { + Queue.RemoveAll(x => x.Info.DownloadId == downloadId); + if (ActiveDownloads.Remove(downloadId)) DownloadSemaphore.Release(); + } +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs new file mode 100644 index 0000000..f100e0b --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs @@ -0,0 +1,81 @@ +using ABI_RC.Core.Util; + +namespace NAK.BetterContentLoading.Queue; + +public class PropDownloadQueue : ContentDownloadQueueBase +{ + private readonly Dictionary _ownerToSpawner = new(); // InstanceId -> SpawnerId + + public PropDownloadQueue(BetterDownloadManager manager) : base(manager, 2) { } + + public void QueueDownload(in DownloadInfo info, string instanceId, string spawnerId, Action onComplete = null) + { + _ownerToSpawner[instanceId] = spawnerId; + float priority = CalculatePropPriority(in info, instanceId, spawnerId); + QueueDownload(in info, instanceId, priority, onComplete); + } + + protected override async Task ProcessDownload(DownloadInfo info) + { + await base.ProcessDownload(info); + } + + protected override void OnDownloadProgress(string downloadId, float progress) + { + if (DownloadOwners.TryGetValue(downloadId, out var owners)) + { + foreach (var instanceId in owners) + { + if (BetterDownloadManager.TryGetPropData(instanceId, out CVRSyncHelper.PropData prop)) + { + BetterContentLoadingMod.Logger.Msg($"Progress for {prop.InstanceId}: {progress:P}"); + } + } + } + } + + protected override float RecalculatePriority(string downloadId) + { + if (!DownloadOwners.TryGetValue(downloadId, out var owners)) + return float.MaxValue; + + float lowestPriority = float.MaxValue; + DownloadInfo? downloadInfo = null; + + // Find the queue item to get the DownloadInfo + var queueItem = Queue.Find(x => x.Info.DownloadId == downloadId); + if (queueItem.Info.AssetId != null) + downloadInfo = queueItem.Info; + + if (downloadInfo == null) + return lowestPriority; + + // Calculate priority for each owner and use the lowest (highest priority) value + foreach (var instanceId in owners) + { + if (_ownerToSpawner.TryGetValue(instanceId, out var spawnerId)) + { + var priority = CalculatePropPriority(downloadInfo.Value, instanceId, spawnerId); + lowestPriority = Math.Min(lowestPriority, priority); + } + } + + return lowestPriority; + } + + private float CalculatePropPriority(in DownloadInfo info, string instanceId, string spawnerId) + { + float priority = info.FileSize; + + if (!BetterDownloadManager.TryGetPropData(instanceId, out var prop)) + return priority; + + if (Manager.PrioritizeFriends && BetterDownloadManager.IsPlayerFriend(spawnerId)) + priority *= 0.5f; + + if (Manager.PrioritizeDistance && Manager.IsPropWithinPriorityDistance(prop)) + priority *= 0.75f; + + return priority; + } +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs new file mode 100644 index 0000000..1cea689 --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs @@ -0,0 +1,66 @@ +namespace NAK.BetterContentLoading.Queue; + +public class WorldDownloadQueue : ContentDownloadQueueBase +{ + private readonly Queue<(DownloadInfo Info, bool JoinOnComplete, bool IsHomeRequest)> _backgroundQueue = new(); + private bool _isProcessingPriorityDownload; + + public WorldDownloadQueue(BetterDownloadManager manager) : base(manager, 1) { } + + public void QueueDownload(in DownloadInfo info, bool joinOnComplete, bool isHomeRequest, Action onComplete = null) + { + if (joinOnComplete || isHomeRequest) + { + // Priority download - clear queue and download immediately + Queue.Clear(); + _isProcessingPriorityDownload = true; + QueueDownload(in info, info.DownloadId, 0f, onComplete); + } + else + { + // Background download - add to background queue + _backgroundQueue.Enqueue((info, false, false)); + if (!_isProcessingPriorityDownload) + ProcessBackgroundQueue(); + } + } + + protected override async Task ProcessDownload(DownloadInfo info) + { + await base.ProcessDownload(info); + + if (_isProcessingPriorityDownload) + { + _isProcessingPriorityDownload = false; + ProcessBackgroundQueue(); + } + } + + protected override void OnDownloadProgress(string downloadId, float progress) + { + BetterContentLoadingMod.Logger.Msg($"World download progress: {progress:P}"); + } + + protected override float RecalculatePriority(string downloadId) + { + // For worlds, priority is based on whether it's a priority download and file size + var queueItem = Queue.Find(x => x.Info.DownloadId == downloadId); + return queueItem.Priority; + } + + private void ProcessBackgroundQueue() + { + while (_backgroundQueue.Count > 0) + { + (DownloadInfo info, var join, var home) = _backgroundQueue.Dequeue(); + QueueDownload(in info, info.DownloadId, info.FileSize, null); + } + } + + protected override void CancelDownload(string downloadId) + { + base.CancelDownload(downloadId); + _backgroundQueue.Clear(); + _isProcessingPriorityDownload = false; + } +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadState.cs b/BetterContentLoading/BetterContentLoading/DownloadState.cs new file mode 100644 index 0000000..785396b --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadState.cs @@ -0,0 +1,26 @@ +namespace NAK.BetterContentLoading; + +public readonly struct DownloadState +{ + public readonly string DownloadId; + public readonly long BytesRead; + public readonly long TotalBytes; + public readonly int ProgressPercent; + public readonly float BytesPerSecond; + + public DownloadState(string downloadId, long bytesRead, long totalBytes, float bytesPerSecond) + { + DownloadId = downloadId; + BytesRead = bytesRead; + TotalBytes = totalBytes; + BytesPerSecond = bytesPerSecond; + ProgressPercent = (int)(((float)bytesRead / totalBytes) * 100f); + } +} + +public interface IDownloadMonitor +{ + void OnDownloadProgress(DownloadState state); + void OnDownloadStarted(string downloadId); + void OnDownloadCompleted(string downloadId, bool success); +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs b/BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs new file mode 100644 index 0000000..280aeb2 --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs @@ -0,0 +1,109 @@ +using JetBrains.Annotations; +using UnityEngine; + +namespace NAK.BetterContentLoading.Util; + +[PublicAPI] +public static class ThreadingHelper +{ + private static readonly SynchronizationContext _mainThreadContext; + + static ThreadingHelper() + { + _mainThreadContext = SynchronizationContext.Current; + } + + public static bool IsMainThread => SynchronizationContext.Current == _mainThreadContext; + + /// + /// Runs an action on the main thread. Optionally waits for its completion. + /// + public static void RunOnMainThread(Action action, bool waitForCompletion = true, Action onError = null) + { + if (SynchronizationContext.Current == _mainThreadContext) + { + // Already on the main thread + TryExecute(action, onError); + } + else + { + if (waitForCompletion) + { + ManualResetEvent done = new(false); + _mainThreadContext.Post(_ => + { + TryExecute(action, onError); + done.Set(); + }, null); + done.WaitOne(50000); // Block until action is completed + } + else + { + // Fire and forget (don't wait for the action to complete) + _mainThreadContext.Post(_ => TryExecute(action, onError), null); + } + } + } + + /// + /// Runs an action asynchronously on the main thread and returns a Task. + /// + public static Task RunOnMainThreadAsync(Action action, Action onError = null) + { + if (SynchronizationContext.Current == _mainThreadContext) + { + // Already on the main thread + TryExecute(action, onError); + return Task.CompletedTask; + } + + var tcs = new TaskCompletionSource(); + _mainThreadContext.Post(_ => + { + try + { + TryExecute(action, onError); + tcs.SetResult(true); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, null); + return tcs.Task; + } + + /// + /// Runs a task on a background thread with cancellation support. + /// + public static async Task RunOffMainThreadAsync(Action action, CancellationToken cancellationToken, Action onError = null) + { + try + { + await Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + TryExecute(action, onError); + }, cancellationToken); + } + catch (OperationCanceledException) + { + Debug.LogWarning("Task was canceled."); + } + } + + /// + /// Helper method for error handling. + /// + private static void TryExecute(Action action, Action onError) + { + try + { + action(); + } + catch (Exception ex) + { + onError?.Invoke(ex); + } + } +} diff --git a/BetterContentLoading/DownloadManager/DownloadManager.Core.cs b/BetterContentLoading/DownloadManager/DownloadManager.Core.cs new file mode 100644 index 0000000..ce484cd --- /dev/null +++ b/BetterContentLoading/DownloadManager/DownloadManager.Core.cs @@ -0,0 +1,237 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Networking.API.Responses; +using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Savior; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager +{ + #region Singleton + private static DownloadManager _instance; + public static DownloadManager Instance => _instance ??= new DownloadManager(); + #endregion + + private DownloadManager() + { + + } + + #region Settings + public bool IsDebugEnabled { get; set; } = true; + public bool PrioritizeFriends { get; set; } = true; + public bool PrioritizeDistance { get; set; } = true; + public float PriorityDownloadDistance { get; set; } = 25f; + public int MaxConcurrentDownloads { get; set; } = 3; + public int MaxDownloadBandwidth { get; set; } = 100 * 1024 * 1024; // 100MB default + private const int THROTTLE_THRESHOLD = 25 * 1024 * 1024; // 25MB threshold for throttling + + public long MaxAvatarDownloadSize { get; set; } = 25 * 1024 * 1024; // 25MB default + public long MaxPropDownloadSize { get; set; } = 25 * 1024 * 1024; // 25MB default + + #endregion Settings + + #region State + + // priority -> downloadtask + private readonly SortedList _downloadQueue = new(); + + // downloadId -> downloadtask + private readonly Dictionary _cachedDownloads = new(); + + #endregion State + + #region Public Queue Methods + + public void QueueAvatarDownload( + in DownloadInfo info, + string playerId, + CVRLoadingAvatarController loadingController) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing Avatar Download:\n{info.GetLogString()}\n" + + $"PlayerId: {playerId}\n" + + $"LoadingController: {loadingController}"); + } + + if (!ShouldQueueAvatarDownload(info, playerId)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar Download not eligible: {info.DownloadId}"); + return; + } + + if (_cachedDownloads.TryGetValue(info.DownloadId, out DownloadTask cachedDownload)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar Download already queued: {info.DownloadId}"); + cachedDownload.AddInstantiationTarget(playerId); + cachedDownload.BasePriority = CalculatePriority(cachedDownload); + return; + } + + DownloadTask task = new() + { + Info = info, + Type = DownloadTaskType.Avatar + }; + task.AddInstantiationTarget(playerId); + task.BasePriority = CalculatePriority(task); + } + + private bool ShouldQueueAvatarDownload( + in DownloadInfo info, + string playerId) + { + // Check if content is incompatible or banned + if (info.TagsData.Incompatible || info.TagsData.AdminBanned) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar is incompatible or banned"); + return false; + } + + // Check if player is blocked + if (MetaPort.Instance.blockedUserIds.Contains(playerId)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Player is blocked: {playerId}"); + return false; + } + + // Check if mature content is disabled + UgcTagsData tags = info.TagsData; + if (!MetaPort.Instance.matureContentAllowed && (tags.Gore || tags.Nudity)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Mature content is disabled"); + return false; + } + + // Check file size + if (info.FileSize > MaxAvatarDownloadSize) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar Download too large: {info.FileSize} > {MaxAvatarDownloadSize}"); + return false; + } + + // Get visibility status for the avatar + // ForceHidden means player avatar or avatar itself is forced off. + // ForceShown will bypass all checks and return true. + MetaPort.Instance.SelfModerationManager.GetAvatarVisibility(playerId, info.AssetId, + out bool wasForceHidden, out bool wasForceShown); + + if (!wasForceHidden) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar is not visible either because player avatar or avatar itself is forced off"); + return false; + } + + if (!wasForceShown) + { + // Check content filter settings if not force shown + CVRSettings settings = MetaPort.Instance.settings; + bool isLocalPlayer = playerId == MetaPort.Instance.ownerId; + bool isFriend = Friends.FriendsWith(playerId); + bool CheckFilterSettings(string settingName) + { + int settingVal = settings.GetSettingInt(settingName); + switch (settingVal) + { + // Only Self + case 0 when !isLocalPlayer: + // Only Friends + case 1 when !isFriend: + return false; + } + return true; + } + + if (!CheckFilterSettings("ContentFilterVisibility")) return false; + if (!CheckFilterSettings("ContentFilterNudity")) return false; + if (!CheckFilterSettings("ContentFilterGore")) return false; + if (!CheckFilterSettings("ContentFilterSuggestive")) return false; + if (!CheckFilterSettings("ContentFilterFlashingColors")) return false; + if (!CheckFilterSettings("ContentFilterFlashingLights")) return false; + if (!CheckFilterSettings("ContentFilterScreenEffects")) return false; + if (!CheckFilterSettings("ContentFilterExtremelyBright")) return false; + if (!CheckFilterSettings("ContentFilterViolence")) return false; + if (!CheckFilterSettings("ContentFilterJumpscare")) return false; + if (!CheckFilterSettings("ContentFilterExcessivelyHuge")) return false; + if (!CheckFilterSettings("ContentFilterExcessivelySmall")) return false; + } + + // All eligibility checks passed + return true; + } + + /// + /// Queues a prop download. + /// + /// The download info. + /// The instance ID for the prop. + /// The user who spawned the prop. + public void QueuePropDownload( + in DownloadInfo info, + string instanceId, + string spawnerId) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing Prop Download:\n{info.GetLogString()}\n" + + $"InstanceId: {instanceId}\n" + + $"SpawnerId: {spawnerId}"); + } + + if (_cachedDownloads.TryGetValue(info.DownloadId, out DownloadTask cachedDownload)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Prop Download already queued: {info.DownloadId}"); + cachedDownload.AddInstantiationTarget(instanceId); + cachedDownload.BasePriority = CalculatePriority(cachedDownload); + return; + } + + DownloadTask task = new() + { + Info = info, + Type = DownloadTaskType.Prop + }; + task.AddInstantiationTarget(instanceId); + task.BasePriority = CalculatePriority(task); + } + + /// + /// Queues a world download. + /// + /// Download info. + /// Whether to load into this world once downloaded. + /// Whether the home world is requested. + public void QueueWorldDownload( + in DownloadInfo info, + bool joinOnComplete, + bool isHomeRequested) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing World Download:\n{info.GetLogString()}\n" + + $"JoinOnComplete: {joinOnComplete}\n" + + $"IsHomeRequested: {isHomeRequested}"); + } + + if (_cachedDownloads.TryGetValue(info.DownloadId, out DownloadTask cachedDownload)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"World Download already queued: {info.DownloadId}"); + cachedDownload.BasePriority = CalculatePriority(cachedDownload); + return; + } + + DownloadTask task = new() + { + Info = info, + Type = DownloadTaskType.World + }; + task.BasePriority = CalculatePriority(task); + } + + #endregion Public Queue Methods + +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs b/BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs new file mode 100644 index 0000000..3664ed4 --- /dev/null +++ b/BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs @@ -0,0 +1,58 @@ +using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core.Util; +using UnityEngine; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager +{ + internal static bool TryGetPlayerEntity(string playerId, out CVRPlayerEntity playerEntity) + { + CVRPlayerEntity player = CVRPlayerManager.Instance.NetworkPlayers.Find(p => p.Uuid == playerId); + if (player == null) + { + // BetterContentLoadingMod.Logger.Error($"Player entity not found for ID: {playerId}"); + playerEntity = null; + return false; + } + playerEntity = player; + return true; + } + + internal static bool TryGetPropData(string instanceId, out CVRSyncHelper.PropData propData) + { + CVRSyncHelper.PropData prop = CVRSyncHelper.Props.Find(p => p.InstanceId == instanceId); + if (prop == null) + { + // BetterContentLoadingMod.Logger.Error($"Prop data not found for ID: {instanceId}"); + propData = null; + return false; + } + propData = prop; + return true; + } + + private static bool IsPlayerLocal(string playerId) + { + return playerId == MetaPort.Instance.ownerId; + } + + private static bool IsPlayerFriend(string playerId) + { + return Friends.FriendsWith(playerId); + } + + private bool IsPlayerWithinPriorityDistance(CVRPlayerEntity player) + { + if (player.PuppetMaster == null) return false; + return player.PuppetMaster.animatorManager.DistanceTo < PriorityDownloadDistance; + } + + internal bool IsPropWithinPriorityDistance(CVRSyncHelper.PropData prop) + { + Vector3 propPosition = new(prop.PositionX, prop.PositionY, prop.PositionZ); + return Vector3.Distance(propPosition, PlayerSetup.Instance.GetPlayerPosition()) < PriorityDownloadDistance; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadManager.Priority.cs b/BetterContentLoading/DownloadManager/DownloadManager.Priority.cs new file mode 100644 index 0000000..ae28cbc --- /dev/null +++ b/BetterContentLoading/DownloadManager/DownloadManager.Priority.cs @@ -0,0 +1,38 @@ +using ABI_RC.Core.Player; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager +{ + private float CalculatePriority(DownloadTask task) + { + return task.Type switch + { + DownloadTaskType.Avatar => CalculateAvatarPriority(task), + // DownloadTaskType.Prop => CalculatePropPriority(task2), + // DownloadTaskType.World => CalculateWorldPriority(task2), + _ => task.Info.FileSize + }; + } + + private float CalculateAvatarPriority(DownloadTask task) + { + float priority = task.Info.FileSize; + + foreach (string target in task.InstantiationTargets) + { + if (IsPlayerLocal(target)) return 0f; + + if (!TryGetPlayerEntity(target, out CVRPlayerEntity player)) + return priority; + + if (PrioritizeFriends && IsPlayerFriend(target)) + priority *= 0.5f; + + if (PrioritizeDistance && IsPlayerWithinPriorityDistance(player)) + priority *= 0.75f; + } + + return priority; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadTask.Main.cs b/BetterContentLoading/DownloadManager/DownloadTask.Main.cs new file mode 100644 index 0000000..5397cf7 --- /dev/null +++ b/BetterContentLoading/DownloadManager/DownloadTask.Main.cs @@ -0,0 +1,33 @@ +namespace NAK.BetterContentLoading; + +public partial class DownloadTask +{ + public DownloadInfo Info { get; set; } + public DownloadTaskStatus Status { get; set; } + public DownloadTaskType Type { get; set; } + + public float BasePriority { get; set; } + public float CurrentPriority => BasePriority * (1 + Progress / 100f); + + public long BytesRead { get; set; } + public int Progress { get; set; } + + /// The avatar/prop instances that wish to utilize this bundle. + public List InstantiationTargets { get; } = new(); + + public void AddInstantiationTarget(string target) + { + if (InstantiationTargets.Contains(target)) + return; + + InstantiationTargets.Add(target); + } + + public void RemoveInstantiationTarget(string target) + { + if (!InstantiationTargets.Contains(target)) + return; + + InstantiationTargets.Remove(target); + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadTask.Priority.cs b/BetterContentLoading/DownloadManager/DownloadTask.Priority.cs new file mode 100644 index 0000000..f697a5e --- /dev/null +++ b/BetterContentLoading/DownloadManager/DownloadTask.Priority.cs @@ -0,0 +1,6 @@ +namespace NAK.BetterContentLoading; + +public partial class DownloadTask +{ + +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs b/BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs new file mode 100644 index 0000000..df844d5 --- /dev/null +++ b/BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs @@ -0,0 +1,43 @@ +namespace NAK.BetterContentLoading; + +public class ConcurrentPriorityQueue where TPriority : IComparable +{ + private readonly object _lock = new(); + private readonly SortedDictionary> _queues = new(); + + public void Enqueue(TElement item, TPriority priority) + { + lock (_lock) + { + if (!_queues.TryGetValue(priority, out var queue)) + { + queue = new Queue(); + _queues[priority] = queue; + } + queue.Enqueue(item); + } + } + + public bool TryDequeue(out TElement item, out TPriority priority) + { + lock (_lock) + { + if (_queues.Count == 0) + { + item = default; + priority = default; + return false; + } + + var firstQueue = _queues.First(); + priority = firstQueue.Key; + var queue = firstQueue.Value; + item = queue.Dequeue(); + + if (queue.Count == 0) + _queues.Remove(priority); + + return true; + } + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs new file mode 100644 index 0000000..54d5792 --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs @@ -0,0 +1,24 @@ +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + private void StartBandwidthMonitor() + { + Task.Run(async () => + { + while (true) + { + await Task.Delay(1000); + Interlocked.Exchange(ref _bytesReadLastSecond, 0); + Interlocked.Exchange(ref _completedDownloads, 0); + } + }); + } + + private int ComputeUsableBandwidthPerDownload() + { + var activeCount = _activeDownloads.Count; + if (activeCount == 0) return MaxDownloadBandwidth; + return MaxDownloadBandwidth / activeCount; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Core.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Core.cs new file mode 100644 index 0000000..63fd4c2 --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Core.cs @@ -0,0 +1,126 @@ +using System.Collections.Concurrent; +using ABI_RC.Core; +using ABI_RC.Core.IO; +using ABI_RC.Core.IO.AssetManagement; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + #region Singleton + private static DownloadManager2 _instance; + public static DownloadManager2 Instance => _instance ??= new DownloadManager2(); + #endregion + + #region Settings + public bool IsDebugEnabled { get; set; } = true; + public bool PrioritizeFriends { get; set; } = true; + public bool PrioritizeDistance { get; set; } = true; + public float PriorityDownloadDistance { get; set; } = 25f; + public int MaxConcurrentDownloads { get; set; } = 5; + public int MaxDownloadBandwidth { get; set; } // 100MB default + private const int THROTTLE_THRESHOLD = 25 * 1024 * 1024; // 25MB threshold for throttling + #endregion + + #region State + private readonly ConcurrentDictionary _activeDownloads; + private readonly ConcurrentPriorityQueue _queuedDownloads; + private readonly ConcurrentDictionary _completedDownloads; + private readonly object _downloadLock = new(); + private long _bytesReadLastSecond; + #endregion + + private DownloadManager2() + { + _activeDownloads = new ConcurrentDictionary(); + _queuedDownloads = new ConcurrentPriorityQueue(); + MaxDownloadBandwidth = 100 * 1024 * 1024; + StartBandwidthMonitor(); + } + + public async Task QueueAvatarDownload(DownloadInfo info, string playerId) + { + if (await ValidateAndCheckCache(info)) + return true; + + DownloadTask2 task2 = GetOrCreateDownloadTask(info, DownloadTaskType.Avatar); + task2.AddTarget(playerId); + QueueDownload(task2); + return false; + } + + public async Task QueuePropDownload(DownloadInfo info, string instanceId, string spawnerId) + { + if (await ValidateAndCheckCache(info)) + return true; + + DownloadTask2 task2 = GetOrCreateDownloadTask(info, DownloadTaskType.Prop); + task2.AddTarget(instanceId, spawnerId); + QueueDownload(task2); + return false; + } + + public async Task QueueWorldDownload(DownloadInfo info, bool loadOnComplete) + { + if (await ValidateAndCheckCache(info)) + return true; + + DownloadTask2 task2 = GetOrCreateDownloadTask(info, DownloadTaskType.World, loadOnComplete); + QueueDownload(task2); + return false; + } + + private async Task ValidateAndCheckCache(DownloadInfo info) + { + // Check if already cached and up to date + if (await CacheManager.Instance.IsCachedFileUpToDate( + info.AssetId, + info.FileId, + info.FileHash)) + { + return true; + } + + // Validate disk space + var filePath = CacheManager.Instance.GetCachePath(info.AssetId, info.FileId); + if (!CVRTools.HasEnoughDiskSpace(filePath, info.FileSize)) + { + BetterContentLoadingMod.Logger.Error($"Not enough disk space to download {info.AssetId}"); + return false; + } + + // Ensure cache directory exists + CacheManager.Instance.EnsureCacheDirectoryExists(info.AssetId); + return false; + } + + private DownloadTask2 GetOrCreateDownloadTask(DownloadInfo info, DownloadTaskType type, bool loadOnComplete = false) + { + // Check if task already exists in active downloads + if (_activeDownloads.TryGetValue(info.DownloadId, out var activeTask)) + return activeTask; + + // Check if task exists in queued downloads + var queuedTask = _queuedDownloads.TryFind(t => t.Info.DownloadId == info.DownloadId); + if (queuedTask != null) + return queuedTask; + + // Create new task + var cachePath = CacheManager.Instance.GetCachePath(info.AssetId, info.FileId); + return new DownloadTask2(info, cachePath, type, loadOnComplete); + } + + public bool TryFindTask(string downloadId, out DownloadTask2 task2) + { + return _activeDownloads.TryGetValue(downloadId, out task2) || + _completedDownloads.TryGetValue(downloadId, out task2) || + TryFindQueuedTask(downloadId, out task2); + } + + private bool TryFindQueuedTask(string downloadId, out DownloadTask2 task2) + { + task2 = _queuedDownloads.UnorderedItems + .FirstOrDefault(x => x.Element.Info.DownloadId == downloadId).Element; + return task2 != null; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs new file mode 100644 index 0000000..2dd205d --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs @@ -0,0 +1,58 @@ +using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core.Util; +using UnityEngine; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + internal static bool TryGetPlayerEntity(string playerId, out CVRPlayerEntity playerEntity) + { + CVRPlayerEntity player = CVRPlayerManager.Instance.NetworkPlayers.Find(p => p.Uuid == playerId); + if (player == null) + { + // BetterContentLoadingMod.Logger.Error($"Player entity not found for ID: {playerId}"); + playerEntity = null; + return false; + } + playerEntity = player; + return true; + } + + internal static bool TryGetPropData(string instanceId, out CVRSyncHelper.PropData propData) + { + CVRSyncHelper.PropData prop = CVRSyncHelper.Props.Find(p => p.InstanceId == instanceId); + if (prop == null) + { + // BetterContentLoadingMod.Logger.Error($"Prop data not found for ID: {instanceId}"); + propData = null; + return false; + } + propData = prop; + return true; + } + + private static bool IsPlayerLocal(string playerId) + { + return playerId == MetaPort.Instance.ownerId; + } + + private static bool IsPlayerFriend(string playerId) + { + return Friends.FriendsWith(playerId); + } + + private bool IsPlayerWithinPriorityDistance(CVRPlayerEntity player) + { + if (player.PuppetMaster == null) return false; + return player.PuppetMaster.animatorManager.DistanceTo < PriorityDownloadDistance; + } + + internal bool IsPropWithinPriorityDistance(CVRSyncHelper.PropData prop) + { + Vector3 propPosition = new(prop.PositionX, prop.PositionY, prop.PositionZ); + return Vector3.Distance(propPosition, PlayerSetup.Instance.GetPlayerPosition()) < PriorityDownloadDistance; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs new file mode 100644 index 0000000..1132b8e --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs @@ -0,0 +1,47 @@ +using ABI_RC.Core.IO; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + private float CalculatePriority(DownloadTask2 task2) + { + return task2.Type switch + { + DownloadTaskType.Avatar => CalculateAvatarPriority(task2), + DownloadTaskType.Prop => CalculatePropPriority(task2), + DownloadTaskType.World => CalculateWorldPriority(task2), + _ => task2.Info.FileSize + }; + } + + private float CalculateAvatarPriority(DownloadTask2 task2) + { + float priority = task2.Info.FileSize; + + if (IsPlayerLocal(task2.PlayerId)) + return 0f; + + if (!TryGetPlayerEntity(task2.PlayerId, out var player)) + return priority; + + if (PrioritizeFriends && IsPlayerFriend(task2.PlayerId)) + priority *= 0.5f; + + if (PrioritizeDistance && IsPlayerWithinPriorityDistance(player)) + priority *= 0.75f; + + // Factor in download progress + priority *= (1 + task2.Progress / 100f); + + return priority; + } + + private float CalculatePropPriority(DownloadTask2 task2) + { + float priority = task2.Info.FileSize; + + if (IsPlayerLocal(task2.PlayerId)) + return 0f; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs new file mode 100644 index 0000000..698ac06 --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs @@ -0,0 +1,144 @@ +using System.Diagnostics; +using System.Net.Http.Headers; +using ABI_RC.Core.IO; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + private async Task ProcessDownload(DownloadTask2 task2) + { + using var client = new HttpClient(); + + // Set up resume headers if we have a resume token + if (!string.IsNullOrEmpty(task2.ResumeToken)) + { + client.DefaultRequestHeaders.Range = new RangeHeaderValue(task2.BytesRead, null); + } + + using var response = await client.GetAsync(task2.Info.AssetUrl, HttpCompletionOption.ResponseHeadersRead); + using var dataStream = await response.Content.ReadAsStreamAsync(); + + // Open file in append mode if resuming, otherwise create new + using var fileStream = new FileStream( + task2.TargetPath, + string.IsNullOrEmpty(task2.ResumeToken) ? FileMode.Create : FileMode.Append, + FileAccess.Write); + + bool isEligibleForThrottle = task2.Info.FileSize > THROTTLE_THRESHOLD; + var stopwatch = new Stopwatch(); + + int bytesRead; + do + { + if (task2.Status == DownloadTaskStatus.Paused) + { + task2.ResumeToken = GenerateResumeToken(task2); + await fileStream.FlushAsync(); + return; + } + + if (task2.Status != DownloadTaskStatus.Downloading) + { + HandleCancellation(task2, dataStream, fileStream); + return; + } + + stopwatch.Restart(); + var lengthToRead = isEligibleForThrottle ? + ComputeUsableBandwidthPerDownload() : + 16384; + + var buffer = new byte[lengthToRead]; + bytesRead = await dataStream.ReadAsync(buffer, 0, lengthToRead); + + if (isEligibleForThrottle) + Interlocked.Add(ref _bytesReadLastSecond, bytesRead); + + await fileStream.WriteAsync(buffer, 0, bytesRead); + UpdateProgress(task2, bytesRead); + + } while (bytesRead > 0); + + CompleteDownload(task2); + } + + private string GenerateResumeToken(DownloadTask2 task2) + { + // Generate a unique token that includes file position and hash + return $"{task2.BytesRead}:{DateTime.UtcNow.Ticks}"; + } + + private async Task FinalizeDownload(DownloadTask2 task2) + { + var tempPath = task2.CachePath + ".tmp"; + + try + { + // Decrypt the file if needed + if (task2.Info.EncryptionAlgorithm != 0) + { + await DecryptFile(tempPath, task2.CachePath, task2.Info); + File.Delete(tempPath); + } + else + { + File.Move(tempPath, task2.CachePath); + } + + CompleteDownload(task2); + } + catch (Exception ex) + { + // _logger.Error($"Failed to finalize download for {task.Info.AssetId}: {ex.Message}"); + task2.Status = DownloadTaskStatus.Failed; + File.Delete(tempPath); + _activeDownloads.TryRemove(task2.Info.DownloadId, out _); + } + } + + private async Task DecryptFile(string sourcePath, string targetPath, DownloadInfo info) + { + // Implementation of file decryption based on EncryptionAlgorithm + // This would use the FileKey from the DownloadInfo + throw new NotImplementedException("File decryption not implemented"); + } + + private void HandleCancellation(DownloadTask2 task2, Stream dataStream, Stream fileStream) + { + if (task2.Status != DownloadTaskStatus.Failed) + task2.Status = DownloadTaskStatus.Cancelled; + + dataStream.Close(); + fileStream.Close(); + + task2.Progress = 0; + task2.BytesRead = 0; + + _activeDownloads.TryRemove(task2.Info.DownloadId, out _); + } + + private void UpdateProgress(DownloadTask2 task2, int bytesRead) + { + task2.BytesRead += bytesRead; + task2.Progress = Math.Clamp( + (int)(((float)task2.BytesRead / task2.Info.FileSize) * 100f), + 0, 100); + } + + private void CompleteDownload(DownloadTask2 task2) + { + task2.Status = DownloadTaskStatus.Complete; + task2.Progress = 100; + _activeDownloads.TryRemove(task2.Info.DownloadId, out _); + _completedDownloads.TryAdd(task2.Info.DownloadId, task2); + + lock (_downloadLock) + { + if (_queuedDownloads.TryDequeue(out var nextTask, out _)) + { + StartDownload(nextTask); + } + } + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs new file mode 100644 index 0000000..e8a580a --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs @@ -0,0 +1,80 @@ +using ABI_RC.Core.IO; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + public void QueueDownload(DownloadTask2 newTask2) + { + if (_completedDownloads.TryGetValue(newTask2.Info.DownloadId, out var completedTask)) + { + completedTask.AddPlayer(newTask2.PlayerIds.FirstOrDefault()); + return; + } + + if (TryFindTask(newTask2.Info.DownloadId, out var existingTask)) + { + existingTask.AddPlayer(newTask2.PlayerIds.FirstOrDefault()); + RecalculatePriority(existingTask); + return; + } + + float priority = CalculatePriority(newTask2); + newTask2.CurrentPriority = priority; + + lock (_downloadLock) + { + if (_activeDownloads.Count < MaxConcurrentDownloads) + { + StartDownload(newTask2); + return; + } + + var lowestPriorityTask = _activeDownloads.Values + .OrderByDescending(t => t.CurrentPriority * (1 + t.Progress / 100f)) + .LastOrDefault(); + + if (lowestPriorityTask != null && priority < lowestPriorityTask.CurrentPriority) + { + PauseDownload(lowestPriorityTask); + StartDownload(newTask2); + } + else + { + _queuedDownloads.Enqueue(newTask2, priority); + } + } + } + + private void StartDownload(DownloadTask2 task2) + { + task2.Status = DownloadTaskStatus.Downloading; + _activeDownloads.TryAdd(task2.Info.DownloadId, task2); + Task.Run(() => ProcessDownload(task2)); + } + + private void PauseDownload(DownloadTask2 task2) + { + task2.Status = DownloadTaskStatus.Queued; + _activeDownloads.TryRemove(task2.Info.DownloadId, out _); + _queuedDownloads.Enqueue(task2, task2.CurrentPriority); + } + + + + + private void RecalculatePriority(DownloadTask2 task2) + { + var newPriority = CalculatePriority(task2); + if (Math.Abs(newPriority - task2.CurrentPriority) < float.Epsilon) + return; + + task2.CurrentPriority = newPriority; + + if (task2.Status == DownloadTaskStatus.Queued || task2.Status == DownloadTaskStatus.Paused) + { + // Re-enqueue with new priority + _queuedDownloads.UpdatePriority(task2, newPriority); + } + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadTask2.cs b/BetterContentLoading/DownloadManager2/DownloadTask2.cs new file mode 100644 index 0000000..0c531f6 --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadTask2.cs @@ -0,0 +1,62 @@ +namespace NAK.BetterContentLoading; + +public class DownloadTask2 +{ + public DownloadInfo Info { get; } + public DownloadTaskStatus Status { get; set; } + public DownloadTaskType Type { get; } + + public float BasePriority { get; set; } + public float CurrentPriority => BasePriority * (1 + Progress / 100f); + + public long BytesRead { get; set; } + public int Progress { get; set; } + + public string CachePath { get; } + public Dictionary Targets { get; } // Key: targetId (playerId/instanceId), Value: spawnerId + public bool LoadOnComplete { get; } // For worlds only + + public DownloadTask2( + DownloadInfo info, + string cachePath, + DownloadTaskType type, + bool loadOnComplete = false) + { + Info = info; + CachePath = cachePath; + Type = type; + LoadOnComplete = loadOnComplete; + Targets = new Dictionary(); + Status = DownloadTaskStatus.Queued; + } + + public void AddTarget(string targetId, string spawnerId = null) + { + if (Type == DownloadTaskType.World && Targets.Count > 0) + throw new InvalidOperationException("World downloads cannot have multiple targets"); + + Targets[targetId] = spawnerId; + } + + public void RemoveTarget(string targetId) + { + Targets.Remove(targetId); + } +} + +public enum DownloadTaskType +{ + Avatar, + Prop, + World +} + +public enum DownloadTaskStatus +{ + Queued, + Downloading, + Paused, + Complete, + Failed, + Cancelled +} \ No newline at end of file diff --git a/InteractionTest/Main.cs b/BetterContentLoading/Main.cs similarity index 68% rename from InteractionTest/Main.cs rename to BetterContentLoading/Main.cs index a88cbfd..5b5d812 100644 --- a/InteractionTest/Main.cs +++ b/BetterContentLoading/Main.cs @@ -1,22 +1,23 @@ using MelonLoader; +using NAK.BetterContentLoading.Patches; -namespace NAK.InteractionTest; +namespace NAK.BetterContentLoading; -public class InteractionTestMod : MelonMod +public class BetterContentLoadingMod : MelonMod { internal static MelonLogger.Instance Logger; - - #region Melon Mod Overrides + + #region Melon Events public override void OnInitializeMelon() { Logger = LoggerInstance; - ApplyPatches(typeof(Patches.ControllerRayPatches)); + ApplyPatches(typeof(CVRDownloadManager_Patches)); } - #endregion Melon Mod Overrides - + #endregion Melon Events + #region Melon Mod Utilities private void ApplyPatches(Type type) @@ -33,4 +34,4 @@ public class InteractionTestMod : MelonMod } #endregion Melon Mod Utilities -} +} \ No newline at end of file diff --git a/BetterContentLoading/ModSettings.cs b/BetterContentLoading/ModSettings.cs new file mode 100644 index 0000000..f07436c --- /dev/null +++ b/BetterContentLoading/ModSettings.cs @@ -0,0 +1,31 @@ +using MelonLoader; + +namespace NAK.RCCVirtualSteeringWheel; + +internal static class ModSettings +{ + #region Constants + + private const string ModName = nameof(RCCVirtualSteeringWheel); + + #endregion Constants + + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(ModName); + + internal static readonly MelonPreferences_Entry EntryOverrideSteeringRange = + Category.CreateEntry("override_steering_range", false, + "Override Steering Range", description: "Should the steering wheel use a custom steering range instead of the vehicle's default?"); + + internal static readonly MelonPreferences_Entry EntryCustomSteeringRange = + Category.CreateEntry("custom_steering_range", 60f, + "Custom Steering Range", description: "The custom steering range in degrees when override is enabled (default: 60)"); + + internal static readonly MelonPreferences_Entry EntryInvertSteering = + Category.CreateEntry("invert_steering", false, + "Invert Steering", description: "Inverts the steering direction"); + + #endregion Melon Preferences +} \ No newline at end of file diff --git a/BetterContentLoading/Patches.cs b/BetterContentLoading/Patches.cs new file mode 100644 index 0000000..d3c452b --- /dev/null +++ b/BetterContentLoading/Patches.cs @@ -0,0 +1,71 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.IO; +using ABI_RC.Core.Networking.API; +using ABI_RC.Core.Networking.API.Responses; +using HarmonyLib; +using NAK.BetterContentLoading.Util; + +namespace NAK.BetterContentLoading.Patches; + +internal static class CVRDownloadManager_Patches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(CVRDownloadManager), nameof(CVRDownloadManager.QueueTask))] + private static bool Prefix_CVRDownloadManager_QueueTask( + string assetId, + DownloadTask2.ObjectType type, + string assetUrl, + string fileId, + long fileSize, + string fileKey, + string toAttach, + string fileHash = null, + UgcTagsData tagsData = null, + CVRLoadingAvatarController loadingAvatarController = null, + bool joinOnComplete = false, + bool isHomeRequested = false, + int compatibilityVersion = 0, + int encryptionAlgorithm = 0, + string spawnerId = null) + { + DownloadInfo info; + + switch (type) + { + case DownloadTask2.ObjectType.Avatar: + info = new DownloadInfo( + assetId, assetUrl, fileId, fileSize, fileKey, fileHash, + compatibilityVersion, encryptionAlgorithm, tagsData); + BetterDownloadManager.Instance.QueueAvatarDownload(in info, toAttach, loadingAvatarController); + return true; + case DownloadTask2.ObjectType.Prop: + info = new DownloadInfo( + assetId, assetUrl, fileId, fileSize, fileKey, fileHash, + compatibilityVersion, encryptionAlgorithm, tagsData); + BetterDownloadManager.Instance.QueuePropDownload(in info, toAttach, spawnerId); + return true; + case DownloadTask2.ObjectType.World: + _ = ThreadingHelper.RunOffMainThreadAsync(() => + { + var response = ApiConnection.MakeRequest( + ApiConnection.ApiOperation.WorldMeta, + new { worldID = assetId } + ); + + if (response?.Result.Data == null) + return; + + info = new DownloadInfo( + assetId, response.Result.Data.FileLocation, response.Result.Data.FileId, + response.Result.Data.FileSize, response.Result.Data.FileKey, response.Result.Data.FileHash, + (int)response.Result.Data.CompatibilityVersion, (int)response.Result.Data.EncryptionAlgorithm, + null); + + BetterDownloadManager.Instance.QueueWorldDownload(in info, joinOnComplete, isHomeRequested); + }, CancellationToken.None); + return true; + default: + return true; + } + } +} \ No newline at end of file diff --git a/BetterContentLoading/Properties/AssemblyInfo.cs b/BetterContentLoading/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9ab241d --- /dev/null +++ b/BetterContentLoading/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using MelonLoader; +using NAK.BetterContentLoading; +using NAK.BetterContentLoading.Properties; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.BetterContentLoading))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.BetterContentLoading))] + +[assembly: MelonInfo( + typeof(BetterContentLoadingMod), + nameof(NAK.BetterContentLoading), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/BetterContentLoading" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.BetterContentLoading.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/BetterContentLoading/README.md b/BetterContentLoading/README.md new file mode 100644 index 0000000..8d9f529 --- /dev/null +++ b/BetterContentLoading/README.md @@ -0,0 +1,14 @@ +# RCCVirtualSteeringWheel + +Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive.~~~~ \ No newline at end of file diff --git a/BetterContentLoading/format.json b/BetterContentLoading/format.json new file mode 100644 index 0000000..f565d36 --- /dev/null +++ b/BetterContentLoading/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "RCCVirtualSteeringWheel", + "modversion": "1.0.1", + "gameversion": "2024r177", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component.\n", + "searchtags": [ + "rcc", + "steering", + "vehicle", + "car" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r44/RCCVirtualSteeringWheel.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RCCVirtualSteeringWheel/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Constants.cs b/CVRGizmos/Popcron.Gizmos/Constants.cs deleted file mode 100644 index e5884c9..0000000 --- a/CVRGizmos/Popcron.Gizmos/Constants.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Popcron -{ - public class Constants - { - public const string UniqueIdentifier = "Popcron.Gizmos"; - public const string EnabledKey = UniqueIdentifier + ".Enabled"; - } -} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs b/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs deleted file mode 100644 index f9193cf..0000000 --- a/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs +++ /dev/null @@ -1,19 +0,0 @@ -using UnityEngine; - -namespace Popcron -{ - public class LineDrawer : Drawer - { - public LineDrawer() - { - - } - - public override int Draw(ref Vector3[] buffer, params object[] args) - { - buffer[0] = (Vector3)args[0]; - buffer[1] = (Vector3)args[1]; - return 2; - } - } -} diff --git a/CVRGizmos/Popcron.Gizmos/Element.cs b/CVRGizmos/Popcron.Gizmos/Element.cs deleted file mode 100644 index 361fd59..0000000 --- a/CVRGizmos/Popcron.Gizmos/Element.cs +++ /dev/null @@ -1,12 +0,0 @@ -using UnityEngine; - -namespace Popcron -{ - internal class Element - { - public Vector3[] points = { }; - public Color color = Color.white; - public bool dashed = false; - public Matrix4x4 matrix = Matrix4x4.identity; - } -} \ No newline at end of file diff --git a/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs b/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs index 6f77a61..8c07542 100644 --- a/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs +++ b/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs @@ -2,17 +2,21 @@ using ABI.Scripting.CVRSTL.Client; using System.Diagnostics; using MTJobSystem; +using UnityEngine; namespace NAK.CVRLuaToolsExtension; public static class CVRLuaClientBehaviourExtensions { internal static readonly Dictionary _isRestarting = new(); + private static string PersistentDataPath; #region Public Methods public static void Restart(this CVRLuaClientBehaviour behaviour) { + PersistentDataPath ??= Application.persistentDataPath; // needs to be set on main + if (_isRestarting.TryGetValue(behaviour, out bool isRestarting) && isRestarting) { CVRLuaToolsExtensionMod.Logger.Warning($"Restart is already in progress for {behaviour.ScriptName}."); @@ -105,7 +109,7 @@ public static class CVRLuaClientBehaviourExtensions behaviour.LogInfo("[CVRLuaToolsExtension] Resetting script...\n"); behaviour.script = null; - behaviour.script = LuaScriptFactory.ForLuaBehaviour(behaviour, boundObjectEntries, behaviour.gameObject, behaviour.transform); + behaviour.script = LuaScriptFactory.ForLuaBehaviour(behaviour, boundObjectEntries, behaviour.gameObject, behaviour.transform, PersistentDataPath); behaviour.InitTimerIfNeeded(); // only null if crashed prior behaviour.script.AttachDebugger(behaviour.timer); // reattach the debugger diff --git a/CustomRichPresence/CustomRichPresence.csproj b/CustomRichPresence/CustomRichPresence.csproj new file mode 100644 index 0000000..4e44ed3 --- /dev/null +++ b/CustomRichPresence/CustomRichPresence.csproj @@ -0,0 +1,11 @@ + + + + net48 + + + + ..\.ManagedLibs\TheClapper.dll + + + diff --git a/CustomRichPresence/Main.cs b/CustomRichPresence/Main.cs new file mode 100644 index 0000000..a2702d5 --- /dev/null +++ b/CustomRichPresence/Main.cs @@ -0,0 +1,123 @@ +using System.Reflection; +using ABI_RC.Core.Networking; +using ABI_RC.Core.Savior; +using ABI_RC.Core.Util.AnimatorManager; +using ABI_RC.Helpers; +using HarmonyLib; +using MagicaCloth; +using MelonLoader; +using Steamworks; +using UnityEngine; + +namespace NAK.CustomRichPresence; + +public class CustomRichPresenceMod : MelonMod +{ + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(CustomRichPresence)); + + private static readonly MelonPreferences_Entry EntryUseCustomPresence = + Category.CreateEntry("use_custom_presence", true, + "Use Custom Presence", description: "Uses the custom rich presence setup."); + + // Discord Rich Presence Customization + private static readonly MelonPreferences_Entry DiscordStatusFormat = + Category.CreateEntry("discord_status_format", "Online using {mode}.", + "Discord Status Format", description: "Format for Discord status message. Available variables: {mode}, {instance_name}, {privacy}"); + + private static readonly MelonPreferences_Entry DiscordDetailsFormat = + Category.CreateEntry("discord_details_format", "{instance_name} [{privacy}]", + "Discord Details Format", description: "Format for Discord details. Available variables: {instance_name}, {privacy}, {world_name}, {mission_name}"); + + // Steam Rich Presence Customization + private static readonly MelonPreferences_Entry SteamStatusFormat = + Category.CreateEntry("steam_status_format", "Exploring ({mode}) {instance_name} [{privacy}].", + "Steam Status Format", description: "Format for Steam status. Available variables: {mode}, {instance_name}, {privacy}"); + + private static readonly MelonPreferences_Entry SteamGameStatusFormat = + Category.CreateEntry("steam_game_status_format", "Connected to a server, Privacy: {privacy}.", + "Steam Game Status Format", description: "Format for Steam game status. Available variables: {privacy}, {instance_name}, {world_name}"); + + private static readonly MelonPreferences_Entry SteamDisplayStatus = + Category.CreateEntry("steam_display_status", "#Status_Online", + "Steam Display Status", description: "Steam display status localization key."); + + #endregion Melon Preferences + + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(RichPresence).GetMethod(nameof(RichPresence.PopulateLastMessage), + BindingFlags.NonPublic | BindingFlags.Static), + prefix: new HarmonyMethod(typeof(CustomRichPresenceMod).GetMethod(nameof(OnPopulateLastMessage), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + } + + private static string FormatPresenceText(string format, string mode) + { + return format + .Replace("{mode}", mode) + .Replace("{instance_name}", RichPresence.LastMsg.InstanceName) + .Replace("{privacy}", RichPresence.LastMsg.InstancePrivacy) + .Replace("{world_name}", RichPresence.LastMsg.InstanceWorldName) + .Replace("{mission_name}", RichPresence.LastMsg.InstanceMissionName) + .Replace("{current_players}", RichPresence.LastMsg.CurrentPlayers.ToString()) + .Replace("{max_players}", RichPresence.LastMsg.MaxPlayers.ToString()); + } + + private static bool OnPopulateLastMessage() + { + if (!EntryUseCustomPresence.Value) + return true; + + string mode = MetaPort.Instance.isUsingVr ? "VR Mode" : "Desktop Mode"; + + PresenceManager.ClearPresence(); + if (RichPresence.DiscordEnabled) + { + string status = FormatPresenceText(DiscordStatusFormat.Value, mode); + string details = FormatPresenceText(DiscordDetailsFormat.Value, mode); + + PresenceManager.UpdatePresence( + status, + details, + RichPresence.LastConnectedToServer, + 0L, + "discordrp-cvrmain", + null, + null, + null, + RichPresence.LastMsg.InstanceMeshId, + RichPresence.LastMsg.CurrentPlayers, + RichPresence.LastMsg.MaxPlayers + ); + } + + if (!CheckVR.Instance.skipSteamApiRegister && SteamManager.Initialized) + { + SteamFriends.ClearRichPresence(); + if (RichPresence.SteamEnabled) + { + string status = FormatPresenceText(SteamStatusFormat.Value, mode); + string gameStatus = FormatPresenceText(SteamGameStatusFormat.Value, mode); + + SteamFriends.SetRichPresence("status", status); + SteamFriends.SetRichPresence("gamestatus", gameStatus); + SteamFriends.SetRichPresence("steam_display", SteamDisplayStatus.Value); + SteamFriends.SetRichPresence("steam_player_group", RichPresence.LastMsg.InstanceMeshId); + SteamFriends.SetRichPresence("steam_player_group_size", RichPresence.LastMsg.CurrentPlayers.ToString()); + SteamFriends.SetRichPresence("gamemode", RichPresence.LastMsg.InstanceMissionName); + SteamFriends.SetRichPresence("worldname", RichPresence.LastMsg.InstanceWorldName); + SteamFriends.SetRichPresence("instancename", RichPresence.LastMsg.InstanceName); + SteamFriends.SetRichPresence("instanceprivacy", RichPresence.LastMsg.InstancePrivacy); + SteamFriends.SetRichPresence("currentplayer", RichPresence.LastMsg.CurrentPlayers.ToString()); + SteamFriends.SetRichPresence("maxplayer", RichPresence.LastMsg.MaxPlayers.ToString()); + } + } + + return false; + } +} \ No newline at end of file diff --git a/InteractionTest/Properties/AssemblyInfo.cs b/CustomRichPresence/Properties/AssemblyInfo.cs similarity index 65% rename from InteractionTest/Properties/AssemblyInfo.cs rename to CustomRichPresence/Properties/AssemblyInfo.cs index ffc8f5e..0e00c7b 100644 --- a/InteractionTest/Properties/AssemblyInfo.cs +++ b/CustomRichPresence/Properties/AssemblyInfo.cs @@ -1,30 +1,30 @@ -using NAK.InteractionTest.Properties; +using NAK.CustomRichPresence.Properties; using MelonLoader; using System.Reflection; [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.InteractionTest))] +[assembly: AssemblyTitle(nameof(NAK.CustomRichPresence))] [assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.InteractionTest))] +[assembly: AssemblyProduct(nameof(NAK.CustomRichPresence))] [assembly: MelonInfo( - typeof(NAK.InteractionTest.InteractionTestMod), - nameof(NAK.InteractionTest), + typeof(NAK.CustomRichPresence.CustomRichPresenceMod), + nameof(NAK.CustomRichPresence), AssemblyInfoParams.Version, AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/InteractionTest" + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/CustomRichPresence" )] [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 125, 126, 129)] -[assembly: MelonAuthorColor(255, 158, 21, 32)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] -namespace NAK.InteractionTest.Properties; +namespace NAK.CustomRichPresence.Properties; internal static class AssemblyInfoParams { public const string Version = "1.0.0"; diff --git a/CustomRichPresence/README.md b/CustomRichPresence/README.md new file mode 100644 index 0000000..33bd3fd --- /dev/null +++ b/CustomRichPresence/README.md @@ -0,0 +1,14 @@ +# DropPropTweak + +Gives the Drop Prop button more utility by allowing you to drop props in the air. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/CustomRichPresence/format.json b/CustomRichPresence/format.json new file mode 100644 index 0000000..a599614 --- /dev/null +++ b/CustomRichPresence/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "DropPropTweak", + "modversion": "1.0.0", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Gives the Drop Prop button more utility by allowing you to drop props in the air.", + "searchtags": [ + "prop", + "spawn", + "indicator", + "loading" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r34/DropPropTweak.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DropPropTweak/", + "changelog": "- Initial Release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/CustomSpawnPoint/SpawnPointManager.cs b/CustomSpawnPoint/SpawnPointManager.cs index 12bcd43..350d07c 100644 --- a/CustomSpawnPoint/SpawnPointManager.cs +++ b/CustomSpawnPoint/SpawnPointManager.cs @@ -7,38 +7,38 @@ using Object = UnityEngine.Object; using ABI_RC.Core; using Newtonsoft.Json; -namespace NAK.CustomSpawnPoint +namespace NAK.CustomSpawnPoint; + +internal static class SpawnPointManager { - internal static class SpawnPointManager - { - #region Fields + #region Fields - private static string currentWorldId = string.Empty; - private static SpawnPointData? currentSpawnPoint; + private static string currentWorldId = string.Empty; + private static SpawnPointData? currentSpawnPoint; - private static string requestedWorldId = string.Empty; - private static SpawnPointData? requestedSpawnPoint; + private static string requestedWorldId = string.Empty; + private static SpawnPointData? requestedSpawnPoint; - private static Dictionary spawnPoints = new(); - private static readonly string jsonFilePath = Path.Combine("UserData", "customspawnpoints.json"); + private static Dictionary spawnPoints = new(); + private static readonly string jsonFilePath = Path.Combine("UserData", "customspawnpoints.json"); - private static GameObject[] customSpawnPointsArray; - private static GameObject[] originalSpawnPointsArray; + private static GameObject[] customSpawnPointsArray; + private static GameObject[] originalSpawnPointsArray; - #endregion Fields + #endregion Fields - #region Initialization + #region Initialization - internal static void Init() - { + internal static void Init() + { LoadSpawnpoints(); CVRGameEventSystem.World.OnLoad.AddListener(OnWorldLoaded); CVRGameEventSystem.World.OnUnload.AddListener(OnWorldUnloaded); MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); } - private static System.Collections.IEnumerator WaitMainMenuUi() - { + private static System.Collections.IEnumerator WaitMainMenuUi() + { while (ViewManager.Instance == null) yield return null; while (ViewManager.Instance.gameMenuView == null) @@ -65,12 +65,12 @@ namespace NAK.CustomSpawnPoint customSpawnPointsArray = new[] { customSpawnPointObject }; } - #endregion Initialization + #endregion Initialization - #region Game Events + #region Game Events - private static void OnWorldLoaded(string worldId) - { + private static void OnWorldLoaded(string worldId) + { CVRWorld world = CVRWorld.Instance; if (world == null) return; @@ -90,13 +90,13 @@ namespace NAK.CustomSpawnPoint } } - private static void OnWorldUnloaded(string worldId) - { + private static void OnWorldUnloaded(string worldId) + { ClearCurrentWorldState(); } - internal static void OnRequestWorldDetailsPage(string worldId) - { + internal static void OnRequestWorldDetailsPage(string worldId) + { //CustomSpawnPointMod.Logger.Msg("Requesting world details page for world: " + worldId); requestedWorldId = worldId; @@ -106,24 +106,24 @@ namespace NAK.CustomSpawnPoint UpdateMenuButtonState(hasSpawnpoint, worldId == currentWorldId && CVRWorld.Instance != null && CVRWorld.Instance.allowFlying); } - private static void OnClearSpawnpointConfirm(string id, string value, string data) - { + private static void OnClearSpawnpointConfirm(string id, string value, string data) + { if (id != "nak_clear_spawnpoint") return; if (value == "true") ClearSpawnPoint(); } - #endregion Game Events + #endregion Game Events - #region Spawnpoint Management + #region Spawnpoint Management - public static void SetSpawnPoint() - => SetSpawnPointForWorld(currentWorldId); + public static void SetSpawnPoint() + => SetSpawnPointForWorld(currentWorldId); - public static void ClearSpawnPoint() - => ClearSpawnPointForWorld(currentWorldId); + public static void ClearSpawnPoint() + => ClearSpawnPointForWorld(currentWorldId); - private static void SetSpawnPointForWorld(string worldId) - { + private static void SetSpawnPointForWorld(string worldId) + { CustomSpawnPointMod.Logger.Msg("Setting spawn point for world: " + worldId); Vector3 playerPosition = PlayerSetup.Instance.GetPlayerPosition(); @@ -152,8 +152,8 @@ namespace NAK.CustomSpawnPoint UpdateMenuButtonState(true, worldId == currentWorldId); } - private static void ClearSpawnPointForWorld(string worldId) - { + private static void ClearSpawnPointForWorld(string worldId) + { CustomSpawnPointMod.Logger.Msg("Clearing spawn point for world: " + worldId); if (spawnPoints.ContainsKey(worldId)) @@ -172,29 +172,29 @@ namespace NAK.CustomSpawnPoint UpdateMenuButtonState(false, worldId == currentWorldId); } - private static void UpdateCustomSpawnPointTransform(SpawnPointData spawnPoint) - { + private static void UpdateCustomSpawnPointTransform(SpawnPointData spawnPoint) + { customSpawnPointsArray[0].transform.SetPositionAndRotation(spawnPoint.Position, Quaternion.Euler(spawnPoint.Rotation)); } - private static void UpdateMenuButtonState(bool hasSpawnpoint, bool isInWorld) - { + private static void UpdateMenuButtonState(bool hasSpawnpoint, bool isInWorld) + { ViewManager.Instance.gameMenuView.View.TriggerEvent("NAKUpdateSpawnpointStatus", hasSpawnpoint.ToString(), isInWorld.ToString()); } - private static void ClearCurrentWorldState() - { + private static void ClearCurrentWorldState() + { currentWorldId = string.Empty; currentSpawnPoint = null; originalSpawnPointsArray = null; } - #endregion Spawnpoint Management + #endregion Spawnpoint Management - #region JSON Management + #region JSON Management - private static void LoadSpawnpoints() - { + private static void LoadSpawnpoints() + { if (File.Exists(jsonFilePath)) { string json = File.ReadAllText(jsonFilePath); @@ -206,18 +206,18 @@ namespace NAK.CustomSpawnPoint } } - private static void SaveSpawnpoints() - { + private static void SaveSpawnpoints() + { File.WriteAllText(jsonFilePath, JsonConvert.SerializeObject(spawnPoints, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore } // death )); } - #endregion JSON Management + #endregion JSON Management - #region Spawnpoint JS + #region Spawnpoint JS - private const string spawnpointJs = @" + private const string spawnpointJs = @" let hasSpawnpointForThisWorld = false; let spawnpointButton = null; @@ -249,17 +249,16 @@ engine.on('NAKUpdateSpawnpointStatus', function (hasSpawnpoint, isInWorld) { }); "; - #endregion Spawnpoint JS - } + #endregion Spawnpoint JS +} - #region Serializable +#region Serializable - [Serializable] - public struct SpawnPointData - { - public Vector3 Position; - public Vector3 Rotation; - } +[Serializable] +public struct SpawnPointData +{ + public Vector3 Position; + public Vector3 Rotation; +} - #endregion Serializable -} \ No newline at end of file +#endregion Serializable \ No newline at end of file diff --git a/InteractionTest/Components/InteractionTracker.cs b/InteractionTest/Components/InteractionTracker.cs deleted file mode 100644 index b5ea1b1..0000000 --- a/InteractionTest/Components/InteractionTracker.cs +++ /dev/null @@ -1,213 +0,0 @@ -using System.Collections; -using ABI_RC.Core; -using ABI_RC.Systems.GameEventSystem; -using ABI_RC.Systems.IK; -using ABI_RC.Systems.Movement; -using ABI.CCK.Components; -using RootMotion.FinalIK; -using UnityEngine; - -namespace NAK.InteractionTest.Components; - -public class InteractionTracker : MonoBehaviour -{ - #region Setup - - public static void Setup(GameObject parentObject, bool isLeft = true) - { - // LeapMotion: RotationTarget - - GameObject trackerObject = new("NAK.InteractionTracker"); - trackerObject.transform.SetParent(parentObject.transform); - trackerObject.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); - - GameObject ikObject = new("NAK.InteractionTracker.IK"); - ikObject.transform.SetParent(trackerObject.transform); - ikObject.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); - - SphereCollider sphereCol = trackerObject.AddComponent(); - sphereCol.radius = 0f; - sphereCol.isTrigger = true; - - BetterBetterCharacterController.QueueRemovePlayerCollision(sphereCol); - - InteractionTracker tracker = trackerObject.AddComponent(); - tracker.isLeft = isLeft; - tracker.Initialize(); - } - - #endregion Setup - - #region Actions - - public Action OnPenetrationDetected; // called on start of penetration - public Action OnPenetrationLost; // called on end of penetration - public Action OnPenetrationNormalChanged; // called when penetration normal changes after 2 degree threshold - - #endregion Actions - - public bool isLeft; - - public bool IsColliding => _isColliding; - public Vector3 ClosestPoint { get; private set; } - public Vector3 LastPenetrationNormal => _lastPenetrationNormal; - - private bool _isColliding; - private bool _wasPenetrating; - public Vector3 _lastPenetrationNormal = Vector3.forward; - private Collider _selfCollider; - private const float NormalChangeThreshold = 0.2f; - - #region Unity Events - - private void Initialize() - { - _selfCollider = GetComponent(); - CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(OnLocalAvatarLoaded); - } - - private void OnDestroy() - { - CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(OnLocalAvatarLoaded); - } - - private void OnLocalAvatarLoaded(CVRAvatar _) - { - StartCoroutine(FrameLateInit()); - } - - private IEnumerator FrameLateInit() - { - yield return null; - yield return null; - OnInitSolver(); - IKSystem.vrik.onPreSolverUpdate.AddListener(OnPreSolverUpdate); - IKSystem.vrik.onPostSolverUpdate.AddListener(OnPostSolverUpdate); - } - - private void OnTriggerStay(Collider other) - { - if (other.gameObject.layer == CVRLayers.PlayerLocal) - return; - - if (_selfCollider == null) - return; - - Transform selfTransform = transform; - Transform otherTransform = other.transform; - - bool isPenetrating = Physics.ComputePenetration( - _selfCollider, selfTransform.position, selfTransform.rotation, - other, otherTransform.position, otherTransform.rotation, - out Vector3 direction, out float distance); - - if (isPenetrating) - { - ClosestPoint = selfTransform.position + direction * distance; - Debug.DrawRay(ClosestPoint, direction * 10, Color.red); - - if (!_wasPenetrating) - { - OnPenetrationDetected?.Invoke(); - _wasPenetrating = true; - _lastPenetrationNormal = direction; - } - - float angleChange = Vector3.Angle(_lastPenetrationNormal, direction); - Debug.Log("Angle change: " + angleChange); - if (angleChange > NormalChangeThreshold) - { - _lastPenetrationNormal = direction; - OnPenetrationNormalChanged?.Invoke(); - } - } - else - { - if (_wasPenetrating) - { - OnPenetrationLost?.Invoke(); - _wasPenetrating = false; - } - } - } - - private void OnTriggerEnter(Collider other) - { - if (other.gameObject.layer == CVRLayers.PlayerLocal) - return; - - Debug.Log("Triggered with " + other.gameObject.name); - _isColliding = true; - } - - private void OnTriggerExit(Collider other) - { - if (other.gameObject.layer == CVRLayers.PlayerLocal) - return; - - Debug.Log("Exited trigger with " + other.gameObject.name); - _isColliding = false; - - if (_wasPenetrating) - { - OnPenetrationLost?.Invoke(); - _wasPenetrating = false; - } - } - - #endregion Unity Events - - private Transform _oldTarget; - - private Vector3 _initialPosOffset; - private Quaternion _initialRotOffset; - - private IKSolverVR.Arm _armSolver; - - private void OnInitSolver() - { - _armSolver = isLeft ? IKSystem.vrik.solver.arms[0] : IKSystem.vrik.solver.arms[1]; - - Transform target = _armSolver.target; - if (target == null) - target = transform.parent.Find("RotationTarget"); // LeapMotion: RotationTarget - - if (target == null) return; - - _initialPosOffset = target.localPosition; - _initialRotOffset = target.localRotation; - } - - private void OnPreSolverUpdate() - { - if (!IsColliding) - return; - - Transform selfTransform = transform; - - float dot = Vector3.Dot(_lastPenetrationNormal, selfTransform.forward); - if (dot > -0.45f) - return; - - _oldTarget = _armSolver.target; - _armSolver.target = selfTransform.GetChild(0); - - _armSolver.target.position = ClosestPoint + selfTransform.rotation * _initialPosOffset; - _armSolver.target.rotation = _initialRotOffset * Quaternion.LookRotation(-_lastPenetrationNormal, selfTransform.up); - - _armSolver.positionWeight = 1f; - _armSolver.rotationWeight = 1f; - } - - private void OnPostSolverUpdate() - { - if (!_oldTarget) - return; - - _armSolver.target = _oldTarget; - _oldTarget = null; - - _armSolver.positionWeight = 0f; - _armSolver.rotationWeight = 0f; - } -} \ No newline at end of file diff --git a/InteractionTest/ModSettings.cs b/InteractionTest/ModSettings.cs deleted file mode 100644 index 010f81b..0000000 --- a/InteractionTest/ModSettings.cs +++ /dev/null @@ -1,7 +0,0 @@ -using MelonLoader; - -namespace NAK.InteractionTest; - -internal static class ModSettings -{ -} \ No newline at end of file diff --git a/InteractionTest/Patches.cs b/InteractionTest/Patches.cs deleted file mode 100644 index 1fa65fd..0000000 --- a/InteractionTest/Patches.cs +++ /dev/null @@ -1,17 +0,0 @@ - -using ABI_RC.Core; -using ABI_RC.Core.InteractionSystem; -using HarmonyLib; -using NAK.InteractionTest.Components; - -namespace NAK.InteractionTest.Patches; - -internal static class ControllerRayPatches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(ControllerRay), nameof(ControllerRay.Start))] - private static void Postfix_BetterCharacterController_Start(ref ControllerRay __instance) - { - InteractionTracker.Setup(__instance.gameObject, __instance.hand == CVRHand.Left); - } -} \ No newline at end of file diff --git a/InteractionTest/README.md b/InteractionTest/README.md deleted file mode 100644 index 35bb285..0000000 --- a/InteractionTest/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# OriginShift - -Experimental mod that allows world origin to be shifted to prevent floating point precision issues. - -## Compromises -- Steam Audio data cannot be shifted. -- NavMesh data cannot be shifted. -- Light Probe data cannot be shifted (until [unity 2022](https://docs.unity3d.com/2022.3/Documentation/Manual/LightProbes-Moving.html)). -- Occlusion Culling data cannot be shifted. - - When using "Forced" mode, occlusion culling is disabled. -- Only 10k trail positions can be shifted per Trail Renderer (artificial limit). -- Only 10k particle positions can be shifted per Particle System (artificial limit). - - Potentially can fix by changing Particle System to Custom Simulation Space ? (untested) -- World Constraints are not shifted. - -## Known Issues -- Mod Network is not yet implemented, so Compatibility Mode is required to play with others. -- Portable Camera drone mode is not yet offset by the world origin shift. -- Chunk threshold past 10 units will break Voice Chat with remote players in some cases (without Compatibility Mode). - - This is because the voice server dictates who can hear who based on distance from each other and the world origin shift messes with that. -- Teleports past 50k units will not work. - - BetterBetterCharacterController prevents teleports past 50k units. -- Magica Cloth. - -## Mod Incompatibilities -- PlayerRagdollMod will freak out when you ragdoll between chunk boundaries. - -## Provided Components -- `OriginShiftController` - World script to configure origin shift. -- `OriginShiftEventReceiver` - Event receiver for OriginShift events. -- `OriginShiftTransformReceiver` - Shifts the transform of the GameObject it is attached to. -- `OriginShiftRigidbodyReceiver` - Shifts the rigidbody of the GameObject it is attached to. -- `OriginShiftTrailRendererReceiver` - Shifts the positions of the Trail Renderer of the GameObject it is attached to. -- `OriginShiftParticleSystemReceiver` - Shifts the positions of the Particle System of the GameObject it is attached to. - -The provided receiver components are automatically added to Props, Players, and Object Syncs. - -## Provided Shader Globals -- `_OriginShiftChunkOffset` - The current amount of chunks offset from the origin. -- `_OriginShiftChunkThreshold` - The size of a chunk in world units. -- `_OriginShiftChunkPosition` - The chunk offset multiplied by the chunk threshold. - ---- - -Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. -https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games - -> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. - -> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. - -> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/InteractionTest/format.json b/InteractionTest/format.json deleted file mode 100644 index 39d8c48..0000000 --- a/InteractionTest/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": 211, - "name": "RelativeSync", - "modversion": "1.0.3", - "gameversion": "2024r175", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network.\n\nProvides some Experimental settings to also fix local jitter on movement parents.", - "searchtags": [ - "relative", - "sync", - "movement", - "chair" - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r29/RelativeSync.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSync/", - "changelog": "- Enabled the Experimental settings to fix **local** jitter on Movement Parents by default\n- Adjusted BBCC No Interpolation fix to account for potential native fix (now respects initial value)", - "embedcolor": "#507e64" -} \ No newline at end of file diff --git a/LegacyContentMitigation/ModSettings.cs b/LegacyContentMitigation/ModSettings.cs deleted file mode 100644 index 0fdef02..0000000 --- a/LegacyContentMitigation/ModSettings.cs +++ /dev/null @@ -1,24 +0,0 @@ -using MelonLoader; - -namespace NAK.LegacyContentMitigation; - -internal static class ModSettings -{ - #region Constants - - internal const string ModName = nameof(LegacyContentMitigation); - internal const string LCM_SettingsCategory = "Legacy Content Mitigation"; - - #endregion Constants - - #region Melon Preferences - - private static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(ModName); - - internal static readonly MelonPreferences_Entry EntryAutoForLegacyWorlds = - Category.CreateEntry("auto_for_legacy_worlds", true, - "Auto For Legacy Worlds", description: "Should Legacy View be auto enabled for detected Legacy worlds?"); - - #endregion Melon Preferences -} \ No newline at end of file diff --git a/LuaNetworkVariables/SyncedBehaviour/PickupableBehaviour.cs b/LuaNetworkVariables/SyncedBehaviour/PickupableBehaviour.cs deleted file mode 100644 index 30fddc1..0000000 --- a/LuaNetworkVariables/SyncedBehaviour/PickupableBehaviour.cs +++ /dev/null @@ -1,161 +0,0 @@ -using UnityEngine; -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Systems.ModNetwork; - -namespace NAK.LuaNetVars; - -public class PickupableBehaviour : MNSyncedBehaviour -{ - private enum PickupMessageType : byte - { - GrabState, - Transform - } - - private bool isHeld; - private string holderId; - private Vector3 lastPosition; - private Quaternion lastRotation; - - public PickupableObject Pickupable { get; private set; } - - public PickupableBehaviour(string networkId, PickupableObject pickupable) : base(networkId, autoAcceptTransfers: false) - { - Pickupable = pickupable; - isHeld = false; - holderId = string.Empty; - lastPosition = pickupable.transform.position; - lastRotation = pickupable.transform.rotation; - } - - public void OnGrabbed(InteractionContext context) - { - RequestOwnership(success => { - if (success) - { - isHeld = true; - holderId = LocalUserId; - SendNetworkedData(WriteGrabState); - } - else - { - // Ownership request failed, drop the object - Pickupable.ControllerRay = null; // Force drop - } - }); - } - - public void OnDropped() - { - if (!HasOwnership) return; - - isHeld = false; - holderId = string.Empty; - SendNetworkedData(WriteGrabState); - } - - public void UpdateTransform(Vector3 position, Quaternion rotation) - { - if (!HasOwnership || !isHeld) return; - - lastPosition = position; - lastRotation = rotation; - SendNetworkedData(WriteTransform); - } - - protected override OwnershipResponse OnOwnershipRequested(string requesterId) - { - // If the object is held by the current owner, reject the transfer - if (isHeld && holderId == LocalUserId) - return OwnershipResponse.Rejected; - - // If theft is disallowed and the object is held by someone, reject the transfer - if (Pickupable.DisallowTheft && !string.IsNullOrEmpty(holderId)) - return OwnershipResponse.Rejected; - - return OwnershipResponse.Accepted; - } - - protected override void WriteState(ModNetworkMessage message) - { - message.Write(isHeld); - message.Write(holderId); - message.Write(lastPosition); - message.Write(lastRotation); - } - - protected override void ReadState(ModNetworkMessage message) - { - message.Read(out isHeld); - message.Read(out holderId); - message.Read(out lastPosition); - message.Read(out lastRotation); - - UpdatePickupableState(); - } - - private void WriteGrabState(ModNetworkMessage message) - { - message.Write((byte)PickupMessageType.GrabState); - message.Write(isHeld); - message.Write(holderId); - } - - private void WriteTransform(ModNetworkMessage message) - { - message.Write((byte)PickupMessageType.Transform); - message.Write(lastPosition); - message.Write(lastRotation); - } - - protected override void ReadCustomData(ModNetworkMessage message) - { - message.Read(out byte messageType); - - switch ((PickupMessageType)messageType) - { - case PickupMessageType.GrabState: - message.Read(out isHeld); - message.Read(out holderId); - break; - - case PickupMessageType.Transform: - message.Read(out Vector3 position); - message.Read(out Quaternion rotation); - lastPosition = position; - lastRotation = rotation; - break; - } - - UpdatePickupableState(); - } - - private void UpdatePickupableState() - { - // Update transform if we're not the holder - if (!isHeld || holderId != LocalUserId) - { - Pickupable.transform.position = lastPosition; - Pickupable.transform.rotation = lastRotation; - } - - // Force drop if we were holding but someone else took ownership - if (isHeld && holderId != LocalUserId) - { - Pickupable.ControllerRay = null; // Force drop - } - } - - protected override void OnOwnershipChanged(string newOwnerId) - { - base.OnOwnershipChanged(newOwnerId); - - // If we lost ownership and were holding, force drop - if (!HasOwnership && holderId == LocalUserId) - { - isHeld = false; - holderId = string.Empty; - Pickupable.ControllerRay = null; // Force drop - } - } -} \ No newline at end of file diff --git a/LuaNetworkVariables/SyncedBehaviour/PickupableObject.cs b/LuaNetworkVariables/SyncedBehaviour/PickupableObject.cs deleted file mode 100644 index 76b495a..0000000 --- a/LuaNetworkVariables/SyncedBehaviour/PickupableObject.cs +++ /dev/null @@ -1,72 +0,0 @@ -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.InteractionSystem.Base; -using UnityEngine; - -namespace NAK.LuaNetVars; - -public class PickupableObject : Pickupable -{ - [SerializeField] private bool canPickup = true; - [SerializeField] private bool disallowTheft = false; - [SerializeField] private float maxGrabDistance = 2f; - [SerializeField] private float maxPushDistance = 2f; - [SerializeField] private bool isAutoHold = false; - [SerializeField] private bool allowRotation = true; - [SerializeField] private bool allowPushPull = true; - [SerializeField] private bool allowInteraction = true; - - private PickupableBehaviour behaviour; - private bool isInitialized; - - private void Awake() - { - // Generate a unique network ID based on the instance ID - string networkId = $"pickup_{gameObject.name}"; - behaviour = new PickupableBehaviour(networkId, this); - isInitialized = true; - } - - private void OnDestroy() - { - behaviour?.Dispose(); - } - - private void Update() - { - if (behaviour?.HasOwnership == true) - { - transform.SetPositionAndRotation(ControllerRay.pivotPoint.position, ControllerRay.pivotPoint.rotation); - behaviour.UpdateTransform(transform.position, transform.rotation); - } - } - - #region Pickupable Implementation - - public override void OnGrab(InteractionContext context, Vector3 grabPoint) - { - if (!isInitialized) return; - behaviour.OnGrabbed(context); - } - - public override void OnDrop(InteractionContext context) - { - if (!isInitialized) return; - behaviour.OnDropped(); - } - - public override void OnFlingTowardsTarget(Vector3 target) - { - // ignore - } - - public override bool CanPickup => canPickup; - public override bool DisallowTheft => disallowTheft; - public override float MaxGrabDistance => maxGrabDistance; - public override float MaxPushDistance => maxPushDistance; - public override bool IsAutoHold => isAutoHold; - public override bool IsObjectRotationAllowed => allowRotation; - public override bool IsObjectPushPullAllowed => allowPushPull; - public override bool IsObjectInteractionAllowed => allowInteraction; - - #endregion Pickupable Implementation -} \ No newline at end of file diff --git a/LuaTTS/Main.cs b/LuaTTS/Main.cs index 2035bb9..6242c04 100644 --- a/LuaTTS/Main.cs +++ b/LuaTTS/Main.cs @@ -1,4 +1,6 @@ -using MelonLoader; +using ABI_RC.Scripting.ScriptNetwork; +using ABI_RC.Systems.ModNetwork; +using MelonLoader; using NAK.LuaTTS.Patches; namespace NAK.LuaTTS; @@ -8,6 +10,33 @@ public class LuaTTSMod : MelonMod public override void OnInitializeMelon() { ApplyPatches(typeof(LuaScriptFactoryPatches)); + + ModNetworkMessage.AddConverter(ReadScriptID, WriteScriptID); + ModNetworkMessage.AddConverter(ReadScriptInstanceID, WriteScriptInstanceID); + } + + private static ScriptID ReadScriptID(ModNetworkMessage msg) + { + msg.Read(out byte[] value); + ScriptID scriptID = new(value); + return scriptID; + } + + private static void WriteScriptID(ModNetworkMessage msg, ScriptID scriptID) + { + msg.Write(scriptID.value); + } + + private static ScriptInstanceID ReadScriptInstanceID(ModNetworkMessage msg) + { + msg.Read(out byte[] value); + ScriptInstanceID scriptInstanceID = new(value); + return scriptInstanceID; + } + + private static void WriteScriptInstanceID(ModNetworkMessage msg, ScriptInstanceID scriptInstanceID) + { + msg.Write(scriptInstanceID.value); } private void ApplyPatches(Type type) diff --git a/LuaTTS/Patches.cs b/LuaTTS/Patches.cs index 07d4297..c45cec1 100644 --- a/LuaTTS/Patches.cs +++ b/LuaTTS/Patches.cs @@ -11,17 +11,17 @@ internal static class LuaScriptFactoryPatches [HarmonyPostfix] [HarmonyPatch(typeof(LuaScriptFactory.CVRRequireModule), nameof(LuaScriptFactory.CVRRequireModule.Require))] private static void Postfix_CVRRequireModule_require( - string modid, + string moduleFriendlyName, ref LuaScriptFactory.CVRRequireModule __instance, ref object __result, - ref Script ___script, - ref CVRLuaContext ___context) + ref Script ____script, + ref CVRLuaContext ____context) { const string TTSModuleID = "TextToSpeech"; - if (TTSModuleID != modid) + if (TTSModuleID != moduleFriendlyName) return; // not our module - __result = TTSLuaModule.RegisterUserData(___script, ___context); + __result = TTSLuaModule.RegisterUserData(____script, ____context); __instance.RegisteredModules[TTSModuleID] = __result; // add module to cache } } \ No newline at end of file diff --git a/NAK_CVR_Mods.sln b/NAK_CVR_Mods.sln index ce1db86..082aeae 100644 --- a/NAK_CVR_Mods.sln +++ b/NAK_CVR_Mods.sln @@ -87,6 +87,34 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComponentMonitor", "Compone EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShareBubbles", "ShareBubbles\ShareBubbles.csproj", "{ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MutualMute", "MutualMute\MutualMute.csproj", "{6E315182-CC9F-4F62-8385-5E26EFA3B98A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BullshitWatcher", "BullshitWatcher\BullshitWatcher.csproj", "{09238300-4583-45C6-A997-025CBDC44C24}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LegacyContentMitigation", "LegacyContentMitigation\LegacyContentMitigation.csproj", "{21FDAB94-5014-488D-86C7-A366F1902B24}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RCCVirtualSteeringWheel", "RCCVirtualSteeringWheel\RCCVirtualSteeringWheel.csproj", "{4A378F81-3805-41E8-9565-A8A89A8C00D6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterContentLoading", "BetterContentLoading\BetterContentLoading.csproj", "{FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CameraExperiments", "CameraExperiments\CameraExperiments.csproj", "{71CBD7CC-C787-4796-B05E-4F3BC3C28B48}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteAvatarDisablingCameraOnFirstFrameFix", "RemoteAvatarDisablingCameraOnFirstFrameFix\RemoteAvatarDisablingCameraOnFirstFrameFix.csproj", "{42E626F7-9A7E-4F55-B02C-16EB56E2B540}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarCloneTest", "AvatarCloneTest\AvatarCloneTest.csproj", "{8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FuckOffUICamera", "FuckOffUICamera\FuckOffUICamera.csproj", "{262A8AE0-E610-405F-B4EC-DB714FB54C00}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomRichPresence", "CustomRichPresence\CustomRichPresence.csproj", "{E5F07862-5715-470D-B324-19BDEBB2AA4D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FuckMagicaCloth2", "FuckMagicaCloth2\FuckMagicaCloth2.csproj", "{21B591A0-F6E5-4645-BF2D-4E71F47394A7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperAwesomeMod", "SuperAwesomeMod\SuperAwesomeMod.csproj", "{F093BDE5-1824-459E-B86E-B9F79B548E58}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlToUnlockMouse", "ControlToUnlockMouse\ControlToUnlockMouse.csproj", "{EDA96974-0BEA-404B-8EED-F19CCA2C95A8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EzCurls", ".DepricatedMods\EzCurls\EzCurls.csproj", "{ED2CAA2D-4E49-4636-86C4-367D0CDC3572}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -261,6 +289,62 @@ Global {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Debug|Any CPU.Build.0 = Debug|Any CPU {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Release|Any CPU.ActiveCfg = Release|Any CPU {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Release|Any CPU.Build.0 = Release|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Release|Any CPU.Build.0 = Release|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Release|Any CPU.Build.0 = Release|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Release|Any CPU.Build.0 = Release|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Release|Any CPU.Build.0 = Release|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Release|Any CPU.Build.0 = Release|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Release|Any CPU.Build.0 = Release|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Release|Any CPU.Build.0 = Release|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Release|Any CPU.Build.0 = Release|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Release|Any CPU.Build.0 = Release|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Release|Any CPU.Build.0 = Release|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Release|Any CPU.Build.0 = Release|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Release|Any CPU.Build.0 = Release|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Release|Any CPU.Build.0 = Release|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs b/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs index 543ea43..cd32e4f 100644 --- a/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs +++ b/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs @@ -4,19 +4,19 @@ using BTKUILib.UIObjects; using BTKUILib.UIObjects.Components; using NAK.OriginShift; -namespace NAK.OriginShiftMod.Integrations +namespace NAK.OriginShiftMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon + private static Category _ourCategory; + + private static Button _ourMainButton; + private static bool _isForcedMode; + + private static ToggleButton _ourToggle; + + private static void Setup_OriginShiftModCategory(Page page) { - private static Category _ourCategory; - - private static Button _ourMainButton; - private static bool _isForcedMode; - - private static ToggleButton _ourToggle; - - private static void Setup_OriginShiftModCategory(Page page) - { // dear category _ourCategory = page.AddCategory(ModSettings.OSM_SettingsCategory, ModSettings.ModName, true, true, false); @@ -38,21 +38,21 @@ namespace NAK.OriginShiftMod.Integrations debugToggle.OnValueUpdated += OnDebugToggle; } - #region Category Actions + #region Category Actions - private static void UpdateCategoryModUserCount() - { + private static void UpdateCategoryModUserCount() + { int modUsers = 1; // we are always here :3 int playerCount = CVRPlayerManager.Instance.NetworkPlayers.Count + 1; // +1 for us :3 _ourCategory.CategoryName = $"{ModSettings.OSM_SettingsCategory} ({modUsers}/{playerCount})"; } - #endregion Category Actions + #endregion Category Actions - #region Button Actions + #region Button Actions - private static void SetButtonState(OriginShiftManager.OriginShiftState state) - { + private static void SetButtonState(OriginShiftManager.OriginShiftState state) + { switch (state) { default: @@ -74,8 +74,8 @@ namespace NAK.OriginShiftMod.Integrations } } - private static void OnMainButtonClick() - { + private static void OnMainButtonClick() + { // if active, return as world is using Origin Shift if (OriginShiftManager.Instance.CurrentState is OriginShiftManager.OriginShiftState.Active) @@ -97,19 +97,19 @@ namespace NAK.OriginShiftMod.Integrations } } - private static void OnOriginShiftStateChanged(OriginShiftManager.OriginShiftState state) - { + private static void OnOriginShiftStateChanged(OriginShiftManager.OriginShiftState state) + { _isForcedMode = state == OriginShiftManager.OriginShiftState.Forced; SetButtonState(state); SetToggleLocked(_isForcedMode); } - #endregion Button Actions + #endregion Button Actions - #region Toggle Actions + #region Toggle Actions - private static void SetToggleLocked(bool value) - { + private static void SetToggleLocked(bool value) + { if (value) { // lock the toggle @@ -126,20 +126,19 @@ namespace NAK.OriginShiftMod.Integrations } } - private static void OnCompatibilityModeToggle(bool value) - { + private static void OnCompatibilityModeToggle(bool value) + { ModSettings.EntryCompatibilityMode.Value = value; } - #endregion Toggle Actions + #endregion Toggle Actions - #region Debug Toggle Actions + #region Debug Toggle Actions - private static void OnDebugToggle(bool value) - { + private static void OnDebugToggle(bool value) + { OriginShiftManager.Instance.ToggleDebugOverlay(value); } - #endregion Debug Toggle Actions - } + #endregion Debug Toggle Actions } \ No newline at end of file diff --git a/OriginShift/Integrations/BTKUI/BtkuiAddon.cs b/OriginShift/Integrations/BTKUI/BtkuiAddon.cs index aa64098..f980330 100644 --- a/OriginShift/Integrations/BTKUI/BtkuiAddon.cs +++ b/OriginShift/Integrations/BTKUI/BtkuiAddon.cs @@ -3,23 +3,23 @@ using BTKUILib; using BTKUILib.UIObjects; using NAK.OriginShift; -namespace NAK.OriginShiftMod.Integrations -{ - public static partial class BtkUiAddon - { - private static Page _miscTabPage; - private static string _miscTabElementID; +namespace NAK.OriginShiftMod.Integrations; - public static void Initialize() - { +public static partial class BtkUiAddon +{ + private static Page _miscTabPage; + private static string _miscTabElementID; + + public static void Initialize() + { Prepare_Icons(); Setup_OriginShiftTab(); } - #region Initialization + #region Initialization - private static void Prepare_Icons() - { + private static void Prepare_Icons() + { QuickMenuAPI.PrepareIcon(ModSettings.ModName, "OriginShift-Icon-Active", GetIconStream("OriginShift-Icon-Active.png")); @@ -30,8 +30,8 @@ namespace NAK.OriginShiftMod.Integrations GetIconStream("OriginShift-Icon-Forced.png")); } - private static void Setup_OriginShiftTab() - { + private static void Setup_OriginShiftTab() + { _miscTabPage = QuickMenuAPI.MiscTabPage; _miscTabElementID = _miscTabPage.ElementID; QuickMenuAPI.UserJoin += OnUserJoinLeave; @@ -51,16 +51,15 @@ namespace NAK.OriginShiftMod.Integrations // Setup_DebugOptionsCategory(_miscTabPage); } - #endregion + #endregion - #region Player Count Display + #region Player Count Display - private static void OnWorldLeave() - => UpdateCategoryModUserCount(); + private static void OnWorldLeave() + => UpdateCategoryModUserCount(); - private static void OnUserJoinLeave(CVRPlayerEntity _) - => UpdateCategoryModUserCount(); + private static void OnUserJoinLeave(CVRPlayerEntity _) + => UpdateCategoryModUserCount(); - #endregion - } -} + #endregion +} \ No newline at end of file diff --git a/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs b/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs index a5cec73..823d41f 100644 --- a/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs +++ b/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs @@ -5,60 +5,59 @@ using BTKUILib.UIObjects.Components; using MelonLoader; using UnityEngine; -namespace NAK.OriginShiftMod.Integrations +namespace NAK.OriginShiftMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon - { - #region Melon Preference Helpers + #region Melon Preference Helpers - private static ToggleButton AddMelonToggle(ref Category category, MelonPreferences_Entry entry) - { + private static ToggleButton AddMelonToggle(ref Category category, MelonPreferences_Entry entry) + { ToggleButton toggle = category.AddToggle(entry.DisplayName, entry.Description, entry.Value); toggle.OnValueUpdated += b => entry.Value = b; return toggle; } - private static SliderFloat AddMelonSlider(ref Category category, MelonPreferences_Entry entry, float min, - float max, int decimalPlaces = 2, bool allowReset = true) - { + private static SliderFloat AddMelonSlider(ref Category category, MelonPreferences_Entry entry, float min, + float max, int decimalPlaces = 2, bool allowReset = true) + { SliderFloat slider = category.AddSlider(entry.DisplayName, entry.Description, Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset); slider.OnValueUpdated += f => entry.Value = f; return slider; } - private static Button AddMelonStringInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) - { + private static Button AddMelonStringInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) + { Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); button.OnPress += () => QuickMenuAPI.OpenKeyboard(entry.Value, s => entry.Value = s); return button; } - private static Button AddMelonNumberInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) - { + private static Button AddMelonNumberInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) + { Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); button.OnPress += () => QuickMenuAPI.OpenNumberInput(entry.DisplayName, entry.Value, f => entry.Value = f); return button; } - private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry entry, bool showHeader = true) - { + private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry entry, bool showHeader = true) + { Category category = page.AddCategory(entry.DisplayName, showHeader, true, entry.Value); category.OnCollapse += b => entry.Value = b; return category; } - #endregion Melon Preference Helpers + #endregion Melon Preference Helpers - #region Icon Utils + #region Icon Utils - private static Stream GetIconStream(string iconName) - { + private static Stream GetIconStream(string iconName) + { Assembly assembly = Assembly.GetExecutingAssembly(); string assemblyName = assembly.GetName().Name; return assembly.GetManifestResourceStream($"{assemblyName}.Resources.{iconName}"); } - #endregion Icon Utils - } + #endregion Icon Utils } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/OriginShiftController.cs b/OriginShift/OriginShift/Components/OriginShiftController.cs index 70784f3..568409a 100644 --- a/OriginShift/OriginShift/Components/OriginShiftController.cs +++ b/OriginShift/OriginShift/Components/OriginShiftController.cs @@ -7,45 +7,45 @@ using NAK.OriginShift.Utility; // Creator Exposed component -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftController : MonoBehaviour { - public class OriginShiftController : MonoBehaviour - { - public static OriginShiftController Instance { get; private set; } + public static OriginShiftController Instance { get; private set; } - #region Serialized Fields + #region Serialized Fields - [Header("Config / Shift Params")] + [Header("Config / Shift Params")] - [SerializeField] private bool _shiftVertical = true; - [SerializeField] [Range(10, 2500)] private int _shiftThreshold = 15; + [SerializeField] private bool _shiftVertical = true; + [SerializeField] [Range(10, 2500)] private int _shiftThreshold = 15; - [Header("Config / Scene Objects")] + [Header("Config / Scene Objects")] - [SerializeField] private bool _autoMoveSceneRoots = true; - [SerializeField] private Transform[] _toShiftTransforms = Array.Empty(); + [SerializeField] private bool _autoMoveSceneRoots = true; + [SerializeField] private Transform[] _toShiftTransforms = Array.Empty(); - [Header("Config / Additive Objects")] + [Header("Config / Additive Objects")] - [SerializeField] private bool _shiftRemotePlayers = true; - [SerializeField] private bool _shiftSpawnedObjects = true; + [SerializeField] private bool _shiftRemotePlayers = true; + [SerializeField] private bool _shiftSpawnedObjects = true; - #endregion Serialized Fields + #endregion Serialized Fields - #region Internal Fields + #region Internal Fields - internal bool IsForced { get; set; } + internal bool IsForced { get; set; } - #endregion Internal Fields + #endregion Internal Fields #if !UNITY_EDITOR - public static int ORIGIN_SHIFT_THRESHOLD = 15; + public static int ORIGIN_SHIFT_THRESHOLD = 15; - #region Unity Events + #region Unity Events - private void Awake() - { + private void Awake() + { if (Instance != null && Instance != this) { @@ -56,8 +56,8 @@ namespace NAK.OriginShift.Components Instance = this; } - private void Start() - { + private void Start() + { // set threshold (we can not support dynamic threshold change) ORIGIN_SHIFT_THRESHOLD = IsForced ? 1000 : _shiftThreshold; @@ -73,26 +73,26 @@ namespace NAK.OriginShift.Components AnchorAllStaticRenderers(); } - private void OnDestroy() - { + private void OnDestroy() + { OriginShiftManager.OnOriginShifted -= OnOriginShifted; OriginShiftManager.Instance.ResetManager(); } - #endregion Unity Events + #endregion Unity Events - #region Private Methods + #region Private Methods - private void GetAllSceneRootTransforms() - { + private void GetAllSceneRootTransforms() + { Scene scene = gameObject.scene; var sceneRoots = scene.GetRootGameObjects(); _toShiftTransforms = new Transform[sceneRoots.Length + 1]; // +1 for the static batch anchor for (var i = 0; i < sceneRoots.Length; i++) _toShiftTransforms[i] = sceneRoots[i].transform; } - private void AnchorAllStaticRenderers() - { + private void AnchorAllStaticRenderers() + { // create an anchor object at 0,0,0 Transform anchor = new GameObject("NAK.StaticBatchAnchor").transform; anchor.SetPositionAndRotation(Vector3.zero, Quaternion.identity); @@ -113,12 +113,12 @@ namespace NAK.OriginShift.Components } } - #endregion Private Methods + #endregion Private Methods - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShifted(Vector3 shift) - { + private void OnOriginShifted(Vector3 shift) + { foreach (Transform toShiftTransform in _toShiftTransforms) { if (toShiftTransform == null) continue; // skip nulls @@ -126,8 +126,7 @@ namespace NAK.OriginShift.Components } } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs b/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs index fd329bf..11fe6fc 100644 --- a/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs +++ b/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs @@ -1,56 +1,65 @@ -using JetBrains.Annotations; +using ABI.CCK.Components; +using JetBrains.Annotations; using UnityEngine; using UnityEngine.Events; #if !UNITY_EDITOR +using ABI_RC.Core.Util; using ABI_RC.Core.Util.AssetFiltering; #endif -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftEventReceiver : MonoBehaviour { - public class OriginShiftEventReceiver : MonoBehaviour - { - #region Serialized Fields + #region Serialized Fields - [SerializeField] private UnityEvent _onOriginShifted = new(); - [SerializeField] private bool _filterChunkBoundary; - [SerializeField] private Vector3 _chunkBoundaryMin = Vector3.zero; - [SerializeField] private Vector3 _chunkBoundaryMax = Vector3.one; + [SerializeField] private UnityEvent _onOriginShifted = new(); + [SerializeField] private bool _filterChunkBoundary; + [SerializeField] private Vector3 _chunkBoundaryMin = Vector3.zero; + [SerializeField] private Vector3 _chunkBoundaryMax = Vector3.one; - #endregion Serialized Fields + #endregion Serialized Fields #if !UNITY_EDITOR - #region Private Fields + #region Private Fields - private bool _isInitialized; + private bool _isInitialized; - #endregion Private Fields + #endregion Private Fields - #region Unity Events + #region Unity Events - private void OnEnable() - { + private void OnEnable() + { if (!_isInitialized) { - SharedFilter.SanitizeUnityEvents("OriginShiftEventReceiver", _onOriginShifted); + //SharedFilter.SanitizeUnityEvents("OriginShiftEventReceiver", _onOriginShifted); + + UnityEventsHelper.SanitizeUnityEvents("OriginShiftEventReceiver", + UnityEventsHelper.EventSource.Unknown, + this, + CVRWorld.Instance, + _onOriginShifted); + _isInitialized = true; } OriginShiftManager.OnOriginShifted += HandleOriginShifted; } - private void OnDisable() - { + private void OnDisable() + { OriginShiftManager.OnOriginShifted -= HandleOriginShifted; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void HandleOriginShifted(Vector3 shift) - { + private void HandleOriginShifted(Vector3 shift) + { if (_filterChunkBoundary && !IsWithinChunkBoundary(shift)) return; @@ -65,15 +74,14 @@ namespace NAK.OriginShift.Components } } - private bool IsWithinChunkBoundary(Vector3 shift) - { + private bool IsWithinChunkBoundary(Vector3 shift) + { return shift.x >= _chunkBoundaryMin.x && shift.x <= _chunkBoundaryMax.x && shift.y >= _chunkBoundaryMin.y && shift.y <= _chunkBoundaryMax.y && shift.z >= _chunkBoundaryMin.z && shift.z <= _chunkBoundaryMax.z; } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs b/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs index 819b351..c5f4c52 100644 --- a/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs +++ b/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs @@ -1,20 +1,20 @@ using UnityEngine; -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftParticleSystemReceiver : MonoBehaviour { - public class OriginShiftParticleSystemReceiver : MonoBehaviour - { #if !UNITY_EDITOR - // max particles count cause i said so 2 - private static readonly ParticleSystem.Particle[] _tempParticles = new ParticleSystem.Particle[10000]; + // max particles count cause i said so 2 + private static readonly ParticleSystem.Particle[] _tempParticles = new ParticleSystem.Particle[10000]; - private ParticleSystem[] _particleSystems; + private ParticleSystem[] _particleSystems; - #region Unity Events + #region Unity Events - private void Start() - { + private void Start() + { _particleSystems = GetComponentsInChildren(true); if (_particleSystems.Length == 0) { @@ -23,35 +23,34 @@ namespace NAK.OriginShift.Components } } - private void OnEnable() - { + private void OnEnable() + { OriginShiftManager.OnOriginShifted += OnOriginShifted; } - private void OnDisable() - { + private void OnDisable() + { OriginShiftManager.OnOriginShifted -= OnOriginShifted; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShifted(Vector3 offset) - { + private void OnOriginShifted(Vector3 offset) + { foreach (ParticleSystem particleSystem in _particleSystems) ShiftParticleSystem(particleSystem, offset); } - private static void ShiftParticleSystem(ParticleSystem particleSystem, Vector3 offset) - { + private static void ShiftParticleSystem(ParticleSystem particleSystem, Vector3 offset) + { int particleCount = particleSystem.GetParticles(_tempParticles); for (int i = 0; i < particleCount; i++) _tempParticles[i].position += offset; particleSystem.SetParticles(_tempParticles, particleCount); } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs b/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs index ae2ca54..7fdc939 100644 --- a/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs +++ b/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs @@ -1,17 +1,17 @@ using UnityEngine; -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftRigidbodyReceiver : MonoBehaviour { - public class OriginShiftRigidbodyReceiver : MonoBehaviour - { #if !UNITY_EDITOR - private Rigidbody _rigidbody; + private Rigidbody _rigidbody; - #region Unity Events + #region Unity Events - private void Start() - { + private void Start() + { _rigidbody = GetComponentInChildren(); if (_rigidbody == null) { @@ -20,27 +20,26 @@ namespace NAK.OriginShift.Components } } - private void OnEnable() - { + private void OnEnable() + { OriginShiftManager.OnOriginShifted += OnOriginShifted; } - private void OnDisable() - { + private void OnDisable() + { OriginShiftManager.OnOriginShifted -= OnOriginShifted; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShifted(Vector3 shift) - { + private void OnOriginShifted(Vector3 shift) + { _rigidbody.position += shift; } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs b/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs index da1140c..4c3b34d 100644 --- a/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs +++ b/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs @@ -1,20 +1,20 @@ using UnityEngine; -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftTrailRendererReceiver : MonoBehaviour { - public class OriginShiftTrailRendererReceiver : MonoBehaviour - { #if !UNITY_EDITOR - // max positions count cause i said so - private static readonly Vector3[] _tempPositions = new Vector3[10000]; + // max positions count cause i said so + private static readonly Vector3[] _tempPositions = new Vector3[10000]; - private TrailRenderer[] _trailRenderers; + private TrailRenderer[] _trailRenderers; - #region Unity Events + #region Unity Events - private void Start() - { + private void Start() + { _trailRenderers = GetComponentsInChildren(true); if (_trailRenderers.Length == 0) { @@ -23,35 +23,34 @@ namespace NAK.OriginShift.Components } } - private void OnEnable() - { + private void OnEnable() + { OriginShiftManager.OnOriginShifted += OnOriginShifted; } - private void OnDisable() - { + private void OnDisable() + { OriginShiftManager.OnOriginShifted -= OnOriginShifted; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShifted(Vector3 offset) - { + private void OnOriginShifted(Vector3 offset) + { foreach (TrailRenderer trailRenderer in _trailRenderers) ShiftTrailRenderer(trailRenderer, offset); } - private static void ShiftTrailRenderer(TrailRenderer trailRenderer, Vector3 offset) - { + private static void ShiftTrailRenderer(TrailRenderer trailRenderer, Vector3 offset) + { trailRenderer.GetPositions(_tempPositions); for (var i = 0; i < _tempPositions.Length; i++) _tempPositions[i] += offset; trailRenderer.SetPositions(_tempPositions); } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs b/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs index 1370e34..1e98ce7 100644 --- a/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs +++ b/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs @@ -1,34 +1,33 @@ using UnityEngine; -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftTransformReceiver : MonoBehaviour { - public class OriginShiftTransformReceiver : MonoBehaviour - { #if !UNITY_EDITOR - #region Unity Events + #region Unity Events - private void OnEnable() - { + private void OnEnable() + { OriginShiftManager.OnOriginShifted += OnOriginShifted; } - private void OnDisable() - { + private void OnDisable() + { OriginShiftManager.OnOriginShifted -= OnOriginShifted; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShifted(Vector3 shift) - { + private void OnOriginShifted(Vector3 shift) + { transform.position += shift; } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs b/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs index 2e78a6c..3fb90f1 100644 --- a/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs +++ b/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs @@ -1,16 +1,16 @@ using UnityEngine; -namespace NAK.OriginShift.Hacks -{ - public class OriginShiftOcclusionCullingDisabler : MonoBehaviour - { - private Camera _camera; - private bool _originalCullingState; - - #region Unity Events +namespace NAK.OriginShift.Hacks; - private void Start() - { +public class OriginShiftOcclusionCullingDisabler : MonoBehaviour +{ + private Camera _camera; + private bool _originalCullingState; + + #region Unity Events + + private void Start() + { _camera = GetComponent(); if (_camera == null) { @@ -21,25 +21,24 @@ namespace NAK.OriginShift.Hacks _originalCullingState = _camera.useOcclusionCulling; } - private void Awake() // we want to execute even if the component is disabled - { + private void Awake() // we want to execute even if the component is disabled + { OriginShiftManager.OnStateChanged += OnOriginShiftStateChanged; } - private void OnDestroy() - { + private void OnDestroy() + { OriginShiftManager.OnStateChanged -= OnOriginShiftStateChanged; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShiftStateChanged(OriginShiftManager.OriginShiftState state) - { + private void OnOriginShiftStateChanged(OriginShiftManager.OriginShiftState state) + { _camera.useOcclusionCulling = state != OriginShiftManager.OriginShiftState.Forced && _originalCullingState; } - #endregion Origin Shift Events - } + #endregion Origin Shift Events } \ No newline at end of file diff --git a/OriginShift/OriginShift/Player/OriginShiftMonitor.cs b/OriginShift/OriginShift/Player/OriginShiftMonitor.cs index a812e08..f2157a0 100644 --- a/OriginShift/OriginShift/Player/OriginShiftMonitor.cs +++ b/OriginShift/OriginShift/Player/OriginShiftMonitor.cs @@ -9,35 +9,35 @@ using UnityEngine; using ABI_RC.Systems.Movement; #endif -namespace NAK.OriginShift +namespace NAK.OriginShift; + +[DefaultExecutionOrder(int.MaxValue)] +public class OriginShiftMonitor : MonoBehaviour { - [DefaultExecutionOrder(int.MaxValue)] - public class OriginShiftMonitor : MonoBehaviour - { #if !UNITY_EDITOR - private PlayerSetup _playerSetup; - private BetterBetterCharacterController _characterController; + private PlayerSetup _playerSetup; + private BetterBetterCharacterController _characterController; #endif - #region Unity Events + #region Unity Events - private void Start() - { + private void Start() + { #if !UNITY_EDITOR - _playerSetup = GetComponent(); - _characterController = GetComponent(); + _playerSetup = GetComponent(); + _characterController = GetComponent(); #endif - OriginShiftManager.OnPostOriginShifted += OnPostOriginShifted; - } + OriginShiftManager.OnPostOriginShifted += OnPostOriginShifted; + } - private void OnDestroy() - { + private void OnDestroy() + { OriginShiftManager.OnPostOriginShifted -= OnPostOriginShifted; StopAllCoroutines(); } - private void Update() - { + private void Update() + { // in CVR use GetPlayerPosition to account for VR offset Vector3 position = PlayerSetup.Instance.GetPlayerPosition(); @@ -56,21 +56,20 @@ namespace NAK.OriginShift OriginShiftManager.Instance.ShiftOrigin(position); } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnPostOriginShifted(Vector3 shift) - { + private void OnPostOriginShifted(Vector3 shift) + { #if UNITY_EDITOR // shift our transform back transform.position += shift; #else - _characterController.OffsetBy(shift); - _playerSetup.OffsetAvatarMovementData(shift); + _characterController.OffsetBy(shift); + _playerSetup.OffsetAvatarMovementData(shift); #endif - } - - #endregion Origin Shift Events } + + #endregion Origin Shift Events } \ No newline at end of file diff --git a/OriginShift/Patches.cs b/OriginShift/Patches.cs index 8e17cb0..cd61791 100644 --- a/OriginShift/Patches.cs +++ b/OriginShift/Patches.cs @@ -10,6 +10,7 @@ using ABI_RC.Systems.GameEventSystem; using ABI_RC.Systems.Movement; using ABI.CCK.Components; using DarkRift; +using ECM2; using HarmonyLib; using NAK.OriginShift.Components; using NAK.OriginShift.Hacks; diff --git a/PhysicsGunMod/Components/ObjectSyncBridge.cs b/PhysicsGunMod/Components/ObjectSyncBridge.cs deleted file mode 100644 index fe3c563..0000000 --- a/PhysicsGunMod/Components/ObjectSyncBridge.cs +++ /dev/null @@ -1,92 +0,0 @@ -using ABI_RC.Core.Savior; -using ABI_RC.Core.Util; -using ABI.CCK.Components; -using UnityEngine; - -namespace NAK.PhysicsGunMod.Components; - -public class ObjectSyncBridge : MonoBehaviour -{ - private PhysicsGunInteractionBehavior _physicsGun; - - private void Start() - { - // find physics gun - if (!TryGetComponent(out _physicsGun)) - { - PhysicsGunMod.Logger.Msg("Failed to find physics gun!"); - Destroy(this); - return; - } - - // listen for events - _physicsGun.OnPreGrabbedObject = o => - { - bool canTakeOwnership = false; - - // - CVRObjectSync objectSync = o.GetComponentInParent(); - // if (objectSync != null - // && (objectSync.SyncType == 0 // check if physics synced or synced by us - // || objectSync.SyncedByMe)) - // canTakeOwnership = true; - // - CVRSpawnable spawnable = o.GetComponentInParent(); - // if (spawnable != null) - // { - // CVRSyncHelper.PropData propData = CVRSyncHelper.Props.Find(match => match.InstanceId == spawnable.instanceId); - // if (propData != null - // && (propData.syncType == 0 // check if physics synced or synced by us - // || propData.syncedBy == MetaPort.Instance.ownerId)) - // canTakeOwnership = true; - // } - // - CVRPickupObject pickup = o.GetComponentInParent(); - // if (pickup != null - // && (pickup.grabbedBy == MetaPort.Instance.ownerId // check if already grabbed by us - // || pickup.grabbedBy == "" || !pickup.disallowTheft)) // check if not grabbed or allows theft - // canTakeOwnership = true; - // - // if (!canTakeOwnership // if we can't take ownership, don't grab, unless there is no syncing at all (local object) - // && (objectSync || spawnable || pickup )) - // return false; - - if (pickup) - { - pickup.GrabbedBy = MetaPort.Instance.ownerId; - pickup._grabStartTime = Time.time; - } - if (spawnable) spawnable.isPhysicsSynced = true; - if (objectSync) objectSync.isPhysicsSynced = true; - - return true; - }; - - _physicsGun.OnObjectReleased = o => - { - // CVRObjectSync objectSync = o.GetComponentInParent(); - // if (objectSync != null && objectSync.SyncType == 0) - // objectSync.isPhysicsSynced = false; - // - // CVRSpawnable spawnable = o.GetComponentInParent(); - // if (spawnable != null) - // { - // CVRSyncHelper.PropData propData = CVRSyncHelper.Props.Find(match => match.InstanceId == spawnable.instanceId); - // if (propData != null && (propData.syncType == 0 || propData.syncedBy == MetaPort.Instance.ownerId)) - // spawnable.isPhysicsSynced = false; - // } - - // CVRPickupObject pickup = o.GetComponentInParent(); - // if (pickup != null && pickup.grabbedBy == MetaPort.Instance.ownerId) - // pickup.grabbedBy = ""; - - return false; - }; - } - - private void OnDestroy() - { - // stop listening for events - _physicsGun.OnObjectGrabbed = null; - } -} \ No newline at end of file diff --git a/PhysicsGunMod/Components/PhysicsGunInteractionBehavior.cs b/PhysicsGunMod/Components/PhysicsGunInteractionBehavior.cs deleted file mode 100644 index bce3321..0000000 --- a/PhysicsGunMod/Components/PhysicsGunInteractionBehavior.cs +++ /dev/null @@ -1,572 +0,0 @@ -using ABI_RC.Core.Player; -using ABI_RC.Systems.InputManagement; -using ABI.CCK.Attributes; -using UnityEngine; -using UnityEngine.Events; -using UnityEngine.Scripting.APIUpdating; - -/* - * Physics Gun script from repository - https://github.com/Laumania/Unity3d-PhysicsGun - * Created by: - * Mads Laumann, https://github.com/laumania - * WarmedxMints, https://github.com/WarmedxMints - * - * Original/initial script "Gravity Gun": https://pastebin.com/w1G8m3dH - * Original author: Jake Perry, reddit.com/user/nandos13 -*/ - -namespace NAK.PhysicsGunMod.Components; - -[CCKWhitelistComponent(spawnable: true)] -public class PhysicsGunInteractionBehavior : MonoBehaviour -{ - public static PhysicsGunInteractionBehavior Instance; - - [Header("LayerMask")] [Tooltip("The layer which the gun can grab objects from")] [SerializeField] - private LayerMask _grabLayer; - - [SerializeField] private Camera _camera; - - [Header("Input Setting")] [Space(10)] public KeyCode Rotate = KeyCode.R; - public KeyCode SnapRotation = KeyCode.LeftShift; - public KeyCode SwitchAxis = KeyCode.Tab; - public KeyCode RotateZ = KeyCode.Space; - public KeyCode RotationSpeedIncrease = KeyCode.LeftControl; - public KeyCode ResetRotation = KeyCode.LeftAlt; - - /// The rigidbody we are currently holding - private Rigidbody _grabbedRigidbody; - - /// The offset vector from the object's position to hit point, in local space - private Vector3 _hitOffsetLocal; - - /// The distance we are holding the object at - private float _currentGrabDistance; - - /// The interpolation state when first grabbed - private RigidbodyInterpolation _initialInterpolationSetting; - - /// The difference between player & object rotation, updated when picked up or when rotated by the player - private Quaternion _rotationDifference; - - /// The start point for the Laser. This will typically be on the end of the gun - [SerializeField] private Transform _laserStartPoint; - - /// Tracks player input to rotate current object. Used and reset every fixedupdate call - private Vector3 _rotationInput = Vector3.zero; - - [Header("Rotation Settings")] [Tooltip("Transform of the player, that rotations should be relative to")] - public Transform PlayerTransform; - - [SerializeField] private float _rotationSenstivity = 10f; - - public float SnapRotationDegrees = 45f; - [SerializeField] private float _snappedRotationSens = 25f; - [SerializeField] private float _rotationSpeed = 10f; - - private Quaternion _desiredRotation = Quaternion.identity; - - [SerializeField] [Tooltip("Input values above this will be considered and intentional change in rotation")] - private float _rotationTollerance = 0.8f; - - private bool m_UserRotation; - - public bool UserRotation - { - get => m_UserRotation; - private set - { - if (m_UserRotation == value) - return; - - m_UserRotation = value; - OnRotation?.Invoke(value); - } - } - - private bool m_SnapRotation; - - private bool _snapRotation - { - get => m_SnapRotation; - set - { - if (m_SnapRotation == value) - return; - - m_SnapRotation = value; - OnRotationSnapped?.Invoke(value); - } - } - - private bool m_RotationAxis; - - private bool _rotationAxis - { - get => m_RotationAxis; - set - { - if (m_RotationAxis == value) - return; - - m_RotationAxis = value; - OnAxisChanged?.Invoke(value); - } - } - - private Vector3 _lockedRot; - - private Vector3 _forward; - private Vector3 _up; - private Vector3 _right; - - //ScrollWheel ObjectMovement - private Vector3 _scrollWheelInput = Vector3.zero; - - [Header("Scroll Wheel Object Movement")] [Space(5)] [SerializeField] - private float _scrollWheelSensitivity = 5f; - - [SerializeField] [Tooltip("The min distance the object can be from the player")] - private float _minObjectDistance = 2.5f; - - /// The maximum distance at which a new object can be picked up - [SerializeField] [Tooltip("The maximum distance at which a new object can be picked up")] - private float _maxGrabDistance = 50f; - - private bool _distanceChanged; - - //Vector3.Zero and Vector2.zero create a new Vector3 each time they are called so these simply save that process and a small amount of cpu runtime. - private readonly Vector3 _zeroVector3 = Vector3.zero; - private readonly Vector3 _oneVector3 = Vector3.one; - private readonly Vector3 _zeroVector2 = Vector2.zero; - - private bool _justReleased; - private bool _wasKinematic; - - [Serializable] - public class BoolEvent : UnityEvent {} - - [Serializable] - public class GrabEvent : UnityEvent {} - - [Header("Events")] [Space(10)] - public BoolEvent OnRotation; - public BoolEvent OnRotationSnapped; - public BoolEvent OnAxisChanged; - - public GrabEvent OnObjectGrabbed; - public Func OnObjectReleased; - - // pre event for OnPreGrabbedObject, return false to cancel grab - public Func OnPreGrabbedObject; - // public Action OnGrabbedObject; - - //public properties for the Axis Arrows. These are optional and can be safely removed - // public Vector3 CurrentForward => _forward; - // public Vector3 CurrentUp => _up; - // public Vector3 CurrentRight => _right; - - /// The transfor of the rigidbody we are holding - public Transform CurrentGrabbedTransform { get; private set; } - - //public properties for the Line Renderer - public Vector3 StartPoint { get; private set; } - public Vector3 MidPoint { get; private set; } - public Vector3 EndPoint { get; private set; } - - private void Start() - { - if (Instance != null - && Instance != this) - { - Destroy(this); - return; - } - Instance = this; - gameObject.AddComponent(); - - _camera = PlayerSetup.Instance.GetActiveCamera().GetComponent(); - PlayerTransform = PlayerSetup.Instance.transform; // TODO: this might be fucked in VR - } - - private void OnDestroy() - { - if (Instance == this) - Instance = null; - } - - private void Update() - { - if (!Input.GetMouseButton(0)) - { - // We are not holding the mouse button. Release the object and return before checking for a new one - if (_grabbedRigidbody != null) ReleaseObject(); - - _justReleased = false; - return; - } - - if (_grabbedRigidbody == null && !_justReleased) - { - // We are not holding an object, look for one to pick up - Ray ray = CenterRay(); - RaycastHit hit; - - //Just so These aren't included in a build -#if UNITY_EDITOR - Debug.DrawRay(ray.origin, ray.direction * _maxGrabDistance, Color.blue, 0.01f); -#endif - if (Physics.Raycast(ray, out hit, _maxGrabDistance, _grabLayer)) - // Don't pick up kinematic rigidbodies (they can't move) - if (hit.rigidbody != null /*&& !hit.rigidbody.isKinematic*/) - { - // Check if we are allowed to pick up this object - if (OnPreGrabbedObject != null - && !OnPreGrabbedObject(hit.rigidbody.gameObject)) - return; - - // Track rigidbody's initial information - _grabbedRigidbody = hit.rigidbody; - _wasKinematic = _grabbedRigidbody.isKinematic; - _grabbedRigidbody.isKinematic = false; - _grabbedRigidbody.freezeRotation = true; - _initialInterpolationSetting = _grabbedRigidbody.interpolation; - _rotationDifference = Quaternion.Inverse(PlayerTransform.rotation) * _grabbedRigidbody.rotation; - _hitOffsetLocal = hit.transform.InverseTransformVector(hit.point - hit.transform.position); - _currentGrabDistance = hit.distance; // Vector3.Distance(ray.origin, hit.point); - CurrentGrabbedTransform = _grabbedRigidbody.transform; - // Set rigidbody's interpolation for proper collision detection when being moved by the player - _grabbedRigidbody.interpolation = RigidbodyInterpolation.Interpolate; - - OnObjectGrabbed?.Invoke(_grabbedRigidbody.gameObject); - -#if UNITY_EDITOR - Debug.DrawRay(hit.point, hit.normal * 10f, Color.red, 10f); -#endif - } - } - else if (_grabbedRigidbody != null) - { - UserRotation = Input.GetKey(Rotate); - - if (Input.GetKeyDown(Rotate)) - _desiredRotation = _grabbedRigidbody.rotation; - - if (Input.GetKey(ResetRotation)) - { - _desiredRotation = Quaternion.identity; - } - - // We are already holding an object, listen for rotation input - if (Input.GetKey(Rotate)) - { - var rotateZ = Input.GetKey(RotateZ); - - var increaseSens = Input.GetKey(RotationSpeedIncrease) ? 2.5f : 1f; - - if (Input.GetKeyDown(SwitchAxis)) - { - _rotationAxis = !_rotationAxis; - - OnAxisChanged?.Invoke(_rotationAxis); - } - - //Snap Object nearest _snapRotationDegrees - if (Input.GetKeyDown(SnapRotation)) - { - _snapRotation = true; - - Vector3 newRot = _grabbedRigidbody.transform.rotation.eulerAngles; - - newRot.x = Mathf.Round(newRot.x / SnapRotationDegrees) * SnapRotationDegrees; - newRot.y = Mathf.Round(newRot.y / SnapRotationDegrees) * SnapRotationDegrees; - newRot.z = Mathf.Round(newRot.z / SnapRotationDegrees) * SnapRotationDegrees; - - Quaternion rot = Quaternion.Euler(newRot); - - _desiredRotation = rot; - //_grabbedRigidbody.MoveRotation(rot); - } - else if (Input.GetKeyUp(SnapRotation)) - { - _snapRotation = false; - } - - var x = Input.GetAxisRaw("Mouse X"); - var y = Input.GetAxisRaw("Mouse Y"); - - if (Mathf.Abs(x) > _rotationTollerance) - { - _rotationInput.x = rotateZ ? 0f : x * _rotationSenstivity * increaseSens; - _rotationInput.z = rotateZ ? x * _rotationSenstivity * increaseSens : 0f; - } - - if (Mathf.Abs(y) > _rotationTollerance) _rotationInput.y = y * _rotationSenstivity * increaseSens; - } - else - { - _snapRotation = false; - } - - var direction = Input.GetAxis("Mouse ScrollWheel"); - - //Optional Keyboard inputs - if (Input.GetKeyDown(KeyCode.T)) - direction = -0.1f; - else if (Input.GetKeyDown(KeyCode.G)) - direction = 0.1f; - - if (Mathf.Abs(direction) > 0 && CheckObjectDistance(direction)) - { - _distanceChanged = true; - _scrollWheelInput = PlayerTransform.forward * (_scrollWheelSensitivity * direction); - } - else - { - _scrollWheelInput = _zeroVector3; - } - - if (Input.GetMouseButtonDown(1)) - { - //To prevent warnings in the inpector - _grabbedRigidbody.collisionDetectionMode = !_wasKinematic - ? CollisionDetectionMode.ContinuousSpeculative - : CollisionDetectionMode.Continuous; - _grabbedRigidbody.isKinematic = _wasKinematic = !_wasKinematic; - - _justReleased = true; - ReleaseObject(); - } - } - } - - private void FixedUpdate() - { - if (_grabbedRigidbody) - { - // We are holding an object, time to rotate & move it - Ray ray = CenterRay(); - - UpdateRotationAxis(); - -#if UNITY_EDITOR - Debug.DrawRay(_grabbedTransform.position, _up * 5f , Color.green); - Debug.DrawRay(_grabbedTransform.position, _right * 5f , Color.red); - Debug.DrawRay(_grabbedTransform.position, _forward * 5f , Color.blue); -#endif - // Apply any intentional rotation input made by the player & clear tracked input - Quaternion intentionalRotation = Quaternion.AngleAxis(_rotationInput.z, _forward) * - Quaternion.AngleAxis(_rotationInput.y, _right) * - Quaternion.AngleAxis(-_rotationInput.x, _up) * _desiredRotation; - Quaternion relativeToPlayerRotation = PlayerTransform.rotation * _rotationDifference; - - if (UserRotation && _snapRotation) - { - //Add mouse movement to vector so we can measure the amount of movement - _lockedRot += _rotationInput; - - //If the mouse has moved far enough to rotate the snapped object - if (Mathf.Abs(_lockedRot.x) > _snappedRotationSens || Mathf.Abs(_lockedRot.y) > _snappedRotationSens || - Mathf.Abs(_lockedRot.z) > _snappedRotationSens) - { - for (var i = 0; i < 3; i++) - if (_lockedRot[i] > _snappedRotationSens) - _lockedRot[i] += SnapRotationDegrees; - else if (_lockedRot[i] < -_snappedRotationSens) - _lockedRot[i] += -SnapRotationDegrees; - else - _lockedRot[i] = 0; - - Quaternion q = Quaternion.AngleAxis(-_lockedRot.x, _up) * - Quaternion.AngleAxis(_lockedRot.y, _right) * - Quaternion.AngleAxis(_lockedRot.z, _forward) * _desiredRotation; - - Vector3 newRot = q.eulerAngles; - - newRot.x = Mathf.Round(newRot.x / SnapRotationDegrees) * SnapRotationDegrees; - newRot.y = Mathf.Round(newRot.y / SnapRotationDegrees) * SnapRotationDegrees; - newRot.z = Mathf.Round(newRot.z / SnapRotationDegrees) * SnapRotationDegrees; - - _desiredRotation = Quaternion.Euler(newRot); - - _lockedRot = _zeroVector2; - } - } - else - { - //Rotate the object to remain consistent with any changes in player's rotation - _desiredRotation = UserRotation ? intentionalRotation : relativeToPlayerRotation; - } - - // Remove all torque, reset rotation input & store the rotation difference for next FixedUpdate call - _grabbedRigidbody.angularVelocity = _zeroVector3; - _rotationInput = _zeroVector2; - _rotationDifference = Quaternion.Inverse(PlayerTransform.rotation) * _desiredRotation; - - // Calculate object's center position based on the offset we stored - // NOTE: We need to convert the local-space point back to world coordinates - // Get the destination point for the point on the object we grabbed - Vector3 holdPoint = ray.GetPoint(_currentGrabDistance) + _scrollWheelInput; - Vector3 centerDestination = holdPoint - CurrentGrabbedTransform.TransformVector(_hitOffsetLocal); - -#if UNITY_EDITOR - Debug.DrawLine(ray.origin, holdPoint, Color.blue, Time.fixedDeltaTime); -#endif - // Find vector from current position to destination - Vector3 toDestination = centerDestination - CurrentGrabbedTransform.position; - - // Calculate force - Vector3 force = toDestination / Time.fixedDeltaTime * 0.3f/* / _grabbedRigidbody.mass*/; - - //force += _scrollWheelInput; - // Remove any existing velocity and add force to move to final position - _grabbedRigidbody.velocity = _zeroVector3; - _grabbedRigidbody.AddForce(force, ForceMode.VelocityChange); - - //Rotate object - RotateGrabbedObject(); - - //We need to recalculte the grabbed distance as the object distance from the player has been changed - if (_distanceChanged) - { - _distanceChanged = false; - _currentGrabDistance = Vector3.Distance(ray.origin, holdPoint); - } - - //Update public properties - StartPoint = _laserStartPoint.transform.position; - MidPoint = holdPoint; - EndPoint = CurrentGrabbedTransform.TransformPoint(_hitOffsetLocal); - } - } - - private void RotateGrabbedObject() - { - if (_grabbedRigidbody == null) - return; - - // lerp to desired rotation - _grabbedRigidbody.MoveRotation(Quaternion.Lerp(_grabbedRigidbody.rotation, _desiredRotation, - Time.fixedDeltaTime * _rotationSpeed)); - } - - //Update Rotation axis based on movement - private void UpdateRotationAxis() - { - if (!_snapRotation) - { - _forward = PlayerTransform.forward; - _right = PlayerTransform.right; - _up = PlayerTransform.up; - - return; - } - - if (_rotationAxis) - { - _forward = CurrentGrabbedTransform.forward; - _right = CurrentGrabbedTransform.right; - _up = CurrentGrabbedTransform.up; - - return; - } - - NearestTranformDirection(CurrentGrabbedTransform, PlayerTransform, ref _up, ref _forward, ref _right); - } - - private void NearestTranformDirection(Transform transformToCheck, Transform referenceTransform, ref Vector3 up, - ref Vector3 forward, ref Vector3 right) - { - var directions = new List - { - transformToCheck.forward, - -transformToCheck.forward, - transformToCheck.up, - -transformToCheck.up, - transformToCheck.right, - -transformToCheck.right - }; - - //Find the up Vector - up = GetDirectionVector(directions, referenceTransform.up); - //Remove Vectors from list to prevent duplicates and the opposite vector being found in case where the player is at around a 45 degree angle to the object - directions.Remove(up); - directions.Remove(-up); - //Find the Forward Vector - forward = GetDirectionVector(directions, referenceTransform.forward); - //Remove used directions - directions.Remove(forward); - directions.Remove(-forward); - - right = GetDirectionVector(directions, referenceTransform.right); - } - - private Vector3 GetDirectionVector(List directions, Vector3 direction) - { - var maxDot = -Mathf.Infinity; - Vector3 ret = Vector3.zero; - - for (var i = 0; i < directions.Count; i++) - { - var dot = Vector3.Dot(direction, directions[i]); - - if (dot > maxDot) - { - ret = directions[i]; - maxDot = dot; - } - } - - return ret; - } - - /// Ray from center of the main camera's viewport forward - private Ray CenterRay() - { - return _camera.ViewportPointToRay(_oneVector3 * 0.5f); - } - - //Check distance is within range when moving object with the scroll wheel - private bool CheckObjectDistance(float direction) - { - Vector3 pointA = PlayerTransform.position; - Vector3 pointB = _grabbedRigidbody.position; - - var distance = Vector3.Distance(pointA, pointB); - - if (direction > 0) - return distance <= _maxGrabDistance; - - if (direction < 0) - return distance >= _minObjectDistance; - - return false; - } - - private void ReleaseObject() - { - if (OnObjectReleased != null) - OnObjectReleased(_grabbedRigidbody.gameObject); - - if (_grabbedRigidbody) - { - //Move rotation to desired rotation in case the lerp hasn't finished - //_grabbedRigidbody.MoveRotation(_desiredRotation); - // Reset the rigidbody to how it was before we grabbed it - _grabbedRigidbody.isKinematic = _wasKinematic; - _grabbedRigidbody.interpolation = _initialInterpolationSetting; - _grabbedRigidbody.freezeRotation = false; - _grabbedRigidbody = null; - } - - _scrollWheelInput = _zeroVector3; - CurrentGrabbedTransform = null; - UserRotation = false; - _snapRotation = false; - StartPoint = _zeroVector3; - MidPoint = _zeroVector3; - EndPoint = _zeroVector3; - - OnObjectGrabbed?.Invoke(null); - } -} \ No newline at end of file diff --git a/PhysicsGunMod/HarmonyPatches.cs b/PhysicsGunMod/HarmonyPatches.cs deleted file mode 100644 index 73a618c..0000000 --- a/PhysicsGunMod/HarmonyPatches.cs +++ /dev/null @@ -1,20 +0,0 @@ -using ABI_RC.Systems.InputManagement; -using HarmonyLib; -using NAK.PhysicsGunMod.Components; -using UnityEngine; - -namespace NAK.PhysicsGunMod.HarmonyPatches; - -internal static class CVRInputManagerPatches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(CVRInputManager), nameof(CVRInputManager.Update))] - private static void Postfix_CVRInputManager_Update(ref CVRInputManager __instance) - { - if (PhysicsGunInteractionBehavior.Instance == null) - return; - - if (PhysicsGunInteractionBehavior.Instance.UserRotation) - __instance.lookVector = Vector2.zero; - } -} diff --git a/PhysicsGunMod/Main.cs b/PhysicsGunMod/Main.cs deleted file mode 100644 index b431ca1..0000000 --- a/PhysicsGunMod/Main.cs +++ /dev/null @@ -1,43 +0,0 @@ -using ABI_RC.Core.Util.AssetFiltering; -using MelonLoader; -using NAK.PhysicsGunMod.Components; -using NAK.PhysicsGunMod.HarmonyPatches; - -namespace NAK.PhysicsGunMod; - -public class PhysicsGunMod : MelonMod -{ - internal static MelonLogger.Instance Logger; - - public override void OnInitializeMelon() - { - Logger = LoggerInstance; - - // // add to prop whitelist - // //SharedFilter._spawnableWhitelist.Add(typeof(PhysicsGunInteractionBehavior)); - // - // // add to event whitelist - // SharedFilter._allowedEventComponents.Add(typeof(PhysicsGunInteractionBehavior)); - // SharedFilter._allowedEventFunctions.Add(typeof(PhysicsGunInteractionBehavior), new List - // { - // "set_enabled", - // // TODO: expose more methods like release ? - // }); - - // apply patches - ApplyPatches(typeof(CVRInputManagerPatches)); - } - - private void ApplyPatches(Type type) - { - try - { - HarmonyInstance.PatchAll(type); - } - catch (Exception e) - { - LoggerInstance.Msg($"Failed while patching {type.Name}!"); - LoggerInstance.Error(e); - } - } -} \ No newline at end of file diff --git a/PhysicsGunMod/ModSettings.cs b/PhysicsGunMod/ModSettings.cs deleted file mode 100644 index 86e4b48..0000000 --- a/PhysicsGunMod/ModSettings.cs +++ /dev/null @@ -1,12 +0,0 @@ -using MelonLoader; - -namespace NAK.PhysicsGunMod; - -internal static class ModSettings -{ - internal const string ModName = nameof(PhysicsGunMod); - internal const string ASM_SettingsCategory = "Physics Gun Mod"; - - private static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(ModName); -} \ No newline at end of file diff --git a/PhysicsGunMod/PhysicsGunMod.csproj b/PhysicsGunMod/PhysicsGunMod.csproj deleted file mode 100644 index 22588f8..0000000 --- a/PhysicsGunMod/PhysicsGunMod.csproj +++ /dev/null @@ -1,37 +0,0 @@ - - - - - netstandard2.1 - - - - - - - - - - - - - - - - - - - - - - - $(MsBuildThisFileDirectory)\..\.ManagedLibs\BTKUILib.dll - False - - - $(MsBuildThisFileDirectory)\..\.ManagedLibs\ActionMenu.dll - False - - - - \ No newline at end of file diff --git a/PhysicsGunMod/README.md b/PhysicsGunMod/README.md deleted file mode 100644 index eca47c9..0000000 --- a/PhysicsGunMod/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# AvatarScaleMod - -Proof of concept mod to add Avatar Scaling to any avatar. This is local-only, but I may toy with using Mod Network. - -Legit threw this together in three hours. ChilloutVR handles all the hard stuff already with its existing animation-clip-based Avatar Scaling. - -https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/7405cef5-fd68-4103-8c18-b3164029eab1 - -## Notes: -* Constraint scaling partially conflicts with avatars run through my [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool). -* This is local-only, at least unless I bother with Mod Network. -* The entire thing is pretty messy and I am unsure of the performance impact, especially with scaling all lights, audio, & constraints. - -## Relevant Feedback Posts: -https://feedback.abinteractive.net/p/built-in-avatar-scaling-system - -This mod is me creating the system I wanted when I wrote the above feedback post. - ---- - -Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. -https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games - -> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. - -> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. - -> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/PhysicsGunMod/format.json b/PhysicsGunMod/format.json deleted file mode 100644 index b1de45e..0000000 --- a/PhysicsGunMod/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": 126, - "name": "BetterCalibration", - "modversion": "1.0.0", - "gameversion": "2022r173", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Mod to improve the calibration process for FBT.", - "searchtags": [ - "IK", - "FBT", - "VRIK", - "calibration", - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r3/BetterCalibration.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/BetterCalibration/", - "changelog": "", - "embedcolor": "9b59b6" -} \ No newline at end of file diff --git a/PlayerColorsAPI/Main.cs b/PlayerColorsAPI/Main.cs new file mode 100644 index 0000000..9e5634d --- /dev/null +++ b/PlayerColorsAPI/Main.cs @@ -0,0 +1,44 @@ +using System; +using MelonLoader; + +namespace NAK.VisualCloneFix; + +public class VisualCloneFixMod : MelonMod +{ + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(VisualCloneFix)); + + internal static readonly MelonPreferences_Entry EntryUseVisualClone = + Category.CreateEntry("use_visual_clone", true, + "Use Visual Clone", description: "Uses the potentially faster Visual Clone setup for the local avatar."); + + #endregion Melon Preferences + + #region Melon Events + + public override void OnInitializeMelon() + { + ApplyPatches(typeof(Patches)); // slapped together a fix cause HarmonyInstance.Patch was null ref for no reason? + } + + #endregion Melon Events + + #region Melon Mod Utilities + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } + + #endregion Melon Mod Utilities +} \ No newline at end of file diff --git a/VisualCloneFix/Patches.cs b/PlayerColorsAPI/Patches.cs similarity index 100% rename from VisualCloneFix/Patches.cs rename to PlayerColorsAPI/Patches.cs diff --git a/PlayerColorsAPI/PlayerColorsAPI.csproj b/PlayerColorsAPI/PlayerColorsAPI.csproj new file mode 100644 index 0000000..8dc4bcd --- /dev/null +++ b/PlayerColorsAPI/PlayerColorsAPI.csproj @@ -0,0 +1,6 @@ + + + + LocalCloneFix + + diff --git a/PlayerColorsAPI/Properties/AssemblyInfo.cs b/PlayerColorsAPI/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..10b75bb --- /dev/null +++ b/PlayerColorsAPI/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.VisualCloneFix.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.VisualCloneFix))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.VisualCloneFix))] + +[assembly: MelonInfo( + typeof(NAK.VisualCloneFix.VisualCloneFixMod), + nameof(NAK.VisualCloneFix), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/VisualCloneFix" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.VisualCloneFix.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.1"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/PlayerColorsAPI/README.md b/PlayerColorsAPI/README.md new file mode 100644 index 0000000..cc12a9c --- /dev/null +++ b/PlayerColorsAPI/README.md @@ -0,0 +1,18 @@ +# VisualCloneFix + +Fixes the Visual Clone system and allows you to use it again. + +Using the Visual Clone should be faster than the default Head Hiding & Shadow Clones, but will add a longer hitch on initial avatar load. + +**NOTE:** The Visual Clone is still an experimental feature that was temporarily removed in [ChilloutVR 2024r175 Hotfix 1](https://abinteractive.net/blog/chilloutvr_2024r175_hotfix_1), so there may be bugs or issues with it. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/PlayerColorsAPI/format.json b/PlayerColorsAPI/format.json new file mode 100644 index 0000000..6634e9f --- /dev/null +++ b/PlayerColorsAPI/format.json @@ -0,0 +1,23 @@ +{ + "_id": 221, + "name": "VisualCloneFix", + "modversion": "1.0.1", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes the Visual Clone system and allows you to use it again.\n\nUsing the Visual Clone should be faster than the default Head Hiding & Shadow Clones, but will add a longer hitch on initial avatar load.\n\n**NOTE:** The Visual Clone is still an experimental feature that was temporarily removed in [ChilloutVR 2024r175 Hotfix 1](https://abinteractive.net/blog/chilloutvr_2024r175_hotfix_1), so there may be bugs or issues with it.", + "searchtags": [ + "visual", + "clone", + "head", + "hiding" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r36/VisualCloneFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/VisualCloneFix/", + "changelog": "- Fixed FPRExclusions IsShown state being inverted when toggled.\n- Fixed head FPRExclusion generation not checking for existing exclusion.\n- Sped up FindExclusionVertList by 100x by not being an idiot. This heavily reduces avatar hitch with Visual Clone active.", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/Portals/format.json b/Portals/format.json deleted file mode 100644 index d3c7457..0000000 --- a/Portals/format.json +++ /dev/null @@ -1 +0,0 @@ - "None" diff --git a/References.Items.props b/References.Items.props index b618151..275c721 100644 --- a/References.Items.props +++ b/References.Items.props @@ -196,6 +196,18 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\PICO.Platform.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\Pico.Spatializer.dll + False + + + $(MsBuildThisFileDirectory)\.ManagedLibs\Pico.Spatializer.Example.dll + False + + + $(MsBuildThisFileDirectory)\.ManagedLibs\PICO.TobSupport.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\PWCommon3DLL.dll False @@ -396,6 +408,10 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.InputSystem.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.InputSystem.ForUI.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.InternalAPIEngineBridge.002.dll False @@ -584,6 +600,10 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.Hands.Samples.VisualizerSample.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.Interaction.Toolkit.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.Management.dll False @@ -616,16 +636,12 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.OpenXR.Features.OculusQuestSupport.dll False - - $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.OpenXR.Features.PICOSupport.dll - False - $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.OpenXR.Features.RuntimeDebugger.dll False - - $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.OpenXRPico.dll + + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.PICO.dll False diff --git a/SmootherRay/Main.cs b/SmootherRay/Main.cs index b1b1056..eb6c36a 100644 --- a/SmootherRay/Main.cs +++ b/SmootherRay/Main.cs @@ -39,6 +39,10 @@ public class SmootherRayMod : MelonMod Category.CreateEntry("Small Angle Threshold (6f)", 6f, description: "Angle difference to consider a 'small' movement. The less shaky your hands are, the lower you probably want to set this. This is probably the primary value you want to tweak. Use the slider to adjust the threshold angle. Range: 4 to 15."); + public static readonly MelonPreferences_Entry EntrySmoothWhenHoldingPickup = + Category.CreateEntry("Smooth When Holding Pickup", false, + description: "Enable or disable smoothing when holding a pickup."); + #endregion Melon Preferences #region Melon Events diff --git a/SmootherRay/Properties/AssemblyInfo.cs b/SmootherRay/Properties/AssemblyInfo.cs index 57dbe09..d7f1704 100644 --- a/SmootherRay/Properties/AssemblyInfo.cs +++ b/SmootherRay/Properties/AssemblyInfo.cs @@ -28,6 +28,6 @@ namespace NAK.SmootherRay.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.5"; + public const string Version = "1.0.6"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/SmootherRay/SmootherRayer.cs b/SmootherRay/SmootherRayer.cs index 44ef320..6262824 100644 --- a/SmootherRay/SmootherRayer.cs +++ b/SmootherRay/SmootherRayer.cs @@ -227,6 +227,10 @@ public class SmootherRayer : MonoBehaviour } } + if (SmootherRayMod.EntrySmoothWhenHoldingPickup.Value + && ray.grabbedObject) + canSmoothRay = true; + return canSmoothRay; } diff --git a/Stickers/Stickers/Networking/ModNetwork.Inbound.cs b/Stickers/Stickers/Networking/ModNetwork.Inbound.cs index e769006..57b355c 100644 --- a/Stickers/Stickers/Networking/ModNetwork.Inbound.cs +++ b/Stickers/Stickers/Networking/ModNetwork.Inbound.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Player; using ABI_RC.Core.Savior; using ABI_RC.Systems.ModNetwork; using NAK.Stickers.Utilities; @@ -47,6 +48,9 @@ public static partial class ModNetwork if (StickerSystem.Instance.IsRestrictedInstance) // ignore messages from users when the world is restricted. This also includes older or modified version of Stickers mod. return false; + if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(sender, out PuppetMaster _)) + return false; // ignore messages from players that don't exist + return true; } @@ -108,7 +112,10 @@ public static partial class ModNetwork msg.Read(out Vector3 up); if (!StickerSystem.Instance.HasTextureHash(msg.Sender, textureHash)) + { SendRequestTexture(stickerSlot, textureHash); + StickerSystem.Instance.ClearStickersForPlayer(msg.Sender, stickerSlot); // Ensure no exploit + } StickerSystem.Instance.OnStickerPlaceReceived(msg.Sender, stickerSlot, position, forward, up); } @@ -158,7 +165,7 @@ public static partial class ModNetwork LoggerInbound($"Received StartTexture message from {sender}: Slot: {stickerSlot}, Hash: {textureHash}, Chunks: {chunkCount}, Resolution: {width}x{height}"); } - + private static void HandleSendTexture(ModNetworkMessage msg) { string sender = msg.Sender; diff --git a/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs b/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs index e8ab380..f2b5dd3 100644 --- a/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs +++ b/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs @@ -62,7 +62,7 @@ public partial class StickerSystem #endregion Player Callbacks - #region Player Callbacks + #region Sticker Callbacks public void OnStickerPlaceReceived(string playerId, int stickerSlot, Vector3 position, Vector3 forward, Vector3 up) => AttemptPlaceSticker(playerId, position, forward, up, alignWithNormal: true, stickerSlot); @@ -81,5 +81,5 @@ public partial class StickerSystem stickerData.IdentifyTime = Time.time + 3f; } - #endregion Player Callbacks + #endregion Sticker Callbacks } diff --git a/Stickers/Stickers/StickerSystem.StickerLifecycle.cs b/Stickers/Stickers/StickerSystem.StickerLifecycle.cs index df4ee96..5f350dd 100644 --- a/Stickers/Stickers/StickerSystem.StickerLifecycle.cs +++ b/Stickers/Stickers/StickerSystem.StickerLifecycle.cs @@ -110,7 +110,7 @@ public partial class StickerSystem stickerData.Clear(); } - private void ClearStickersForPlayer(string playerId, int stickerSlot) + public void ClearStickersForPlayer(string playerId, int stickerSlot) { if (!_playerStickers.TryGetValue(playerId, out StickerData stickerData)) return; diff --git a/ThirdPerson/CameraLogic.cs b/ThirdPerson/CameraLogic.cs index 24d10c5..f1b83ef 100644 --- a/ThirdPerson/CameraLogic.cs +++ b/ThirdPerson/CameraLogic.cs @@ -39,7 +39,6 @@ internal static class CameraLogic if (_state) _storedCamMask = _desktopCam.cullingMask; _desktopCam.cullingMask = _state ? 0 : _storedCamMask; - _uiCam.cullingMask = _state ? _uiCam.cullingMask & ~(1 << CVRLayers.PlayerClone) : _uiCam.cullingMask | (1 << CVRLayers.PlayerClone); _thirdPersonCam.gameObject.SetActive(_state); } } @@ -73,6 +72,9 @@ internal static class CameraLogic ThirdPerson.Logger.Msg("Copying active camera settings & components."); CVRTools.CopyToDestCam(activePlayerCam, _thirdPersonCam, true); + + // Remove PlayerClone + _thirdPersonCam.cullingMask &= ~(1 << CVRLayers.PlayerClone); if (!CheckIsRestricted()) return; diff --git a/ThirdPerson/Patches.cs b/ThirdPerson/Patches.cs index 9267d2e..60dc4dd 100644 --- a/ThirdPerson/Patches.cs +++ b/ThirdPerson/Patches.cs @@ -28,10 +28,6 @@ internal static class Patches typeof(CVRTools).GetMethod(nameof(CVRTools.ConfigureHudAffinity), BindingFlags.Public | BindingFlags.Static), postfix: typeof(Patches).GetMethod(nameof(OnConfigureHudAffinity), BindingFlags.NonPublic | BindingFlags.Static).ToNewHarmonyMethod() ); - harmony.Patch( - typeof(TransformHiderManager).GetMethod(nameof(TransformHiderManager.CheckPlayerCamWithinRange), BindingFlags.NonPublic | BindingFlags.Static), - prefix: typeof(Patches).GetMethod(nameof(OnCheckPlayerCamWithinRange), BindingFlags.NonPublic | BindingFlags.Static).ToNewHarmonyMethod() - ); } //Copy camera settings & postprocessing components @@ -39,5 +35,4 @@ internal static class Patches //Adjust camera distance with height as modifier private static void OnScaleAdjusted(float height) => AdjustScale(height); private static void OnConfigureHudAffinity() => CheckVRMode(); - private static bool OnCheckPlayerCamWithinRange() => !State; // don't hide head if in third person } \ No newline at end of file diff --git a/ThirdPerson/Properties/AssemblyInfo.cs b/ThirdPerson/Properties/AssemblyInfo.cs index ab34afe..6c055d1 100644 --- a/ThirdPerson/Properties/AssemblyInfo.cs +++ b/ThirdPerson/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ThirdPerson.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.9"; + public const string Version = "1.1.0"; public const string Author = "Davi & NotAKidoS"; } \ No newline at end of file