Compare commits

...
12 Commits
6 changed files with 257 additions and 4 deletions

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<VersionPrefix>0.3.7</VersionPrefix>
<VersionPrefix>0.3.8</VersionPrefix>
<VersionSuffix>dev</VersionSuffix>
<Authors>All Of Us, XtraCube, Angxl</Authors>
@@ -24,6 +24,7 @@ public static class ModdedOptionsManager
private static readonly Dictionary<Type, AbstractOptionGroup> TypeToGroup = [];
internal static readonly Dictionary<OptionBehaviour, ModdedPlayerOption> CreatedPlayerOptions = [];
internal static readonly Dictionary<OptionBehaviour, ModdedStringOption> CreatedStringOptions = [];
internal static readonly Dictionary<uint, IModdedOption> ModdedOptions = [];
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);
}
}
}
+59 -3
View File
@@ -7,10 +7,12 @@ using Assets.CoreScripts;
using BepInEx.Unity.IL2CPP.Utils;
using MiraAPI.Events;
using MiraAPI.Events.Vanilla.Gameplay;
using MiraAPI.Utilities;
using Reactor.Networking.Attributes;
using Reactor.Networking.Rpc;
using Reactor.Utilities;
using Reactor.Utilities.Extensions;
using Rewired;
using UnityEngine;
using Object = UnityEngine.Object;
@@ -22,7 +24,7 @@ namespace MiraAPI.Networking;
public static class CustomMurderRpc
{
/// <summary>
/// Networked Custom Murder method.
/// Networked Custom Murder method, ran by clients for the host to confirm kills.
/// </summary>
/// <param name="source">The killer.</param>
/// <param name="target">The player to murder.</param>
@@ -54,7 +56,7 @@ public static class CustomMurderRpc
}
/// <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>
/// <param name="source">The killer.</param>
/// <param name="target">The player to murder.</param>
@@ -77,6 +79,10 @@ public static class CustomMurderRpc
bool showKillAnim = true,
bool playKillSound = true)
{
if (LobbyBehaviour.Instance)
{
return;
}
var murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError;
var beforeMurderEvent = new BeforeMurderEvent(source, target, inMeeting);
@@ -92,6 +98,52 @@ public static class CustomMurderRpc
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;
source.CustomMurder(
@@ -126,7 +178,7 @@ public static class CustomMurderRpc
bool playKillSound = true)
{
source.isKilling = false;
if (resultFlags.HasFlag(MurderResultFlags.FailedError))
if (resultFlags.HasFlag(MurderResultFlags.FailedError) || LobbyBehaviour.Instance)
{
return;
}
@@ -249,6 +301,10 @@ public static class CustomMurderRpc
bool createDeadBody = true,
bool teleportMurderer = true)
{
if (LobbyBehaviour.Instance)
{
yield break;
}
var cam = Camera.main?.GetComponent<FollowerCamera>();
var isParticipant = source.AmOwner || target.AmOwner;
var sourcePhys = source.MyPhysics;
+5
View File
@@ -35,6 +35,11 @@ public enum MiraRpc : uint
/// </summary>
CustomMurder,
/// <summary>
/// Custom Murder RPC Confirmation.
/// </summary>
ConfirmCustomMurder,
/// <summary>
/// Custom Game Over RPC.
/// </summary>
+14
View File
@@ -117,6 +117,20 @@ internal static class PlayerControlPatches
__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]
[HarmonyPatch(nameof(PlayerControl.FixedUpdate))]
// ReSharper disable once InconsistentNaming