Compare commits

...

207 commits
r39 ... main

Author SHA1 Message Date
github-actions[bot]
226b369537 [NAK_CVR_Mods] Update mod list in README
Some checks failed
Update Mod List / update-modlist (push) Has been cancelled
2025-08-27 10:22:00 +00:00
NotAKidoS
e54e50e76d Merge remote-tracking branch 'origin/main' 2025-08-27 05:21:38 -05:00
NotAKidoS
6bef1d0c96 [Tinyboard] Initial release 2025-08-27 05:21:26 -05:00
github-actions[bot]
1496c25184 [NAK_CVR_Mods] Update mod list in README 2025-08-27 06:35:11 +00:00
NotAKidoS
c368daab4f killed RelativeSync, now its just RelativeSyncJitterFix 2025-08-27 01:34:56 -05:00
NotAKidoS
30c069388c [PathCamDisabler] Fixes for 2025r180 2025-08-27 01:23:56 -05:00
NotAKidoS
c9acb00088 [DoubleTapJumpToExitSeat] Fixes for 2025r180 2025-08-27 01:23:45 -05:00
NotAKidoS
4123a1f25d [ASTExtension] Fixes for 2025r180 2025-08-27 01:23:37 -05:00
NotAKidoS
7f5ca4b29d Merge remote-tracking branch 'origin/main'
Some checks failed
Update Mod List / update-modlist (push) Has been cancelled
2025-08-20 12:31:14 -05:00
NotAKidoS
6dc7f8a267 [ShareBubbles] Updated format.json 2025-08-20 12:31:04 -05:00
github-actions[bot]
6ad23e6fc5 [NAK_CVR_Mods] Update mod list in README 2025-08-20 17:09:37 +00:00
NotAKidoS
2f668b289c [YouAreMyPropNowWeAreHavingSoftTacosLater] Updated README.md 2025-08-20 12:09:14 -05:00
NotAKidoS
6d28f734da [YouAreMyPropNowWeAreHavingSoftTacosLater] Updated format.json 2025-08-20 00:04:03 -05:00
NotAKidoS
969bd00df3 [YouAreMyPropNowWeAreHavingSoftTacosLater] Updated format.json 2025-08-19 23:57:04 -05:00
NotAKidoS
7deddd88ea [CustomSpawnPoint] Fixes for 2025r180 2025-08-19 23:47:06 -05:00
NotAKidoS
1a591749c6 [YouAreMyPropNowWeAreHavingSoftTacosLater] Update format.json 2025-08-19 23:42:54 -05:00
NotAKidoS
218344a121 [ShareBubbles] Updated format.json 2025-08-19 23:41:03 -05:00
NotAKidoS
07daceea44 [ScrollFlight] Fixes for 2025r180 2025-08-19 23:35:04 -05:00
NotAKidoS
aaeb187b9e [PropUndoButton] Fixes for 2025r180 2025-08-19 23:34:19 -05:00
NotAKidoS
e378a717d3 [RCCVirtualSteeringWheel] Fixes for 2025r180 2025-08-19 23:34:09 -05:00
NotAKidoS
a0a859aa86 [ShareBubbles] Fixes for 2025r180 2025-08-19 23:33:53 -05:00
NotAKidoS
13e206cd58 [ThirdPerson] Updated format.json 2025-08-19 23:33:42 -05:00
NotAKidoS
548fcf72bc [ThirdPerson] Updated format.json 2025-08-19 23:31:07 -05:00
NotAKidoS
ee4df06d2e [ThirdPerson] Fixes for r180 2025-08-19 23:30:16 -05:00
NotAKidoS
faf9d48fb6 [YouAreMyPropNowWeAreHavingSoftTacosLater] initial release 2025-08-19 23:30:02 -05:00
NotAKidoS
c455d20f9c [ThirdPerson] update format.json 2025-07-15 21:13:55 -05:00
NotAKidoS
0cdef04a53 Create DepthCameraFix.cs 2025-07-15 21:02:05 -05:00
NotAKidoS
e96a0e164d [ThirdPerson] Fixed for Stable and Nightly, did some cleanup
- Adjusted the local player scaled event patch to work both on Stable and Nightly
2025-07-15 21:02:03 -05:00
NotAKidoS
bf877124c1 Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods
Some checks failed
Update Mod List / update-modlist (push) Has been cancelled
2025-05-08 17:36:37 -05:00
NotAKidoS
cc7762293d [LuaNetworkVariables] fixed readmoe 2025-05-08 17:36:28 -05:00
github-actions[bot]
b75dce1d02 [NAK_CVR_Mods] Update mod list in README 2025-05-08 22:16:07 +00:00
NotAKidoS
0a01534aa4 [LuaNetworkVariables] rename classes 2025-05-08 17:15:52 -05:00
NotAKidoS
8b34359d1b Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-29 00:33:45 -05:00
NotAKidoS
d54ec06190 [ShareBubbles] no send shit if no people 2025-04-29 00:33:43 -05:00
NotAKidoS
daf2d7db0f
Merge pull request #36 from SketchFoxsky/main
updated seated calibration pose
2025-04-25 07:47:34 -05:00
SketchFoxsky
bdf6b0e51a updated seated calibration 2025-04-24 23:29:32 -04:00
github-actions[bot]
abd7b9d674 [NAK_CVR_Mods] Update mod list in README
Some checks failed
Update Mod List / update-modlist (push) Has been cancelled
2025-04-25 02:15:00 +00:00
NotAKidoS
da6520beb0 [ConfigureCalibrationPose] initial builds 2025-04-24 21:14:49 -05:00
NotAKidoS
3521453010 [ASTExtension] Fix no supported parameter found spam 2025-04-24 21:14:35 -05:00
NotAKidoS
0f6006db83 [CVRLuaToolsExtension] kinda fix 2025-04-24 21:14:17 -05:00
NotAKidoS
e85c1e2f25 [LuaNetworkVariables] Remove exp stuff, fix context properties 2025-04-14 18:11:23 -05:00
NotAKidoS
ece15e0dfc [YouAreMyPropNowWeAreHavingSoftTacosLater] fix for relative sync
Some checks failed
Update Mod List / update-modlist (push) Has been cancelled
2025-04-12 17:01:33 -05:00
NotAKidoS
47b69dfbc7 [RelativeSync] add support for YouAreMyPropNowWeAreHavingSoftTacosLaterMod 2025-04-12 17:01:24 -05:00
NotAKidoS
63948ddf69 Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-12 16:41:11 -05:00
NotAKidoS
f6afea3c44 [FuckToes] fix format.json 2025-04-12 16:41:05 -05:00
github-actions[bot]
8343d6c5bb [NAK_CVR_Mods] Update mod list in README 2025-04-12 21:38:33 +00:00
NotAKidoS
6e37bcbabb [FuckToes] i guess bring this back 2025-04-12 16:38:19 -05:00
NotAKidoS
c4ab9cce47 [DoubleTapJumpToExitSeat] fix format.json 2025-04-12 16:23:00 -05:00
NotAKidoS
88f3b1a41f Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-12 16:20:58 -05:00
NotAKidoS
9606b10c9d [NAK_CVR_Mods] update solution 2025-04-12 16:20:56 -05:00
github-actions[bot]
d5d4e3eddd [NAK_CVR_Mods] Update mod list in README 2025-04-12 21:20:39 +00:00
NotAKidoS
377b365cdc [YouAreMyPropNowWeAreHavingSoftTacosLater] fix accessors 2025-04-12 16:20:37 -05:00
NotAKidoS
21b791083b [DoubleTapJumpToExitSeat] bump for release 2025-04-12 16:20:22 -05:00
github-actions[bot]
8ad74b5ef6 [NAK_CVR_Mods] Update mod list in README
Some checks are pending
Update Mod List / update-modlist (push) Waiting to run
2025-04-12 09:29:46 +00:00
NotAKidoS
134c8e7878 Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-12 04:29:32 -05:00
NotAKidoS
1f8435edb9 nvm 2025-04-12 04:29:25 -05:00
github-actions[bot]
446a89f35d [NAK_CVR_Mods] Update mod list in README 2025-04-12 09:06:01 +00:00
NotAKidoS
1f99312c22 [WindowFocusCheckFix] iniyial push 2025-04-12 04:05:48 -05:00
NotAKidoS
a6fa59d24c Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-12 03:33:12 -05:00
NotAKidoS
89b8f19288 [YouAreMyPropNowWeAreHavingSoftTacosLaterMod] added settingd 2025-04-12 03:33:10 -05:00
github-actions[bot]
8764339ac8 [NAK_CVR_Mods] Update mod list in README 2025-04-12 07:41:58 +00:00
NotAKidoS
a8e0553e53 [DoubleTapJumpToExitSeat] Initial push 2025-04-12 02:41:43 -05:00
github-actions[bot]
2af27cc81d [NAK_CVR_Mods] Update mod list in README
Some checks are pending
Update Mod List / update-modlist (push) Waiting to run
2025-04-11 12:52:38 +00:00
NotAKidoS
784249a08b Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-11 07:52:21 -05:00
NotAKidoS
1fbfcd80cd [NAK_CVR_Mods] 2 2025-04-11 07:52:15 -05:00
github-actions[bot]
d5eb9ae1a0 [NAK_CVR_Mods] Update mod list in README 2025-04-11 12:47:11 +00:00
NotAKidoS
88faf93b3b Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-11 07:46:57 -05:00
NotAKidoS
a2e29149e2 [NAK_CVR_Mods] test 2025-04-11 07:46:51 -05:00
NotAKidoS
8f8f2ad1fb [NAK_CVR_Mods] fixed generated download link in readme 2025-04-11 07:45:31 -05:00
github-actions[bot]
a2aa3b9871 [NAK_CVR_Mods] Update mod list in README 2025-04-11 12:41:14 +00:00
NotAKidoS
febd9f2741 Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-11 07:40:59 -05:00
NotAKidoS
b246f71e6e [CustomRichPresence] fix readme 2025-04-11 07:40:53 -05:00
github-actions[bot]
0cde9ecb21 [NAK_CVR_Mods] Update mod list in README 2025-04-11 12:39:51 +00:00
NotAKidoS
964d6009b7 Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-11 07:39:35 -05:00
NotAKidoS
392390cde7 [YouAreMyPropNowWeAreHavingSoftTacosLater] Initial push 2025-04-11 07:39:32 -05:00
NotAKidoS
ba26a1faae [CustomRichPresence] Move to .Experimental folder 2025-04-11 07:39:16 -05:00
github-actions[bot]
c13e48638c [NAK_CVR_Mods] Update mod list in README
Some checks failed
Update Mod List / update-modlist (push) Has been cancelled
2025-04-09 21:32:36 +00:00
NotAKidoS
77426c4235 Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-09 16:32:22 -05:00
NotAKidoS
ef6ad34a4e [NAK_CVR_Mods] Fixed finding description for FuckToes 2025-04-09 16:32:15 -05:00
github-actions[bot]
e67d571971 [NAK_CVR_Mods] Update mod list in README 2025-04-09 21:29:34 +00:00
NotAKidoS
d63fb02026 Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-09 16:29:21 -05:00
NotAKidoS
d5480e32b4 [NAK_CVR_Mods] test 2025-04-09 16:29:13 -05:00
github-actions[bot]
21aa646359 [NAK_CVR_Mods] Update mod list in README 2025-04-09 21:23:54 +00:00
NotAKidoS
02be4ec445 [NAK_CVR_Mods] trust 2 2025-04-09 16:07:44 -05:00
NotAKidoS
dafff6a9a2 [NAK_CVR_Mods] trust
Some checks are pending
Update Mod List / update-modlist (push) Waiting to run
2025-04-09 16:05:01 -05:00
NotAKidoS
68d7c22b7c [NAK_CVR_Mods] Experiment 2 2025-04-09 16:02:53 -05:00
NotAKidoS
3c81f71d15 Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-04-09 15:52:36 -05:00
NotAKidoS
0564de3ebf [NAK_CVR_Mods] Experiment 2025-04-09 15:52:32 -05:00
NotAKidoS
7030ed8650
[NAK_CVR_Mods] Update README.md 2025-04-09 15:49:27 -05:00
NotAKidoS
364de89b30 [RelativeSync] Updated format.json 2025-04-03 05:25:37 -05:00
NotAKidoS
fea10ac221 [RelativeSync] actually fixed distance hider 2025-04-03 05:24:48 -05:00
NotAKidoS
6249696efa [RelativeSync] Updated format.json 2025-04-03 05:08:57 -05:00
NotAKidoS
ea5a9eef97 [RelativeSync] Fixed execution order of RelativeSyncController & PuppetMaster.ProcessAvatarVisibility, so moving at high speeds with passengers does not disrupt voice or avatar distance hider 2025-04-03 05:08:25 -05:00
NotAKidoS
063669e8a6 [SmootherRay] Update format.json 2025-04-03 04:40:20 -05:00
NotAKidoS
9133c6b161 [ShareBubbles] Remove todo notes 2025-04-03 04:34:30 -05:00
NotAKidoS
84dcf35362 [ScrollFlight] Update format.json 2025-04-03 04:19:17 -05:00
NotAKidoS
0fdbcdec34 [ShareBubbles] Updated format.json 2025-04-03 04:16:01 -05:00
NotAKidoS
72b690365b [ShareBubbles] Fixed Public/Private text on bubble not being correct, Fixed bubble displaying as locked or not claimed despite being shared the content if it was private and not owned by you 2025-04-03 04:15:11 -05:00
NotAKidoS
e540628db1 [RCCVirtualSteeringWheel] Updated format.json 2025-04-03 04:12:04 -05:00
NotAKidoS
018112d6b9 [RCCVirtualSteeringWheel] Fixed error spam when sitting in a CVRSeat with lockControls, but no RCC component in parent 2025-04-03 04:11:40 -05:00
NotAKidoS
138c9a9856 [RCCVirtualSteeringWheel] Fixed generated steering wheel pickup collider not being marked isTrigger 2025-04-03 04:06:43 -05:00
NotAKidoS
aad4276f88 [Stickers] Update format.json 2025-04-03 04:05:24 -05:00
NotAKidoS
a9cebb85e9 [Stickers] Fixed scrolling cycling selected sticker slot despite not being in placement mode 2025-04-03 04:04:14 -05:00
NotAKidoS
f99a22499c [Stickers] Fixed placing stickers when Cohtml text input fields were focused 2025-04-03 04:02:58 -05:00
NotAKidoS
c35d03b1ec [NAK_CVR_Mods] update sln 2025-04-03 04:01:50 -05:00
NotAKidoS
16fb070e8b [ThirdPerson] bump version 2025-04-03 04:01:37 -05:00
NotAKidoS
bf89ee24f5 [Stickers] bump version, fixes for 2025r179 2025-04-03 04:01:28 -05:00
NotAKidoS
cdcb70a4b1 [SmootherRay] bump version, fixes for 2025r179 2025-04-03 04:01:22 -05:00
NotAKidoS
697ad77f5f [ShareBubbles] bump version, fixes for 2025r179 2025-04-03 04:01:15 -05:00
NotAKidoS
940777d9e5 [ScrollFlight] bump version 2025-04-03 04:00:56 -05:00
NotAKidoS
73d76010bc [ScrollFlight] bump version 2025-04-03 04:00:48 -05:00
NotAKidoS
75de6d33a0 [RelativeSync] bump version 2025-04-03 04:00:42 -05:00
NotAKidoS
9d2c3ed244 [RCCVirtualSteeringWheel] bump version 2025-04-03 04:00:35 -05:00
NotAKidoS
bddc21ec08 [PropUndoButton] bump version 2025-04-03 04:00:19 -05:00
NotAKidoS
e24eae5a22 [PropLoadingHexagon] bump version, fix for 2025r179 2025-04-03 04:00:08 -05:00
NotAKidoS
d0504fef91 [PortableCameraAdditions] bump version 2025-04-03 03:59:40 -05:00
NotAKidoS
ef3ecde553 [PathCamDisabler] bump version 2025-04-03 03:59:29 -05:00
NotAKidoS
200e174b3f [LazyPrune] bump version 2025-04-03 03:59:19 -05:00
NotAKidoS
4b5c19676d [KeepVelocityOnExitFlight] bump version 2025-04-03 03:59:10 -05:00
NotAKidoS
c0ba230fa5 [CustomSpawnPoint] bump version 2025-04-03 03:58:57 -05:00
NotAKidoS
736dc71eec [AvatarQueueSystemTweaks] bump version 2025-04-03 03:58:46 -05:00
NotAKidoS
61f56b2f84 [ASTExtension] bump version 2025-04-03 03:58:34 -05:00
NotAKidoS
915253972d [MuteSFX] Deprecate because functionality is doable native 2025-04-03 03:31:01 -05:00
NotAKidoS
8cffe8a5be [NAK_CVR_Mods] Update solution 2025-04-03 03:16:00 -05:00
NotAKidoS
7ad549b0bb dead 2025-04-03 03:08:25 -05:00
NotAKidoS
323eb92f2e further cleanup of repo 2025-04-03 03:03:24 -05:00
NotAKidoS
4f8dcb0cd0 including mutual mute 2025-04-03 02:59:18 -05:00
NotAKidoS
0042590aa6 Move many mods to Deprecated folder, fix spelling 2025-04-03 02:57:35 -05:00
NotAKidoS
5e822cec8d Merge branch 'main' of https://github.com/NotAKidoS/NAK_CVR_Mods 2025-01-29 16:37:17 -06:00
NotAKidoS
3660b8f683 AvatarCloneTest: push so i can reference in an email 2025-01-29 16:37:15 -06:00
NotAKidoS
f90b83706b
Merge pull request #35 from SurprisinglySuspicious/main
[copy_and_nstrip_dll.ps1] Immediately closes if NStrip is not found.
2025-01-15 16:47:11 -06:00
NotAKidoS
6d30fe1f41 ShareBubbles: Fixes for 2025r178 2025-01-15 16:42:53 -06:00
NotAKidoS
ac9af46bd6 MutualMute: Stole name idea, now it's MutualMute 2025-01-15 16:42:27 -06:00
NotAKidoS
40bc88586e RCCVirtualSteeringWheel: Fixes for 2025r178 2025-01-15 16:42:05 -06:00
NotAKidoS
621321c498 ASTExtension: Fixes for 2025r178 2025-01-15 16:41:37 -06:00
NotAKidoS
1282b2ca48 RCCVirtualSteeringWheel: tuning & prepare for release 2025-01-07 13:40:32 -06:00
NotAKidoS
5d77eb61a5 LegacyContentMitigation: fixed culling issue 2025-01-07 02:37:14 -06:00
NotAKidoS
5c8c724b58 RCCVirtualSteeringWheel: renamed mod, fixed things 2025-01-07 02:36:44 -06:00
NotAKidoS
3a00ff104a GrabbableSteeringWheel: commit 2025-01-04 04:46:06 -06:00
NotAKidoS
39da88d3d3 LegacyContentMitigation: fix cvrmg embed color 2024-12-31 11:17:16 -06:00
NotAKidoS
e5ee4631c7 LegacyContentMitigation: bump for updater 2024-12-31 11:15:22 -06:00
NotAKidoS
d4dc8fba44 LegacyContentMitigation: prepare for submission 2024-12-31 11:14:39 -06:00
NotAKidoS
94515efbe3 LegacyContentMitigation: initial commit
manual "multipass" in legacy worlds
2024-12-31 05:21:00 -06:00
NotAKidoS
3d6b1bbd59 BullshitWatcher: lame 2024-12-27 22:01:03 -06:00
NotAKidoS
19d7eb1c7c TwoWayMute: added newline to readme 2024-12-27 17:59:40 -06:00
NotAKidoS
e027829103 TwoWayMute: initial release 2024-12-27 17:55:39 -06:00
NotAKidoS
3d42301f24 ShareBubbles: added notice to readme about missing api stuff 2024-12-08 17:04:42 -06:00
NotAKidoS
f5c6a92472 ShareBubbles: bump version 2024-12-08 16:55:12 -06:00
NotAKidoS
ef2be62605 Make work on Stable, Add response on claim fail 2024-12-08 16:54:19 -06:00
NotAKidoS
e7b2ad4c31 ShareBubbles: move to additive scene 2024-12-02 21:53:17 -06:00
NotAKidoS
6fb1e0658d Update NAK_CVR_Mods.sln 2024-12-02 20:07:24 -06:00
NotAKidoS
f72a25a4c7 Update References.Items.props 2024-12-02 20:07:07 -06:00
NotAKidoS
0720ab508d ScrollFlight: fixed error spam on launch, added reset on exit flight option 2024-12-02 20:07:01 -06:00
NotAKidoS
7b73452df6 ShareBubbles: initial commit 2024-12-02 20:06:26 -06:00
NotAKidoS
fe768029eb LuaNetworkVariables: idk 2024-12-02 20:05:34 -06:00
NotAKidoS
db07d53971 ASTExtension: Fix for latest nightlies 2024-12-02 20:04:47 -06:00
SurprisinglySuspicious
70a54b632c
Add it for PATH too 2024-11-20 16:59:19 -05:00
SurprisinglySuspicious
04c4a4590d Issue: If NStrip wasn't found in folder or PATH, it tries to show a message to user, but it doesn't wait for key input, so it just immediately closes. 2024-11-20 16:07:52 -05:00
NotAKidoS
d0c8298074 SearchWithSpacesFix: initial release 2024-10-29 23:56:10 -05:00
NotAKidoS
379be57b84 Stickers: update format.json 2024-09-21 01:21:15 -05:00
NotAKidoS
dbc6341f9e Stickers: cleanup 2024-09-21 01:07:04 -05:00
NotAKidoS
50804b323d
Merge pull request #34 from SketchFoxsky/main
Stickers World Restrictions
2024-09-20 23:24:27 -05:00
SketchFoxsky
4c582e3edf
Stickers World Restrictions
Added Resources and World Restriction checks.
2024-09-20 18:17:18 -04:00
SketchFoxsky
14eeb1e559
Added Disabled Icons 2024-09-20 18:15:50 -04:00
SketchFoxsky
fa050d8103
Added Sketch contributions 2024-09-20 18:14:59 -04:00
SketchFoxsky
be05c04e72
World Restriction Checks
Updated the UI based on the world restriction.
2024-09-20 18:14:03 -04:00
SketchFoxsky
498dcff8b9
World Restriction Check
Disabled incoming messages when world is Restricted.
2024-09-20 18:12:09 -04:00
SketchFoxsky
71d780248f
Added World Restriction Checks 2024-09-20 18:10:40 -04:00
SketchFoxsky
5f6a85984d
Update README.md
Added Restrictions section.
2024-09-20 18:08:40 -04:00
NotAKidoS
d2c42391b9 SmootherRay: update format.json 2024-09-18 19:57:56 -05:00
NotAKidoS
31858c81eb SmootherRay: updated readme 2024-09-18 19:54:25 -05:00
NotAKidoS
70ade663bc SmootherRay: expanded and enhanced 2024-09-18 19:53:25 -05:00
NotAKidoS
59cec7e7d3 SmoothRay: cleanup 2024-09-18 19:45:08 -05:00
NotAKidoS
35943bd709 LuaTTS: fixes for latest scripting nightly 2024-09-11 16:25:19 -05:00
NotAKidoS
af00f4c6d0 Stickers: fixed shader replacement hitting stickers 2024-09-10 20:22:26 -05:00
NotAKidoS
958f07ed08 Stickers: added subscription check on outbound mod network calls 2024-09-10 20:22:14 -05:00
NotAKidoS
52315f5d51 Stickers: updated to BTKUIv2.3.0 2024-09-10 20:21:41 -05:00
NotAKidoS
a168619d19 SmoothRay: brought back from the dead 2024-09-08 16:38:06 -05:00
NotAKidoS
a51d5812e7 SmartReticle: updated readme 2024-09-06 01:41:20 -05:00
NotAKidoS
6c2b6d29a2 README: updated release table 2024-09-06 01:31:21 -05:00
NotAKidoS
437e4c5ea2 removed project references 2024-09-06 01:23:05 -05:00
NotAKidoS
7f4237bf95 depricated bunch of mods i will never touch or are native now 2024-09-06 01:22:37 -05:00
NotAKidoS
1ed32799a8 InteractionTest: idk never committed this 2024-09-06 01:19:35 -05:00
NotAKidoS
fd4fe2ea9d AvatarScaleMod: renamed folder 2024-09-06 01:19:20 -05:00
NotAKidoS
a1d73bf156 deleted unfinished mods 2024-09-06 01:17:59 -05:00
NotAKidoS
51f29106c3 FuckToes: fixes for r176 2024-09-06 01:08:37 -05:00
NotAKidoS
16a1a35a91 Nevermind: fixes for r176 2024-09-06 01:04:54 -05:00
NotAKidoS
83139bf1da OriginShift: fixed missing harmony reference 2024-09-06 00:59:52 -05:00
NotAKidoS
d2d0e86e26 NAK_CVR_Mods: new project references 2024-09-06 00:58:02 -05:00
NotAKidoS
9433779641 Stickers: added lazy placement preview 2024-09-06 00:57:39 -05:00
NotAKidoS
d409bf1743 ScriptingSpoofer: fixes for latest scripting builds 2024-09-06 00:57:23 -05:00
NotAKidoS
6ebc55ee16 updated readme 2024-09-06 00:39:46 -05:00
NotAKidoS
0cf0d46018 removal 2024-09-06 00:36:26 -05:00
NotAKidoS
f711f6fb9c Stickers: Fixed error saving melon prefs 2024-09-05 10:06:25 -05:00
NotAKidoS
9c45d8179d Stickers: deleted whitespace 2024-09-02 01:37:17 -05:00
NotAKidoS
a2d65520c9 Stickers: nvm 2024-09-02 01:28:08 -05:00
NotAKidoS
96369f5659 Stickers: oops... 2024-09-02 01:21:10 -05:00
NotAKidoS
a17ad66bdd SmartReticle: bumped ver 2024-09-02 01:03:12 -05:00
NotAKidoS
45bbfe0d93 CustomSpawnPoint: removed unneeded logging 2024-09-02 01:03:04 -05:00
NotAKidoS
e61049462b SmartReticle: made work for VR reticle 2024-09-02 00:53:54 -05:00
NotAKidoS
dbdf4308c7 WhereAmIPointing: updated format.json 2024-09-02 00:46:13 -05:00
NotAKidoS
832f392682 WhereAmIPointing: fixed dimming of ray when no menu is open 2024-09-02 00:45:07 -05:00
NotAKidoS
da90e4623f Stickers: update format.json 2024-09-02 00:44:50 -05:00
NotAKidoS
192ba3cceb Stickers: Added back Identify button 2024-09-02 00:36:49 -05:00
NotAKidoS
2f65634031 Stickers: minor changes 2024-09-02 00:18:57 -05:00
NotAKidoS
c206d98a97 Stickers: fixed nullref when materials were destroyed 2024-08-27 17:48:53 -05:00
NotAKidoS
c408a9f83c WhereAmIPointing: Initial Release 2024-08-27 14:05:42 -05:00
762 changed files with 15867 additions and 6756 deletions

