mass commit of laziness

This commit is contained in:
NotAKidoS 2025-12-28 20:30:00 -06:00
parent ce992c70ee
commit 6d4fc549d9
167 changed files with 5471 additions and 675 deletions

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>YouAreMineNow</RootNamespace>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,236 @@
using System.Reflection;
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player;
using ABI_RC.Core.Util;
using ABI_RC.Systems.Communications;
using ABI_RC.Systems.GameEventSystem;
using ABI_RC.Systems.RuntimeDebug;
using HarmonyLib;
using MelonLoader;
using UnityEngine;
namespace NAK.YouAreMyPropNowWeAreHavingSoftTacosLater;
public class ChatBubblesMod : MelonMod
{
#region Melon Preferences
private static readonly MelonPreferences_Category Category =
MelonPreferences.CreateCategory(nameof(YouAreMyPropNowWeAreHavingSoftTacosLater));
private static readonly MelonPreferences_Entry<KeyCode> EntryChatBubblesKey =
Category.CreateEntry("keyboard_bind", KeyCode.Y, display_name: "Chat Bubbles Key",
description: "Key to open chat bubble input.");
private static readonly MelonPreferences_Entry<float> EntryBubbleDuration =
Category.CreateEntry("bubble_duration", 5.0f, display_name: "Bubble Duration",
description: "Base duration in seconds for chat bubbles to stay visible.");
private static readonly MelonPreferences_Entry<float> EntryDurationPerChar =
Category.CreateEntry("duration_per_char", 0.05f, display_name: "Duration Per Character",
description: "Additional duration per character in the message.");
private static readonly MelonPreferences_Entry<int> EntryPoolSize =
Category.CreateEntry("pool_size", 20, display_name: "Pool Size",
description: "Maximum number of chat bubbles that can be displayed at once.");
private static readonly MelonPreferences_Entry<Color> EntryBubbleColor =
Category.CreateEntry("bubble_color", new Color(1.0f, 1.0f, 1.0f, 1.0f), display_name: "Bubble Color",
description: "Color of chat bubble text.");
#endregion Melon Preferences
#region Object Pool
private class ChatBubble
{
public CVRPlayerEntity Player { get; set; }
public string Message { get; set; }
public float Duration { get; set; }
public float Timer { get; set; }
public bool IsActive { get; set; }
public void Reset()
{
Player = null;
Message = string.Empty;
Duration = 0f;
Timer = 0f;
IsActive = false;
}
}
private readonly List<ChatBubble> _chatBubblePool = [];
private readonly List<ChatBubble> _activeBubbles = [];
private void InitializePool()
{
MelonLogger.Msg("Initializing chat bubble pool with size: " + EntryPoolSize.Value);
_chatBubblePool.Clear();
for (int i = 0; i < EntryPoolSize.Value; i++)
{
_chatBubblePool.Add(new ChatBubble());
}
}
private ChatBubble GetBubbleFromPool()
{
// First try to find an inactive bubble
foreach (var bubble in _chatBubblePool)
{
if (!bubble.IsActive)
{
bubble.Reset();
bubble.IsActive = true;
_activeBubbles.Add(bubble);
return bubble;
}
}
// If all bubbles are active, reuse the oldest one
if (_activeBubbles.Count > 0)
{
var oldestBubble = _activeBubbles[0];
_activeBubbles.RemoveAt(0);
oldestBubble.Reset();
oldestBubble.IsActive = true;
_activeBubbles.Add(oldestBubble);
return oldestBubble;
}
// This should never happen if the pool is initialized properly
MelonLogger.Warning("No chat bubbles available in pool!");
return null;
}
private void ReturnBubbleToPool(ChatBubble bubble)
{
bubble.IsActive = false;
_activeBubbles.Remove(bubble);
}
#endregion Object Pool
#region Melon Events
public override void OnInitializeMelon()
{
MelonLogger.Msg("Initializing Chat Bubbles Mod");
InitializePool();
CVRGameEventSystem.Communications.TextChat.Local.OnMessageReceived.AddListener(OnLocalMessageReceived);
CVRGameEventSystem.Communications.TextChat.Direct.OnMessageReceived.AddListener(OnGlobalMessageReceived);
CVRGameEventSystem.Communications.TextChat.Global.OnMessageReceived.AddListener(OnDirectMessageReceived);
HarmonyInstance.Patch(
typeof(ViewManager).GetMethod(nameof(ViewManager.SendToWorldUi),
BindingFlags.NonPublic | BindingFlags.Instance),
postfix: new HarmonyMethod(typeof(ChatBubblesMod).GetMethod(nameof(OnViewManagerSendToWorldUi),
BindingFlags.NonPublic | BindingFlags.Static))
);
MelonLogger.Msg("Chat Bubbles Mod initialized successfully");
}
public override void OnUpdate()
{
// Process key input to open chat
if (Input.GetKeyDown(EntryChatBubblesKey.Value))
{
if (!CVRSyncHelper.IsConnectedToGameNetwork())
return;
IsInKeyboardToWriteANiceMessage = true;
ViewManager.Instance.openMenuKeyboard(string.Empty);
}
// Update and render active chat bubbles
UpdateChatBubbles();
}
private void UpdateChatBubbles()
{
// Make a copy of the list to avoid issues when modifying during iteration
var bubblesToUpdate = new List<ChatBubble>(_activeBubbles);
foreach (var bubble in bubblesToUpdate)
{
if (bubble.Player == null || bubble.Player.PuppetMaster == null)
{
ReturnBubbleToPool(bubble);
continue;
}
bubble.Timer += Time.deltaTime;
if (bubble.Timer >= bubble.Duration)
{
ReturnBubbleToPool(bubble);
continue;
}
// Draw the bubble text at the player's nameplate position
var nameplatePosition = bubble.Player.PuppetMaster.GetNamePlateWorldPosition();
// Offset slightly above the nameplate
nameplatePosition.y += 0.2f;
RuntimeGizmos.DrawText(nameplatePosition, bubble.Message, 5, EntryBubbleColor.Value);
}
}
#endregion Melon Events
#region Game Events
public static bool IsInKeyboardToWriteANiceMessage { get; set; }
private static void OnViewManagerSendToWorldUi(string value)
{
if (!IsInKeyboardToWriteANiceMessage) return;
IsInKeyboardToWriteANiceMessage = false;
Comms_Manager.SendLocalTextMessage(value);
Comms_Manager.SendDirectTextMessage(CVRPlayerManager.Instance.NetworkPlayers[0].Uuid, value);
Comms_Manager.SendGlobalTextMessage(value);
MelonLogger.Msg("Sending message: " + value);
}
private void OnLocalMessageReceived(CVRPlayerEntity player, string message)
{
CreateChatBubble(player, message);
MelonLogger.Msg("OnLocalMessageReceived - Player: " + player?.Username + ", Message: " + message);
}
private void OnDirectMessageReceived(CVRPlayerEntity player, string message)
{
CreateChatBubble(player, message);
MelonLogger.Msg("OnDirectMessageReceived - Player: " + player?.Username + ", Message: " + message);
}
private void OnGlobalMessageReceived(CVRPlayerEntity player, string message)
{
CreateChatBubble(player, message);
MelonLogger.Msg("OnGlobalMessageReceived - Player: " + player?.Username + ", Message: " + message);
}
private void CreateChatBubble(CVRPlayerEntity player, string message)
{
if (player == null || player.PuppetMaster == null)
return;
// Calculate duration based on message length
float baseDuration = EntryBubbleDuration.Value;
float charDuration = EntryDurationPerChar.Value * message.Length;
float totalDuration = Mathf.Clamp(baseDuration + charDuration, baseDuration, 15f);
ChatBubble bubble = GetBubbleFromPool();
if (bubble == null) return;
bubble.Player = player;
bubble.Message = message;
bubble.Duration = totalDuration;
bubble.Timer = 0f;
}
#endregion Game Events
}

View file

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

View file

@ -0,0 +1,19 @@
# YouAreMyPropNowWeAreHavingSoftTacosLater
Lets you bring held & attached props through world loads.
https://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO
## Examples
https://fixupx.com/NotAKidoS/status/1910545346922422675
---
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": -1,
"name": "YouAreMyPropNowWeAreHavingSoftTacosLater",
"modversion": "1.0.0",
"gameversion": "2025r179",
"loaderversion": "0.6.1",
"modtype": "Mod",
"author": "NotAKidoS",
"description": "Lets you bring held & attached props through world loads.\nhttps://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO",
"searchtags": [
"prop",
"spawn",
"friend",
"load"
],
"requirements": [
"None"
],
"downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/YouAreMyPropNowWeAreHavingSoftTacosLater.dll",
"sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/YouAreMyPropNowWeAreHavingSoftTacosLater/",
"changelog": "- Initial Release",
"embedcolor": "#00FFFF"
}