mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 01:46:15 +00:00
Compare commits
12
Commits
0.3.7
...
runtime-options
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cff46ebd19 | ||
|
|
9270de408d | ||
|
|
8940de76bb | ||
|
|
1813fe5a84 | ||
|
|
272b14f0e0 | ||
|
|
c29e882d7e | ||
|
|
8774c9da70 | ||
|
|
51c7e248f9 | ||
|
|
02f9c20804 | ||
|
|
7f506000a4 | ||
|
|
795b6a81d7 | ||
|
|
bd8d7a3208 |
No files matched your search
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
|
|
||||||
<VersionPrefix>0.3.7</VersionPrefix>
|
<VersionPrefix>0.3.8</VersionPrefix>
|
||||||
<VersionSuffix>dev</VersionSuffix>
|
<VersionSuffix>dev</VersionSuffix>
|
||||||
|
|
||||||
<Authors>All Of Us, XtraCube, Angxl</Authors>
|
<Authors>All Of Us, XtraCube, Angxl</Authors>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ public static class ModdedOptionsManager
|
|||||||
private static readonly Dictionary<Type, AbstractOptionGroup> TypeToGroup = [];
|
private static readonly Dictionary<Type, AbstractOptionGroup> TypeToGroup = [];
|
||||||
|
|
||||||
internal static readonly Dictionary<OptionBehaviour, ModdedPlayerOption> CreatedPlayerOptions = [];
|
internal static readonly Dictionary<OptionBehaviour, ModdedPlayerOption> CreatedPlayerOptions = [];
|
||||||
|
internal static readonly Dictionary<OptionBehaviour, ModdedStringOption> CreatedStringOptions = [];
|
||||||
internal static readonly Dictionary<uint, IModdedOption> ModdedOptions = [];
|
internal static readonly Dictionary<uint, IModdedOption> ModdedOptions = [];
|
||||||
internal static readonly List<AbstractOptionGroup> Groups = [];
|
internal static readonly List<AbstractOptionGroup> Groups = [];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||||
|
using MiraAPI.Networking;
|
||||||
|
using Reactor.Localization.Utilities;
|
||||||
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace MiraAPI.GameOptions.OptionTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An option for selecting an enum value.
|
||||||
|
/// </summary>
|
||||||
|
public class ModdedStringOption : ModdedOption<string>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the string values of the option.
|
||||||
|
/// </summary>
|
||||||
|
public string[] Values { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the String Name values of the option.
|
||||||
|
/// </summary>
|
||||||
|
public StringNames[] StringNameValues { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the string's index
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The option's string value.</param>
|
||||||
|
/// <returns>The option's value in the index.</returns>
|
||||||
|
public int GetIndex(string value, int location)
|
||||||
|
{
|
||||||
|
if (Values.Contains(value))
|
||||||
|
{
|
||||||
|
return Values.ToList().IndexOf(value);
|
||||||
|
}
|
||||||
|
Info($"Cannot find a valid index for {value} in {location}. Returning 0 instead. Values: {string.Join(", ", Values)}");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a value to the option.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The option's string value.</param>
|
||||||
|
/// <param name="index">The additional value's index on the list.</param>
|
||||||
|
public void RegisterExtraValue(string value, int index = -1)
|
||||||
|
{
|
||||||
|
if (!Values.Contains(value))
|
||||||
|
{
|
||||||
|
if (index <= -1)
|
||||||
|
index = Values.Length;
|
||||||
|
|
||||||
|
var newVals = Values.ToList();
|
||||||
|
newVals.Insert(index, value);
|
||||||
|
Values = newVals.ToArray();
|
||||||
|
var newStrVals = StringNameValues.ToList();
|
||||||
|
newStrVals.Insert(index, CustomStringName.CreateAndRegister(value));
|
||||||
|
StringNameValues = newStrVals.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Data != null)
|
||||||
|
{
|
||||||
|
var data = (StringGameSetting)Data;
|
||||||
|
data.Values = StringNameValues;
|
||||||
|
|
||||||
|
data.Index = GetIndex(Value, 1);
|
||||||
|
if (OptionBehaviour != null)
|
||||||
|
{
|
||||||
|
var strOpt = OptionBehaviour.TryCast<StringOption>();
|
||||||
|
if (strOpt != null)
|
||||||
|
{
|
||||||
|
strOpt.Values = StringNameValues;
|
||||||
|
strOpt.Value = GetIndex(Value, 2);
|
||||||
|
Warning("StringOption is valid");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error("StringOption is null.");
|
||||||
|
}
|
||||||
|
Warning("OptionBehaviour is valid");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error("OptionBehaviour is null.");
|
||||||
|
}
|
||||||
|
Warning("Data is valid");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error("Data is null.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ModdedStringOption"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="title">The title of the option.</param>
|
||||||
|
/// <param name="defaultValue">The default value as a string.</param>
|
||||||
|
/// <param name="values">An option list of string values to use.</param>
|
||||||
|
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
||||||
|
public ModdedStringOption(string title, string defaultValue, string[] values, bool includeInPreset=true) : base(title, defaultValue, includeInPreset)
|
||||||
|
{
|
||||||
|
Values = values;
|
||||||
|
Data = ScriptableObject.CreateInstance<StringGameSetting>();
|
||||||
|
var data = (StringGameSetting)Data;
|
||||||
|
|
||||||
|
data.Title = StringName;
|
||||||
|
data.Type = global::OptionTypes.String;
|
||||||
|
StringNameValues = values.Select(CustomStringName.CreateAndRegister).ToArray();
|
||||||
|
data.Values = StringNameValues;
|
||||||
|
|
||||||
|
data.Index = GetIndex(Value, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
||||||
|
{
|
||||||
|
var stringOption = Object.Instantiate(stringOpt, container);
|
||||||
|
stringOption.name =
|
||||||
|
$"{ParentMod!.OptionsTitleText}.StringOption.{TranslationController.Instance.GetString(StringName)}";
|
||||||
|
|
||||||
|
stringOption.SetUpFromData(Data, 20);
|
||||||
|
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||||
|
|
||||||
|
// SetUpFromData method doesnt work correctly so we must set the values manually
|
||||||
|
stringOption.Title = StringName;
|
||||||
|
stringOption.Values = (Data as StringGameSetting)?.Values ?? new Il2CppStructArray<StringNames>(0);
|
||||||
|
stringOption.Value = GetIndex(Value, 4);
|
||||||
|
|
||||||
|
OptionBehaviour = stringOption;
|
||||||
|
ModdedOptionsManager.CreatedStringOptions.TryAdd(stringOption, this);
|
||||||
|
|
||||||
|
return stringOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override float GetFloatData()
|
||||||
|
{
|
||||||
|
return Values.IndexOf(Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override NetData GetNetData()
|
||||||
|
{
|
||||||
|
return new NetData(Id, Encoding.Unicode.GetBytes(Convert.ToString(Value, NumberFormatInfo.InvariantInfo)!));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void HandleNetData(byte[] data)
|
||||||
|
{
|
||||||
|
SetValue(Encoding.Unicode.GetString(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour)
|
||||||
|
{
|
||||||
|
return Values[optionBehaviour.GetInt()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnValueChanged(string newValue)
|
||||||
|
{
|
||||||
|
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(GetIndex(newValue, 5)), false);
|
||||||
|
if (!OptionBehaviour)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OptionBehaviour is StringOption opt)
|
||||||
|
{
|
||||||
|
opt.Value = GetIndex(newValue, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,10 +7,12 @@ using Assets.CoreScripts;
|
|||||||
using BepInEx.Unity.IL2CPP.Utils;
|
using BepInEx.Unity.IL2CPP.Utils;
|
||||||
using MiraAPI.Events;
|
using MiraAPI.Events;
|
||||||
using MiraAPI.Events.Vanilla.Gameplay;
|
using MiraAPI.Events.Vanilla.Gameplay;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
using Reactor.Networking.Attributes;
|
using Reactor.Networking.Attributes;
|
||||||
using Reactor.Networking.Rpc;
|
using Reactor.Networking.Rpc;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
using Reactor.Utilities.Extensions;
|
using Reactor.Utilities.Extensions;
|
||||||
|
using Rewired;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ namespace MiraAPI.Networking;
|
|||||||
public static class CustomMurderRpc
|
public static class CustomMurderRpc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Networked Custom Murder method.
|
/// Networked Custom Murder method, ran by clients for the host to confirm kills.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">The killer.</param>
|
/// <param name="source">The killer.</param>
|
||||||
/// <param name="target">The player to murder.</param>
|
/// <param name="target">The player to murder.</param>
|
||||||
@@ -54,7 +56,7 @@ public static class CustomMurderRpc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Networked Custom Murder method, which checks for meetings as well.
|
/// Networked Custom Murder method, which checks for meetings as well, ran by clients for the host to confirm kills.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">The killer.</param>
|
/// <param name="source">The killer.</param>
|
||||||
/// <param name="target">The player to murder.</param>
|
/// <param name="target">The player to murder.</param>
|
||||||
@@ -77,6 +79,10 @@ public static class CustomMurderRpc
|
|||||||
bool showKillAnim = true,
|
bool showKillAnim = true,
|
||||||
bool playKillSound = true)
|
bool playKillSound = true)
|
||||||
{
|
{
|
||||||
|
if (LobbyBehaviour.Instance)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
var murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError;
|
var murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError;
|
||||||
|
|
||||||
var beforeMurderEvent = new BeforeMurderEvent(source, target, inMeeting);
|
var beforeMurderEvent = new BeforeMurderEvent(source, target, inMeeting);
|
||||||
@@ -92,6 +98,52 @@ public static class CustomMurderRpc
|
|||||||
murderResultFlags = MurderResultFlags.FailedError;
|
murderResultFlags = MurderResultFlags.FailedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!PlayerControl.LocalPlayer.IsHost())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcConfirmCustomMurder(
|
||||||
|
PlayerControl.LocalPlayer,
|
||||||
|
source,
|
||||||
|
target,
|
||||||
|
murderResultFlags,
|
||||||
|
resetKillTimer,
|
||||||
|
createDeadBody,
|
||||||
|
teleportMurderer,
|
||||||
|
showKillAnim,
|
||||||
|
playKillSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Networked Custom Murder method, which checks for meetings as well, ran by clients for the host to confirm kills.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="host">The game host.</param>
|
||||||
|
/// <param name="source">The killer.</param>
|
||||||
|
/// <param name="target">The player to murder.</param>
|
||||||
|
/// <param name="murderResultFlags">End result for the murder.</param>
|
||||||
|
/// <param name="resetKillTimer">Should the kill timer be reset.</param>
|
||||||
|
/// <param name="createDeadBody">Should a dead body be created.</param>
|
||||||
|
/// <param name="teleportMurderer">Should the killer be snapped to the dead player.</param>
|
||||||
|
/// <param name="showKillAnim">Should the kill animation be shown.</param>
|
||||||
|
/// <param name="playKillSound">Should the kill sound be played.</param>
|
||||||
|
[MethodRpc((uint)MiraRpc.ConfirmCustomMurder, LocalHandling = RpcLocalHandling.Before)]
|
||||||
|
public static void RpcConfirmCustomMurder(
|
||||||
|
this PlayerControl host,
|
||||||
|
PlayerControl source,
|
||||||
|
PlayerControl target,
|
||||||
|
MurderResultFlags murderResultFlags,
|
||||||
|
bool resetKillTimer = true,
|
||||||
|
bool createDeadBody = true,
|
||||||
|
bool teleportMurderer = true,
|
||||||
|
bool showKillAnim = true,
|
||||||
|
bool playKillSound = true)
|
||||||
|
{
|
||||||
|
if (LobbyBehaviour.Instance || !host.IsHost() || target.Data.IsDead || target.Data.Disconnected)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags;
|
var murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags;
|
||||||
|
|
||||||
source.CustomMurder(
|
source.CustomMurder(
|
||||||
@@ -126,7 +178,7 @@ public static class CustomMurderRpc
|
|||||||
bool playKillSound = true)
|
bool playKillSound = true)
|
||||||
{
|
{
|
||||||
source.isKilling = false;
|
source.isKilling = false;
|
||||||
if (resultFlags.HasFlag(MurderResultFlags.FailedError))
|
if (resultFlags.HasFlag(MurderResultFlags.FailedError) || LobbyBehaviour.Instance)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -249,6 +301,10 @@ public static class CustomMurderRpc
|
|||||||
bool createDeadBody = true,
|
bool createDeadBody = true,
|
||||||
bool teleportMurderer = true)
|
bool teleportMurderer = true)
|
||||||
{
|
{
|
||||||
|
if (LobbyBehaviour.Instance)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
var cam = Camera.main?.GetComponent<FollowerCamera>();
|
var cam = Camera.main?.GetComponent<FollowerCamera>();
|
||||||
var isParticipant = source.AmOwner || target.AmOwner;
|
var isParticipant = source.AmOwner || target.AmOwner;
|
||||||
var sourcePhys = source.MyPhysics;
|
var sourcePhys = source.MyPhysics;
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ public enum MiraRpc : uint
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
CustomMurder,
|
CustomMurder,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Custom Murder RPC Confirmation.
|
||||||
|
/// </summary>
|
||||||
|
ConfirmCustomMurder,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom Game Over RPC.
|
/// Custom Game Over RPC.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -117,6 +117,20 @@ internal static class PlayerControlPatches
|
|||||||
__instance.RpcMurderPlayer(target, true);
|
__instance.RpcMurderPlayer(target, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(nameof(PlayerControl.RpcMurderPlayer))]
|
||||||
|
[HarmonyPatch(nameof(PlayerControl.MurderPlayer))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public static bool MurderPlayerPrefix(PlayerControl __instance)
|
||||||
|
{
|
||||||
|
if (LobbyBehaviour.Instance)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(nameof(PlayerControl.FixedUpdate))]
|
[HarmonyPatch(nameof(PlayerControl.FixedUpdate))]
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
|
|||||||
Reference in new issue
Block a user