Compare commits
81 Commits
ee1b827c91
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d3f9f8afb | |||
| 1fa8516ebe | |||
| 3dbe62a64d | |||
|
|
6d7f9aa8c0 | ||
| 671d8e4ad6 | |||
| 335df69fcd | |||
| 54ec8da1fe | |||
| f6f484549a | |||
| 5f148bc86f | |||
| b72add4e81 | |||
| b9390bbf03 | |||
| f5ad619ed5 | |||
|
|
8edfcff56f | ||
|
|
e29f0ebb70 | ||
|
|
77a6101e08 | ||
|
|
9a468564e8 | ||
|
|
b004b725f0 | ||
|
|
ff52da9542 | ||
|
|
3d879a605d | ||
|
|
143505f762 | ||
| 21e44cc4c7 | |||
| ba6d71a2ec | |||
| f06af0647d | |||
| 253f29f5be | |||
|
|
64b2005beb | ||
|
|
922c33d4a1 | ||
|
|
2f27e39610 | ||
|
|
104c52c183 | ||
| 95cd554eb0 | |||
| f1f8f1cbcf | |||
| 1843410a4d | |||
| 3f359ed4ec | |||
| 632230b8b2 | |||
| 756deee097 | |||
|
|
a7769147e3 | ||
|
|
3238fb7acf | ||
|
|
92ab39ed69 | ||
|
|
f27e325526 | ||
|
|
a7dc4441a7 | ||
|
|
68aa949591 | ||
|
|
a479fa8dd6 | ||
|
|
52f3d57721 | ||
|
|
00f0a33a47 | ||
|
|
f9db5be09b | ||
|
|
3b0c26a687 | ||
|
|
20a624fb0f | ||
|
|
adbd7f4704 | ||
|
|
eb66d0b089 | ||
|
|
a892e80068 | ||
|
|
7bc1b21098 | ||
|
|
252f6ba49a | ||
|
|
c0e912be87 | ||
|
|
0030f68f99 | ||
|
|
28715ef80d | ||
| 54301cbf37 | |||
| 84e3efe3e9 | |||
| 2c8f1af97d | |||
| 44776c3499 | |||
| 5f0b1d40fb | |||
| 2004f9cd0d | |||
| 4bd96e59bd | |||
| 8c887ae0e4 | |||
| 03127bd810 | |||
| 7ab5f9779b | |||
| 7b5b4b2744 | |||
| bc10f6b1b7 | |||
| e2e91ce513 | |||
| 51d7d81605 | |||
| 6402afc72b | |||
|
|
c11256f9a1 | ||
|
|
9295ba43e3 | ||
|
|
b7bd646520 | ||
|
|
7f266321db | ||
|
|
fc744fd1ab | ||
|
|
055ee44da5 | ||
|
|
b485ab3259 | ||
|
|
76062e026e | ||
|
|
061e7e6d8d | ||
| d0eb7f89be | |||
| 1dce1960f6 | |||
| ff70bad234 |
13
.idea/.idea.BoneSync/.idea/.gitignore
generated
vendored
Normal file
13
.idea/.idea.BoneSync/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/contentModel.xml
|
||||||
|
/.idea.BoneSync.iml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/modules.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
4
.idea/.idea.BoneSync/.idea/encodings.xml
generated
Normal file
4
.idea/.idea.BoneSync/.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
||||||
8
.idea/.idea.BoneSync/.idea/indexLayout.xml
generated
Normal file
8
.idea/.idea.BoneSync/.idea/indexLayout.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/.idea.BoneSync/.idea/vcs.xml
generated
Normal file
6
.idea/.idea.BoneSync/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="..\packages\xunit.runner.visualstudio.3.0.2\build\net472\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.3.0.2\build\net472\xunit.runner.visualstudio.props')" />
|
|
||||||
<Import Project="..\packages\xunit.core.2.9.3\build\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.9.3\build\xunit.core.props')" />
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
@@ -45,7 +43,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="0Harmony, Version=2.9.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="0Harmony, Version=2.9.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\0Harmony.dll</HintPath>
|
<HintPath>A:\SteamLibrary\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\0Harmony.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Assembly-CSharp">
|
<Reference Include="Assembly-CSharp">
|
||||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\Assembly-CSharp.dll</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\Assembly-CSharp.dll</HintPath>
|
||||||
@@ -57,24 +55,9 @@
|
|||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\MelonLoader.dll</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\MelonLoader.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.TestPlatform.CoreUtilities, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.TestPlatform.ObjectModel.17.12.0\lib\net462\Microsoft.TestPlatform.CoreUtilities.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.TestPlatform.PlatformAbstractions, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.TestPlatform.ObjectModel.17.12.0\lib\net462\Microsoft.TestPlatform.PlatformAbstractions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.ObjectModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.TestPlatform.ObjectModel.17.12.0\lib\net462\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Collections.Immutable, Version=1.2.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Configuration" />
|
<Reference Include="System.Configuration" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Reflection.Metadata, Version=1.4.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Reflection.Metadata.1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime" />
|
<Reference Include="System.Runtime" />
|
||||||
<Reference Include="System.Runtime.Serialization" />
|
<Reference Include="System.Runtime.Serialization" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
@@ -92,6 +75,10 @@
|
|||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AssetBundleModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>A:\SteamLibrary\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="UnityEngine.CoreModule">
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.CoreModule.dll</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -99,26 +86,66 @@
|
|||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
<Reference Include="UnityEngine.TextRenderingModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll</HintPath>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="xunit.assert, Version=2.9.3.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
<Reference Include="UnityEngine.UI, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\xunit.assert.2.9.3\lib\netstandard1.1\xunit.assert.dll</HintPath>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.UI.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="xunit.core, Version=2.9.3.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
<Reference Include="UnityEngine.UIElementsModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\xunit.extensibility.core.2.9.3\lib\net452\xunit.core.dll</HintPath>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.UIElementsModule.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="xunit.execution.desktop, Version=2.9.3.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
<Reference Include="UnityEngine.UIModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\xunit.extensibility.execution.2.9.3\lib\net452\xunit.execution.desktop.dll</HintPath>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.UIModule.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Data\ByteEncoder.cs" />
|
||||||
|
<Compile Include="Data\Debugger.cs" />
|
||||||
|
<Compile Include="Data\EmebeddedAssetBundle.cs" />
|
||||||
|
<Compile Include="Data\PlayerScripts.cs" />
|
||||||
|
<Compile Include="Data\SpawnableManager.cs" />
|
||||||
|
<Compile Include="Data\Structs.cs" />
|
||||||
|
<Compile Include="Networking\Messages\AISyncMessage.cs" />
|
||||||
|
<Compile Include="Networking\Messages\DiscardSyncableMessage.cs" />
|
||||||
|
<Compile Include="Networking\Messages\GunSyncMessage.cs" />
|
||||||
|
<Compile Include="Networking\Messages\SceneChangeMessage.cs" />
|
||||||
|
<Compile Include="Patching\AIHealthPatches.cs" />
|
||||||
|
<Compile Include="Patching\ButtonTogglePatches.cs" />
|
||||||
|
<Compile Include="Patching\CartPatches.cs" />
|
||||||
|
<Compile Include="Patching\HolsterSlotPatches.cs" />
|
||||||
|
<Compile Include="Networking\Messages\MagazineSyncMessage.cs" />
|
||||||
|
<Compile Include="Networking\Messages\ObjectDamageMessage.cs" />
|
||||||
<Compile Include="Networking\Messages\ObjectSyncMessage.cs" />
|
<Compile Include="Networking\Messages\ObjectSyncMessage.cs" />
|
||||||
|
<Compile Include="Networking\Messages\OwnershipTransferMessage.cs" />
|
||||||
|
<Compile Include="Networking\Messages\PlugSyncMessage.cs" />
|
||||||
<Compile Include="Networking\Messages\RegisterSyncableMessage.cs" />
|
<Compile Include="Networking\Messages\RegisterSyncableMessage.cs" />
|
||||||
|
<Compile Include="Networking\Messages\SimpleSyncableEventMessage.cs" />
|
||||||
|
<Compile Include="Patching\CallPatchedMethod.cs" />
|
||||||
|
<Compile Include="Patching\DebugPatches.cs" />
|
||||||
|
<Compile Include="Patching\GripPatches.cs" />
|
||||||
|
<Compile Include="Patching\GunPatches.cs" />
|
||||||
<Compile Include="Patching\InteractableHostPatches.cs" />
|
<Compile Include="Patching\InteractableHostPatches.cs" />
|
||||||
<Compile Include="Sync\Components\Syncable.cs" />
|
<Compile Include="Patching\ObjectHealthPatches.cs" />
|
||||||
|
<Compile Include="Patching\PlugPatches.cs" />
|
||||||
|
<Compile Include="Patching\PrefabSpawnerPatches.cs" />
|
||||||
|
<Compile Include="Patching\SceneManagerPatches.cs" />
|
||||||
|
<Compile Include="Patching\SkeletonHandPatches.cs" />
|
||||||
|
<Compile Include="Patching\UnityEventPatching.cs" />
|
||||||
|
<Compile Include="Patching\ZonePatches.cs" />
|
||||||
|
<Compile Include="Sync\Components\SyncableAI.cs" />
|
||||||
|
<Compile Include="Sync\Components\SyncableBase.cs" />
|
||||||
|
<Compile Include="Sync\Components\SyncableDamage.cs" />
|
||||||
|
<Compile Include="Sync\Components\SyncableNetworking.cs" />
|
||||||
|
<Compile Include="Sync\Components\SyncablePhysics.cs" />
|
||||||
|
<Compile Include="Sync\Components\SyncablePlugs.cs" />
|
||||||
|
<Compile Include="Sync\Components\SyncableProperties.cs" />
|
||||||
<Compile Include="Sync\ObjectSync.cs" />
|
<Compile Include="Sync\ObjectSync.cs" />
|
||||||
<Compile Include="Sync\PlayerSync.cs" />
|
<Compile Include="Sync\ObjectSyncCache.cs" />
|
||||||
<Compile Include="Facepunch.Steamworks\Callbacks\CallResult.cs" />
|
<Compile Include="Facepunch.Steamworks\Callbacks\CallResult.cs" />
|
||||||
<Compile Include="Facepunch.Steamworks\Callbacks\ICallbackData.cs" />
|
<Compile Include="Facepunch.Steamworks\Callbacks\ICallbackData.cs" />
|
||||||
<Compile Include="Facepunch.Steamworks\Classes\AuthTicket.cs" />
|
<Compile Include="Facepunch.Steamworks\Classes\AuthTicket.cs" />
|
||||||
@@ -272,39 +299,24 @@
|
|||||||
<Compile Include="Networking\Messages\PlayerSyncMessage.cs" />
|
<Compile Include="Networking\Messages\PlayerSyncMessage.cs" />
|
||||||
<Compile Include="Networking\Packet.cs" />
|
<Compile Include="Networking\Packet.cs" />
|
||||||
<Compile Include="Networking\PacketTypes.cs" />
|
<Compile Include="Networking\PacketTypes.cs" />
|
||||||
<Compile Include="Networking\Structs.cs" />
|
|
||||||
<Compile Include="Networking\Transport\SteamTransport.cs" />
|
<Compile Include="Networking\Transport\SteamTransport.cs" />
|
||||||
<Compile Include="Networking\Transport\TransportBase.cs" />
|
<Compile Include="Networking\Transport\TransportBase.cs" />
|
||||||
<Compile Include="Patching\PoolPatches.cs" />
|
<Compile Include="Patching\PoolPatches.cs" />
|
||||||
<Compile Include="Player\PlayerRig.cs" />
|
<Compile Include="Player\PlayerRig.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Networking\ByteEncoder.cs" />
|
|
||||||
<Compile Include="Sync\SceneSync.cs" />
|
<Compile Include="Sync\SceneSync.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Include="packages.config" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Analyzer Include="..\packages\xunit.analyzers.1.18.0\analyzers\dotnet\cs\xunit.analyzers.dll" />
|
|
||||||
<Analyzer Include="..\packages\xunit.analyzers.1.18.0\analyzers\dotnet\cs\xunit.analyzers.fixes.dll" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Facepunch.Steamworks\LICENSE.txt" />
|
<Content Include="Facepunch.Steamworks\LICENSE.txt" />
|
||||||
<EmbeddedResource Include="steam_api.dll" />
|
<EmbeddedResource Include="steam_api.dll" />
|
||||||
<EmbeddedResource Include="steam_api64.dll" />
|
<EmbeddedResource Include="steam_api64.dll" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="playerrep.eres" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>xcopy /Y "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\Mods\"</PostBuildEvent>
|
<PostBuildEvent>xcopy /Y "$(TargetPath)" "A:\SteamLibrary\steamapps\common\BONEWORKS\BONEWORKS\Mods\"
|
||||||
|
xcopy /Y "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\Mods\"</PostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
|
||||||
<PropertyGroup>
|
|
||||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Error Condition="!Exists('..\packages\xunit.core.2.9.3\build\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.9.3\build\xunit.core.props'))" />
|
|
||||||
<Error Condition="!Exists('..\packages\xunit.core.2.9.3\build\xunit.core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.9.3\build\xunit.core.targets'))" />
|
|
||||||
<Error Condition="!Exists('..\packages\xunit.runner.visualstudio.3.0.2\build\net472\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.3.0.2\build\net472\xunit.runner.visualstudio.props'))" />
|
|
||||||
</Target>
|
|
||||||
<Import Project="..\packages\xunit.core.2.9.3\build\xunit.core.targets" Condition="Exists('..\packages\xunit.core.2.9.3\build\xunit.core.targets')" />
|
|
||||||
</Project>
|
</Project>
|
||||||
384
BoneSync/Data/ByteEncoder.cs
Normal file
384
BoneSync/Data/ByteEncoder.cs
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using StressLevelZero;
|
||||||
|
using StressLevelZero.Combat;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Data
|
||||||
|
{
|
||||||
|
public static class BitPacking
|
||||||
|
{
|
||||||
|
public static byte[] PackBits(bool[] bits)
|
||||||
|
{
|
||||||
|
int byteCount = bits.Length / 8;
|
||||||
|
if (bits.Length % 8 != 0)
|
||||||
|
{
|
||||||
|
byteCount++;
|
||||||
|
}
|
||||||
|
byte[] bytes = new byte[byteCount];
|
||||||
|
for (int i = 0; i < bits.Length; i++)
|
||||||
|
{
|
||||||
|
int byteIndex = i / 8;
|
||||||
|
int bitIndex = i % 8;
|
||||||
|
if (bits[i])
|
||||||
|
{
|
||||||
|
bytes[byteIndex] |= (byte)(1 << bitIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool[] UnpackBits(byte[] bytes, int bitCount)
|
||||||
|
{
|
||||||
|
bool[] bits = new bool[bitCount];
|
||||||
|
for (int i = 0; i < bitCount; i++)
|
||||||
|
{
|
||||||
|
int byteIndex = i / 8;
|
||||||
|
int bitIndex = i % 8;
|
||||||
|
bits[i] = (bytes[byteIndex] & (1 << bitIndex)) != 0;
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal class ByteEncoder
|
||||||
|
{
|
||||||
|
private MemoryStream stream;
|
||||||
|
private BinaryWriter writer;
|
||||||
|
private BinaryReader reader;
|
||||||
|
private bool isWriting;
|
||||||
|
|
||||||
|
public ByteEncoder()
|
||||||
|
{
|
||||||
|
stream = new MemoryStream();
|
||||||
|
writer = new BinaryWriter(stream);
|
||||||
|
isWriting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteEncoder(byte[] data)
|
||||||
|
{
|
||||||
|
stream = new MemoryStream(data);
|
||||||
|
reader = new BinaryReader(stream);
|
||||||
|
isWriting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] ToArray()
|
||||||
|
{
|
||||||
|
byte[] buf = stream.GetBuffer();
|
||||||
|
int start, len;
|
||||||
|
if (isWriting)
|
||||||
|
{
|
||||||
|
start = 0;
|
||||||
|
len = (int)stream.Length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
start = (int)stream.Position;
|
||||||
|
len = (int)stream.Length - start;
|
||||||
|
}
|
||||||
|
byte[] res = new byte[len];
|
||||||
|
Array.Copy(buf, start, res, 0, len);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBytes(byte[] data)
|
||||||
|
{
|
||||||
|
if (stream != null)
|
||||||
|
{
|
||||||
|
stream.Dispose();
|
||||||
|
}
|
||||||
|
stream = new MemoryStream(data);
|
||||||
|
reader = new BinaryReader(stream);
|
||||||
|
writer = null;
|
||||||
|
isWriting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteByte(byte value)
|
||||||
|
{
|
||||||
|
writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteBytes(byte[] value)
|
||||||
|
{
|
||||||
|
writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] ReadBytes(int count)
|
||||||
|
{
|
||||||
|
byte[] value = reader.ReadBytes(count);
|
||||||
|
if (value.Length != count)
|
||||||
|
{
|
||||||
|
throw new Exception("Not enough data to read, expected " + count + " but only have " + value.Length);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte ReadByte()
|
||||||
|
{
|
||||||
|
return reader.ReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteBool(bool value)
|
||||||
|
{
|
||||||
|
WriteByte((byte)(value ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ReadBool()
|
||||||
|
{
|
||||||
|
return ReadByte() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteInt(int value)
|
||||||
|
{
|
||||||
|
writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ReadInt()
|
||||||
|
{
|
||||||
|
return reader.ReadInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteLong(long value)
|
||||||
|
{
|
||||||
|
writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ReadLong()
|
||||||
|
{
|
||||||
|
return reader.ReadInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteFloat(float value)
|
||||||
|
{
|
||||||
|
writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float ReadFloat()
|
||||||
|
{
|
||||||
|
return reader.ReadSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteUShort(ushort value)
|
||||||
|
{
|
||||||
|
writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort ReadUShort()
|
||||||
|
{
|
||||||
|
return reader.ReadUInt16();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteDouble(double value)
|
||||||
|
{
|
||||||
|
writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double ReadDouble()
|
||||||
|
{
|
||||||
|
return reader.ReadDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteString(string value)
|
||||||
|
{
|
||||||
|
byte[] bytes = Encoding.UTF8.GetBytes(value);
|
||||||
|
WriteInt(bytes.Length);
|
||||||
|
WriteBytes(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ReadString()
|
||||||
|
{
|
||||||
|
int length = ReadInt();
|
||||||
|
return Encoding.UTF8.GetString(ReadBytes(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteULong(ulong value)
|
||||||
|
{
|
||||||
|
writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong ReadULong()
|
||||||
|
{
|
||||||
|
return reader.ReadUInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteVector3(Vector3 value)
|
||||||
|
{
|
||||||
|
WriteFloat(value.x);
|
||||||
|
WriteFloat(value.y);
|
||||||
|
WriteFloat(value.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 ReadVector3()
|
||||||
|
{
|
||||||
|
float x = ReadFloat();
|
||||||
|
float y = ReadFloat();
|
||||||
|
float z = ReadFloat();
|
||||||
|
return new Vector3(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteQuaternion(Quaternion value)
|
||||||
|
{
|
||||||
|
WriteVector3(value.eulerAngles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Quaternion ReadQuaternion()
|
||||||
|
{
|
||||||
|
Vector3 eulerAngles = ReadVector3();
|
||||||
|
return Quaternion.Euler(eulerAngles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteSimpleTransform(SimpleSyncTransform value)
|
||||||
|
{
|
||||||
|
WriteVector3(value.position);
|
||||||
|
WriteQuaternion(value.rotation);
|
||||||
|
WriteBool(value.scale.HasValue);
|
||||||
|
if (value.scale.HasValue)
|
||||||
|
WriteVector3(value.scale.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleSyncTransform ReadSimpleTransform()
|
||||||
|
{
|
||||||
|
Vector3 position = ReadVector3();
|
||||||
|
Quaternion rotation = ReadQuaternion();
|
||||||
|
bool hasScale = ReadBool();
|
||||||
|
Vector3? scale = null;
|
||||||
|
if (hasScale)
|
||||||
|
{
|
||||||
|
scale = ReadVector3();
|
||||||
|
}
|
||||||
|
return new SimpleSyncTransform()
|
||||||
|
{
|
||||||
|
position = position,
|
||||||
|
rotation = rotation,
|
||||||
|
scale = scale
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteMatrix4x4(Matrix4x4 matrix)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
WriteFloat(matrix[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix4x4 ReadMatrix4x4()
|
||||||
|
{
|
||||||
|
Matrix4x4 matrix = new Matrix4x4();
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
matrix[i] = ReadFloat();
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteBoolArray(bool[] array)
|
||||||
|
{
|
||||||
|
byte[] bytes = BitPacking.PackBits(array);
|
||||||
|
WriteByte((byte)bytes.Length);
|
||||||
|
WriteBytes(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool[] ReadBoolArray()
|
||||||
|
{
|
||||||
|
byte length = ReadByte();
|
||||||
|
byte[] bytes = ReadBytes(length);
|
||||||
|
return BitPacking.UnpackBits(bytes, length * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteAmmoVariables(AmmoVariables ammoVariables)
|
||||||
|
{
|
||||||
|
WriteBool(ammoVariables.Tracer);
|
||||||
|
WriteFloat(ammoVariables.ProjectileMass);
|
||||||
|
WriteFloat(ammoVariables.ExitVelocity);
|
||||||
|
WriteFloat(ammoVariables.AttackDamage);
|
||||||
|
WriteByte((byte)ammoVariables.AttackType);
|
||||||
|
WriteByte((byte)ammoVariables.cartridgeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AmmoVariables ReadAmmoVariables()
|
||||||
|
{
|
||||||
|
AmmoVariables ammoVariables = new AmmoVariables()
|
||||||
|
{
|
||||||
|
Tracer = ReadBool(),
|
||||||
|
ProjectileMass = ReadFloat(),
|
||||||
|
ExitVelocity = ReadFloat(),
|
||||||
|
AttackDamage = ReadFloat(),
|
||||||
|
AttackType = (AttackType)ReadByte(),
|
||||||
|
cartridgeType = (Cart)ReadByte()
|
||||||
|
};
|
||||||
|
return ammoVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteMagazineData(MagazineData magazineData)
|
||||||
|
{
|
||||||
|
WriteByte((byte)magazineData.weight);
|
||||||
|
WriteByte((byte)magazineData.platform);
|
||||||
|
WriteUShort((byte)magazineData.cartridgeType);
|
||||||
|
BulletObject[] bulletObjects = magazineData.AmmoSlots;
|
||||||
|
WriteByte((byte)bulletObjects.Length);
|
||||||
|
for (int i = 0; i < bulletObjects.Length; i++)
|
||||||
|
{
|
||||||
|
WriteAmmoVariables(bulletObjects[i].ammoVariables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MagazineData ReadMagazineData()
|
||||||
|
{
|
||||||
|
MagazineData mag = new MagazineData();
|
||||||
|
mag.weight = (Weight)ReadByte();
|
||||||
|
mag.platform = (Platform)ReadByte();
|
||||||
|
mag.cartridgeType = (Cart)ReadUShort();
|
||||||
|
byte bulletCount = ReadByte();
|
||||||
|
|
||||||
|
mag.AmmoSlots = new BulletObject[bulletCount];
|
||||||
|
for (int i = 0; i < bulletCount; i++)
|
||||||
|
{
|
||||||
|
mag.AmmoSlots[i] = new BulletObject()
|
||||||
|
{
|
||||||
|
ammoVariables = ReadAmmoVariables()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return mag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteCompressedFloat(float value)
|
||||||
|
{
|
||||||
|
value = Mathf.Clamp01(value);
|
||||||
|
int rounded = Mathf.FloorToInt(value * 255f);
|
||||||
|
WriteByte((byte)rounded);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float ReadCompressedFloat()
|
||||||
|
{
|
||||||
|
return ReadByte() / 255f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteFingerCurl(SimpleFingerCurl fingerCurl)
|
||||||
|
{
|
||||||
|
WriteCompressedFloat(fingerCurl.thumb);
|
||||||
|
WriteCompressedFloat(fingerCurl.index);
|
||||||
|
WriteCompressedFloat(fingerCurl.middle);
|
||||||
|
WriteCompressedFloat(fingerCurl.ring);
|
||||||
|
WriteCompressedFloat(fingerCurl.pinky);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleFingerCurl ReadFingerCurl()
|
||||||
|
{
|
||||||
|
SimpleFingerCurl fingerCurl = new SimpleFingerCurl()
|
||||||
|
{
|
||||||
|
thumb = ReadCompressedFloat(),
|
||||||
|
index = ReadCompressedFloat(),
|
||||||
|
middle = ReadCompressedFloat(),
|
||||||
|
ring = ReadCompressedFloat(),
|
||||||
|
pinky = ReadCompressedFloat()
|
||||||
|
};
|
||||||
|
return fingerCurl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
110
BoneSync/Data/Debugger.cs
Normal file
110
BoneSync/Data/Debugger.cs
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
using MelonLoader;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace BoneSync.Data
|
||||||
|
{
|
||||||
|
internal static class SyncLogger
|
||||||
|
{
|
||||||
|
private static string GetCleanCaller(string className, string methodName)
|
||||||
|
{
|
||||||
|
if (className.Contains("BoneSync"))
|
||||||
|
className = className.Replace("BoneSync.", "");
|
||||||
|
if (methodName.Contains("BoneSync"))
|
||||||
|
methodName = methodName.Replace("BoneSync.", "");
|
||||||
|
return $"{className}.{methodName}";
|
||||||
|
}
|
||||||
|
public static void Msg(string message, ConsoleColor color = ConsoleColor.White, int frame = 1)
|
||||||
|
{
|
||||||
|
StackTrace stackTrace = new StackTrace();
|
||||||
|
StackFrame stackFrame = stackTrace.GetFrame(frame);
|
||||||
|
MethodBase methodBase = stackFrame.GetMethod();
|
||||||
|
|
||||||
|
string methodName = methodBase.Name;
|
||||||
|
string className = methodBase.DeclaringType.Name;
|
||||||
|
string cleanCaller = GetCleanCaller(className, methodName);
|
||||||
|
|
||||||
|
MelonLogger.Msg(color, $"[{cleanCaller}] {message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Warning(string message)
|
||||||
|
{
|
||||||
|
Msg(message, ConsoleColor.Yellow, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Error(string message)
|
||||||
|
{
|
||||||
|
Msg(message, ConsoleColor.Red, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Debug(string v)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
Msg($"[DEBUG] {v}", ConsoleColor.Gray, 2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*internal static class SyncDebugUI
|
||||||
|
{
|
||||||
|
public static Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
|
||||||
|
public static Text debugText;
|
||||||
|
public static void CreateUI()
|
||||||
|
{
|
||||||
|
if (debugText != null)
|
||||||
|
return;
|
||||||
|
GameObject canvas = new GameObject("BoneSyncDebugCanvas");
|
||||||
|
canvas.AddComponent<Canvas>();
|
||||||
|
canvas.AddComponent<CanvasScaler>();
|
||||||
|
canvas.AddComponent<GraphicRaycaster>();
|
||||||
|
canvas.GetComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
|
||||||
|
|
||||||
|
GameObject panel = new GameObject("BoneSyncDebugPanel");
|
||||||
|
panel.transform.SetParent(canvas.transform);
|
||||||
|
panel.AddComponent<CanvasRenderer>();
|
||||||
|
panel.AddComponent<Image>();
|
||||||
|
panel.GetComponent<Image>().color = new Color(0, 0, 0, 0.5f);
|
||||||
|
panel.GetComponent<RectTransform>().anchorMin = new Vector2(0, 0);
|
||||||
|
panel.GetComponent<RectTransform>().anchorMax = new Vector2(1, 1);
|
||||||
|
panel.GetComponent<RectTransform>().offsetMin = new Vector2(0, 0);
|
||||||
|
panel.GetComponent<RectTransform>().offsetMax = new Vector2(0, 0);
|
||||||
|
|
||||||
|
GameObject text = new GameObject("BoneSyncDebugText");
|
||||||
|
text.transform.SetParent(panel.transform);
|
||||||
|
text.AddComponent<RectTransform>();
|
||||||
|
text.AddComponent<Text>();
|
||||||
|
text.GetComponent<Text>().font = Font.CreateDynamicFontFromOSFont("Arial", 12);
|
||||||
|
text.GetComponent<Text>().color = Color.white;
|
||||||
|
text.GetComponent<Text>().alignment = TextAnchor.UpperLeft;
|
||||||
|
text.GetComponent<Text>().resizeTextForBestFit = true;
|
||||||
|
text.GetComponent<Text>().resizeTextMaxSize = 12;
|
||||||
|
text.GetComponent<Text>().resizeTextMinSize = 8;
|
||||||
|
text.GetComponent<Text>().text = "BoneSync Debug";
|
||||||
|
text.GetComponent<RectTransform>().anchorMin = new Vector2(0, 0);
|
||||||
|
text.GetComponent<RectTransform>().anchorMax = new Vector2(1, 1);
|
||||||
|
text.GetComponent<RectTransform>().offsetMin = new Vector2(0, 0);
|
||||||
|
text.GetComponent<RectTransform>().offsetMax = new Vector2(0, 0);
|
||||||
|
|
||||||
|
debugText = text.GetComponent<Text>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateUI()
|
||||||
|
{
|
||||||
|
CreateUI();
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (var kvp in keyValuePairs)
|
||||||
|
{
|
||||||
|
sb.AppendLine($"{kvp.Key}: {kvp.Value}");
|
||||||
|
}
|
||||||
|
debugText.text = sb.ToString();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
42
BoneSync/Data/EmebeddedAssetBundle.cs
Normal file
42
BoneSync/Data/EmebeddedAssetBundle.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Data
|
||||||
|
{
|
||||||
|
public static class EmebeddedAssetBundle
|
||||||
|
{
|
||||||
|
// Credit to the "Entanglement" mod. The playerrep asset bundle is also by them.
|
||||||
|
public static AssetBundle LoadFromAssembly(string name)
|
||||||
|
{
|
||||||
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||||
|
string[] manifestResources = assembly.GetManifestResourceNames();
|
||||||
|
|
||||||
|
if (manifestResources.Contains(name))
|
||||||
|
{
|
||||||
|
SyncLogger.Msg($"Loading embedded bundle data {name}...");
|
||||||
|
|
||||||
|
byte[] bytes;
|
||||||
|
using (Stream str = assembly.GetManifestResourceStream(name))
|
||||||
|
using (MemoryStream memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
str.CopyTo(memoryStream);
|
||||||
|
bytes = memoryStream.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncLogger.Msg($"Loading bundle from data {name}, please be patient...");
|
||||||
|
AssetBundle temp = AssetBundle.LoadFromMemory(bytes);
|
||||||
|
SyncLogger.Msg($"Done!");
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
SyncLogger.Warning($"Failed to load embedded bundle data {name}! Bundle not found.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
63
BoneSync/Data/PlayerScripts.cs
Normal file
63
BoneSync/Data/PlayerScripts.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
using StressLevelZero.Player;
|
||||||
|
using StressLevelZero.Rig;
|
||||||
|
using StressLevelZero.VRMK;
|
||||||
|
using UnhollowerBaseLib;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Data
|
||||||
|
{
|
||||||
|
// copied from Entanglement mod
|
||||||
|
public static class PlayerScripts
|
||||||
|
{
|
||||||
|
public static GameObject localPlayerGameObject;
|
||||||
|
public static RigManager playerRig;
|
||||||
|
public static PhysBody playerPhysBody;
|
||||||
|
public static Player_Health playerHealth;
|
||||||
|
public static PhysGrounder playerGrounder;
|
||||||
|
public static Hand playerLeftHand;
|
||||||
|
public static Hand playerRightHand;
|
||||||
|
public static bool reloadLevelOnDeath;
|
||||||
|
public static RuntimeAnimatorController playerAnimatorController;
|
||||||
|
public static Il2CppStringArray playerHandPoses = null;
|
||||||
|
|
||||||
|
public static void GetPlayerScripts()
|
||||||
|
{
|
||||||
|
if (playerRig != null)
|
||||||
|
return;
|
||||||
|
localPlayerGameObject = GameObject.Find("[RigManager (Default Brett)]");
|
||||||
|
playerRig = localPlayerGameObject.GetComponentInChildren<RigManager>();
|
||||||
|
playerHealth = playerRig.playerHealth;
|
||||||
|
|
||||||
|
reloadLevelOnDeath = playerHealth.reloadLevelOnDeath;
|
||||||
|
|
||||||
|
playerHealth.reloadLevelOnDeath = !BoneSync.IsConnected;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PhysicsRig physicsRig = playerRig.physicsRig;
|
||||||
|
playerPhysBody = physicsRig.physBody;
|
||||||
|
playerGrounder = playerPhysBody.physG;
|
||||||
|
playerLeftHand = physicsRig.leftHand;
|
||||||
|
playerRightHand = physicsRig.rightHand;
|
||||||
|
playerAnimatorController = playerRig.gameWorldSkeletonRig.characterAnimationManager.animator.runtimeAnimatorController;
|
||||||
|
} catch
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("Failed to get physicsRig player scripts!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetHandPoses()
|
||||||
|
{
|
||||||
|
// Checks if we already got the hand poses to prevent crashes
|
||||||
|
if (playerHandPoses == null)
|
||||||
|
CharacterAnimationManager.FetchHandPoseList(out playerHandPoses); // Lets hope this is constant!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
84
BoneSync/Data/SpawnableManager.cs
Normal file
84
BoneSync/Data/SpawnableManager.cs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
using BoneSync.Patching;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Data;
|
||||||
|
using StressLevelZero.Pool;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnhollowerBaseLib;
|
||||||
|
using UnhollowerRuntimeLib;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityObject = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace BoneSync.Data
|
||||||
|
{
|
||||||
|
public static class SpawnableManager
|
||||||
|
{
|
||||||
|
private static Dictionary<string, SpawnableObject> _spawnableCache = new Dictionary<string, SpawnableObject>();
|
||||||
|
private static Dictionary<string, SpawnableObject> _spawnablePrefabNameCache = new Dictionary<string, SpawnableObject>();
|
||||||
|
|
||||||
|
public static void AddUnregisteredSpawnables()
|
||||||
|
{
|
||||||
|
Il2CppReferenceArray<UnityObject> foundSpawnables = UnityObject.FindObjectsOfTypeIncludingAssets(Il2CppType.Of<SpawnableObject>());
|
||||||
|
foreach (UnityObject obj in foundSpawnables)
|
||||||
|
{
|
||||||
|
SpawnableObject spawnable = obj.Cast<SpawnableObject>();
|
||||||
|
RegisterSpawnable(spawnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void _ClearCache()
|
||||||
|
{
|
||||||
|
_spawnableCache.Clear();
|
||||||
|
_spawnablePrefabNameCache.Clear();
|
||||||
|
}
|
||||||
|
public static void RegisterSpawnable(SpawnableObject spawnable)
|
||||||
|
{
|
||||||
|
if (!_spawnableCache.ContainsKey(spawnable?.title))
|
||||||
|
_spawnableCache.Add(spawnable?.title, spawnable);
|
||||||
|
if (spawnable?.prefab?.name != null && !_spawnablePrefabNameCache.ContainsKey(spawnable.prefab.name))
|
||||||
|
_spawnablePrefabNameCache.Add(spawnable.prefab.name, spawnable);
|
||||||
|
}
|
||||||
|
public static SpawnableObject GetSpawnable(string title)
|
||||||
|
{
|
||||||
|
if (_spawnableCache.ContainsKey(title))
|
||||||
|
return _spawnableCache[title];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpawnableObject GetSpawnableByPrefabName(string prefabName)
|
||||||
|
{
|
||||||
|
if (_spawnablePrefabNameCache.ContainsKey(prefabName))
|
||||||
|
return _spawnablePrefabNameCache[prefabName];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pool GetPool(SpawnableObject spawnable) {
|
||||||
|
PoolManager.RegisterPool(spawnable);
|
||||||
|
return PoolManager.GetPool(spawnable.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Poolee SpawnPoolee(SpawnableObject spawnableObject, Vector3 position, Quaternion rotation)
|
||||||
|
{
|
||||||
|
if (spawnableObject == null) return null;
|
||||||
|
Pool pool = GetPool(spawnableObject);
|
||||||
|
if (pool == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("Failed to find pool: " + spawnableObject.title);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Poolee poolee = CallPatchedMethods.InstantiatePoolee(pool, position, rotation, pool.Prefab.transform.localScale);
|
||||||
|
|
||||||
|
return poolee;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
_ClearCache();
|
||||||
|
AddUnregisteredSpawnables();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,28 +5,28 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace BoneSync.Networking
|
namespace BoneSync.Data
|
||||||
{
|
{
|
||||||
|
|
||||||
public static class SimpleTransformExtensions
|
public static class SimpleTransformExtensions
|
||||||
{
|
{
|
||||||
public static void ApplySimpleTransform(this UnityEngine.Transform transform, SimpleTransform simpleTransform)
|
public static void ApplySimpleTransform(this Transform transform, SimpleSyncTransform simpleTransform)
|
||||||
{
|
{
|
||||||
transform.position = simpleTransform.position;
|
transform.position = simpleTransform.position;
|
||||||
transform.rotation = simpleTransform.rotation;
|
transform.rotation = simpleTransform.rotation;
|
||||||
transform.localScale = simpleTransform.scale;
|
if (simpleTransform.scale.HasValue) transform.localScale = simpleTransform.scale.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public struct SimpleTransform
|
public struct SimpleSyncTransform
|
||||||
{
|
{
|
||||||
public Vector3 position;
|
public Vector3 position;
|
||||||
public Quaternion rotation;
|
public Quaternion rotation;
|
||||||
public Vector3 scale;
|
public Vector3? scale;
|
||||||
public SimpleTransform(UnityEngine.Transform transform)
|
public SimpleSyncTransform(Transform transform, bool withScale = true)
|
||||||
{
|
{
|
||||||
position = transform.position;
|
position = transform.position;
|
||||||
rotation = transform.rotation;
|
rotation = transform.rotation;
|
||||||
scale = transform.localScale;
|
scale = withScale ? transform.localScale : (Vector3?)null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,9 @@ using UnityEngine;
|
|||||||
using BoneSync.Player;
|
using BoneSync.Player;
|
||||||
using BoneSync.Sync;
|
using BoneSync.Sync;
|
||||||
using Facepunch.Steamworks;
|
using Facepunch.Steamworks;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
|
||||||
namespace BoneSync
|
namespace BoneSync
|
||||||
{
|
{
|
||||||
@@ -21,14 +24,18 @@ namespace BoneSync
|
|||||||
|
|
||||||
public class BoneSync : MelonMod
|
public class BoneSync : MelonMod
|
||||||
{
|
{
|
||||||
|
public static bool IsConnected
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static LobbyManager lobby;
|
public static LobbyManager lobby;
|
||||||
public static TransportBase transport;
|
public static ITransportBase transport;
|
||||||
public override void OnApplicationStart()
|
public override void OnApplicationStart()
|
||||||
{
|
{
|
||||||
SteamClient.Init(823500, true);
|
SteamClient.Init(823500, true);
|
||||||
|
|
||||||
PatchAll();
|
|
||||||
|
|
||||||
SteamLobbyManager steamLobbyManager = new SteamLobbyManager();
|
SteamLobbyManager steamLobbyManager = new SteamLobbyManager();
|
||||||
|
|
||||||
lobby = steamLobbyManager;
|
lobby = steamLobbyManager;
|
||||||
@@ -36,49 +43,67 @@ namespace BoneSync
|
|||||||
|
|
||||||
SceneSync.Initialize();
|
SceneSync.Initialize();
|
||||||
NetworkMessage.RegisterPacketTypes();
|
NetworkMessage.RegisterPacketTypes();
|
||||||
|
|
||||||
|
SpawnableManager.Initialize();
|
||||||
|
|
||||||
|
PlayerRig.LoadBundle();
|
||||||
|
|
||||||
|
PatchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PatchAll()
|
public static void PatchAll()
|
||||||
{
|
{
|
||||||
HarmonyLib.Harmony harmony = new HarmonyLib.Harmony("com.aarov.bonesync");
|
//HarmonyLib.Harmony harmony = new HarmonyLib.Harmony("com.aarov.bonesync");
|
||||||
harmony.PatchAll();
|
//harmony.i
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnSceneWasLoaded(int buildIndex, string sceneName)
|
public override void OnSceneWasLoaded(int buildIndex, string sceneName)
|
||||||
{
|
{
|
||||||
//MelonLogger.Msg("OnLevelWasLoaded: " + sceneName);
|
//SyncLogger.Msg("OnLevelWasLoaded: " + sceneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnSceneWasInitialized(int buildIndex, string sceneName)
|
public override void OnSceneWasInitialized(int buildIndex, string sceneName)
|
||||||
{
|
{
|
||||||
//MelonLogger.Msg("OnLevelWasInitialized: " + sceneName);
|
//SyncLogger.Msg("OnLevelWasInitialized: " + sceneName);
|
||||||
|
SceneSync.OnSceneInit(buildIndex);
|
||||||
|
PlayerScripts.GetPlayerScripts();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
|
public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
|
||||||
{
|
{
|
||||||
//MelonLogger.Msg("OnLevelWasLoaded: " + sceneName);
|
//SyncLogger.Msg("OnLevelWasLoaded: " + sceneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnUpdate()
|
public override void OnUpdate()
|
||||||
{
|
{
|
||||||
|
PlayerRig.LocalSyncTick();
|
||||||
transport.Tick();
|
transport.Tick();
|
||||||
|
|
||||||
|
//SyncDebugUI.UpdateUI();
|
||||||
|
|
||||||
//PlayerRig.Tick();
|
//PlayerRig.Tick();
|
||||||
|
|
||||||
if (Input.GetKeyDown(KeyCode.P))
|
if (Input.GetKeyDown(KeyCode.P))
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("P key pressed");
|
SyncLogger.Msg("P key pressed");
|
||||||
//PlayerRig playerRig = PlayerRig.InstantiatePlayerRigPrefab();
|
//PlayerRig playerRig = PlayerRig.InstantiatePlayerRigPrefab();
|
||||||
}
|
}
|
||||||
if (Input.GetKeyDown(KeyCode.I))
|
if (Input.GetKeyDown(KeyCode.I))
|
||||||
{
|
{
|
||||||
lobby.CreateLobby();
|
lobby.CreateLobby();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnLevelWasInitialized(int level)
|
if (Input.GetKeyDown(KeyCode.N))
|
||||||
{
|
{
|
||||||
SceneSync.OnSceneInit(level);
|
SyncLogger.Msg("Creating debug player rig");
|
||||||
|
PlayerRig debugRig = PlayerRig.GetPlayerRig(0);
|
||||||
|
PlayerSyncInfo? playerSyncInfo = PlayerRig.GetLocalSyncInfo();
|
||||||
|
if (!playerSyncInfo.HasValue)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("PlayerSyncInfo is null");
|
||||||
|
}
|
||||||
|
debugRig.UpdatePlayerSync(playerSyncInfo.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void BONEWORKS_OnLoadingScreen()
|
public override void BONEWORKS_OnLoadingScreen()
|
||||||
@@ -88,27 +113,30 @@ namespace BoneSync
|
|||||||
|
|
||||||
public override void OnFixedUpdate()
|
public override void OnFixedUpdate()
|
||||||
{
|
{
|
||||||
//MelonLogger.Msg("OnFixedUpdate");
|
IsConnected = lobby.IsConnected();
|
||||||
|
transport.Tick();
|
||||||
|
Packet.TryCatchup();
|
||||||
|
PlayerRig.Tick(Time.fixedDeltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnLateUpdate()
|
public override void OnLateUpdate()
|
||||||
{
|
{
|
||||||
//MelonLogger.Msg("OnLateUpdate");
|
//SyncLogger.Msg("OnLateUpdate");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnGUI()
|
public override void OnGUI()
|
||||||
{
|
{
|
||||||
//MelonLogger.Msg("OnGUI");
|
//SyncLogger.Msg("OnGUI");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnApplicationQuit()
|
public override void OnApplicationQuit()
|
||||||
{
|
{
|
||||||
//MelonLogger.Msg("OnApplicationQuit");
|
//SyncLogger.Msg("OnApplicationQuit");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnPreferencesLoaded()
|
public override void OnPreferencesLoaded()
|
||||||
{
|
{
|
||||||
//MelonLogger.Msg("OnPreferencesLoaded");
|
//SyncLogger.Msg("OnPreferencesLoaded");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
using StressLevelZero;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace BoneSync.Networking
|
|
||||||
{
|
|
||||||
internal class ByteEncoder
|
|
||||||
{
|
|
||||||
public List<byte> Data;
|
|
||||||
public ByteEncoder()
|
|
||||||
{
|
|
||||||
Data = new List<byte>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteEncoder(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] ToArray()
|
|
||||||
{
|
|
||||||
return Data.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteByte(byte value)
|
|
||||||
{
|
|
||||||
Data.Add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteBytes(byte[] value)
|
|
||||||
{
|
|
||||||
Data.AddRange(value);
|
|
||||||
}
|
|
||||||
public byte[] ReadBytes(int count)
|
|
||||||
{
|
|
||||||
if (Data.Count < count)
|
|
||||||
{
|
|
||||||
throw new Exception("Not enough data to read, expected " + count + " but only have " + Data.Count);
|
|
||||||
}
|
|
||||||
byte[] value = Data.GetRange(0, count).ToArray();
|
|
||||||
Data.RemoveRange(0, count);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte ReadByte()
|
|
||||||
{
|
|
||||||
byte value = Data[0];
|
|
||||||
Data.RemoveAt(0);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteInt(int value)
|
|
||||||
{
|
|
||||||
WriteBytes(BitConverter.GetBytes(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ReadInt()
|
|
||||||
{
|
|
||||||
return BitConverter.ToInt32(ReadBytes(sizeof(int)), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteLong(long value)
|
|
||||||
{
|
|
||||||
WriteBytes(BitConverter.GetBytes(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public long ReadLong()
|
|
||||||
{
|
|
||||||
return BitConverter.ToInt64(ReadBytes(sizeof(long)), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteFloat(float value)
|
|
||||||
{
|
|
||||||
WriteBytes(BitConverter.GetBytes(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public float ReadFloat()
|
|
||||||
{
|
|
||||||
return BitConverter.ToSingle(ReadBytes(sizeof(float)), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteUShort(ushort value)
|
|
||||||
{
|
|
||||||
WriteBytes(BitConverter.GetBytes(value));
|
|
||||||
}
|
|
||||||
public ushort ReadUShort() {
|
|
||||||
return BitConverter.ToUInt16(ReadBytes(sizeof(ushort)), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteDouble(double value)
|
|
||||||
{
|
|
||||||
WriteBytes(BitConverter.GetBytes(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public double ReadDouble()
|
|
||||||
{
|
|
||||||
return BitConverter.ToDouble(ReadBytes(sizeof(double)), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteString(string value)
|
|
||||||
{
|
|
||||||
byte[] bytes = Encoding.UTF8.GetBytes(value);
|
|
||||||
WriteInt(bytes.Length);
|
|
||||||
WriteBytes(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ReadString()
|
|
||||||
{
|
|
||||||
int length = ReadInt();
|
|
||||||
return Encoding.UTF8.GetString(ReadBytes(length));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteUlong(ulong value)
|
|
||||||
{
|
|
||||||
WriteBytes(BitConverter.GetBytes(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong ReadUlong()
|
|
||||||
{
|
|
||||||
return BitConverter.ToUInt64(ReadBytes(sizeof(ulong)), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteVector3(UnityEngine.Vector3 value)
|
|
||||||
{
|
|
||||||
WriteFloat(value.x);
|
|
||||||
WriteFloat(value.y);
|
|
||||||
WriteFloat(value.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnityEngine.Vector3 ReadVector3()
|
|
||||||
{
|
|
||||||
float x = ReadFloat();
|
|
||||||
float y = ReadFloat();
|
|
||||||
float z = ReadFloat();
|
|
||||||
return new UnityEngine.Vector3(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteQuaternion(UnityEngine.Quaternion value)
|
|
||||||
{
|
|
||||||
WriteVector3(value.eulerAngles);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnityEngine.Quaternion ReadQuaternion()
|
|
||||||
{
|
|
||||||
UnityEngine.Vector3 eulerAngles = ReadVector3();
|
|
||||||
return UnityEngine.Quaternion.Euler(eulerAngles);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteSimpleTransform(SimpleTransform value)
|
|
||||||
{
|
|
||||||
WriteVector3(value.position);
|
|
||||||
WriteQuaternion(value.rotation);
|
|
||||||
WriteVector3(value.scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimpleTransform ReadSimpleTransform()
|
|
||||||
{
|
|
||||||
UnityEngine.Vector3 position = ReadVector3();
|
|
||||||
UnityEngine.Quaternion rotation = ReadQuaternion();
|
|
||||||
UnityEngine.Vector3 scale = ReadVector3();
|
|
||||||
return new SimpleTransform()
|
|
||||||
{
|
|
||||||
position = position,
|
|
||||||
rotation = rotation,
|
|
||||||
scale = scale
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
using BoneSync.Sync;
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Player;
|
||||||
|
using BoneSync.Sync;
|
||||||
using Facepunch.Steamworks;
|
using Facepunch.Steamworks;
|
||||||
using Facepunch.Steamworks.Data;
|
using Facepunch.Steamworks.Data;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
@@ -17,46 +19,49 @@ namespace BoneSync.Networking.LobbyManager
|
|||||||
SteamMatchmaking.OnLobbyCreated += (Result result, Lobby lobby) =>
|
SteamMatchmaking.OnLobbyCreated += (Result result, Lobby lobby) =>
|
||||||
{
|
{
|
||||||
_lobbyInstance = lobby;
|
_lobbyInstance = lobby;
|
||||||
MelonLogger.Msg("Created lobby " + lobby.Id);
|
SyncLogger.Msg("Created lobby " + lobby.Id);
|
||||||
UpdateLobbyData();
|
UpdateLobbyData();
|
||||||
|
_lobbyInstance.SetPublic();
|
||||||
};
|
};
|
||||||
SteamMatchmaking.OnLobbyEntered += (Lobby lobby) =>
|
SteamMatchmaking.OnLobbyEntered += (Lobby lobby) =>
|
||||||
{
|
{
|
||||||
_lobbyInstance = lobby;
|
_lobbyInstance = lobby;
|
||||||
MelonLogger.Msg("Entered lobby " + lobby.Id);
|
SyncLogger.Msg("Entered lobby " + lobby.Id);
|
||||||
UpdateLobbyData();
|
UpdateLobbyData();
|
||||||
};
|
};
|
||||||
SteamMatchmaking.OnLobbyMemberLeave += (Lobby lobby, Friend friend) =>
|
SteamMatchmaking.OnLobbyMemberLeave += (Lobby lobby, Friend friend) =>
|
||||||
{
|
{
|
||||||
if (friend.Id == SteamClient.SteamId)
|
if (friend.Id == SteamClient.SteamId)
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("Left lobby " + lobby.Id);
|
SyncLogger.Msg("Left lobby " + lobby.Id);
|
||||||
_lobbyInstance = new Lobby();
|
_lobbyInstance = new Lobby();
|
||||||
}
|
}
|
||||||
MelonLogger.Msg("Member left " + friend.Id);
|
SyncLogger.Msg("Member left " + friend.Id);
|
||||||
UpdateLobbyData();
|
UpdateLobbyData();
|
||||||
};
|
};
|
||||||
SteamMatchmaking.OnLobbyMemberJoined += (Lobby lobby, Friend friend) =>
|
SteamMatchmaking.OnLobbyMemberJoined += (Lobby lobby, Friend friend) =>
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("Member joined " + friend.Id);
|
SyncLogger.Msg("Member joined " + friend.Id);
|
||||||
|
SteamFriends.SetPlayedWith(friend.Id);
|
||||||
UpdateLobbyData();
|
UpdateLobbyData();
|
||||||
};
|
};
|
||||||
MelonLogger.Msg("SteamLobbyManager initialized");
|
SyncLogger.Msg("SteamLobbyManager initialized");
|
||||||
|
|
||||||
SteamFriends.OnGameLobbyJoinRequested += (Lobby lobby, SteamId friend) =>
|
SteamFriends.OnGameLobbyJoinRequested += (Lobby lobby, SteamId friend) =>
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("Joining lobby " + lobby.Id);
|
SyncLogger.Msg("Joining lobby " + lobby.Id);
|
||||||
JoinLobby(lobby.Id.Value);
|
JoinLobby(lobby.Id.Value);
|
||||||
};
|
};
|
||||||
|
|
||||||
SteamFriends.OnGameRichPresenceJoinRequested += (Friend friend, string connectString) =>
|
SteamFriends.OnGameRichPresenceJoinRequested += (Friend friend, string connectString) =>
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("Joining lobby " + connectString);
|
SyncLogger.Msg("Joining lobby " + connectString);
|
||||||
ulong lobbyId = ulong.Parse(connectString.Split(':')[1]);
|
ulong lobbyId = ulong.Parse(connectString.Split(':')[1]);
|
||||||
JoinLobby(lobbyId);
|
JoinLobby(lobbyId);
|
||||||
};
|
};
|
||||||
|
|
||||||
SteamNetworkingUtils.InitRelayNetworkAccess();
|
|
||||||
|
//SteamMatchmaking.LobbyList.
|
||||||
}
|
}
|
||||||
|
|
||||||
private Lobby _lobbyInstance;
|
private Lobby _lobbyInstance;
|
||||||
@@ -65,10 +70,16 @@ namespace BoneSync.Networking.LobbyManager
|
|||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SteamId[] _steamIds;
|
||||||
public SteamId[] steamIds
|
public SteamId[] steamIds
|
||||||
{
|
{
|
||||||
get;
|
get => _steamIds;
|
||||||
private set;
|
private set
|
||||||
|
{
|
||||||
|
_steamIds = value;
|
||||||
|
_peersCache = _steamIds.Select(x => x.Value).ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsConnected()
|
public override bool IsConnected()
|
||||||
@@ -76,7 +87,8 @@ namespace BoneSync.Networking.LobbyManager
|
|||||||
return _lobbyInstance.Id.IsValid;
|
return _lobbyInstance.Id.IsValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ulong[] GetPeers() => steamIds.Select(x => x.Value).ToArray();
|
private ulong[] _peersCache = new ulong[0];
|
||||||
|
public override ulong[] GetPeers() => _peersCache;
|
||||||
public override ulong GetLocalId() => SteamClient.SteamId.Value;
|
public override ulong GetLocalId() => SteamClient.SteamId.Value;
|
||||||
public override ulong GetHostId() => _lobbyInstance.Owner.Id.Value;
|
public override ulong GetHostId() => _lobbyInstance.Owner.Id.Value;
|
||||||
public override ulong GetLobbyId() => _lobbyInstance.Id.Value;
|
public override ulong GetLobbyId() => _lobbyInstance.Id.Value;
|
||||||
@@ -86,6 +98,8 @@ namespace BoneSync.Networking.LobbyManager
|
|||||||
LobbyMembers = _lobbyInstance.Members.ToArray();
|
LobbyMembers = _lobbyInstance.Members.ToArray();
|
||||||
steamIds = LobbyMembers.Select(x => x.Id).ToArray();
|
steamIds = LobbyMembers.Select(x => x.Id).ToArray();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (_lobbyInstance.Id.IsValid)
|
if (_lobbyInstance.Id.IsValid)
|
||||||
{
|
{
|
||||||
SteamFriends.SetRichPresence("steam_display", "BoneSync - " + SceneSync.CurrentSceneDisplayName);
|
SteamFriends.SetRichPresence("steam_display", "BoneSync - " + SceneSync.CurrentSceneDisplayName);
|
||||||
@@ -103,12 +117,14 @@ namespace BoneSync.Networking.LobbyManager
|
|||||||
SteamFriends.SetRichPresence("status", "Not in a multiplayer lobby");
|
SteamFriends.SetRichPresence("status", "Not in a multiplayer lobby");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lobbyInstance.SetMemberData("sceneName", SceneSync.CurrentSceneDisplayName);
|
||||||
|
_lobbyInstance.SetMemberData("playerModel", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void CreateLobby()
|
public override void CreateLobby()
|
||||||
{
|
{
|
||||||
LeaveLobby();
|
LeaveLobby();
|
||||||
MelonLogger.Msg("Trying to create lobby");
|
SyncLogger.Msg("Trying to create lobby");
|
||||||
_ = SteamMatchmaking.CreateLobbyAsync(16);
|
_ = SteamMatchmaking.CreateLobbyAsync(16);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -116,7 +132,7 @@ namespace BoneSync.Networking.LobbyManager
|
|||||||
public override void JoinLobby(ulong lobbyId)
|
public override void JoinLobby(ulong lobbyId)
|
||||||
{
|
{
|
||||||
LeaveLobby();
|
LeaveLobby();
|
||||||
MelonLogger.Msg("Trying to join lobby " + lobbyId);
|
SyncLogger.Msg("Trying to join lobby " + lobbyId);
|
||||||
_ = SteamMatchmaking.JoinLobbyAsync(lobbyId);
|
_ = SteamMatchmaking.JoinLobbyAsync(lobbyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
90
BoneSync/Networking/Messages/AISyncMessage.cs
Normal file
90
BoneSync/Networking/Messages/AISyncMessage.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using PuppetMasta;
|
||||||
|
using StressLevelZero.AI;
|
||||||
|
|
||||||
|
namespace BoneSync.Networking.Messages
|
||||||
|
{
|
||||||
|
public struct AIBehaviourHealth
|
||||||
|
{
|
||||||
|
public float cur_hp;
|
||||||
|
public float cur_arm_lf;
|
||||||
|
public float cur_arm_rt;
|
||||||
|
public float cur_leg_lf;
|
||||||
|
public float cur_leg_rt;
|
||||||
|
|
||||||
|
public AIBehaviourHealth(SubBehaviourHealth behaviourHealth)
|
||||||
|
{
|
||||||
|
cur_hp = behaviourHealth.cur_hp;
|
||||||
|
cur_arm_lf = behaviourHealth.cur_arm_lf;
|
||||||
|
cur_arm_rt = behaviourHealth.cur_arm_rt;
|
||||||
|
cur_leg_lf = behaviourHealth.cur_leg_lf;
|
||||||
|
cur_leg_rt = behaviourHealth.cur_leg_rt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AISyncInfo
|
||||||
|
{
|
||||||
|
public ushort syncId;
|
||||||
|
public AIBehaviourHealth health;
|
||||||
|
public PuppetMaster.State puppetState;
|
||||||
|
public PuppetMaster.Mode puppetMode;
|
||||||
|
public BehaviourBaseNav.MentalState mentalState;
|
||||||
|
|
||||||
|
public AISyncInfo(ushort syncid, AIBrain aiBrain)
|
||||||
|
{
|
||||||
|
this.syncId = syncid;
|
||||||
|
this.health = new AIBehaviourHealth(aiBrain.behaviour.health);
|
||||||
|
this.puppetState = aiBrain.puppetMaster.activeState;
|
||||||
|
this.puppetMode = aiBrain.puppetMaster.activeMode;
|
||||||
|
this.mentalState = aiBrain.behaviour.mentalState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[PacketType(PacketType.AISync), PacketReliability(PacketReliability.Unreliable)]
|
||||||
|
public class AISyncMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
private AISyncInfo _aiSyncInfo;
|
||||||
|
public AISyncInfo aiSyncInfo => _aiSyncInfo;
|
||||||
|
|
||||||
|
public AISyncMessage(AISyncInfo aiSyncInfo)
|
||||||
|
{
|
||||||
|
_aiSyncInfo = aiSyncInfo;
|
||||||
|
byteEncoder.WriteUShort(_aiSyncInfo.syncId);
|
||||||
|
byteEncoder.WriteCompressedFloat(_aiSyncInfo.health.cur_hp);
|
||||||
|
byteEncoder.WriteCompressedFloat(_aiSyncInfo.health.cur_arm_lf);
|
||||||
|
byteEncoder.WriteCompressedFloat(_aiSyncInfo.health.cur_arm_rt);
|
||||||
|
byteEncoder.WriteCompressedFloat(_aiSyncInfo.health.cur_leg_lf);
|
||||||
|
byteEncoder.WriteCompressedFloat(_aiSyncInfo.health.cur_leg_rt);
|
||||||
|
byteEncoder.WriteByte((byte)_aiSyncInfo.puppetState);
|
||||||
|
byteEncoder.WriteByte((byte)_aiSyncInfo.puppetMode);
|
||||||
|
byteEncoder.WriteByte((byte)_aiSyncInfo.mentalState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AISyncMessage(Packet packet)
|
||||||
|
{
|
||||||
|
byteEncoder.WriteBytes(packet.Data);
|
||||||
|
_aiSyncInfo = new AISyncInfo();
|
||||||
|
_aiSyncInfo.syncId = byteEncoder.ReadUShort();
|
||||||
|
_aiSyncInfo.health.cur_hp = byteEncoder.ReadCompressedFloat();
|
||||||
|
_aiSyncInfo.health.cur_arm_lf = byteEncoder.ReadCompressedFloat();
|
||||||
|
_aiSyncInfo.health.cur_arm_rt = byteEncoder.ReadCompressedFloat();
|
||||||
|
_aiSyncInfo.health.cur_leg_lf = byteEncoder.ReadCompressedFloat();
|
||||||
|
_aiSyncInfo.health.cur_leg_rt = byteEncoder.ReadCompressedFloat();
|
||||||
|
_aiSyncInfo.puppetState = (PuppetMaster.State)byteEncoder.ReadByte();
|
||||||
|
_aiSyncInfo.puppetMode = (PuppetMaster.Mode)byteEncoder.ReadByte();
|
||||||
|
_aiSyncInfo.mentalState = (BehaviourBaseNav.MentalState)byteEncoder.ReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Execute()
|
||||||
|
{
|
||||||
|
Syncable syncable = ObjectSyncCache.GetSyncable(_aiSyncInfo.syncId);
|
||||||
|
if (syncable == null) return;
|
||||||
|
syncable.OnAISyncData(_aiSyncInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
BoneSync/Networking/Messages/DiscardSyncableMessage.cs
Normal file
52
BoneSync/Networking/Messages/DiscardSyncableMessage.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using MelonLoader;
|
||||||
|
|
||||||
|
namespace BoneSync.Networking.Messages
|
||||||
|
{
|
||||||
|
public struct DiscardSyncableMessageData
|
||||||
|
{
|
||||||
|
public ushort syncId;
|
||||||
|
public bool despawn;
|
||||||
|
}
|
||||||
|
[PacketType(PacketType.DiscardSyncable), PacketReliability(PacketReliability.ReliableFast)]
|
||||||
|
internal class DiscardSyncableMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
private DiscardSyncableMessageData _data;
|
||||||
|
|
||||||
|
public DiscardSyncableMessage(DiscardSyncableMessageData discardSyncableMessageData)
|
||||||
|
{
|
||||||
|
_data = discardSyncableMessageData;
|
||||||
|
byteEncoder.WriteUShort(_data.syncId);
|
||||||
|
byteEncoder.WriteBool(_data.despawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscardSyncableMessage(Packet packet)
|
||||||
|
{
|
||||||
|
byteEncoder.WriteBytes(packet.Data);
|
||||||
|
_data.syncId = byteEncoder.ReadUShort();
|
||||||
|
_data.despawn = byteEncoder.ReadBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Execute()
|
||||||
|
{
|
||||||
|
Syncable syncable = ObjectSyncCache.GetSyncable(_data.syncId);
|
||||||
|
|
||||||
|
if (syncable != null)
|
||||||
|
{
|
||||||
|
syncable.DiscardSyncable(true, _data.despawn);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
SyncLogger.Warning(senderId + " tried to discard a syncable that doesn't exist (syncId: " + _data.syncId + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
68
BoneSync/Networking/Messages/GunSyncMessage.cs
Normal file
68
BoneSync/Networking/Messages/GunSyncMessage.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Combat;
|
||||||
|
using StressLevelZero.Props.Weapons;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BoneSync.Networking.Messages
|
||||||
|
{
|
||||||
|
public enum GunSyncMessageType
|
||||||
|
{
|
||||||
|
StateUpdate = 0,
|
||||||
|
Fire = 1,
|
||||||
|
EjectCartridge = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct GunSyncInfo
|
||||||
|
{
|
||||||
|
public ushort syncId;
|
||||||
|
public BulletObject bulletObject;
|
||||||
|
public GunSyncMessageType messageType;
|
||||||
|
public Gun.HammerStates hammerState;
|
||||||
|
public Gun.CartridgeStates cartridgeState;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PacketType(PacketType.GunSync), PacketReliability(PacketReliability.Unreliable)]
|
||||||
|
public class GunSyncMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
GunSyncInfo gunSyncInfo;
|
||||||
|
public GunSyncMessage(GunSyncInfo gunSyncInfo)
|
||||||
|
{
|
||||||
|
this.gunSyncInfo = gunSyncInfo;
|
||||||
|
|
||||||
|
byteEncoder.WriteUShort(gunSyncInfo.syncId);
|
||||||
|
byteEncoder.WriteByte((byte)gunSyncInfo.messageType);
|
||||||
|
byteEncoder.WriteByte((byte)gunSyncInfo.hammerState);
|
||||||
|
byteEncoder.WriteByte((byte)gunSyncInfo.cartridgeState);
|
||||||
|
|
||||||
|
byteEncoder.WriteBool(gunSyncInfo.bulletObject != null);
|
||||||
|
byteEncoder.WriteAmmoVariables(gunSyncInfo.bulletObject.ammoVariables);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public GunSyncMessage(Packet packet) {
|
||||||
|
byteEncoder.WriteBytes(packet.Data);
|
||||||
|
gunSyncInfo.syncId = byteEncoder.ReadUShort();
|
||||||
|
gunSyncInfo.messageType = (GunSyncMessageType)byteEncoder.ReadByte();
|
||||||
|
gunSyncInfo.hammerState = (Gun.HammerStates)byteEncoder.ReadByte();
|
||||||
|
gunSyncInfo.cartridgeState = (Gun.CartridgeStates)byteEncoder.ReadByte();
|
||||||
|
|
||||||
|
if (byteEncoder.ReadBool()) { // If bulletObject is not null
|
||||||
|
gunSyncInfo.bulletObject = new BulletObject() { ammoVariables = byteEncoder.ReadAmmoVariables() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Execute()
|
||||||
|
{
|
||||||
|
Syncable syncable = ObjectSyncCache.GetSyncable(gunSyncInfo.syncId);
|
||||||
|
if (syncable == null) return;
|
||||||
|
//SyncLogger.Msg("GunSyncMessage.Execute: " + gunSyncInfo.syncId + ":" + syncable.name + " hasBulletObject: " + (gunSyncInfo.bulletObject != null));
|
||||||
|
syncable.OnWeaponSyncData(gunSyncInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,10 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
#if TEST
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace BoneSync.Networking.Messages
|
namespace BoneSync.Networking.Messages
|
||||||
{
|
{
|
||||||
@@ -40,7 +43,7 @@ namespace BoneSync.Networking.Messages
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if TEST
|
||||||
public class LobbyInfoMessageTests
|
public class LobbyInfoMessageTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -58,4 +61,5 @@ namespace BoneSync.Networking.Messages
|
|||||||
Assert.Equal(5, newMessage.CurrentPlayers);
|
Assert.Equal(5, newMessage.CurrentPlayers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
43
BoneSync/Networking/Messages/MagazineSyncMessage.cs
Normal file
43
BoneSync/Networking/Messages/MagazineSyncMessage.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using StressLevelZero.Combat;
|
||||||
|
using StressLevelZero.Props.Weapons;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BoneSync.Networking.Messages
|
||||||
|
{
|
||||||
|
public struct MagazineSyncData
|
||||||
|
{
|
||||||
|
public ushort syncId;
|
||||||
|
public MagazineData magazineData;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PacketType(PacketType.MagazineSync), PacketReliability(PacketReliability.Unreliable)]
|
||||||
|
public class MagazineSyncMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
public MagazineSyncData magazineData;
|
||||||
|
|
||||||
|
public MagazineSyncMessage(MagazineSyncData magazineData)
|
||||||
|
{
|
||||||
|
this.magazineData = magazineData;
|
||||||
|
byteEncoder.WriteMagazineData(magazineData.magazineData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MagazineSyncMessage(Packet packet)
|
||||||
|
{
|
||||||
|
byteEncoder.WriteBytes(packet.Data);
|
||||||
|
magazineData = new MagazineSyncData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Execute()
|
||||||
|
{
|
||||||
|
Syncable syncable = ObjectSyncCache.GetSyncable(magazineData.syncId);
|
||||||
|
if (!syncable) return;
|
||||||
|
syncable.ApplyMagazineData(magazineData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
BoneSync/Networking/Messages/ObjectDamageMessage.cs
Normal file
87
BoneSync/Networking/Messages/ObjectDamageMessage.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using BoneSync.Sync;
|
||||||
|
using StressLevelZero.Combat;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Networking.Messages
|
||||||
|
{
|
||||||
|
public struct ObjectHealthInfo
|
||||||
|
{
|
||||||
|
public float _health;
|
||||||
|
public int _hits;
|
||||||
|
public Vector3 normal;
|
||||||
|
public float damage;
|
||||||
|
public bool crit;
|
||||||
|
public AttackType attackType;
|
||||||
|
public byte index;
|
||||||
|
public ObjectHealthInfo(float health, int hits, Vector3 normal, float damage, bool crit, AttackType attackType, byte index)
|
||||||
|
{
|
||||||
|
_health = health;
|
||||||
|
_hits = hits;
|
||||||
|
this.normal = normal;
|
||||||
|
this.damage = damage;
|
||||||
|
this.crit = crit;
|
||||||
|
this.attackType = attackType;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public enum ObjectDamageType
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
SyncHealth = 1,
|
||||||
|
DestructibleTakeDamage = 2,
|
||||||
|
PropHealthTakeDamage = 3,
|
||||||
|
}
|
||||||
|
public struct ObjectDamageInfo
|
||||||
|
{
|
||||||
|
public ushort objectId;
|
||||||
|
public ObjectDamageType eventType;
|
||||||
|
public ObjectHealthInfo objectHealthInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PacketType(PacketType.ObjectDamageEvent), PacketReliability(PacketReliability.Unreliable), PacketCatchup(4)]
|
||||||
|
public class ObjectDamageMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
public ObjectDamageInfo objectEventInfo => _objectEventInfo;
|
||||||
|
private ObjectDamageInfo _objectEventInfo;
|
||||||
|
|
||||||
|
public ObjectDamageMessage(ObjectDamageInfo objectEventInfo)
|
||||||
|
{
|
||||||
|
_objectEventInfo = objectEventInfo;
|
||||||
|
byteEncoder.WriteUShort(_objectEventInfo.objectId);
|
||||||
|
byteEncoder.WriteByte((byte)_objectEventInfo.eventType);
|
||||||
|
byteEncoder.WriteByte(_objectEventInfo.objectHealthInfo.index);
|
||||||
|
byteEncoder.WriteFloat(_objectEventInfo.objectHealthInfo._health);
|
||||||
|
byteEncoder.WriteInt(_objectEventInfo.objectHealthInfo._hits);
|
||||||
|
if (_objectEventInfo.eventType == ObjectDamageType.SyncHealth) return; // No need to write the rest of the data
|
||||||
|
byteEncoder.WriteVector3(_objectEventInfo.objectHealthInfo.normal);
|
||||||
|
byteEncoder.WriteFloat(_objectEventInfo.objectHealthInfo.damage);
|
||||||
|
byteEncoder.WriteBool(_objectEventInfo.objectHealthInfo.crit);
|
||||||
|
byteEncoder.WriteByte((byte)_objectEventInfo.objectHealthInfo.attackType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectDamageMessage(Packet packet)
|
||||||
|
{
|
||||||
|
byteEncoder.WriteBytes(packet.Data);
|
||||||
|
_objectEventInfo.objectId = byteEncoder.ReadUShort();
|
||||||
|
_objectEventInfo.eventType = (ObjectDamageType)byteEncoder.ReadByte();
|
||||||
|
_objectEventInfo.objectHealthInfo.index = byteEncoder.ReadByte();
|
||||||
|
_objectEventInfo.objectHealthInfo._health = byteEncoder.ReadFloat();
|
||||||
|
_objectEventInfo.objectHealthInfo._hits = byteEncoder.ReadInt();
|
||||||
|
if (_objectEventInfo.eventType == ObjectDamageType.SyncHealth) return; // No need to read the rest of the data
|
||||||
|
_objectEventInfo.objectHealthInfo.normal = byteEncoder.ReadVector3();
|
||||||
|
_objectEventInfo.objectHealthInfo.damage = byteEncoder.ReadFloat();
|
||||||
|
_objectEventInfo.objectHealthInfo.crit = byteEncoder.ReadBool();
|
||||||
|
_objectEventInfo.objectHealthInfo.attackType = (AttackType)byteEncoder.ReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Execute()
|
||||||
|
{
|
||||||
|
ObjectSync.OnObjectDamageMessage(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using BoneSync.Sync;
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Sync;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -11,8 +12,9 @@ namespace BoneSync.Networking.Messages
|
|||||||
|
|
||||||
public struct ObjectSyncTransform
|
public struct ObjectSyncTransform
|
||||||
{
|
{
|
||||||
public SimpleTransform transform;
|
public SimpleSyncTransform transform;
|
||||||
public Vector3 velocity;
|
public Vector3 velocity;
|
||||||
|
public Vector3 angularVelocity;
|
||||||
}
|
}
|
||||||
public struct ObjectSyncMessageData
|
public struct ObjectSyncMessageData
|
||||||
{
|
{
|
||||||
@@ -20,7 +22,7 @@ namespace BoneSync.Networking.Messages
|
|||||||
public ObjectSyncTransform[] objectSyncTransforms;
|
public ObjectSyncTransform[] objectSyncTransforms;
|
||||||
}
|
}
|
||||||
|
|
||||||
[PacketType(PacketType.ObjectSync), PacketReliability(PacketReliability.UnreliableNoDelay)]
|
[PacketType(PacketType.ObjectSync), PacketReliability(PacketReliability.Unreliable)]
|
||||||
internal class ObjectSyncMessage : NetworkMessage
|
internal class ObjectSyncMessage : NetworkMessage
|
||||||
{
|
{
|
||||||
private ObjectSyncMessageData _objectSyncMessageData = new ObjectSyncMessageData();
|
private ObjectSyncMessageData _objectSyncMessageData = new ObjectSyncMessageData();
|
||||||
|
|||||||
43
BoneSync/Networking/Messages/OwnershipTransferMessage.cs
Normal file
43
BoneSync/Networking/Messages/OwnershipTransferMessage.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
|
||||||
|
namespace BoneSync.Networking.Messages
|
||||||
|
{
|
||||||
|
public struct OwnershipTransferMessageData
|
||||||
|
{
|
||||||
|
public ushort syncId;
|
||||||
|
public bool force;
|
||||||
|
public ulong NewOwnerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PacketType(PacketType.ObjectOwnership), PacketReliability(PacketReliability.ReliableFast), PacketCatchup(2)]
|
||||||
|
internal class OwnershipTransferMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
private OwnershipTransferMessageData Data;
|
||||||
|
public OwnershipTransferMessage(OwnershipTransferMessageData data)
|
||||||
|
{
|
||||||
|
Data = data;
|
||||||
|
byteEncoder.WriteUShort(Data.syncId);
|
||||||
|
byteEncoder.WriteULong(Data.NewOwnerId);
|
||||||
|
byteEncoder.WriteBool(Data.force);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OwnershipTransferMessage(Packet packet)
|
||||||
|
{
|
||||||
|
byteEncoder.WriteBytes(packet.Data);
|
||||||
|
Data.syncId = byteEncoder.ReadUShort();
|
||||||
|
Data.NewOwnerId = byteEncoder.ReadULong();
|
||||||
|
Data.force = byteEncoder.ReadBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
override public void Execute()
|
||||||
|
{
|
||||||
|
ObjectSync.OnOwnershipChangeMessage(Data.syncId, Data.NewOwnerId, Data.force);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,49 @@
|
|||||||
|
|
||||||
|
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Player;
|
||||||
using BoneSync.Sync;
|
using BoneSync.Sync;
|
||||||
|
using StressLevelZero.Player;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace BoneSync.Networking.Messages
|
namespace BoneSync.Networking.Messages
|
||||||
{
|
{
|
||||||
|
public struct SimpleFingerCurl
|
||||||
|
{
|
||||||
|
public float thumb;
|
||||||
|
public float index;
|
||||||
|
public float middle;
|
||||||
|
public float ring;
|
||||||
|
public float pinky;
|
||||||
|
public SimpleFingerCurl(FingerCurl fingerCurl)
|
||||||
|
{
|
||||||
|
thumb = fingerCurl.thumb;
|
||||||
|
index = fingerCurl.index;
|
||||||
|
middle = fingerCurl.middle;
|
||||||
|
ring = fingerCurl.ring;
|
||||||
|
pinky = fingerCurl.pinky;
|
||||||
|
}
|
||||||
|
}
|
||||||
public struct PlayerSyncInfo
|
public struct PlayerSyncInfo
|
||||||
{
|
{
|
||||||
public SimpleTransform headPos;
|
public Vector3 rootPos;
|
||||||
public SimpleTransform leftHandPos;
|
public SimpleSyncTransform headPos;
|
||||||
public SimpleTransform rightHandPos;
|
public SimpleSyncTransform leftHandPos;
|
||||||
|
public SimpleSyncTransform rightHandPos;
|
||||||
|
public SimpleFingerCurl leftHandFingerCurl;
|
||||||
|
public SimpleFingerCurl rightHandFingerCurl;
|
||||||
|
public byte poseIndexRight;
|
||||||
|
public byte poseIndexLeft;
|
||||||
|
public float poseRadiusRight;
|
||||||
|
public float poseRadiusLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
[PacketType(PacketType.PlayerSync)]
|
[PacketType(PacketType.PlayerSync), PacketReliability(PacketReliability.Unreliable)]
|
||||||
internal class PlayerSyncMessage : NetworkMessage
|
internal class PlayerSyncMessage : NetworkMessage
|
||||||
{
|
{
|
||||||
private PlayerSyncInfo _playerSyncInfo;
|
private PlayerSyncInfo _playerSyncInfo;
|
||||||
@@ -26,22 +52,36 @@ namespace BoneSync.Networking.Messages
|
|||||||
public PlayerSyncMessage(PlayerSyncInfo playerSyncInfo)
|
public PlayerSyncMessage(PlayerSyncInfo playerSyncInfo)
|
||||||
{
|
{
|
||||||
_playerSyncInfo = playerSyncInfo;
|
_playerSyncInfo = playerSyncInfo;
|
||||||
|
byteEncoder.WriteVector3(_playerSyncInfo.rootPos);
|
||||||
byteEncoder.WriteSimpleTransform(_playerSyncInfo.headPos);
|
byteEncoder.WriteSimpleTransform(_playerSyncInfo.headPos);
|
||||||
byteEncoder.WriteSimpleTransform(_playerSyncInfo.leftHandPos);
|
byteEncoder.WriteSimpleTransform(_playerSyncInfo.leftHandPos);
|
||||||
byteEncoder.WriteSimpleTransform(_playerSyncInfo.rightHandPos);
|
byteEncoder.WriteSimpleTransform(_playerSyncInfo.rightHandPos);
|
||||||
|
byteEncoder.WriteByte(_playerSyncInfo.poseIndexRight);
|
||||||
|
byteEncoder.WriteByte(_playerSyncInfo.poseIndexLeft);
|
||||||
|
byteEncoder.WriteCompressedFloat(_playerSyncInfo.poseRadiusRight);
|
||||||
|
byteEncoder.WriteCompressedFloat(_playerSyncInfo.poseRadiusLeft);
|
||||||
|
byteEncoder.WriteFingerCurl(_playerSyncInfo.leftHandFingerCurl);
|
||||||
|
byteEncoder.WriteFingerCurl(_playerSyncInfo.rightHandFingerCurl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerSyncMessage(Packet packet)
|
public PlayerSyncMessage(Packet packet)
|
||||||
{
|
{
|
||||||
byteEncoder.WriteBytes(packet.Data);
|
byteEncoder.WriteBytes(packet.Data);
|
||||||
|
_playerSyncInfo.rootPos = byteEncoder.ReadVector3();
|
||||||
_playerSyncInfo.headPos = byteEncoder.ReadSimpleTransform();
|
_playerSyncInfo.headPos = byteEncoder.ReadSimpleTransform();
|
||||||
_playerSyncInfo.leftHandPos = byteEncoder.ReadSimpleTransform();
|
_playerSyncInfo.leftHandPos = byteEncoder.ReadSimpleTransform();
|
||||||
_playerSyncInfo.rightHandPos = byteEncoder.ReadSimpleTransform();
|
_playerSyncInfo.rightHandPos = byteEncoder.ReadSimpleTransform();
|
||||||
|
_playerSyncInfo.poseIndexRight = byteEncoder.ReadByte();
|
||||||
|
_playerSyncInfo.poseIndexLeft = byteEncoder.ReadByte();
|
||||||
|
_playerSyncInfo.poseRadiusRight = byteEncoder.ReadCompressedFloat();
|
||||||
|
_playerSyncInfo.poseRadiusLeft = byteEncoder.ReadCompressedFloat();
|
||||||
|
_playerSyncInfo.leftHandFingerCurl = byteEncoder.ReadFingerCurl();
|
||||||
|
_playerSyncInfo.rightHandFingerCurl = byteEncoder.ReadFingerCurl();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Execute()
|
public override void Execute()
|
||||||
{
|
{
|
||||||
PlayerSync.OnPlayerSync(this);
|
PlayerRig.OnPlayerSync(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
86
BoneSync/Networking/Messages/PlugSyncMessage.cs
Normal file
86
BoneSync/Networking/Messages/PlugSyncMessage.cs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BoneSync.Networking.Messages
|
||||||
|
{
|
||||||
|
|
||||||
|
public struct PlugSyncMessageData
|
||||||
|
{
|
||||||
|
public ushort plugSyncId;
|
||||||
|
public byte plugIndex;
|
||||||
|
public ushort socketSyncId;
|
||||||
|
public byte socketIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PacketType(PacketType.PlugSync), PacketReliability(PacketReliability.Unreliable), PacketCatchup(10)]
|
||||||
|
internal class PlugSyncMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
private PlugSyncMessageData messageData;
|
||||||
|
public PlugSyncMessage(PlugSyncMessageData plugSyncMessageData)
|
||||||
|
{
|
||||||
|
this.messageData = plugSyncMessageData;
|
||||||
|
byteEncoder.WriteUShort(plugSyncMessageData.plugSyncId);
|
||||||
|
byteEncoder.WriteByte(plugSyncMessageData.plugIndex);
|
||||||
|
byteEncoder.WriteUShort(plugSyncMessageData.socketSyncId);
|
||||||
|
byteEncoder.WriteByte(plugSyncMessageData.socketIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlugSyncMessage(Packet packet) {
|
||||||
|
byteEncoder.WriteBytes(packet.Data);
|
||||||
|
messageData.plugSyncId = byteEncoder.ReadUShort();
|
||||||
|
messageData.plugIndex = byteEncoder.ReadByte();
|
||||||
|
messageData.socketSyncId = byteEncoder.ReadUShort();
|
||||||
|
messageData.socketIndex = byteEncoder.ReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Execute()
|
||||||
|
{
|
||||||
|
//SyncLogger.Msg("Got PlugSyncMessage " + messageData.plugSyncId + ":" + messageData.plugIndex + " " + messageData.socketSyncId + ":" + messageData.socketIndex);
|
||||||
|
Syncable plugSyncable = ObjectSyncCache.GetSyncable(messageData.plugSyncId);
|
||||||
|
Syncable socketSyncable = ObjectSyncCache.GetSyncable(messageData.socketSyncId);
|
||||||
|
|
||||||
|
if (!plugSyncable || messageData.plugIndex == byte.MaxValue)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("PlugSyncable not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AlignPlug plug = plugSyncable.GetPlugFromId(messageData.plugIndex);
|
||||||
|
|
||||||
|
if (plug == null) {
|
||||||
|
SyncLogger.Warning("Plug not found, " + plugSyncable.transform.GetPath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (plug == null) {
|
||||||
|
SyncLogger.Warning("Plug is not an AlignPlug");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!socketSyncable || messageData.socketIndex == byte.MaxValue) {
|
||||||
|
SyncLogger.Warning("SocketSyncable not found");
|
||||||
|
plug.SafeEject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket socket = socketSyncable.GetSocketFromId(messageData.socketIndex);
|
||||||
|
if (socket == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("Unable to find socket from ID");
|
||||||
|
plug.SafeEject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SyncLogger.Msg("Inserting networked plug");
|
||||||
|
|
||||||
|
plug.SafeInsert(socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
using BoneSync.Sync;
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Patching;
|
||||||
|
using BoneSync.Sync;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -12,15 +14,23 @@ namespace BoneSync.Networking.Messages
|
|||||||
RegisterFromPath = 0,
|
RegisterFromPath = 0,
|
||||||
RegisterAndSpawn = 1,
|
RegisterAndSpawn = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct SpawnPoolableInfo
|
||||||
|
{
|
||||||
|
public string spawnableTitle;
|
||||||
|
public SimpleSyncTransform spawnLocation;
|
||||||
|
}
|
||||||
public struct RegisterSyncableInfo
|
public struct RegisterSyncableInfo
|
||||||
{
|
{
|
||||||
public string transformPath;
|
public string transformPath;
|
||||||
public ushort id;
|
public ushort id;
|
||||||
|
public ushort callbackId;
|
||||||
public ulong ownerId;
|
public ulong ownerId;
|
||||||
public RegisterSyncType type;
|
public RegisterSyncType type;
|
||||||
|
public SpawnPoolableInfo? spawnInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
[PacketType(PacketType.RegisterSyncable)]
|
[PacketType(PacketType.RegisterSyncable), PacketReliability(PacketReliability.ReliableFast), PacketCatchup(1)]
|
||||||
internal class RegisterSyncableMessage : NetworkMessage
|
internal class RegisterSyncableMessage : NetworkMessage
|
||||||
{
|
{
|
||||||
private RegisterSyncableInfo _info;
|
private RegisterSyncableInfo _info;
|
||||||
@@ -29,9 +39,19 @@ namespace BoneSync.Networking.Messages
|
|||||||
{
|
{
|
||||||
_info = info;
|
_info = info;
|
||||||
byteEncoder.WriteByte((byte)_info.type);
|
byteEncoder.WriteByte((byte)_info.type);
|
||||||
byteEncoder.WriteString(_info.transformPath);
|
byteEncoder.WriteULong(_info.ownerId);
|
||||||
byteEncoder.WriteUlong(_info.ownerId);
|
|
||||||
byteEncoder.WriteUShort(_info.id);
|
byteEncoder.WriteUShort(_info.id);
|
||||||
|
byteEncoder.WriteUShort(_info.callbackId);
|
||||||
|
switch (_info.type)
|
||||||
|
{
|
||||||
|
case RegisterSyncType.RegisterAndSpawn:
|
||||||
|
byteEncoder.WriteString(_info.spawnInfo.Value.spawnableTitle);
|
||||||
|
byteEncoder.WriteSimpleTransform(_info.spawnInfo.Value.spawnLocation);
|
||||||
|
break;
|
||||||
|
case RegisterSyncType.RegisterFromPath:
|
||||||
|
byteEncoder.WriteString(_info.transformPath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,9 +59,22 @@ namespace BoneSync.Networking.Messages
|
|||||||
{
|
{
|
||||||
byteEncoder.WriteBytes(packet.Data);
|
byteEncoder.WriteBytes(packet.Data);
|
||||||
_info.type = (RegisterSyncType)byteEncoder.ReadByte();
|
_info.type = (RegisterSyncType)byteEncoder.ReadByte();
|
||||||
_info.transformPath = byteEncoder.ReadString();
|
_info.ownerId = byteEncoder.ReadULong();
|
||||||
_info.ownerId = byteEncoder.ReadUlong();
|
|
||||||
_info.id = byteEncoder.ReadUShort();
|
_info.id = byteEncoder.ReadUShort();
|
||||||
|
_info.callbackId = byteEncoder.ReadUShort();
|
||||||
|
switch (_info.type)
|
||||||
|
{
|
||||||
|
case RegisterSyncType.RegisterAndSpawn:
|
||||||
|
_info.spawnInfo = new SpawnPoolableInfo()
|
||||||
|
{
|
||||||
|
spawnableTitle = byteEncoder.ReadString(),
|
||||||
|
spawnLocation = byteEncoder.ReadSimpleTransform(),
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case RegisterSyncType.RegisterFromPath:
|
||||||
|
_info.transformPath = byteEncoder.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Execute()
|
public override void Execute()
|
||||||
|
|||||||
91
BoneSync/Networking/Messages/SceneChangeMessage.cs
Normal file
91
BoneSync/Networking/Messages/SceneChangeMessage.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Utilities;
|
||||||
|
|
||||||
|
namespace BoneSync.Networking.Messages
|
||||||
|
{
|
||||||
|
public enum sceneChangeType
|
||||||
|
{
|
||||||
|
FromIndex,
|
||||||
|
FromName,
|
||||||
|
CustomMap,
|
||||||
|
}
|
||||||
|
public struct SceneChangeInfo
|
||||||
|
{
|
||||||
|
public sceneChangeType sceneChangeType;
|
||||||
|
public string sceneName;
|
||||||
|
public byte sceneIndex;
|
||||||
|
public bool reloadScene;
|
||||||
|
}
|
||||||
|
[PacketType(PacketType.SceneChange), PacketReliability(PacketReliability.Reliable), AlwaysExecute]
|
||||||
|
internal class SceneChangeMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
private SceneChangeInfo _sceneChangeInfo;
|
||||||
|
public SceneChangeInfo sceneChangeInfo => _sceneChangeInfo;
|
||||||
|
|
||||||
|
public SceneChangeMessage(SceneChangeInfo sceneChangeInfo)
|
||||||
|
{
|
||||||
|
_sceneChangeInfo = sceneChangeInfo;
|
||||||
|
byteEncoder.WriteByte((byte)_sceneChangeInfo.sceneChangeType);
|
||||||
|
byteEncoder.WriteBool(_sceneChangeInfo.reloadScene);
|
||||||
|
switch (_sceneChangeInfo.sceneChangeType)
|
||||||
|
{
|
||||||
|
case sceneChangeType.FromIndex:
|
||||||
|
byteEncoder.WriteByte(_sceneChangeInfo.sceneIndex);
|
||||||
|
break;
|
||||||
|
case sceneChangeType.FromName:
|
||||||
|
byteEncoder.WriteString(_sceneChangeInfo.sceneName);
|
||||||
|
break;
|
||||||
|
case sceneChangeType.CustomMap:
|
||||||
|
byteEncoder.WriteString(_sceneChangeInfo.sceneName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SceneChangeMessage(Packet packet)
|
||||||
|
{
|
||||||
|
byteEncoder.SetBytes(packet.Data);
|
||||||
|
_sceneChangeInfo = new SceneChangeInfo();
|
||||||
|
_sceneChangeInfo.sceneChangeType = (sceneChangeType)byteEncoder.ReadByte();
|
||||||
|
_sceneChangeInfo.reloadScene = byteEncoder.ReadBool();
|
||||||
|
switch (_sceneChangeInfo.sceneChangeType)
|
||||||
|
{
|
||||||
|
case sceneChangeType.FromIndex:
|
||||||
|
_sceneChangeInfo.sceneIndex = byteEncoder.ReadByte();
|
||||||
|
break;
|
||||||
|
case sceneChangeType.FromName:
|
||||||
|
_sceneChangeInfo.sceneName = byteEncoder.ReadString();
|
||||||
|
break;
|
||||||
|
case sceneChangeType.CustomMap:
|
||||||
|
_sceneChangeInfo.sceneName = byteEncoder.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Execute()
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("SceneChangeMessage: " + _sceneChangeInfo.sceneName + " " + _sceneChangeInfo.sceneIndex);
|
||||||
|
switch (_sceneChangeInfo.sceneChangeType)
|
||||||
|
{
|
||||||
|
case sceneChangeType.FromIndex:
|
||||||
|
if (!_sceneChangeInfo.reloadScene && _sceneChangeInfo.sceneIndex == BoneworksSceneManager.currentSceneIndex) return; // don't reload the scene if it's already loaded
|
||||||
|
BoneworksSceneManager.LoadScene(_sceneChangeInfo.sceneIndex);
|
||||||
|
break;
|
||||||
|
case sceneChangeType.FromName:
|
||||||
|
BoneworksSceneManager.LoadScene(_sceneChangeInfo.sceneName);
|
||||||
|
break;
|
||||||
|
case sceneChangeType.CustomMap:
|
||||||
|
BoneworksSceneManager.LoadScene(_sceneChangeInfo.sceneName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
BoneSync/Networking/Messages/SimpleSyncableEventMessage.cs
Normal file
70
BoneSync/Networking/Messages/SimpleSyncableEventMessage.cs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BoneSync.Networking.Messages
|
||||||
|
{
|
||||||
|
public enum SimpleEventType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
OnDevicePull = 1,
|
||||||
|
OnDeviceRelease = 2,
|
||||||
|
OnButtonPress = 3,
|
||||||
|
OnButtonRelease = 4,
|
||||||
|
OnButtonOneShot = 5,
|
||||||
|
CartGo = 6,
|
||||||
|
CartGoBackwards = 7,
|
||||||
|
CartLaunch = 8,
|
||||||
|
CartGoForward = 9,
|
||||||
|
CartDrop = 10,
|
||||||
|
}
|
||||||
|
public struct SimpleSyncableEvent
|
||||||
|
{
|
||||||
|
public ushort syncId;
|
||||||
|
public SimpleEventType eventType;
|
||||||
|
public byte index;
|
||||||
|
public byte length;
|
||||||
|
public byte[] extraData;
|
||||||
|
}
|
||||||
|
[PacketType(PacketType.SimpleObjectEventSync), PacketReliability(PacketReliability.ReliableFast), PacketCatchup(20)]
|
||||||
|
public class SimpleSyncableEventMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
private SimpleSyncableEvent eventData;
|
||||||
|
public SimpleSyncableEventMessage(SimpleSyncableEvent simpleSyncableEvent)
|
||||||
|
{
|
||||||
|
eventData = simpleSyncableEvent;
|
||||||
|
byteEncoder.WriteUShort(simpleSyncableEvent.syncId);
|
||||||
|
byteEncoder.WriteByte((byte)simpleSyncableEvent.eventType);
|
||||||
|
byteEncoder.WriteByte(simpleSyncableEvent.index);
|
||||||
|
byteEncoder.WriteByte(simpleSyncableEvent.length);
|
||||||
|
if (simpleSyncableEvent.extraData == null)
|
||||||
|
{
|
||||||
|
simpleSyncableEvent.extraData = new byte[0];
|
||||||
|
}
|
||||||
|
byteEncoder.WriteByte((byte)simpleSyncableEvent.extraData.Length);
|
||||||
|
byteEncoder.WriteBytes(simpleSyncableEvent.extraData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleSyncableEventMessage(Packet packet)
|
||||||
|
{
|
||||||
|
byteEncoder.WriteBytes(packet.Data);
|
||||||
|
eventData.syncId = byteEncoder.ReadUShort();
|
||||||
|
eventData.eventType = (SimpleEventType)byteEncoder.ReadByte();
|
||||||
|
eventData.index = byteEncoder.ReadByte();
|
||||||
|
eventData.length = byteEncoder.ReadByte();
|
||||||
|
ushort extraDataLength = byteEncoder.ReadByte();
|
||||||
|
eventData.extraData = byteEncoder.ReadBytes(extraDataLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Execute()
|
||||||
|
{
|
||||||
|
Syncable syncable = ObjectSyncCache.GetSyncable(eventData.syncId);
|
||||||
|
if (syncable == null) return;
|
||||||
|
syncable.OnSimpleSyncableEvent(eventData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
using BoneSync.Networking.Transport;
|
using System;
|
||||||
using MelonLoader;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking.Transport;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using MelonLoader;
|
||||||
|
using Oculus.Platform;
|
||||||
|
#if TEST
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace BoneSync.Networking
|
namespace BoneSync.Networking
|
||||||
{
|
{
|
||||||
@@ -31,6 +36,20 @@ namespace BoneSync.Networking
|
|||||||
public PacketReliability reliability { get; }
|
public PacketReliability reliability { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PacketCatchupAttribute : Attribute
|
||||||
|
{
|
||||||
|
public int order { get; }
|
||||||
|
public PacketCatchupAttribute(int order)
|
||||||
|
{
|
||||||
|
this.order = order;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AlwaysExecuteAttribute : Attribute
|
||||||
|
{
|
||||||
|
public AlwaysExecuteAttribute() {}
|
||||||
|
}
|
||||||
|
|
||||||
public abstract class NetworkMessage
|
public abstract class NetworkMessage
|
||||||
{
|
{
|
||||||
public ulong senderId
|
public ulong senderId
|
||||||
@@ -44,10 +63,19 @@ namespace BoneSync.Networking
|
|||||||
|
|
||||||
internal PacketType _packetType;
|
internal PacketType _packetType;
|
||||||
internal PacketReliability? _reliability;
|
internal PacketReliability? _reliability;
|
||||||
|
internal int? _catchupOrder;
|
||||||
|
internal bool? _alwaysExecute;
|
||||||
internal ByteEncoder byteEncoder = new ByteEncoder();
|
internal ByteEncoder byteEncoder = new ByteEncoder();
|
||||||
|
|
||||||
public byte[] GetBytes() => byteEncoder.ToArray();
|
public byte[] GetBytes() => byteEncoder.ToArray();
|
||||||
|
|
||||||
|
public bool GetAlwaysExecute()
|
||||||
|
{
|
||||||
|
if (_alwaysExecute.HasValue) return _alwaysExecute.Value;
|
||||||
|
AlwaysExecuteAttribute alwaysExecuteAttribute = GetType().GetCustomAttribute<AlwaysExecuteAttribute>();
|
||||||
|
_alwaysExecute = alwaysExecuteAttribute != null;
|
||||||
|
return _alwaysExecute.Value;
|
||||||
|
}
|
||||||
public PacketType GetPacketType()
|
public PacketType GetPacketType()
|
||||||
{
|
{
|
||||||
RegisterPacketTypes();
|
RegisterPacketTypes();
|
||||||
@@ -64,6 +92,20 @@ namespace BoneSync.Networking
|
|||||||
return _packetType;
|
return _packetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetCatchupOrder()
|
||||||
|
{
|
||||||
|
if (_catchupOrder.HasValue) return _catchupOrder.Value;
|
||||||
|
PacketCatchupAttribute catchupAttribute = GetType().GetCustomAttribute<PacketCatchupAttribute>();
|
||||||
|
if (catchupAttribute == null)
|
||||||
|
{
|
||||||
|
_catchupOrder = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_catchupOrder = catchupAttribute.order;
|
||||||
|
return _catchupOrder.Value;
|
||||||
|
}
|
||||||
|
|
||||||
public PacketReliability GetPacketReliability()
|
public PacketReliability GetPacketReliability()
|
||||||
{
|
{
|
||||||
if (_reliability.HasValue) return _reliability.Value;
|
if (_reliability.HasValue) return _reliability.Value;
|
||||||
@@ -96,19 +138,34 @@ namespace BoneSync.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static NetworkMessage ParsePacket(Packet packet)
|
|
||||||
|
private static readonly Dictionary<PacketType, ConstructorInfo> ConstructorCache = new Dictionary<PacketType, ConstructorInfo>();
|
||||||
|
public static ConstructorInfo GetConstructor(Packet packet)
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("Received packet of type " + packet.Info.packetType + " from " + packet.Info.senderId + " Length: " + packet.Data.Length);
|
if (ConstructorCache.ContainsKey(packet.Info.packetType))
|
||||||
// find a class that can parse this packet using Reflection
|
{
|
||||||
// and return it
|
return ConstructorCache[packet.Info.packetType];
|
||||||
|
}
|
||||||
if (!PacketTypeMap.ContainsKey(packet.Info.packetType))
|
if (!PacketTypeMap.ContainsKey(packet.Info.packetType))
|
||||||
{
|
{
|
||||||
throw new Exception("No class found for packet type '" + packet.Info.packetType+"'");
|
throw new Exception("No class found for packet type '" + packet.Info.packetType + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
Type type = PacketTypeMap[packet.Info.packetType];
|
Type type = PacketTypeMap[packet.Info.packetType];
|
||||||
// get the constructor that takes a Packet
|
// get the constructor that takes a Packet
|
||||||
ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(Packet) }) ?? throw new Exception("No constructor found for type " + type.Name);
|
ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(Packet) }) ?? throw new Exception("No constructor found for type " + type.Name);
|
||||||
|
ConstructorCache[packet.Info.packetType] = constructor;
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static NetworkMessage ParsePacket(Packet packet)
|
||||||
|
{
|
||||||
|
//SyncLogger.Msg("Received packet of type " + packet.Info.packetType + " from " + packet.Info.senderId + " Length: " + packet.Data.Length);
|
||||||
|
// find a class that can parse this packet using Reflection
|
||||||
|
// and return it
|
||||||
|
|
||||||
|
ConstructorInfo constructor = GetConstructor(packet);
|
||||||
NetworkMessage networkMessage = (NetworkMessage)constructor.Invoke(new object[] { packet });
|
NetworkMessage networkMessage = (NetworkMessage)constructor.Invoke(new object[] { packet });
|
||||||
networkMessage.senderId = packet.Info.senderId;
|
networkMessage.senderId = packet.Info.senderId;
|
||||||
return networkMessage;
|
return networkMessage;
|
||||||
@@ -116,35 +173,40 @@ namespace BoneSync.Networking
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public Packet GetPacket(int id, ulong senderId, ulong receiverId)
|
public Packet GetPacket(ulong senderId, ulong receiverId)
|
||||||
{
|
{
|
||||||
PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, GetPacketType(), GetPacketReliability());
|
PacketInfo packetInfo = new PacketInfo(senderId, receiverId, GetPacketType(), GetPacketReliability(), 0, (byte)SceneSync.CurrentSceneIndex);
|
||||||
Packet packet = new Packet(packetInfo, GetBytes());
|
Packet packet = new Packet(packetInfo, GetBytes());
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
public void Broadcast()
|
public void Broadcast()
|
||||||
{
|
{
|
||||||
Send(TransportBase.BORADCAST_ID);
|
Send(BoneSync.transport.BROADCAST_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendToHost()
|
||||||
|
{
|
||||||
|
Send(BoneSync.lobby.GetHostId());
|
||||||
}
|
}
|
||||||
public void Send(ulong receiverId)
|
public void Send(ulong receiverId)
|
||||||
{
|
{
|
||||||
if (BoneSync.lobby.IsConnected() == false)
|
if (BoneSync.IsConnected == false)
|
||||||
{
|
{
|
||||||
MelonLogger.Warning("Cannot send packet, not connected to lobby");
|
SyncLogger.Warning("Cannot send packet, not connected to lobby");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int PacketId = Packet.GenerateId();
|
|
||||||
ulong senderId = BoneSync.lobby.GetLocalId();
|
ulong senderId = BoneSync.lobby.GetLocalId();
|
||||||
Packet packet = GetPacket(PacketId, senderId, receiverId);
|
Packet packet = GetPacket(senderId, receiverId);
|
||||||
BoneSync.transport.Send(packet);
|
BoneSync.transport.Send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Execute()
|
public virtual void Execute()
|
||||||
{
|
{
|
||||||
MelonLogger.Warning("Execute not implemented for " + GetType().Name);
|
SyncLogger.Warning("Execute not implemented for " + GetType().Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#if TEST
|
||||||
public class NetworkMessageTests
|
public class NetworkMessageTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -154,4 +216,5 @@ namespace BoneSync.Networking
|
|||||||
Assert.NotEmpty(NetworkMessage.PacketTypeMap);
|
Assert.NotEmpty(NetworkMessage.PacketTypeMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
using BoneSync.Networking.Messages;
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Sync;
|
||||||
using Facepunch.Steamworks;
|
using Facepunch.Steamworks;
|
||||||
|
using MelonLoader;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
#if TEST
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace BoneSync.Networking
|
namespace BoneSync.Networking
|
||||||
{
|
{
|
||||||
@@ -13,35 +18,65 @@ namespace BoneSync.Networking
|
|||||||
public enum PacketReliability
|
public enum PacketReliability
|
||||||
{
|
{
|
||||||
Unreliable = 0,
|
Unreliable = 0,
|
||||||
UnreliableNoDelay = 1,
|
Reliable = 1,
|
||||||
Reliable = 2,
|
ReliableFast = 2,
|
||||||
ReliableWithBuffering = 3,
|
|
||||||
}
|
}
|
||||||
public struct PacketInfo
|
public struct PacketInfo
|
||||||
{
|
{
|
||||||
public int id;
|
public ulong id;
|
||||||
public ulong senderId;
|
public ulong senderId;
|
||||||
public ulong receiverId;
|
public ulong receiverId;
|
||||||
|
public byte sceneIndex;
|
||||||
public PacketType packetType;
|
public PacketType packetType;
|
||||||
public PacketReliability reliability;
|
public PacketReliability reliability;
|
||||||
|
|
||||||
public PacketInfo(
|
public PacketInfo(
|
||||||
int id,
|
|
||||||
ulong senderId,
|
ulong senderId,
|
||||||
ulong receiverId,
|
ulong receiverId,
|
||||||
PacketType packetType,
|
PacketType packetType,
|
||||||
PacketReliability reliability = PacketReliability.Reliable
|
PacketReliability reliability,
|
||||||
|
ulong id,
|
||||||
|
byte sceneIndex
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.id = id;
|
|
||||||
this.senderId = senderId;
|
this.senderId = senderId;
|
||||||
this.receiverId = receiverId;
|
this.receiverId = receiverId;
|
||||||
this.packetType = packetType;
|
this.packetType = packetType;
|
||||||
this.reliability = reliability;
|
this.reliability = reliability;
|
||||||
|
this.id = id == 0 ? Packet.GenerateId() : id;
|
||||||
|
this.sceneIndex = sceneIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class Packet
|
public class Packet
|
||||||
{
|
{
|
||||||
|
private static Dictionary<byte, Queue<NetworkMessage>> _packetQueues = new Dictionary<byte, Queue<NetworkMessage>>();
|
||||||
|
|
||||||
|
private static ulong _packetId = 1;
|
||||||
|
|
||||||
|
private static Dictionary<ulong, Dictionary<PacketType, ulong>> _latestPacketIds = new Dictionary<ulong, Dictionary<PacketType, ulong>>();
|
||||||
|
|
||||||
|
private static void SetLatestPacketId(ulong id, PacketType packetType, ulong value)
|
||||||
|
{
|
||||||
|
if (!_latestPacketIds.ContainsKey(id))
|
||||||
|
{
|
||||||
|
_latestPacketIds.Add(id, new Dictionary<PacketType, ulong>());
|
||||||
|
}
|
||||||
|
_latestPacketIds[id][packetType] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ulong GetLatestPacketId(ulong id, PacketType packetType)
|
||||||
|
{
|
||||||
|
if (!_latestPacketIds.ContainsKey(id))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!_latestPacketIds[id].ContainsKey(packetType))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _latestPacketIds[id][packetType];
|
||||||
|
}
|
||||||
|
|
||||||
public PacketInfo Info
|
public PacketInfo Info
|
||||||
{
|
{
|
||||||
get => _packetInfo;
|
get => _packetInfo;
|
||||||
@@ -64,11 +99,12 @@ namespace BoneSync.Networking
|
|||||||
|
|
||||||
byte packetType = byteEncoder.ReadByte();
|
byte packetType = byteEncoder.ReadByte();
|
||||||
byte reliability = byteEncoder.ReadByte();
|
byte reliability = byteEncoder.ReadByte();
|
||||||
int id = byteEncoder.ReadInt();
|
byte sceneIndex = byteEncoder.ReadByte();
|
||||||
ulong senderId = byteEncoder.ReadUlong();
|
ulong id = byteEncoder.ReadULong();
|
||||||
ulong receiverId = byteEncoder.ReadUlong();
|
ulong senderId = byteEncoder.ReadULong();
|
||||||
|
ulong receiverId = byteEncoder.ReadULong();
|
||||||
|
|
||||||
PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, (PacketType)packetType, (PacketReliability)reliability);
|
PacketInfo packetInfo = new PacketInfo(senderId, receiverId, (PacketType)packetType, (PacketReliability)reliability, id, sceneIndex);
|
||||||
return new Packet(packetInfo, byteEncoder.ToArray());
|
return new Packet(packetInfo, byteEncoder.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,28 +113,83 @@ namespace BoneSync.Networking
|
|||||||
ByteEncoder byteEncoder = new ByteEncoder();
|
ByteEncoder byteEncoder = new ByteEncoder();
|
||||||
byteEncoder.WriteByte((byte)_packetInfo.packetType);
|
byteEncoder.WriteByte((byte)_packetInfo.packetType);
|
||||||
byteEncoder.WriteByte((byte)_packetInfo.reliability);
|
byteEncoder.WriteByte((byte)_packetInfo.reliability);
|
||||||
byteEncoder.WriteInt(_packetInfo.id);
|
byteEncoder.WriteByte(_packetInfo.sceneIndex);
|
||||||
byteEncoder.WriteUlong(_packetInfo.senderId);
|
byteEncoder.WriteULong(_packetInfo.id);
|
||||||
byteEncoder.WriteUlong(_packetInfo.receiverId);
|
byteEncoder.WriteULong(_packetInfo.senderId);
|
||||||
|
byteEncoder.WriteULong(_packetInfo.receiverId);
|
||||||
byteEncoder.WriteBytes(_dataBytes);
|
byteEncoder.WriteBytes(_dataBytes);
|
||||||
return byteEncoder.ToArray();
|
return byteEncoder.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EnsureQueueForScene(byte sceneIndex)
|
||||||
|
{
|
||||||
|
if (!_packetQueues.ContainsKey(sceneIndex))
|
||||||
|
{
|
||||||
|
_packetQueues.Add(sceneIndex, new Queue<NetworkMessage>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool OnPacketReceived(Packet packet)
|
public static bool OnPacketReceived(Packet packet)
|
||||||
{
|
{
|
||||||
|
if (packet._packetInfo.reliability == PacketReliability.ReliableFast)
|
||||||
|
{
|
||||||
|
if (packet.Info.id <= GetLatestPacketId(packet.Info.senderId, packet.Info.packetType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetLatestPacketId(packet.Info.senderId, packet.Info.packetType, packet.Info.id);
|
||||||
|
}
|
||||||
|
|
||||||
NetworkMessage networkMessage = NetworkMessage.ParsePacket(packet);
|
NetworkMessage networkMessage = NetworkMessage.ParsePacket(packet);
|
||||||
|
|
||||||
|
if (packet._packetInfo.sceneIndex != SceneSync.CurrentSceneIndex && !networkMessage.GetAlwaysExecute())
|
||||||
|
{
|
||||||
|
bool addToQueue = networkMessage.GetCatchupOrder() > 0;
|
||||||
|
if (!addToQueue) return false;
|
||||||
|
SyncLogger.Msg("Adding packet to queue for scene " + packet._packetInfo.sceneIndex);
|
||||||
|
EnsureQueueForScene(packet._packetInfo.sceneIndex);
|
||||||
|
_packetQueues[packet._packetInfo.sceneIndex].Enqueue(networkMessage);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
networkMessage.Execute();
|
networkMessage.Execute();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void TryCatchup()
|
||||||
|
{
|
||||||
|
if (!BoneSync.IsConnected)
|
||||||
|
{
|
||||||
|
if (_packetQueues.Count > 0) _packetQueues.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte sceneIndex = (byte)SceneSync.CurrentSceneIndex;
|
||||||
|
if (!_packetQueues.ContainsKey(sceneIndex))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Queue<NetworkMessage> queue = _packetQueues[sceneIndex];
|
||||||
|
int processed = 0;
|
||||||
|
while (queue.Count > 0 && processed < 10 && SceneSync.TimeSinceLastSceneChange > SceneSync.MAP_LOAD_GRACE_PERIOD)
|
||||||
|
{
|
||||||
|
processed++;
|
||||||
|
NetworkMessage networkMessage = queue.Dequeue();
|
||||||
|
networkMessage.Execute();
|
||||||
|
}
|
||||||
|
if (processed > 0)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Processed " + processed + " queued packets for scene " + sceneIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] Data => _dataBytes;
|
public byte[] Data => _dataBytes;
|
||||||
|
|
||||||
public static int GenerateId()
|
public static ulong GenerateId()
|
||||||
{
|
{
|
||||||
return new Random().Next();
|
return _packetId++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if TEST
|
||||||
public class PacketTests
|
public class PacketTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -127,4 +218,5 @@ namespace BoneSync.Networking
|
|||||||
Assert.NotEqual(bytes, randomDataBytes);
|
Assert.NotEqual(bytes, randomDataBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,14 @@ namespace BoneSync.Networking
|
|||||||
PlayerSync = 2,
|
PlayerSync = 2,
|
||||||
RegisterSyncable = 3,
|
RegisterSyncable = 3,
|
||||||
ObjectSync = 4,
|
ObjectSync = 4,
|
||||||
|
ObjectDamageEvent = 5,
|
||||||
|
ObjectOwnership = 6,
|
||||||
|
DiscardSyncable = 7,
|
||||||
|
MagazineSync = 8,
|
||||||
|
GunSync = 9,
|
||||||
|
SimpleObjectEventSync = 10,
|
||||||
|
PlugSync = 11,
|
||||||
|
AISync = 12,
|
||||||
|
SceneChange = 13,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,24 +4,30 @@ using System.Linq;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
using BoneSync.Networking.LobbyManager;
|
using BoneSync.Networking.LobbyManager;
|
||||||
using Facepunch.Steamworks;
|
using Facepunch.Steamworks;
|
||||||
using Facepunch.Steamworks.Data;
|
using Facepunch.Steamworks.Data;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
|
using Oculus.Platform;
|
||||||
|
|
||||||
namespace BoneSync.Networking.Transport
|
namespace BoneSync.Networking.Transport
|
||||||
{
|
{
|
||||||
internal class SteamTransport : TransportBase
|
internal class SteamTransport : ITransportBase
|
||||||
{
|
{
|
||||||
|
|
||||||
public SteamTransport()
|
public SteamTransport()
|
||||||
{
|
{
|
||||||
SteamNetworking.OnP2PSessionRequest += OnP2PSessionRequest;
|
SteamNetworking.OnP2PSessionRequest += OnP2PSessionRequest;
|
||||||
|
SteamNetworkingUtils.InitRelayNetworkAccess();
|
||||||
}
|
}
|
||||||
private List<SteamId> OpenP2PConnections = new List<SteamId>();
|
private List<SteamId> OpenP2PConnections = new List<SteamId>();
|
||||||
|
|
||||||
|
public ulong BROADCAST_ID => 0;
|
||||||
|
|
||||||
private void OnP2PSessionRequest(SteamId steamId)
|
private void OnP2PSessionRequest(SteamId steamId)
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("P2P Request from " + steamId);
|
SyncLogger.Msg("P2P Request from " + steamId);
|
||||||
if (BoneSync.lobby.GetPeers().Contains(steamId))
|
if (BoneSync.lobby.GetPeers().Contains(steamId))
|
||||||
{
|
{
|
||||||
SteamNetworking.AcceptP2PSessionWithUser(steamId);
|
SteamNetworking.AcceptP2PSessionWithUser(steamId);
|
||||||
@@ -34,7 +40,7 @@ namespace BoneSync.Networking.Transport
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void CleanUp()
|
public void CleanUp()
|
||||||
{
|
{
|
||||||
ulong[] peers = BoneSync.lobby.GetPeers();
|
ulong[] peers = BoneSync.lobby.GetPeers();
|
||||||
for (int i = 0; i < OpenP2PConnections.Count; i++)
|
for (int i = 0; i < OpenP2PConnections.Count; i++)
|
||||||
@@ -51,16 +57,16 @@ namespace BoneSync.Networking.Transport
|
|||||||
private void ProcessPacket(P2Packet steamPacket)
|
private void ProcessPacket(P2Packet steamPacket)
|
||||||
{
|
{
|
||||||
Packet packet = Packet.FromBytes(steamPacket.Data);
|
Packet packet = Packet.FromBytes(steamPacket.Data);
|
||||||
bool isTarget = packet.Info.receiverId == BORADCAST_ID || packet.Info.receiverId == BoneSync.lobby.GetLocalId();
|
bool isTarget = packet.Info.receiverId == BROADCAST_ID || packet.Info.receiverId == BoneSync.lobby.GetLocalId();
|
||||||
if (isTarget)
|
if (isTarget)
|
||||||
{
|
{
|
||||||
Packet.OnPacketReceived(packet);
|
Packet.OnPacketReceived(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Tick()
|
public int Tick()
|
||||||
{
|
{
|
||||||
if (!SteamClient.IsValid) return false;
|
if (!SteamClient.IsValid) return 0;
|
||||||
int processed = 0;
|
int processed = 0;
|
||||||
while (SteamNetworking.IsP2PPacketAvailable())
|
while (SteamNetworking.IsP2PPacketAvailable())
|
||||||
{
|
{
|
||||||
@@ -69,38 +75,65 @@ namespace BoneSync.Networking.Transport
|
|||||||
ProcessPacket(packet.Value);
|
ProcessPacket(packet.Value);
|
||||||
processed++;
|
processed++;
|
||||||
}
|
}
|
||||||
return processed > 0;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendP2P(SteamId peer, byte[] data)
|
public P2PSend GetSteamSendType(PacketReliability packetReliability)
|
||||||
{
|
{
|
||||||
|
switch (packetReliability)
|
||||||
|
{
|
||||||
|
case PacketReliability.Unreliable:
|
||||||
|
return P2PSend.UnreliableNoDelay;
|
||||||
|
case PacketReliability.Reliable:
|
||||||
|
return P2PSend.Reliable;
|
||||||
|
default:
|
||||||
|
return P2PSend.Reliable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendP2P(SteamId peer, byte[] data, PacketReliability sendType)
|
||||||
|
{
|
||||||
|
|
||||||
if (peer == BoneSync.lobby.GetLocalId())
|
if (peer == BoneSync.lobby.GetLocalId())
|
||||||
{
|
{
|
||||||
//MelonLogger.Msg("Trying to send packet to self");
|
//SyncLogger.Msg("Trying to send packet to self");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, P2PSend.Reliable);
|
|
||||||
}
|
if (sendType == PacketReliability.ReliableFast)
|
||||||
public override void Send(Packet packet)
|
|
||||||
{
|
{
|
||||||
|
SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, P2PSend.UnreliableNoDelay);
|
||||||
|
SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, P2PSend.Reliable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
P2PSend steamSendType = GetSteamSendType(sendType);
|
||||||
|
SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, steamSendType);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
public void Send(Packet packet)
|
||||||
|
{
|
||||||
|
|
||||||
LobbyManager.LobbyManager _instance = BoneSync.lobby;
|
LobbyManager.LobbyManager _instance = BoneSync.lobby;
|
||||||
if (_instance == null)
|
if (_instance == null)
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("Lobby instance is null");
|
SyncLogger.Msg("Lobby instance is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (packet.Info.receiverId == BORADCAST_ID)
|
if (packet.Info.receiverId == BROADCAST_ID)
|
||||||
{
|
{
|
||||||
foreach (SteamId peer in _instance.GetPeers())
|
foreach (SteamId peer in _instance.GetPeers())
|
||||||
{
|
{
|
||||||
SendP2P(peer, packet.ToBytes());
|
SendP2P(peer, packet.ToBytes(), packet.Info.reliability);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SendP2P(packet.Info.receiverId, packet.ToBytes());
|
SendP2P(packet.Info.receiverId, packet.ToBytes(), packet.Info.reliability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace BoneSync.Networking.Transport
|
namespace BoneSync.Networking.Transport
|
||||||
{
|
{
|
||||||
public abstract class TransportBase
|
public interface ITransportBase
|
||||||
{
|
{
|
||||||
public const int BORADCAST_ID = 0;
|
ulong BROADCAST_ID { get; }
|
||||||
public abstract void Send(Packet packet);
|
void Send(Packet packet);
|
||||||
public abstract bool Tick();
|
int Tick();
|
||||||
public abstract void CleanUp();
|
void CleanUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
BoneSync/Patching/AIHealthPatches.cs
Normal file
25
BoneSync/Patching/AIHealthPatches.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using HarmonyLib;
|
||||||
|
using PuppetMasta;
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(SubBehaviourHealth))]
|
||||||
|
internal class AIHealthPatches
|
||||||
|
{
|
||||||
|
/*[HarmonyPatch(nameof(SubBehaviourHealth.TakeDamage)), HarmonyPrefix]
|
||||||
|
private static bool DamagePrefix(SubBehaviourHealth __instance)
|
||||||
|
{
|
||||||
|
if (!BoneSync.IsConnected) return true;
|
||||||
|
if (CallPatchedMethods.allowPatchedMethodCall) return true;
|
||||||
|
Syncable syncable = __instance.behaviour.GetComponentInParent<Syncable>();
|
||||||
|
if (syncable != null && syncable.Registered && !syncable.isOwner) return false;
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
26
BoneSync/Patching/ButtonTogglePatches.cs
Normal file
26
BoneSync/Patching/ButtonTogglePatches.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Environment;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(ButtonToggle))]
|
||||||
|
internal class ButtonTogglePatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(nameof(ButtonToggle.OnEnable)), HarmonyPostfix]
|
||||||
|
private static void OnEnablePostfix(ButtonToggle __instance)
|
||||||
|
{
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
97
BoneSync/Patching/CallPatchedMethod.cs
Normal file
97
BoneSync/Patching/CallPatchedMethod.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
using BoneSync.Data;
|
||||||
|
using StressLevelZero.Combat;
|
||||||
|
using StressLevelZero.Environment;
|
||||||
|
using StressLevelZero.Pool;
|
||||||
|
using StressLevelZero.Props;
|
||||||
|
using StressLevelZero.Props.Weapons;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using Cart = StressLevelZero.Environment.Cart;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
public static class CallPatchedMethods
|
||||||
|
{
|
||||||
|
public static bool allowPatchedMethodCall
|
||||||
|
{
|
||||||
|
private set;
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
public static void TakeDamage(ObjectDestructable __instance, Vector3 normal, float damage, bool crit, AttackType attackType)
|
||||||
|
{
|
||||||
|
allowPatchedMethodCall = true;
|
||||||
|
__instance.TakeDamage(normal, damage, crit, attackType);
|
||||||
|
allowPatchedMethodCall = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TakeDamage(Prop_Health __instance, float damage, bool crit, AttackType attackType)
|
||||||
|
{
|
||||||
|
allowPatchedMethodCall = true;
|
||||||
|
__instance.TAKEDAMAGE(damage, crit, attackType);
|
||||||
|
allowPatchedMethodCall = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FireGun(Gun __instance)
|
||||||
|
{
|
||||||
|
allowPatchedMethodCall = true;
|
||||||
|
__instance.Fire();
|
||||||
|
allowPatchedMethodCall = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CartGo(Cart __instance)
|
||||||
|
{
|
||||||
|
if (__instance == null) return;
|
||||||
|
allowPatchedMethodCall = true;
|
||||||
|
__instance.Go();
|
||||||
|
allowPatchedMethodCall = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CartLaunch(Cart __instance)
|
||||||
|
{
|
||||||
|
if (__instance == null) return;
|
||||||
|
allowPatchedMethodCall = true;
|
||||||
|
__instance.Launch();
|
||||||
|
allowPatchedMethodCall = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CartGoBackward(Cart __instance)
|
||||||
|
{
|
||||||
|
if (__instance == null) return;
|
||||||
|
allowPatchedMethodCall = true;
|
||||||
|
__instance.GoBackward();
|
||||||
|
allowPatchedMethodCall = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CartGoForward(Cart __instance)
|
||||||
|
{
|
||||||
|
if (__instance == null) return;
|
||||||
|
allowPatchedMethodCall = true;
|
||||||
|
__instance.GoForward();
|
||||||
|
allowPatchedMethodCall = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BypassPatchInvoke(this UnityEvent e)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Bypassing patched UnityEvent invoke for event " + e.GetHashCode());
|
||||||
|
UnityEventPatching.GetOriginalEvent(e).Invoke(); // invoke the original event directly
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Poolee InstantiatePoolee(Pool pool, Vector3 position, Quaternion rotation, Vector3 scale)
|
||||||
|
{
|
||||||
|
allowPatchedMethodCall = true;
|
||||||
|
Poolee poolee = pool.InstantiatePoolee(position, rotation);
|
||||||
|
poolee.transform.position = position;
|
||||||
|
poolee.transform.rotation = rotation;
|
||||||
|
poolee.transform.localScale = scale;
|
||||||
|
poolee.transform.parent = null;
|
||||||
|
poolee.gameObject.SetActive(true);
|
||||||
|
allowPatchedMethodCall = false;
|
||||||
|
return poolee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
BoneSync/Patching/CartPatches.cs
Normal file
55
BoneSync/Patching/CartPatches.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using HarmonyLib;
|
||||||
|
using StressLevelZero.Environment;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(Cart))]
|
||||||
|
public class CartPatches
|
||||||
|
{
|
||||||
|
public static bool CartEvent(Cart cart, SimpleEventType eventType)
|
||||||
|
{
|
||||||
|
if (CallPatchedMethods.allowPatchedMethodCall) return true;
|
||||||
|
SyncLogger.Msg("CartEvent: " + cart.transform.GetPath() + " " + eventType);
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(cart);
|
||||||
|
if (syncable == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Error("CartEvent: syncable is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return syncable.AddSimpleEventToQueue(eventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(Cart.Go)), HarmonyPrefix]
|
||||||
|
public static bool CartStartPostfix(Cart __instance)
|
||||||
|
{
|
||||||
|
return CartEvent(__instance, SimpleEventType.CartGo);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(Cart.Launch)), HarmonyPrefix]
|
||||||
|
public static bool CartStopPostfix(Cart __instance)
|
||||||
|
{
|
||||||
|
return CartEvent(__instance, SimpleEventType.CartLaunch);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(Cart.GoBackward)), HarmonyPrefix]
|
||||||
|
public static bool CartGoBackwardPostfix(Cart __instance)
|
||||||
|
{
|
||||||
|
return CartEvent(__instance, SimpleEventType.CartGoBackwards);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(Cart.GoForward)), HarmonyPrefix]
|
||||||
|
public static bool CartGoForwardPostfix(Cart __instance)
|
||||||
|
{
|
||||||
|
return CartEvent(__instance, SimpleEventType.CartGoForward);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
BoneSync/Patching/DebugPatches.cs
Normal file
25
BoneSync/Patching/DebugPatches.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using HarmonyLib;
|
||||||
|
using StressLevelZero.AI;
|
||||||
|
using StressLevelZero.Combat;
|
||||||
|
using StressLevelZero.Pool;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
/*[HarmonyPatch(typeof(PoolSpawner))]
|
||||||
|
internal class DebugPatches
|
||||||
|
{
|
||||||
|
// patch the static method "PoolSpawner.SpawnProjectile"
|
||||||
|
[HarmonyPatch(nameof(PoolSpawner.SpawnProjectile)), HarmonyPrefix]
|
||||||
|
private static void SpawnProjectilePrefix(Vector3 position, Quaternion rotation, BulletObject bulletObject, string weaponName, TriggerRefProxy proxy)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("PoolSpawner.SpawnProjectile " + weaponName);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
43
BoneSync/Patching/GripPatches.cs
Normal file
43
BoneSync/Patching/GripPatches.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
|
||||||
|
// Credit: Entanglement
|
||||||
|
// this patch is based on the one from Entanglement
|
||||||
|
[HarmonyPatch(typeof(ForcePullGrip), nameof(ForcePullGrip.OnFarHandHoverUpdate))]
|
||||||
|
public class ForcePullPatch
|
||||||
|
{
|
||||||
|
public static void Prefix(ForcePullGrip __instance, ref bool __state, Hand hand)
|
||||||
|
{
|
||||||
|
__state = __instance.pullCoroutine != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Postfix(ForcePullGrip __instance, ref bool __state, Hand hand)
|
||||||
|
{
|
||||||
|
if (!(__instance.pullCoroutine != null && !__state))
|
||||||
|
return;
|
||||||
|
|
||||||
|
SyncLogger.Msg("ForcePullGrip.OnFarHandHoverUpdate: " + __instance.name + " Hand: " + hand.name);
|
||||||
|
|
||||||
|
InteractableHost interactableHost = __instance?.grip?.host;
|
||||||
|
if (interactableHost == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Error("InteractableHost is null for " + __instance.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(interactableHost);
|
||||||
|
|
||||||
|
syncable?.RegisterSyncable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
BoneSync/Patching/GunPatches.cs
Normal file
56
BoneSync/Patching/GunPatches.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Props.Weapons;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Gun))]
|
||||||
|
public class GunPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(nameof(Gun.Fire)), HarmonyPrefix]
|
||||||
|
public static bool FirePatch(Gun __instance)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(Gun.OnFire)), HarmonyPrefix]
|
||||||
|
public static void OnFirePatch(Gun __instance)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Gun.OnFire: " + __instance.name);
|
||||||
|
if (!BoneSync.IsConnected) return;
|
||||||
|
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject);
|
||||||
|
if (syncable == null) return;
|
||||||
|
if (!syncable.Registered) return;
|
||||||
|
if (syncable.isOwner)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Gun.OnFire: " + __instance.name + " is owner");
|
||||||
|
GunSyncInfo gunSyncInfo = new GunSyncInfo()
|
||||||
|
{
|
||||||
|
cartridgeState = __instance.cartridgeState,
|
||||||
|
hammerState = __instance.hammerState,
|
||||||
|
syncId = syncable.GetSyncId(),
|
||||||
|
messageType = GunSyncMessageType.Fire,
|
||||||
|
bulletObject = __instance.chamberedCartridge
|
||||||
|
};
|
||||||
|
|
||||||
|
GunSyncMessage gunSyncMessage = new GunSyncMessage(gunSyncInfo);
|
||||||
|
gunSyncMessage.Broadcast();
|
||||||
|
SyncLogger.Msg("Gun.OnFire: " + __instance.name + " sent message");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
50
BoneSync/Patching/HolsterSlotPatches.cs
Normal file
50
BoneSync/Patching/HolsterSlotPatches.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
using StressLevelZero.Props.Weapons;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(HandWeaponSlotReciever))]
|
||||||
|
internal class HolsterSlotPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(nameof(HandWeaponSlotReciever.MakeStatic)), HarmonyPrefix]
|
||||||
|
public static void StaticPatch(HandWeaponSlotReciever __instance)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("HandWeaponSlotReciever.MakeStatic: " + __instance.name);
|
||||||
|
InteractableHost interactableHost = __instance.m_WeaponHost;
|
||||||
|
if (interactableHost == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Error("InteractableHost is null for " + __instance.transform.GetPath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(interactableHost);
|
||||||
|
syncable?.SetInHolster(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(HandWeaponSlotReciever.MakeDynamic)), HarmonyPrefix]
|
||||||
|
public static void DynamicPatch(HandWeaponSlotReciever __instance)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("HandWeaponSlotReciever.MakeDynamic: " + __instance.name);
|
||||||
|
InteractableHost interactableHost = __instance.m_WeaponHost;
|
||||||
|
if (interactableHost == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Error("InteractableHost is null for " + __instance.transform.GetPath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(interactableHost);
|
||||||
|
syncable?.SetInHolster(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
using BoneSync.Sync;
|
using BoneSync.Sync;
|
||||||
using BoneSync.Sync.Components;
|
using BoneSync.Sync.Components;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
@@ -18,24 +19,19 @@ namespace BoneSync.Patching
|
|||||||
[HarmonyPatch(nameof(InteractableHost.OnEnable)), HarmonyPostfix]
|
[HarmonyPatch(nameof(InteractableHost.OnEnable)), HarmonyPostfix]
|
||||||
public static void OnEnablePatch(InteractableHost __instance)
|
public static void OnEnablePatch(InteractableHost __instance)
|
||||||
{
|
{
|
||||||
//MelonLoader.MelonLogger.Msg("InteractableHost enabled: " + __instance.name + " Manager: " + __instance?.manager?.name);
|
//SyncLogger.Msg("InteractableHost enabled: " + __instance.name + " Manager: " + __instance?.manager?.name);
|
||||||
ObjectSync.MakeOrGetSyncable(__instance);
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance);
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(nameof(InteractableHost.OnDestroy)), HarmonyPostfix]
|
|
||||||
public static void OnDestroyPatch(InteractableHost __instance)
|
|
||||||
{
|
|
||||||
MelonLogger.Msg("InteractableHost destroyed: " + __instance.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPatch(nameof(InteractableHost.AttachHand)), HarmonyPostfix]
|
[HarmonyPatch(nameof(InteractableHost.AttachHand)), HarmonyPostfix]
|
||||||
public static void AttachHandPatch(InteractableHost __instance, Hand hand)
|
public static void AttachHandPatch(InteractableHost __instance, Hand hand)
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("InteractableHost attached to hand: " + __instance.name + " Hand: " + hand.name);
|
SyncLogger.Msg("InteractableHost attached to hand: " + __instance.name + " Hand: " + hand.name);
|
||||||
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance);
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance);
|
||||||
if (syncable == null)
|
if (syncable == null)
|
||||||
{
|
{
|
||||||
MelonLogger.Error("Syncable is null for " + __instance.name);
|
SyncLogger.Error("Syncable is null for " + __instance.name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
syncable.RegisterSyncable();
|
syncable.RegisterSyncable();
|
||||||
@@ -45,7 +41,7 @@ namespace BoneSync.Patching
|
|||||||
/*[HarmonyPatch(nameof(InteractableHost.AddForcePullGrip)), HarmonyPostfix]
|
/*[HarmonyPatch(nameof(InteractableHost.AddForcePullGrip)), HarmonyPostfix]
|
||||||
public static void AddForcePullGripPatch(InteractableHost __instance, ForcePullGrip grip)
|
public static void AddForcePullGripPatch(InteractableHost __instance, ForcePullGrip grip)
|
||||||
{
|
{
|
||||||
MelonLoader.MelonLogger.Msg("AddForcePullGrip to hand: " + __instance.name + " Hand: " + grip.name);
|
SyncLogger.Msg("AddForcePullGrip to hand: " + __instance.name + " Hand: " + grip.name);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -56,7 +52,7 @@ namespace BoneSync.Patching
|
|||||||
[HarmonyPatch(nameof(InteractableHostManager.Start)), HarmonyPostfix]
|
[HarmonyPatch(nameof(InteractableHostManager.Start)), HarmonyPostfix]
|
||||||
public static void OnEnablePatch(InteractableHostManager __instance)
|
public static void OnEnablePatch(InteractableHostManager __instance)
|
||||||
{
|
{
|
||||||
MelonLoader.MelonLogger.Msg("InteractableHostManager started: " + __instance.transform.GetPath());
|
SyncLogger.Msg("InteractableHostManager started: " + __instance.transform.GetPath());
|
||||||
ObjectSync.MakeOrGetSyncable(__instance);
|
ObjectSync.MakeOrGetSyncable(__instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
87
BoneSync/Patching/ObjectHealthPatches.cs
Normal file
87
BoneSync/Patching/ObjectHealthPatches.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using HarmonyLib;
|
||||||
|
using StressLevelZero.Combat;
|
||||||
|
using StressLevelZero.Data;
|
||||||
|
using StressLevelZero.Props;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(ObjectDestructable))]
|
||||||
|
public class ObjectDestructablePatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(nameof(ObjectDestructable.TakeDamage))]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
private static bool TakeDamagePatch(ObjectDestructable __instance, ref Vector3 normal, ref float damage, ref bool crit, ref AttackType attackType)
|
||||||
|
{
|
||||||
|
if (CallPatchedMethods.allowPatchedMethodCall) return true;
|
||||||
|
if (!BoneSync.IsConnected) return true;
|
||||||
|
if (damage < 0.05f) return true; // ignore small damage (e.g. a little bit of fall damage)
|
||||||
|
//SyncLogger.Msg("ObjectDestructable.TakeDamage: " + damage);
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject);
|
||||||
|
if (syncable != null)
|
||||||
|
{
|
||||||
|
if (damage > 0.5f) syncable.RegisterSyncable(); // register syncable if damage is very significant, e.g. a bullet hit
|
||||||
|
if (syncable.Registered && !syncable.isOwner) return false;
|
||||||
|
//SyncLogger.Msg("Patch: ObjectDestructable.TakeDamage: " + damage + " " + syncable.gameObject.name);
|
||||||
|
ObjectHealthInfo objectHealthInfo = new ObjectHealthInfo(__instance._health, __instance._hits, normal, damage, crit, attackType, 0);
|
||||||
|
|
||||||
|
ObjectSync.SendObjectDamageMessage(syncable, ObjectDamageType.DestructibleTakeDamage, objectHealthInfo);
|
||||||
|
|
||||||
|
return false; // prevent networked objects from taking damage locally
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*// patch the getter for lootTable to return null if the object is networked
|
||||||
|
[HarmonyPatch(nameof(ObjectDestructable.lootTable), MethodType.Getter)]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
private static bool LootTablePatch(ObjectDestructable __instance, ref LootTableData __result)
|
||||||
|
{
|
||||||
|
if (!BoneSync.IsConnected) return true;
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject);
|
||||||
|
if (syncable != null && !BoneSync.lobby.IsHost)
|
||||||
|
{
|
||||||
|
__result = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Prop_Health))]
|
||||||
|
public class PropHealthPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(nameof(Prop_Health.TAKEDAMAGE))]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
private static bool TakeDamagePatch(Prop_Health __instance, ref float damage, ref bool crit, ref AttackType attackType)
|
||||||
|
{
|
||||||
|
if (CallPatchedMethods.allowPatchedMethodCall) return true;
|
||||||
|
if (!BoneSync.IsConnected) return true;
|
||||||
|
//SyncLogger.Msg("Prop_Health.TAKEDAMAGE: " + damage);
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject);
|
||||||
|
if (syncable != null)
|
||||||
|
{
|
||||||
|
if (damage > 0.5f) syncable.RegisterSyncable();
|
||||||
|
if (syncable.Registered && !syncable.isOwner) return false;
|
||||||
|
//SyncLogger.Msg("Patch: Prop_Health.TAKEDAMAGE: " + damage + " " + syncable.gameObject.name);
|
||||||
|
ObjectHealthInfo objectHealthInfo = new ObjectHealthInfo(__instance.cur_Health, __instance.hits, Vector3.zero, damage, crit, attackType, 0);
|
||||||
|
|
||||||
|
ObjectSync.SendObjectDamageMessage(syncable, ObjectDamageType.PropHealthTakeDamage, objectHealthInfo);
|
||||||
|
|
||||||
|
return false; // prevent networked objects from taking damage locally
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
101
BoneSync/Patching/PlugPatches.cs
Normal file
101
BoneSync/Patching/PlugPatches.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
|
||||||
|
public static class AlignPlugPatches
|
||||||
|
{
|
||||||
|
public static void OnPlugSocketChange(AlignPlug plug, Socket socket)
|
||||||
|
{
|
||||||
|
|
||||||
|
Syncable plugSyncable = plug.GetComponentInParent<Syncable>();
|
||||||
|
Syncable socketSyncable = socket?.GetComponentInParent<Syncable>();
|
||||||
|
|
||||||
|
if (!plugSyncable)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("PlugSyncable not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugSyncable.FindAndUpdateComponents();
|
||||||
|
|
||||||
|
if (!plugSyncable.Registered)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("PlugSyncable not registered");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!socketSyncable)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("SocketSyncable not found");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
socketSyncable.FindAndUpdateComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (socketSyncable != null && socketSyncable.isOwner && !plugSyncable.isOwner)
|
||||||
|
{
|
||||||
|
plugSyncable.TryBecomeOwner(true); // forcefully take ownership of the plug
|
||||||
|
}
|
||||||
|
|
||||||
|
byte plugId = plugSyncable.GetPlugId(plug);
|
||||||
|
byte socketId = socketSyncable != null ? socketSyncable.GetSocketId(socket) : byte.MaxValue;
|
||||||
|
|
||||||
|
//SyncLogger.Msg("AlignPlug state:" + plug.transform.GetPath() + " Socket:" + socket?.transform?.GetPath() + " PlugID:" + plugId + " SocketID:" + socketId);
|
||||||
|
|
||||||
|
if (!plugSyncable.isOwner) return;
|
||||||
|
|
||||||
|
PlugSyncMessageData messageData = new PlugSyncMessageData
|
||||||
|
{
|
||||||
|
plugSyncId = plugSyncable.GetSyncId(),
|
||||||
|
plugIndex = plugId,
|
||||||
|
socketSyncId = socketSyncable != null ? socketSyncable.GetSyncId() : ushort.MinValue,
|
||||||
|
socketIndex = socketId
|
||||||
|
};
|
||||||
|
|
||||||
|
PlugSyncMessage plugSyncMessage = new PlugSyncMessage(messageData);
|
||||||
|
plugSyncMessage.Broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
// for some reason AlignPlug.OnPlugInsertComplete can't be patched directly
|
||||||
|
/*
|
||||||
|
[HarmonyPatch(nameof(AlignPlug.OnPlugExitComplete)), HarmonyPostfix]
|
||||||
|
public static void AlignPlugEjectPatch(AlignPlug __instance)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("AlignPlug ejected: " + __instance.transform.GetPath());
|
||||||
|
OnPlugSocketChange(__instance, null);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(MagazinePlug))]
|
||||||
|
public static class MagazinePlugPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(nameof(MagazinePlug.OnPlugInsertComplete)), HarmonyPostfix]
|
||||||
|
public static void MagazinePlugInsertPatch(MagazinePlug __instance)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("MagazinePlug inserted: " + __instance.transform.GetPath());
|
||||||
|
AlignPlugPatches.OnPlugSocketChange(__instance, __instance.GetSocket());
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(MagazinePlug.OnPlugExitComplete)), HarmonyPostfix]
|
||||||
|
public static void MagazinePlugEjectPatch(MagazinePlug __instance)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("MagazinePlug ejected: " + __instance.transform.GetPath());
|
||||||
|
AlignPlugPatches.OnPlugSocketChange(__instance, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,41 +1,211 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using StressLevelZero;
|
using StressLevelZero;
|
||||||
using StressLevelZero.Pool;
|
using StressLevelZero.Pool;
|
||||||
|
using StressLevelZero.Props.Weapons;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace BoneSync.Patching
|
namespace BoneSync.Patching
|
||||||
{
|
{
|
||||||
/*
|
public static class PoolBlacklist
|
||||||
|
{
|
||||||
|
private static Dictionary<Pool, bool> _blacklistedCache = new Dictionary<Pool, bool>();
|
||||||
|
private static Dictionary<Pool, bool> _clientSpawnCache = new Dictionary<Pool, bool>();
|
||||||
|
|
||||||
|
private static bool _isBlacklistedPool(Pool pool)
|
||||||
|
{
|
||||||
|
if (pool.name.Contains("RigidbodyProjectile")) return true;
|
||||||
|
if (pool.name.Contains("VFX Despawn Mesh")) return true;
|
||||||
|
if (pool.name.Contains("AudioPlayer")) return true;
|
||||||
|
if (pool.name.Contains("Decal")) return true;
|
||||||
|
if (pool.name.Contains("PopupText")) return true;
|
||||||
|
//if (pool.name.Contains("Nimbus")) return true;
|
||||||
|
|
||||||
|
if (pool.Prefab.GetComponent<SpawnFragment>() != null) return true;
|
||||||
|
if (pool.Prefab.GetComponent<SpawnFragmentArray>() != null) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool _isClientSpawnPool(Pool pool)
|
||||||
|
{
|
||||||
|
if (pool.Prefab.GetComponent<Magazine>() != null) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public static bool IsBlacklistedPool(Pool pool)
|
||||||
|
{
|
||||||
|
if (_blacklistedCache.ContainsKey(pool))
|
||||||
|
return _blacklistedCache[pool];
|
||||||
|
_blacklistedCache[pool] = _isBlacklistedPool(pool);
|
||||||
|
return _blacklistedCache[pool];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsClientSpawnPool(Pool pool)
|
||||||
|
{
|
||||||
|
if (_clientSpawnCache.ContainsKey(pool))
|
||||||
|
return _clientSpawnCache[pool];
|
||||||
|
_clientSpawnCache[pool] = _isClientSpawnPool(pool);
|
||||||
|
return _clientSpawnCache[pool];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HarmonyPatch(typeof(Pool))]
|
[HarmonyPatch(typeof(Pool))]
|
||||||
internal class PoolPatches
|
public static class PoolPatches
|
||||||
{
|
{
|
||||||
|
[HarmonyPatch(nameof(Pool.InstantiatePoolee), new Type[] { typeof(Vector3), typeof(Quaternion) }), HarmonyPrefix]
|
||||||
[HarmonyPatch(nameof(Pool.Spawn))]
|
private static bool InstantiatePooleePatchPre(Pool __instance)
|
||||||
[HarmonyPostfix]
|
|
||||||
private static void SpawnPatch(Pool __instance, ref GameObject __result)
|
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("Spawned object: " + __result.name);
|
if (!__instance.Prefab)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPatch(nameof(Pool.FlagPooleeForRespawn))]
|
[HarmonyPatch(nameof(Pool.InstantiatePoolee), new Type[] { typeof(Vector3), typeof(Quaternion) }), HarmonyPostfix]
|
||||||
[HarmonyPostfix]
|
private static void InstantiatePooleePatchPost(Pool __instance, Poolee __result, Vector3 position, Quaternion rotation)
|
||||||
private static void FlagPooleeForRespawnPatch(Pool __instance, ref GameObject p)
|
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("Flagged object for respawn: " + p.name);
|
if (CallPatchedMethods.allowPatchedMethodCall) return;
|
||||||
}
|
if (__instance == null) return;
|
||||||
[HarmonyPatch(nameof(Pool.InstantiatePoolee))]
|
if (PoolBlacklist.IsBlacklistedPool(__instance)) return;
|
||||||
[HarmonyPostfix]
|
//SyncLogger.Msg("Patched Instantiating object in pool: " + __instance.name);
|
||||||
private static void InstantiatePooleePatch(Pool __instance, ref Poolee __result)
|
__result.onSpawnDelegate = Il2CppSystem.Delegate.Combine(__result.onSpawnDelegate, (Il2CppSystem.Action<GameObject>)((g) => { PooleePatches.OnSpawnPatchPost(__result); })).Cast<Il2CppSystem.Action<GameObject>>();
|
||||||
{
|
__result.onDespawnDelegate = Il2CppSystem.Delegate.Combine(__result.onDespawnDelegate, (Il2CppSystem.Action<GameObject>)((g) => { PooleePatches.OnDespawnPatchPost(__result); })).Cast<Il2CppSystem.Action<GameObject>>();
|
||||||
MelonLogger.Msg("Instantiated object: " + __result.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*[HarmonyPatch(nameof(Pool.Spawn))]
|
||||||
|
[HarmonyPostfix]
|
||||||
|
private static void SpawnPatchPost(Pool __instance, ref GameObject __result)
|
||||||
|
{
|
||||||
|
if (__instance == null) return;
|
||||||
|
if (__instance.Prefab == null) return;
|
||||||
|
if (CallPatchedMethods.allowPatchedMethodCall) return;
|
||||||
|
if (PoolBlacklist.isBlacklistedPool(__instance)) return;
|
||||||
|
if (BoneSync.IsConnected)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Patched Spawning object in pool: " + __instance.name);
|
||||||
|
bool isHost = BoneSync.lobby.IsHost;
|
||||||
|
if (!isHost) GameObject.DestroyImmediate(__result);
|
||||||
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
/*[HarmonyPatch(nameof(Pool.Spawn))]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
private static bool SpawnPatchPre(Pool __instance, ref Vector3 position, ref Quaternion rotation, ref Il2CppSystem.Nullable<Vector3> scale, ref Il2CppSystem.Nullable<bool> autoEnable)
|
||||||
|
{
|
||||||
|
if (__instance == null) return true;
|
||||||
|
if (__instance.Prefab == null) return true;
|
||||||
|
if (CallPatchedMethods.allowPatchedMethodCall) return true;
|
||||||
|
if (PoolBlacklist.isBlacklistedPool(__instance)) return true;
|
||||||
|
if (BoneSync.IsConnected)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Patched Spawning object in pool: " + __instance.name);
|
||||||
|
return BoneSync.lobby.IsHost; // only allow host to spawn objects naturally
|
||||||
|
}
|
||||||
|
__instance.
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
[HarmonyPatch(typeof(Poolee))]
|
||||||
|
public static class PooleePatches
|
||||||
|
{
|
||||||
|
public static void OnSpawnPatchPost(Poolee __instance)
|
||||||
|
{
|
||||||
|
if (CallPatchedMethods.allowPatchedMethodCall) return;
|
||||||
|
if (!BoneSync.IsConnected) return;
|
||||||
|
|
||||||
|
SyncLogger.Msg("Poolee.OnSpawn: " + __instance.gameObject.transform.GetPath());
|
||||||
|
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance);
|
||||||
|
|
||||||
|
bool spawnNormally = BoneSync.lobby.IsHost || PoolBlacklist.IsClientSpawnPool(__instance.pool);
|
||||||
|
|
||||||
|
SyncLogger.Msg("Poolee.OnSpawn: " + __instance.gameObject.transform.GetPath() + " syncid:" + syncable?.GetSyncId() + " spawnNormally" + spawnNormally);
|
||||||
|
|
||||||
|
if (!spawnNormally) {
|
||||||
|
MelonCoroutines.Start(OnSpawnClient(__instance)); // block object from spawning
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncable == null) return;
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//.Msg("Poolee.OnSpawn: " + __instance.gameObject.transform.GetPath() + " " + syncable.GetSyncId());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnDespawnPatchPost(Poolee __instance)
|
||||||
|
{
|
||||||
|
if (CallPatchedMethods.allowPatchedMethodCall) return;
|
||||||
|
if (!BoneSync.IsConnected) return;
|
||||||
|
|
||||||
|
SyncLogger.Msg("Poolee.OnDespawn: " + __instance.gameObject.transform.GetPath());
|
||||||
|
|
||||||
|
//Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance);
|
||||||
|
|
||||||
|
//if (syncable == null) return;
|
||||||
|
|
||||||
|
//if (syncable.isOwner) return;
|
||||||
|
|
||||||
|
//syncable.DiscardSyncable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerator OnSpawnClient(Poolee poolee)
|
||||||
|
{
|
||||||
|
GameObject go = poolee.gameObject;
|
||||||
|
if (SceneLoader.loading)
|
||||||
|
{
|
||||||
|
while (SceneLoader.loading)
|
||||||
|
{
|
||||||
|
go.SetActive(false);
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
go.SetActive(false);
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static IEnumerator OnSpawnHost(Poolee poolee)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* // DONT USE THIS PATCH, CRASHES GAME WITH NO ERROR
|
||||||
|
[HarmonyPatch(nameof(Poolee.Despawn), new Type[] { typeof(Il2CppSystem.Nullable<bool>), typeof(Il2CppSystem.Nullable<Color>) }), HarmonyPrefix]
|
||||||
|
private static bool DespawnPatchPre(Poolee __instance, ref Il2CppSystem.Nullable<bool> playVFX, ref Il2CppSystem.Nullable<Color> despawnColor)
|
||||||
|
{
|
||||||
|
if (CallPatchedMethods.allowPatchedMethodCall) return true;
|
||||||
|
if (!BoneSync.IsConnected) return true;
|
||||||
|
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance);
|
||||||
|
if (syncable == null) return true;
|
||||||
|
if (!syncable.isOwner) return false; // if not owner, don't despawn
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
56
BoneSync/Patching/PrefabSpawnerPatches.cs
Normal file
56
BoneSync/Patching/PrefabSpawnerPatches.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Data;
|
||||||
|
using StressLevelZero.Pool;
|
||||||
|
using UnityEngine;
|
||||||
|
using static StressLevelZero.VFX.ParticleSpreadManager;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(PrefabSpawner))]
|
||||||
|
internal class PrefabSpawnerPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(nameof(PrefabSpawner.SpawnPrefab), new Type[] { typeof(Transform), typeof(Vector3), typeof(Quaternion) }), HarmonyPrefix]
|
||||||
|
private static bool SpawnPrefabPrefix(PrefabSpawner __instance, Transform AttachTo, Vector3 Position, Quaternion Rotation)
|
||||||
|
{
|
||||||
|
if (!BoneSync.IsConnected) return true;
|
||||||
|
if (!BoneSync.lobby.IsHost) return false;
|
||||||
|
|
||||||
|
Syncable syncable = SpawnPrefabSyncable(__instance, AttachTo, Position, Rotation);
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(PrefabSpawner.SpawnPrefab), new Type[] { }), HarmonyPrefix]
|
||||||
|
private static bool SpawnPrefabSimplePrefix(PrefabSpawner __instance)
|
||||||
|
{
|
||||||
|
return SpawnPrefabPrefix(__instance, null, __instance.transform.position, __instance.transform.rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Syncable SpawnPrefabSyncable(PrefabSpawner __instance, Transform AttachTo, Vector3 Position, Quaternion Rotation)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Spawning prefab: " + __instance.Prefab.name);
|
||||||
|
SpawnableObject spawnable = SpawnableManager.GetSpawnableByPrefabName(__instance.Prefab.name);
|
||||||
|
if (spawnable == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Error("Spawnable not found for prefab: " + __instance.Prefab.name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Poolee poolee = SpawnableManager.SpawnPoolee(spawnable, Position, Rotation);
|
||||||
|
Syncable syncable = ObjectSync.MakeOrGetSyncable(poolee);
|
||||||
|
syncable.RegisterSyncable();
|
||||||
|
|
||||||
|
return syncable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
BoneSync/Patching/SceneManagerPatches.cs
Normal file
41
BoneSync/Patching/SceneManagerPatches.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Sync;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Utilities;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(BoneworksSceneManager))]
|
||||||
|
internal class SceneManagerPatches
|
||||||
|
{
|
||||||
|
/*[HarmonyPatch(nameof(BoneworksSceneManager.LoadScene), new Type[] { typeof(int) }), HarmonyPrefix]
|
||||||
|
private static void LoadSceneIndexPrefix(int sceneBuildIndex)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("LoadScenePrefix: " + sceneBuildIndex);
|
||||||
|
if (!BoneSync.IsConnected) return;
|
||||||
|
if (BoneSync.lobby.IsHost)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Host is loading scene, sending message to clients...");
|
||||||
|
SceneSync.SendSceneSyncMessage(sceneBuildIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(BoneworksSceneManager.LoadScene), new Type[] { typeof(string) }), HarmonyPostfix]
|
||||||
|
private static void LoadSceneStringPrefix(string sceneName)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("LoadScenePrefix: " + sceneName);
|
||||||
|
if (!BoneSync.IsConnected) return;
|
||||||
|
if (BoneSync.lobby.IsHost)
|
||||||
|
{
|
||||||
|
//SyncLogger.Msg("Host is loading scene, sending message to clients...");
|
||||||
|
//SceneSync.SendSceneSyncMessage(sceneName);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
94
BoneSync/Patching/SkeletonHandPatches.cs
Normal file
94
BoneSync/Patching/SkeletonHandPatches.cs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Rig;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using StressLevelZero;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(SkeletonHand))]
|
||||||
|
internal static class SkeletonHandPatches
|
||||||
|
{
|
||||||
|
public static byte poseIndexRight = 0;
|
||||||
|
public static float radiusRight = 0.0f;
|
||||||
|
|
||||||
|
public static byte poseIndexLeft = 0;
|
||||||
|
public static float radiusLeft = 0.0f;
|
||||||
|
|
||||||
|
private static Dictionary<string, byte> handPoses = new Dictionary<string, byte>();
|
||||||
|
|
||||||
|
private static byte GetHandPoseIndex(string handPoseName)
|
||||||
|
{
|
||||||
|
if (handPoses.ContainsKey(handPoseName))
|
||||||
|
return handPoses[handPoseName];
|
||||||
|
|
||||||
|
if (PlayerScripts.playerHandPoses == null || PlayerScripts.playerHandPoses.Count == 0)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("PlayerScripts.playerHandPoses is empty, getting hand poses...");
|
||||||
|
PlayerScripts.GetHandPoses();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = PlayerScripts.playerHandPoses.Contains(handPoseName);
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
//SyncLogger.Error($"Hand pose {handPoseName} not found in playerHandPoses!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
byte index = (byte)PlayerScripts.playerHandPoses.IndexOf(handPoseName);
|
||||||
|
handPoses.Add(handPoseName, index);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(SkeletonHand.SetHandPose)), HarmonyPrefix]
|
||||||
|
private static void SetHandPosePostfix(SkeletonHand __instance, string handPoseName)
|
||||||
|
{
|
||||||
|
if (!__instance.GetCharacterAnimationManager()) return;
|
||||||
|
SyncLogger.Msg($"SetHandPosePostfix: {handPoseName}");
|
||||||
|
|
||||||
|
int poseIndex = GetHandPoseIndex(handPoseName);
|
||||||
|
switch (__instance.handedness)
|
||||||
|
{
|
||||||
|
case Handedness.LEFT:
|
||||||
|
poseIndexLeft = (byte)poseIndex;
|
||||||
|
break;
|
||||||
|
case Handedness.RIGHT:
|
||||||
|
poseIndexRight = (byte)poseIndex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(SkeletonHand.SetCylinderRadius)), HarmonyPrefix]
|
||||||
|
private static void SetCylinderRadiusPrefix(SkeletonHand __instance, float radius)
|
||||||
|
{
|
||||||
|
if (!__instance.GetCharacterAnimationManager()) return;
|
||||||
|
|
||||||
|
//SyncLogger.Msg($"SetCylinderRadiusPrefix: {radius}");
|
||||||
|
|
||||||
|
switch (__instance.handedness)
|
||||||
|
{
|
||||||
|
case Handedness.LEFT:
|
||||||
|
if (radiusLeft == radius) return;
|
||||||
|
SyncLogger.Msg($"SetCylinderRadiusPrefixLeft: {radius}");
|
||||||
|
radiusLeft = radius;
|
||||||
|
break;
|
||||||
|
case Handedness.RIGHT:
|
||||||
|
if (radiusRight == radius) return;
|
||||||
|
SyncLogger.Msg($"SetCylinderRadiusPrefixRight: {radius}");
|
||||||
|
radiusRight = radius;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
82
BoneSync/Patching/UnityEventPatching.cs
Normal file
82
BoneSync/Patching/UnityEventPatching.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using HarmonyLib;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
public class UnityEventPatching
|
||||||
|
{
|
||||||
|
internal static Dictionary<int, UnityEvent> _patchToOriginalMap = new Dictionary<int, UnityEvent>();
|
||||||
|
public static UnityEvent GetOriginalEvent(UnityEvent unityEvent)
|
||||||
|
{
|
||||||
|
int eventHash = unityEvent.GetHashCode();
|
||||||
|
if (_patchToOriginalMap.TryGetValue(eventHash, out UnityEvent originalEvent))
|
||||||
|
{
|
||||||
|
return originalEvent;
|
||||||
|
}
|
||||||
|
return unityEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class UnityEventPatch<T>
|
||||||
|
{
|
||||||
|
private static Dictionary<int, UnityEventPatch<T>> patches = new Dictionary<int, UnityEventPatch<T>>();
|
||||||
|
|
||||||
|
private T arg;
|
||||||
|
private UnityEvent unityEvent;
|
||||||
|
private Func<T, bool> handler;
|
||||||
|
private UnityEvent proxyUnityEvent;
|
||||||
|
//private float lastInvokeTime = 0f;
|
||||||
|
//private float invokeCooldown = 0.05f;
|
||||||
|
private UnityEventPatch(T arg, UnityEvent unityEvent, Func<T, bool> handler)
|
||||||
|
{
|
||||||
|
this.arg = arg;
|
||||||
|
this.unityEvent = unityEvent;
|
||||||
|
this.handler = handler;
|
||||||
|
this.proxyUnityEvent = new UnityEvent();
|
||||||
|
this.proxyUnityEvent.AddListener((UnityAction)OnEventInvoked);
|
||||||
|
int patchEventHash = proxyUnityEvent.GetHashCode();
|
||||||
|
patches[patchEventHash] = this; // avoid creating multiple patches for same event
|
||||||
|
UnityEventPatching._patchToOriginalMap[patchEventHash] = unityEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnityEvent GetOriginalEvent()
|
||||||
|
{
|
||||||
|
return unityEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEventInvoked()
|
||||||
|
{
|
||||||
|
bool allowInvoke = handler.Invoke(arg);
|
||||||
|
SyncLogger.Msg("UnityEventPatch invoked for event " + unityEvent.GetHashCode() + ", allowInvoke: " + allowInvoke);
|
||||||
|
if (allowInvoke)
|
||||||
|
{
|
||||||
|
unityEvent.Invoke(); // only invoke the original event if allowed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnityEvent GetPatchedEvent()
|
||||||
|
{
|
||||||
|
return proxyUnityEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UnityEventPatch<T> Patch(T arg, UnityEvent unityEvent, Func<T, bool> handler)
|
||||||
|
{
|
||||||
|
int eventHash = unityEvent.GetHashCode();
|
||||||
|
UnityEventPatch<T> existingPatch = patches.TryGetValue(eventHash, out UnityEventPatch<T> foundPatch) ? foundPatch : null;
|
||||||
|
if (existingPatch != null)
|
||||||
|
{
|
||||||
|
return existingPatch;
|
||||||
|
}
|
||||||
|
UnityEventPatch<T> patch = new UnityEventPatch<T>(arg, unityEvent, handler);
|
||||||
|
patches[eventHash] = patch;
|
||||||
|
return patch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
134
BoneSync/Patching/ZonePatches.cs
Normal file
134
BoneSync/Patching/ZonePatches.cs
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Player;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using HarmonyLib;
|
||||||
|
using StressLevelZero.Zones;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Patching
|
||||||
|
{
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(ZoneSpawner))]
|
||||||
|
public static class ZoneSpawnerPatch
|
||||||
|
{
|
||||||
|
// this patch should catch most of the spawning, but the pool spawning patch should catch the rest
|
||||||
|
[HarmonyPatch(nameof(ZoneSpawner.Spawn)), HarmonyPrefix]
|
||||||
|
public static bool ZoneSpawnPrefix(ZoneSpawner __instance)
|
||||||
|
{
|
||||||
|
if (!BoneSync.IsConnected) return true; // do not block if not connected
|
||||||
|
|
||||||
|
//.Msg("ZoneSpawner.Spawn: " + __instance.transform.GetPath());
|
||||||
|
|
||||||
|
if (BoneSync.lobby.IsHost)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // don't spawn if not host
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(ZoneEncounter))]
|
||||||
|
public static class ZoneEncounterPatch
|
||||||
|
{
|
||||||
|
[HarmonyPatch(nameof(ZoneEncounter.StartEncounter)), HarmonyPrefix]
|
||||||
|
public static bool ZoneEncounterSpawnPrefix(ZoneEncounter __instance)
|
||||||
|
{
|
||||||
|
if (!BoneSync.IsConnected) return true;
|
||||||
|
|
||||||
|
SyncLogger.Msg("ZoneEncounter.StartEncounter: " + __instance.transform.GetPath());
|
||||||
|
|
||||||
|
if (BoneSync.lobby.IsHost)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SceneZone and PlayerTrigger patches are based on the ones from entanglement mod
|
||||||
|
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(SceneZone))]
|
||||||
|
public static class SceneZonePatch
|
||||||
|
{
|
||||||
|
public static bool IsChildOfLocalRig(Transform transform)
|
||||||
|
{
|
||||||
|
if (PlayerRig.localRigWorldRoot == null) return false;
|
||||||
|
return transform.root == PlayerRig.localRigWorldRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsChildOfHostRig(Transform transform)
|
||||||
|
{
|
||||||
|
if (!BoneSync.IsConnected|| BoneSync.lobby.IsHost)
|
||||||
|
{
|
||||||
|
return IsChildOfLocalRig(transform);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlayerRig hostRig = PlayerRig.GetPlayerRig(BoneSync.lobby.GetHostId());
|
||||||
|
Transform hostRoot = hostRig?.transform.root;
|
||||||
|
return hostRoot != null && transform.root == hostRoot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(SceneZone.OnTriggerEnter)), HarmonyPrefix]
|
||||||
|
public static bool EnterPrefix(SceneZone __instance, Collider other)
|
||||||
|
{
|
||||||
|
if (other.CompareTag("Player"))
|
||||||
|
{
|
||||||
|
return IsChildOfLocalRig(other.transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(SceneZone.OnTriggerExit)), HarmonyPrefix]
|
||||||
|
public static bool ExitPrefix(SceneZone __instance, Collider other)
|
||||||
|
{
|
||||||
|
if (other.CompareTag("Player"))
|
||||||
|
{
|
||||||
|
return IsChildOfLocalRig(other.transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(PlayerTrigger))]
|
||||||
|
public static class PlayerTriggerPatch
|
||||||
|
{
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(PlayerTrigger.OnTriggerEnter)), HarmonyPrefix]
|
||||||
|
public static bool EnterPrefix(PlayerTrigger __instance, Collider other)
|
||||||
|
{
|
||||||
|
if (other.CompareTag("Player"))
|
||||||
|
{
|
||||||
|
|
||||||
|
return SceneZonePatch.IsChildOfLocalRig(other.transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// only patch exit, as we want to allow activating a trigger always
|
||||||
|
[HarmonyPatch(nameof(PlayerTrigger.OnTriggerExit)), HarmonyPrefix]
|
||||||
|
public static bool ExitPrefix(PlayerTrigger __instance, Collider other)
|
||||||
|
{
|
||||||
|
if (other.CompareTag("Player"))
|
||||||
|
{
|
||||||
|
return SceneZonePatch.IsChildOfLocalRig(other.transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,38 +11,306 @@ using StressLevelZero.Player;
|
|||||||
using StressLevelZero.VRMK;
|
using StressLevelZero.VRMK;
|
||||||
using BoneSync.Networking;
|
using BoneSync.Networking;
|
||||||
using BoneSync.Networking.Messages;
|
using BoneSync.Networking.Messages;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.IO;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
using UnhollowerBaseLib;
|
||||||
|
using BoneSync.Patching;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using Oculus.Platform.Models;
|
||||||
|
|
||||||
|
|
||||||
namespace BoneSync.Player
|
namespace BoneSync.Player
|
||||||
{
|
{
|
||||||
internal class PlayerRig
|
internal class PlayerRig
|
||||||
{
|
{
|
||||||
//public const string RIGMANAGER_SCENE_NAME = "[RigManager (Default Brett)]";
|
private const float RIG_SYNC_FPS = Syncable.OBJECT_SYNC_FPS;
|
||||||
|
|
||||||
private static List<PlayerRig> _playerRigs = new List<PlayerRig>();
|
public static AssetBundle rigBundle;
|
||||||
|
private static float _lastLocalSyncTime = 0;
|
||||||
|
private static Dictionary<ulong, PlayerRig> _playerRigs = new Dictionary<ulong, PlayerRig>();
|
||||||
|
|
||||||
|
private ulong _ownerId;
|
||||||
|
|
||||||
private GameObject playerRig;
|
private GameObject playerRig;
|
||||||
private RigManager rigManager;
|
|
||||||
private SLZ_Body body;
|
private SLZ_Body body;
|
||||||
private CharacterAnimationManager characterAnimationManager;
|
private CharacterAnimationManager characterAnimationManager;
|
||||||
private Animator repAnimator;
|
private Animator animator;
|
||||||
|
|
||||||
|
private Transform headTransform;
|
||||||
|
private Transform leftHandTransform;
|
||||||
|
private Transform rightHandTransform;
|
||||||
|
|
||||||
|
public Transform transform => playerRig.transform;
|
||||||
|
|
||||||
|
public static void LoadBundle()
|
||||||
|
{
|
||||||
|
rigBundle = EmebeddedAssetBundle.LoadFromAssembly("BoneSync.playerrep.eres");
|
||||||
|
|
||||||
|
if (rigBundle == null)
|
||||||
|
throw new NullReferenceException("playerRepBundle is null! Did you forget to compile the player bundle into the dll?");
|
||||||
|
|
||||||
|
|
||||||
|
SyncLogger.Msg("Loaded playerRepBundle success");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Tick(float deltaTime)
|
||||||
|
{
|
||||||
|
foreach (PlayerRig playerRig in _playerRigs.Values)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
playerRig.UpdatePlayerTransforms(deltaTime);
|
||||||
|
playerRig.UpdateIK(deltaTime);
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
SyncLogger.Error("Error updating player rig for " + playerRig._ownerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void LocalSyncTick()
|
||||||
|
{
|
||||||
|
if (Time.realtimeSinceStartup - _lastLocalSyncTime > 1 / RIG_SYNC_FPS)
|
||||||
|
{
|
||||||
|
SendLocalPlayerSync();
|
||||||
|
_lastLocalSyncTime = Time.realtimeSinceStartup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetFingerCurl(Handedness handedness, SimpleFingerCurl fingerCurl)
|
||||||
|
{
|
||||||
|
characterAnimationManager.ApplyFingerCurl(handedness, 1f - fingerCurl.thumb, 1f - fingerCurl.index, 1f - fingerCurl.middle, 1f - fingerCurl.ring, 1f - fingerCurl.pinky);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3 _targetRootPos = Vector3.zero;
|
||||||
|
|
||||||
|
private Vector3 _targetHeadPos = Vector3.zero;
|
||||||
|
private Quaternion _targetHeadRot = Quaternion.identity;
|
||||||
|
|
||||||
|
private Vector3 _targetLeftHandPos = Vector3.zero;
|
||||||
|
private Quaternion _targetLeftHandRot = Quaternion.identity;
|
||||||
|
|
||||||
|
private Vector3 _targetRightHandPos = Vector3.zero;
|
||||||
|
private Quaternion _targetRightHandRot = Quaternion.identity;
|
||||||
|
|
||||||
|
private void UpdatePlayerTransforms(float deltaTime)
|
||||||
|
{
|
||||||
|
float step = deltaTime * 5f; // smoothing factor
|
||||||
|
|
||||||
|
playerRig.transform.position = Vector3.Lerp(playerRig.transform.position, _targetRootPos, step);
|
||||||
|
|
||||||
|
headTransform.position = Vector3.Lerp(headTransform.position, _targetHeadPos, step);
|
||||||
|
leftHandTransform.position = Vector3.Lerp(leftHandTransform.position, _targetLeftHandPos, step);
|
||||||
|
rightHandTransform.position = Vector3.Lerp(rightHandTransform.position, _targetRightHandPos, step);
|
||||||
|
|
||||||
|
|
||||||
|
headTransform.rotation = Quaternion.Lerp(headTransform.rotation, _targetHeadRot, step);
|
||||||
|
leftHandTransform.rotation = Quaternion.Lerp(leftHandTransform.rotation, _targetLeftHandRot, step);
|
||||||
|
rightHandTransform.rotation = Quaternion.Lerp(rightHandTransform.rotation, _targetRightHandRot, step);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void UpdatePlayerSync(PlayerSyncInfo playerSyncInfo)
|
public void UpdatePlayerSync(PlayerSyncInfo playerSyncInfo)
|
||||||
{
|
{
|
||||||
//playerRig.transform.ApplySimpleTransform(playerSyncInfo.headPos);
|
EnsurePlayerRig();
|
||||||
|
//SyncLogger.Msg("Updating player sync for " + _ownerId);
|
||||||
|
//playerRig.transform.position = playerSyncInfo.rootPos;
|
||||||
|
_targetRootPos = playerSyncInfo.rootPos;
|
||||||
|
|
||||||
|
_targetHeadRot = playerSyncInfo.headPos.rotation;
|
||||||
|
_targetHeadPos = playerSyncInfo.headPos.position;
|
||||||
|
|
||||||
|
_targetLeftHandPos = playerSyncInfo.leftHandPos.position;
|
||||||
|
_targetLeftHandRot = playerSyncInfo.leftHandPos.rotation;
|
||||||
|
|
||||||
|
_targetRightHandPos = playerSyncInfo.rightHandPos.position;
|
||||||
|
_targetRightHandRot = playerSyncInfo.rightHandPos.rotation;
|
||||||
|
|
||||||
|
//headTransform.ApplySimpleTransform(playerSyncInfo.headPos);
|
||||||
|
//leftHandTransform.ApplySimpleTransform(playerSyncInfo.leftHandPos);
|
||||||
|
//rightHandTransform.ApplySimpleTransform(playerSyncInfo.rightHandPos);
|
||||||
|
|
||||||
|
SetFingerCurl(Handedness.LEFT, playerSyncInfo.leftHandFingerCurl);
|
||||||
|
SetFingerCurl(Handedness.RIGHT, playerSyncInfo.rightHandFingerCurl);
|
||||||
|
|
||||||
|
UpdatePose(Handedness.LEFT, playerSyncInfo.poseIndexLeft);
|
||||||
|
UpdatePose(Handedness.RIGHT, playerSyncInfo.poseIndexRight);
|
||||||
|
|
||||||
|
UpdatePoseRadius(Handedness.LEFT, playerSyncInfo.poseRadiusLeft);
|
||||||
|
UpdatePoseRadius(Handedness.RIGHT, playerSyncInfo.poseRadiusRight);
|
||||||
|
|
||||||
|
UpdatePlayerTransforms( 1f / RIG_SYNC_FPS); // immediately update transforms to avoid lag
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerRig()
|
public void UpdatePose(Handedness hand, int index)
|
||||||
{
|
{
|
||||||
|
|
||||||
_playerRigs.Add(this);
|
Il2CppStringArray handPoses = PlayerScripts.playerHandPoses;
|
||||||
|
if (handPoses == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("PlayerScripts.playerHandPoses is null, getting hand poses...");
|
||||||
|
PlayerScripts.GetHandPoses();
|
||||||
|
handPoses = PlayerScripts.playerHandPoses;
|
||||||
|
}
|
||||||
|
if (handPoses.Count < index + 1)
|
||||||
|
return;
|
||||||
|
UpdatePose(hand, handPoses[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdatePose(Handedness hand, string pose) => characterAnimationManager?.SetHandPose(hand, pose);
|
||||||
|
|
||||||
|
public void UpdatePoseRadius(Handedness hand, float radius) => characterAnimationManager?.SetCylinderRadius(hand, radius);
|
||||||
|
|
||||||
|
|
||||||
|
public static GameObject localPlayerRig;
|
||||||
|
public static Transform localRigSkeletonRoot;
|
||||||
|
public static Transform localRigWorldRoot;
|
||||||
|
|
||||||
|
private static Transform localRigHeadTransform;
|
||||||
|
private static Transform localRigLeftHandTransform;
|
||||||
|
private static Transform localRigRightHandTransform;
|
||||||
|
public static void SetLocalRigReferences()
|
||||||
|
{
|
||||||
|
if (localPlayerRig != null) return;
|
||||||
|
localPlayerRig = GameObject.Find("[RigManager (Default Brett)]/[SkeletonRig (GameWorld Brett)]");
|
||||||
|
localRigSkeletonRoot = localPlayerRig.transform;
|
||||||
|
localRigWorldRoot = localRigSkeletonRoot.root;
|
||||||
|
|
||||||
|
localRigHeadTransform = localRigSkeletonRoot.Find("Head");
|
||||||
|
localRigLeftHandTransform = localRigSkeletonRoot.Find("Hand (left)");
|
||||||
|
localRigRightHandTransform = localRigSkeletonRoot.Find("Hand (right)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PlayerSyncInfo? GetLocalSyncInfo()
|
||||||
|
{
|
||||||
|
SetLocalRigReferences();
|
||||||
|
|
||||||
|
if (localPlayerRig == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Local player rig not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (localRigHeadTransform == null || localRigLeftHandTransform == null || localRigRightHandTransform == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Local player rig components not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerSyncInfo playerSyncInfo = new PlayerSyncInfo()
|
||||||
|
{
|
||||||
|
rootPos = localRigSkeletonRoot.position,
|
||||||
|
headPos = new SimpleSyncTransform(localRigHeadTransform, false),
|
||||||
|
leftHandPos = new SimpleSyncTransform(localRigLeftHandTransform, false),
|
||||||
|
rightHandPos = new SimpleSyncTransform(localRigRightHandTransform, false),
|
||||||
|
//leftHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerLeftHand.fingerCurl),
|
||||||
|
//rightHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerRightHand.fingerCurl)
|
||||||
|
poseIndexLeft = SkeletonHandPatches.poseIndexLeft,
|
||||||
|
poseIndexRight = SkeletonHandPatches.poseIndexRight,
|
||||||
|
poseRadiusLeft = SkeletonHandPatches.radiusLeft,
|
||||||
|
poseRadiusRight = SkeletonHandPatches.radiusRight
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if (PlayerScripts.playerLeftHand)
|
||||||
|
playerSyncInfo.leftHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerLeftHand.fingerCurl);
|
||||||
|
if (PlayerScripts.playerRightHand)
|
||||||
|
playerSyncInfo.rightHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerRightHand.fingerCurl);
|
||||||
|
|
||||||
|
return playerSyncInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SendLocalPlayerSync()
|
||||||
|
{
|
||||||
|
if (!BoneSync.IsConnected) return;
|
||||||
|
//SyncLogger.Msg("Sending local player sync");
|
||||||
|
PlayerSyncInfo? playerSyncInfo = GetLocalSyncInfo();
|
||||||
|
if (!playerSyncInfo.HasValue) return;
|
||||||
|
PlayerSyncMessage playerSyncMessage = new PlayerSyncMessage(playerSyncInfo.Value);
|
||||||
|
playerSyncMessage.Broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PlayerRig GetPlayerRig(ulong ownerId)
|
||||||
|
{
|
||||||
|
if (_playerRigs.ContainsKey(ownerId))
|
||||||
|
{
|
||||||
|
//SyncLogger.Msg("PlayerRig already exists for " + ownerId);
|
||||||
|
return _playerRigs[ownerId];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rigBundle == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("playerRepBundle is null! Did you forget to load the bundle?");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//PlayerScripts.GetPlayerScripts();
|
||||||
|
|
||||||
|
PlayerRig rig = new PlayerRig(ownerId);
|
||||||
|
return rig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DestroyRig(ulong ownerId)
|
||||||
|
{
|
||||||
|
if (_playerRigs.ContainsKey(ownerId))
|
||||||
|
{
|
||||||
|
_playerRigs[ownerId].Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsurePlayerRig() {
|
||||||
|
if (playerRig != null) return;
|
||||||
|
|
||||||
|
playerRig = GameObject.Instantiate(rigBundle.LoadAsset<GameObject>("PlayerRep"));
|
||||||
|
playerRig.name = "PlayerRep";
|
||||||
|
|
||||||
|
body = playerRig.GetComponentInChildren<SLZ_Body>();
|
||||||
|
characterAnimationManager = playerRig.GetComponentInChildren<CharacterAnimationManager>();
|
||||||
|
animator = playerRig.GetComponentInChildren<Animator>();
|
||||||
|
|
||||||
|
headTransform = playerRig.transform.Find("Head");
|
||||||
|
leftHandTransform = playerRig.transform.Find("Hand (left)");
|
||||||
|
rightHandTransform = playerRig.transform.Find("Hand (right)");
|
||||||
|
|
||||||
|
body.OnStart();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateIK(float deltaTime)
|
||||||
|
{
|
||||||
|
// Catch errors so other players arent broken
|
||||||
|
|
||||||
|
if (body == null || characterAnimationManager == null || animator == null || playerRig == null) return;
|
||||||
|
|
||||||
|
animator.Update(deltaTime);
|
||||||
|
characterAnimationManager.OnLateUpdate();
|
||||||
|
Vector3 repInputVel = Vector3.zero;
|
||||||
|
|
||||||
|
body.FullBodyUpdate(repInputVel, Vector3.zero);
|
||||||
|
body.ArtToBlender.UpdateBlender();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private PlayerRig(ulong id)
|
||||||
|
{
|
||||||
|
_playerRigs.Add(id, this);
|
||||||
|
_ownerId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnPlayerSync(PlayerSyncMessage playerSyncMessage)
|
||||||
|
{
|
||||||
|
//SyncLogger.Msg("Player Sync Received " + playerSyncMessage.senderId);
|
||||||
|
PlayerRig playerRig = GetPlayerRig(playerSyncMessage.senderId);
|
||||||
|
if (playerRig == null) return;
|
||||||
|
playerRig.UpdatePlayerSync(playerSyncMessage.playerSyncInfo);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void Destroy()
|
public void Destroy()
|
||||||
{
|
{
|
||||||
_playerRigs.Remove(this);
|
_playerRigs.Remove(_ownerId);
|
||||||
GameObject.Destroy(playerRig);
|
GameObject.Destroy(playerRig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,249 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
using MelonLoader;
|
|
||||||
using StressLevelZero.Interaction;
|
|
||||||
using StressLevelZero.Pool;
|
|
||||||
using UnityEngine.Experimental.PlayerLoop;
|
|
||||||
using BoneSync.Networking.Messages;
|
|
||||||
using BoneSync.Networking;
|
|
||||||
using StressLevelZero.Data;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
|
|
||||||
namespace BoneSync.Sync.Components
|
|
||||||
{
|
|
||||||
|
|
||||||
public static class TransformExtensions
|
|
||||||
{
|
|
||||||
public static string GetPath(this Transform current)
|
|
||||||
{
|
|
||||||
if (current.parent == null)
|
|
||||||
return "/" + current.name;
|
|
||||||
return current.parent.GetPath() + "/" + current.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Transform FromPath(string path)
|
|
||||||
{
|
|
||||||
Transform current = null;
|
|
||||||
foreach (string name in path.Split('/'))
|
|
||||||
{
|
|
||||||
if (current == null)
|
|
||||||
{
|
|
||||||
current = GameObject.Find(name).transform;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
current = current.Find(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[RegisterTypeInIl2Cpp]
|
|
||||||
public class Syncable : MonoBehaviour
|
|
||||||
{
|
|
||||||
public const int SYNC_FPS = 20;
|
|
||||||
|
|
||||||
public static List<Syncable> syncablesCache = new List<Syncable>();
|
|
||||||
public Syncable(IntPtr intPtr) : base(intPtr) {
|
|
||||||
syncablesCache.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool _syncCoroutineRunning;
|
|
||||||
|
|
||||||
public ulong _ownerId
|
|
||||||
{
|
|
||||||
private set;
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
private ushort _syncId;
|
|
||||||
private ulong _lastSyncTime;
|
|
||||||
|
|
||||||
private bool _attemptedRegister;
|
|
||||||
|
|
||||||
public bool Registered => _syncId != 0;
|
|
||||||
public bool isStale => Time.time - _lastSyncTime > 5f;
|
|
||||||
public bool isOwner => _ownerId == BoneSync.lobby.GetLocalId();
|
|
||||||
|
|
||||||
public ushort GetSyncId() => _syncId;
|
|
||||||
public void SetSyncId(ushort id)
|
|
||||||
{
|
|
||||||
|
|
||||||
_syncId = id;
|
|
||||||
ObjectSyncCache.UpdateSyncId(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InteractableHost interactableHost;
|
|
||||||
public InteractableHostManager interactableManager;
|
|
||||||
public Poolee poolee;
|
|
||||||
|
|
||||||
private Rigidbody[] rigidbodies;
|
|
||||||
private Transform[] transforms;
|
|
||||||
|
|
||||||
private void SetKinematic(bool kinematic)
|
|
||||||
{
|
|
||||||
foreach (Rigidbody rb in rigidbodies)
|
|
||||||
{
|
|
||||||
rb.isKinematic = kinematic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObjectSyncTransform[] GetObjectSyncTransforms()
|
|
||||||
{
|
|
||||||
ObjectSyncTransform[] objectSyncTransforms = new ObjectSyncTransform[transforms.Length];
|
|
||||||
for (int i = 0; i < transforms.Length; i++)
|
|
||||||
{
|
|
||||||
objectSyncTransforms[i] = new ObjectSyncTransform()
|
|
||||||
{
|
|
||||||
transform = new SimpleTransform(transforms[i]),
|
|
||||||
velocity = Vector3.zero
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return objectSyncTransforms;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ApplyObjectSyncTransforms(ObjectSyncTransform[] objectSyncTransforms)
|
|
||||||
{
|
|
||||||
if (objectSyncTransforms.Length != transforms.Length)
|
|
||||||
{
|
|
||||||
MelonLogger.Warning("ObjectSyncTransforms length mismatch: " + objectSyncTransforms.Length + " != " + transforms.Length);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < objectSyncTransforms.Length; i++)
|
|
||||||
{
|
|
||||||
ObjectSyncTransform objectSyncTransform = objectSyncTransforms[i];
|
|
||||||
transforms[i].ApplySimpleTransform(objectSyncTransform.transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SyncCoroutineAsync()
|
|
||||||
{
|
|
||||||
MelonLogger.Msg("Running sync coroutine for: " + gameObject.name);
|
|
||||||
if (_syncCoroutineRunning) return;
|
|
||||||
_syncCoroutineRunning = true;
|
|
||||||
while (isOwner)
|
|
||||||
{
|
|
||||||
MelonLogger.Msg("Sending object sync message for: " + gameObject.name);
|
|
||||||
ObjectSync.SendObjectSyncMessage(this);
|
|
||||||
await Task.Delay( GetSyncId() == 0 ? 1000 : 1000 / SYNC_FPS);
|
|
||||||
}
|
|
||||||
_syncCoroutineRunning = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnEnable()
|
|
||||||
{
|
|
||||||
FindComponents();
|
|
||||||
MelonLogger.Msg("Syncable enabled: " + transform.GetPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateTransformList()
|
|
||||||
{
|
|
||||||
if (interactableManager)
|
|
||||||
{
|
|
||||||
transforms = interactableManager.hosts.Select(host => host.transform).ToArray();
|
|
||||||
}
|
|
||||||
else if (interactableHost)
|
|
||||||
{
|
|
||||||
transforms = new Transform[] { interactableHost.transform };
|
|
||||||
}
|
|
||||||
else if (poolee)
|
|
||||||
{
|
|
||||||
transforms = new Transform[] { poolee.transform };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetSyncableWorldPath()
|
|
||||||
{
|
|
||||||
if (poolee && poolee.pool)
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
if (interactableHost || interactableManager)
|
|
||||||
{
|
|
||||||
return transform.GetPath();
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FindComponents()
|
|
||||||
{
|
|
||||||
ObjectSyncCache.RemoveSyncable(this);
|
|
||||||
|
|
||||||
interactableManager = GetComponent<InteractableHostManager>();
|
|
||||||
interactableHost = GetComponent<InteractableHost>();
|
|
||||||
poolee = GetComponent<Poolee>();
|
|
||||||
rigidbodies = GetComponentsInChildren<Rigidbody>();
|
|
||||||
UpdateTransformList();
|
|
||||||
|
|
||||||
ObjectSyncCache.AddSyncable(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShouldSync()
|
|
||||||
{
|
|
||||||
FindComponents();
|
|
||||||
if (interactableManager && interactableManager.hosts.Count > 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (interactableHost && interactableHost.hasRigidbody)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DiscardSyncable()
|
|
||||||
{
|
|
||||||
ObjectSyncCache.RemoveSyncable(this);
|
|
||||||
Destroy(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnDisable()
|
|
||||||
{
|
|
||||||
if (!Registered)
|
|
||||||
{
|
|
||||||
DiscardSyncable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MelonLogger.Warning("Registered Syncable disabled: " + transform.GetPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetOwner(ulong ownerId)
|
|
||||||
{
|
|
||||||
_ownerId = ownerId;
|
|
||||||
MelonLogger.Msg("Set owner for " + gameObject.name + " to " + ownerId);
|
|
||||||
_ = SyncCoroutineAsync();
|
|
||||||
UpdateKinematic();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateKinematic()
|
|
||||||
{
|
|
||||||
SetKinematic(_ownerId != BoneSync.lobby.GetLocalId() && Registered);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void _SendRegisterSync()
|
|
||||||
{
|
|
||||||
MelonLogger.Msg("Registering syncable object: " + gameObject.name);
|
|
||||||
SetOwner(BoneSync.lobby.GetLocalId());
|
|
||||||
SetSyncId(ObjectSync.SendRegisterSyncableMessage(this));
|
|
||||||
}
|
|
||||||
public void RegisterSyncable()
|
|
||||||
{
|
|
||||||
if (!BoneSync.lobby.IsConnected()) return;
|
|
||||||
if (_attemptedRegister) return;
|
|
||||||
if (Registered) return;
|
|
||||||
if (!ShouldSync()) return;
|
|
||||||
_attemptedRegister = true;
|
|
||||||
_SendRegisterSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
63
BoneSync/Sync/Components/SyncableAI.cs
Normal file
63
BoneSync/Sync/Components/SyncableAI.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Sync.Components
|
||||||
|
{
|
||||||
|
public partial class Syncable : MonoBehaviour
|
||||||
|
{
|
||||||
|
private AISyncInfo _aiSyncInfo;
|
||||||
|
private float _lastAISyncTime;
|
||||||
|
private const float AI_SYNC_FPS = 5f;
|
||||||
|
|
||||||
|
private void TrySendAISync()
|
||||||
|
{
|
||||||
|
if (!aiBrain) return;
|
||||||
|
if (Time.realtimeSinceStartup - _lastAISyncTime > 1 / AI_SYNC_FPS)
|
||||||
|
{
|
||||||
|
_SendAIStateSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void _SendAIStateSync()
|
||||||
|
{
|
||||||
|
if (!aiBrain) return;
|
||||||
|
_lastAISyncTime = Time.realtimeSinceStartup;
|
||||||
|
AISyncInfo aiSyncInfo = new AISyncInfo(_syncId, aiBrain);
|
||||||
|
AISyncMessage message = new AISyncMessage(aiSyncInfo);
|
||||||
|
message.Broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _ApplyAISyncInfo(AISyncInfo aiSyncInfo)
|
||||||
|
{
|
||||||
|
if (!aiBrain) return;
|
||||||
|
aiBrain.behaviour.health.cur_hp = aiSyncInfo.health.cur_hp;
|
||||||
|
aiBrain.behaviour.health.cur_arm_lf = aiSyncInfo.health.cur_arm_lf;
|
||||||
|
aiBrain.behaviour.health.cur_arm_rt = aiSyncInfo.health.cur_arm_rt;
|
||||||
|
aiBrain.behaviour.health.cur_leg_lf = aiSyncInfo.health.cur_leg_lf;
|
||||||
|
aiBrain.behaviour.health.cur_leg_rt = aiSyncInfo.health.cur_leg_rt;
|
||||||
|
|
||||||
|
if (aiSyncInfo.health.cur_hp <= 0 && !aiBrain.puppetMaster.isDead)
|
||||||
|
{
|
||||||
|
aiBrain.puppetMaster.Kill();
|
||||||
|
}
|
||||||
|
else if (aiSyncInfo.health.cur_hp > 0 && aiBrain.puppetMaster.isDead)
|
||||||
|
{
|
||||||
|
aiBrain.puppetMaster.Resurrect();
|
||||||
|
}
|
||||||
|
|
||||||
|
aiBrain.puppetMaster.activeState = aiSyncInfo.puppetState;
|
||||||
|
aiBrain.puppetMaster.activeMode = aiSyncInfo.puppetMode;
|
||||||
|
aiBrain.behaviour.mentalState = aiSyncInfo.mentalState;
|
||||||
|
}
|
||||||
|
public void OnAISyncData(AISyncInfo aiSyncInfo)
|
||||||
|
{
|
||||||
|
_aiSyncInfo = aiSyncInfo;
|
||||||
|
_ApplyAISyncInfo(_aiSyncInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
408
BoneSync/Sync/Components/SyncableBase.cs
Normal file
408
BoneSync/Sync/Components/SyncableBase.cs
Normal file
@@ -0,0 +1,408 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
using StressLevelZero.Pool;
|
||||||
|
using UnityEngine.Experimental.PlayerLoop;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Networking;
|
||||||
|
using StressLevelZero.Data;
|
||||||
|
using System.Collections;
|
||||||
|
using StressLevelZero.Props;
|
||||||
|
using BoneSync.Patching;
|
||||||
|
using StressLevelZero.Props.Weapons;
|
||||||
|
using StressLevelZero.AI;
|
||||||
|
using PuppetMasta;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
using BoneSync.Data;
|
||||||
|
using StressLevelZero.Environment;
|
||||||
|
|
||||||
|
|
||||||
|
namespace BoneSync.Sync.Components
|
||||||
|
{
|
||||||
|
|
||||||
|
public static class TransformExtensions
|
||||||
|
{
|
||||||
|
public static string GetPath(this Transform current)
|
||||||
|
{
|
||||||
|
if (current.parent == null)
|
||||||
|
return "/" + current.name;
|
||||||
|
return current.parent.GetPath() + "/" + current.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Transform TransformFromPath(string path)
|
||||||
|
{
|
||||||
|
if (path.StartsWith("/"))
|
||||||
|
{
|
||||||
|
path = path.Substring(1);
|
||||||
|
}
|
||||||
|
string[] pathParts = path.Split('/');
|
||||||
|
Transform current = null;
|
||||||
|
foreach (string part in pathParts)
|
||||||
|
{
|
||||||
|
if (current == null)
|
||||||
|
{
|
||||||
|
current = GameObject.Find(part).transform;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current = current.Find(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[RegisterTypeInIl2Cpp]
|
||||||
|
public partial class Syncable : MonoBehaviour
|
||||||
|
{
|
||||||
|
public const int OBJECT_SYNC_FPS = 20;
|
||||||
|
|
||||||
|
public static Dictionary<int, Syncable> syncablesCache = new Dictionary<int, Syncable>();
|
||||||
|
public Syncable(IntPtr intPtr) : base(intPtr) {
|
||||||
|
syncablesCache[gameObject.GetHashCode()] = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _syncCoroutineRunning;
|
||||||
|
private bool _ownerCoroutineRunning;
|
||||||
|
|
||||||
|
public ulong _ownerId
|
||||||
|
{
|
||||||
|
private set;
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
private ushort _syncId;
|
||||||
|
private float _lastObjectSyncTime;
|
||||||
|
|
||||||
|
private bool _isInHolster;
|
||||||
|
private bool _attemptedRegister;
|
||||||
|
|
||||||
|
public bool Registered => _syncId != 0;
|
||||||
|
public bool isStale => Time.realtimeSinceStartup - _lastObjectSyncTime > 30f;
|
||||||
|
public bool isOwner => _ownerId == BoneSync.lobby.GetLocalId();
|
||||||
|
|
||||||
|
public bool isValid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_isInvalidCached) return false;
|
||||||
|
bool valid = _GetIsValid();
|
||||||
|
if (valid) return true;
|
||||||
|
_isInvalidCached = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private bool _isInvalidCached = false;
|
||||||
|
|
||||||
|
private bool _GetIsValid()
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (this == null) return false;
|
||||||
|
if (gameObject == null) return false;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetInHolster(bool val)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg(transform.GetPath() + " hosterState:" + val);
|
||||||
|
_isInHolster = val;
|
||||||
|
FindAndUpdateComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsHolding()
|
||||||
|
{
|
||||||
|
if (interactableManager)
|
||||||
|
{
|
||||||
|
return interactableManager.grabbedHosts.Count > 0;
|
||||||
|
}
|
||||||
|
if (interactableHost)
|
||||||
|
{
|
||||||
|
return interactableHost.isAttached;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InteractableHost interactableHost { private set; get; }
|
||||||
|
public InteractableHostManager interactableManager { private set; get; }
|
||||||
|
public Poolee poolee { private set; get; }
|
||||||
|
|
||||||
|
private Prop_Health propHealth;
|
||||||
|
private ObjectDestructable objectDestructable;
|
||||||
|
|
||||||
|
private Rigidbody[] rigidbodies;
|
||||||
|
private Transform[] _transforms;
|
||||||
|
|
||||||
|
private Gun gun;
|
||||||
|
private Magazine magazine;
|
||||||
|
|
||||||
|
private AlignPlug[] plugs;
|
||||||
|
private Socket[] sockets;
|
||||||
|
|
||||||
|
private AIBrain aiBrain;
|
||||||
|
|
||||||
|
private PullDevice pullDevice;
|
||||||
|
private ButtonToggle[] buttonToggles;
|
||||||
|
|
||||||
|
private SpawnFragment spawnFragment;
|
||||||
|
private SpawnFragmentArray spawnFragmentArray;
|
||||||
|
|
||||||
|
private Powerable powerable;
|
||||||
|
private Cart physicsCart;
|
||||||
|
|
||||||
|
private void CheckAutoSync()
|
||||||
|
{
|
||||||
|
if (!isValid) return;
|
||||||
|
FindAndUpdateComponents();
|
||||||
|
if (ShouldAutoSync())
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("AutoSyncing: " + transform.GetPath());
|
||||||
|
RegisterSyncable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private IEnumerator _OnEnableCo()
|
||||||
|
{
|
||||||
|
// wait for a couple frames to make sure all components are initialized, I hate this but it works
|
||||||
|
yield return null;
|
||||||
|
yield return null;
|
||||||
|
yield return null;
|
||||||
|
CheckAutoSync();
|
||||||
|
yield return new WaitForSeconds(SceneSync.MAP_LOAD_GRACE_PERIOD);
|
||||||
|
CheckAutoSync(); // check again after grace period
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEnable()
|
||||||
|
{
|
||||||
|
syncablesCache[gameObject.GetHashCode()] = this;
|
||||||
|
|
||||||
|
FindAndUpdateComponents();
|
||||||
|
|
||||||
|
MelonCoroutines.Start(_OnEnableCo());
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldAutoSync()
|
||||||
|
{
|
||||||
|
if (SceneSync.TimeSinceLastSceneChange < SceneSync.MAP_LOAD_GRACE_PERIOD) return false; // don't sync if scene just changed, to prevent some weird stuff that happens when a level is loaded
|
||||||
|
if (!BoneSync.lobby.IsHost && !ClientSpawningAllowed()) return false;
|
||||||
|
if (InPoolManagerTransform()) return false;
|
||||||
|
if (!gameObject.activeInHierarchy) return false;
|
||||||
|
if (poolee && poolee.pool) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (buttonToggles.Length > 0 && rigidbodies.Length == 0) return true;
|
||||||
|
if (physicsCart != null) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetSyncableWorldPath()
|
||||||
|
{
|
||||||
|
if (!isValid) return "";
|
||||||
|
if (transform == null) return "";
|
||||||
|
if (poolee && poolee.pool)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (interactableHost || interactableManager)
|
||||||
|
{
|
||||||
|
return transform.GetPath();
|
||||||
|
}
|
||||||
|
if (rigidbodies?.Length == 0 && buttonToggles?.Length > 0)
|
||||||
|
{
|
||||||
|
return transform.GetPath();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void FindAndUpdateComponents()
|
||||||
|
{
|
||||||
|
if (!isValid) return;
|
||||||
|
ObjectSyncCache.RemoveSyncable(this);
|
||||||
|
|
||||||
|
pullDevice = GetComponent<PullDevice>();
|
||||||
|
interactableManager = GetComponent<InteractableHostManager>();
|
||||||
|
interactableHost = GetComponent<InteractableHost>();
|
||||||
|
poolee = GetComponent<Poolee>();
|
||||||
|
propHealth = GetComponent<Prop_Health>();
|
||||||
|
objectDestructable = GetComponent<ObjectDestructable>();
|
||||||
|
gun = GetComponent<Gun>();
|
||||||
|
magazine = GetComponent<Magazine>();
|
||||||
|
sockets = GetComponentsInChildren<Socket>();
|
||||||
|
aiBrain = GetComponent<AIBrain>();
|
||||||
|
buttonToggles = GetComponentsInChildren<ButtonToggle>();
|
||||||
|
physicsCart = GetComponent<Cart>();
|
||||||
|
if (sockets.Length == 0)
|
||||||
|
{
|
||||||
|
plugs = GetComponentsInChildren<AlignPlug>();
|
||||||
|
} else {
|
||||||
|
plugs = new AlignPlug[0]; // don't use plugs if sockets are present
|
||||||
|
}
|
||||||
|
|
||||||
|
spawnFragment = GetComponent<SpawnFragment>();
|
||||||
|
spawnFragmentArray = GetComponent<SpawnFragmentArray>();
|
||||||
|
|
||||||
|
UpdateTransformList();
|
||||||
|
TryPatchUnityEvents();
|
||||||
|
|
||||||
|
ObjectSyncCache.AddSyncable(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetSyncStatus()
|
||||||
|
{
|
||||||
|
_ownerId = 0;
|
||||||
|
_syncId = 0;
|
||||||
|
_attemptedRegister = false;
|
||||||
|
SetKinematic(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool InPoolManagerTransform()
|
||||||
|
{
|
||||||
|
return (transform.root.name == "Pool Manager");
|
||||||
|
}
|
||||||
|
public bool CanBeSynced()
|
||||||
|
{
|
||||||
|
FindAndUpdateComponents();
|
||||||
|
if (spawnFragment) return false; // if has spawn fragment, don't sync
|
||||||
|
if (spawnFragmentArray) return false; // if has spawn fragment array, don't sync
|
||||||
|
if (rigidbodies?.Length > 0) return true;
|
||||||
|
if (ShouldAutoSync()) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator DespawnSyncable()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
gameObject?.SetActive(false);
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPlugged()
|
||||||
|
{
|
||||||
|
if (plugs.Length == 0) return false;
|
||||||
|
for (int i = 0; i < plugs.Length; i++)
|
||||||
|
{
|
||||||
|
AlignPlug alignPlug = plugs[i];
|
||||||
|
if (alignPlug.GetSocket()) return true;
|
||||||
|
if (alignPlug._isExitTransition || alignPlug._isEnterTransition) return true; // if plug is in transition, consider it plugged
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _DiscardSyncable(bool force, bool despawn)
|
||||||
|
{
|
||||||
|
if (!isValid) return; // if object is destroyed, don't do anything
|
||||||
|
bool isRegistered = Registered;
|
||||||
|
|
||||||
|
//SyncLogger.Debug("Discarding syncable: " + transform.GetPath() + " force:" + force + " registered:" + isRegistered + " despawn:" + despawn + " isPlugged:" + IsPlugged());
|
||||||
|
|
||||||
|
if (isRegistered)
|
||||||
|
{
|
||||||
|
bool isPlugged = IsPlugged();
|
||||||
|
|
||||||
|
bool canDiscard = isOwner && (!isPlugged || force); // only owner can discard
|
||||||
|
SyncLogger.Debug("Discarding syncable: " + transform.GetPath() + " force:" + force + " registered:" + isRegistered + " despawn:" + despawn + " isPlugged:" + isPlugged + " canDiscard:" + canDiscard);
|
||||||
|
//SyncLogger.Warning("Discarding registered syncable: " + transform.GetPath() + " force: " + force);
|
||||||
|
|
||||||
|
if (canDiscard)
|
||||||
|
{
|
||||||
|
_SendDiscard(true); // owner sends discard message
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canDiscard && !force) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SyncLogger.Msg("Discarding syncable: " + transform.GetPath() + " force:" + force + " registered:" + isRegistered + " despawn:" + despawn + " isPlugged:" + IsPlugged());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
EjectAllPlugs(true);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
SyncLogger.Warning("Failed to eject plugs (should be fine)");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (gameObject) syncablesCache.Remove(gameObject.GetHashCode());
|
||||||
|
|
||||||
|
ObjectSyncCache.RemoveSyncable(this);
|
||||||
|
|
||||||
|
ResetSyncStatus();
|
||||||
|
|
||||||
|
Destroy(this); // delete the component
|
||||||
|
|
||||||
|
if (despawn) MelonCoroutines.Start(DespawnSyncable());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDestroy()
|
||||||
|
{
|
||||||
|
if (Registered)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("Destroying registered syncable: " + transform.GetPath());
|
||||||
|
}
|
||||||
|
DiscardSyncableImmediate(true, Registered);
|
||||||
|
//SyncLogger.Msg("Syncable destroyed: " + transform.GetPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator _FlagForDiscardCo(bool force, bool despawn) {
|
||||||
|
yield return null;
|
||||||
|
yield return null;
|
||||||
|
_DiscardSyncable(force, despawn);
|
||||||
|
} // delay discard to prevent silly behavior
|
||||||
|
|
||||||
|
public void DiscardSyncable(bool force = false, bool despawn = false)
|
||||||
|
{
|
||||||
|
if (Registered && isOwner)
|
||||||
|
{
|
||||||
|
DiscardSyncableImmediate(force, despawn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MelonCoroutines.Start(_FlagForDiscardCo(force, despawn));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DiscardSyncableImmediate(bool force = false, bool despawn = false)
|
||||||
|
{
|
||||||
|
_DiscardSyncable(force, despawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDisable()
|
||||||
|
{
|
||||||
|
if (Registered && !isOwner)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("tried to disable non-owner syncable: " + transform.GetPath());
|
||||||
|
gameObject.SetActive(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DiscardSyncable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterSyncable()
|
||||||
|
{
|
||||||
|
if (!BoneSync.IsConnected) return;
|
||||||
|
FindAndUpdateComponents();
|
||||||
|
if (Registered)
|
||||||
|
{
|
||||||
|
TryBecomeOwner();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_attemptedRegister) return;
|
||||||
|
if (!CanBeSynced()) return;
|
||||||
|
_attemptedRegister = true;
|
||||||
|
_SendRegisterSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
BoneSync/Sync/Components/SyncableDamage.cs
Normal file
87
BoneSync/Sync/Components/SyncableDamage.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Patching;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Data;
|
||||||
|
using StressLevelZero.Props;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Sync.Components
|
||||||
|
{
|
||||||
|
public partial class Syncable : MonoBehaviour
|
||||||
|
{
|
||||||
|
//private LootTableData originalLootTableData = null;
|
||||||
|
private Dictionary<int, LootTableData> originalLootTableData = new Dictionary<int, LootTableData>();
|
||||||
|
|
||||||
|
private void _UpdateLootTable(ObjectDestructable destructable)
|
||||||
|
{
|
||||||
|
if (!destructable) return;
|
||||||
|
if (!originalLootTableData.ContainsKey(destructable.GetHashCode()))
|
||||||
|
{
|
||||||
|
originalLootTableData[destructable.GetHashCode()] = destructable.lootTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BoneSync.IsConnected || BoneSync.lobby.IsHost)
|
||||||
|
{
|
||||||
|
if (originalLootTableData[destructable.GetHashCode()] != null)
|
||||||
|
{
|
||||||
|
destructable.lootTable = originalLootTableData[destructable.GetHashCode()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
destructable.lootTable = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private void SetHealth(float health, int hits = 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (gameObject.activeSelf == false && health > 0)
|
||||||
|
{
|
||||||
|
gameObject.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propHealth)
|
||||||
|
{
|
||||||
|
propHealth.cur_Health = health;
|
||||||
|
propHealth.hits = hits;
|
||||||
|
}
|
||||||
|
if (objectDestructable)
|
||||||
|
{
|
||||||
|
_UpdateLootTable(objectDestructable);
|
||||||
|
objectDestructable._health = health;
|
||||||
|
objectDestructable._hits = hits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Damage(ObjectDamageInfo damageInfo)
|
||||||
|
{
|
||||||
|
ObjectHealthInfo healthInfo = damageInfo.objectHealthInfo;
|
||||||
|
SetHealth(healthInfo._health, healthInfo._hits); // always set health first
|
||||||
|
|
||||||
|
ObjectDamageType eventType = damageInfo.eventType;
|
||||||
|
if (eventType == ObjectDamageType.SyncHealth) return;
|
||||||
|
|
||||||
|
if (eventType == ObjectDamageType.DestructibleTakeDamage && objectDestructable)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("NetworkDestructableTakeDamage: " + healthInfo.damage);
|
||||||
|
CallPatchedMethods.TakeDamage(objectDestructable, healthInfo.normal, healthInfo.damage, healthInfo.crit, healthInfo.attackType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventType == ObjectDamageType.PropHealthTakeDamage && propHealth)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("NetworkPropHealthTakeDamage: " + healthInfo.damage);
|
||||||
|
CallPatchedMethods.TakeDamage(propHealth, healthInfo.damage, healthInfo.crit, healthInfo.attackType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
227
BoneSync/Sync/Components/SyncableNetworking.cs
Normal file
227
BoneSync/Sync/Components/SyncableNetworking.cs
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Patching;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Zones;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Sync.Components
|
||||||
|
{
|
||||||
|
// SyncableNetworking.cs
|
||||||
|
public partial class Syncable : MonoBehaviour
|
||||||
|
{
|
||||||
|
private float _syncInterval = 0f;
|
||||||
|
private Queue<byte[]> _simpleEventQueue = new Queue<byte[]>();
|
||||||
|
private void SendObjectSync()
|
||||||
|
{
|
||||||
|
_lastObjectSyncTime = Time.realtimeSinceStartup;
|
||||||
|
ObjectSync.SendObjectSyncMessage(this);
|
||||||
|
}
|
||||||
|
private IEnumerator OwnerCoroutineAsync()
|
||||||
|
{
|
||||||
|
if (_ownerCoroutineRunning) yield break;
|
||||||
|
SyncLogger.Msg("Running owner coroutine for: " + _syncId);
|
||||||
|
_ownerCoroutineRunning = true;
|
||||||
|
while (isOwner)
|
||||||
|
{
|
||||||
|
if (!_syncCoroutineRunning)
|
||||||
|
{
|
||||||
|
RunSyncLoop(); // start sync loop if it's not running
|
||||||
|
}
|
||||||
|
yield return new WaitForSeconds(_syncInterval * 10f); // 10x sync interval
|
||||||
|
}
|
||||||
|
_ownerCoroutineRunning = false;
|
||||||
|
SyncLogger.Msg("Owner coroutine ended for: " + _syncId);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
public IEnumerator SyncCoroutineAsync()
|
||||||
|
{
|
||||||
|
if (_syncCoroutineRunning) yield break;
|
||||||
|
if (!ShouldSendSync()) yield break;
|
||||||
|
SyncLogger.Msg("Starting sync coroutine for: " + transform.GetPath());
|
||||||
|
_syncCoroutineRunning = true;
|
||||||
|
_syncInterval = 1 / OBJECT_SYNC_FPS; // micro optimization to avoid division every frame, propably makes no difference
|
||||||
|
while (ShouldSendSync())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SendObjectSync();
|
||||||
|
TrySendPlugSync();
|
||||||
|
TrySendAISync();
|
||||||
|
TrySendAttributeSync();
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
MelonLogger.Error("Error in sync coroutine", e);
|
||||||
|
}
|
||||||
|
yield return new WaitForSeconds(_syncInterval);
|
||||||
|
}
|
||||||
|
SyncLogger.Msg("Ending sync coroutine for: " + transform.GetPath());
|
||||||
|
_syncCoroutineRunning = false;
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
private void RunSyncLoop()
|
||||||
|
{
|
||||||
|
MelonCoroutines.Start(SyncCoroutineAsync());
|
||||||
|
}
|
||||||
|
public void SetOwner(ulong ownerId)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Setting owner for " + _syncId + " to " + ownerId);
|
||||||
|
_ownerId = ownerId;
|
||||||
|
//FindAndUpdateComponents();
|
||||||
|
UpdateKinematic();
|
||||||
|
RunSyncLoop();
|
||||||
|
TryCatchUpSimpleEvents();
|
||||||
|
MelonCoroutines.Start(OwnerCoroutineAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ClientSpawningAllowed()
|
||||||
|
{
|
||||||
|
if (poolee && poolee.pool)
|
||||||
|
{
|
||||||
|
return PoolBlacklist.IsClientSpawnPool(poolee.pool);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator __SendRegisterSyncCo()
|
||||||
|
{
|
||||||
|
yield return null; // wait a frame
|
||||||
|
SetSyncId(ObjectSync.SendRegisterSyncableMessage(this));
|
||||||
|
SetOwner(BoneSync.lobby.GetLocalId());
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _SendRegisterSync()
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Registering syncable object: " + gameObject.name);
|
||||||
|
MelonCoroutines.Start(__SendRegisterSyncCo());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _SendDiscard(bool despawn = false)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Sending discard for " + _syncId + " despawn: " + despawn);
|
||||||
|
DiscardSyncableMessageData discardSyncableMessageData = new DiscardSyncableMessageData()
|
||||||
|
{
|
||||||
|
syncId = _syncId,
|
||||||
|
despawn = despawn
|
||||||
|
};
|
||||||
|
DiscardSyncableMessage discardSyncableMessage = new DiscardSyncableMessage(discardSyncableMessageData);
|
||||||
|
discardSyncableMessage.Broadcast();
|
||||||
|
}
|
||||||
|
public void OnOwnershipTransferRequest(ulong newOwnerId)
|
||||||
|
{
|
||||||
|
//SyncLogger.Msg("Ownership transfer request for " + _syncId + " to " + newOwnerId);
|
||||||
|
if (isOwner && !IsHolding() && !_isInHolster)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Sending ownership transfer for " + _syncId + " to " + newOwnerId);
|
||||||
|
OwnershipTransferMessageData data = new OwnershipTransferMessageData()
|
||||||
|
{
|
||||||
|
syncId = _syncId,
|
||||||
|
NewOwnerId = newOwnerId,
|
||||||
|
force = true
|
||||||
|
};
|
||||||
|
OwnershipTransferMessage message = new OwnershipTransferMessage(data);
|
||||||
|
message.Broadcast();
|
||||||
|
SetOwner(newOwnerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TryBecomeOwner(bool force = false)
|
||||||
|
{
|
||||||
|
if (Registered && !isOwner)
|
||||||
|
{
|
||||||
|
ulong localId = BoneSync.lobby.GetLocalId();
|
||||||
|
SyncLogger.Msg("Attempting to become owner of " + _syncId + " force: " + force);
|
||||||
|
OwnershipTransferMessageData data = new OwnershipTransferMessageData()
|
||||||
|
{
|
||||||
|
syncId = _syncId,
|
||||||
|
NewOwnerId = localId,
|
||||||
|
force = force
|
||||||
|
};
|
||||||
|
OwnershipTransferMessage message = new OwnershipTransferMessage(data);
|
||||||
|
message.Broadcast();
|
||||||
|
if (force)
|
||||||
|
{
|
||||||
|
SetOwner(localId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunSyncLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldSendSync()
|
||||||
|
{
|
||||||
|
if (!Registered) return false;
|
||||||
|
if (!isOwner) return false;
|
||||||
|
if (isStale) return true;
|
||||||
|
if (_isInHolster) return true;
|
||||||
|
if (AllRigidbodiesSleeping()) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AddSimpleEventToQueue(SimpleEventType eType, byte index = 0, byte len = 0, byte[] extraData = null)
|
||||||
|
{
|
||||||
|
RegisterSyncable();
|
||||||
|
if (!isOwner && Registered) { return false; }
|
||||||
|
_simpleEventQueue.Enqueue(new byte[] { (byte)eType, index, len }.Concat(extraData ?? new byte[0]).ToArray());
|
||||||
|
TryCatchUpSimpleEvents();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryCatchUpSimpleEvents()
|
||||||
|
{
|
||||||
|
if (Registered && !isOwner)
|
||||||
|
{
|
||||||
|
_simpleEventQueue.Clear();
|
||||||
|
SyncLogger.Debug("Clearing simple event queue for " + _syncId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_simpleEventQueue.Count > 0 && Registered && isOwner)
|
||||||
|
{
|
||||||
|
byte[] eventData = _simpleEventQueue.Dequeue();
|
||||||
|
_SendSimpleEvent((SimpleEventType)eventData[0], eventData[1], eventData[2], eventData.Skip(3).ToArray());
|
||||||
|
TryCatchUpSimpleEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void _SendSimpleEvent(SimpleEventType eType, byte index = 0, byte len = 0, byte[] extraData = null)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Sending simple event: " + eType);
|
||||||
|
SimpleSyncableEvent data = new SimpleSyncableEvent()
|
||||||
|
{
|
||||||
|
syncId = _syncId,
|
||||||
|
eventType = eType,
|
||||||
|
index = index,
|
||||||
|
length = len,
|
||||||
|
extraData = extraData
|
||||||
|
};
|
||||||
|
|
||||||
|
SimpleSyncableEventMessage simpleSyncEvent = new SimpleSyncableEventMessage(data);
|
||||||
|
simpleSyncEvent.Broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DestroyZoneTrackers()
|
||||||
|
{
|
||||||
|
/*ZoneTracker[] zoneTrackers = GetComponentsInChildren<ZoneTracker>(true);
|
||||||
|
foreach (ZoneTracker zoneTracker in zoneTrackers)
|
||||||
|
{
|
||||||
|
Destroy(zoneTracker);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort GetSyncId() => _syncId;
|
||||||
|
public void SetSyncId(ushort id)
|
||||||
|
{
|
||||||
|
_syncId = id;
|
||||||
|
ObjectSyncCache.UpdateSyncId(this);
|
||||||
|
if (id != 0)
|
||||||
|
{
|
||||||
|
DestroyZoneTrackers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
308
BoneSync/Sync/Components/SyncablePhysics.cs
Normal file
308
BoneSync/Sync/Components/SyncablePhysics.cs
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Patching;
|
||||||
|
using Facepunch.Steamworks;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
namespace BoneSync.Sync.Components
|
||||||
|
{
|
||||||
|
public partial class Syncable : MonoBehaviour
|
||||||
|
{
|
||||||
|
private HashSet<int> patchedButtonToggles = new HashSet<int>();
|
||||||
|
private bool pullDevicePatched = false;
|
||||||
|
|
||||||
|
bool OnButtonEvent(ButtonToggle toggle, SimpleEventType eventType)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("ButtonToggle:" + eventType + " " + toggle.transform.GetPath());
|
||||||
|
byte index = (byte)Array.IndexOf(buttonToggles, toggle);
|
||||||
|
bool isPressed = toggle._isPressed;
|
||||||
|
bool hasBeenPressed = toggle._hasBeenPressed;
|
||||||
|
byte[] buttonState = BitPacking.PackBits(new bool[] { isPressed, hasBeenPressed });
|
||||||
|
return AddSimpleEventToQueue(eventType, index, (byte)buttonToggles.Length, buttonState);
|
||||||
|
}
|
||||||
|
bool ButtonOnPress(ButtonToggle toggle)
|
||||||
|
{
|
||||||
|
return OnButtonEvent(toggle, SimpleEventType.OnButtonPress);
|
||||||
|
}
|
||||||
|
bool ButtonOnRelease(ButtonToggle toggle)
|
||||||
|
{
|
||||||
|
return OnButtonEvent(toggle, SimpleEventType.OnButtonRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ButtonOnOneShot(ButtonToggle toggle)
|
||||||
|
{
|
||||||
|
return OnButtonEvent(toggle, SimpleEventType.OnButtonOneShot);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceOnPull(PullDevice device)
|
||||||
|
{
|
||||||
|
return AddSimpleEventToQueue(SimpleEventType.OnDevicePull);
|
||||||
|
}
|
||||||
|
bool DeviceOnRelease(PullDevice device)
|
||||||
|
{
|
||||||
|
return AddSimpleEventToQueue(SimpleEventType.OnDeviceRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryPatchUnityEvents()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_TryPatchPullDevice();
|
||||||
|
foreach (ButtonToggle buttonToggle in GetComponentsInChildren<ButtonToggle>())
|
||||||
|
{
|
||||||
|
_TryPatchButtonToggle(buttonToggle);
|
||||||
|
}
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
SyncLogger.Error("Failed to patch UnityEvents: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _TryPatchPullDevice()
|
||||||
|
{
|
||||||
|
if (pullDevicePatched) return;
|
||||||
|
if (!pullDevice) return;
|
||||||
|
//pullDevice.OnHandlePull.AddListener((UnityAction)DeviceOnPull);
|
||||||
|
//pullDevice.OnHandleReturn.AddListener((UnityAction)DeviceOnRelease);
|
||||||
|
|
||||||
|
pullDevice.OnHandlePull =UnityEventPatch<PullDevice>.Patch(pullDevice, pullDevice.OnHandlePull, DeviceOnPull).GetPatchedEvent();
|
||||||
|
pullDevice.OnHandleReturn = UnityEventPatch<PullDevice>.Patch(pullDevice, pullDevice.OnHandleReturn, DeviceOnRelease).GetPatchedEvent();
|
||||||
|
|
||||||
|
pullDevicePatched = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _TryPatchButtonToggle(ButtonToggle buttonToggle)
|
||||||
|
{
|
||||||
|
if (patchedButtonToggles.Contains(buttonToggle.GetHashCode())) return;
|
||||||
|
SyncLogger.Msg("Patching ButtonToggle: " + buttonToggle.transform.GetPath());
|
||||||
|
//buttonToggle.onPress.AddListenerWithArgs<ButtonToggle>((btn, args) => ButtonOnPress(btn), buttonToggle);
|
||||||
|
//buttonToggle.onDepress.AddListenerWithArgs<ButtonToggle>((btn, args) => ButtonOnRelease(btn), buttonToggle);
|
||||||
|
buttonToggle.onPress = UnityEventPatch<ButtonToggle>.Patch(buttonToggle, buttonToggle.onPress, ButtonOnPress).GetPatchedEvent();
|
||||||
|
buttonToggle.onDepress = UnityEventPatch<ButtonToggle>.Patch(buttonToggle, buttonToggle.onDepress, ButtonOnRelease).GetPatchedEvent();
|
||||||
|
buttonToggle.onPressOneShot = UnityEventPatch<ButtonToggle>.Patch(buttonToggle, buttonToggle.onPressOneShot, ButtonOnOneShot).GetPatchedEvent();
|
||||||
|
|
||||||
|
patchedButtonToggles.Add(buttonToggle.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AllRigidbodiesSleeping()
|
||||||
|
{
|
||||||
|
if (rigidbodies.Length == 0) return false;
|
||||||
|
foreach (Rigidbody rb in rigidbodies)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!rb.IsSleeping()) return false;
|
||||||
|
}
|
||||||
|
catch { } // ignore null rigidbodies
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _SetKinematic(bool kinematic)
|
||||||
|
{
|
||||||
|
if (rigidbodies.Length == 0) return;
|
||||||
|
foreach (Rigidbody rb in rigidbodies)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
rb.isKinematic = kinematic;
|
||||||
|
}
|
||||||
|
catch { } // ignore null rigidbodies
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void SetKinematic(bool kinematic)
|
||||||
|
{
|
||||||
|
if (!isValid) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_SetKinematic(kinematic);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
SyncLogger.Warning("Failed to set kinematic");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectSyncTransform[] GetObjectSyncTransforms()
|
||||||
|
{
|
||||||
|
ObjectSyncTransform[] objectSyncTransforms = new ObjectSyncTransform[rigidbodies.Length];
|
||||||
|
for (int i = 0; i < _transforms.Length; i++)
|
||||||
|
{
|
||||||
|
objectSyncTransforms[i] = new ObjectSyncTransform()
|
||||||
|
{
|
||||||
|
transform = new SimpleSyncTransform(_transforms[i]),
|
||||||
|
velocity = rigidbodies[i].velocity,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return objectSyncTransforms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyObjectSyncTransforms(ObjectSyncTransform[] objectSyncTransforms)
|
||||||
|
{
|
||||||
|
_lastObjectSyncTime = Time.realtimeSinceStartup;
|
||||||
|
if (IsPlugged()) { return; }
|
||||||
|
if (objectSyncTransforms.Length != rigidbodies.Length)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("ObjectSyncTransforms length mismatch: " + objectSyncTransforms.Length + " != " + _transforms.Length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < objectSyncTransforms.Length; i++)
|
||||||
|
{
|
||||||
|
ObjectSyncTransform objectSyncTransform = objectSyncTransforms[i];
|
||||||
|
Rigidbody rb = rigidbodies[i];
|
||||||
|
rb.angularVelocity = objectSyncTransform.angularVelocity;
|
||||||
|
rb.velocity = objectSyncTransform.velocity;
|
||||||
|
|
||||||
|
//rb.MovePosition(objectSyncTransform.transform.position);
|
||||||
|
//rb.MoveRotation(objectSyncTransform.transform.rotation);
|
||||||
|
rb.position = objectSyncTransform.transform.position;
|
||||||
|
rb.rotation = objectSyncTransform.transform.rotation;
|
||||||
|
if (objectSyncTransform.transform.scale.HasValue)
|
||||||
|
{
|
||||||
|
_transforms[i].localScale = objectSyncTransform.transform.scale.Value;
|
||||||
|
}
|
||||||
|
//_transforms[i].ApplySimpleTransform(objectSyncTransform.transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Syncable GetRigidbodySyncable(Rigidbody rigidbody)
|
||||||
|
{
|
||||||
|
if (rigidbody == null) return null;
|
||||||
|
return rigidbody.GetComponentInParent<Syncable>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool RigidbodyBelongsToSyncable(Rigidbody rigidbody)
|
||||||
|
{
|
||||||
|
return GetRigidbodySyncable(rigidbody) == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rigidbody[] GetRigidbodies()
|
||||||
|
{
|
||||||
|
if (interactableManager)
|
||||||
|
{
|
||||||
|
return interactableManager.hosts.Select(host => host.rb).ToArray();
|
||||||
|
}
|
||||||
|
if (interactableHost)
|
||||||
|
{
|
||||||
|
return new Rigidbody[] { interactableHost.rb };
|
||||||
|
}
|
||||||
|
if (poolee)
|
||||||
|
{
|
||||||
|
return poolee.GetComponentsInChildren<Rigidbody>(true);
|
||||||
|
}
|
||||||
|
if (physicsCart)
|
||||||
|
{
|
||||||
|
return new Rigidbody[] { physicsCart.rb };
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Rigidbody[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTransformList()
|
||||||
|
{
|
||||||
|
// get non-null rigidbodies
|
||||||
|
Rigidbody[] rbs = GetRigidbodies().Where(rb => rb != null).ToArray();
|
||||||
|
rigidbodies = rbs;
|
||||||
|
_transforms = rbs.Select(rb => rb.transform).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateKinematic()
|
||||||
|
{
|
||||||
|
//SetKinematic(false);
|
||||||
|
SetKinematic(_ownerId != BoneSync.lobby.GetLocalId() && Registered && !IsPlugged());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void OnSimpleSyncableEvent(SimpleSyncableEvent eventData)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("OnSimpleSyncableEvent: " + eventData.eventType);
|
||||||
|
SimpleEventType eType = eventData.eventType;
|
||||||
|
byte index = eventData.index;
|
||||||
|
byte len = eventData.length;
|
||||||
|
switch (eType) {
|
||||||
|
case SimpleEventType.OnDevicePull:
|
||||||
|
pullDevice?.OnHandlePull?.BypassPatchInvoke();
|
||||||
|
break;
|
||||||
|
case SimpleEventType.OnDeviceRelease:
|
||||||
|
pullDevice?.OnHandleReturn?.BypassPatchInvoke();
|
||||||
|
break;
|
||||||
|
case SimpleEventType.OnButtonPress:
|
||||||
|
if (len != eventData.length) { SyncLogger.Warning("ButtonPress length mismatch: " + len + " != " + eventData.length); }
|
||||||
|
if (index < buttonToggles.Length)
|
||||||
|
{
|
||||||
|
ButtonToggle toggle = buttonToggles[index];
|
||||||
|
if (toggle == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("ButtonToggle at index " + index + " is null");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bool[] buttonState = BitPacking.UnpackBits(eventData.extraData, 2);
|
||||||
|
toggle._isPressed = buttonState[0];
|
||||||
|
toggle._hasBeenPressed = buttonState[1];
|
||||||
|
toggle.onPress.BypassPatchInvoke();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SimpleEventType.OnButtonRelease:
|
||||||
|
if (len != eventData.length) { SyncLogger.Warning("ButtonPress length mismatch: " + len + " != " + eventData.length); }
|
||||||
|
if (index < buttonToggles.Length)
|
||||||
|
{
|
||||||
|
ButtonToggle toggle = buttonToggles[index];
|
||||||
|
if (toggle == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("ButtonToggle at index " + index + " is null");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bool[] buttonState = BitPacking.UnpackBits(eventData.extraData, 2);
|
||||||
|
toggle._isPressed = buttonState[0];
|
||||||
|
toggle._hasBeenPressed = buttonState[1];
|
||||||
|
toggle.onDepress.BypassPatchInvoke();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SimpleEventType.OnButtonOneShot:
|
||||||
|
if (len != eventData.length) {
|
||||||
|
SyncLogger.Warning("ButtonPress length mismatch: " + len + " != " + eventData.length);
|
||||||
|
}
|
||||||
|
if (index < buttonToggles.Length)
|
||||||
|
{
|
||||||
|
ButtonToggle toggle = buttonToggles[index];
|
||||||
|
if (toggle == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("ButtonToggle at index " + index + " is null");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bool[] buttonState = BitPacking.UnpackBits(eventData.extraData, 2);
|
||||||
|
toggle._isPressed = buttonState[0];
|
||||||
|
toggle._hasBeenPressed = buttonState[1];
|
||||||
|
toggle.onPressOneShot.BypassPatchInvoke();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SimpleEventType.CartGo:
|
||||||
|
CallPatchedMethods.CartGo(physicsCart);
|
||||||
|
break;
|
||||||
|
case SimpleEventType.CartGoBackwards:
|
||||||
|
CallPatchedMethods.CartGoBackward(physicsCart);
|
||||||
|
break;
|
||||||
|
case SimpleEventType.CartLaunch:
|
||||||
|
CallPatchedMethods.CartLaunch(physicsCart);
|
||||||
|
break;
|
||||||
|
case SimpleEventType.CartGoForward:
|
||||||
|
CallPatchedMethods.CartGoForward(physicsCart);
|
||||||
|
break;
|
||||||
|
case SimpleEventType.CartDrop:
|
||||||
|
//CallPatchedMethods.Drop();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SyncLogger.Warning("Unknown SimpleEventType: " + eType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// on collision
|
||||||
|
}
|
||||||
|
}
|
||||||
158
BoneSync/Sync/Components/SyncablePlugs.cs
Normal file
158
BoneSync/Sync/Components/SyncablePlugs.cs
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
using BoneSync.Patching;
|
||||||
|
using BoneSync.Data;
|
||||||
|
|
||||||
|
namespace BoneSync.Sync.Components
|
||||||
|
{
|
||||||
|
public static class PlugExtensions
|
||||||
|
{
|
||||||
|
public static Socket GetSocket(this AlignPlug plug)
|
||||||
|
{
|
||||||
|
Socket socket = plug._lastSocket;
|
||||||
|
if (!socket) return null;
|
||||||
|
if (socket.LockedPlug == plug) return socket;
|
||||||
|
if (plug._isEnterTransition) return socket;
|
||||||
|
if (plug._isExitTransition) return socket;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool SafeEject(this AlignPlug plug)
|
||||||
|
{
|
||||||
|
if (!plug.GetSocket()) return false;
|
||||||
|
plug.EjectPlug();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ForceEject(this AlignPlug plug)
|
||||||
|
{
|
||||||
|
if (!plug.GetSocket()) return;
|
||||||
|
plug.EjectPlug();
|
||||||
|
plug.ClearFromSocket();
|
||||||
|
plug._isEnterTransition = false;
|
||||||
|
plug._isExitTransition = false;
|
||||||
|
plug._isExitComplete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool SafeInsert(this AlignPlug plug, Socket socket)
|
||||||
|
{
|
||||||
|
if (!socket) return false;
|
||||||
|
Plug lockedPlug = socket.LockedPlug;
|
||||||
|
if (lockedPlug && lockedPlug != plug)
|
||||||
|
{
|
||||||
|
AlignPlug alignPlug = lockedPlug.GetComponent<AlignPlug>();
|
||||||
|
if (alignPlug)
|
||||||
|
{
|
||||||
|
alignPlug.ForceEject();
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plug.GetSocket() != socket)
|
||||||
|
{
|
||||||
|
plug.ForceEject();
|
||||||
|
}
|
||||||
|
plug.InsertPlug(socket);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public partial class Syncable : MonoBehaviour
|
||||||
|
{
|
||||||
|
private float _lastPlugSyncTime;
|
||||||
|
private const float PLUG_SYNC_FPS = 1f;
|
||||||
|
private void TrySendPlugSync()
|
||||||
|
{
|
||||||
|
if (Time.realtimeSinceStartup - _lastPlugSyncTime > (1 / PLUG_SYNC_FPS))
|
||||||
|
{
|
||||||
|
_SendPlugSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _SendPlugSync()
|
||||||
|
{
|
||||||
|
if (!isOwner) return;
|
||||||
|
if (!Registered) return;
|
||||||
|
foreach (AlignPlug plug in plugs)
|
||||||
|
{
|
||||||
|
if (!plug) continue;
|
||||||
|
Socket socket = plug.GetSocket();
|
||||||
|
AlignPlugPatches.OnPlugSocketChange(plug, socket);
|
||||||
|
_lastPlugSyncTime = Time.realtimeSinceStartup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EjectAllPlugs(bool force = false)
|
||||||
|
{
|
||||||
|
if (plugs == null) return;
|
||||||
|
foreach (AlignPlug plug in plugs)
|
||||||
|
{
|
||||||
|
if (plug == null) continue;
|
||||||
|
if (plug.GetSocket())
|
||||||
|
{
|
||||||
|
if (force)
|
||||||
|
{
|
||||||
|
plug.ForceEject();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plug.SafeEject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public AlignPlug GetPlugFromId(byte id)
|
||||||
|
{
|
||||||
|
if (plugs.Length <= id)
|
||||||
|
{
|
||||||
|
SyncLogger.Error("Plug ID out of range");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugs[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Socket GetSocketFromId(byte id)
|
||||||
|
{
|
||||||
|
if (sockets.Length <= id)
|
||||||
|
{
|
||||||
|
SyncLogger.Error("Socket ID out of range");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return sockets[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte GetSocketId(Socket socket)
|
||||||
|
{
|
||||||
|
for (byte i = 0; i < sockets.Length; i++)
|
||||||
|
{
|
||||||
|
if (sockets[i] == socket)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte GetPlugId(AlignPlug plug)
|
||||||
|
{
|
||||||
|
for (byte i = 0; i < plugs.Length; i++)
|
||||||
|
{
|
||||||
|
if (plugs[i] == plug)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
98
BoneSync/Sync/Components/SyncableProperties.cs
Normal file
98
BoneSync/Sync/Components/SyncableProperties.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Patching;
|
||||||
|
using StressLevelZero.Combat;
|
||||||
|
using StressLevelZero.Pool;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Sync.Components
|
||||||
|
{
|
||||||
|
public partial class Syncable : MonoBehaviour
|
||||||
|
{
|
||||||
|
private const float ATTRIBUTE_SYNC_FPS = 0.2f;
|
||||||
|
private float _lastAttributeSyncTime;
|
||||||
|
|
||||||
|
private void StripDamage(ref BulletObject bulletObject)
|
||||||
|
{
|
||||||
|
AmmoVariables ammoVariables = bulletObject.ammoVariables;
|
||||||
|
ammoVariables.AttackDamage = 0f;
|
||||||
|
bulletObject.ammoVariables = ammoVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TrySendAttributeSync()
|
||||||
|
{
|
||||||
|
if (!Registered) return;
|
||||||
|
if (!isOwner) return;
|
||||||
|
if (Time.realtimeSinceStartup - _lastAttributeSyncTime > 1 / ATTRIBUTE_SYNC_FPS)
|
||||||
|
{
|
||||||
|
_SendAttributeSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _SendAttributeSync()
|
||||||
|
{
|
||||||
|
_SendMagazineData();
|
||||||
|
_lastAttributeSyncTime = Time.realtimeSinceStartup;
|
||||||
|
}
|
||||||
|
public void ApplyMagazineData(MagazineSyncData magazineSyncData)
|
||||||
|
{
|
||||||
|
if (!magazine) return; // If the magazine is null, return
|
||||||
|
MagazineData magazineData = magazineSyncData.magazineData;
|
||||||
|
if (!magazineData) return;
|
||||||
|
magazine.magazineData.AmmoSlots = magazineData.AmmoSlots;
|
||||||
|
magazine.magazineData.cartridgeType = magazineData.cartridgeType;
|
||||||
|
magazine.magazineData.weight = magazineData.weight;
|
||||||
|
magazine.magazineData.platform = magazineData.platform;
|
||||||
|
magazine.firstBullet?.SetActive(magazineData.AmmoSlots.Count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MagazineSyncData GetMagazineData()
|
||||||
|
{
|
||||||
|
MagazineSyncData data = new MagazineSyncData();
|
||||||
|
data.syncId = GetSyncId();
|
||||||
|
data.magazineData = magazine.magazineData;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _SendMagazineData()
|
||||||
|
{
|
||||||
|
if (!magazine) return;
|
||||||
|
MagazineSyncData data = GetMagazineData();
|
||||||
|
MagazineSyncMessage message = new MagazineSyncMessage(data);
|
||||||
|
message.Broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnWeaponSyncData(GunSyncInfo gunSyncInfo)
|
||||||
|
{
|
||||||
|
if (!gun) return;
|
||||||
|
|
||||||
|
gun.chamberedCartridge = gunSyncInfo.bulletObject;
|
||||||
|
gun.cartridgeState = gunSyncInfo.cartridgeState;
|
||||||
|
gun.hammerState = gunSyncInfo.hammerState;
|
||||||
|
|
||||||
|
if (gunSyncInfo.messageType == GunSyncMessageType.Fire)
|
||||||
|
{
|
||||||
|
gun.gunSFX?.GunShot();
|
||||||
|
Transform firepointTransform = gun.firePointTransform;
|
||||||
|
Vector3 position = firepointTransform.position;
|
||||||
|
Quaternion rotation = firepointTransform.rotation;
|
||||||
|
BulletObject bulletObject = gunSyncInfo.bulletObject;
|
||||||
|
StripDamage(ref bulletObject);
|
||||||
|
//gun.EjectCartridge();
|
||||||
|
PoolSpawner.SpawnProjectile(position, rotation, gunSyncInfo.bulletObject, "1911", null);
|
||||||
|
PoolSpawner.SpawnMuzzleFlare(position, rotation, PoolSpawner.MuzzleFlareType.Default);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gunSyncInfo.messageType == GunSyncMessageType.EjectCartridge)
|
||||||
|
{
|
||||||
|
gun.EjectCartridge();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
using BoneSync.Networking.Messages;
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Patching;
|
||||||
using BoneSync.Sync.Components;
|
using BoneSync.Sync.Components;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Data;
|
||||||
|
using StressLevelZero.Environment;
|
||||||
using StressLevelZero.Interaction;
|
using StressLevelZero.Interaction;
|
||||||
using StressLevelZero.Pool;
|
using StressLevelZero.Pool;
|
||||||
using System;
|
using System;
|
||||||
@@ -9,138 +14,11 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
namespace BoneSync.Sync
|
namespace BoneSync.Sync
|
||||||
{
|
{
|
||||||
|
|
||||||
public static class ObjectSyncCache
|
|
||||||
{
|
|
||||||
private static Dictionary<string, Syncable> _pathToSyncable = new Dictionary<string, Syncable>();
|
|
||||||
private static Dictionary<ushort, Syncable> _idToSyncable = new Dictionary<ushort, Syncable>();
|
|
||||||
private static Dictionary<Poolee, Syncable> _pooleeToSyncable = new Dictionary<Poolee, Syncable>();
|
|
||||||
private static Dictionary<InteractableHost, Syncable> _interactableHostToSyncable = new Dictionary<InteractableHost, Syncable>();
|
|
||||||
private static Dictionary<InteractableHostManager, Syncable> _interactableHostManagerToSyncable = new Dictionary<InteractableHostManager, Syncable>();
|
|
||||||
|
|
||||||
|
|
||||||
public static void AddSyncable(Syncable syncable)
|
|
||||||
{
|
|
||||||
string path = syncable.transform.GetPath();
|
|
||||||
if (path != null && path != "")
|
|
||||||
{
|
|
||||||
_pathToSyncable[path] = syncable;
|
|
||||||
}
|
|
||||||
if (syncable.GetSyncId() != 0)
|
|
||||||
{
|
|
||||||
_idToSyncable[syncable.GetSyncId()] = syncable;
|
|
||||||
}
|
|
||||||
if (syncable.interactableHost)
|
|
||||||
{
|
|
||||||
_interactableHostToSyncable[syncable.interactableHost] = syncable;
|
|
||||||
}
|
|
||||||
if (syncable.interactableManager)
|
|
||||||
{
|
|
||||||
_interactableHostManagerToSyncable[syncable.interactableManager] = syncable;
|
|
||||||
}
|
|
||||||
if (syncable.poolee)
|
|
||||||
{
|
|
||||||
_pooleeToSyncable[syncable.poolee] = syncable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RemoveSyncable(Syncable syncable)
|
|
||||||
{
|
|
||||||
if (syncable.transform)
|
|
||||||
{
|
|
||||||
_pathToSyncable.Remove(syncable.transform.GetPath());
|
|
||||||
}
|
|
||||||
if (syncable.GetSyncId() != 0)
|
|
||||||
{
|
|
||||||
_idToSyncable.Remove(syncable.GetSyncId());
|
|
||||||
}
|
|
||||||
if (syncable.interactableHost)
|
|
||||||
{
|
|
||||||
_interactableHostToSyncable.Remove(syncable.interactableHost);
|
|
||||||
}
|
|
||||||
if (syncable.interactableManager)
|
|
||||||
{
|
|
||||||
_interactableHostManagerToSyncable.Remove(syncable.interactableManager);
|
|
||||||
}
|
|
||||||
if (syncable.poolee)
|
|
||||||
{
|
|
||||||
_pooleeToSyncable.Remove(syncable.poolee);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void UpdateSyncId(Syncable syncable)
|
|
||||||
{
|
|
||||||
// remove other enties where value is the same
|
|
||||||
foreach (KeyValuePair<ushort, Syncable> entry in _idToSyncable)
|
|
||||||
{
|
|
||||||
if (entry.Value == syncable)
|
|
||||||
{
|
|
||||||
_idToSyncable.Remove(entry.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ushort id = syncable.GetSyncId();
|
|
||||||
if (_idToSyncable.ContainsKey(id))
|
|
||||||
{
|
|
||||||
_idToSyncable.Remove(id);
|
|
||||||
}
|
|
||||||
_idToSyncable[id] = syncable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Syncable GetSyncable(string path)
|
|
||||||
{
|
|
||||||
if (_pathToSyncable.ContainsKey(path))
|
|
||||||
{
|
|
||||||
return _pathToSyncable[path];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Syncable GetSyncable(ushort id)
|
|
||||||
{
|
|
||||||
if (_idToSyncable.ContainsKey(id))
|
|
||||||
{
|
|
||||||
return _idToSyncable[id];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Syncable GetSyncable(Poolee poolee)
|
|
||||||
{
|
|
||||||
if (_pooleeToSyncable.ContainsKey(poolee))
|
|
||||||
{
|
|
||||||
return _pooleeToSyncable[poolee];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Syncable GetSyncable(InteractableHost interactableHost)
|
|
||||||
{
|
|
||||||
if (_interactableHostToSyncable.ContainsKey(interactableHost))
|
|
||||||
{
|
|
||||||
return _interactableHostToSyncable[interactableHost];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Syncable GetSyncable(InteractableHostManager interactableHostManager)
|
|
||||||
{
|
|
||||||
if (_interactableHostManagerToSyncable.ContainsKey(interactableHostManager))
|
|
||||||
{
|
|
||||||
return _interactableHostManagerToSyncable[interactableHostManager];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DISCARD_ALL_SYNCABLES() {
|
|
||||||
foreach (Syncable syncable in Syncable.syncablesCache)
|
|
||||||
{
|
|
||||||
syncable.DiscardSyncable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal class ObjectSync
|
internal class ObjectSync
|
||||||
{
|
{
|
||||||
private static ushort _nextSyncableId = 1;
|
private static ushort _nextSyncableId = 1;
|
||||||
@@ -149,8 +27,10 @@ namespace BoneSync.Sync
|
|||||||
return _nextSyncableId++;
|
return _nextSyncableId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegisterSyncableInfo? GetRegisterInfo(Syncable syncable)
|
|
||||||
|
public static RegisterSyncableInfo? GetRegisterInfo(Syncable syncable, bool allowClientRegister)
|
||||||
{
|
{
|
||||||
|
ulong ownerId = BoneSync.lobby.GetLocalId();
|
||||||
RegisterSyncableInfo? info = null;
|
RegisterSyncableInfo? info = null;
|
||||||
string path = syncable.GetSyncableWorldPath();
|
string path = syncable.GetSyncableWorldPath();
|
||||||
if (path.Length > 0)
|
if (path.Length > 0)
|
||||||
@@ -159,15 +39,26 @@ namespace BoneSync.Sync
|
|||||||
{
|
{
|
||||||
type = RegisterSyncType.RegisterFromPath,
|
type = RegisterSyncType.RegisterFromPath,
|
||||||
transformPath = path,
|
transformPath = path,
|
||||||
ownerId = syncable._ownerId,
|
ownerId = ownerId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (syncable.poolee)
|
else if (syncable.poolee && syncable.poolee.pool && (BoneSync.lobby.IsHost || allowClientRegister))
|
||||||
{
|
{
|
||||||
|
string spawnableRealTitle = syncable?.poolee?.spawnObject?.title;
|
||||||
|
string spawnableAlternateTitle = syncable?.poolee?.pool?.name.Replace("pool - ", ""); // hacky, but use when real title is unknown
|
||||||
|
|
||||||
|
string spawnableTitle = spawnableRealTitle ?? spawnableAlternateTitle;
|
||||||
|
|
||||||
|
SyncLogger.Msg("Spawnable title: " + spawnableTitle);
|
||||||
info = new RegisterSyncableInfo()
|
info = new RegisterSyncableInfo()
|
||||||
{
|
{
|
||||||
|
ownerId = ownerId,
|
||||||
type = RegisterSyncType.RegisterAndSpawn,
|
type = RegisterSyncType.RegisterAndSpawn,
|
||||||
transformPath = syncable.poolee.transform.GetPath(),
|
spawnInfo = new SpawnPoolableInfo()
|
||||||
|
{
|
||||||
|
spawnableTitle = spawnableTitle,
|
||||||
|
spawnLocation = new SimpleSyncTransform(syncable.poolee.transform, false),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
@@ -175,33 +66,39 @@ namespace BoneSync.Sync
|
|||||||
|
|
||||||
public static ushort SendRegisterSyncableMessage(Syncable syncable)
|
public static ushort SendRegisterSyncableMessage(Syncable syncable)
|
||||||
{
|
{
|
||||||
RegisterSyncableInfo? infoNullable = GetRegisterInfo(syncable);
|
SyncLogger.Msg("Sending register syncable message for: " + syncable.transform.name);
|
||||||
|
RegisterSyncableInfo? infoNullable = GetRegisterInfo(syncable, syncable.ClientSpawningAllowed());
|
||||||
|
|
||||||
if (infoNullable == null)
|
if (infoNullable == null)
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("No valid registeration method for syncable");
|
SyncLogger.Warning("No valid registeration method for syncable");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterSyncableInfo info = infoNullable.Value;
|
RegisterSyncableInfo info = infoNullable.Value;
|
||||||
|
|
||||||
RegisterSyncableMessage message = new RegisterSyncableMessage(info);
|
|
||||||
|
|
||||||
if (BoneSync.lobby.IsHost)
|
if (BoneSync.lobby.IsHost)
|
||||||
{
|
{
|
||||||
info.id = GetNextId();
|
info.id = GetNextId();
|
||||||
message.Broadcast();
|
new RegisterSyncableMessage(info).Broadcast();
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
{
|
||||||
info.id = 0;
|
info.callbackId = (ushort)Random.Range(1, ushort.MaxValue);
|
||||||
message.Send(BoneSync.lobby.GetHostId());
|
ObjectSyncCache.CallbackIdToSyncable[info.callbackId] = syncable;
|
||||||
|
new RegisterSyncableMessage(info).SendToHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SyncLogger.Msg("Sending register syncable message for: " + syncable.transform.name + " with id: " + info.id + " and type : " + info.type);
|
||||||
|
|
||||||
return info.id;
|
return info.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SendObjectSyncMessage(Syncable syncable)
|
public static void SendObjectSyncMessage(Syncable syncable)
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("Sending object sync message for: " + syncable.transform.name);
|
if (!syncable.Registered) return;
|
||||||
|
//SyncLogger.Msg("Sending object sync message for: " + syncable.transform.name);
|
||||||
ObjectSyncTransform[] objectSyncTransforms = syncable.GetObjectSyncTransforms();
|
ObjectSyncTransform[] objectSyncTransforms = syncable.GetObjectSyncTransforms();
|
||||||
|
|
||||||
ObjectSyncMessageData data = new ObjectSyncMessageData()
|
ObjectSyncMessageData data = new ObjectSyncMessageData()
|
||||||
@@ -213,61 +110,198 @@ namespace BoneSync.Sync
|
|||||||
ObjectSyncMessage message = new ObjectSyncMessage(data);
|
ObjectSyncMessage message = new ObjectSyncMessage(data);
|
||||||
message.Broadcast();
|
message.Broadcast();
|
||||||
}
|
}
|
||||||
private static Syncable _MakeOrGetSyncable(GameObject gameObject, bool deleteSubSyncabled = true)
|
private static Transform _GetPerferredSyncRootTransform(Transform t)
|
||||||
{
|
{
|
||||||
Syncable[] subSyncables = gameObject.GetComponentsInChildren<Syncable>();
|
if (t == null) return null;
|
||||||
|
Transform parent = t.parent;
|
||||||
|
if (parent == null) return t;
|
||||||
|
|
||||||
|
Cart cart = parent.GetComponentInParent<Cart>();
|
||||||
|
if (cart) return cart.transform;
|
||||||
|
|
||||||
|
InteractableHostManager manager = parent.GetComponentInParent<InteractableHostManager>();
|
||||||
|
if (manager) return manager.transform;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
|
||||||
|
}
|
||||||
|
private static Syncable _MakeOrGetSyncable(GameObject gameObject, bool deleteSubSyncables = true)
|
||||||
|
{
|
||||||
|
//Scene scene = gameObject.scene;
|
||||||
|
//SyncLogger.Msg("Making or getting syncable for: " + gameObject.name);
|
||||||
|
if (gameObject == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Syncable syncable = gameObject.GetComponent<Syncable>();
|
Syncable syncable = gameObject.GetComponent<Syncable>();
|
||||||
|
|
||||||
// delete all sub syncables
|
// delete all sub syncables
|
||||||
|
if (deleteSubSyncables)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Syncable[] subSyncables = gameObject.GetComponentsInChildren<Syncable>(true);
|
||||||
for (int i = 0; i < subSyncables.Length; i++)
|
for (int i = 0; i < subSyncables.Length; i++)
|
||||||
{
|
{
|
||||||
if (subSyncables[i] != syncable)
|
Syncable subSyncable = subSyncables[i];
|
||||||
|
if (subSyncable == syncable) continue;
|
||||||
|
if (subSyncable == null) continue;
|
||||||
|
bool isRegistered = subSyncable.Registered;
|
||||||
|
bool isPlugged = subSyncable.IsPlugged();
|
||||||
|
|
||||||
|
SyncLogger.Msg("Discarding subSyncable: " + subSyncable.transform.GetPath() + " registered:" + isRegistered + " plugged:" + isPlugged);
|
||||||
|
if (isRegistered || isPlugged) continue;
|
||||||
|
subSyncable.DiscardSyncable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
subSyncables[i].DiscardSyncable();
|
SyncLogger.Warning("Failed to delete sub syncables: " + e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (syncable == null)
|
if (syncable == null)
|
||||||
{
|
{
|
||||||
syncable = gameObject.AddComponent<Syncable>();
|
Transform perferredObjectParent = _GetPerferredSyncRootTransform(gameObject.transform);
|
||||||
}
|
Syncable foundComponent = perferredObjectParent.GetComponent<Syncable>();
|
||||||
else
|
if (foundComponent)
|
||||||
{
|
{
|
||||||
syncable.FindComponents();
|
return foundComponent;
|
||||||
|
}
|
||||||
|
syncable = perferredObjectParent.gameObject.AddComponent<Syncable>();
|
||||||
}
|
}
|
||||||
return syncable;
|
return syncable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Syncable _GetSyncableFromCache(GameObject gameObject)
|
||||||
|
{
|
||||||
|
bool success = Syncable.syncablesCache.TryGetValue(gameObject.GetHashCode(), out Syncable syncable);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return syncable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Syncable MakeOrGetSyncable(ButtonToggle buttonToggle)
|
||||||
|
{
|
||||||
|
Syncable parentSyncable = buttonToggle.GetComponentInParent<Syncable>();
|
||||||
|
if (parentSyncable)
|
||||||
|
{
|
||||||
|
return parentSyncable;
|
||||||
|
}
|
||||||
|
return MakeOrGetSyncable(buttonToggle.gameObject);
|
||||||
|
}
|
||||||
|
public static Syncable MakeOrGetSyncable(GameObject gameObject, bool deleteSubSyncables = true)
|
||||||
|
{
|
||||||
|
Syncable syncable = _GetSyncableFromCache(gameObject);
|
||||||
|
if (syncable == null)
|
||||||
|
{
|
||||||
|
syncable = _MakeOrGetSyncable(gameObject, deleteSubSyncables);
|
||||||
|
}
|
||||||
|
return syncable;
|
||||||
|
}
|
||||||
|
public static Syncable MakeOrGetSyncable(Poolee poolee)
|
||||||
|
{
|
||||||
|
return MakeOrGetSyncable(poolee.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
public static Syncable MakeOrGetSyncable(InteractableHost interactableHost)
|
public static Syncable MakeOrGetSyncable(InteractableHost interactableHost)
|
||||||
{
|
{
|
||||||
if (interactableHost.manager) return MakeOrGetSyncable(interactableHost.manager);
|
if (interactableHost.manager) return MakeOrGetSyncable(interactableHost.manager);
|
||||||
return _MakeOrGetSyncable(interactableHost.gameObject);
|
return MakeOrGetSyncable(interactableHost.gameObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Syncable MakeOrGetSyncable(InteractableHostManager interactableHostManager)
|
public static Syncable MakeOrGetSyncable(InteractableHostManager interactableHostManager)
|
||||||
{
|
{
|
||||||
return _MakeOrGetSyncable(interactableHostManager.gameObject);
|
return MakeOrGetSyncable(interactableHostManager.gameObject, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Syncable SpawnPooleeAndMakeSyncable(SpawnPoolableInfo spawnInfo)
|
||||||
|
{
|
||||||
|
|
||||||
|
SimpleSyncTransform spawnLocation = spawnInfo.spawnLocation;
|
||||||
|
|
||||||
|
SpawnableObject spawnableObject = SpawnableManager.GetSpawnable(spawnInfo.spawnableTitle);
|
||||||
|
if (spawnableObject == null) {
|
||||||
|
SyncLogger.Warning("Failed to find spawnable: " + spawnInfo.spawnableTitle);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Pool pool = SpawnableManager.GetPool(spawnableObject);
|
||||||
|
|
||||||
|
if (!pool)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("[SpawnPooleeAndMakeSyncable] Failed to find pool: " + spawnInfo.spawnableTitle);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Poolee poolee = CallPatchedMethods.InstantiatePoolee(pool, spawnLocation.position, spawnLocation.rotation, pool.Prefab.transform.localScale);*/
|
||||||
|
Poolee poolee = SpawnableManager.SpawnPoolee(spawnableObject, spawnLocation.position, spawnLocation.rotation);
|
||||||
|
if (poolee == null) {
|
||||||
|
SyncLogger.Warning("Failed to spawn poolee: " + spawnInfo.spawnableTitle);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Syncable syncable = MakeOrGetSyncable(poolee);
|
||||||
|
SyncLogger.Msg("Spawned poolee with syncable: " + poolee.transform.GetPath());
|
||||||
|
return syncable;
|
||||||
|
}
|
||||||
public static void OnRegisterSyncMessage(RegisterSyncableMessage registerSyncableMessage)
|
public static void OnRegisterSyncMessage(RegisterSyncableMessage registerSyncableMessage)
|
||||||
{
|
{
|
||||||
|
SyncLogger.Msg("Received register sync message");
|
||||||
Syncable syncable = null;
|
Syncable syncable = null;
|
||||||
RegisterSyncableInfo info = registerSyncableMessage.info;
|
RegisterSyncableInfo info = registerSyncableMessage.info;
|
||||||
if (BoneSync.lobby.IsHost)
|
if (BoneSync.lobby.IsHost)
|
||||||
{
|
{
|
||||||
info.id = GetNextId();
|
info.id = GetNextId();
|
||||||
new RegisterSyncableMessage(info).Broadcast();
|
new RegisterSyncableMessage(info).Broadcast();
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// only host can register syncables, all spawn requests should be sent to host
|
||||||
|
if (registerSyncableMessage.senderId != BoneSync.lobby.GetHostId())
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("Received register sync message from non-host: " + registerSyncableMessage.senderId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info.id == 0)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("Received register sync message with id 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasCallback = info.callbackId != 0;
|
||||||
|
if (hasCallback)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Received register sync message with callback id: " + info.callbackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCallback && ObjectSyncCache.CallbackIdToSyncable.ContainsKey(info.callbackId))
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Found syncable for callback id: " + info.callbackId);
|
||||||
|
syncable = ObjectSyncCache.CallbackIdToSyncable[info.callbackId];
|
||||||
|
ObjectSyncCache.CallbackIdToSyncable.Remove(info.callbackId);
|
||||||
|
} else
|
||||||
|
{
|
||||||
switch (info.type)
|
switch (info.type)
|
||||||
{
|
{
|
||||||
case RegisterSyncType.RegisterFromPath:
|
case RegisterSyncType.RegisterFromPath:
|
||||||
MelonLogger.Msg("Registering syncable from path: " + info.transformPath + " with id: " + info.id);
|
SyncLogger.Msg("Registering syncable from path: " + info.transformPath + " with id: " + info.id);
|
||||||
syncable = ObjectSyncCache.GetSyncable(info.transformPath);
|
syncable = ObjectSyncCache.GetSyncable(info.transformPath);
|
||||||
break;
|
break;
|
||||||
case RegisterSyncType.RegisterAndSpawn:
|
case RegisterSyncType.RegisterAndSpawn:
|
||||||
|
SyncLogger.Msg("Registering and spawning syncable from pool: " + info.spawnInfo.Value.spawnableTitle + " with id: " + info.id);
|
||||||
|
syncable = SpawnPooleeAndMakeSyncable(info.spawnInfo.Value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!syncable)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("Failed to create/obtain syncable for register sync message "+ info.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
syncable.SetSyncId(info.id);
|
syncable.SetSyncId(info.id);
|
||||||
syncable.SetOwner(info.ownerId);
|
syncable.SetOwner(info.ownerId);
|
||||||
@@ -276,13 +310,72 @@ namespace BoneSync.Sync
|
|||||||
public static void OnObjectSyncMessage(ObjectSyncMessage objectSyncMessage)
|
public static void OnObjectSyncMessage(ObjectSyncMessage objectSyncMessage)
|
||||||
{
|
{
|
||||||
ObjectSyncMessageData data = objectSyncMessage.objectSyncMessageData;
|
ObjectSyncMessageData data = objectSyncMessage.objectSyncMessageData;
|
||||||
Syncable syncable = ObjectSyncCache.GetSyncable(data.objectId);
|
ushort objectId = data.objectId;
|
||||||
|
|
||||||
|
if (objectId == 0) return;
|
||||||
|
|
||||||
|
if (objectId >= _nextSyncableId && !BoneSync.lobby.IsHost)
|
||||||
|
{
|
||||||
|
_nextSyncableId = (ushort)(objectId + 1);
|
||||||
|
}
|
||||||
|
Syncable syncable = ObjectSyncCache.GetSyncable(objectId);
|
||||||
if (syncable == null)
|
if (syncable == null)
|
||||||
{
|
{
|
||||||
MelonLogger.Msg("Syncable not found for id: " + data.objectId);
|
//SyncLogger.Msg("SyncEvent: Syncable not found for id: " + objectId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
syncable.ApplyObjectSyncTransforms(data.objectSyncTransforms);
|
syncable.ApplyObjectSyncTransforms(data.objectSyncTransforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void OnObjectDamageMessage(ObjectDamageMessage damageMessge)
|
||||||
|
{
|
||||||
|
|
||||||
|
ObjectDamageInfo damageInfo = damageMessge.objectEventInfo;
|
||||||
|
if (damageInfo.objectId == 0) return;
|
||||||
|
Syncable syncable = ObjectSyncCache.GetSyncable(damageInfo.objectId);
|
||||||
|
if (syncable == null)
|
||||||
|
{
|
||||||
|
//SyncLogger.Msg("DamageEvent: Syncable not found for id: " + damageInfo.objectId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
syncable.Damage(damageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendObjectDamageMessage(Syncable syncable, ObjectDamageType damageType, ObjectHealthInfo healthInfo)
|
||||||
|
{
|
||||||
|
ObjectDamageInfo damageInfo = new ObjectDamageInfo()
|
||||||
|
{
|
||||||
|
objectId = syncable.GetSyncId(),
|
||||||
|
objectHealthInfo = healthInfo,
|
||||||
|
eventType = damageType,
|
||||||
|
};
|
||||||
|
ObjectDamageMessage message = new ObjectDamageMessage(damageInfo);
|
||||||
|
message.Broadcast();
|
||||||
|
message.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void OnOwnershipChangeMessage(ushort syncId, ulong newOwnerId, bool force)
|
||||||
|
{
|
||||||
|
Syncable syncable = ObjectSyncCache.GetSyncable(syncId);
|
||||||
|
if (syncable == null)
|
||||||
|
{
|
||||||
|
SyncLogger.Warning("Ownership transfer request for non-existant syncable: " + syncId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (force)
|
||||||
|
{
|
||||||
|
syncable.SetOwner(newOwnerId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
syncable.OnOwnershipTransferRequest(newOwnerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Syncable MakeOrGetSyncable(Cart instance)
|
||||||
|
{
|
||||||
|
Syncable syncable = MakeOrGetSyncable(instance.gameObject);
|
||||||
|
return syncable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
161
BoneSync/Sync/ObjectSyncCache.cs
Normal file
161
BoneSync/Sync/ObjectSyncCache.cs
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
|
using StressLevelZero.Pool;
|
||||||
|
using StressLevelZero.Props.Weapons;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnhollowerBaseLib;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BoneSync.Sync
|
||||||
|
{
|
||||||
|
public static class ObjectSyncCache
|
||||||
|
{
|
||||||
|
private static Dictionary<string, Syncable> _pathToSyncable = new Dictionary<string, Syncable>();
|
||||||
|
private static Dictionary<ushort, Syncable> _idToSyncable = new Dictionary<ushort, Syncable>();
|
||||||
|
|
||||||
|
private static Dictionary<int, Syncable> _componentToSyncable = new Dictionary<int, Syncable>();
|
||||||
|
private static Dictionary<Syncable, Component[]> _syncableToComponent = new Dictionary<Syncable, Component[]>();
|
||||||
|
|
||||||
|
public static Dictionary<ushort, Syncable> CallbackIdToSyncable = new Dictionary<ushort, Syncable>();
|
||||||
|
|
||||||
|
private static string GetComponentNamespace(Component component)
|
||||||
|
{
|
||||||
|
return component.GetType().Namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsCachableComponent(Component component)
|
||||||
|
{
|
||||||
|
if (component is MonoBehaviour) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
//string ns = GetComponentNamespace(component);
|
||||||
|
//return ns.StartsWith("StressLevelZero") || ns.StartsWith("BoneSync");
|
||||||
|
}
|
||||||
|
private static Component[] GetComponentsToCache(Syncable syncable)
|
||||||
|
{
|
||||||
|
Component[] components = syncable.GetComponentsInChildren<Component>(true);
|
||||||
|
List<Component> slzComponents = new List<Component>();
|
||||||
|
for (int i = 0; i < components.Length; i++)
|
||||||
|
{
|
||||||
|
if (IsCachableComponent(components[i]))
|
||||||
|
{
|
||||||
|
slzComponents.Add(components[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slzComponents.ToArray();
|
||||||
|
}
|
||||||
|
private static void _AddSyncableComponents(Syncable syncable)
|
||||||
|
{
|
||||||
|
Component[] components = GetComponentsToCache(syncable);
|
||||||
|
_syncableToComponent[syncable] = components;
|
||||||
|
foreach (Component component in components)
|
||||||
|
{
|
||||||
|
_componentToSyncable[component.GetHashCode()] = syncable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void _RemoveSyncableComponents(Syncable syncable)
|
||||||
|
{
|
||||||
|
if (_syncableToComponent.ContainsKey(syncable))
|
||||||
|
{
|
||||||
|
Component[] components = _syncableToComponent[syncable];
|
||||||
|
foreach (Component component in components)
|
||||||
|
{
|
||||||
|
_componentToSyncable.Remove(component.GetHashCode());
|
||||||
|
}
|
||||||
|
_syncableToComponent.Remove(syncable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void _AddSyncableKeys(Syncable syncable)
|
||||||
|
{
|
||||||
|
string path = syncable.GetSyncableWorldPath();
|
||||||
|
if (path != null && path != "")
|
||||||
|
{
|
||||||
|
_pathToSyncable[path] = syncable;
|
||||||
|
}
|
||||||
|
if (syncable.GetSyncId() != 0)
|
||||||
|
{
|
||||||
|
_idToSyncable[syncable.GetSyncId()] = syncable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void _RemoveSyncableKeys(Syncable syncable)
|
||||||
|
{
|
||||||
|
string path = syncable.GetSyncableWorldPath();
|
||||||
|
if (path != null && path != "")
|
||||||
|
{
|
||||||
|
_pathToSyncable.Remove(path);
|
||||||
|
}
|
||||||
|
if (syncable.GetSyncId() != 0)
|
||||||
|
{
|
||||||
|
_idToSyncable.Remove(syncable.GetSyncId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void AddSyncable(Syncable syncable)
|
||||||
|
{
|
||||||
|
_AddSyncableKeys(syncable);
|
||||||
|
_AddSyncableComponents(syncable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RemoveSyncable(Syncable syncable)
|
||||||
|
{
|
||||||
|
_RemoveSyncableKeys(syncable);
|
||||||
|
_RemoveSyncableComponents(syncable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateSyncId(Syncable syncable)
|
||||||
|
{
|
||||||
|
// remove other enties where value is the same
|
||||||
|
ushort id = syncable.GetSyncId();
|
||||||
|
if (_idToSyncable.ContainsKey(id))
|
||||||
|
{
|
||||||
|
_idToSyncable.Remove(id);
|
||||||
|
}
|
||||||
|
_idToSyncable[id] = syncable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Syncable GetSyncable(string path)
|
||||||
|
{
|
||||||
|
if (_pathToSyncable.ContainsKey(path))
|
||||||
|
{
|
||||||
|
return _pathToSyncable[path];
|
||||||
|
}
|
||||||
|
Transform transform = TransformExtensions.TransformFromPath(path);
|
||||||
|
if (transform)
|
||||||
|
{
|
||||||
|
return transform.GetComponent<Syncable>();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Syncable GetSyncable(ushort id)
|
||||||
|
{
|
||||||
|
if (_idToSyncable.ContainsKey(id))
|
||||||
|
{
|
||||||
|
return _idToSyncable[id];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Syncable GetSyncable(Component component)
|
||||||
|
{
|
||||||
|
if (_componentToSyncable.ContainsKey(component.GetHashCode()))
|
||||||
|
{
|
||||||
|
return _componentToSyncable[component.GetHashCode()];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DISCARD_ALL_SYNCABLES()
|
||||||
|
{
|
||||||
|
foreach (Syncable syncable in Syncable.syncablesCache.Values)
|
||||||
|
{
|
||||||
|
syncable.DiscardSyncableImmediate(true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using BoneSync.Networking;
|
|
||||||
using BoneSync.Networking.Messages;
|
|
||||||
using BoneSync.Player;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace BoneSync.Sync
|
|
||||||
{
|
|
||||||
internal static class PlayerSync
|
|
||||||
{
|
|
||||||
|
|
||||||
private static GameObject _localPlayerRig;
|
|
||||||
|
|
||||||
private static Dictionary<ulong, PlayerRig> _playerRigMap = new Dictionary<ulong, PlayerRig>();
|
|
||||||
private static PlayerRig GetPlayerRig(ulong playerId)
|
|
||||||
{
|
|
||||||
if (!_playerRigMap.ContainsKey(playerId))
|
|
||||||
{
|
|
||||||
PlayerRig playerRig = new PlayerRig();
|
|
||||||
_playerRigMap.Add(playerId, playerRig);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _playerRigMap[playerId];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CleanUp()
|
|
||||||
{
|
|
||||||
foreach (PlayerRig playerRig in _playerRigMap.Values)
|
|
||||||
{
|
|
||||||
playerRig.Destroy();
|
|
||||||
}
|
|
||||||
_playerRigMap.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SyncPlayer()
|
|
||||||
{
|
|
||||||
PlayerSyncInfo playerSyncInfo = new PlayerSyncInfo();
|
|
||||||
playerSyncInfo.headPos = new SimpleTransform();
|
|
||||||
playerSyncInfo.leftHandPos = new SimpleTransform();
|
|
||||||
playerSyncInfo.rightHandPos = new SimpleTransform();
|
|
||||||
|
|
||||||
PlayerSyncMessage playerSyncMessage = new PlayerSyncMessage(playerSyncInfo);
|
|
||||||
playerSyncMessage.Broadcast();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void OnPlayerSync(PlayerSyncMessage playerSyncMessage)
|
|
||||||
{
|
|
||||||
PlayerRig playerRig = GetPlayerRig(playerSyncMessage.senderId);
|
|
||||||
playerRig.UpdatePlayerSync(playerSyncMessage.playerSyncInfo);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,28 @@
|
|||||||
using MelonLoader;
|
using BoneSync.Data;
|
||||||
|
using BoneSync.Networking.Messages;
|
||||||
|
using BoneSync.Sync.Components;
|
||||||
|
using MelonLoader;
|
||||||
|
using StressLevelZero.Interaction;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
|
|
||||||
namespace BoneSync.Sync
|
namespace BoneSync.Sync
|
||||||
{
|
{
|
||||||
internal class SceneSync
|
internal class SceneSync
|
||||||
{
|
{
|
||||||
|
public const float MAP_LOAD_GRACE_PERIOD = 5f; // allow x seconds for the game to load the scene before doing anything that requires the scene to be fully initialized
|
||||||
|
|
||||||
private static List<Scene> scenes = new List<Scene>();
|
private static List<Scene> scenes = new List<Scene>();
|
||||||
private static string _currentSceneName;
|
private static string _currentSceneName;
|
||||||
|
private static int _currentSceneIndex;
|
||||||
|
private static float _lastSceneChangeTime;
|
||||||
|
public static float TimeSinceLastSceneChange => Time.realtimeSinceStartup - _lastSceneChangeTime;
|
||||||
|
public static int CurrentSceneIndex => _currentSceneIndex;
|
||||||
|
|
||||||
public static string CurrentSceneDisplayName
|
public static string CurrentSceneDisplayName
|
||||||
{
|
{
|
||||||
@@ -28,11 +39,44 @@ namespace BoneSync.Sync
|
|||||||
return sceneName;
|
return sceneName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void RenameDuplicateSceneTransforms(Scene scene)
|
||||||
|
{
|
||||||
|
Dictionary<string, ushort> seenTransformNames = new Dictionary<string, ushort>();
|
||||||
|
uint total = 0;
|
||||||
|
foreach (GameObject go in scene.GetRootGameObjects())
|
||||||
|
{
|
||||||
|
foreach (InteractableHost host in go.GetComponentsInChildren<InteractableHost>(true))
|
||||||
|
{
|
||||||
|
Transform t = host.transform;
|
||||||
|
string path = t.GetPath();
|
||||||
|
if (seenTransformNames.ContainsKey(path))
|
||||||
|
{
|
||||||
|
seenTransformNames[path]++;
|
||||||
|
t.name = t.name + " (BoneSync." + seenTransformNames[path] + ")";
|
||||||
|
total++;
|
||||||
|
//SyncLogger.Msg("Renamed duplicate transform: " + path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seenTransformNames[path] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncLogger.Msg("Renamed " + total + " duplicate transforms in " + scene.name);
|
||||||
|
}
|
||||||
public static void OnSceneInit(int buildIndex)
|
public static void OnSceneInit(int buildIndex)
|
||||||
{
|
{
|
||||||
string SceneName = SceneManager.GetSceneByBuildIndex(buildIndex).name;
|
Scene scene = SceneManager.GetSceneByBuildIndex(buildIndex);
|
||||||
|
_lastSceneChangeTime = Time.realtimeSinceStartup;
|
||||||
|
_currentSceneIndex = buildIndex;
|
||||||
|
string SceneName = scene.name;
|
||||||
_currentSceneName = SceneName;
|
_currentSceneName = SceneName;
|
||||||
MelonLogger.Msg("Scene initialized: " + SceneName);
|
SyncLogger.Msg("Scene initialized: " + SceneName);
|
||||||
|
RenameDuplicateSceneTransforms(scene);
|
||||||
|
SpawnableManager.AddUnregisteredSpawnables();
|
||||||
|
SendSceneSyncMessage(buildIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Initialize()
|
public static void Initialize()
|
||||||
@@ -42,5 +86,32 @@ namespace BoneSync.Sync
|
|||||||
scenes.Add(SceneManager.GetSceneByBuildIndex(i));
|
scenes.Add(SceneManager.GetSceneByBuildIndex(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SendSceneSyncMessage(string sceneName)
|
||||||
|
{
|
||||||
|
int index = scenes.FindIndex(x => x.name == sceneName);
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
SyncLogger.Error("Scene not found: " + sceneName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SendSceneSyncMessage(index);
|
||||||
|
}
|
||||||
|
public static void SendSceneSyncMessage(int index)
|
||||||
|
{
|
||||||
|
if (!BoneSync.IsConnected) return;
|
||||||
|
if (BoneSync.lobby.IsHost)
|
||||||
|
{
|
||||||
|
SyncLogger.Msg("Host is loading scene, sending message to clients...");
|
||||||
|
SceneChangeInfo info = new SceneChangeInfo()
|
||||||
|
{
|
||||||
|
sceneName = scenes[index].name,
|
||||||
|
sceneChangeType = sceneChangeType.FromIndex,
|
||||||
|
sceneIndex = (byte)index
|
||||||
|
};
|
||||||
|
SceneChangeMessage message = new SceneChangeMessage(info);
|
||||||
|
message.Broadcast();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<packages>
|
|
||||||
<package id="Microsoft.TestPlatform.ObjectModel" version="17.12.0" targetFramework="net472" />
|
|
||||||
<package id="MSTest.Analyzers" version="3.8.2" targetFramework="net472" developmentDependency="true" />
|
|
||||||
<package id="MSTest.TestFramework" version="3.8.2" targetFramework="net472" />
|
|
||||||
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net472" />
|
|
||||||
<package id="System.Reflection.Metadata" version="1.6.0" targetFramework="net472" />
|
|
||||||
<package id="xunit" version="2.9.3" targetFramework="net472" />
|
|
||||||
<package id="xunit.abstractions" version="2.0.3" targetFramework="net472" />
|
|
||||||
<package id="xunit.analyzers" version="1.20.0" targetFramework="net472" developmentDependency="true" />
|
|
||||||
<package id="xunit.assert" version="2.9.3" targetFramework="net472" />
|
|
||||||
<package id="xunit.core" version="2.9.3" targetFramework="net472" />
|
|
||||||
<package id="xunit.extensibility.core" version="2.9.3" targetFramework="net472" />
|
|
||||||
<package id="xunit.extensibility.execution" version="2.9.3" targetFramework="net472" />
|
|
||||||
<package id="xunit.runner.visualstudio" version="3.0.2" targetFramework="net472" developmentDependency="true" />
|
|
||||||
</packages>
|
|
||||||
BIN
BoneSync/playerrep.eres
Normal file
BIN
BoneSync/playerrep.eres
Normal file
Binary file not shown.
Reference in New Issue
Block a user