Compare commits

..

4 Commits

Author SHA1 Message Date
3ed7191acf 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>
2024-08-06 17:26:31 +00:00
971f8f6c2b Update README.md 2024-06-01 17:52:53 +00:00
18c559847c Add warning for MelonLoader 2024-06-01 07:41:41 +00:00
a664f59f4b Create external folder for dependencies 2024-05-23 16:25:12 +07:00
27 changed files with 367 additions and 132 deletions

2
.gitignore vendored
View File

@ -489,5 +489,5 @@ fabric.properties
# End of https://www.toptal.com/developers/gitignore/api/csharp,rider,dotnetcore
External
External/*
!External/.gitkeep

0
External/.gitkeep vendored Normal file
View File

View File

@ -21,10 +21,16 @@ place it in the same folder as the game executable (Sinmai.exe), then follow **o
targetAssembly=BepInEx\core\BepInEx.Preloader.dll
```
> **Warning**
>
> If you have MelonLoader installed (for YuanCon ADX HID input or other mods):
> - Grab [MLLoader-UnityMono-BepInEx5-v0.5.7.zip](https://github.com/BepInEx/BepInEx.MelonLoader.Loader/releases/download/v2.1.0/MLLoader-UnityMono-BepInEx5-v0.5.7.zip) and extract this zip into the base game folder, overwriting any conflicts. This allow BepInEx to also load MelonLoader mods.
> - Delete `version.dll`, which is used to load MelonLoader, from the game folder.
### BepInEx
#### Installing BepInEx
- Update [segatools](https://gitea.tendokyu.moe/Dniel97/segatools/releases/latest).
- Download [BepInEx 5](https://github.com/BepInEx/BepInEx/releases/tag/v5.4.23.1).
- Download [BepInEx v5.4.22](https://github.com/BepInEx/BepInEx/releases/tag/v5.4.22) (>=v5.4.23 does not work on stable segatools!).
- Extract the `BepInEx` folder from the archive into the base game folder, ignoring other files.
- Edit `segatools.ini`, adding this entry:
```ini
@ -49,6 +55,12 @@ In the end, your game directory should look like this:
└───segatools.ini
```
> **Warning**
>
> If you have MelonLoader installed (for YuanCon ADX HID input or other mods):
> - Grab [MLLoader-UnityMono-BepInEx5-v0.5.7.zip](https://github.com/BepInEx/BepInEx.MelonLoader.Loader/releases/download/v2.1.0/MLLoader-UnityMono-BepInEx5-v0.5.7.zip) and extract this zip into the base game folder, overwriting any conflicts. This allow BepInEx to also load MelonLoader mods.
> - Delete `version.dll`, which is used to load MelonLoader, from the game folder.
### Hard-patching using MonoMod
- Download [MonoMod](https://github.com/MonoMod/MonoMod/releases/latest).
- Download `Assembly-CSharp.Rizu.mm.dll` from [releases](https://gitea.tendokyu.moe/beerpsi/Rizu/releases/latest)

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

@ -31,8 +31,18 @@ public class Exporter
}
var user = Singleton<UserDataManager>.Instance.GetUserData(score.PlayerIndex);
var import = ScoreConversion.CreateScoreBatchManual(score);
string import = "";
try
{
import = ScoreConversion.CreateScoreBatchManual(score);
}
catch (Exception exception)
{
Logger.Error(exception.ToString());
}
if (import != "")
yield return SubmitImport(import, user.Detail.AccessCode);
}
@ -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();
[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