mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 11:39:45 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56c2d9c0df | ||
|
|
ab5f997fb6 | ||
|
|
869d4970fd | ||
|
|
2cbbcca161 | ||
|
|
2f09baa371 | ||
|
|
acf1d44b52 | ||
|
|
03ef684691 | ||
|
|
eafc740aca | ||
|
|
7af85d9fbb | ||
|
|
bdce8fa37d | ||
|
|
9fc5044085 | ||
|
|
7cb103f318 | ||
|
|
dd8d3df2b0 |
No files matched your search
@@ -1,19 +1,28 @@
|
||||
name: CI
|
||||
|
||||
on: workflow_dispatch
|
||||
on: ["workflow_dispatch", "push", "pull_request"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.nuget/packages
|
||||
~/.cache/bepinex
|
||||
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-nuget-
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 6.x
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Run the Cake script
|
||||
uses: cake-build/cake-action@v2
|
||||
@@ -24,3 +33,19 @@ jobs:
|
||||
with:
|
||||
name: MiraAPI.dll
|
||||
path: MiraAPI/bin/Release/net6.0/MiraAPI.dll
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: AllOfUs.MiraAPI.nupkg
|
||||
path: MiraAPI/bin/Release/AllOfUs.MiraAPI.*.nupkg
|
||||
|
||||
- uses: softprops/action-gh-release@v1
|
||||
if: github.ref_type == 'tag'
|
||||
with:
|
||||
draft: true
|
||||
files: MiraAPI/bin/Release/net6.0/MiraAPI.dll
|
||||
|
||||
- name: Push NuGet package
|
||||
if: github.repository == 'All-Of-Us-Mods/MiraAPI' && github.ref == 'refs/heads/master' && github.ref_type == 'tag'
|
||||
run: |
|
||||
dotnet nuget push {MiraAPI/bin/Release/AllOfUs.MiraAPI.*.nupkg} --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
|
||||
+2
-1
@@ -4,4 +4,5 @@
|
||||
obj/
|
||||
bin/
|
||||
|
||||
*.user
|
||||
*.user
|
||||
*.lock.json
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Reactor" Version="2.3.1" />
|
||||
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.697" Private="false" ExcludeAssets="runtime;native" />
|
||||
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2024.8.13" PrivateAssets="all" />
|
||||
|
||||
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
|
||||
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.0.1" PrivateAssets="all" ExcludeAssets="runtime" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Copy" AfterTargets="Build" Condition="'$(AmongUs)' != ''">
|
||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(AmongUs)/BepInEx/plugins/" UseSymboliclinksIfPossible="true" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,40 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<DebugType>embedded</DebugType>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
|
||||
<VersionPrefix>0.1.3</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
|
||||
<Authors>All Of Us, XtraCube, Angxl</Authors>
|
||||
<Company>All Of Us</Company>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/All-Of-Us-Mods/MiraAPI</RepositoryUrl>
|
||||
<PackageLicenseExpression>LGPL-2.1-or-later</PackageLicenseExpression>
|
||||
|
||||
<!-- SourceLink -->
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
<AnalysisLevel>latest</AnalysisLevel>
|
||||
<AnalysisMode>recommended</AnalysisMode>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" PrivateAssets="all" />
|
||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)\stylecop.json" Link="stylecop.json" Visible="false" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)\stylecop.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -18,7 +18,7 @@ public class FreezeButton : CustomActionButton<PlayerControl>
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
Target.AddModifier<FreezeModifier>();
|
||||
Target?.RpcAddModifier<FreezeModifier>();
|
||||
}
|
||||
|
||||
public override PlayerControl GetTarget()
|
||||
|
||||
@@ -41,7 +41,7 @@ public class MeetingButton : CustomActionButton
|
||||
|
||||
if (UsesLeft == 0 && PlayerControl.LocalPlayer.HasModifier<CaptainModifier>())
|
||||
{
|
||||
PlayerControl.LocalPlayer.RemoveModifier<CaptainModifier>();
|
||||
PlayerControl.LocalPlayer.RpcRemoveModifier<CaptainModifier>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ public class TeleportButton : CustomActionButton
|
||||
|
||||
public override int MaxUses => 0;
|
||||
|
||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.TeleportButton;
|
||||
public static bool IsZoom { get; private set; }
|
||||
|
||||
public override bool Enabled(RoleBehaviour role)
|
||||
|
||||
@@ -5,5 +5,8 @@ namespace MiraAPI.Example;
|
||||
public static class ExampleAssets
|
||||
{
|
||||
public static LoadableResourceAsset ExampleButton { get; } = new("MiraAPI.Example.Resources.ExampleButton.png");
|
||||
|
||||
// Credit to EpicHorrors for the teleport button asset.
|
||||
public static LoadableResourceAsset TeleportButton { get; } = new("MiraAPI.Example.Resources.TeleportButton.png");
|
||||
public static LoadableResourceAsset Banner { get; } = new("MiraAPI.Example.Resources.FortniteBanner.jpeg");
|
||||
}
|
||||
@@ -1,25 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<DebugType>embedded</DebugType>
|
||||
|
||||
<VersionPrefix>1.0.0</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
<Version>1.0.0</Version>
|
||||
<Description>Example mod for Mira API</Description>
|
||||
<Authors>Angxl, XtraCube</Authors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Reactor" Version="2.3.1" />
|
||||
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.697" Private="false" ExcludeAssets="runtime;native" />
|
||||
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2024.8.13" PrivateAssets="all" />
|
||||
|
||||
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
|
||||
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" PrivateAssets="all" ExcludeAssets="runtime">
|
||||
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MiraAPI\MiraAPI.csproj" />
|
||||
@@ -28,9 +12,8 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\ExampleButton.png" />
|
||||
<EmbeddedResource Include="Resources\FortniteBanner.jpeg" />
|
||||
<EmbeddedResource Include="Resources\TeleportButton.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Copy" AfterTargets="Build" Condition="'$(AmongUs)' != ''">
|
||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(AmongUs)/BepInEx/plugins/" UseSymboliclinksIfPossible="true" />
|
||||
</Target>
|
||||
<Import Project="..\AmongUs.props" />
|
||||
</Project>
|
||||
@@ -22,13 +22,13 @@ public class ExampleOptions : AbstractOptionGroup
|
||||
[ModdedStringOption("String Opt", ["Hello", "Hey", "Bye"])]
|
||||
public int StringOpt { get; set; } = 2;
|
||||
|
||||
[ModdedEnumOption("Enum Opt", typeof(TestEnum))]
|
||||
public TestEnum EnumOpt { get; set; } = TestEnum.Mira;
|
||||
[ModdedEnumOption("Best API", typeof(BestApiEnum), ["Mira API", "Mitochondria", "Reactor"])]
|
||||
public BestApiEnum EnumOpt { get; set; } = BestApiEnum.MiraAPI;
|
||||
}
|
||||
|
||||
public enum TestEnum
|
||||
public enum BestApiEnum
|
||||
{
|
||||
Welcome,
|
||||
To,
|
||||
Mira
|
||||
MiraAPI,
|
||||
Mitochondria,
|
||||
Reactor
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -13,5 +13,5 @@ public class FreezerRole : ImpostorRole, ICustomRole
|
||||
public Color RoleColor => Palette.Blue;
|
||||
public ModdedRoleTeams Team => ModdedRoleTeams.Impostor;
|
||||
public LoadableAsset<Sprite> OptionsScreenshot => ExampleAssets.Banner;
|
||||
|
||||
public int MaxPlayers => 2;
|
||||
}
|
||||
@@ -4,12 +4,12 @@ using System.Reflection;
|
||||
|
||||
namespace MiraAPI.GameOptions.Attributes;
|
||||
|
||||
public class ModdedEnumOptionAttribute(string title, Type enumType, Type roleType = null)
|
||||
public class ModdedEnumOptionAttribute(string title, Type enumType, string[] values = null, Type roleType = null)
|
||||
: ModdedOptionAttribute(title, roleType)
|
||||
{
|
||||
internal override IModdedOption CreateOption(object value, PropertyInfo property)
|
||||
{
|
||||
var opt = new ModdedEnumOption(Title, (int)value, enumType, RoleType);
|
||||
var opt = new ModdedEnumOption(Title, (int)value, enumType, values, RoleType);
|
||||
return opt;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,14 @@ public static class ModdedOptionsManager
|
||||
|
||||
internal static void HandleSyncOptions(NetData[] data)
|
||||
{
|
||||
// necessary to disable then re-enable this setting
|
||||
// we dont know how other plugins handle their configs
|
||||
// this way, all the options are saved at once, instead of one by one
|
||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins.Values)
|
||||
{
|
||||
plugin.PluginConfig.SaveOnConfigSet = false;
|
||||
}
|
||||
|
||||
foreach (var netData in data)
|
||||
{
|
||||
if (!ModdedOptions.TryGetValue(netData.Id, out var option))
|
||||
@@ -129,7 +137,13 @@ public static class ModdedOptionsManager
|
||||
|
||||
option.HandleNetData(netData.Data);
|
||||
}
|
||||
|
||||
|
||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins.Values)
|
||||
{
|
||||
plugin.PluginConfig.Save();
|
||||
plugin.PluginConfig.SaveOnConfigSet = true;
|
||||
}
|
||||
|
||||
if (LobbyInfoPane.Instance)
|
||||
{
|
||||
LobbyInfoPane.Instance.RefreshPane();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Reactor.Localization.Utilities;
|
||||
using MiraAPI.Networking;
|
||||
using Reactor.Localization.Utilities;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MiraAPI.Networking;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
@@ -11,15 +11,18 @@ public class ModdedEnumOption : ModdedOption<int>
|
||||
{
|
||||
public string[] Values { get; }
|
||||
|
||||
public ModdedEnumOption(string title, int defaultValue, Type enumType, Type roleType=null) : base(title, defaultValue, roleType)
|
||||
public ModdedEnumOption(string title, int defaultValue, Type enumType, string[] values = null, Type roleType = null) : base(title, defaultValue, roleType)
|
||||
{
|
||||
Values = Enum.GetNames(enumType);
|
||||
Values = values is null ? Enum.GetNames(enumType) : values;
|
||||
Data = ScriptableObject.CreateInstance<StringGameSetting>();
|
||||
var data = (StringGameSetting)Data;
|
||||
|
||||
|
||||
data.Title = StringName;
|
||||
data.Type = global::OptionTypes.String;
|
||||
data.Values = Values.Select(CustomStringName.CreateAndRegister).ToArray();
|
||||
data.Values = values is null ?
|
||||
Enum.GetNames(enumType).Select(CustomStringName.CreateAndRegister).ToArray()
|
||||
: values.Select(CustomStringName.CreateAndRegister).ToArray();
|
||||
|
||||
data.Index = Value;
|
||||
}
|
||||
|
||||
@@ -29,7 +32,7 @@ public class ModdedEnumOption : ModdedOption<int>
|
||||
|
||||
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 = ((StringGameSetting)Data).Values;
|
||||
|
||||
@@ -66,14 +66,14 @@ public abstract class ModdedOption<T> : IModdedOption
|
||||
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
if (ParentMod?.GetConfigFile().TryGetEntry<T>(ConfigDefinition, out var entry) == true)
|
||||
{
|
||||
entry.Value = Value;
|
||||
}
|
||||
|
||||
Rpc<SyncOptionsRpc>.Instance.Send(PlayerControl.LocalPlayer, [GetNetData()], true);
|
||||
}
|
||||
|
||||
if (ParentMod?.GetConfigFile().TryGetEntry<T>(ConfigDefinition, out var entry) == true)
|
||||
{
|
||||
entry.Value = Value;
|
||||
}
|
||||
|
||||
OnValueChanged(newValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#nullable enable
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
@@ -55,17 +54,17 @@ public abstract class CustomActionButton
|
||||
/// <summary>
|
||||
/// Returns true if the effect is currently active.
|
||||
/// </summary>
|
||||
protected bool EffectActive;
|
||||
|
||||
/// <summary>
|
||||
/// A timer variable to measure cooldowns and effects.
|
||||
/// </summary>
|
||||
protected float Timer;
|
||||
public bool EffectActive { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of uses left.
|
||||
/// </summary>
|
||||
protected int UsesLeft;
|
||||
public int UsesLeft { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// A timer variable to measure cooldowns and effects.
|
||||
/// </summary>
|
||||
public float Timer { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// The button object in game. This is created by Mira API automatically.
|
||||
@@ -135,6 +134,61 @@ public abstract class CustomActionButton
|
||||
Button?.OverrideText(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the button's timer.
|
||||
/// </summary>
|
||||
/// <param name="amount">The amount you want to set to.</param>
|
||||
public void SetTimer(float time)
|
||||
{
|
||||
Timer = Mathf.Clamp(time, -1, float.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increase the button's timer.
|
||||
/// </summary>
|
||||
/// <param name="amount">The amount you want to increase by.</param>
|
||||
public void IncreaseTimer(float amount)
|
||||
{
|
||||
SetTimer(Timer + amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrease the button's timer.
|
||||
/// </summary>
|
||||
/// <param name="amount">The amount you want to decrease by.</param>
|
||||
public void DecreaseTimer(float amount)
|
||||
{
|
||||
SetTimer(Timer - amount);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set the amount of uses this button has left.
|
||||
/// </summary>
|
||||
/// <param name="amount">The amount you want to set to.</param>
|
||||
public void SetUses(int amount)
|
||||
{
|
||||
UsesLeft = Mathf.Clamp(amount, 0, int.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increase the amount of uses this button has left.
|
||||
/// </summary>
|
||||
/// <param name="amount">The amount you want to increase by. Default: 1</param>
|
||||
public void IncreaseUses(int amount = 1)
|
||||
{
|
||||
SetUses(UsesLeft + amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrease the amount of uses this button has left.
|
||||
/// </summary>
|
||||
/// <param name="amount">The amount you want to decrease by. Default: 1</param>
|
||||
public void DecreaseUses(int amount = 1)
|
||||
{
|
||||
SetUses(UsesLeft - amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A utility function that runs with the local PlayerControl's FixedUpdate if the button is enabled.
|
||||
/// </summary>
|
||||
|
||||
+6
-29
@@ -1,15 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<DebugType>embedded</DebugType>
|
||||
<PackageId>AllOfUs.MiraAPI</PackageId>
|
||||
<Version>0.1.2</Version>
|
||||
<Description>Simple and easy to use Among Us modding API.</Description>
|
||||
<Authors>Angxl, XtraCube</Authors>
|
||||
<Company>All Of Us</Company>
|
||||
<PackageLicenseExpression>LGPL-2.1-or-later</PackageLicenseExpression>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<PackageId>AllOfUs.MiraAPI</PackageId>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -17,27 +12,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Checkmark.png" />
|
||||
<EmbeddedResource Include="Resources\CheckMarkBox.png" />
|
||||
<EmbeddedResource Include="Resources\Cog.png" />
|
||||
<EmbeddedResource Include="Resources\CogActive.png" />
|
||||
<EmbeddedResource Include="Resources\NextButton.png" />
|
||||
<EmbeddedResource Include="Resources\NextButtonActive.png" />
|
||||
<EmbeddedResource Include="Resources\Empty.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Reactor" Version="2.3.1" />
|
||||
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.697" Private="false" ExcludeAssets="runtime;native" />
|
||||
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2024.8.13" PrivateAssets="all" />
|
||||
|
||||
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
|
||||
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" PrivateAssets="all" ExcludeAssets="runtime">
|
||||
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<EmbeddedResource Include="Resources\**\*.*" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Copy" AfterTargets="Build" Condition="'$(AmongUs)' != ''">
|
||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(AmongUs)/BepInEx/plugins/" />
|
||||
</Target>
|
||||
<Import Project="../AmongUs.props" />
|
||||
|
||||
</Project>
|
||||
@@ -1,7 +1,5 @@
|
||||
using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using System;
|
||||
@@ -38,23 +36,31 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
|
||||
|
||||
public void FixedUpdate()
|
||||
{
|
||||
if (ActiveModifiers is null) return;
|
||||
|
||||
foreach (var modifier in ActiveModifiers)
|
||||
{
|
||||
if (modifier is null) continue;
|
||||
|
||||
modifier.FixedUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (ActiveModifiers is null) return;
|
||||
|
||||
foreach (var modifier in ActiveModifiers)
|
||||
{
|
||||
if (modifier is null) continue;
|
||||
|
||||
modifier.Update();
|
||||
}
|
||||
|
||||
var filteredModifiers = ActiveModifiers.Where(mod => !mod.HideOnUi);
|
||||
|
||||
var baseModifiers = filteredModifiers as BaseModifier[] ?? filteredModifiers.ToArray();
|
||||
|
||||
|
||||
if (player.AmOwner && baseModifiers.Any())
|
||||
{
|
||||
var stringBuild = new StringBuilder();
|
||||
@@ -74,17 +80,9 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveModifier(PlayerControl target, uint modifierId)
|
||||
public void RemoveModifier(Type type)
|
||||
{
|
||||
if (!ModifierManager.IdToTypeModifiers.TryGetValue(modifierId, out var type))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Cannot remove modifier with id {modifierId} because it is not registered.");
|
||||
return;
|
||||
}
|
||||
|
||||
var modifierComponent = target.GetModifierComponent();
|
||||
|
||||
var modifier = modifierComponent?.ActiveModifiers.Find(x => x.GetType() == type);
|
||||
var modifier = ActiveModifiers.Find(x => x.GetType() == type);
|
||||
|
||||
if (modifier is null)
|
||||
{
|
||||
@@ -92,58 +90,101 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
|
||||
return;
|
||||
}
|
||||
|
||||
modifier.OnDeactivate();
|
||||
modifierComponent.ActiveModifiers.Remove(modifier);
|
||||
RemoveModifier(modifier);
|
||||
}
|
||||
|
||||
if (target.AmOwner)
|
||||
public void RemoveModifier<T>() where T : BaseModifier
|
||||
{
|
||||
RemoveModifier(typeof(T));
|
||||
}
|
||||
|
||||
public void RemoveModifier(uint modifierId)
|
||||
{
|
||||
var modifier = ActiveModifiers.Find(x => x.ModifierId == modifierId);
|
||||
|
||||
if (modifier is null)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Cannot remove modifier with id {modifierId} because it is not active.");
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveModifier(modifier);
|
||||
}
|
||||
|
||||
public void RemoveModifier(BaseModifier modifier)
|
||||
{
|
||||
if (!ActiveModifiers.Contains(modifier))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Cannot remove modifier {modifier.ModifierName} because it is not active on this player.");
|
||||
return;
|
||||
}
|
||||
|
||||
modifier.OnDeactivate();
|
||||
ActiveModifiers.Remove(modifier);
|
||||
|
||||
if (player.AmOwner)
|
||||
{
|
||||
HudManager.Instance.SetHudActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddModifier(PlayerControl target, uint modifierId)
|
||||
public BaseModifier AddModifier(BaseModifier modifier)
|
||||
{
|
||||
if (!ModifierManager.IdToTypeModifiers.TryGetValue(modifierId, out var type))
|
||||
if (ActiveModifiers.Contains(modifier))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Cannot add modifier with id {modifierId} because it is not registered.");
|
||||
return;
|
||||
Logger<MiraApiPlugin>.Error($"Player already has modifier with id {modifier.ModifierId}!");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (target.HasModifier(modifierId))
|
||||
ActiveModifiers.Add(modifier);
|
||||
modifier.Player = player;
|
||||
modifier.ModifierId = ModifierManager.TypeToIdModifiers[modifier.GetType()];
|
||||
modifier.OnActivate();
|
||||
|
||||
if (!player.AmOwner)
|
||||
{
|
||||
return modifier;
|
||||
}
|
||||
|
||||
if (modifier is TimedModifier { AutoStart: true } timer)
|
||||
{
|
||||
timer.StartTimer();
|
||||
}
|
||||
|
||||
HudManager.Instance.SetHudActive(true);
|
||||
|
||||
return modifier;
|
||||
}
|
||||
|
||||
public BaseModifier AddModifier(Type type)
|
||||
{
|
||||
if (!ModifierManager.TypeToIdModifiers.TryGetValue(type, out var modifierId))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Cannot add modifier {type.Name} because it is not registered.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ActiveModifiers.Find(x => x.ModifierId == modifierId) != null)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Player already has modifier with id {modifierId}!");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
var modifier = (BaseModifier)Activator.CreateInstance(type);
|
||||
|
||||
var modifierComponent = target.GetModifierComponent();
|
||||
|
||||
if (modifier is null)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Cannot add modifier {type.Name} because it is null.");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
modifierComponent.ActiveModifiers.Add(modifier);
|
||||
modifier.Player = modifierComponent.player;
|
||||
modifier.ModifierId = modifierId;
|
||||
modifier.OnActivate();
|
||||
AddModifier(modifier);
|
||||
|
||||
if (target.AmOwner)
|
||||
{
|
||||
if (modifier is TimedModifier { AutoStart: true } timer)
|
||||
{
|
||||
timer.StartTimer();
|
||||
}
|
||||
|
||||
HudManager.Instance.SetHudActive(true);
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
|
||||
[MethodRpc((uint)MiraRpc.RemoveModifier)]
|
||||
public static void RpcRemoveModifier(PlayerControl target, uint modifierId) => RemoveModifier(target, modifierId);
|
||||
|
||||
[MethodRpc((uint)MiraRpc.AddModifier)]
|
||||
public static void RpcAddModifier(PlayerControl target, uint modifierId) => AddModifier(target, modifierId);
|
||||
public T AddModifier<T>() where T : BaseModifier
|
||||
{
|
||||
return AddModifier(typeof(T)) as T;
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ public static class ModifierManager
|
||||
}
|
||||
|
||||
shuffledModifiers.RemoveAt(0);
|
||||
ModifierComponent.RpcAddModifier(plr, id);
|
||||
plr.RpcAddModifier(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +152,13 @@ public static class ModifierManager
|
||||
|
||||
foreach (var id in ids)
|
||||
{
|
||||
ModifierComponent.AddModifier(plr, id);
|
||||
if (!IdToTypeModifiers.TryGetValue(id, out var type))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Cannot add modifier with id {id} because it is not registered.");
|
||||
continue;
|
||||
}
|
||||
|
||||
modifierComponent.AddModifier(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Reactor.Utilities;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Modifiers.Types;
|
||||
@@ -32,7 +33,7 @@ public abstract class TimedModifier : BaseModifier
|
||||
|
||||
if (RemoveOnComplete)
|
||||
{
|
||||
ModifierComponent.RpcRemoveModifier(Player, ModifierId);
|
||||
Player.RpcRemoveModifier(ModifierId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
using AmongUs.GameOptions;
|
||||
using Assets.CoreScripts;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Networking;
|
||||
public static class CustomMurderRpcs
|
||||
{
|
||||
[MethodRpc((uint)MiraRpc.CustomMurder)]
|
||||
public static void RpcCustomMurder(this PlayerControl source, PlayerControl target, bool didSucceed = true,
|
||||
bool resetKillTimer = true, bool createDeadBody = true, bool teleportMurderer = true, bool showKillAnim = true, bool playKillSound = true)
|
||||
{
|
||||
MurderResultFlags murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError;
|
||||
MurderResultFlags murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags;
|
||||
|
||||
source.CustomMurder(target, murderResultFlags2, resetKillTimer, createDeadBody, teleportMurderer, showKillAnim, playKillSound);
|
||||
}
|
||||
|
||||
public static void CustomMurder(this PlayerControl source, PlayerControl target, MurderResultFlags resultFlags,
|
||||
bool resetKillTimer = true, bool createDeadBody = true, bool teleportMurderer = true, bool showKillAnim = true, bool playKillSound = true)
|
||||
{
|
||||
source.isKilling = false;
|
||||
source.logger.Debug(string.Format("{0} trying to murder {1}", source.PlayerId, target.PlayerId), null);
|
||||
NetworkedPlayerInfo data = target.Data;
|
||||
if (resultFlags.HasFlag(MurderResultFlags.FailedError))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (resultFlags.HasFlag(MurderResultFlags.FailedProtected) || (resultFlags.HasFlag(MurderResultFlags.DecisionByHost) && target.protectedByGuardianId > -1))
|
||||
{
|
||||
target.protectedByGuardianThisRound = true;
|
||||
bool flag = PlayerControl.LocalPlayer.Data.Role.Role == RoleTypes.GuardianAngel;
|
||||
if (flag && PlayerControl.LocalPlayer.Data.PlayerId == target.protectedByGuardianId)
|
||||
{
|
||||
StatsManager.Instance.IncrementStat(StringNames.StatsGuardianAngelCrewmatesProtected);
|
||||
DestroyableSingleton<AchievementManager>.Instance.OnProtectACrewmate();
|
||||
}
|
||||
if (source.AmOwner || flag)
|
||||
{
|
||||
target.ShowFailedMurder();
|
||||
|
||||
if (resetKillTimer)
|
||||
{
|
||||
source.SetKillTimer(GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown) / 2f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
target.RemoveProtection();
|
||||
}
|
||||
source.logger.Debug(string.Format("{0} failed to murder {1} due to guardian angel protection", source.PlayerId, target.PlayerId), null);
|
||||
return;
|
||||
}
|
||||
if (resultFlags.HasFlag(MurderResultFlags.Succeeded) || resultFlags.HasFlag(MurderResultFlags.DecisionByHost))
|
||||
{
|
||||
DestroyableSingleton<DebugAnalytics>.Instance.Analytics.Kill(target.Data, source.Data);
|
||||
if (source.AmOwner)
|
||||
{
|
||||
if (GameManager.Instance.IsHideAndSeek())
|
||||
{
|
||||
StatsManager.Instance.IncrementStat(StringNames.StatsImpostorKills_HideAndSeek);
|
||||
}
|
||||
else
|
||||
{
|
||||
StatsManager.Instance.IncrementStat(StringNames.StatsImpostorKills);
|
||||
}
|
||||
if (source.CurrentOutfitType == PlayerOutfitType.Shapeshifted)
|
||||
{
|
||||
StatsManager.Instance.IncrementStat(StringNames.StatsShapeshifterShiftedKills);
|
||||
}
|
||||
if (Constants.ShouldPlaySfx() && playKillSound)
|
||||
{
|
||||
SoundManager.Instance.PlaySound(source.KillSfx, false, 0.8f, null);
|
||||
}
|
||||
|
||||
if (resetKillTimer)
|
||||
{
|
||||
source.SetKillTimer(GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown));
|
||||
}
|
||||
}
|
||||
DestroyableSingleton<UnityTelemetry>.Instance.WriteMurder();
|
||||
target.gameObject.layer = LayerMask.NameToLayer("Ghost");
|
||||
if (target.AmOwner)
|
||||
{
|
||||
StatsManager.Instance.IncrementStat(StringNames.StatsTimesMurdered);
|
||||
if (Minigame.Instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
Minigame.Instance.Close();
|
||||
Minigame.Instance.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (showKillAnim)
|
||||
{
|
||||
DestroyableSingleton<HudManager>.Instance.KillOverlay.ShowKillAnimation(source.Data, data);
|
||||
}
|
||||
|
||||
target.cosmetics.SetNameMask(false);
|
||||
target.RpcSetScanner(false);
|
||||
}
|
||||
DestroyableSingleton<AchievementManager>.Instance.OnMurder(source.AmOwner, target.AmOwner, source.CurrentOutfitType == PlayerOutfitType.Shapeshifted, source.shapeshiftTargetPlayerId, (int)target.PlayerId);
|
||||
Coroutines.Start(source.KillAnimations.Random().CoPerformCustomKill(source, target, createDeadBody, teleportMurderer));
|
||||
source.logger.Debug(string.Format("{0} succeeded in murdering {1}", source.PlayerId, target.PlayerId), null);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerator CoPerformCustomKill(this KillAnimation anim, PlayerControl source, PlayerControl target,
|
||||
bool createDeadBody = true, bool teleportMurderer = true)
|
||||
{
|
||||
FollowerCamera cam = Camera.main.GetComponent<FollowerCamera>();
|
||||
bool isParticipant = PlayerControl.LocalPlayer == source || PlayerControl.LocalPlayer == target;
|
||||
PlayerPhysics sourcePhys = source.MyPhysics;
|
||||
|
||||
if (teleportMurderer)
|
||||
{
|
||||
KillAnimation.SetMovement(source, false);
|
||||
}
|
||||
|
||||
KillAnimation.SetMovement(target, false);
|
||||
|
||||
if (isParticipant)
|
||||
{
|
||||
PlayerControl.LocalPlayer.isKilling = true;
|
||||
source.isKilling = true;
|
||||
}
|
||||
|
||||
DeadBody deadBody = null;
|
||||
|
||||
if (createDeadBody)
|
||||
{
|
||||
deadBody = Object.Instantiate(GameManager.Instance.DeadBodyPrefab);
|
||||
deadBody.enabled = false;
|
||||
deadBody.ParentId = target.PlayerId;
|
||||
deadBody.bodyRenderers.ToArray().ToList().ForEach(target.SetPlayerMaterialColors);
|
||||
|
||||
target.SetPlayerMaterialColors(deadBody.bloodSplatter);
|
||||
Vector3 vector = target.transform.position + anim.BodyOffset;
|
||||
vector.z = vector.y / 1000f;
|
||||
deadBody.transform.position = vector;
|
||||
}
|
||||
|
||||
if (isParticipant)
|
||||
{
|
||||
cam.Locked = true;
|
||||
ConsoleJoystick.SetMode_Task();
|
||||
if (PlayerControl.LocalPlayer.AmOwner)
|
||||
{
|
||||
PlayerControl.LocalPlayer.MyPhysics.inputHandler.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
target.Die(DeathReason.Kill, true);
|
||||
yield return source.MyPhysics.Animations.CoPlayCustomAnimation(anim.BlurAnim);
|
||||
sourcePhys.Animations.PlayIdleAnimation();
|
||||
|
||||
if (teleportMurderer)
|
||||
{
|
||||
source.NetTransform.SnapTo(target.transform.position);
|
||||
KillAnimation.SetMovement(source, true);
|
||||
}
|
||||
KillAnimation.SetMovement(target, true);
|
||||
|
||||
if (deadBody)
|
||||
{
|
||||
deadBody.enabled = true;
|
||||
}
|
||||
|
||||
if (isParticipant)
|
||||
{
|
||||
cam.Locked = false;
|
||||
PlayerControl.LocalPlayer.isKilling = false;
|
||||
source.isKilling = false;
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
@@ -6,5 +6,6 @@ public enum MiraRpc : uint
|
||||
SyncRoleOptions,
|
||||
AddModifier,
|
||||
RemoveModifier,
|
||||
SyncModifiers
|
||||
SyncModifiers,
|
||||
CustomMurder,
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
@@ -8,7 +9,6 @@ using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
@@ -224,7 +224,7 @@ public static class RoleSettingMenuPatches
|
||||
__instance.roleScreenshot.drawMode = SpriteDrawMode.Sliced;
|
||||
__instance.roleHeaderSprite.color = customRole.RoleColor;
|
||||
__instance.roleHeaderText.color = customRole.RoleColor.GetAlternateColor();
|
||||
|
||||
|
||||
var bg = __instance.AdvancedRolesSettings.transform.Find("Background");
|
||||
bg.localPosition = new Vector3(1.4041f, -7.08f, 0);
|
||||
bg.GetComponent<SpriteRenderer>().size = new Vector2(89.4628f, 100);
|
||||
@@ -237,7 +237,7 @@ public static class RoleSettingMenuPatches
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
optionBehaviour.OnValueChanged = new Action<OptionBehaviour>(__instance.ValueChanged);
|
||||
if (AmongUsClient.Instance && !AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
@@ -263,7 +263,7 @@ public static class RoleSettingMenuPatches
|
||||
roleOptionSetting.titleText.transform.localPosition = new Vector3(-0.5376f, -0.2923f, 0f);
|
||||
roleOptionSetting.titleText.color = customRole.RoleColor.GetAlternateColor();
|
||||
roleOptionSetting.titleText.horizontalAlignment = HorizontalAlignmentOptions.Left;
|
||||
|
||||
|
||||
if (GameSettingMenuPatches.SelectedMod is null ||
|
||||
GameSettingMenuPatches.SelectedMod.Options.Any(x => x.AdvancedRole != null && x.AdvancedRole.IsInstanceOfType(role)))
|
||||
{
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using AmongUs.GameOptions;
|
||||
using Il2CppInterop.Runtime;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
@@ -9,8 +11,6 @@ using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
using MiraAPI.Utilities;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
@@ -20,11 +20,11 @@ namespace MiraAPI.Roles;
|
||||
public static class CustomRoleManager
|
||||
{
|
||||
public static readonly Dictionary<ushort, RoleBehaviour> CustomRoles = new();
|
||||
|
||||
|
||||
public static readonly Dictionary<Type, ushort> RoleIds = new();
|
||||
|
||||
|
||||
private static ushort _roleId = 100;
|
||||
|
||||
|
||||
private static ushort GetNextRoleId()
|
||||
{
|
||||
return _roleId++;
|
||||
@@ -37,8 +37,8 @@ public static class CustomRoleManager
|
||||
|
||||
public static void RegisterRoleTypes(List<Type> roles, MiraPluginInfo pluginInfo)
|
||||
{
|
||||
roles.ForEach(x=>RoleIds.Add(x, GetNextRoleId()));
|
||||
|
||||
roles.ForEach(x => RoleIds.Add(x, GetNextRoleId()));
|
||||
|
||||
foreach (var roleType in roles)
|
||||
{
|
||||
ClassInjector.RegisterTypeInIl2Cpp(roleType);
|
||||
@@ -68,7 +68,7 @@ public static class CustomRoleManager
|
||||
roleBehaviour.gameObject.Destroy();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var roleId = RoleIds[roleType];
|
||||
|
||||
roleBehaviour.Role = (RoleTypes)roleId;
|
||||
@@ -83,7 +83,7 @@ public static class CustomRoleManager
|
||||
roleBehaviour.TasksCountTowardProgress = customRole.TasksCount;
|
||||
roleBehaviour.CanVent = customRole.CanUseVent;
|
||||
roleBehaviour.DefaultGhostRole = customRole.GhostRole;
|
||||
roleBehaviour.MaxCount = 15;
|
||||
roleBehaviour.MaxCount = customRole.MaxPlayers;
|
||||
roleBehaviour.RoleScreenshot = customRole.OptionsScreenshot.LoadAsset();
|
||||
|
||||
if (customRole.IsGhostRole)
|
||||
@@ -101,7 +101,7 @@ public static class CustomRoleManager
|
||||
var config = parentMod.PluginConfig;
|
||||
config.Bind(customRole.NumConfigDefinition, 1);
|
||||
config.Bind(customRole.ChanceConfigDefinition, 100);
|
||||
|
||||
|
||||
return roleBehaviour;
|
||||
}
|
||||
|
||||
@@ -156,8 +156,8 @@ public static class CustomRoleManager
|
||||
|
||||
panel.SetTaskText(role.SetTabText().ToString());
|
||||
}
|
||||
|
||||
internal static void SyncAllRoleSettings(int targetId=-1)
|
||||
|
||||
internal static void SyncAllRoleSettings(int targetId = -1)
|
||||
{
|
||||
var data = CustomRoles.Values
|
||||
.Where(x => x is ICustomRole { HideSettings: false })
|
||||
@@ -172,6 +172,16 @@ public static class CustomRoleManager
|
||||
|
||||
internal static void HandleSyncRoleOptions(NetData[] data)
|
||||
{
|
||||
// necessary to disable then re-enable this setting
|
||||
// we dont know how other plugins handle their configs
|
||||
// this way, all the options are saved at once, instead of one by one
|
||||
var oldConfigSetting = new Dictionary<MiraPluginInfo, bool>();
|
||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins.Values)
|
||||
{
|
||||
oldConfigSetting.Add(plugin, plugin.PluginConfig.SaveOnConfigSet);
|
||||
plugin.PluginConfig.SaveOnConfigSet = false;
|
||||
}
|
||||
|
||||
foreach (var netData in data)
|
||||
{
|
||||
if (!CustomRoles.TryGetValue((ushort)netData.Id, out var role))
|
||||
@@ -187,7 +197,7 @@ public static class CustomRoleManager
|
||||
|
||||
var num = BitConverter.ToInt32(netData.Data, 0);
|
||||
var chance = BitConverter.ToInt32(netData.Data, 4);
|
||||
|
||||
|
||||
DestroyableSingleton<HudManager>.Instance.Notifier.AddRoleSettingsChangeMessage(role.StringName, num, chance, role.TeamType, false);
|
||||
|
||||
try
|
||||
@@ -206,6 +216,12 @@ public static class CustomRoleManager
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins.Values)
|
||||
{
|
||||
plugin.PluginConfig.Save();
|
||||
plugin.PluginConfig.SaveOnConfigSet = oldConfigSetting[plugin];
|
||||
}
|
||||
|
||||
if (LobbyInfoPane.Instance)
|
||||
{
|
||||
LobbyInfoPane.Instance.RefreshPane();
|
||||
|
||||
@@ -3,11 +3,11 @@ using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using System;
|
||||
using System.Text;
|
||||
using MiraAPI.PluginLoading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Roles;
|
||||
@@ -24,6 +24,8 @@ public interface ICustomRole
|
||||
|
||||
ModdedRoleTeams Team { get; }
|
||||
|
||||
int MaxPlayers => 15;
|
||||
|
||||
LoadableAsset<Sprite> OptionsScreenshot => MiraAssets.Empty;
|
||||
|
||||
LoadableAsset<Sprite> Icon => MiraAssets.Empty;
|
||||
@@ -53,7 +55,7 @@ public interface ICustomRole
|
||||
RoleTypes GhostRole => Team == ModdedRoleTeams.Crewmate ? RoleTypes.CrewmateGhost : RoleTypes.ImpostorGhost;
|
||||
|
||||
MiraPluginInfo ParentMod => CustomRoleManager.FindParentMod(this);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Runs on the PlayerControl FixedUpdate method for any player with this role
|
||||
/// </summary>
|
||||
@@ -76,7 +78,7 @@ public interface ICustomRole
|
||||
var taskStringBuilder = Helpers.CreateForRole(this);
|
||||
return taskStringBuilder;
|
||||
}
|
||||
|
||||
|
||||
bool IsModifierApplicable(BaseModifier modifier)
|
||||
{
|
||||
return true;
|
||||
@@ -86,7 +88,7 @@ public interface ICustomRole
|
||||
{
|
||||
ParentMod.PluginConfig.TryGetEntry<int>(NumConfigDefinition, out var numEntry);
|
||||
ParentMod.PluginConfig.TryGetEntry<int>(ChanceConfigDefinition, out var chanceEntry);
|
||||
|
||||
|
||||
return new NetData(RoleId.Get(GetType()), BitConverter.GetBytes(numEntry.Value).AddRangeToArray(BitConverter.GetBytes(chanceEntry.Value)));
|
||||
}
|
||||
}
|
||||
@@ -1,62 +1,62 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers;
|
||||
using Reactor.Utilities;
|
||||
using System.Linq;
|
||||
using MiraAPI.Networking;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Utilities;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static bool IsStatic(this Type type)
|
||||
public static bool IsStatic(this System.Type type)
|
||||
{
|
||||
return type is { IsClass: true, IsAbstract: true, IsSealed: true };
|
||||
}
|
||||
|
||||
|
||||
public static Color32 GetShadowColor(this Color32 color, byte darknessAmount)
|
||||
{
|
||||
return
|
||||
new Color32((byte)Mathf.Clamp(color.r - darknessAmount, 0, 255), (byte)Mathf.Clamp(color.g - darknessAmount, 0, 255),
|
||||
(byte)Mathf.Clamp(color.b - darknessAmount, 0, 255), byte.MaxValue);
|
||||
}
|
||||
|
||||
|
||||
public static string? Truncate(this string? value, int maxLength, string truncationSuffix = "…")
|
||||
{
|
||||
return value?.Length > maxLength
|
||||
? value[..maxLength] + truncationSuffix
|
||||
: value;
|
||||
}
|
||||
|
||||
|
||||
public static Queue<NetData[]> ChunkNetData(this IEnumerable<NetData> dataCollection, int chunkSize)
|
||||
{
|
||||
Queue<NetData[]> chunks = [];
|
||||
List<NetData> current = [];
|
||||
|
||||
|
||||
var count = 0;
|
||||
foreach (var netData in dataCollection)
|
||||
{
|
||||
var length = netData.GetLength();
|
||||
|
||||
|
||||
if (length > chunkSize)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"NetData length is greater than chunk size: {length} > {chunkSize}");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (count + length > chunkSize)
|
||||
{
|
||||
chunks.Enqueue(current.ToArray());
|
||||
current.Clear();
|
||||
count = 0;
|
||||
}
|
||||
|
||||
|
||||
current.Add(netData);
|
||||
}
|
||||
|
||||
|
||||
if (current.Count > 0)
|
||||
{
|
||||
chunks.Enqueue(current.ToArray());
|
||||
@@ -64,16 +64,29 @@ public static class Extensions
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static bool IsCustom(this OptionBehaviour optionBehaviour)
|
||||
{
|
||||
return ModdedOptionsManager.ModdedOptions.Values.Any(opt => opt.OptionBehaviour && opt.OptionBehaviour.Equals(optionBehaviour));
|
||||
}
|
||||
|
||||
public static readonly Dictionary<PlayerControl, ModifierComponent> ModifierComponents = new();
|
||||
|
||||
public static ModifierComponent? GetModifierComponent(this PlayerControl player)
|
||||
{
|
||||
return player.GetComponent<ModifierComponent>();
|
||||
if (ModifierComponents.TryGetValue(player, out var component))
|
||||
{
|
||||
return component;
|
||||
}
|
||||
|
||||
component = player.GetComponent<ModifierComponent>();
|
||||
if (component)
|
||||
{
|
||||
ModifierComponents[player] = component;
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
public static List<T> Randomize<T>(this List<T> list)
|
||||
@@ -89,16 +102,40 @@ public static class Extensions
|
||||
return randomizedList;
|
||||
}
|
||||
|
||||
public static T? GetModifier<T>(this PlayerControl? player) where T : BaseModifier
|
||||
{
|
||||
return player?.GetModifierComponent()?.ActiveModifiers.Find(x => x is T) as T;
|
||||
}
|
||||
|
||||
public static bool HasModifier<T>(this PlayerControl? player) where T : BaseModifier
|
||||
{
|
||||
return player?.GetModifierComponent() != null && player.GetModifierComponent()!.ActiveModifiers.Exists(x => x is T);
|
||||
}
|
||||
|
||||
public static bool HasModifier(this PlayerControl? player, uint id)
|
||||
{
|
||||
return player?.GetModifierComponent() != null && player.GetModifierComponent()!.ActiveModifiers.Exists(x => x.ModifierId == id);
|
||||
}
|
||||
|
||||
public static void AddModifier<T>(this PlayerControl player) where T : BaseModifier
|
||||
[MethodRpc((uint)MiraRpc.RemoveModifier)]
|
||||
public static void RpcRemoveModifier(this PlayerControl target, uint modifierId)
|
||||
{
|
||||
target.GetModifierComponent()?.RemoveModifier(modifierId);
|
||||
}
|
||||
|
||||
[MethodRpc((uint)MiraRpc.AddModifier)]
|
||||
public static BaseModifier? RpcAddModifier(this PlayerControl target, uint modifierId)
|
||||
{
|
||||
if (ModifierManager.IdToTypeModifiers.TryGetValue(modifierId, out var type))
|
||||
{
|
||||
return target.GetModifierComponent()?.AddModifier(type);
|
||||
}
|
||||
|
||||
Logger<MiraApiPlugin>.Error($"Cannot add modifier with id {modifierId} because it is not registered.");
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void RpcAddModifier<T>(this PlayerControl player) where T : BaseModifier
|
||||
{
|
||||
if (!ModifierManager.TypeToIdModifiers.TryGetValue(typeof(T), out var id))
|
||||
{
|
||||
@@ -106,10 +143,10 @@ public static class Extensions
|
||||
return;
|
||||
}
|
||||
|
||||
ModifierComponent.RpcAddModifier(player, id);
|
||||
player.RpcAddModifier(id);
|
||||
}
|
||||
|
||||
public static void RemoveModifier<T>(this PlayerControl player) where T : BaseModifier
|
||||
public static void RpcRemoveModifier<T>(this PlayerControl player) where T : BaseModifier
|
||||
{
|
||||
if (!ModifierManager.TypeToIdModifiers.TryGetValue(typeof(T), out var id))
|
||||
{
|
||||
@@ -117,21 +154,21 @@ public static class Extensions
|
||||
return;
|
||||
}
|
||||
|
||||
ModifierComponent.RpcRemoveModifier(player, id);
|
||||
player.RpcAddModifier(id);
|
||||
}
|
||||
|
||||
public static Color DarkenColor(this Color color)
|
||||
public static Color DarkenColor(this Color color, float amount = 0.45f)
|
||||
{
|
||||
return new Color(color.r - 0.45f, color.g - 0.45f, color.b - 0.45f);
|
||||
return new Color(color.r - amount, color.g - amount, color.b - amount);
|
||||
}
|
||||
public static Color GetAlternateColor(this Color color)
|
||||
public static Color GetAlternateColor(this Color color, float amount = 0.45f)
|
||||
{
|
||||
return color.IsColorDark() ? LightenColor(color) : DarkenColor(color);
|
||||
return color.IsColorDark() ? LightenColor(color, amount) : DarkenColor(color, amount);
|
||||
}
|
||||
|
||||
public static Color LightenColor(this Color color)
|
||||
public static Color LightenColor(this Color color, float amount = 0.45f)
|
||||
{
|
||||
return new Color(color.r + 0.45f, color.g + 0.45f, color.b + 0.45f);
|
||||
return new Color(color.r + amount, color.g + amount, color.b + amount);
|
||||
}
|
||||
|
||||
public static bool IsColorDark(this Color color)
|
||||
@@ -139,60 +176,27 @@ public static class Extensions
|
||||
return color.r < 0.5f && color is { g: < 0.5f, b: < 0.5f };
|
||||
}
|
||||
|
||||
public static DeadBody? NearestDeadBody(this PlayerControl playerControl, float radius)
|
||||
public static DeadBody? GetNearestDeadBody(this PlayerControl playerControl, float radius)
|
||||
{
|
||||
var results = new Il2CppSystem.Collections.Generic.List<Collider2D>();
|
||||
Physics2D.OverlapCircle(playerControl.GetTruePosition(), radius, Helpers.Filter, results);
|
||||
return results.ToArray()
|
||||
.Where(collider2D => collider2D.CompareTag("DeadBody"))
|
||||
.Select(collider2D => collider2D.GetComponent<DeadBody>())
|
||||
.FirstOrDefault(component => component && !component.Reported);
|
||||
return Helpers.GetNearestDeadBodies(playerControl.GetTruePosition(), radius).FirstOrDefault(component => component && !component.Reported);
|
||||
}
|
||||
|
||||
public static T? GetNearestObjectOfType<T>(this PlayerControl playerControl, float radius, string? colliderTag=null, Func<T, bool>? predicate=null) where T : Component
|
||||
public static T? GetNearestObjectOfType<T>(this PlayerControl playerControl, float radius, string? colliderTag = null, System.Func<T, bool>? predicate = null) where T : Component
|
||||
{
|
||||
var results = new Il2CppSystem.Collections.Generic.List<Collider2D>();
|
||||
Physics2D.OverlapCircle(playerControl.GetTruePosition(), radius, Helpers.Filter, results);
|
||||
return results.ToArray()
|
||||
.Where(collider2D => colliderTag == null || collider2D.CompareTag(colliderTag))
|
||||
.Select(collider2D => collider2D.GetComponent<T>())
|
||||
.FirstOrDefault(predicate ?? (component => component));
|
||||
return Helpers.GetNearestObjectsOfType<T>(playerControl.GetTruePosition(), radius, colliderTag).FirstOrDefault(predicate ?? (component => component));
|
||||
}
|
||||
|
||||
public static PlayerControl? GetClosestPlayer(this PlayerControl playerControl, bool includeImpostors, float distance)
|
||||
public static PlayerControl? GetClosestPlayer(this PlayerControl playerControl, bool includeImpostors, float distance, bool ignoreColliders = false)
|
||||
{
|
||||
PlayerControl? result = null;
|
||||
if (!ShipStatus.Instance)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var truePosition = playerControl.GetTruePosition();
|
||||
var filteredPlayers = Helpers.GetClosestPlayers(playerControl, distance, ignoreColliders)
|
||||
.Where(playerInfo => !playerInfo.Data.Disconnected && playerInfo.PlayerId != playerControl.PlayerId && !playerInfo.Data.IsDead &&
|
||||
(includeImpostors || !playerInfo.Data.Role.IsImpostor));
|
||||
|
||||
var filteredPlayers = GameData.Instance.AllPlayers.ToArray()
|
||||
.Where(playerInfo => !playerInfo.Disconnected && playerInfo.PlayerId != playerControl.PlayerId && !playerInfo.IsDead &&
|
||||
(includeImpostors || !playerInfo.Role.IsImpostor));
|
||||
|
||||
foreach (var playerInfo in filteredPlayers)
|
||||
{
|
||||
var @object = playerInfo.Object;
|
||||
if (!@object)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var vector = @object.GetTruePosition() - truePosition;
|
||||
var magnitude = vector.magnitude;
|
||||
if (!(magnitude <= distance) || PhysicsHelpers.AnyNonTriggersBetween(truePosition,
|
||||
vector.normalized,
|
||||
magnitude, LayerMask.GetMask("Ship", "Objects")))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = @object;
|
||||
distance = magnitude;
|
||||
}
|
||||
return result;
|
||||
return filteredPlayers.First();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using MiraAPI.Roles;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.Utilities;
|
||||
|
||||
@@ -14,6 +16,102 @@ public static class Helpers
|
||||
return ShipStatus.Instance.AllRooms.ToList().Find(room => room.roomArea.OverlapPoint(pos));
|
||||
}
|
||||
|
||||
public static List<DeadBody> GetNearestDeadBodies(Vector2 source, float radius)
|
||||
{
|
||||
var results = new Il2CppSystem.Collections.Generic.List<Collider2D>();
|
||||
Physics2D.OverlapCircle(source, radius, Filter, results);
|
||||
return results.ToArray()
|
||||
.Where(collider2D => collider2D.CompareTag("DeadBody"))
|
||||
.Select(collider2D => collider2D.GetComponent<DeadBody>()).ToList();
|
||||
}
|
||||
|
||||
public static List<T> GetNearestObjectsOfType<T>(Vector2 source, float radius, string colliderTag = null) where T : Component
|
||||
{
|
||||
var results = new Il2CppSystem.Collections.Generic.List<Collider2D>();
|
||||
Physics2D.OverlapCircle(source, radius, Filter, results);
|
||||
return results.ToArray()
|
||||
.Where(collider2D => colliderTag == null || collider2D.CompareTag(colliderTag))
|
||||
.Select(collider2D => collider2D.GetComponent<T>()).ToList();
|
||||
}
|
||||
|
||||
public static List<PlayerControl> GetClosestPlayersInCircle(Vector2 source, float radius, bool ignoreColliders = true)
|
||||
{
|
||||
List<PlayerControl> newList = GetNearestObjectsOfType<PlayerControl>(source, radius);
|
||||
|
||||
if (ignoreColliders)
|
||||
{
|
||||
List<PlayerControl> filteredList = new List<PlayerControl>();
|
||||
foreach (var player in newList)
|
||||
{
|
||||
Vector2 vector = player.GetTruePosition() - source;
|
||||
float magnitude = vector.magnitude;
|
||||
if (!PhysicsHelpers.AnyNonTriggersBetween(source, vector.normalized, magnitude, Constants.ShipAndObjectsMask))
|
||||
{
|
||||
filteredList.Add(player);
|
||||
}
|
||||
}
|
||||
|
||||
return filteredList;
|
||||
}
|
||||
|
||||
return newList;
|
||||
}
|
||||
public static List<PlayerControl> GetClosestPlayers(PlayerControl source, float distance = 2f, bool ignoreColliders = true, bool ignoreSource = true)
|
||||
{
|
||||
if (!ShipStatus.Instance)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Vector2 myPos = source.GetTruePosition();
|
||||
List<PlayerControl> players = GetClosestPlayers(myPos, distance, ignoreColliders);
|
||||
|
||||
return ignoreSource ? players.Where(plr => plr.PlayerId != source.PlayerId).ToList() : players;
|
||||
}
|
||||
|
||||
public static List<PlayerControl> GetClosestPlayers(Vector2 source, float distance = 2f, bool ignoreColliders = true)
|
||||
{
|
||||
if (!ShipStatus.Instance)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<PlayerControl> outputList = new List<PlayerControl>();
|
||||
outputList.Clear();
|
||||
List<NetworkedPlayerInfo> allPlayers = GameData.Instance.AllPlayers.ToArray().ToList();
|
||||
|
||||
for (int i = 0; i < allPlayers.Count; i++)
|
||||
{
|
||||
NetworkedPlayerInfo networkedPlayerInfo = allPlayers[i];
|
||||
|
||||
PlayerControl @object = networkedPlayerInfo.Object;
|
||||
if (@object && @object.Collider.enabled)
|
||||
{
|
||||
Vector2 vector = @object.GetTruePosition() - source;
|
||||
float magnitude = vector.magnitude;
|
||||
if (magnitude <= distance && (ignoreColliders || !PhysicsHelpers.AnyNonTriggersBetween(source, vector.normalized, magnitude, Constants.ShipAndObjectsMask)))
|
||||
{
|
||||
outputList.Add(@object);
|
||||
}
|
||||
}
|
||||
}
|
||||
outputList.Sort(delegate (PlayerControl a, PlayerControl b)
|
||||
{
|
||||
float magnitude2 = (a.GetTruePosition() - source).magnitude;
|
||||
float magnitude3 = (b.GetTruePosition() - source).magnitude;
|
||||
if (magnitude2 > magnitude3)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (magnitude2 < magnitude3)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return outputList;
|
||||
}
|
||||
|
||||
public static TextMeshPro CreateTextLabel(string name, Transform parent,
|
||||
AspectPosition.EdgeAlignments alignment, Vector3 distance, float fontSize = 2f,
|
||||
TextAlignmentOptions textAlignment = TextAlignmentOptions.Center)
|
||||
|
||||
@@ -180,6 +180,15 @@ public class MyOptionsGroup : AbstractOptionGroup
|
||||
|
||||
An example can be found [here](https://github.com/All-Of-Us-Mods/MiraAPI/blob/master/MiraAPI.Example/Options/Roles/CustomRoleSettings.cs).
|
||||
|
||||
## Custom Murders
|
||||
Mira API provides it's own implementation for murders. Our implementation allows for more customization on kills, and helps bypass server checks.
|
||||
You can use `PlayerControl.RpcCustomMurder` to perform a networked custom murder, or `PlayerControl.CustomMurder` to normally perform a custom murder.
|
||||
For example:
|
||||
```cs
|
||||
PlayerControl.LocalPlayer.RpcCustomMurder(Target, createDeadBody: false, teleportMurderer: false, playKillSound: false, resetKillTimer: false, showKillAnim: false);
|
||||
```
|
||||
This will kill a player without creating a dead body and without teleporting the murderer.
|
||||
|
||||
## Buttons
|
||||
|
||||
Mira API provides a simple interface for adding ability buttons to the game. There is only 2 steps:
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
|
||||
"settings": {
|
||||
"orderingRules": {
|
||||
"usingDirectivesPlacement": "outsideNamespace"
|
||||
},
|
||||
"layoutRules": {
|
||||
"newlineAtEndOfFile": "require",
|
||||
"allowDoWhileOnClosingBrace": true
|
||||
},
|
||||
"documentationRules": {
|
||||
"xmlHeader": false,
|
||||
"documentInterfaces": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
<?xml version="1.0"?>
|
||||
<RuleSet Name="StyleCop.Analyzers rules with default action"
|
||||
Description="StyleCop.Analyzers with default action. Rules with IsEnabledByDefault = false are disabled."
|
||||
ToolsVersion="14.0">
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.SpecialRules">
|
||||
<Rule Id="SA0001" Action="None" /> <!-- XML comment analysis disabled -->
|
||||
<Rule Id="SA0002" Action="Warning" /> <!-- Invalid settings file -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.SpacingRules">
|
||||
<Rule Id="SA1000" Action="Warning" /> <!-- Keywords should be spaced correctly -->
|
||||
<Rule Id="SA1001" Action="Warning" /> <!-- Commas should be spaced correctly -->
|
||||
<Rule Id="SA1002" Action="Warning" /> <!-- Semicolons should be spaced correctly -->
|
||||
<Rule Id="SA1003" Action="None" /> <!-- Symbols should be spaced correctly -->
|
||||
<Rule Id="SA1004" Action="Warning" /> <!-- Documentation lines should begin with single space -->
|
||||
<Rule Id="SA1005" Action="Warning" /> <!-- Single line comments should begin with single space -->
|
||||
<Rule Id="SA1006" Action="Warning" /> <!-- Preprocessor keywords should not be preceded by space -->
|
||||
<Rule Id="SA1007" Action="Warning" /> <!-- Operator keyword should be followed by space -->
|
||||
<Rule Id="SA1008" Action="None" /> <!-- Opening parenthesis should be spaced correctly -->
|
||||
<Rule Id="SA1009" Action="None" /> <!-- Closing parenthesis should be spaced correctly -->
|
||||
<Rule Id="SA1010" Action="Warning" /> <!-- Opening square brackets should be spaced correctly -->
|
||||
<Rule Id="SA1011" Action="Warning" /> <!-- Closing square brackets should be spaced correctly -->
|
||||
<Rule Id="SA1012" Action="Warning" /> <!-- Opening braces should be spaced correctly -->
|
||||
<Rule Id="SA1013" Action="Warning" /> <!-- Closing braces should be spaced correctly -->
|
||||
<Rule Id="SA1014" Action="Warning" /> <!-- Opening generic brackets should be spaced correctly -->
|
||||
<Rule Id="SA1015" Action="Warning" /> <!-- Closing generic brackets should be spaced correctly -->
|
||||
<Rule Id="SA1016" Action="Warning" /> <!-- Opening attribute brackets should be spaced correctly -->
|
||||
<Rule Id="SA1017" Action="Warning" /> <!-- Closing attribute brackets should be spaced correctly -->
|
||||
<Rule Id="SA1018" Action="Warning" /> <!-- Nullable type symbols should be spaced correctly -->
|
||||
<Rule Id="SA1019" Action="Warning" /> <!-- Member access symbols should be spaced correctly -->
|
||||
<Rule Id="SA1020" Action="Warning" /> <!-- Increment decrement symbols should be spaced correctly -->
|
||||
<Rule Id="SA1021" Action="Warning" /> <!-- Negative signs should be spaced correctly -->
|
||||
<Rule Id="SA1022" Action="Warning" /> <!-- Positive signs should be spaced correctly -->
|
||||
<Rule Id="SA1023" Action="Warning" /> <!-- Dereference and access of symbols should be spaced correctly -->
|
||||
<Rule Id="SA1024" Action="Warning" /> <!-- Colons should be spaced correctly -->
|
||||
<Rule Id="SA1025" Action="Warning" /> <!-- Code should not contain multiple whitespace in a row -->
|
||||
<Rule Id="SA1026" Action="Warning" /> <!-- Code should not contain space after new or stackalloc keyword in implicitly typed array allocation -->
|
||||
<Rule Id="SA1027" Action="Warning" /> <!-- Use tabs correctly -->
|
||||
<Rule Id="SA1028" Action="Warning" /> <!-- Code should not contain trailing whitespace -->
|
||||
</Rules>
|
||||
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.ReadabilityRules">
|
||||
<Rule Id="SA1100" Action="Warning" /> <!-- Do not prefix calls with base unless local implementation exists -->
|
||||
<Rule Id="SA1101" Action="None" /> <!-- Prefix local calls with this -->
|
||||
<Rule Id="SA1102" Action="Warning" /> <!-- Query clause should follow previous clause -->
|
||||
<Rule Id="SA1103" Action="Warning" /> <!-- Query clauses should be on separate lines or all on one line -->
|
||||
<Rule Id="SA1104" Action="Warning" /> <!-- Query clause should begin on new line when previous clause spans multiple lines -->
|
||||
<Rule Id="SA1105" Action="Warning" /> <!-- Query clauses spanning multiple lines should begin on own line -->
|
||||
<Rule Id="SA1106" Action="Warning" /> <!-- Code should not contain empty statements -->
|
||||
<Rule Id="SA1107" Action="Warning" /> <!-- Code should not contain multiple statements on one line -->
|
||||
<Rule Id="SA1108" Action="Warning" /> <!-- Block statements should not contain embedded comments -->
|
||||
<Rule Id="SA1109" Action="None" /> <!-- Block statements should not contain embedded regions -->
|
||||
<Rule Id="SA1110" Action="Warning" /> <!-- Opening parenthesis or bracket should be on declaration line -->
|
||||
<Rule Id="SA1111" Action="None" /> <!-- Closing parenthesis should be on line of last parameter -->
|
||||
<Rule Id="SA1112" Action="Warning" /> <!-- Closing parenthesis should be on line of opening parenthesis -->
|
||||
<Rule Id="SA1113" Action="Warning" /> <!-- Comma should be on the same line as previous parameter -->
|
||||
<Rule Id="SA1114" Action="Warning" /> <!-- Parameter list should follow declaration -->
|
||||
<Rule Id="SA1115" Action="Warning" /> <!-- Parameter should follow comma -->
|
||||
<Rule Id="SA1116" Action="Warning" /> <!-- Split parameters should start on line after declaration -->
|
||||
<Rule Id="SA1117" Action="Warning" /> <!-- Parameters should be on same line or separate lines -->
|
||||
<Rule Id="SA1118" Action="None" /> <!-- Parameter should not span multiple lines -->
|
||||
<Rule Id="SA1120" Action="Warning" /> <!-- Comments should contain text -->
|
||||
<Rule Id="SA1121" Action="Warning" /> <!-- Use built-in type alias -->
|
||||
<Rule Id="SA1122" Action="Warning" /> <!-- Use string.Empty for empty strings -->
|
||||
<Rule Id="SA1123" Action="Warning" /> <!-- Do not place regions within elements -->
|
||||
<Rule Id="SA1124" Action="Warning" /> <!-- Do not use regions -->
|
||||
<Rule Id="SA1125" Action="Warning" /> <!-- Use shorthand for nullable types -->
|
||||
<Rule Id="SA1126" Action="None" /> <!-- Prefix calls correctly -->
|
||||
<Rule Id="SA1127" Action="None" /> <!-- Generic type constraints should be on their own line -->
|
||||
<Rule Id="SA1128" Action="None" /> <!-- Put constructor initializers on their own line -->
|
||||
<Rule Id="SA1129" Action="Warning" /> <!-- Do not use default value type constructor -->
|
||||
<Rule Id="SA1130" Action="Warning" /> <!-- Use lambda syntax -->
|
||||
<Rule Id="SA1131" Action="Warning" /> <!-- Use readable conditions -->
|
||||
<Rule Id="SA1132" Action="None" /> <!-- Do not combine fields -->
|
||||
<Rule Id="SA1133" Action="None" /> <!-- Do not combine attributes -->
|
||||
<Rule Id="SA1134" Action="Warning" /> <!-- Attributes should not share line -->
|
||||
<Rule Id="SA1135" Action="Warning" /> <!-- Using directives should be qualified -->
|
||||
<Rule Id="SA1136" Action="Warning" /> <!-- Enum values should be on separate lines -->
|
||||
<Rule Id="SA1137" Action="Warning" /> <!-- Elements should have the same indentation -->
|
||||
<Rule Id="SA1139" Action="Warning" /> <!-- Use literal suffix notation instead of casting -->
|
||||
<Rule Id="SX1101" Action="None" /> <!-- Do not prefix local calls with 'this.' -->
|
||||
</Rules>
|
||||
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.OrderingRules">
|
||||
<Rule Id="SA1200" Action="Warning" /> <!-- Using directives should be placed correctly -->
|
||||
<Rule Id="SA1201" Action="None" /> <!-- Elements should appear in the correct order -->
|
||||
<Rule Id="SA1202" Action="None" /> <!-- Elements should be ordered by access -->
|
||||
<Rule Id="SA1203" Action="None" /> <!-- Constants should appear before fields -->
|
||||
<Rule Id="SA1204" Action="None" /> <!-- Static elements should appear before instance elements -->
|
||||
<Rule Id="SA1205" Action="None" /> <!-- Partial elements should declare access -->
|
||||
<Rule Id="SA1206" Action="Warning" /> <!-- Declaration keywords should follow order -->
|
||||
<Rule Id="SA1207" Action="Warning" /> <!-- Protected should come before internal -->
|
||||
<Rule Id="SA1208" Action="None" /> <!-- System using directives should be placed before other using directives -->
|
||||
<Rule Id="SA1209" Action="Warning" /> <!-- Using alias directives should be placed after other using directives -->
|
||||
<Rule Id="SA1210" Action="Warning" /> <!-- Using directives should be ordered alphabetically by namespace -->
|
||||
<Rule Id="SA1211" Action="Warning" /> <!-- Using alias directives should be ordered alphabetically by alias name -->
|
||||
<Rule Id="SA1212" Action="Warning" /> <!-- Property accessors should follow order -->
|
||||
<Rule Id="SA1213" Action="Warning" /> <!-- Event accessors should follow order -->
|
||||
<Rule Id="SA1214" Action="None" /> <!-- Readonly fields should appear before non-readonly fields -->
|
||||
<Rule Id="SA1216" Action="None" /> <!-- Using static directives should be placed at the correct location -->
|
||||
<Rule Id="SA1217" Action="Warning" /> <!-- Using static directives should be ordered alphabetically -->
|
||||
</Rules>
|
||||
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.NamingRules">
|
||||
<Rule Id="SA1300" Action="None" /> <!-- Element should begin with upper-case letter -->
|
||||
<Rule Id="SA1301" Action="None" /> <!-- Element should begin with lower-case letter -->
|
||||
<Rule Id="SA1302" Action="Warning" /> <!-- Interface names should begin with I -->
|
||||
<Rule Id="SA1303" Action="Warning" /> <!-- Const field names should begin with upper-case letter -->
|
||||
<Rule Id="SA1304" Action="Warning" /> <!-- Non-private readonly fields should begin with upper-case letter -->
|
||||
<Rule Id="SA1305" Action="None" /> <!-- Field names should not use Hungarian notation -->
|
||||
<Rule Id="SA1306" Action="Warning" /> <!-- Field names should begin with lower-case letter -->
|
||||
<Rule Id="SA1307" Action="Warning" /> <!-- Accessible fields should begin with upper-case letter -->
|
||||
<Rule Id="SA1308" Action="Warning" /> <!-- Variable names should not be prefixed -->
|
||||
<Rule Id="SA1309" Action="None" /> <!-- Field names should not begin with underscore -->
|
||||
<Rule Id="SA1310" Action="Warning" /> <!-- Field names should not contain underscore -->
|
||||
<Rule Id="SA1311" Action="Warning" /> <!-- Static readonly fields should begin with upper-case letter -->
|
||||
<Rule Id="SA1312" Action="Warning" /> <!-- Variable names should begin with lower-case letter -->
|
||||
<Rule Id="SA1313" Action="None" /> <!-- Parameter names should begin with lower-case letter -->
|
||||
<Rule Id="SA1314" Action="Warning" /> <!-- Type parameter names should begin with T -->
|
||||
<Rule Id="SX1309" Action="None" /> <!-- Field names should begin with underscore -->
|
||||
<Rule Id="SX1309S" Action="None" /> <!-- Static field names should begin with underscore -->
|
||||
</Rules>
|
||||
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.MaintainabilityRules">
|
||||
<Rule Id="SA1119" Action="Warning" /> <!-- Statement should not use unnecessary parenthesis -->
|
||||
<Rule Id="SA1400" Action="Warning" /> <!-- Access modifier should be declared -->
|
||||
<Rule Id="SA1401" Action="Warning" /> <!-- Fields should be private -->
|
||||
<Rule Id="SA1402" Action="None" /> <!-- File may only contain a single type -->
|
||||
<Rule Id="SA1403" Action="Warning" /> <!-- File may only contain a single namespace -->
|
||||
<Rule Id="SA1404" Action="Warning" /> <!-- Code analysis suppression should have justification -->
|
||||
<Rule Id="SA1405" Action="Warning" /> <!-- Debug.Assert should provide message text -->
|
||||
<Rule Id="SA1406" Action="Warning" /> <!-- Debug.Fail should provide message text -->
|
||||
<Rule Id="SA1407" Action="None" /> <!-- Arithmetic expressions should declare precedence -->
|
||||
<Rule Id="SA1408" Action="Warning" /> <!-- Conditional expressions should declare precedence -->
|
||||
<Rule Id="SA1409" Action="None" /> <!-- Remove unnecessary code -->
|
||||
<Rule Id="SA1410" Action="Warning" /> <!-- Remove delegate parenthesis when possible -->
|
||||
<Rule Id="SA1411" Action="Warning" /> <!-- Attribute constructor should not use unnecessary parenthesis -->
|
||||
<Rule Id="SA1412" Action="None" /> <!-- Store files as UTF-8 with byte order mark -->
|
||||
<Rule Id="SA1413" Action="Warning" /> <!-- Use trailing comma in multi-line initializers -->
|
||||
</Rules>
|
||||
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.LayoutRules">
|
||||
<Rule Id="SA1500" Action="Warning" /> <!-- Braces for multi-line statements should not share line -->
|
||||
<Rule Id="SA1501" Action="None" /> <!-- Statement should not be on a single line -->
|
||||
<Rule Id="SA1502" Action="Warning" /> <!-- Element should not be on a single line -->
|
||||
<Rule Id="SA1503" Action="None" /> <!-- Braces should not be omitted -->
|
||||
<Rule Id="SA1504" Action="Warning" /> <!-- All accessors should be single-line or multi-line -->
|
||||
<Rule Id="SA1505" Action="Warning" /> <!-- Opening braces should not be followed by blank line -->
|
||||
<Rule Id="SA1506" Action="Warning" /> <!-- Element documentation headers should not be followed by blank line -->
|
||||
<Rule Id="SA1507" Action="Warning" /> <!-- Code should not contain multiple blank lines in a row -->
|
||||
<Rule Id="SA1508" Action="Warning" /> <!-- Closing braces should not be preceded by blank line -->
|
||||
<Rule Id="SA1509" Action="Warning" /> <!-- Opening braces should not be preceded by blank line -->
|
||||
<Rule Id="SA1510" Action="Warning" /> <!-- Chained statement blocks should not be preceded by blank line -->
|
||||
<Rule Id="SA1511" Action="Warning" /> <!-- While-do footer should not be preceded by blank line -->
|
||||
<Rule Id="SA1512" Action="Warning" /> <!-- Single-line comments should not be followed by blank line -->
|
||||
<Rule Id="SA1513" Action="None" /> <!-- Closing brace should be followed by blank line -->
|
||||
<Rule Id="SA1514" Action="Warning" /> <!-- Element documentation header should be preceded by blank line -->
|
||||
<Rule Id="SA1515" Action="None" /> <!-- Single-line comment should be preceded by blank line -->
|
||||
<Rule Id="SA1516" Action="None" /> <!-- Elements should be separated by blank line -->
|
||||
<Rule Id="SA1517" Action="Warning" /> <!-- Code should not contain blank lines at start of file -->
|
||||
<Rule Id="SA1518" Action="Warning" /> <!-- Use line endings correctly at end of file -->
|
||||
<Rule Id="SA1519" Action="Warning" /> <!-- Braces should not be omitted from multi-line child statement -->
|
||||
<Rule Id="SA1520" Action="Warning" /> <!-- Use braces consistently -->
|
||||
</Rules>
|
||||
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.DocumentationRules">
|
||||
<Rule Id="SA1600" Action="None" /> <!-- Elements should be documented -->
|
||||
<Rule Id="SA1601" Action="None" /> <!-- Partial elements should be documented -->
|
||||
<Rule Id="SA1602" Action="None" /> <!-- Enumeration items should be documented -->
|
||||
<Rule Id="SA1603" Action="Warning" /> <!-- Documentation should contain valid XML -->
|
||||
<Rule Id="SA1604" Action="Warning" /> <!-- Element documentation should have summary -->
|
||||
<Rule Id="SA1605" Action="Warning" /> <!-- Partial element documentation should have summary -->
|
||||
<Rule Id="SA1606" Action="Warning" /> <!-- Element documentation should have summary text -->
|
||||
<Rule Id="SA1607" Action="Warning" /> <!-- Partial element documentation should have summary text -->
|
||||
<Rule Id="SA1608" Action="Warning" /> <!-- Element documentation should not have default summary -->
|
||||
<Rule Id="SA1609" Action="None" /> <!-- Property documentation should have value -->
|
||||
<Rule Id="SA1610" Action="Warning" /> <!-- Property documentation should have value text -->
|
||||
<Rule Id="SA1611" Action="Warning" /> <!-- Element parameters should be documented -->
|
||||
<Rule Id="SA1612" Action="Warning" /> <!-- Element parameter documentation should match element parameters -->
|
||||
<Rule Id="SA1613" Action="Warning" /> <!-- Element parameter documentation should declare parameter name -->
|
||||
<Rule Id="SA1614" Action="Warning" /> <!-- Element parameter documentation should have text -->
|
||||
<Rule Id="SA1615" Action="Warning" /> <!-- Element return value should be documented -->
|
||||
<Rule Id="SA1616" Action="Warning" /> <!-- Element return value documentation should have text -->
|
||||
<Rule Id="SA1617" Action="Warning" /> <!-- Void return value should not be documented -->
|
||||
<Rule Id="SA1618" Action="Warning" /> <!-- Generic type parameters should be documented -->
|
||||
<Rule Id="SA1619" Action="Warning" /> <!-- Generic type parameters should be documented partial class -->
|
||||
<Rule Id="SA1620" Action="Warning" /> <!-- Generic type parameter documentation should match type parameters -->
|
||||
<Rule Id="SA1621" Action="Warning" /> <!-- Generic type parameter documentation should declare parameter name -->
|
||||
<Rule Id="SA1622" Action="Warning" /> <!-- Generic type parameter documentation should have text -->
|
||||
<Rule Id="SA1623" Action="Warning" /> <!-- Property summary documentation should match accessors -->
|
||||
<Rule Id="SA1624" Action="Warning" /> <!-- Property summary documentation should omit accessor with restricted access -->
|
||||
<Rule Id="SA1625" Action="Warning" /> <!-- Element documentation should not be copied and pasted -->
|
||||
<Rule Id="SA1626" Action="Warning" /> <!-- Single-line comments should not use documentation style slashes -->
|
||||
<Rule Id="SA1627" Action="Warning" /> <!-- Documentation text should not be empty -->
|
||||
<Rule Id="SA1628" Action="Warning" /> <!-- Documentation text should begin with a capital letter -->
|
||||
<Rule Id="SA1629" Action="Warning" /> <!-- Documentation text should end with a period -->
|
||||
<Rule Id="SA1630" Action="Warning" /> <!-- Documentation text should contain whitespace -->
|
||||
<Rule Id="SA1631" Action="Warning" /> <!-- Documentation should meet character percentage -->
|
||||
<Rule Id="SA1632" Action="Warning" /> <!-- Documentation text should meet minimum character length -->
|
||||
<Rule Id="SA1633" Action="None" /> <!-- File should have header -->
|
||||
<Rule Id="SA1634" Action="Warning" /> <!-- File header should show copyright -->
|
||||
<Rule Id="SA1635" Action="Warning" /> <!-- File header should have copyright text -->
|
||||
<Rule Id="SA1636" Action="Warning" /> <!-- File header copyright text should match -->
|
||||
<Rule Id="SA1637" Action="Warning" /> <!-- File header should contain file name -->
|
||||
<Rule Id="SA1638" Action="Warning" /> <!-- File header file name documentation should match file name -->
|
||||
<Rule Id="SA1639" Action="Warning" /> <!-- File header should have summary -->
|
||||
<Rule Id="SA1640" Action="Warning" /> <!-- File header should have valid company text -->
|
||||
<Rule Id="SA1641" Action="Warning" /> <!-- File header company name text should match -->
|
||||
<Rule Id="SA1642" Action="Warning" /> <!-- Constructor summary documentation should begin with standard text -->
|
||||
<Rule Id="SA1643" Action="Warning" /> <!-- Destructor summary documentation should begin with standard text -->
|
||||
<Rule Id="SA1644" Action="Warning" /> <!-- Documentation headers should not contain blank lines -->
|
||||
<Rule Id="SA1645" Action="Warning" /> <!-- Included documentation file does not exist -->
|
||||
<Rule Id="SA1646" Action="Warning" /> <!-- Included documentation XPath does not exist -->
|
||||
<Rule Id="SA1647" Action="Warning" /> <!-- Include node does not contain valid file and path -->
|
||||
<Rule Id="SA1648" Action="None" /> <!-- Inheritdoc should be used with inheriting class -->
|
||||
<Rule Id="SA1649" Action="None" /> <!-- File name should match first type name -->
|
||||
<Rule Id="SA1650" Action="Warning" /> <!-- Element documentation should be spelled correctly -->
|
||||
<Rule Id="SA1651" Action="Warning" /> <!-- Do not use placeholder elements -->
|
||||
</Rules>
|
||||
</RuleSet>
|
||||
Reference in new issue
Block a user