Use System.Text.Json with BepInEx (#1)

When running via BepInEx, Unity's JsonUtility produces and reads empty documents.

As a bit of a hacky fix, this builds using System.Text.Json. granted, this pulls new deps in. All of the deps listed in the csproj will need to be included in the install package for BepInEx.

Reviewed-on: #1
Co-authored-by: Adele Reed <virepri2k@gmail.com>
Co-committed-by: Adele Reed <virepri2k@gmail.com>
This commit is contained in:
Adele Reed 2024-08-06 17:26:31 +00:00 committed by beerpsi
parent 971f8f6c2b
commit 3ed7191acf
24 changed files with 284 additions and 61 deletions

View File

@ -20,24 +20,22 @@
https://nuget.bepinex.dev/v3/index.json
</RestoreAdditionalProjectSources>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'BepInEx (Debug)|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<OutputPath>bin\BepInEx (Debug)\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'BepInEx (Release)|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<OutputPath>bin\BepInEx (Release)\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="System"/>

10
Rizu.Core/App.config Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?><configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -29,11 +29,21 @@ public class Exporter
{
yield break;
}
var user = Singleton<UserDataManager>.Instance.GetUserData(score.PlayerIndex);
var import = ScoreConversion.CreateScoreBatchManual(score);
yield return SubmitImport(import, user.Detail.AccessCode);
var user = Singleton<UserDataManager>.Instance.GetUserData(score.PlayerIndex);
string import = "";
try
{
import = ScoreConversion.CreateScoreBatchManual(score);
}
catch (Exception exception)
{
Logger.Error(exception.ToString());
}
if (import != "")
yield return SubmitImport(import, user.Detail.AccessCode);
}
public IEnumerator ExportDan(UserDetail userDetail)
@ -123,9 +133,10 @@ public class Exporter
TachiResponse<BatchManualResponseBody> resp;
Logger.Debug("Received response from Tachi (Response code {1}): {0}", req.downloadHandler.text, req.responseCode);
try
{
resp = JsonUtility.FromJson<TachiResponse<BatchManualResponseBody>>(req.downloadHandler.text);
resp = JsonShim.Deserialize<TachiResponse<BatchManualResponseBody>>(req.downloadHandler.text);
}
catch (Exception e)
{
@ -139,12 +150,11 @@ public class Exporter
yield break;
}
Logger.Info("{0}", resp.description);
var pollUrl = resp.body?.url;
if (string.IsNullOrEmpty(pollUrl))
{
Logger.Debug("Received no poll uri!");
yield break;
}
@ -170,7 +180,7 @@ public class Exporter
try
{
pollResp = JsonUtility.FromJson<TachiResponse<ImportStatusResponseBody>>(pollReq.downloadHandler.text);
pollResp = JsonShim.Deserialize<TachiResponse<ImportStatusResponseBody>>(pollReq.downloadHandler.text);
}
catch (Exception e)
{

39
Rizu.Core/JsonShim.cs Normal file
View File

@ -0,0 +1,39 @@
namespace Rizu.Core;
/*
* JsonShim creates a single place that JSON APIs get called from, to avoid having to manually write precompiler directives every time.
* Never call a JSON package directly, always call via JsonShim.
*/
#if MONOMOD
using UnityEngine;
using System;
#else
using System.Text.Json;
#endif
public class JsonShim
{
public static string Serialize(object Target)
{
#if MONOMOD
return JsonUtility.ToJson(Target);
#else
return JsonSerializer.Serialize(Target);
#endif
}
public static T Deserialize<T>(string data)
{
#if MONOMOD
return JsonUtility.FromJson<T>(data);
#else
return JsonSerializer.Deserialize<T>(data);
#endif
}
}
#if MONOMOD
[AttributeUsage(AttributeTargets.Property | System.AttributeTargets.Field, AllowMultiple = false)]
public class JsonIncludeAttribute : Attribute { }
#endif

View File

@ -1,11 +1,18 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class BatchManual
{
[JsonInclude]
public BatchManualMeta meta = new();
public BatchManualScore[] scores;
[JsonInclude]
public BatchManualScore[] scores;
[JsonInclude]
public BatchManualMatchingClass classes;
}

View File

@ -1,9 +1,14 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class BatchManualDan
{
[JsonInclude]
public string dan;
}

View File

@ -1,9 +1,14 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class BatchManualMatchingClass
{
[JsonInclude]
public string matchingClass;
}

View File

@ -1,11 +1,18 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class BatchManualMeta
{
[JsonInclude]
public string game = "maimaidx";
[JsonInclude]
public string playtype = "Single";
[JsonInclude]
public string service = "Rizu";
}

View File

@ -1,11 +1,18 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class BatchManualOptional
{
[JsonInclude]
public uint fast;
[JsonInclude]
public uint slow;
[JsonInclude]
public uint maxCombo;
}

View File

@ -1,11 +1,18 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class BatchManualRankUp
{
[JsonInclude]
public BatchManualMeta meta = new();
[JsonInclude]
public BatchManualScore[] scores;
[JsonInclude]
public BatchManualDan classes;
}

View File

@ -1,9 +1,14 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class BatchManualResponseBody
{
[JsonInclude]
public string url;
}

View File

@ -1,16 +1,28 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class BatchManualScore
{
[JsonInclude]
public float percent;
[JsonInclude]
public string lamp;
[JsonInclude]
public string matchType = "songTitle";
[JsonInclude]
public string identifier;
[JsonInclude]
public string difficulty;
[JsonInclude]
public long timeAchieved;
[JsonInclude]
public BatchManualScoreJudgements judgements;
[JsonInclude]
public BatchManualOptional optional;
}

View File

@ -1,13 +1,22 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class BatchManualScoreJudgements
{
[JsonInclude]
public uint pcrit;
[JsonInclude]
public uint perfect;
[JsonInclude]
public uint great;
[JsonInclude]
public uint good;
[JsonInclude]
public uint miss;
}

View File

@ -1,11 +1,18 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class ImportDocument
{
[JsonInclude]
public string[] scoreIDs;
[JsonInclude]
public ImportErrContent[] errors;
[JsonInclude]
public SessionInfoReturn[] createdSessions;
}

View File

@ -1,10 +1,16 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class ImportErrContent
{
[JsonInclude]
public string type;
[JsonInclude]
public string message;
}

View File

@ -1,10 +1,16 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class ImportProgress
{
[JsonInclude]
public string description;
[JsonInclude]
public int value;
}

View File

@ -1,11 +1,18 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class ImportStatusResponseBody
{
[JsonInclude]
public string importStatus;
[JsonInclude]
public ImportProgress progress;
[JsonInclude]
public ImportDocument import;
}

View File

@ -1,10 +1,16 @@
using System;
#if BEPINEX
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class SessionInfoReturn
{
[JsonInclude]
public string type;
[JsonInclude]
public string sessionID;
}

View File

@ -1,11 +1,18 @@
using System;
#if BEPINEX // When we're building for BepInEx, the dummy JsonInclude is *not* defined, so let's cover that base.
using System.Text.Json.Serialization;
#endif
namespace Rizu.Core.Models;
[Serializable]
public class TachiResponse<T>
{
[JsonInclude]
public bool success;
[JsonInclude]
public string description;
[JsonInclude]
public T body;
}

View File

@ -15,25 +15,83 @@
<FileAlignment>512</FileAlignment>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'MonoMod (Release)|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<DefineConstants>MONOMOD;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<OutputPath>bin\MonoMod (Release)\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'MonoMod (Debug)|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>MONOMOD;DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<OutputPath>bin\MonoMod (Debug)\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<ItemGroup Condition="$(DefineConstants.Contains(MONOMOD))">
<Reference Include="UnityEngine.JSONSerializeModule">
<HintPath>..\External\UnityEngine.JSONSerializeModule.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'BepInEx (Debug)|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>BEPINEX;DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<OutputPath>bin\BepInEx (Debug)\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'BepInEx (Release)|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<DefineConstants>BEPINEX;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<OutputPath>bin\BepInEx (Release)\</OutputPath>
</PropertyGroup>
<ItemGroup Condition="$(DefineConstants.Contains(BEPINEX))">
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=8.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Json.8.0.4\lib\net462\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
</Reference>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Reference Include="System"/>
<Reference Include="System.Core"/>
@ -47,10 +105,6 @@
<HintPath>..\External\UnityEngine.CoreModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.JSONSerializeModule">
<HintPath>..\External\UnityEngine.JSONSerializeModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestModule">
<HintPath>..\External\UnityEngine.UnityWebRequestModule.dll</HintPath>
<Private>False</Private>
@ -60,6 +114,7 @@
<Compile Include="Config.cs" />
<Compile Include="Exporter.cs" />
<Compile Include="ForceAcceptAllCertificateHandler.cs" />
<Compile Include="JsonShim.cs" />
<Compile Include="Logger.cs" />
<Compile Include="Models\BatchManual.cs" />
<Compile Include="Models\BatchManualDan.cs" />

View File

@ -3,7 +3,6 @@ using DB;
using MAI2.Util;
using Manager;
using Rizu.Core.Models;
using UnityEngine;
namespace Rizu.Core;
@ -89,7 +88,7 @@ public static class ScoreConversion
score.matchType = "tachiSongID";
}
return JsonUtility.ToJson(new BatchManual
return JsonShim.Serialize(new BatchManual
{
meta = new BatchManualMeta(),
scores = [score],
@ -108,7 +107,7 @@ public static class ScoreConversion
return null;
}
return JsonUtility.ToJson(new BatchManualRankUp
return JsonShim.Serialize(new BatchManualRankUp
{
meta = new BatchManualMeta(),
scores = [],

12
Rizu.Core/packages.config Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net462" />
<package id="System.Buffers" version="4.5.1" targetFramework="net462" />
<package id="System.Memory" version="4.5.5" targetFramework="net462" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net462" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net462" />
<package id="System.Text.Encodings.Web" version="8.0.0" targetFramework="net462" />
<package id="System.Text.Json" version="8.0.4" targetFramework="net462" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net462" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net462" />
</packages>

View File

@ -15,24 +15,11 @@
<FileAlignment>512</FileAlignment>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'MonoMod (Debug)|AnyCPU' ">
<OutputPath>bin\MonoMod (Debug)\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'MonoMod (Release)|AnyCPU' ">
<OutputPath>bin\MonoMod (Release)\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="System"/>

View File

@ -8,21 +8,31 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rizu.BepInEx", "Rizu.BepInE
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
MonoMod (Debug)|Any CPU = MonoMod (Debug)|Any CPU
MonoMod (Release)|Any CPU = MonoMod (Release)|Any CPU
BepInEx (Release)|Any CPU = BepInEx (Release)|Any CPU
BepInEx (Debug)|Any CPU = BepInEx (Debug)|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4241A369-1619-4450-8182-CB66F447985F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.Release|Any CPU.Build.0 = Release|Any CPU
{888E076C-8A77-453F-87DC-BC0186FDBB55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{888E076C-8A77-453F-87DC-BC0186FDBB55}.Debug|Any CPU.Build.0 = Debug|Any CPU
{888E076C-8A77-453F-87DC-BC0186FDBB55}.Release|Any CPU.ActiveCfg = Release|Any CPU
{888E076C-8A77-453F-87DC-BC0186FDBB55}.Release|Any CPU.Build.0 = Release|Any CPU
{4DDF918E-7A74-4266-B56A-028D66ED336F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4DDF918E-7A74-4266-B56A-028D66ED336F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4DDF918E-7A74-4266-B56A-028D66ED336F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4DDF918E-7A74-4266-B56A-028D66ED336F}.Release|Any CPU.Build.0 = Release|Any CPU
{4DDF918E-7A74-4266-B56A-028D66ED336F}.MonoMod (Debug)|Any CPU.ActiveCfg = BepInEx (Debug)|Any CPU
{4DDF918E-7A74-4266-B56A-028D66ED336F}.MonoMod (Release)|Any CPU.ActiveCfg = BepInEx (Release)|Any CPU
{4DDF918E-7A74-4266-B56A-028D66ED336F}.BepInEx (Release)|Any CPU.ActiveCfg = BepInEx (Release)|Any CPU
{4DDF918E-7A74-4266-B56A-028D66ED336F}.BepInEx (Release)|Any CPU.Build.0 = BepInEx (Release)|Any CPU
{4DDF918E-7A74-4266-B56A-028D66ED336F}.BepInEx (Debug)|Any CPU.ActiveCfg = BepInEx (Debug)|Any CPU
{4DDF918E-7A74-4266-B56A-028D66ED336F}.BepInEx (Debug)|Any CPU.Build.0 = BepInEx (Debug)|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.MonoMod (Debug)|Any CPU.ActiveCfg = MonoMod (Debug)|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.MonoMod (Debug)|Any CPU.Build.0 = MonoMod (Debug)|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.MonoMod (Release)|Any CPU.ActiveCfg = MonoMod (Release)|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.MonoMod (Release)|Any CPU.Build.0 = MonoMod (Release)|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.BepInEx (Release)|Any CPU.ActiveCfg = BepInEx (Release)|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.BepInEx (Release)|Any CPU.Build.0 = BepInEx (Release)|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.BepInEx (Debug)|Any CPU.ActiveCfg = BepInEx (Debug)|Any CPU
{4241A369-1619-4450-8182-CB66F447985F}.BepInEx (Debug)|Any CPU.Build.0 = BepInEx (Debug)|Any CPU
{888E076C-8A77-453F-87DC-BC0186FDBB55}.MonoMod (Debug)|Any CPU.ActiveCfg = MonoMod (Debug)|Any CPU
{888E076C-8A77-453F-87DC-BC0186FDBB55}.MonoMod (Debug)|Any CPU.Build.0 = MonoMod (Debug)|Any CPU
{888E076C-8A77-453F-87DC-BC0186FDBB55}.MonoMod (Release)|Any CPU.ActiveCfg = MonoMod (Release)|Any CPU
{888E076C-8A77-453F-87DC-BC0186FDBB55}.MonoMod (Release)|Any CPU.Build.0 = MonoMod (Release)|Any CPU
{888E076C-8A77-453F-87DC-BC0186FDBB55}.BepInEx (Release)|Any CPU.ActiveCfg = MonoMod (Release)|Any CPU
{888E076C-8A77-453F-87DC-BC0186FDBB55}.BepInEx (Debug)|Any CPU.ActiveCfg = MonoMod (Debug)|Any CPU
EndGlobalSection
EndGlobal