-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PropCompanion] Initial implementation
- Loading branch information
Showing
8 changed files
with
299 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,172 @@ | ||
using System.Collections; | ||
using ABI_RC.Core.InteractionSystem; | ||
using ABI_RC.Core.Player; | ||
using ABI_RC.Core.Savior; | ||
using ABI_RC.Core.Util; | ||
using ABI_RC.Systems.GameEventSystem; | ||
using ABI.CCK.Components; | ||
using HarmonyLib; | ||
using MelonLoader; | ||
using UnityEngine; | ||
|
||
namespace Kafe.CompanionProp; | ||
|
||
public class CompanionProp : MelonMod { | ||
|
||
|
||
public override void OnInitializeMelon() { | ||
|
||
ModConfig.InitializeMelonPrefs(); | ||
|
||
CheckGuid(ModConfig.MePropGuid.Value, false); | ||
|
||
object spawning = null; | ||
|
||
CVRGameEventSystem.Instance.OnConnected.AddListener(instanceID => { | ||
if (!ShouldSpawnProp) return; | ||
// Handle can't spawn notification | ||
if (!CVRWorld.Instance.allowSpawnables) { | ||
if (ModConfig.MeSendHudSpawnNotAllowedNotification.Value) | ||
ViewManager.Instance.NotifyUser("(Local) Client", "CompanionProp - This world doesn't allow props :c", 2f); | ||
return; | ||
} | ||
// Cancel previous | ||
if (spawning != null) | ||
MelonCoroutines.Stop(spawning); | ||
// Start the spawning coroutine | ||
spawning = MelonCoroutines.Start(DelaySpawnProp(instanceID)); | ||
}); | ||
} | ||
|
||
private IEnumerator DelaySpawnProp(string instanceIdToSpawn) { | ||
|
||
int delaySeconds = ModConfig.MeSpawnDelay.Value; | ||
|
||
MelonLogger.Msg($"Connected to instance: {instanceIdToSpawn}, spawning {ModConfig.MePropGuid.Value} in {delaySeconds} seconds..."); | ||
|
||
yield return new WaitForSeconds(delaySeconds); | ||
|
||
// Double-check our settings | ||
if (!ShouldSpawnProp) yield break; | ||
|
||
// Ensure we're still on the same instance | ||
if (instanceIdToSpawn != MetaPort.Instance.CurrentInstanceId) { | ||
MelonLogger.Warning($"Prop started spawning when we were on the instance {instanceIdToSpawn}, but now we're on {MetaPort.Instance.CurrentInstanceId}. Ignoring..."); | ||
yield break; | ||
} | ||
|
||
// Handle spawning notification | ||
if (ModConfig.MeSendHudSpawnNotification.Value) | ||
ViewManager.Instance.NotifyUser("(Local) Client", "CompanionProp - Spawning our prop c:", 2f); | ||
|
||
PlayerSetup.Instance.DropProp(ModConfig.MePropGuid.Value); | ||
|
||
MelonLogger.Msg($"Spawned our precious {ModConfig.MePropGuid.Value} prop!"); | ||
} | ||
|
||
public static void CheckGuid(string guidValue, bool forceCheck) { | ||
if (!ModConfig.SpawnPropOnJoin.Value && !forceCheck) return; | ||
if (Guid.TryParse(guidValue, out _)) { | ||
MelonLogger.Msg($"Using the prop's guid to {guidValue}"); | ||
} | ||
else { | ||
MelonLogger.Warning($"The current prop's guid \"{guidValue}\" is not valid. Ensure to input a valid guid on the configuration."); | ||
} | ||
} | ||
|
||
private bool ShouldSpawnProp => ModConfig.MeEnabled.Value && ModConfig.SpawnPropOnJoin.Value && Guid.TryParse(ModConfig.MePropGuid.Value, out _); | ||
|
||
|
||
[HarmonyPatch] | ||
internal class HarmonyPatches { | ||
|
||
private static bool MatchesOurProp(CVRSyncHelper.PropData prop) { | ||
return prop.SpawnedBy == MetaPort.Instance.ownerId && prop.ObjectId == ModConfig.MePropGuid.Value; | ||
} | ||
|
||
private static bool MatchesOurPropInstanceID(string propInstanceId) { | ||
return propInstanceId.StartsWith("p " ModConfig.MePropGuid.Value, StringComparison.OrdinalIgnoreCase); | ||
} | ||
|
||
[HarmonyPrefix] | ||
[HarmonyPatch(typeof(CVRSyncHelper), nameof(CVRSyncHelper.DeleteMyProps))] | ||
static void Before_CVRSyncHelper_DeleteMyProps(out (IEnumerable<CVRSyncHelper.PropData>, IEnumerable<string>) __state) { | ||
__state = default; | ||
|
||
// Ignore and execute the normal method like usual | ||
if (!ModConfig.MeEnabled.Value || !ModConfig.MePreventRemoveAllMyProps.Value) { | ||
return; | ||
} | ||
|
||
try { | ||
__state = (CVRSyncHelper.Props.Where(MatchesOurProp).ToArray(), CVRSyncHelper.MySpawnedPropInstanceIds.Where(MatchesOurPropInstanceID).ToArray()); | ||
CVRSyncHelper.Props.RemoveAll(MatchesOurProp); | ||
CVRSyncHelper.MySpawnedPropInstanceIds.RemoveWhere(MatchesOurPropInstanceID); | ||
} | ||
catch (Exception e) { | ||
MelonLogger.Error($"Error executing {nameof(Before_CVRSyncHelper_DeleteMyProps)} Patch"); | ||
MelonLogger.Error(e); | ||
} | ||
} | ||
[HarmonyPostfix] | ||
[HarmonyPatch(typeof(CVRSyncHelper), nameof(CVRSyncHelper.DeleteMyProps))] | ||
static void After_CVRSyncHelper_DeleteMyProps((IEnumerable<CVRSyncHelper.PropData>, IEnumerable<string>) __state) { | ||
|
||
// Ignore and execute the normal method like usual | ||
if (!ModConfig.MeEnabled.Value || !ModConfig.MePreventRemoveAllMyProps.Value) | ||
return; | ||
|
||
try { | ||
CVRSyncHelper.Props.AddRange(__state.Item1); | ||
CVRSyncHelper.MySpawnedPropInstanceIds.UnionWith(__state.Item2); | ||
} | ||
catch (Exception e) { | ||
MelonLogger.Error($"Error executing {nameof(After_CVRSyncHelper_DeleteMyProps)} Patch"); | ||
MelonLogger.Error(e); | ||
} | ||
} | ||
|
||
[HarmonyPrefix] | ||
[HarmonyPatch(typeof(CVRSyncHelper), nameof(CVRSyncHelper.DeleteAllProps))] | ||
static void Before_CVRSyncHelper_DeleteAllProps(out (IEnumerable<CVRSyncHelper.PropData>, IEnumerable<string>) __state) { | ||
__state = default; | ||
|
||
// Ignore and execute the normal method like usual | ||
if (!ModConfig.MeEnabled.Value || !ModConfig.MePreventRemoveAllProps.Value) { | ||
return; | ||
} | ||
|
||
try { | ||
__state = (CVRSyncHelper.Props.Where(MatchesOurProp).ToArray(), CVRSyncHelper.MySpawnedPropInstanceIds.Where(MatchesOurPropInstanceID).ToArray()); | ||
CVRSyncHelper.Props.RemoveAll(MatchesOurProp); | ||
CVRSyncHelper.MySpawnedPropInstanceIds.RemoveWhere(MatchesOurPropInstanceID); | ||
} | ||
catch (Exception e) { | ||
MelonLogger.Error($"Error executing {nameof(Before_CVRSyncHelper_DeleteAllProps)} Patch"); | ||
MelonLogger.Error(e); | ||
} | ||
} | ||
|
||
[HarmonyPostfix] | ||
[HarmonyPatch(typeof(CVRSyncHelper), nameof(CVRSyncHelper.DeleteAllProps))] | ||
static void After_CVRSyncHelper_DeleteAllProps((IEnumerable<CVRSyncHelper.PropData>, IEnumerable<string>) __state) { | ||
|
||
// Ignore and execute the normal method like usual | ||
if (!ModConfig.MeEnabled.Value || !ModConfig.MePreventRemoveAllProps.Value) | ||
return; | ||
|
||
try { | ||
CVRSyncHelper.Props.AddRange(__state.Item1); | ||
CVRSyncHelper.MySpawnedPropInstanceIds.UnionWith(__state.Item2); | ||
} | ||
catch (Exception e) { | ||
MelonLogger.Error($"Error executing {nameof(After_CVRSyncHelper_DeleteAllProps)} Patch"); | ||
MelonLogger.Error(e); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,56 @@ | ||
using MelonLoader; | ||
|
||
namespace Kafe.CompanionProp; | ||
|
||
public static class ModConfig { | ||
|
||
private static MelonPreferences_Category _melonCategory; | ||
|
||
internal static MelonPreferences_Entry<bool> MeEnabled; | ||
internal static MelonPreferences_Entry<string> MePropGuid; | ||
|
||
internal static MelonPreferences_Entry<bool> SpawnPropOnJoin; | ||
internal static MelonPreferences_Entry<int> MeSpawnDelay; | ||
|
||
internal static MelonPreferences_Entry<bool> MePreventRemoveAllProps; | ||
internal static MelonPreferences_Entry<bool> MePreventRemoveAllMyProps; | ||
|
||
internal static MelonPreferences_Entry<bool> MeSendHudSpawnNotification; | ||
internal static MelonPreferences_Entry<bool> MeSendHudSpawnNotAllowedNotification; | ||
|
||
public static void InitializeMelonPrefs() { | ||
|
||
_melonCategory = MelonPreferences.CreateCategory(nameof(CompanionProp)); | ||
|
||
MeEnabled = _melonCategory.CreateEntry("Enabled", true, | ||
description: "Whether all the mod functionality should be enabled or not."); | ||
|
||
MePropGuid = _melonCategory.CreateEntry("PropGuid", "", | ||
description: "The guid of the prop we're settings as our companion."); | ||
MePropGuid.OnEntryValueChanged.Subscribe((_, newValue) => { | ||
CompanionProp.CheckGuid(newValue, true); | ||
}); | ||
|
||
|
||
SpawnPropOnJoin = _melonCategory.CreateEntry("SpawnPropOnJoin", true, | ||
description: "Whether to spawn the prop on joining an instance that allows props or not."); | ||
|
||
MeSpawnDelay = _melonCategory.CreateEntry("SpawnDelay", 5, | ||
description: "Time in seconds to spawn the prop after joining the instance."); | ||
|
||
|
||
MePreventRemoveAllProps = _melonCategory.CreateEntry("PreventRemoveAllProps", true, | ||
description: "Whether to prevent removing our prop when pressing the remove all props button."); | ||
|
||
MePreventRemoveAllMyProps = _melonCategory.CreateEntry("PreventRemoveAllMyProps", true, | ||
description: "Whether to prevent removing our prop when pressed the remove my props button."); | ||
|
||
|
||
MeSendHudSpawnNotification = _melonCategory.CreateEntry("SendHudSpawnNotification", true, | ||
description: "Whether to send a notification to the hud when the prop is spawned or not."); | ||
|
||
MeSendHudSpawnNotAllowedNotification = _melonCategory.CreateEntry("SendHudSpawnNotAllowedNotification", false, | ||
description: "Whether to send a notification to the hud when the prop is was not allowed to be spawned."); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,2 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project Sdk="Microsoft.NET.Sdk"/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,32 @@ | ||
using System.Reflection; | ||
using Kafe.CompanionProp; | ||
using Kafe.CompanionProp.Properties; | ||
using MelonLoader; | ||
|
||
|
||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)] | ||
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] | ||
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] | ||
[assembly: AssemblyTitle(nameof(Kafe.CompanionProp))] | ||
[assembly: AssemblyCompany(AssemblyInfoParams.Author)] | ||
[assembly: AssemblyProduct(nameof(Kafe.CompanionProp))] | ||
|
||
[assembly: MelonInfo( | ||
typeof(CompanionProp), | ||
nameof(Kafe.CompanionProp), | ||
AssemblyInfoParams.Version, | ||
AssemblyInfoParams.Author, | ||
downloadLink: "https://github.com/kafeijao/Kafe_CVR_Mods" | ||
)] | ||
[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] | ||
[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] | ||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] | ||
[assembly: VerifyLoaderVersion(0, 6, 1, true)] | ||
[assembly: MelonColor(255, 0, 255, 0)] | ||
[assembly: MelonAuthorColor(255, 119, 77, 79)] | ||
|
||
namespace Kafe.CompanionProp.Properties; | ||
internal static class AssemblyInfoParams { | ||
public const string Version = "0.0.1"; | ||
public const string Author = "kafeijao"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,19 @@ | ||
{ | ||
"_id": -1, | ||
"name": "CompanionProp", | ||
"modversion": "0.0.1", | ||
"gameversion": "2024r175", | ||
"loaderversion": "v0.6.1", | ||
"modtype": "Mod", | ||
"author": "kafeijao", | ||
"description": "Automatically spawn a single prop upon joining an instance (that allows props), while being able to optionally exclude them from being removed when pressing the Remove All Props or Remove my Props buttons.\n\nYou can start using by setting the prop Guid on the melon preferences. Either by editing the config file or by using the `UIExpansionKit` mod.\n\nCheck [README.md](https://github.com/kafeijao/Kafe_CVR_Mods/tree/master/CompanionProp) for more in-depth info.\n\n", | ||
"searchtags": [ | ||
"prop", | ||
"companion" | ||
], | ||
"requirements": [], | ||
"downloadlink": "https://github.com/kafeijao/Kafe_CVR_Mods/releases/download/r68/CompanionProp.dll", | ||
"sourcelink": "https://github.com/kafeijao/Kafe_CVR_Mods/tree/master/CompanionProp", | ||
"changelog": "- Initial Implementation", | ||
"embedcolor": "16C60C" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,11 @@ | ||
# PropCompanion | ||
|
||
[![Download Latest PropCompanion.dll](../.Resources/DownloadButtonEnabled.svg "Download Latest PropCompanion.dll")](https://github.com/kafeijao/Kafe_CVR_Mods/releases/latest/download/PropCompanion.dll) | ||
|
||
Very simple mod that automatically spawn a prop upon joining an instance (that allows props), while being able to | ||
optionally exclude them from being removed when pressing the Remove All Props or Remove my Props buttons. | ||
|
||
You can start using by setting the prop Guid on the melon preferences. Either by editing the config file or by using the | ||
`UIExpansionKit` mod. | ||
|
||
You can only have a single prop companion. This is by design to avoid people keeping a ton of props on all the time. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters