From 102321ccbd5a43693fac7b9682d9521f85bf8267 Mon Sep 17 00:00:00 2001 From: Clergue Valentin Date: Thu, 30 May 2024 14:12:36 +0200 Subject: [PATCH] add segregation between legacy code and explicit objects --- RustPlusApi.sln | 80 +++- .../GetAlarmInfo.csproj} | 8 +- .../Program.cs | 6 +- .../Examples/GetEntityChanges/Program.cs | 38 -- RustPlusApi/Examples/GetInfo/Program.cs | 2 - RustPlusApi/Examples/GetMap/Program.cs | 13 +- .../GetSmartSwitchChanges.csproj} | 8 +- .../Examples/GetSmartSwitchChanges/Program.cs | 22 + .../GetSmartSwitchInfo.csproj | 15 + .../Examples/GetSmartSwitchInfo/Program.cs | 19 + .../GetStorageMonitorChanges.csproj | 15 + .../GetStorageMonitorChanges/Program.cs | 22 + .../GetStorageMonitorInfo.csproj | 15 + .../Examples/GetStorageMonitorInfo/Program.cs | 19 + .../GetEntityChangesLegacy.csproj | 15 + .../Legacy/GetEntityChangesLegacy/Program.cs | 25 ++ .../GetEntityInfoLegacy.csproj | 15 + .../Legacy/GetEntityInfoLegacy/Program.cs | 19 + .../Legacy/GetInfoLegacy/GetInfoLegacy.csproj | 15 + .../Examples/Legacy/GetInfoLegacy/Program.cs | 18 + .../Legacy/GetMapLegacy/GetMapLegacy.csproj | 15 + .../Examples/Legacy/GetMapLegacy/Program.cs | 20 + .../Examples/__Constants/ExamplesConst.cs | 2 + RustPlusApi/RustPlusApi/Data/Response.cs | 14 + .../Extensions/AppEntityInfoToModel.cs | 1 + .../{ => Protobuf}/RustPlusContracts.cs | 0 .../{ => Protobuf}/RustPlusContracts.proto | 0 RustPlusApi/RustPlusApi/RustPlus.cs | 385 +++--------------- RustPlusApi/RustPlusApi/RustPlusLegacy.cs | 366 +++++++++++++++++ .../RustPlusApi/Utils/ResponseHelper.cs | 17 + 30 files changed, 800 insertions(+), 409 deletions(-) rename RustPlusApi/Examples/{GetEntityChanges/GetEntityChanges.csproj => GetAlarmInfo/GetAlarmInfo.csproj} (58%) rename RustPlusApi/Examples/{GetEntityInfo => GetAlarmInfo}/Program.cs (57%) delete mode 100644 RustPlusApi/Examples/GetEntityChanges/Program.cs rename RustPlusApi/Examples/{GetEntityInfo/GetEntityInfo.csproj => GetSmartSwitchChanges/GetSmartSwitchChanges.csproj} (58%) create mode 100644 RustPlusApi/Examples/GetSmartSwitchChanges/Program.cs create mode 100644 RustPlusApi/Examples/GetSmartSwitchInfo/GetSmartSwitchInfo.csproj create mode 100644 RustPlusApi/Examples/GetSmartSwitchInfo/Program.cs create mode 100644 RustPlusApi/Examples/GetStorageMonitorChanges/GetStorageMonitorChanges.csproj create mode 100644 RustPlusApi/Examples/GetStorageMonitorChanges/Program.cs create mode 100644 RustPlusApi/Examples/GetStorageMonitorInfo/GetStorageMonitorInfo.csproj create mode 100644 RustPlusApi/Examples/GetStorageMonitorInfo/Program.cs create mode 100644 RustPlusApi/Examples/Legacy/GetEntityChangesLegacy/GetEntityChangesLegacy.csproj create mode 100644 RustPlusApi/Examples/Legacy/GetEntityChangesLegacy/Program.cs create mode 100644 RustPlusApi/Examples/Legacy/GetEntityInfoLegacy/GetEntityInfoLegacy.csproj create mode 100644 RustPlusApi/Examples/Legacy/GetEntityInfoLegacy/Program.cs create mode 100644 RustPlusApi/Examples/Legacy/GetInfoLegacy/GetInfoLegacy.csproj create mode 100644 RustPlusApi/Examples/Legacy/GetInfoLegacy/Program.cs create mode 100644 RustPlusApi/Examples/Legacy/GetMapLegacy/GetMapLegacy.csproj create mode 100644 RustPlusApi/Examples/Legacy/GetMapLegacy/Program.cs create mode 100644 RustPlusApi/RustPlusApi/Data/Response.cs rename RustPlusApi/RustPlusApi/{ => Protobuf}/RustPlusContracts.cs (100%) rename RustPlusApi/RustPlusApi/{ => Protobuf}/RustPlusContracts.proto (100%) create mode 100644 RustPlusApi/RustPlusApi/RustPlusLegacy.cs create mode 100644 RustPlusApi/RustPlusApi/Utils/ResponseHelper.cs diff --git a/RustPlusApi.sln b/RustPlusApi.sln index a8f4b9a..e09af8f 100644 --- a/RustPlusApi.sln +++ b/RustPlusApi.sln @@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RustPlusApi", "RustPlusApi\ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{BC948ADE-1674-4955-B27C-F0E96100978E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetEntityInfo", "RustPlusApi\Examples\GetEntityInfo\GetEntityInfo.csproj", "{A53B0FAC-F59B-4021-9A67-997D1F5727D7}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "__Constants", "RustPlusApi\Examples\__Constants\__Constants.csproj", "{DF3F9213-6F6D-4832-8738-CA106BE49860}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetInfo", "RustPlusApi\Examples\GetInfo\GetInfo.csproj", "{AB17A661-1D1D-496C-A39C-B31F3BAEADA1}" @@ -21,8 +19,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetTime", "RustPlusApi\Exam EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SendTeamChat", "RustPlusApi\Examples\SendTeamChat\SendTeamChat.csproj", "{D70DD514-081F-4055-8779-6626DA96D18D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetEntityChanges", "RustPlusApi\Examples\GetEntityChanges\GetEntityChanges.csproj", "{C1BA15FE-9F2E-4A9A-BBB3-9161FCFEE344}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SetEntityValue", "RustPlusApi\Examples\SetEntityValue\SetEntityValue.csproj", "{4E5DCE64-A8E5-42C0-8786-EA1FF36CACE4}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StrobeEntity", "RustPlusApi\Examples\StrobeEntity\StrobeEntity.csproj", "{3C4E8016-7B7F-4C5E-A5CA-A92A3797AA2B}" @@ -43,6 +39,26 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PromoteToLeader", "RustPlus EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetTeamChatChanges", "RustPlusApi\Examples\GetTeamChatChanges\GetTeamChatChanges.csproj", "{D39626D0-079C-40C6-A260-09852E11C70A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetSmartSwitchInfo", "RustPlusApi\Examples\GetSmartSwitchInfo\GetSmartSwitchInfo.csproj", "{CCC95529-EA3A-4FF3-945A-97151848F6BB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetAlarmInfo", "RustPlusApi\Examples\GetAlarmInfo\GetAlarmInfo.csproj", "{B9E7E802-867B-40E4-BEEE-807735F091E3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetStorageMonitorInfo", "RustPlusApi\Examples\GetStorageMonitorInfo\GetStorageMonitorInfo.csproj", "{51CD85C0-0240-4C7C-BBDC-0DCF5234299E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Legacy", "Legacy", "{EBB661D0-93FF-4742-AF91-9036027CD136}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetEntityInfoLegacy", "RustPlusApi\Examples\Legacy\GetEntityInfoLegacy\GetEntityInfoLegacy.csproj", "{39EC2C27-0351-4099-A07B-237DD8C73FA6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetEntityChangesLegacy", "RustPlusApi\Examples\Legacy\GetEntityChangesLegacy\GetEntityChangesLegacy.csproj", "{443F0C99-2BC7-44CB-9DE8-A292B10B9CE3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetInfoLegacy", "RustPlusApi\Examples\Legacy\GetInfoLegacy\GetInfoLegacy.csproj", "{17F33FF0-AFE2-4DE4-81E9-6804A2B210A7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetMapLegacy", "RustPlusApi\Examples\Legacy\GetMapLegacy\GetMapLegacy.csproj", "{4C4D800C-1DF9-4139-BD7C-2FE0D78FF30C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetSmartSwitchChanges", "RustPlusApi\Examples\GetSmartSwitchChanges\GetSmartSwitchChanges.csproj", "{A7852D6E-9371-4026-B3BE-1BE264718D1D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetStorageMonitorChanges", "RustPlusApi\Examples\GetStorageMonitorChanges\GetStorageMonitorChanges.csproj", "{2E65E71F-1C4E-4813-86C9-C5F5D3E60187}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -53,10 +69,6 @@ Global {2E744AA2-4D20-4B44-A79E-AC1CC56E848E}.Debug|Any CPU.Build.0 = Debug|Any CPU {2E744AA2-4D20-4B44-A79E-AC1CC56E848E}.Release|Any CPU.ActiveCfg = Release|Any CPU {2E744AA2-4D20-4B44-A79E-AC1CC56E848E}.Release|Any CPU.Build.0 = Release|Any CPU - {A53B0FAC-F59B-4021-9A67-997D1F5727D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A53B0FAC-F59B-4021-9A67-997D1F5727D7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A53B0FAC-F59B-4021-9A67-997D1F5727D7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A53B0FAC-F59B-4021-9A67-997D1F5727D7}.Release|Any CPU.Build.0 = Release|Any CPU {DF3F9213-6F6D-4832-8738-CA106BE49860}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DF3F9213-6F6D-4832-8738-CA106BE49860}.Debug|Any CPU.Build.0 = Debug|Any CPU {DF3F9213-6F6D-4832-8738-CA106BE49860}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -81,10 +93,6 @@ Global {D70DD514-081F-4055-8779-6626DA96D18D}.Debug|Any CPU.Build.0 = Debug|Any CPU {D70DD514-081F-4055-8779-6626DA96D18D}.Release|Any CPU.ActiveCfg = Release|Any CPU {D70DD514-081F-4055-8779-6626DA96D18D}.Release|Any CPU.Build.0 = Release|Any CPU - {C1BA15FE-9F2E-4A9A-BBB3-9161FCFEE344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C1BA15FE-9F2E-4A9A-BBB3-9161FCFEE344}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C1BA15FE-9F2E-4A9A-BBB3-9161FCFEE344}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C1BA15FE-9F2E-4A9A-BBB3-9161FCFEE344}.Release|Any CPU.Build.0 = Release|Any CPU {4E5DCE64-A8E5-42C0-8786-EA1FF36CACE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4E5DCE64-A8E5-42C0-8786-EA1FF36CACE4}.Debug|Any CPU.Build.0 = Debug|Any CPU {4E5DCE64-A8E5-42C0-8786-EA1FF36CACE4}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -121,19 +129,53 @@ Global {D39626D0-079C-40C6-A260-09852E11C70A}.Debug|Any CPU.Build.0 = Debug|Any CPU {D39626D0-079C-40C6-A260-09852E11C70A}.Release|Any CPU.ActiveCfg = Release|Any CPU {D39626D0-079C-40C6-A260-09852E11C70A}.Release|Any CPU.Build.0 = Release|Any CPU + {CCC95529-EA3A-4FF3-945A-97151848F6BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CCC95529-EA3A-4FF3-945A-97151848F6BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CCC95529-EA3A-4FF3-945A-97151848F6BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CCC95529-EA3A-4FF3-945A-97151848F6BB}.Release|Any CPU.Build.0 = Release|Any CPU + {B9E7E802-867B-40E4-BEEE-807735F091E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B9E7E802-867B-40E4-BEEE-807735F091E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9E7E802-867B-40E4-BEEE-807735F091E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B9E7E802-867B-40E4-BEEE-807735F091E3}.Release|Any CPU.Build.0 = Release|Any CPU + {51CD85C0-0240-4C7C-BBDC-0DCF5234299E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {51CD85C0-0240-4C7C-BBDC-0DCF5234299E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51CD85C0-0240-4C7C-BBDC-0DCF5234299E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {51CD85C0-0240-4C7C-BBDC-0DCF5234299E}.Release|Any CPU.Build.0 = Release|Any CPU + {39EC2C27-0351-4099-A07B-237DD8C73FA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39EC2C27-0351-4099-A07B-237DD8C73FA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39EC2C27-0351-4099-A07B-237DD8C73FA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39EC2C27-0351-4099-A07B-237DD8C73FA6}.Release|Any CPU.Build.0 = Release|Any CPU + {443F0C99-2BC7-44CB-9DE8-A292B10B9CE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {443F0C99-2BC7-44CB-9DE8-A292B10B9CE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {443F0C99-2BC7-44CB-9DE8-A292B10B9CE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {443F0C99-2BC7-44CB-9DE8-A292B10B9CE3}.Release|Any CPU.Build.0 = Release|Any CPU + {17F33FF0-AFE2-4DE4-81E9-6804A2B210A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17F33FF0-AFE2-4DE4-81E9-6804A2B210A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17F33FF0-AFE2-4DE4-81E9-6804A2B210A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17F33FF0-AFE2-4DE4-81E9-6804A2B210A7}.Release|Any CPU.Build.0 = Release|Any CPU + {4C4D800C-1DF9-4139-BD7C-2FE0D78FF30C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C4D800C-1DF9-4139-BD7C-2FE0D78FF30C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C4D800C-1DF9-4139-BD7C-2FE0D78FF30C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C4D800C-1DF9-4139-BD7C-2FE0D78FF30C}.Release|Any CPU.Build.0 = Release|Any CPU + {A7852D6E-9371-4026-B3BE-1BE264718D1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A7852D6E-9371-4026-B3BE-1BE264718D1D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A7852D6E-9371-4026-B3BE-1BE264718D1D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A7852D6E-9371-4026-B3BE-1BE264718D1D}.Release|Any CPU.Build.0 = Release|Any CPU + {2E65E71F-1C4E-4813-86C9-C5F5D3E60187}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E65E71F-1C4E-4813-86C9-C5F5D3E60187}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E65E71F-1C4E-4813-86C9-C5F5D3E60187}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E65E71F-1C4E-4813-86C9-C5F5D3E60187}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A53B0FAC-F59B-4021-9A67-997D1F5727D7} = {BC948ADE-1674-4955-B27C-F0E96100978E} {DF3F9213-6F6D-4832-8738-CA106BE49860} = {BC948ADE-1674-4955-B27C-F0E96100978E} {AB17A661-1D1D-496C-A39C-B31F3BAEADA1} = {BC948ADE-1674-4955-B27C-F0E96100978E} {4E87360D-AC39-4475-957F-D49018DB2DC8} = {BC948ADE-1674-4955-B27C-F0E96100978E} {70453D6E-9C19-41BC-8C96-0E20F919DB11} = {BC948ADE-1674-4955-B27C-F0E96100978E} {E9F90342-34DE-4166-9769-483A3FA1F144} = {BC948ADE-1674-4955-B27C-F0E96100978E} {D70DD514-081F-4055-8779-6626DA96D18D} = {BC948ADE-1674-4955-B27C-F0E96100978E} - {C1BA15FE-9F2E-4A9A-BBB3-9161FCFEE344} = {BC948ADE-1674-4955-B27C-F0E96100978E} {4E5DCE64-A8E5-42C0-8786-EA1FF36CACE4} = {BC948ADE-1674-4955-B27C-F0E96100978E} {3C4E8016-7B7F-4C5E-A5CA-A92A3797AA2B} = {BC948ADE-1674-4955-B27C-F0E96100978E} {DD34FAE8-30AA-4787-A6D1-77C330A0928F} = {BC948ADE-1674-4955-B27C-F0E96100978E} @@ -143,6 +185,16 @@ Global {1A186504-8461-4F19-BDC5-C3DB90A554D6} = {BC948ADE-1674-4955-B27C-F0E96100978E} {3DE93E0D-DAF5-48E7-A353-BD99ABB942DE} = {BC948ADE-1674-4955-B27C-F0E96100978E} {D39626D0-079C-40C6-A260-09852E11C70A} = {BC948ADE-1674-4955-B27C-F0E96100978E} + {CCC95529-EA3A-4FF3-945A-97151848F6BB} = {BC948ADE-1674-4955-B27C-F0E96100978E} + {B9E7E802-867B-40E4-BEEE-807735F091E3} = {BC948ADE-1674-4955-B27C-F0E96100978E} + {51CD85C0-0240-4C7C-BBDC-0DCF5234299E} = {BC948ADE-1674-4955-B27C-F0E96100978E} + {EBB661D0-93FF-4742-AF91-9036027CD136} = {BC948ADE-1674-4955-B27C-F0E96100978E} + {39EC2C27-0351-4099-A07B-237DD8C73FA6} = {EBB661D0-93FF-4742-AF91-9036027CD136} + {443F0C99-2BC7-44CB-9DE8-A292B10B9CE3} = {EBB661D0-93FF-4742-AF91-9036027CD136} + {17F33FF0-AFE2-4DE4-81E9-6804A2B210A7} = {EBB661D0-93FF-4742-AF91-9036027CD136} + {4C4D800C-1DF9-4139-BD7C-2FE0D78FF30C} = {EBB661D0-93FF-4742-AF91-9036027CD136} + {A7852D6E-9371-4026-B3BE-1BE264718D1D} = {BC948ADE-1674-4955-B27C-F0E96100978E} + {2E65E71F-1C4E-4813-86C9-C5F5D3E60187} = {BC948ADE-1674-4955-B27C-F0E96100978E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A4B4251F-ADA4-418D-95B5-27BA99A307A3} diff --git a/RustPlusApi/Examples/GetEntityChanges/GetEntityChanges.csproj b/RustPlusApi/Examples/GetAlarmInfo/GetAlarmInfo.csproj similarity index 58% rename from RustPlusApi/Examples/GetEntityChanges/GetEntityChanges.csproj rename to RustPlusApi/Examples/GetAlarmInfo/GetAlarmInfo.csproj index 0aa3ca6..8587a6a 100644 --- a/RustPlusApi/Examples/GetEntityChanges/GetEntityChanges.csproj +++ b/RustPlusApi/Examples/GetAlarmInfo/GetAlarmInfo.csproj @@ -7,9 +7,9 @@ enable - - - - + + + + diff --git a/RustPlusApi/Examples/GetEntityInfo/Program.cs b/RustPlusApi/Examples/GetAlarmInfo/Program.cs similarity index 57% rename from RustPlusApi/Examples/GetEntityInfo/Program.cs rename to RustPlusApi/Examples/GetAlarmInfo/Program.cs index 36c6ab4..48c0dfe 100644 --- a/RustPlusApi/Examples/GetEntityInfo/Program.cs +++ b/RustPlusApi/Examples/GetAlarmInfo/Program.cs @@ -5,13 +5,11 @@ using static __Constants.ExamplesConst; var rustPlus = new RustPlus(Ip, Port, PlayerId, PlayerToken); -uint entityId = 0; +const uint entityId = 0; rustPlus.Connected += async (_, _) => { - // The message would be SmartSwitchInfo, AlarmInfo, or StorageMonitorInfo - // If you want to do your own parsing you can set the useRawObject parameter to true - var message = await rustPlus.GetEntityInfoAsync(entityId); + var message = await rustPlus.GetAlarmInfoAsync(entityId); Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); diff --git a/RustPlusApi/Examples/GetEntityChanges/Program.cs b/RustPlusApi/Examples/GetEntityChanges/Program.cs deleted file mode 100644 index 1a5f1fa..0000000 --- a/RustPlusApi/Examples/GetEntityChanges/Program.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Newtonsoft.Json; - -using RustPlusApi; - -using static __Constants.ExamplesConst; - -var rustPlus = new RustPlus(Ip, Port, PlayerId, PlayerToken); -uint entityId = 0; - -rustPlus.Connected += async (_, _) => -{ - // The message would be SmartSwitchInfo, AlarmInfo, or StorageMonitorInfo - // If you want to do your own parsing you can set the useRawObject parameter to true - var message = await rustPlus.GetEntityInfoAsync(entityId); - - Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); -}; - -rustPlus.OnSmartSwitchTriggered += (_, message) => -{ - Console.WriteLine($"SmartSwitch:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); -}; - -rustPlus.OnStorageMonitorTriggered += (_, message) => -{ - Console.WriteLine($"StorageMonitor:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); -}; - -// If you want to get the raw message for the notification you can use the MessageReceived event -//rustPlus.MessageReceived += (_, message) => -//{ -// if (message.Broadcast is not { EntityChanged: not null }) return; - -// var entityChanged = message.Broadcast.EntityChanged; -// Console.WriteLine($"Message:\n{JsonConvert.SerializeObject(entityChanged, JsonSettings)}"); -//}; - -await rustPlus.ConnectAsync(); \ No newline at end of file diff --git a/RustPlusApi/Examples/GetInfo/Program.cs b/RustPlusApi/Examples/GetInfo/Program.cs index 3bb9892..d85d435 100644 --- a/RustPlusApi/Examples/GetInfo/Program.cs +++ b/RustPlusApi/Examples/GetInfo/Program.cs @@ -8,8 +8,6 @@ rustPlus.Connected += async (_, _) => { - // The message would be a ServerInfo - // If you want to do your own parsing you can set the useRawObject parameter to true var message = await rustPlus.GetInfoAsync(); Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); diff --git a/RustPlusApi/Examples/GetMap/Program.cs b/RustPlusApi/Examples/GetMap/Program.cs index 986c042..c9a1094 100644 --- a/RustPlusApi/Examples/GetMap/Program.cs +++ b/RustPlusApi/Examples/GetMap/Program.cs @@ -1,7 +1,6 @@ using Newtonsoft.Json; using RustPlusApi; -using RustPlusApi.Data; using static __Constants.ExamplesConst; @@ -9,18 +8,14 @@ rustPlus.Connected += async (_, _) => { - // The message would be a ServerMap - // If you want to do your own parsing you can set the useRawObject parameter to true - // (this code will obviously break if you do) var message = await rustPlus.GetMapAsync(); - if (message is not ServerMap) return; - var serverMap = (ServerMap)message; + if (!message.IsSuccess) return; - File.WriteAllBytes("map.jpg", serverMap.JpgImage!); + File.WriteAllBytes("map.jpg", message.Data?.JpgImage!); - serverMap.JpgImage = null; - Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(serverMap, JsonSettings)}"); + message.Data!.JpgImage = null; + Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); Console.WriteLine($"Image saved under: {Directory.GetCurrentDirectory()}"); diff --git a/RustPlusApi/Examples/GetEntityInfo/GetEntityInfo.csproj b/RustPlusApi/Examples/GetSmartSwitchChanges/GetSmartSwitchChanges.csproj similarity index 58% rename from RustPlusApi/Examples/GetEntityInfo/GetEntityInfo.csproj rename to RustPlusApi/Examples/GetSmartSwitchChanges/GetSmartSwitchChanges.csproj index 0aa3ca6..8587a6a 100644 --- a/RustPlusApi/Examples/GetEntityInfo/GetEntityInfo.csproj +++ b/RustPlusApi/Examples/GetSmartSwitchChanges/GetSmartSwitchChanges.csproj @@ -7,9 +7,9 @@ enable - - - - + + + + diff --git a/RustPlusApi/Examples/GetSmartSwitchChanges/Program.cs b/RustPlusApi/Examples/GetSmartSwitchChanges/Program.cs new file mode 100644 index 0000000..154f681 --- /dev/null +++ b/RustPlusApi/Examples/GetSmartSwitchChanges/Program.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +using RustPlusApi; + +using static __Constants.ExamplesConst; + +var rustPlus = new RustPlus(Ip, Port, PlayerId, PlayerToken); +const uint entityId = 0; + +rustPlus.Connected += async (_, _) => +{ + var message = await rustPlus.GetSmartSwitchInfoAsync(entityId); + + Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); +}; + +rustPlus.OnSmartSwitchTriggered += (_, message) => +{ + Console.WriteLine($"SmartSwitch:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); +}; + +await rustPlus.ConnectAsync(); \ No newline at end of file diff --git a/RustPlusApi/Examples/GetSmartSwitchInfo/GetSmartSwitchInfo.csproj b/RustPlusApi/Examples/GetSmartSwitchInfo/GetSmartSwitchInfo.csproj new file mode 100644 index 0000000..8587a6a --- /dev/null +++ b/RustPlusApi/Examples/GetSmartSwitchInfo/GetSmartSwitchInfo.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + diff --git a/RustPlusApi/Examples/GetSmartSwitchInfo/Program.cs b/RustPlusApi/Examples/GetSmartSwitchInfo/Program.cs new file mode 100644 index 0000000..a452cc7 --- /dev/null +++ b/RustPlusApi/Examples/GetSmartSwitchInfo/Program.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +using RustPlusApi; + +using static __Constants.ExamplesConst; + +var rustPlus = new RustPlus(Ip, Port, PlayerId, PlayerToken); +const uint entityId = 0; + +rustPlus.Connected += async (_, _) => +{ + var message = await rustPlus.GetSmartSwitchInfoAsync(entityId); + + Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); + + rustPlus.Dispose(); +}; + +await rustPlus.ConnectAsync(); \ No newline at end of file diff --git a/RustPlusApi/Examples/GetStorageMonitorChanges/GetStorageMonitorChanges.csproj b/RustPlusApi/Examples/GetStorageMonitorChanges/GetStorageMonitorChanges.csproj new file mode 100644 index 0000000..8587a6a --- /dev/null +++ b/RustPlusApi/Examples/GetStorageMonitorChanges/GetStorageMonitorChanges.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + diff --git a/RustPlusApi/Examples/GetStorageMonitorChanges/Program.cs b/RustPlusApi/Examples/GetStorageMonitorChanges/Program.cs new file mode 100644 index 0000000..962434d --- /dev/null +++ b/RustPlusApi/Examples/GetStorageMonitorChanges/Program.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +using RustPlusApi; + +using static __Constants.ExamplesConst; + +var rustPlus = new RustPlus(Ip, Port, PlayerId, PlayerToken); +const uint entityId = 0; + +rustPlus.Connected += async (_, _) => +{ + var message = await rustPlus.GetStorageMonitorInfoAsync(entityId); + + Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); +}; + +rustPlus.OnStorageMonitorTriggered += (_, message) => +{ + Console.WriteLine($"StorageMonitor:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); +}; + +await rustPlus.ConnectAsync(); \ No newline at end of file diff --git a/RustPlusApi/Examples/GetStorageMonitorInfo/GetStorageMonitorInfo.csproj b/RustPlusApi/Examples/GetStorageMonitorInfo/GetStorageMonitorInfo.csproj new file mode 100644 index 0000000..8587a6a --- /dev/null +++ b/RustPlusApi/Examples/GetStorageMonitorInfo/GetStorageMonitorInfo.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + diff --git a/RustPlusApi/Examples/GetStorageMonitorInfo/Program.cs b/RustPlusApi/Examples/GetStorageMonitorInfo/Program.cs new file mode 100644 index 0000000..c68847d --- /dev/null +++ b/RustPlusApi/Examples/GetStorageMonitorInfo/Program.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +using RustPlusApi; + +using static __Constants.ExamplesConst; + +var rustPlus = new RustPlus(Ip, Port, PlayerId, PlayerToken); +const uint entityId = 0; + +rustPlus.Connected += async (_, _) => +{ + var message = await rustPlus.GetStorageMonitorInfoAsync(entityId); + + Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); + + rustPlus.Dispose(); +}; + +await rustPlus.ConnectAsync(); \ No newline at end of file diff --git a/RustPlusApi/Examples/Legacy/GetEntityChangesLegacy/GetEntityChangesLegacy.csproj b/RustPlusApi/Examples/Legacy/GetEntityChangesLegacy/GetEntityChangesLegacy.csproj new file mode 100644 index 0000000..d9c9c6e --- /dev/null +++ b/RustPlusApi/Examples/Legacy/GetEntityChangesLegacy/GetEntityChangesLegacy.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + diff --git a/RustPlusApi/Examples/Legacy/GetEntityChangesLegacy/Program.cs b/RustPlusApi/Examples/Legacy/GetEntityChangesLegacy/Program.cs new file mode 100644 index 0000000..f7de659 --- /dev/null +++ b/RustPlusApi/Examples/Legacy/GetEntityChangesLegacy/Program.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; + +using RustPlusApi; + +using static __Constants.ExamplesConst; + +var rustPlus = new RustPlusLegacy(Ip, Port, PlayerId, PlayerToken); +const uint entityId = 0; + +rustPlus.Connected += async (_, _) => +{ + var message = await rustPlus.GetEntityInfoLegacyAsync(entityId); + + Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); +}; + +rustPlus.MessageReceived += (_, message) => +{ + if (message.Broadcast is not { EntityChanged: not null }) return; + + var entityChanged = message.Broadcast.EntityChanged; + Console.WriteLine($"Message:\n{JsonConvert.SerializeObject(entityChanged, JsonSettings)}"); +}; + +await rustPlus.ConnectAsync(); \ No newline at end of file diff --git a/RustPlusApi/Examples/Legacy/GetEntityInfoLegacy/GetEntityInfoLegacy.csproj b/RustPlusApi/Examples/Legacy/GetEntityInfoLegacy/GetEntityInfoLegacy.csproj new file mode 100644 index 0000000..d9c9c6e --- /dev/null +++ b/RustPlusApi/Examples/Legacy/GetEntityInfoLegacy/GetEntityInfoLegacy.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + diff --git a/RustPlusApi/Examples/Legacy/GetEntityInfoLegacy/Program.cs b/RustPlusApi/Examples/Legacy/GetEntityInfoLegacy/Program.cs new file mode 100644 index 0000000..c209b77 --- /dev/null +++ b/RustPlusApi/Examples/Legacy/GetEntityInfoLegacy/Program.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +using RustPlusApi; + +using static __Constants.ExamplesConst; + +var rustPlus = new RustPlusLegacy(Ip, Port, PlayerId, PlayerToken); +const uint entityId = 0; + +rustPlus.Connected += async (_, _) => +{ + var message = await rustPlus.GetEntityInfoLegacyAsync(entityId); + + Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); + + rustPlus.Dispose(); +}; + +await rustPlus.ConnectAsync(); \ No newline at end of file diff --git a/RustPlusApi/Examples/Legacy/GetInfoLegacy/GetInfoLegacy.csproj b/RustPlusApi/Examples/Legacy/GetInfoLegacy/GetInfoLegacy.csproj new file mode 100644 index 0000000..d9c9c6e --- /dev/null +++ b/RustPlusApi/Examples/Legacy/GetInfoLegacy/GetInfoLegacy.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + diff --git a/RustPlusApi/Examples/Legacy/GetInfoLegacy/Program.cs b/RustPlusApi/Examples/Legacy/GetInfoLegacy/Program.cs new file mode 100644 index 0000000..1a5a486 --- /dev/null +++ b/RustPlusApi/Examples/Legacy/GetInfoLegacy/Program.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +using RustPlusApi; + +using static __Constants.ExamplesConst; + +var rustPlus = new RustPlus(Ip, Port, PlayerId, PlayerToken); + +rustPlus.Connected += async (_, _) => +{ + var message = await rustPlus.GetInfoLegacyAsync(); + + Console.WriteLine($"Infos:\n{JsonConvert.SerializeObject(message, JsonSettings)}"); + + rustPlus.Dispose(); +}; + +await rustPlus.ConnectAsync(); \ No newline at end of file diff --git a/RustPlusApi/Examples/Legacy/GetMapLegacy/GetMapLegacy.csproj b/RustPlusApi/Examples/Legacy/GetMapLegacy/GetMapLegacy.csproj new file mode 100644 index 0000000..d9c9c6e --- /dev/null +++ b/RustPlusApi/Examples/Legacy/GetMapLegacy/GetMapLegacy.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + diff --git a/RustPlusApi/Examples/Legacy/GetMapLegacy/Program.cs b/RustPlusApi/Examples/Legacy/GetMapLegacy/Program.cs new file mode 100644 index 0000000..a93c528 --- /dev/null +++ b/RustPlusApi/Examples/Legacy/GetMapLegacy/Program.cs @@ -0,0 +1,20 @@ +using RustPlusApi; + +using static __Constants.ExamplesConst; + +var rustPlus = new RustPlus(Ip, Port, PlayerId, PlayerToken); + +rustPlus.Connected += async (_, _) => +{ + var message = await rustPlus.GetMapLegacyAsync(); + + if (message.Response.Error is not null) return; + + File.WriteAllBytes("map.jpg", message.Response.Map.JpgImage.ToByteArray()); + + Console.WriteLine($"Image saved under: {Directory.GetCurrentDirectory()}"); + + rustPlus.Dispose(); +}; + +await rustPlus.ConnectAsync(); \ No newline at end of file diff --git a/RustPlusApi/Examples/__Constants/ExamplesConst.cs b/RustPlusApi/Examples/__Constants/ExamplesConst.cs index 681c3f0..b69f0ff 100644 --- a/RustPlusApi/Examples/__Constants/ExamplesConst.cs +++ b/RustPlusApi/Examples/__Constants/ExamplesConst.cs @@ -1,4 +1,6 @@ using Newtonsoft.Json; +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable FieldCanBeMadeReadOnly.Global namespace __Constants { diff --git a/RustPlusApi/RustPlusApi/Data/Response.cs b/RustPlusApi/RustPlusApi/Data/Response.cs new file mode 100644 index 0000000..509a341 --- /dev/null +++ b/RustPlusApi/RustPlusApi/Data/Response.cs @@ -0,0 +1,14 @@ +namespace RustPlusApi.Data +{ + public class Response + { + public bool IsSuccess { get; set; } + public Error? Error { get; set; } + public T? Data { get; set; } + } + + public class Error + { + public string? Message { get; set; } + } +} diff --git a/RustPlusApi/RustPlusApi/Extensions/AppEntityInfoToModel.cs b/RustPlusApi/RustPlusApi/Extensions/AppEntityInfoToModel.cs index d182b97..5d684c4 100644 --- a/RustPlusApi/RustPlusApi/Extensions/AppEntityInfoToModel.cs +++ b/RustPlusApi/RustPlusApi/Extensions/AppEntityInfoToModel.cs @@ -1,6 +1,7 @@ using RustPlusApi.Data; using RustPlusContracts; +// ReSharper disable MemberCanBePrivate.Global namespace RustPlusApi.Extensions { diff --git a/RustPlusApi/RustPlusApi/RustPlusContracts.cs b/RustPlusApi/RustPlusApi/Protobuf/RustPlusContracts.cs similarity index 100% rename from RustPlusApi/RustPlusApi/RustPlusContracts.cs rename to RustPlusApi/RustPlusApi/Protobuf/RustPlusContracts.cs diff --git a/RustPlusApi/RustPlusApi/RustPlusContracts.proto b/RustPlusApi/RustPlusApi/Protobuf/RustPlusContracts.proto similarity index 100% rename from RustPlusApi/RustPlusApi/RustPlusContracts.proto rename to RustPlusApi/RustPlusApi/Protobuf/RustPlusContracts.proto diff --git a/RustPlusApi/RustPlusApi/RustPlus.cs b/RustPlusApi/RustPlusApi/RustPlus.cs index 56cbcb9..cf4c85c 100644 --- a/RustPlusApi/RustPlusApi/RustPlus.cs +++ b/RustPlusApi/RustPlusApi/RustPlus.cs @@ -1,15 +1,12 @@ using System.Diagnostics; -using System.Net.WebSockets; - -using Google.Protobuf; +using RustPlusApi.Data; using RustPlusApi.Data.Events; using RustPlusApi.Extensions; +using RustPlusApi.Utils; using RustPlusContracts; -using static System.GC; - namespace RustPlusApi { /// @@ -20,400 +17,120 @@ namespace RustPlusApi /// Your Steam ID. /// Your player token acquired with FCM. /// Specifies whether to use the Facepunch proxy. - public class RustPlus(string server, int port, ulong playerId, int playerToken, bool useFacepunchProxy = false) : IDisposable + public class RustPlus(string server, int port, ulong playerId, int playerToken, bool useFacepunchProxy = false) + : RustPlusLegacy(server, port, playerId, playerToken, useFacepunchProxy) { - private ClientWebSocket? _webSocket; - private uint _seq; - private readonly Dictionary> _seqCallbacks = []; - - public event EventHandler? Connecting; - public event EventHandler? Connected; - public event EventHandler? MessageReceived; - public event EventHandler? RequestSent; - public event EventHandler? Disconnected; - public event EventHandler? ErrorOccurred; - - public event EventHandler? OnSmartSwitchTriggered; // The Alarm behave exactly like the SmartSwitch so if you get the status of the alarm, this will be triggered + public event EventHandler? OnSmartSwitchTriggered; // Alarm will also be triggered since there is no physical difference between them public event EventHandler? OnStorageMonitorTriggered; - /// - /// Connects to the Rust+ server asynchronously. - /// - public async Task ConnectAsync() - { - _webSocket = new ClientWebSocket(); - _webSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(20); - var address = useFacepunchProxy - ? new Uri($"wss://companion-rust.facepunch.com/game/{server}/{port}") - : new Uri($"ws://{server}:{port}"); - - Connecting?.Invoke(this, EventArgs.Empty); - - try - { - await _webSocket.ConnectAsync(address, CancellationToken.None); - Connected?.Invoke(this, EventArgs.Empty); - await ReceiveMessagesAsync(); - } - catch (Exception ex) - { - ErrorOccurred?.Invoke(this, ex); - Dispose(); - } - } - - /// - /// Receives messages from the Rust+ server asynchronously. - /// - /// A task representing the asynchronous operation. - protected async Task ReceiveMessagesAsync() - { - const int bufferSize = 1024; - var buffer = new byte[bufferSize]; - - try - { - while (_webSocket!.State == WebSocketState.Open) - { - var receiveBuffer = new List(); - WebSocketReceiveResult result; - - do - { - result = await _webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); - receiveBuffer.AddRange(buffer.Take(result.Count)); - } while (!result.EndOfMessage); - - var messageData = receiveBuffer.ToArray(); - var message = AppMessage.Parser.ParseFrom(messageData); - HandleResponse(message); - } - } - catch (WebSocketException ex) - { - Debug.WriteLine($"Disconnected from the Rust+ socket due to a WebSocketException: {ex}"); - ErrorOccurred?.Invoke(this, ex); - } - catch (Exception ex) - { - Debug.WriteLine($"Disconnected from the Rust+ socket due to an Exception: {ex}"); - ErrorOccurred?.Invoke(this, ex); - } - finally - { - Dispose(); - } - } - - /// - /// Handles the response received from the Rust+ server. - /// - /// The AppMessage received from the server. - protected void HandleResponse(AppMessage message) - { - if (message.Response != null - && message.Response.Seq != 0 - && _seqCallbacks.ContainsKey((int)message.Response.Seq)) - { - var tcs = _seqCallbacks[(int)message.Response.Seq]; - tcs.SetResult(message); - _seqCallbacks.Remove((int)message.Response.Seq); - return; - } - MessageReceived?.Invoke(this, message); - ParseNotification(message.Broadcast); - } - - /// - /// Sends a request to the Rust+ server asynchronously. - /// - /// The request to send. - /// A task representing the asynchronous operation. - public async Task SendRequestAsync(AppRequest request) - { - var seq = ++_seq; - var tcs = new TaskCompletionSource(); - _seqCallbacks[(int)seq] = tcs; - - request.Seq = seq; - request.PlayerId = playerId; - request.PlayerToken = playerToken; - - var requestData = request.ToByteArray(); - var buffer = new ArraySegment(requestData); - await _webSocket!.SendAsync(buffer, WebSocketMessageType.Binary, true, CancellationToken.None); - RequestSent?.Invoke(this, request); - - return await tcs.Task; - } - /// /// Parses the notification received from the Rust+ server. /// - /// The AppBroadcast received from the server. - protected void ParseNotification(AppBroadcast? broadcast) + /// The broadcast received from the server. + protected override void ParseNotification(AppBroadcast? broadcast) { if (broadcast is null) return; if (broadcast.EntityChanged is not null) { - // It is physically impossible to differentiate between a SmartSwitch and an Alarm - // This is a limitation of the Rust+ API + // There is no physical difference between aSmartSwitch and an Alarm + // If you check the status of an alarm, it will return the same as a smart switch if (broadcast.EntityChanged.Payload.Capacity is 0) OnSmartSwitchTriggered?.Invoke(this, broadcast.EntityChanged.ToSmartSwitchEvent()); else OnStorageMonitorTriggered?.Invoke(this, broadcast.EntityChanged.ToStorageMonitorEvent()); } - else Debug.WriteLine($"Unknown broadcast:\n{broadcast}"); - } - - /// - /// Disposes the Rust+ API client and disconnects from the Rust+ server. - /// - public void Dispose() - { - if (_webSocket is not { State: WebSocketState.Open }) return; - - _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Connection closed by client.", CancellationToken.None).Wait(); - _webSocket.Dispose(); - - Disconnected?.Invoke(this, EventArgs.Empty); - - SuppressFinalize(this); + else + { + Debug.WriteLine($"Unknown broadcast:\n{broadcast}"); + } } /// - /// Checks if the client is connected to the Rust+ socket. + /// Processes the request asynchronously and returns the result. /// - /// True if the client is connected; otherwise, false. - public bool IsConnected() => _webSocket is { State: WebSocketState.Open }; - - /// - /// Checks if the given response is an error. - /// - /// The AppMessage response to check. - /// True if the response is an error; otherwise, false. - private static bool IsError(AppMessage response) => response.Response.Error is not null; - - /// - /// Processes a request to the Rust+ server asynchronously. - /// - /// The request to process. - /// Specifies whether to use the raw object or convert it to a custom object. - /// A function to select the success response. - /// The processed response. - private async Task ProcessRequestAsync(AppRequest request, bool useRawObject, Func successSelector) + /// The type of the result. + /// The request to be processed. + /// The function to select the result from the response. + /// A representing the asynchronous operation. The task result contains a with the processed result. + private async Task> ProcessRequestAsync(AppRequest request, Func successSelector) { var response = await SendRequestAsync(request); - if (IsError(response)) - return useRawObject - ? response - : response.Response.Error; - - return useRawObject - ? response - : successSelector(response); + return IsError(response) + ? ResponseHelper.BuildGenericOutput(false, default!, response.Response.Error.Error) + : ResponseHelper.BuildGenericOutput(true, successSelector(response)); } /// - /// Retrieves information about an entity from the Rust+ server asynchronously. + /// Retrieves the information of a smart switch asynchronously. /// - /// The ID of the entity to retrieve information for. - /// Specifies whether to use the raw object or convert it to a custom entity info object. - /// - /// The entity information. - /// If useRawObject is true, it returns an instance of the AppMessage class. - /// If useRawObject is false, it returns a custom entity info object such as SmartSwitchInfo, AlarmInfo, or StorageMonitorInfo. - /// - public async Task GetEntityInfoAsync(uint entityId, bool useRawObject = false) + /// The ID of the smart switch entity. + /// A representing the asynchronous operation. The task result contains a with the smart switch information. + public async Task> GetSmartSwitchInfoAsync(uint entityId) { var request = new AppRequest { EntityId = entityId, GetEntityInfo = new AppEmpty() }; - return await ProcessRequestAsync(request, useRawObject, r => r.Response.EntityInfo.ToEntityInfo()); + return await ProcessRequestAsync(request, r => r.Response.EntityInfo.ToSmartSwitchInfo()); } /// - /// Retrieves information about the Rust+ server asynchronously. + /// Retrieves the information of an alarm asynchronously. /// - /// Specifies whether to use the raw object or convert it to a custom info object. - /// - /// The server information. - /// If useRawObject is true, it returns an instance of the AppMessage class. - /// If useRawObject is false, it returns an ServerInfo. - /// - public async Task GetInfoAsync(bool useRawObject = false) + /// The ID of the alarm entity. + /// A representing the asynchronous operation. The task result contains a with the alarm information. + public async Task> GetAlarmInfoAsync(uint entityId) { var request = new AppRequest { - GetInfo = new AppEmpty() - }; - return await ProcessRequestAsync(request, useRawObject, r => r.Response.Info.ToServerInfo()); - } - - /// - /// Retrieves the map from the Rust+ server asynchronously. - /// - /// Specifies whether to use the raw object or convert it to a custom map object. - /// - /// The map. - /// If useRawObject is true, it returns an instance of the AppMessage class. - /// If useRawObject is false, it returns a MapInfo. - /// - public async Task GetMapAsync(bool useRawObject = false) - { - var request = new AppRequest - { - GetMap = new AppEmpty() - }; - return await ProcessRequestAsync(request, useRawObject, r => r.Response.Map.ToServerMap()); - } - /* - /// - /// Retrieves the map markers from the Rust+ server asynchronously. - /// - /// An optional callback function to handle the response. - /// A task representing the asynchronous operation. - public async Task GetMapMarkersAsync(Func? callback = null) - { - var request = new AppRequest - { - GetMapMarkers = new AppEmpty() - }; - await SendRequestAsync(request, callback); - } - - /// - /// Retrieves the team chat from the Rust+ server asynchronously. - /// - /// An optional callback function to handle the response. - /// A task representing the asynchronous operation. - public async Task GetTeamChatAsync(Func? callback = null) - { - var request = new AppRequest - { - GetTeamChat = new AppEmpty(), - }; - await SendRequestAsync(request, callback); - } - - /// - /// Retrieves team information from the Rust+ server asynchronously. - /// - /// An optional callback function to handle the response. - /// A task representing the asynchronous operation. - public async Task GetTeamInfoAsync(Func? callback = null) - { - var request = new AppRequest - { - GetTeamInfo = new AppEmpty() - }; - await SendRequestAsync(request, callback); - } - - /// - /// Retrieves the current time from the Rust+ server asynchronously. - /// - /// An optional callback function to handle the response. - /// A task representing the asynchronous operation. - public async Task GetTimeAsync(Func? callback = null) - { - var request = new AppRequest - { - GetTime = new AppEmpty() - }; - await SendRequestAsync(request, callback); - } - - /// - /// Retrieves the team chat from the Rust+ server asynchronously. - /// - /// The steam ID of the new group owner - /// An optional callback function to handle the response. - /// A task representing the asynchronous operation. - public async Task PromoteToLeaderAsync(ulong steamId, Func? callback = null) - { - var request = new AppRequest - { - PromoteToLeader = new AppPromoteToLeader - { - SteamId = steamId - } + EntityId = entityId, + GetEntityInfo = new AppEmpty() }; - await SendRequestAsync(request, callback); + return await ProcessRequestAsync(request, r => r.Response.EntityInfo.ToAlarmInfo()); } /// - /// Sends a team message to the Rust+ server asynchronously. + /// Retrieves the information of a storage monitor asynchronously. /// - /// The message to send. - /// An optional callback function to handle the response. - /// A task representing the asynchronous operation. - public async Task SendTeamMessageAsync(string message, Func? callback = null) + /// The ID of the storage monitor entity. + /// A representing the asynchronous operation. The task result contains a with the storage monitor information. + public async Task> GetStorageMonitorInfoAsync(uint entityId) { var request = new AppRequest { - SendTeamMessage = new AppSendMessage - { - Message = message - } + EntityId = entityId, + GetEntityInfo = new AppEmpty() }; - await SendRequestAsync(request, callback); + return await ProcessRequestAsync(request, r => r.Response.EntityInfo.ToStorageMonitorInfo()); } /// - /// Sets the value of an entity asynchronously. + /// Retrieves the server information asynchronously. /// - /// The ID of the entity to set the value for. - /// The value to set. - /// An optional callback function to handle the response. - /// A task representing the asynchronous operation. - public async Task SetEntityValueAsync(int entityId, bool value, Func? callback = null) + /// A representing the asynchronous operation. The task result contains a with the server information. + public async Task> GetInfoAsync() { var request = new AppRequest { - EntityId = (uint)entityId, - SetEntityValue = new AppSetEntityValue - { - Value = value - } + GetInfo = new AppEmpty() }; - await SendRequestAsync(request, callback); + return await ProcessRequestAsync(request, r => r.Response.Info.ToServerInfo()); } /// - /// Toggles the value of an entity repeatedly with a specified timeout. + /// Retrieves the server map asynchronously. /// - /// The ID of the entity to toggle the value for. - /// The timeout in milliseconds between toggling the value. - /// The initial value to set. - /// A task representing the asynchronous operation. - public async Task StrobeAsync(int entityId, int timeoutMilliseconds = 1000, bool value = true) - { - await SetEntityValueAsync(entityId, value); - await Task.Delay(timeoutMilliseconds); - await SetEntityValueAsync(entityId, !value); - } - - public async Task GetClanChatAsync(Func? callback = null) + /// A representing the asynchronous operation. The task result contains a with the server map. + public async Task> GetMapAsync() { var request = new AppRequest { - GetClanChat = new AppEmpty() + GetMap = new AppEmpty() }; - await SendRequestAsync(request, callback); + return await ProcessRequestAsync(request, r => r.Response.Map.ToServerMap()); } - - public async Task GetClanInfoAsync(Func? callback = null) - { - var request = new AppRequest - { - GetClanInfo = new AppEmpty() - }; - await SendRequestAsync(request, callback); - }*/ } } \ No newline at end of file diff --git a/RustPlusApi/RustPlusApi/RustPlusLegacy.cs b/RustPlusApi/RustPlusApi/RustPlusLegacy.cs new file mode 100644 index 0000000..1a3434c --- /dev/null +++ b/RustPlusApi/RustPlusApi/RustPlusLegacy.cs @@ -0,0 +1,366 @@ +using System.Diagnostics; +using System.Net.WebSockets; + +using Google.Protobuf; + +using RustPlusContracts; + +using static System.GC; +// ReSharper disable MemberCanBeProtected.Global +// ReSharper disable MemberCanBePrivate.Global + +namespace RustPlusApi +{ + /// + /// A Rust+ API client made in C#. + /// + /// The IP address of the Rust+ server. + /// The port dedicated for the Rust+ companion app (not the one used to connect in-game). + /// Your Steam ID. + /// Your player token acquired with FCM. + /// Specifies whether to use the Facepunch proxy. + public class RustPlusLegacy(string server, int port, ulong playerId, int playerToken, bool useFacepunchProxy = false) : IDisposable + { + private ClientWebSocket? _webSocket; + private uint _seq; + private readonly Dictionary> _seqCallbacks = []; + + public event EventHandler? Connecting; + public event EventHandler? Connected; + public event EventHandler? MessageReceived; + public event EventHandler? RequestSent; + public event EventHandler? Disconnected; + public event EventHandler? ErrorOccurred; + + /// + /// Connects to the Rust+ server asynchronously. + /// + public async Task ConnectAsync() + { + _webSocket = new ClientWebSocket(); + _webSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(20); + var address = useFacepunchProxy + ? new Uri($"wss://companion-rust.facepunch.com/game/{server}/{port}") + : new Uri($"ws://{server}:{port}"); + + Connecting?.Invoke(this, EventArgs.Empty); + + try + { + await _webSocket.ConnectAsync(address, CancellationToken.None); + Connected?.Invoke(this, EventArgs.Empty); + await ReceiveMessagesAsync(); + } + catch (Exception ex) + { + ErrorOccurred?.Invoke(this, ex); + Dispose(); + } + } + + /// + /// Receives messages from the Rust+ server asynchronously. + /// + /// A task representing the asynchronous operation. + protected async Task ReceiveMessagesAsync() + { + const int bufferSize = 1024; + var buffer = new byte[bufferSize]; + + try + { + while (_webSocket!.State == WebSocketState.Open) + { + var receiveBuffer = new List(); + WebSocketReceiveResult result; + + do + { + result = await _webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + receiveBuffer.AddRange(buffer.Take(result.Count)); + } while (!result.EndOfMessage); + + var messageData = receiveBuffer.ToArray(); + var message = AppMessage.Parser.ParseFrom(messageData); + HandleResponse(message); + } + } + catch (WebSocketException ex) + { + Debug.WriteLine($"Disconnected from the Rust+ socket due to a WebSocketException: {ex}"); + ErrorOccurred?.Invoke(this, ex); + } + catch (Exception ex) + { + Debug.WriteLine($"Disconnected from the Rust+ socket due to an Exception: {ex}"); + ErrorOccurred?.Invoke(this, ex); + } + finally + { + Dispose(); + } + } + + /// + /// Handles the response received from the Rust+ server. + /// + /// The AppMessage received from the server. + protected void HandleResponse(AppMessage message) + { + if (message.Response != null + && message.Response.Seq != 0 + && _seqCallbacks.ContainsKey((int)message.Response.Seq)) + { + var tcs = _seqCallbacks[(int)message.Response.Seq]; + tcs.SetResult(message); + _seqCallbacks.Remove((int)message.Response.Seq); + return; + } + MessageReceived?.Invoke(this, message); + ParseNotification(message.Broadcast); + } + + /// + /// Parses the notification received from the Rust+ server. + /// + /// The AppBroadcast received from the server. + protected virtual void ParseNotification(AppBroadcast? broadcast) { } + + /// + /// Sends a request to the Rust+ server asynchronously. + /// + /// The request to send. + /// A task representing the asynchronous operation. + public async Task SendRequestAsync(AppRequest request) + { + var seq = ++_seq; + var tcs = new TaskCompletionSource(); + _seqCallbacks[(int)seq] = tcs; + + request.Seq = seq; + request.PlayerId = playerId; + request.PlayerToken = playerToken; + + var requestData = request.ToByteArray(); + var buffer = new ArraySegment(requestData); + await _webSocket!.SendAsync(buffer, WebSocketMessageType.Binary, true, CancellationToken.None); + RequestSent?.Invoke(this, request); + + return await tcs.Task; + } + + /// + /// Disposes the Rust+ API client and disconnects from the Rust+ server. + /// + public void Dispose() + { + if (_webSocket is not { State: WebSocketState.Open }) return; + + _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Connection closed by client.", CancellationToken.None).Wait(); + _webSocket.Dispose(); + + Disconnected?.Invoke(this, EventArgs.Empty); + + SuppressFinalize(this); + } + + /// + /// Checks if the client is connected to the Rust+ socket. + /// + /// True if the client is connected; otherwise, false. + public bool IsConnected() => _webSocket is { State: WebSocketState.Open }; + + /// + /// Checks if the given response is an error. + /// + /// The AppMessage response to check. + /// True if the response is an error; otherwise, false. + protected static bool IsError(AppMessage response) => response.Response.Error is not null; + + /// + /// Retrieves information about an entity from the Rust+ server asynchronously. + /// + /// The ID of the entity to retrieve information for. + /// The entity information. + public async Task GetEntityInfoLegacyAsync(uint entityId) + { + var request = new AppRequest + { + EntityId = entityId, + GetEntityInfo = new AppEmpty() + }; + return await SendRequestAsync(request); + } + + /// + /// Retrieves the information from the Rust+ server asynchronously. + /// + /// The information. + public async Task GetInfoLegacyAsync() + { + var request = new AppRequest + { + GetInfo = new AppEmpty() + }; + return await SendRequestAsync(request); + } + + /// + /// Retrieves the map from the Rust+ server asynchronously. + /// + /// The map. + public async Task GetMapLegacyAsync() + { + var request = new AppRequest + { + GetMap = new AppEmpty() + }; + return await SendRequestAsync(request); + } + + /* + /// + /// Retrieves the map markers from the Rust+ server asynchronously. + /// + /// An optional callback function to handle the response. + /// A task representing the asynchronous operation. + public async Task GetMapMarkersAsync(Func? callback = null) + { + var request = new AppRequest + { + GetMapMarkers = new AppEmpty() + }; + await SendRequestAsync(request, callback); + } + + /// + /// Retrieves the team chat from the Rust+ server asynchronously. + /// + /// An optional callback function to handle the response. + /// A task representing the asynchronous operation. + public async Task GetTeamChatAsync(Func? callback = null) + { + var request = new AppRequest + { + GetTeamChat = new AppEmpty(), + }; + await SendRequestAsync(request, callback); + } + + /// + /// Retrieves team information from the Rust+ server asynchronously. + /// + /// An optional callback function to handle the response. + /// A task representing the asynchronous operation. + public async Task GetTeamInfoAsync(Func? callback = null) + { + var request = new AppRequest + { + GetTeamInfo = new AppEmpty() + }; + await SendRequestAsync(request, callback); + } + + /// + /// Retrieves the current time from the Rust+ server asynchronously. + /// + /// An optional callback function to handle the response. + /// A task representing the asynchronous operation. + public async Task GetTimeAsync(Func? callback = null) + { + var request = new AppRequest + { + GetTime = new AppEmpty() + }; + await SendRequestAsync(request, callback); + } + + /// + /// Retrieves the team chat from the Rust+ server asynchronously. + /// + /// The steam ID of the new group owner + /// An optional callback function to handle the response. + /// A task representing the asynchronous operation. + public async Task PromoteToLeaderAsync(ulong steamId, Func? callback = null) + { + var request = new AppRequest + { + PromoteToLeader = new AppPromoteToLeader + { + SteamId = steamId + } + }; + await SendRequestAsync(request, callback); + } + + /// + /// Sends a team message to the Rust+ server asynchronously. + /// + /// The message to send. + /// An optional callback function to handle the response. + /// A task representing the asynchronous operation. + public async Task SendTeamMessageAsync(string message, Func? callback = null) + { + var request = new AppRequest + { + SendTeamMessage = new AppSendMessage + { + Message = message + } + }; + await SendRequestAsync(request, callback); + } + + /// + /// Sets the value of an entity asynchronously. + /// + /// The ID of the entity to set the value for. + /// The value to set. + /// An optional callback function to handle the response. + /// A task representing the asynchronous operation. + public async Task SetEntityValueAsync(int entityId, bool value, Func? callback = null) + { + var request = new AppRequest + { + EntityId = (uint)entityId, + SetEntityValue = new AppSetEntityValue + { + Value = value + } + }; + await SendRequestAsync(request, callback); + } + + /// + /// Toggles the value of an entity repeatedly with a specified timeout. + /// + /// The ID of the entity to toggle the value for. + /// The timeout in milliseconds between toggling the value. + /// The initial value to set. + /// A task representing the asynchronous operation. + public async Task StrobeAsync(int entityId, int timeoutMilliseconds = 1000, bool value = true) + { + await SetEntityValueAsync(entityId, value); + await Task.Delay(timeoutMilliseconds); + await SetEntityValueAsync(entityId, !value); + } + + public async Task GetClanChatAsync(Func? callback = null) + { + var request = new AppRequest + { + GetClanChat = new AppEmpty() + }; + await SendRequestAsync(request, callback); + } + + public async Task GetClanInfoAsync(Func? callback = null) + { + var request = new AppRequest + { + GetClanInfo = new AppEmpty() + }; + await SendRequestAsync(request, callback); + }*/ + } +} diff --git a/RustPlusApi/RustPlusApi/Utils/ResponseHelper.cs b/RustPlusApi/RustPlusApi/Utils/ResponseHelper.cs new file mode 100644 index 0000000..2ae28ef --- /dev/null +++ b/RustPlusApi/RustPlusApi/Utils/ResponseHelper.cs @@ -0,0 +1,17 @@ +using RustPlusApi.Data; + +namespace RustPlusApi.Utils +{ + public static class ResponseHelper + { + public static Response BuildGenericOutput(bool isSuccess, T data, string? message = null) + { + return new Response + { + IsSuccess = isSuccess, + Error = message is null ? null : new Error { Message = message }, + Data = data + }; + } + } +}