View file

@ -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<bool> 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
}

View file

@ -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";
}

View file

@ -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.

View file

@ -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"
}

View file

@ -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<FPRExclusion>();
exclusion.target = head;
exclusion.isShown = false;
}
private void InitializeExclusions()
{
_exclusions = GetComponentsInChildren<FPRExclusion>(true);
var exclusionRoots = new Dictionary<Transform, AvatarCloneExclusion>(_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<Transform>(behaviour.affectedTransforms);
}
// ------------------------------
// **OPTIMIZED EXCLUSION BONE MAPPING**
// ------------------------------
Dictionary<Transform, AvatarCloneExclusion>.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<Transform, List<AvatarCloneExclusion>>(estimatedBoneCount);
foreach (AvatarCloneExclusion behaviour in exclusionBehaviours)
{
foreach (Transform bone in behaviour.affectedTransformSet)
{
if (!boneToExclusion.TryGetValue(bone, out var list))
{
list = new List<AvatarCloneExclusion>(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<int>(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<SkinnedMeshRenderer>().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
}

View file

@ -0,0 +1,304 @@
using ABI_RC.Core.Player.ShadowClone;
using UnityEngine;
using UnityEngine.Rendering;
namespace NAK.AvatarCloneTest;
public partial class AvatarClone
{
#region Initialization
private void InitializeCollections()
{
#if ENABLE_PROFILER
s_InitializeData.Begin();
#endif
// Initialize source collections
_skinnedRenderers = new List<SkinnedMeshRenderer>();
_blendShapeWeights = new List<List<float>>();
_meshRenderers = new List<MeshRenderer>();
_meshFilters = new List<MeshFilter>();
_otherRenderers = new List<Renderer>();
// Initialize clone collections
_skinnedClones = new List<SkinnedMeshRenderer>();
_skinnedCloneMaterials = new List<Material[]>();
_skinnedCloneCullingMaterials = new List<Material[]>();
if (Setting_CloneMeshRenderers)
{
_meshClones = new List<MeshRenderer>();
_meshCloneFilters = new List<MeshFilter>();
_meshCloneMaterials = new List<Material[]>();
_meshCloneCullingMaterials = new List<Material[]>();
}
// Initialize shared resources
_materialWorkingList = new List<Material>();
_propertyBlock = new MaterialPropertyBlock();
#if ENABLE_PROFILER
s_InitializeData.End();
#endif
}
private void CollectRenderers()
{
#if ENABLE_PROFILER
s_InitializeData.Begin();
#endif
var renderers = GetComponentsInChildren<Renderer>(true);
var currentIndex = 0;
var nonCloned = 0;
// Single pass: directly categorize renderers
foreach (Renderer renderer in renderers)
{
switch (renderer)
{
case SkinnedMeshRenderer skinned when skinned.sharedMesh != null:
AddSkinnedRenderer(skinned);
currentIndex++;
break;
case MeshRenderer mesh:
MeshFilter filter = mesh.GetComponent<MeshFilter>();
if (filter != null && filter.sharedMesh != null)
{
if (Setting_CloneMeshRenderers)
{
AddMeshRenderer(mesh, filter);
}
else
{
AddMeshRenderer(mesh, filter);
nonCloned++;
}
currentIndex++;
}
break;
default:
AddOtherRenderer(renderer);
currentIndex++;
nonCloned++;
break;
}
}
_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<float>(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<SkinnedMeshRenderer>();
// 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<MeshRenderer>();
MeshFilter cloneFilter = clone.AddComponent<MeshFilter>();
// 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
}

View file

@ -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
}

View file

@ -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<Material> 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<float> 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
}

View file

@ -0,0 +1,81 @@
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 << LOCAL_LAYER)) != 0;
private static bool CameraRendersPlayerCloneLayer(Camera cam)
=> (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
#endregion Utilities
#region Magica Cloth Support
private void SetupMagicaClothSupport()
{
var magicaCloths1 = GetComponentsInChildren<BaseCloth>(true);
foreach (BaseCloth magicaCloth1 in magicaCloths1)
magicaCloth1.SetCullingMode(PhysicsTeam.TeamCullingMode.Off);
var magicaCloths2 = base.GetComponentsInChildren<MagicaCloth2.MagicaCloth>(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
}

View file

@ -0,0 +1,147 @@
using NAK.AvatarCloneTest;
using UnityEngine;
using UnityEngine.Rendering;
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<SkinnedMeshRenderer> _skinnedRenderers;
private List<List<float>> _blendShapeWeights;
// Mesh renderers (optionally cloned)
private List<MeshRenderer> _meshRenderers;
private List<MeshFilter> _meshFilters;
#endregion Source Collections - Cloned Renderers
#region Source Collections - Non-Cloned Renderers
// All other renderers (never cloned)
private List<Renderer> _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<SkinnedMeshRenderer> _skinnedClones;
private List<Material[]> _skinnedCloneMaterials;
private List<Material[]> _skinnedCloneCullingMaterials;
// Mesh clones (optional)
private List<MeshRenderer> _meshClones;
private List<MeshFilter> _meshCloneFilters;
private List<Material[]> _meshCloneMaterials;
private List<Material[]> _meshCloneCullingMaterials;
#endregion Clone Collections
#region Shared Resources
private List<Material> _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()
{
Setting_CloneMeshRenderers = AvatarCloneTestMod.EntryCloneMeshRenderers.Value;
InitializeCollections();
CollectRenderers();
CreateClones();
AddExclusionToHeadIfNeeded();
InitializeExclusions();
SetupMagicaClothSupport();
// bool animatesClone = transform.Find("[ExplicitlyAnimatesVisualClones]") != null;
// Setting_CopyMaterials = !animatesClone;
// Setting_CopyBlendShapes = !animatesClone;
// Animator animator = GetComponent<Animator>();
// if (animator && animatesClone) animator.Rebind();
// Likely a Unity bug with where we can touch shadowCastingMode & forceRenderingOff
#if !UNITY_EDITOR
Camera.onPreCull += MyOnPreCull;
#else
Camera.onPreRender += MyOnPreCull;
#endif
}
private void LateUpdate()
{
SyncEnabledState();
if (Setting_CopyMaterials && AvatarCloneTestMod.EntryCopyMaterials.Value)
SyncMaterials();
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
}

View file

@ -0,0 +1,39 @@
using ABI.CCK.Components;
using UnityEngine;
namespace NAK.AvatarCloneTest;
public class AvatarCloneExclusion : IExclusionBehaviour
{
public readonly Dictionary<SkinnedMeshRenderer, List<int>> skinnedToBoneIndex = new();
public readonly List<Transform> affectedTransforms = new();
public readonly List<Renderer> affectedRenderers = new();
public HashSet<Transform> affectedTransformSet = new();
private readonly AvatarClone _cloneSystem;
private readonly Transform _target;
internal Transform _shrinkBone;
public bool isImmuneToGlobalState { get; set; }
public AvatarCloneExclusion(AvatarClone cloneSystem, Transform target)
{
_cloneSystem = cloneSystem;
_target = target;
}
public void UpdateExclusions(bool isShown, bool shrinkToZero)
{
if (_shrinkBone == null)
{
// Create shrink bone parented directly to target
_shrinkBone = new GameObject($"{_target.name}_Shrink").transform;
_shrinkBone.SetParent(_target, false);
}
// Set scale based on shrink mode
_shrinkBone.localScale = shrinkToZero ? Vector3.zero : Vector3.positiveInfinity;
// Replace the bone references with the shrink bone for the indicies we modify
_cloneSystem.HandleExclusionUpdate(this, isShown);
}
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>LocalCloneFix</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants>TRACE;TRACE;</DefineConstants>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,81 @@
using ABI_RC.Core;
using ABI_RC.Core.EventSystem;
using ABI_RC.Core.Savior;
using MelonLoader;
using UnityEngine;
namespace NAK.AvatarCloneTest;
public class AvatarCloneTestMod : MelonMod
{
#region Melon Preferences
private static readonly MelonPreferences_Category Category =
MelonPreferences.CreateCategory(nameof(AvatarCloneTest));
internal static readonly MelonPreferences_Entry<bool> EntryUseAvatarCloneTest =
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<bool> 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<bool> 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<bool> EntryCopyMaterials =
Category.CreateEntry("copy_materials", true,
"Copy Materials", description: "Copies the materials from the original avatar to the clone.");
#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?
}
public override void OnUpdate()
{
// press f1 to find all cameras that arent tagged main and set them tno not render CVRLayers.PlayerClone
if (Input.GetKeyDown(KeyCode.F1))
{
foreach (var camera in UnityEngine.Object.FindObjectsOfType<UnityEngine.Camera>())
{
if (camera.tag != "MainCamera")
{
camera.cullingMask &= ~(1 << CVRLayers.PlayerClone);
}
}
}
// 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
#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
}

View file

@ -0,0 +1,22 @@
using ABI_RC.Core;
using ABI_RC.Core.Player;
using ABI_RC.Core.Player.TransformHider;
using ABI_RC.Core.Savior;
using ABI_RC.Systems.Camera;
using HarmonyLib;
using UnityEngine;
namespace NAK.AvatarCloneTest;
public static class Patches
{
[HarmonyPrefix]
[HarmonyPatch(typeof(TransformHiderUtils), nameof(TransformHiderUtils.SetupAvatar))]
private static bool OnSetupAvatar(GameObject avatar)
{
if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) return true;
avatar.AddComponent<AvatarClone>();
return false;
}
}

View file

@ -0,0 +1,32 @@
using MelonLoader;
using NAK.AvatarCloneTest.Properties;
using System.Reflection;
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
[assembly: AssemblyTitle(nameof(NAK.AvatarCloneTest))]
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
[assembly: AssemblyProduct(nameof(NAK.AvatarCloneTest))]
[assembly: MelonInfo(
typeof(NAK.AvatarCloneTest.AvatarCloneTestMod),
nameof(NAK.AvatarCloneTest),
AssemblyInfoParams.Version,
AssemblyInfoParams.Author,
downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AvatarCloneTest"
)]
[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.AvatarCloneTest.Properties;
internal static class AssemblyInfoParams
{
public const string Version = "1.0.3";
public const string Author = "NotAKidoS";
}

View file

@ -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();

View file

@ -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;

View file

@ -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
}

View file

@ -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);
}
}
}

View file

@ -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();
};
}
}
}

View file

@ -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);
}
}
}

View file

@ -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<QMUIElement> USM_QmUiElements = new();
namespace NAK.AvatarScaleMod.Integrations;
private static void Setup_UniversalScalingSettings(Page page)
{
public static partial class BtkUiAddon
{
private static readonly List<QMUIElement> 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
}

View file

@ -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
}

View file

@ -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<bool> 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<float> 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<string> 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<float> 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<float> 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;
// }
/// <summary>
/// Helper method to create a category that saves its collapsed state to a MelonPreferences entry.
/// </summary>
/// <param name="page"></param>
/// <param name="entry"></param>
/// <param name="showHeader"></param>
/// <returns></returns>
private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry<bool> 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
}

View file

@ -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;
}
}
}

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

Some files were not shown because too many files have changed in this diff Show more