fix support for crossplay servers
All checks were successful
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (NuGet) (push) Successful in 4m0s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 4m15s
Build / Build Nuget package (SharedCringe) (push) Successful in 4m16s
Build / Build Nuget package (CringePlugins) (push) Successful in 4m41s
Build / Build Launcher (push) Successful in 5m29s

This commit is contained in:
zznty
2025-07-08 23:01:02 +07:00
parent bac80f9b2b
commit d6882a5dd1
3 changed files with 108 additions and 0 deletions

View File

@@ -12,12 +12,17 @@
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<!-- Required for Serialization of List<MyGameInventoryItem> in VRage.GameServices.MyInventoryHelper -->
<!-- Deserialization is patched to use safer NrbfDecoder instead -->
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
<ApplicationIcon>..\icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NLog.Schema" Version="5.3.4" />
<PackageReference Include="Velopack" Version="0.0.942" />
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="9.0.6" />
</ItemGroup>
<ItemGroup>

View File

@@ -8,6 +8,12 @@
"resolved": "5.3.4",
"contentHash": "eMlf4Y0gx5KycV3cdptEocd9Y9h10fWhRVUKyuY9nF6a55eWJlpKHqCWQbgHjvbC/7cBfF8DsZG8dZbST2fpew=="
},
"System.Runtime.Serialization.Formatters": {
"type": "Direct",
"requested": "[9.0.6, )",
"resolved": "9.0.6",
"contentHash": "zm5backJELHp2RgdVA2LJd+Ydnsd0kkJd2/lNPTH9T8gIpzRKMKQgPMFH+1q/7IPlZu8wYL1ZeRqsVgHqmaC8g=="
},
"Velopack": {
"type": "Direct",
"requested": "[0.0.942, )",

View File

@@ -0,0 +1,97 @@
using System.Formats.Nrbf;
using HarmonyLib;
using VRage.GameServices;
namespace CringeLauncher.Patches;
[HarmonyPatch]
public static class BinaryFormatterPatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(MyInventoryHelper), nameof(MyInventoryHelper.CheckItemData))]
private static bool ReadInventoryItemsPrefix(byte[] checkData, out bool checkResult, out List<MyGameInventoryItem> __result)
{
__result = [];
if (!NrbfDecoder.StartsWithPayloadHeader(checkData))
{
checkResult = false;
return false;
}
var listRecord = NrbfDecoder.DecodeClassRecord(new MemoryStream(checkData));
if (!listRecord.TypeNameMatches(typeof(List<MyGameInventoryItem>)) ||
listRecord.GetArrayRecord("_items") is not { } itemsRecord ||
itemsRecord.GetArray(typeof(MyGameInventoryItem[]), false) is not SerializationRecord[] items)
{
checkResult = false;
return false;
}
__result.Capacity = listRecord.GetInt32("_size");
foreach (var classRecord in items.OfType<ClassRecord>())
{
if (!classRecord.TypeNameMatches(typeof(MyGameInventoryItem)))
continue;
var itemDefinitionRecord = classRecord.GetClassRecord(PropertyName("ItemDefinition"));
if (itemDefinitionRecord is null || !itemDefinitionRecord.TypeNameMatches(typeof(MyGameInventoryItemDefinition)))
continue;
var definitionTypeRecord = itemDefinitionRecord.GetClassRecord(PropertyName("DefinitionType"));
if (definitionTypeRecord is null || !definitionTypeRecord.TypeNameMatches(typeof(MyGameInventoryItemDefinitionType)))
continue;
var itemSlotRecord = itemDefinitionRecord.GetClassRecord(PropertyName("ItemSlot"));
if (itemSlotRecord is null || !itemSlotRecord.TypeNameMatches(typeof(MyGameInventoryItemSlot)))
continue;
var itemQualityRecord = itemDefinitionRecord.GetClassRecord(PropertyName("ItemQuality"));
if (itemQualityRecord is null || !itemQualityRecord.TypeNameMatches(typeof(MyGameInventoryItemQuality)))
continue;
var itemDefinition = new MyGameInventoryItemDefinition
{
ID = itemDefinitionRecord.GetInt32(PropertyName("ID")),
Name = itemDefinitionRecord.GetString(PropertyName("Name")),
Tradable = itemDefinitionRecord.GetString(PropertyName("Tradable")),
Marketable = itemDefinitionRecord.GetString(PropertyName("Marketable")),
Description = itemDefinitionRecord.GetString(PropertyName("Description")),
IconTexture = itemDefinitionRecord.GetString(PropertyName("IconTexture")),
DisplayType = itemDefinitionRecord.GetString(PropertyName("DisplayType")),
AssetModifierId = itemDefinitionRecord.GetString(PropertyName("AssetModifierId")),
NameColor = itemDefinitionRecord.GetString(PropertyName("NameColor")),
BackgroundColor = itemDefinitionRecord.GetString(PropertyName("BackgroundColor")),
ToolName = itemDefinitionRecord.GetString(PropertyName("ToolName")),
IsStoreHidden = itemDefinitionRecord.GetBoolean(PropertyName("IsStoreHidden")),
Hidden = itemDefinitionRecord.GetBoolean(PropertyName("Hidden")),
CanBePurchased = itemDefinitionRecord.GetBoolean(PropertyName("CanBePurchased")),
Exchange = itemDefinitionRecord.GetString(PropertyName("Exchange")),
DefinitionType = (MyGameInventoryItemDefinitionType)definitionTypeRecord.GetInt32("value__"),
ItemSlot = (MyGameInventoryItemSlot)itemSlotRecord.GetInt32("value__"),
ItemQuality = (MyGameInventoryItemQuality)itemQualityRecord.GetInt32("value__")
};
var id = classRecord.GetUInt64(PropertyName("ID"));
var quantity = classRecord.GetUInt16(PropertyName("Quantity"));
var isStoreFakeItem = classRecord.GetBoolean(PropertyName("IsStoreFakeItem"));
var isNew = classRecord.GetBoolean(PropertyName("IsNew"));
__result.Add(new MyGameInventoryItem
{
ID = id,
Quantity = quantity,
ItemDefinition = itemDefinition,
IsStoreFakeItem = isStoreFakeItem,
IsNew = isNew,
UsingCharacters = []
});
}
checkResult = true;
return false;
}
private static string PropertyName(string name) => $"<{name}>k__BackingField";
}