mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-16 14:30:31 +00:00
Compare commits
130 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fa23ecddf | ||
|
|
ab3bfe2460 | ||
|
|
465ca2d4f9 | ||
|
|
21e892c042 | ||
|
|
98be9e1efd | ||
|
|
3081bfe814 | ||
|
|
61e4461bc4 | ||
|
|
5c2bcd551c | ||
|
|
15f9eb4e80 | ||
|
|
5038527c90 | ||
|
|
e8370987ea | ||
|
|
3f7660526d | ||
|
|
f484b50ab3 | ||
|
|
55000c7653 | ||
|
|
4cd2444a1a | ||
|
|
4f23d2e874 | ||
|
|
76bdd898e1 | ||
|
|
a45cf02d52 | ||
|
|
828c76e201 | ||
|
|
32e68f2be3 | ||
|
|
de3f3cd93b | ||
|
|
31fb6fec08 | ||
|
|
cf2473a3d5 | ||
|
|
0d44379948 | ||
|
|
43264e77b2 | ||
|
|
c09af9b937 | ||
|
|
c84565f091 | ||
|
|
d07f1c6852 | ||
|
|
754b52647b | ||
|
|
9f4ed24704 | ||
|
|
015c6b7bdf | ||
|
|
a17c1fc35a | ||
|
|
19e46ce78d | ||
|
|
cf6ee3b60d | ||
|
|
488003993f | ||
|
|
c64a6fabbc | ||
|
|
eb2751861d | ||
|
|
48a1cf1189 | ||
|
|
98e1d51a48 | ||
|
|
5e22c832a2 | ||
|
|
6523b30f10 | ||
|
|
8fefa7c5af | ||
|
|
b6a5b8942c | ||
|
|
cd622989d6 | ||
|
|
8251274bf8 | ||
|
|
dd63c97ced | ||
|
|
b17960096e | ||
|
|
83934af041 | ||
|
|
0421da30cd | ||
|
|
bf084a1ffb | ||
|
|
f3868b9acc | ||
|
|
7c3d195fd4 | ||
|
|
4d7294feac | ||
|
|
6877abed6e | ||
|
|
5353d755a0 | ||
|
|
d2dff449d1 | ||
|
|
d526c6c1ce | ||
|
|
49fc908f0f | ||
|
|
b3162ce390 | ||
|
|
9a2a37f2fc | ||
|
|
a90b3afcdd | ||
|
|
6c903b2433 | ||
|
|
00558441fe | ||
|
|
7e10e6ba81 | ||
|
|
3995b3a083 | ||
|
|
e6c9c3f0a9 | ||
|
|
c8fc25111e | ||
|
|
6b3cf5e788 | ||
|
|
afbd8d12b4 | ||
|
|
e8e393b320 | ||
|
|
84db370516 | ||
|
|
173148ce25 | ||
|
|
0fd0528fd0 | ||
|
|
664a0e0758 | ||
|
|
6454e3ee12 | ||
|
|
33f4a82dd5 | ||
|
|
9bd6532411 | ||
|
|
b89d2977f8 | ||
|
|
25b557d5d1 | ||
|
|
3e34fabfaf | ||
|
|
fc49e8ffa7 | ||
|
|
48a5eeec29 | ||
|
|
7fa176ef7b | ||
|
|
bfaa99a8a9 | ||
|
|
1ff4ed026e | ||
|
|
1703bbfb68 | ||
|
|
a6a2e1605d | ||
|
|
c0c61913c2 | ||
|
|
fb2437d75d | ||
|
|
499e55c473 | ||
|
|
dfd4513b16 | ||
|
|
f873da7236 | ||
|
|
59360c5b60 | ||
|
|
750c34189a | ||
|
|
7c3f5beb3a | ||
|
|
8dfe095dae | ||
|
|
53022632e0 | ||
|
|
29a916e5ad | ||
|
|
44b3a518bd | ||
|
|
1fe60e7037 | ||
|
|
27ad98492f | ||
|
|
e3386c5b29 | ||
|
|
021ac470d3 | ||
|
|
b4fb0bf9a6 | ||
|
|
b63dd1035c | ||
|
|
f577e1a6cb | ||
|
|
34ffb975b6 | ||
|
|
5a3b132d5e | ||
|
|
ef29b6f33d | ||
|
|
e8335ac183 | ||
|
|
90339fb276 | ||
|
|
88759303dd | ||
|
|
befe01ca59 | ||
|
|
c9cc728da3 | ||
|
|
a81a59396d | ||
|
|
df3fcfb1df | ||
|
|
e097b33d89 | ||
|
|
db6e775b10 | ||
|
|
b53c41a0f9 | ||
|
|
fec4873843 | ||
|
|
1e2efe38f1 | ||
|
|
3e0dfac091 | ||
|
|
36d745aece | ||
|
|
7896e7924e | ||
|
|
5b3c730d51 | ||
|
|
f3aee0c34f | ||
|
|
47389f67b8 | ||
|
|
19e72c93c1 | ||
|
|
164240641b | ||
|
|
337c397505 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,9 +2,10 @@
|
||||
## ArchiSteamFarm
|
||||
#################
|
||||
|
||||
# Ignore all config files, apart from example.xml
|
||||
# Ignore all config files, apart from ones we want to include
|
||||
ArchiSteamFarm/config/*
|
||||
!ArchiSteamFarm/config/example.xml
|
||||
!ArchiSteamFarm/config/minimal.xml
|
||||
|
||||
#################
|
||||
## Eclipse
|
||||
|
||||
@@ -5,6 +5,8 @@ VisualStudioVersion = 14.0.23107.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchiSteamFarm", "ArchiSteamFarm\ArchiSteamFarm.csproj", "{35AF7887-08B9-40E8-A5EA-797D8B60B30C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SteamAuth", "SteamAuth\SteamAuth.csproj", "{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -15,6 +17,10 @@ Global
|
||||
{35AF7887-08B9-40E8-A5EA-797D8B60B30C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{35AF7887-08B9-40E8-A5EA-797D8B60B30C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{35AF7887-08B9-40E8-A5EA-797D8B60B30C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
||||
@@ -24,15 +24,27 @@
|
||||
|
||||
using SteamKit2;
|
||||
using SteamKit2.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal sealed class ArchiHandler : ClientMsgHandler {
|
||||
internal sealed class OfflineMessageCallback : CallbackMsg {
|
||||
internal uint OfflineMessages { get; private set; }
|
||||
internal List<uint> Users { get; private set; }
|
||||
internal OfflineMessageCallback(CMsgClientOfflineMessageNotification body) {
|
||||
OfflineMessages = body.offline_messages;
|
||||
Users = body.friends_with_offline_messages;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class PurchaseResponseCallback : CallbackMsg {
|
||||
internal enum EPurchaseResult {
|
||||
Unknown = -1,
|
||||
OK = 0,
|
||||
AlreadyOwned = 9,
|
||||
RegionLockedKey = 13,
|
||||
InvalidKey = 14,
|
||||
DuplicatedKey = 15,
|
||||
BaseGameRequired = 24,
|
||||
@@ -41,14 +53,22 @@ namespace ArchiSteamFarm {
|
||||
|
||||
internal EResult Result { get; private set; }
|
||||
internal EPurchaseResult PurchaseResult { get; private set; }
|
||||
internal int ErrorCode { get; private set; }
|
||||
internal byte[] ReceiptInfo { get; private set; }
|
||||
internal KeyValue ReceiptInfo { get; private set; } = new KeyValue();
|
||||
internal Dictionary<uint, string> Items { get; private set; } = new Dictionary<uint, string>();
|
||||
|
||||
internal PurchaseResponseCallback(CMsgClientPurchaseResponse body) {
|
||||
Result = (EResult) body.eresult;
|
||||
ErrorCode = body.purchase_result_details;
|
||||
ReceiptInfo = body.purchase_receipt_info;
|
||||
PurchaseResult = (EPurchaseResult) ErrorCode;
|
||||
PurchaseResult = (EPurchaseResult) body.purchase_result_details;
|
||||
|
||||
using (MemoryStream ms = new MemoryStream(body.purchase_receipt_info)) {
|
||||
if (!ReceiptInfo.TryReadAsBinary(ms)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (KeyValue lineItem in ReceiptInfo["lineitems"].Children) {
|
||||
Items.Add((uint) lineItem["PackageID"].AsUnsignedLong(), lineItem["ItemDescription"].AsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,14 +99,30 @@ namespace ArchiSteamFarm {
|
||||
Client.Send(request);
|
||||
}
|
||||
|
||||
internal void PlayGames(params ulong[] gameIDs) {
|
||||
internal void PlayGames(params uint[] gameIDs) {
|
||||
var request = new ClientMsgProtobuf<CMsgClientGamesPlayed>(EMsg.ClientGamesPlayed);
|
||||
foreach (ulong gameID in gameIDs) {
|
||||
if (gameID != 0) {
|
||||
request.Body.games_played.Add(new CMsgClientGamesPlayed.GamePlayed {
|
||||
game_id = new GameID(gameID),
|
||||
});
|
||||
foreach (uint gameID in gameIDs) {
|
||||
if (gameID == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
request.Body.games_played.Add(new CMsgClientGamesPlayed.GamePlayed {
|
||||
game_id = new GameID(gameID),
|
||||
});
|
||||
}
|
||||
Client.Send(request);
|
||||
}
|
||||
|
||||
internal void PlayGames(ICollection<uint> gameIDs) {
|
||||
var request = new ClientMsgProtobuf<CMsgClientGamesPlayed>(EMsg.ClientGamesPlayed);
|
||||
foreach (uint gameID in gameIDs) {
|
||||
if (gameID == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
request.Body.games_played.Add(new CMsgClientGamesPlayed.GamePlayed {
|
||||
game_id = new GameID(gameID),
|
||||
});
|
||||
}
|
||||
Client.Send(request);
|
||||
}
|
||||
@@ -99,24 +135,46 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
public sealed override void HandleMsg(IPacketMsg packetMsg) {
|
||||
if (packetMsg != null) {
|
||||
switch (packetMsg.MsgType) {
|
||||
case EMsg.ClientPurchaseResponse:
|
||||
HandlePurchaseResponse(packetMsg);
|
||||
break;
|
||||
case EMsg.ClientUserNotifications:
|
||||
HandleUserNotifications(packetMsg);
|
||||
break;
|
||||
}
|
||||
if (packetMsg == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (packetMsg.MsgType) {
|
||||
case EMsg.ClientFSOfflineMessageNotification:
|
||||
HandleFSOfflineMessageNotification(packetMsg);
|
||||
break;
|
||||
case EMsg.ClientPurchaseResponse:
|
||||
HandlePurchaseResponse(packetMsg);
|
||||
break;
|
||||
case EMsg.ClientUserNotifications:
|
||||
HandleUserNotifications(packetMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleFSOfflineMessageNotification(IPacketMsg packetMsg) {
|
||||
if (packetMsg == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var response = new ClientMsgProtobuf<CMsgClientOfflineMessageNotification>(packetMsg);
|
||||
Client.PostCallback(new OfflineMessageCallback(response.Body));
|
||||
}
|
||||
|
||||
private void HandlePurchaseResponse(IPacketMsg packetMsg) {
|
||||
if (packetMsg == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var response = new ClientMsgProtobuf<CMsgClientPurchaseResponse>(packetMsg);
|
||||
Client.PostCallback(new PurchaseResponseCallback(response.Body));
|
||||
}
|
||||
|
||||
private void HandleUserNotifications(IPacketMsg packetMsg) {
|
||||
if (packetMsg == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var response = new ClientMsgProtobuf<CMsgClientUserNotifications>(packetMsg);
|
||||
foreach (var notification in response.Body.notifications) {
|
||||
Client.PostCallback(new NotificationCallback(notification));
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ArchiSteamFarm</RootNamespace>
|
||||
<AssemblyName>ArchiSteamFarm</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
@@ -26,6 +26,7 @@
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -50,25 +51,30 @@
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>cirno.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\HtmlAgilityPack.1.4.9\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.8.0.1-beta1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<HintPath>..\packages\Newtonsoft.Json.8.0.1-beta3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="protobuf-net, Version=2.0.0.668, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\protobuf-net.2.0.0.668\lib\net40\protobuf-net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SteamKit2, Version=1.6.5.29095, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SteamKit2.1.6.5\lib\net40\SteamKit2.dll</HintPath>
|
||||
<Reference Include="SteamKit2, Version=1.7.0.33680, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SteamKit2.1.7.0\lib\net45\SteamKit2.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
@@ -94,6 +100,7 @@
|
||||
<Compile Include="SteamTradeOffer.cs" />
|
||||
<Compile Include="Trading.cs" />
|
||||
<Compile Include="Utilities.cs" />
|
||||
<Compile Include="WebBrowser.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
@@ -113,22 +120,32 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="cirno.ico" />
|
||||
<Content Include="config\example.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="config\minimal.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SteamAuth\SteamAuth.csproj">
|
||||
<Project>{5ad0934e-f6c4-4ae5-83af-c788313b2a87}</Project>
|
||||
<Name>SteamAuth</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent Condition=" '$(OS)' != 'Unix' ">(robocopy $(ProjectDir)config $(TargetDir)config /S /E) ^& IF %25ERRORLEVEL%25 GEQ 2 exit 0
|
||||
|
||||
if $(ConfigurationName) == Release (
|
||||
mkdir "$(TargetDir)out" "$(TargetDir)out\config"
|
||||
copy "$(TargetDir)config\example.xml" "$(TargetDir)out\config"
|
||||
"$(SolutionDir)tools\ILMerge.exe" /out:"$(TargetDir)out\ASF.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards
|
||||
del "$(TargetDir)out\ASF.pdb"
|
||||
)</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent Condition=" '$(OS)' != 'Unix' ">if $(ConfigurationName) == Release (
|
||||
mkdir "$(TargetDir)out" "$(TargetDir)out\config"
|
||||
copy "$(TargetDir)config\example.xml" "$(TargetDir)out\config"
|
||||
copy "$(TargetDir)config\minimal.xml" "$(TargetDir)out\config"
|
||||
"$(SolutionDir)tools\ILMerge.exe" /ndebug /internalize /out:"$(TargetDir)out\ASF.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2" /wildcards
|
||||
)</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -33,14 +33,15 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal class ArchiWebHandler {
|
||||
private const int Timeout = 1000 * 15; // In miliseconds
|
||||
internal sealed class ArchiWebHandler {
|
||||
private const int Timeout = 1000 * WebBrowser.HttpTimeout; // In miliseconds
|
||||
|
||||
private readonly Bot Bot;
|
||||
private readonly string ApiKey;
|
||||
private readonly Dictionary<string, string> SteamCookieDictionary = new Dictionary<string, string>();
|
||||
|
||||
private ulong SteamID;
|
||||
private string VanityURL;
|
||||
private readonly Dictionary<string, string> SteamCookieDictionary = new Dictionary<string, string>();
|
||||
|
||||
// This is required because home_process request must be done on final URL
|
||||
private string GetHomeProcess() {
|
||||
@@ -53,6 +54,41 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UnlockParentalAccount(string parentalPin) {
|
||||
if (string.IsNullOrEmpty(parentalPin) || parentalPin.Equals("0")) {
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo(Bot.BotName, "Unlocking parental account...");
|
||||
Dictionary<string, string> postData = new Dictionary<string, string>() {
|
||||
{ "pin", parentalPin }
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await WebBrowser.UrlPost("https://steamcommunity.com/parental/ajaxunlock", postData, SteamCookieDictionary, "https://steamcommunity.com/").ConfigureAwait(false);
|
||||
if (response == null) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
IEnumerable<string> setCookieValues;
|
||||
if (!response.Headers.TryGetValues("Set-Cookie", out setCookieValues)) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string setCookieValue in setCookieValues) {
|
||||
if (setCookieValue.Contains("steamparental=")) {
|
||||
string setCookie = setCookieValue.Substring(setCookieValue.IndexOf("steamparental=") + 14);
|
||||
setCookie = setCookie.Substring(0, setCookie.IndexOf(';'));
|
||||
SteamCookieDictionary.Add("steamparental", setCookie);
|
||||
Logging.LogGenericInfo(Bot.BotName, "Success!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo(Bot.BotName, "Failed!");
|
||||
}
|
||||
|
||||
internal ArchiWebHandler(Bot bot, string apiKey) {
|
||||
Bot = bot;
|
||||
|
||||
@@ -124,31 +160,32 @@ namespace ArchiSteamFarm {
|
||||
SteamCookieDictionary.Add("steamLoginSecure", steamLoginSecure);
|
||||
SteamCookieDictionary.Add("birthtime", "-473356799"); // ( ͡° ͜ʖ ͡°)
|
||||
|
||||
if (!string.IsNullOrEmpty(parentalPin) && !parentalPin.Equals("0")) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Unlocking parental account...");
|
||||
Dictionary<string, string> postData = new Dictionary<string, string>() {
|
||||
{"pin", parentalPin}
|
||||
};
|
||||
await UnlockParentalAccount(parentalPin).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
HttpResponseMessage response = await Utilities.UrlPostRequestWithResponse("https://steamcommunity.com/parental/ajaxunlock", postData, SteamCookieDictionary, "https://steamcommunity.com/").ConfigureAwait(false);
|
||||
if (response != null && response.IsSuccessStatusCode) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Success!");
|
||||
|
||||
var setCookieValues = response.Headers.GetValues("Set-Cookie");
|
||||
foreach (string setCookieValue in setCookieValues) {
|
||||
if (setCookieValue.Contains("steamparental=")) {
|
||||
string setCookie = setCookieValue.Substring(setCookieValue.IndexOf("steamparental=") + 14);
|
||||
setCookie = setCookie.Substring(0, setCookie.IndexOf(';'));
|
||||
SteamCookieDictionary.Add("steamparental", setCookie);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Failed!");
|
||||
}
|
||||
internal async Task<bool?> IsLoggedIn() {
|
||||
if (SteamID == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Bot.Trading.CheckTrades();
|
||||
HtmlDocument htmlDocument = await WebBrowser.UrlGetToHtmlDocument("http://steamcommunity.com/my/profile", SteamCookieDictionary).ConfigureAwait(false);
|
||||
if (htmlDocument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//span[@id='account_pulldown']");
|
||||
return htmlNode != null;
|
||||
}
|
||||
|
||||
internal async Task<bool> ReconnectIfNeeded() {
|
||||
bool? isLoggedIn = await IsLoggedIn().ConfigureAwait(false);
|
||||
if (isLoggedIn.HasValue && !isLoggedIn.Value) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Reconnecting because our sessionID expired!");
|
||||
var restart = Task.Run(async () => await Bot.Restart().ConfigureAwait(false));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal List<SteamTradeOffer> GetTradeOffers() {
|
||||
@@ -191,7 +228,9 @@ namespace ArchiSteamFarm {
|
||||
is_our_offer = trade["is_our_offer"].AsBoolean(),
|
||||
time_created = trade["time_created"].AsInteger(),
|
||||
time_updated = trade["time_updated"].AsInteger(),
|
||||
from_real_time_trade = trade["from_real_time_trade"].AsBoolean()
|
||||
from_real_time_trade = trade["from_real_time_trade"].AsBoolean(),
|
||||
escrow_end_date = trade["escrow_end_date"].AsInteger(),
|
||||
confirmation_method = (SteamTradeOffer.ETradeOfferConfirmationMethod) trade["confirmation_method"].AsInteger()
|
||||
};
|
||||
foreach (KeyValue item in trade["items_to_give"].Children) {
|
||||
tradeOffer.items_to_give.Add(new SteamItem {
|
||||
@@ -240,7 +279,7 @@ namespace ArchiSteamFarm {
|
||||
{"action", "join"}
|
||||
};
|
||||
|
||||
await Utilities.UrlPostRequest(request, postData, SteamCookieDictionary).ConfigureAwait(false);
|
||||
await WebBrowser.UrlPost(request, postData, SteamCookieDictionary).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal async Task LeaveClan(ulong clanID) {
|
||||
@@ -259,7 +298,8 @@ namespace ArchiSteamFarm {
|
||||
{"action", "leaveGroup"},
|
||||
{"groupId", clanID.ToString()}
|
||||
};
|
||||
await Utilities.UrlPostRequest(request, postData, SteamCookieDictionary).ConfigureAwait(false);
|
||||
|
||||
await WebBrowser.UrlPost(request, postData, SteamCookieDictionary).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal async Task<bool> AcceptTradeOffer(ulong tradeID) {
|
||||
@@ -281,7 +321,11 @@ namespace ArchiSteamFarm {
|
||||
{"tradeofferid", tradeID.ToString()}
|
||||
};
|
||||
|
||||
HttpResponseMessage result = await Utilities.UrlPostRequestWithResponse(request, postData, SteamCookieDictionary, referer).ConfigureAwait(false);
|
||||
HttpResponseMessage result = await WebBrowser.UrlPost(request, postData, SteamCookieDictionary, referer).ConfigureAwait(false);
|
||||
if (result == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = result.IsSuccessStatusCode;
|
||||
|
||||
if (!success) {
|
||||
@@ -333,7 +377,7 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Utilities.UrlToHtmlDocument("http://steamcommunity.com/profiles/" + SteamID + "/badges?p=" + page, SteamCookieDictionary).ConfigureAwait(false);
|
||||
return await WebBrowser.UrlGetToHtmlDocument("http://steamcommunity.com/profiles/" + SteamID + "/badges?p=" + page, SteamCookieDictionary).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal async Task<HtmlDocument> GetGameCardsPage(ulong appID) {
|
||||
@@ -341,7 +385,7 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Utilities.UrlToHtmlDocument("http://steamcommunity.com/profiles/" + SteamID + "/gamecards/" + appID, SteamCookieDictionary).ConfigureAwait(false);
|
||||
return await WebBrowser.UrlGetToHtmlDocument("http://steamcommunity.com/profiles/" + SteamID + "/gamecards/" + appID, SteamCookieDictionary).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
777
ArchiSteamFarm/Bot.cs
Normal file → Executable file
777
ArchiSteamFarm/Bot.cs
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@@ -27,28 +27,21 @@ using SteamKit2.Internal;
|
||||
using System.IO;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
/// <summary>
|
||||
/// Message used to Accept or Decline a group(clan) invite.
|
||||
/// </summary>
|
||||
internal sealed class CMsgClientClanInviteAction : ISteamSerializableMessage, ISteamSerializable {
|
||||
EMsg ISteamSerializableMessage.GetEMsg() {
|
||||
return EMsg.ClientAcknowledgeClanInvite;
|
||||
}
|
||||
|
||||
public CMsgClientClanInviteAction() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Group invited to.
|
||||
/// </summary>
|
||||
internal ulong GroupID = 0;
|
||||
|
||||
/// <summary>
|
||||
/// To accept or decline the invite.
|
||||
/// </summary>
|
||||
internal bool AcceptInvite = true;
|
||||
|
||||
public CMsgClientClanInviteAction() { }
|
||||
|
||||
void ISteamSerializable.Serialize(Stream stream) {
|
||||
if (stream == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
BinaryWriter binaryWriter = new BinaryWriter(stream);
|
||||
binaryWriter.Write(GroupID);
|
||||
@@ -59,6 +52,10 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
void ISteamSerializable.Deserialize(Stream stream) {
|
||||
if (stream == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
BinaryReader binaryReader = new BinaryReader(stream);
|
||||
GroupID = binaryReader.ReadUInt64();
|
||||
|
||||
302
ArchiSteamFarm/CardsFarmer.cs
Normal file → Executable file
302
ArchiSteamFarm/CardsFarmer.cs
Normal file → Executable file
@@ -23,27 +23,121 @@
|
||||
*/
|
||||
|
||||
using HtmlAgilityPack;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal class CardsFarmer {
|
||||
internal sealed class CardsFarmer {
|
||||
private const byte StatusCheckSleep = 5; // In minutes, how long to wait before checking the appID again
|
||||
private const ushort MaxFarmingTime = 600; // In minutes, how long ASF is allowed to farm one game in solo mode
|
||||
|
||||
private readonly ManualResetEvent FarmResetEvent = new ManualResetEvent(false);
|
||||
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
|
||||
private readonly Bot Bot;
|
||||
|
||||
private volatile bool NowFarming = false;
|
||||
private readonly Bot Bot;
|
||||
private readonly Timer Timer;
|
||||
|
||||
internal readonly ConcurrentDictionary<uint, double> GamesToFarm = new ConcurrentDictionary<uint, double>();
|
||||
internal readonly List<uint> CurrentGamesFarming = new List<uint>();
|
||||
|
||||
private bool NowFarming = false;
|
||||
|
||||
internal CardsFarmer(Bot bot) {
|
||||
Bot = bot;
|
||||
|
||||
Timer = new Timer(
|
||||
async e => await CheckGamesForFarming().ConfigureAwait(false),
|
||||
null,
|
||||
TimeSpan.FromMinutes(15), // Delay
|
||||
TimeSpan.FromMinutes(15) // Period
|
||||
);
|
||||
}
|
||||
|
||||
internal static List<uint> GetGamesToFarmSolo(ConcurrentDictionary<uint, double> gamesToFarm) {
|
||||
if (gamesToFarm == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<uint> result = new List<uint>();
|
||||
foreach (KeyValuePair<uint, double> keyValue in gamesToFarm) {
|
||||
if (keyValue.Value >= 2) {
|
||||
result.Add(keyValue.Key);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static uint GetAnyGameToFarm(ConcurrentDictionary<uint, double> gamesToFarm) {
|
||||
if (gamesToFarm == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach (uint appID in gamesToFarm.Keys) {
|
||||
return appID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal bool FarmMultiple() {
|
||||
if (GamesToFarm.Count == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
double maxHour = -1;
|
||||
|
||||
foreach (double hour in GamesToFarm.Values) {
|
||||
if (hour > maxHour) {
|
||||
maxHour = hour;
|
||||
}
|
||||
}
|
||||
|
||||
CurrentGamesFarming.Clear();
|
||||
foreach (uint appID in GamesToFarm.Keys) {
|
||||
CurrentGamesFarming.Add(appID);
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo(Bot.BotName, "Now farming: " + string.Join(", ", GamesToFarm.Keys));
|
||||
if (Farm(maxHour, GamesToFarm.Keys)) {
|
||||
CurrentGamesFarming.Clear();
|
||||
return true;
|
||||
} else {
|
||||
CurrentGamesFarming.Clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<bool> FarmSolo(uint appID) {
|
||||
if (appID == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CurrentGamesFarming.Clear();
|
||||
CurrentGamesFarming.Add(appID);
|
||||
|
||||
Logging.LogGenericInfo(Bot.BotName, "Now farming: " + appID);
|
||||
if (await Farm(appID).ConfigureAwait(false)) {
|
||||
double hours;
|
||||
GamesToFarm.TryRemove(appID, out hours);
|
||||
return true;
|
||||
} else {
|
||||
CurrentGamesFarming.Clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task RestartFarming() {
|
||||
await StopFarming().ConfigureAwait(false);
|
||||
await StartFarming().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal async Task StartFarming() {
|
||||
await StopFarming().ConfigureAwait(false);
|
||||
|
||||
await Semaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
if (NowFarming) {
|
||||
@@ -51,12 +145,17 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
if (await Bot.ArchiWebHandler.ReconnectIfNeeded().ConfigureAwait(false)) {
|
||||
Semaphore.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo(Bot.BotName, "Checking badges...");
|
||||
|
||||
// Find the number of badge pages
|
||||
HtmlDocument badgesDocument = await Bot.ArchiWebHandler.GetBadgePage(1).ConfigureAwait(false);
|
||||
if (badgesDocument == null) {
|
||||
Logging.LogGenericWarning(Bot.BotName, "Could not get badges information, farming is stopped!");
|
||||
Logging.LogGenericWarning(Bot.BotName, "Could not get badges information, will try again later!");
|
||||
Semaphore.Release();
|
||||
return;
|
||||
}
|
||||
@@ -68,7 +167,6 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// Find APPIDs we need to farm
|
||||
List<uint> appIDs = new List<uint>();
|
||||
for (var page = 1; page <= maxPages; page++) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Checking page: " + page + "/" + maxPages);
|
||||
|
||||
@@ -84,38 +182,115 @@ namespace ArchiSteamFarm {
|
||||
continue;
|
||||
}
|
||||
|
||||
GamesToFarm.Clear();
|
||||
foreach (HtmlNode badgesPageNode in badgesPageNodes) {
|
||||
string steamLink = badgesPageNode.GetAttributeValue("href", null);
|
||||
if (steamLink == null) {
|
||||
Logging.LogGenericError(Bot.BotName, "Couldn't get steamLink for one of the games: " + badgesPageNode.OuterHtml);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint appID = (uint) Utilities.OnlyNumbers(steamLink);
|
||||
if (appID == 0) {
|
||||
Logging.LogGenericError(Bot.BotName, "Couldn't get appID for one of the games: " + badgesPageNode.OuterHtml);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Bot.Blacklist.Contains(appID)) {
|
||||
if (Bot.GlobalBlacklist.Contains(appID) || Bot.Blacklist.Contains(appID)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
appIDs.Add(appID);
|
||||
// We assume that every game has at least 2 hours played, until we actually check them
|
||||
GamesToFarm.AddOrUpdate(appID, 2, (key, value) => 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Start farming
|
||||
while (appIDs.Count > 0) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Farming in progress...");
|
||||
uint appID = appIDs[0];
|
||||
if (await Farm(appID).ConfigureAwait(false)) {
|
||||
appIDs.Remove(appID);
|
||||
} else {
|
||||
return;
|
||||
// If we have restricted card drops, actually do check all games that are left to farm
|
||||
if (Bot.CardDropsRestricted) {
|
||||
foreach (uint appID in GamesToFarm.Keys) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Checking hours of appID: " + appID);
|
||||
HtmlDocument appPage = await Bot.ArchiWebHandler.GetGameCardsPage(appID).ConfigureAwait(false);
|
||||
if (appPage == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HtmlNode appNode = appPage.DocumentNode.SelectSingleNode("//div[@class='badge_title_stats_playtime']");
|
||||
if (appNode == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string hoursString = appNode.InnerText;
|
||||
if (string.IsNullOrEmpty(hoursString)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hoursString = Regex.Match(hoursString, @"[0-9\.,]+").Value;
|
||||
double hours;
|
||||
|
||||
if (string.IsNullOrEmpty(hoursString)) {
|
||||
hours = 0;
|
||||
} else {
|
||||
hours = double.Parse(hoursString, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
GamesToFarm[appID] = hours;
|
||||
}
|
||||
}
|
||||
|
||||
if (GamesToFarm.Count == 0) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "No games to farm!");
|
||||
Semaphore.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo(Bot.BotName, "Farming in progress...");
|
||||
|
||||
NowFarming = true;
|
||||
Semaphore.Release(); // From this point we allow other calls to shut us down
|
||||
|
||||
// Now the algorithm used for farming depends on whether account is restricted or not
|
||||
if (Bot.CardDropsRestricted) {
|
||||
// If we have restricted card drops, we use complex algorithm, which prioritizes farming solo titles >= 2 hours, then all at once, until any game hits mentioned 2 hours
|
||||
Logging.LogGenericInfo(Bot.BotName, "Chosen farming algorithm: Complex");
|
||||
while (GamesToFarm.Count > 0) {
|
||||
List<uint> gamesToFarmSolo = GetGamesToFarmSolo(GamesToFarm);
|
||||
if (gamesToFarmSolo.Count > 0) {
|
||||
while (gamesToFarmSolo.Count > 0) {
|
||||
uint appID = gamesToFarmSolo[0];
|
||||
bool success = await FarmSolo(appID).ConfigureAwait(false);
|
||||
if (success) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Done farming: " + appID);
|
||||
gamesToFarmSolo.Remove(appID);
|
||||
} else {
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool success = FarmMultiple();
|
||||
if (success) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Done farming: " + string.Join(", ", GamesToFarm.Keys));
|
||||
} else {
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If we have unrestricted card drops, we use simple algorithm and farm cards one-by-one
|
||||
Logging.LogGenericInfo(Bot.BotName, "Chosen farming algorithm: Simple");
|
||||
while (GamesToFarm.Count > 0) {
|
||||
uint appID = GetAnyGameToFarm(GamesToFarm);
|
||||
bool success = await FarmSolo(appID).ConfigureAwait(false);
|
||||
if (success) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Done farming: " + appID);
|
||||
} else {
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CurrentGamesFarming.Clear();
|
||||
NowFarming = false;
|
||||
Logging.LogGenericInfo(Bot.BotName, "Farming finished!");
|
||||
await Bot.OnFarmingFinished().ConfigureAwait(false);
|
||||
}
|
||||
@@ -130,39 +305,50 @@ namespace ArchiSteamFarm {
|
||||
|
||||
Logging.LogGenericInfo(Bot.BotName, "Sending signal to stop farming");
|
||||
FarmResetEvent.Set();
|
||||
while (NowFarming) {
|
||||
for (var i = 0; i < 5 && NowFarming; i++) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Waiting for reaction...");
|
||||
Thread.Sleep(1000);
|
||||
await Utilities.SleepAsync(1000).ConfigureAwait(false);
|
||||
}
|
||||
FarmResetEvent.Reset();
|
||||
Logging.LogGenericInfo(Bot.BotName, "Farming stopped!");
|
||||
Semaphore.Release();
|
||||
}
|
||||
|
||||
private async Task<bool?> ShouldFarm(ulong appID) {
|
||||
bool? result = null;
|
||||
HtmlDocument gamePageDocument = await Bot.ArchiWebHandler.GetGameCardsPage(appID).ConfigureAwait(false);
|
||||
if (gamePageDocument != null) {
|
||||
HtmlNode gamePageNode = gamePageDocument.DocumentNode.SelectSingleNode("//span[@class='progress_info_bold']");
|
||||
if (gamePageNode != null) {
|
||||
result = !gamePageNode.InnerText.Contains("No card drops");
|
||||
}
|
||||
private async Task CheckGamesForFarming() {
|
||||
if (NowFarming || GamesToFarm.Count > 0 || !Bot.SteamClient.IsConnected) {
|
||||
return;
|
||||
}
|
||||
return result;
|
||||
|
||||
await StartFarming().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<bool> Farm(ulong appID) {
|
||||
private async Task<bool?> ShouldFarm(ulong appID) {
|
||||
if (appID == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetGameCardsPage(appID).ConfigureAwait(false);
|
||||
if (htmlDocument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//span[@class='progress_info_bold']");
|
||||
if (htmlNode == null) {
|
||||
await Bot.ArchiWebHandler.ReconnectIfNeeded().ConfigureAwait(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
return !htmlNode.InnerText.Contains("No card drops");
|
||||
}
|
||||
|
||||
private async Task<bool> Farm(uint appID) {
|
||||
Bot.ArchiHandler.PlayGames(appID);
|
||||
|
||||
bool success = true;
|
||||
|
||||
bool? keepFarming = await ShouldFarm(appID).ConfigureAwait(false);
|
||||
while (keepFarming == null || keepFarming.Value) {
|
||||
if (!NowFarming) {
|
||||
NowFarming = true;
|
||||
Logging.LogGenericInfo(Bot.BotName, "Now farming: " + appID);
|
||||
Bot.PlayGame(appID);
|
||||
Semaphore.Release(); // We're farming, allow other tasks to shut us down
|
||||
} else {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Still farming: " + appID);
|
||||
}
|
||||
for (ushort farmingTime = 0; farmingTime <= MaxFarmingTime && (!keepFarming.HasValue || keepFarming.Value); farmingTime += StatusCheckSleep) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Still farming: " + appID);
|
||||
if (FarmResetEvent.WaitOne(1000 * 60 * StatusCheckSleep)) {
|
||||
success = false;
|
||||
break;
|
||||
@@ -170,10 +356,42 @@ namespace ArchiSteamFarm {
|
||||
keepFarming = await ShouldFarm(appID).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Bot.PlayGame(0);
|
||||
NowFarming = false;
|
||||
Bot.ArchiHandler.PlayGames(0);
|
||||
Logging.LogGenericInfo(Bot.BotName, "Stopped farming: " + appID);
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool Farm(double maxHour, ICollection<uint> appIDs) {
|
||||
if (maxHour >= 2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Bot.ArchiHandler.PlayGames(appIDs);
|
||||
|
||||
bool success = true;
|
||||
while (maxHour < 2) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Still farming: " + string.Join(", ", appIDs));
|
||||
if (FarmResetEvent.WaitOne(1000 * 60 * StatusCheckSleep)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't forget to update our GamesToFarm hours
|
||||
double timePlayed = StatusCheckSleep / 60.0;
|
||||
foreach (KeyValuePair<uint, double> keyValue in GamesToFarm) {
|
||||
if (!appIDs.Contains(keyValue.Key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GamesToFarm[keyValue.Key] = keyValue.Value + timePlayed;
|
||||
}
|
||||
|
||||
maxHour += timePlayed;
|
||||
}
|
||||
|
||||
Bot.ArchiHandler.PlayGames(0);
|
||||
Logging.LogGenericInfo(Bot.BotName, "Stopped farming: " + string.Join(", ", appIDs));
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ using System.Diagnostics;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal static class Debugging {
|
||||
internal static bool IsReleaseBuild { get; private set; } = true;
|
||||
internal static bool IsDebugBuild { get; private set; } = false;
|
||||
internal static bool IsReleaseBuild { get { return !IsDebugBuild; } }
|
||||
|
||||
static Debugging() {
|
||||
MarkIfDebug();
|
||||
@@ -34,7 +35,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private static void MarkIfDebug() {
|
||||
IsReleaseBuild = false;
|
||||
IsDebugBuild = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,31 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal static class Logging {
|
||||
private static readonly object FileLock = new object();
|
||||
|
||||
internal static void Init() {
|
||||
File.Delete(Program.LogFile);
|
||||
}
|
||||
|
||||
private static void Log(string message) {
|
||||
lock (Program.ConsoleLock) {
|
||||
Console.WriteLine(DateTime.Now + " " + message);
|
||||
if (string.IsNullOrEmpty(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
string loggedMessage = DateTime.Now + " " + message + Environment.NewLine;
|
||||
|
||||
// Write on console only when not awaiting response from user
|
||||
if (!Program.ConsoleIsBusy) {
|
||||
Console.Write(loggedMessage);
|
||||
}
|
||||
|
||||
lock (FileLock) {
|
||||
File.AppendAllText(Program.LogFile, loggedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +76,5 @@ namespace ArchiSteamFarm {
|
||||
internal static void LogGenericDebug(string botName, string message, [CallerMemberName] string previousMethodName = "") {
|
||||
Log("[#] DEBUG: " + previousMethodName + "() <" + botName + "> " + message);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
internal static void LogGenericDebug(string message, [CallerMemberName] string previousMethodName = "") {
|
||||
LogGenericDebug("DEBUG", message, previousMethodName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,23 +34,32 @@ namespace ArchiSteamFarm {
|
||||
internal enum EUserInputType {
|
||||
Login,
|
||||
Password,
|
||||
PhoneNumber,
|
||||
SMS,
|
||||
SteamGuard,
|
||||
SteamParentalPIN,
|
||||
RevocationCode,
|
||||
TwoFactorAuthentication,
|
||||
}
|
||||
|
||||
internal const ulong ArchiSCFarmGroup = 103582791440160998;
|
||||
internal const string ConfigDirectoryPath = "config";
|
||||
private const string LatestGithubReleaseURL = "https://api.github.com/repos/JustArchi/ArchiSteamFarm/releases/latest";
|
||||
internal const string ConfigDirectoryPath = "config";
|
||||
|
||||
internal static readonly object ConsoleLock = new object();
|
||||
private static readonly SemaphoreSlim SteamSemaphore = new SemaphoreSlim(1);
|
||||
private static readonly ManualResetEvent ShutdownResetEvent = new ManualResetEvent(false);
|
||||
private static readonly AssemblyName AssemblyName = Assembly.GetExecutingAssembly().GetName();
|
||||
private static readonly string ExeName = AssemblyName.Name + ".exe";
|
||||
private static readonly string Version = AssemblyName.Version.ToString();
|
||||
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
|
||||
private static readonly string ExecutablePath = Assembly.Location;
|
||||
private static readonly AssemblyName AssemblyName = Assembly.GetName();
|
||||
private static readonly object ConsoleLock = new object();
|
||||
//private static readonly string ExeName = AssemblyName.Name + ".exe";
|
||||
|
||||
internal static readonly string LogFile = Path.Combine(Path.GetDirectoryName(ExecutablePath), "log.txt");
|
||||
internal static readonly string Version = AssemblyName.Version.ToString();
|
||||
|
||||
internal static bool ConsoleIsBusy { get; private set; } = false;
|
||||
|
||||
private static async Task CheckForUpdate() {
|
||||
JObject response = await Utilities.UrlToJObject(LatestGithubReleaseURL).ConfigureAwait(false);
|
||||
JObject response = await WebBrowser.UrlGetToJObject(LatestGithubReleaseURL).ConfigureAwait(false);
|
||||
if (response == null) {
|
||||
return;
|
||||
}
|
||||
@@ -66,11 +75,11 @@ namespace ArchiSteamFarm {
|
||||
Logging.LogGenericNotice("", "Remote version: " + remoteVersion);
|
||||
|
||||
int comparisonResult = localVersion.CompareTo(remoteVersion);
|
||||
if (localVersion.CompareTo(remoteVersion) < 0) {
|
||||
if (comparisonResult < 0) {
|
||||
Logging.LogGenericNotice("", "New version is available!");
|
||||
Logging.LogGenericNotice("", "Consider updating yourself!");
|
||||
Thread.Sleep(5000);
|
||||
} else if (localVersion.CompareTo(remoteVersion) > 0) {
|
||||
await Utilities.SleepAsync(5000).ConfigureAwait(false);
|
||||
} else if (comparisonResult > 0) {
|
||||
Logging.LogGenericNotice("", "You're currently using pre-release version!");
|
||||
Logging.LogGenericNotice("", "Be careful!");
|
||||
}
|
||||
@@ -81,9 +90,22 @@ namespace ArchiSteamFarm {
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
|
||||
internal static string GetUserInput(string botLogin, EUserInputType userInputType) {
|
||||
internal static async Task Restart() {
|
||||
await Bot.ShutdownAllBots().ConfigureAwait(false);
|
||||
System.Diagnostics.Process.Start(ExecutablePath);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
internal static async Task LimitSteamRequestsAsync() {
|
||||
await SteamSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
await Utilities.SleepAsync(5 * 1000).ConfigureAwait(false); // We must add some delay to not get caught by Steam anty-DoS
|
||||
SteamSemaphore.Release();
|
||||
}
|
||||
|
||||
internal static string GetUserInput(string botLogin, EUserInputType userInputType, string extraInformation = null) {
|
||||
string result;
|
||||
lock (ConsoleLock) {
|
||||
ConsoleIsBusy = true;
|
||||
switch (userInputType) {
|
||||
case EUserInputType.Login:
|
||||
Console.Write("<" + botLogin + "> Please enter your login: ");
|
||||
@@ -91,35 +113,65 @@ namespace ArchiSteamFarm {
|
||||
case EUserInputType.Password:
|
||||
Console.Write("<" + botLogin + "> Please enter your password: ");
|
||||
break;
|
||||
case EUserInputType.PhoneNumber:
|
||||
Console.Write("<" + botLogin + "> Please enter your full phone number (e.g. +1234567890): ");
|
||||
break;
|
||||
case EUserInputType.SMS:
|
||||
Console.Write("<" + botLogin + "> Please enter SMS code sent on your mobile: ");
|
||||
break;
|
||||
case EUserInputType.SteamGuard:
|
||||
Console.Write("<" + botLogin + "> Please enter the auth code sent to your email: ");
|
||||
break;
|
||||
case EUserInputType.SteamParentalPIN:
|
||||
Console.Write("<" + botLogin + "> Please enter steam parental PIN: ");
|
||||
break;
|
||||
case EUserInputType.RevocationCode:
|
||||
Console.WriteLine("<" + botLogin + "> PLEASE WRITE DOWN YOUR REVOCATION CODE: " + extraInformation);
|
||||
Console.WriteLine("<" + botLogin + "> THIS IS THE ONLY WAY TO NOT GET LOCKED OUT OF YOUR ACCOUNT!");
|
||||
Console.Write("<" + botLogin + "> Hit enter once ready...");
|
||||
break;
|
||||
case EUserInputType.TwoFactorAuthentication:
|
||||
Console.Write("<" + botLogin + "> Please enter your 2 factor auth code from your authenticator app: ");
|
||||
break;
|
||||
}
|
||||
result = Console.ReadLine();
|
||||
Console.Clear(); // For security purposes
|
||||
ConsoleIsBusy = false;
|
||||
}
|
||||
return result;
|
||||
|
||||
return result.Trim(); // Get rid of all whitespace characters
|
||||
}
|
||||
|
||||
internal static void OnBotShutdown(Bot bot) {
|
||||
internal static async void OnBotShutdown() {
|
||||
if (Bot.GetRunningBotsCount() == 0) {
|
||||
Logging.LogGenericInfo("Main", "No bots are running, exiting");
|
||||
Thread.Sleep(5000); // This might be the only message user gets, consider giving him some time
|
||||
await Utilities.SleepAsync(5000).ConfigureAwait(false); // This might be the only message user gets, consider giving him some time
|
||||
ShutdownResetEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitServices() {
|
||||
Logging.Init();
|
||||
WebBrowser.Init();
|
||||
}
|
||||
|
||||
private static void Main(string[] args) {
|
||||
InitServices();
|
||||
|
||||
Logging.LogGenericInfo("Main", "Archi's Steam Farm, version " + Version);
|
||||
|
||||
Task.Run(async () => await CheckForUpdate().ConfigureAwait(false)).Wait();
|
||||
|
||||
// Allow loading configs from source tree if it's a debug build
|
||||
if (Debugging.IsDebugBuild) {
|
||||
for (var i = 0; i < 4; i++) {
|
||||
Directory.SetCurrentDirectory("..");
|
||||
if (Directory.Exists(ConfigDirectoryPath)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Directory.Exists(ConfigDirectoryPath)) {
|
||||
Logging.LogGenericError("Main", "Config directory doesn't exist!");
|
||||
Console.ReadLine();
|
||||
@@ -135,7 +187,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// Check if we got any bots running
|
||||
OnBotShutdown(null);
|
||||
OnBotShutdown();
|
||||
|
||||
ShutdownResetEvent.WaitOne();
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.5.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.5.0.0")]
|
||||
[assembly: AssemblyVersion("1.2.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.2.0.0")]
|
||||
|
||||
@@ -39,7 +39,14 @@ namespace ArchiSteamFarm {
|
||||
Declined,
|
||||
InvalidItems,
|
||||
EmailPending,
|
||||
EmailCanceled
|
||||
EmailCanceled,
|
||||
OnHold
|
||||
}
|
||||
|
||||
internal enum ETradeOfferConfirmationMethod {
|
||||
Invalid,
|
||||
Email,
|
||||
MobileApp
|
||||
}
|
||||
|
||||
internal string tradeofferid { get; set; }
|
||||
@@ -53,6 +60,8 @@ namespace ArchiSteamFarm {
|
||||
internal int time_created { get; set; }
|
||||
internal int time_updated { get; set; }
|
||||
internal bool from_real_time_trade { get; set; }
|
||||
internal int escrow_end_date { get; set; }
|
||||
internal ETradeOfferConfirmationMethod confirmation_method { get; set; }
|
||||
|
||||
// Extra
|
||||
private ulong _OtherSteamID64 = 0;
|
||||
|
||||
@@ -36,33 +36,33 @@ namespace ArchiSteamFarm {
|
||||
Bot = bot;
|
||||
}
|
||||
|
||||
internal void CheckTrades() {
|
||||
internal async void CheckTrades() {
|
||||
if (ParsingTasks < 2) {
|
||||
ParsingTasks++;
|
||||
Task.Run(() => ParseActiveTrades());
|
||||
|
||||
await Semaphore.WaitAsync().ConfigureAwait(false);
|
||||
await ParseActiveTrades().ConfigureAwait(false);
|
||||
Semaphore.Release();
|
||||
|
||||
ParsingTasks--;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ParseActiveTrades() {
|
||||
await Semaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
List<SteamTradeOffer> tradeOffers = Bot.ArchiWebHandler.GetTradeOffers();
|
||||
if (tradeOffers != null) {
|
||||
List<Task> tasks = new List<Task>();
|
||||
foreach (SteamTradeOffer tradeOffer in tradeOffers) {
|
||||
if (tradeOffer.trade_offer_state == SteamTradeOffer.ETradeOfferState.Active) {
|
||||
Task task = Task.Run(async () => {
|
||||
await ParseTrade(tradeOffer).ConfigureAwait(false);
|
||||
});
|
||||
tasks.Add(task);
|
||||
}
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
if (tradeOffers == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ParsingTasks--;
|
||||
Semaphore.Release();
|
||||
List<Task> tasks = new List<Task>();
|
||||
foreach (SteamTradeOffer tradeOffer in tradeOffers) {
|
||||
if (tradeOffer.trade_offer_state == SteamTradeOffer.ETradeOfferState.Active) {
|
||||
tasks.Add(Task.Run(async () => await ParseTrade(tradeOffer).ConfigureAwait(false)));
|
||||
}
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
await Bot.AcceptAllConfirmations().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task ParseTrade(SteamTradeOffer tradeOffer) {
|
||||
@@ -75,19 +75,11 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
ulong otherSteamID = tradeOffer.OtherSteamID64;
|
||||
bool success = false;
|
||||
bool tradeAccepted = false;
|
||||
|
||||
if (tradeOffer.items_to_give.Count == 0 || otherSteamID == Bot.SteamMasterID) {
|
||||
tradeAccepted = true;
|
||||
success = await Bot.ArchiWebHandler.AcceptTradeOffer(tradeID).ConfigureAwait(false);
|
||||
if (tradeOffer.items_to_give.Count == 0 || tradeOffer.OtherSteamID64 == Bot.SteamMasterID) {
|
||||
Logging.LogGenericInfo(Bot.BotName, "Accepting trade: " + tradeID);
|
||||
await Bot.ArchiWebHandler.AcceptTradeOffer(tradeID).ConfigureAwait(false);
|
||||
} else {
|
||||
success = Bot.ArchiWebHandler.DeclineTradeOffer(tradeID);
|
||||
}
|
||||
|
||||
if (tradeAccepted && success) {
|
||||
// Do whatever we want with success
|
||||
Logging.LogGenericInfo(Bot.BotName, "Ignoring trade: " + tradeID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,190 +22,39 @@
|
||||
|
||||
*/
|
||||
|
||||
using HtmlAgilityPack;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal static class Utilities {
|
||||
internal static async Task SleepAsync(int miliseconds) {
|
||||
await Task.Delay(miliseconds).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static ulong OnlyNumbers(string inputString) {
|
||||
if (string.IsNullOrEmpty(inputString)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
string resultString;
|
||||
try {
|
||||
Regex regexObj = new Regex(@"[^\d]");
|
||||
resultString = regexObj.Replace(inputString, "");
|
||||
} catch (ArgumentException e) {
|
||||
Logging.LogGenericException("Utilities", e);
|
||||
string resultString = OnlyNumbersString(inputString);
|
||||
if (string.IsNullOrEmpty(resultString)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ulong.Parse(resultString, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
internal static async Task<HttpResponseMessage> UrlToHttpResponse(string websiteAddress, Dictionary<string, string> cookieVariables = null) {
|
||||
if (string.IsNullOrEmpty(websiteAddress)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage result = null;
|
||||
|
||||
try {
|
||||
using (HttpClientHandler clientHandler = new HttpClientHandler { UseCookies = false }) {
|
||||
using (HttpClient client = new HttpClient(clientHandler)) {
|
||||
client.Timeout = TimeSpan.FromSeconds(10);
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd("ArchiSteamFarm/1.0");
|
||||
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, websiteAddress);
|
||||
if (cookieVariables != null) {
|
||||
StringBuilder cookie = new StringBuilder();
|
||||
foreach (KeyValuePair<string, string> cookieVariable in cookieVariables) {
|
||||
cookie.Append(cookieVariable.Key + "=" + cookieVariable.Value + ";");
|
||||
}
|
||||
requestMessage.Headers.Add("Cookie", cookie.ToString());
|
||||
}
|
||||
HttpResponseMessage responseMessage = await client.SendAsync(requestMessage).ConfigureAwait(false);
|
||||
if (responseMessage != null) {
|
||||
responseMessage.EnsureSuccessStatusCode();
|
||||
result = responseMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException("Utilities", e);
|
||||
ulong result;
|
||||
if (!ulong.TryParse(resultString, out result)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static async Task<HtmlDocument> UrlToHtmlDocument(string websiteAddress, Dictionary<string, string> cookieVariables = null) {
|
||||
if (string.IsNullOrEmpty(websiteAddress)) {
|
||||
internal static string OnlyNumbersString(string text) {
|
||||
if (string.IsNullOrEmpty(text)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlDocument result = null;
|
||||
|
||||
try {
|
||||
HttpResponseMessage responseMessage = await UrlToHttpResponse(websiteAddress, cookieVariables).ConfigureAwait(false);
|
||||
if (responseMessage != null) {
|
||||
string source = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
if (!string.IsNullOrEmpty(source)) {
|
||||
source = WebUtility.HtmlDecode(source);
|
||||
result = new HtmlDocument();
|
||||
result.LoadHtml(source);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException("Utilities", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static async Task<bool> UrlPostRequest(string request, Dictionary<string, string> postData, Dictionary<string, string> cookieVariables = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request) || postData == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
try {
|
||||
using (HttpClientHandler clientHandler = new HttpClientHandler { UseCookies = false }) {
|
||||
using (HttpClient client = new HttpClient(clientHandler)) {
|
||||
client.Timeout = TimeSpan.FromSeconds(10);
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd("ArchiSteamFarm/1.0");
|
||||
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, request);
|
||||
requestMessage.Content = new FormUrlEncodedContent(postData);
|
||||
if (cookieVariables != null && cookieVariables.Count > 0) {
|
||||
StringBuilder cookie = new StringBuilder();
|
||||
foreach (KeyValuePair<string, string> cookieVariable in cookieVariables) {
|
||||
cookie.Append(cookieVariable.Key + "=" + cookieVariable.Value + ";");
|
||||
}
|
||||
requestMessage.Headers.Add("Cookie", cookie.ToString());
|
||||
}
|
||||
if (referer != null) {
|
||||
requestMessage.Headers.Referrer = new Uri(referer);
|
||||
}
|
||||
HttpResponseMessage responseMessage = await client.SendAsync(requestMessage).ConfigureAwait(false);
|
||||
if (responseMessage != null) {
|
||||
result = responseMessage.IsSuccessStatusCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException("Utilities", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static async Task<HttpResponseMessage> UrlPostRequestWithResponse(string request, Dictionary<string, string> postData, Dictionary<string, string> cookieVariables = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request) || postData == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage result = null;
|
||||
|
||||
try {
|
||||
using (HttpClientHandler clientHandler = new HttpClientHandler { UseCookies = false }) {
|
||||
using (HttpClient client = new HttpClient(clientHandler)) {
|
||||
client.Timeout = TimeSpan.FromSeconds(10);
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd("ArchiSteamFarm/1.0");
|
||||
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, request);
|
||||
requestMessage.Content = new FormUrlEncodedContent(postData);
|
||||
if (cookieVariables != null && cookieVariables.Count > 0) {
|
||||
StringBuilder cookie = new StringBuilder();
|
||||
foreach (KeyValuePair<string, string> cookieVariable in cookieVariables) {
|
||||
cookie.Append(cookieVariable.Key + "=" + cookieVariable.Value + ";");
|
||||
}
|
||||
requestMessage.Headers.Add("Cookie", cookie.ToString());
|
||||
}
|
||||
if (referer != null) {
|
||||
requestMessage.Headers.Referrer = new Uri(referer);
|
||||
}
|
||||
HttpResponseMessage responseMessage = await client.SendAsync(requestMessage).ConfigureAwait(false);
|
||||
if (responseMessage != null) {
|
||||
result = responseMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException("Utilities", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static async Task<JObject> UrlToJObject(string request) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage httpResponseMessage = await UrlToHttpResponse(request, null).ConfigureAwait(false);
|
||||
if (httpResponseMessage == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string source = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(source)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JObject result = null;
|
||||
try {
|
||||
result = JObject.Parse(source);
|
||||
} catch {
|
||||
}
|
||||
|
||||
return result;
|
||||
return Regex.Replace(text, @"[^\d]", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
247
ArchiSteamFarm/WebBrowser.cs
Normal file
247
ArchiSteamFarm/WebBrowser.cs
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
_ _ _ ____ _ _____
|
||||
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
|
||||
Copyright 2015 Łukasz "JustArchi" Domeradzki
|
||||
Contact: JustArchi@JustArchi.net
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
using HtmlAgilityPack;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal static class WebBrowser {
|
||||
internal const byte HttpTimeout = 180; // In seconds
|
||||
|
||||
private static readonly HttpClientHandler HttpClientHandler = new HttpClientHandler { UseCookies = false };
|
||||
private static readonly HttpClient HttpClient = new HttpClient(HttpClientHandler) { Timeout = TimeSpan.FromSeconds(HttpTimeout) };
|
||||
|
||||
internal static void Init() {
|
||||
HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd("ArchiSteamFarm/" + Program.Version);
|
||||
|
||||
// Don't limit maximum number of allowed concurrent connections
|
||||
// It's application's responsibility to handle that stuff
|
||||
ServicePointManager.DefaultConnectionLimit = int.MaxValue;
|
||||
|
||||
// Don't use Expect100Continue, we don't need to do that
|
||||
ServicePointManager.Expect100Continue = false;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponseMessage> UrlRequest(string request, HttpMethod httpMethod, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request) || httpMethod == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpRequestMessage requestMessage = new HttpRequestMessage(httpMethod, request);
|
||||
|
||||
if (httpMethod == HttpMethod.Post && data != null) {
|
||||
requestMessage.Content = new FormUrlEncodedContent(data);
|
||||
}
|
||||
|
||||
if (cookies != null && cookies.Count > 0) {
|
||||
StringBuilder cookieHeader = new StringBuilder();
|
||||
foreach (KeyValuePair<string, string> cookie in cookies) {
|
||||
cookieHeader.Append(cookie.Key + "=" + cookie.Value + ";");
|
||||
}
|
||||
requestMessage.Headers.Add("Cookie", cookieHeader.ToString());
|
||||
}
|
||||
|
||||
if (referer != null) {
|
||||
requestMessage.Headers.Referrer = new Uri(referer);
|
||||
}
|
||||
|
||||
HttpResponseMessage responseMessage;
|
||||
|
||||
try {
|
||||
responseMessage = await HttpClient.SendAsync(requestMessage).ConfigureAwait(false);
|
||||
} catch { // Request failed, we don't need to know the exact reason, swallow exception
|
||||
return null;
|
||||
}
|
||||
|
||||
if (responseMessage == null || !responseMessage.IsSuccessStatusCode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return responseMessage;
|
||||
}
|
||||
|
||||
internal static async Task<HttpResponseMessage> UrlGet(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await UrlRequest(request, HttpMethod.Get, null, cookies, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<HttpResponseMessage> UrlPost(string request, Dictionary<string, string> postData = null, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await UrlRequest(request, HttpMethod.Post, postData, cookies, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<HtmlDocument> HttpResponseToHtmlDocument(HttpResponseMessage httpResponse) {
|
||||
if (httpResponse == null || httpResponse.Content == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
content = WebUtility.HtmlDecode(content);
|
||||
HtmlDocument htmlDocument = new HtmlDocument();
|
||||
htmlDocument.LoadHtml(content);
|
||||
|
||||
return htmlDocument;
|
||||
}
|
||||
|
||||
internal static async Task<string> UrlGetToContent(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage responseMessage = await UrlGet(request, cookies, referer).ConfigureAwait(false);
|
||||
if (responseMessage == null || responseMessage.Content == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<string> UrlPostToContent(string request, Dictionary<string, string> postData = null, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage responseMessage = await UrlPost(request, postData, cookies, referer).ConfigureAwait(false);
|
||||
if (responseMessage == null || responseMessage.Content == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<string> UrlGetToTitle(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlDocument htmlDocument = await UrlGetToHtmlDocument(request, cookies, referer).ConfigureAwait(false);
|
||||
if (htmlDocument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//head/title");
|
||||
if (htmlNode == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return htmlNode.InnerText;
|
||||
}
|
||||
|
||||
internal static async Task<HtmlDocument> UrlGetToHtmlDocument(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage httpResponse = await UrlGet(request, cookies, referer).ConfigureAwait(false);
|
||||
if (httpResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await HttpResponseToHtmlDocument(httpResponse).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<JArray> UrlGetToJArray(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JArray jArray;
|
||||
|
||||
try {
|
||||
jArray = JArray.Parse(content);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException("WebBrowser", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return jArray;
|
||||
}
|
||||
|
||||
internal static async Task<JObject> UrlGetToJObject(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JObject jObject;
|
||||
|
||||
try {
|
||||
jObject = JObject.Parse(content);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException("WebBrowser", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return jObject;
|
||||
}
|
||||
|
||||
internal static async Task<XmlDocument> UrlGetToXML(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
XmlDocument xmlDocument = new XmlDocument();
|
||||
|
||||
try {
|
||||
xmlDocument.LoadXml(content);
|
||||
} catch (XmlException e) {
|
||||
Logging.LogGenericException("WebBrowser", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,92 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<!-- This is full-fledged example config, you may be also interested in minimal.xml for bare minimum one -->
|
||||
<!-- Default values used in config match default ASF values when given config property is not found -->
|
||||
|
||||
<!-- Every bot should have it's own unique .xml configuration file, this is example on which you can base on -->
|
||||
<!-- Notice, if you use special characters reserved for XML, you should escape them -->
|
||||
<!-- Escape table: [& - &] | [" - "] | [' - '] | [< - <] | [> - >] -->
|
||||
<!-- So e.g. if your SteamPassword is "foo&" you should write value="foo&" -->
|
||||
|
||||
<!-- Master switch to turn account on and off, set to "true" after you're done -->
|
||||
<!-- TIP: This bot instance won't run unless below switch is set to "true" -->
|
||||
<Enabled type="bool" value="false"/>
|
||||
<!-- Type of the property is a tip for you that defines what values you can use -->
|
||||
<!-- bool - Boolean value that can be only "true" or "false" -->
|
||||
<!-- string - Any sequence of characters, unless stated otherwise (keep in mind escape table above), with special treatment of "null" value -->
|
||||
<!-- uint - 32-bit unsigned integer, used mostly for steam appID -->
|
||||
<!-- ulong - 64-bit unsigned (long) integer, used mostly for representing steamID64 -->
|
||||
<!-- HashSet(uint) - Comma-separated list of unique 32-bit unsigned integers -->
|
||||
|
||||
<!-- This is your steam login, the one you use for logging in to steam -->
|
||||
<!-- TIP: You can use "null" if you wish to enter login on every startup -->
|
||||
<SteamLogin type="string" value="null"/>
|
||||
<!-- Master switch to turn account on and off, set to "true" after you're done -->
|
||||
<!-- TIP: This bot instance won't run unless below switch is set to "true" -->
|
||||
<Enabled type="bool" value="false"/>
|
||||
|
||||
<!-- This is your steam password, the one you use for logging in to steam -->
|
||||
<!-- TIP: You can use "null" if you wish to enter password on every startup -->
|
||||
<SteamPassword type="string" value="null"/>
|
||||
<!-- This is your steam login, the one you use for logging in to steam -->
|
||||
<!-- TIP: You can use "null" if you wish to enter login on every startup -->
|
||||
<SteamLogin type="string" value="null"/>
|
||||
|
||||
<!-- This is steam nickname, the one you want to use for bot. Can be anything up to 32 characters -->
|
||||
<!-- TIP: You can use "null" if you wish to preserve your actual nickname -->
|
||||
<SteamNickname type="string" value="null"/>
|
||||
<!-- This is your steam password, the one you use for logging in to steam -->
|
||||
<!-- TIP: You can use "null" if you wish to enter password on every startup -->
|
||||
<SteamPassword type="string" value="null"/>
|
||||
|
||||
<!-- This is your bot's API key, get one at https://steamcommunity.com/dev/apikey while logged in as bot, domain doesn't matter -->
|
||||
<!-- TIP: You can use "null", but it will disable all API-based functionalities such as trading -->
|
||||
<SteamApiKey type="string" value="null"/>
|
||||
<!-- This is steam nickname, the one you want to use for bot. Can be anything up to 32 characters -->
|
||||
<!-- TIP: You can use "null" if you wish to preserve your actual nickname -->
|
||||
<SteamNickname type="string" value="null"/>
|
||||
|
||||
<!-- This is your parental PIN if you use steam parental functionality -->
|
||||
<!-- TIP: Most likely you don't want to change it. You can use "null" if you wish to enter PIN on every startup, 0 means there is no PIN -->
|
||||
<SteamParentalPIN type="string" value="0"/>
|
||||
<!-- This is your bot's API key, get one at https://steamcommunity.com/dev/apikey while logged in as bot, domain doesn't matter -->
|
||||
<!-- TIP: You can use "null", but it will disable all API-based functionalities such as trading -->
|
||||
<SteamApiKey type="string" value="null"/>
|
||||
|
||||
<!-- This is steamID of the bot-master - you, in steamID64 format -->
|
||||
<!-- TIP: You can use "0", but bot won't accept steam cd-keys or trades from anybody" -->
|
||||
<SteamMasterID type="ulong" value="76561198006963719"/>
|
||||
<!-- This is your parental PIN if you use steam parental functionality -->
|
||||
<!-- TIP: Most likely you don't want to change it. You can use "null" if you wish to enter PIN on every startup, 0 means there is no PIN -->
|
||||
<SteamParentalPIN type="string" value="0"/>
|
||||
|
||||
<!-- This defines clan of the master, bot will join chatroom of that clan automatically after logging in -->
|
||||
<!-- TIP: Most likely you don't want to change it -->
|
||||
<SteamMasterClanID type="ulong" value="0"/>
|
||||
<!-- This is steamID64 of the bot-master - you, for example "76561198006963719" -->
|
||||
<!-- You can get one e.g. by logging in to http://steamrep.com/ -->
|
||||
<!-- TIP: You can use "0", but bot won't accept steam cd-keys or trades from anybody" -->
|
||||
<SteamMasterID type="ulong" value="0"/>
|
||||
|
||||
<!-- This switch defines if bot should disconnect once farming is finished -->
|
||||
<!-- When no bots are active, ASF will shutdown as well -->
|
||||
<!-- Some people may want to keep their bots 24/7, other disconnect them after job is done -->
|
||||
<!-- Choose yourself what you prefer -->
|
||||
<ShutdownOnFarmingFinished type="bool" value="false"/>
|
||||
<!-- This is steamID64 of the master clan (group). If defined, bot will join the group and the chat automatically after logging in -->
|
||||
<!-- The easiest way to get one is to check groups on your profile: http://steamcommunity.com/my/profile" -->
|
||||
<!-- Then copying the URL of "Leave group" link, it will look like this: javascript:leaveGroupPrompt('103582791440160998','Archi\'s SC Farm') -->
|
||||
<!-- The steamID64 we're looking for is there, in above example: "103582791440160998" -->
|
||||
<!-- TIP: If you don't have your own farming group, most likely you don't want to change it, 0 means there is no master group defined -->
|
||||
<SteamMasterClanID type="ulong" value="0"/>
|
||||
|
||||
<!-- Comma-separated list of IDs that should not be considered for farming -->
|
||||
<!-- TIP: Most likely you don't want to change it -->
|
||||
<Blacklist type="HashSet(uint)" value="368020"/>
|
||||
<!-- This switch defines if you want to use built-in ASF two-factor-authentication (ASF 2FA) for this account -->
|
||||
<!-- The one and only purpose for this function is automating steam logins and steam trades, so you won't need to enter 2FA codes all the time -->
|
||||
<!-- This however defeats the whole purpose of two-factor-auth, and should be used on alt accounts ONLY -->
|
||||
<!-- You should read full documentation, along with explanation here: https://github.com/JustArchi/ArchiSteamFarm/wiki/Escrow -->
|
||||
<!-- WARNING, this option can potentially LOCK OUT YOUR ACCOUNT! If you don't fully understand this feature, DON'T USE IT! -->
|
||||
<UseAsfAsMobileAuthenticator type="bool" value="false"/>
|
||||
|
||||
<!-- This enables statistics for me - bot will join Archi's SC Farm group and chat -->
|
||||
<!-- Consider leaving it at "true", this way I can check how many running bots are active -->
|
||||
<!-- TIP: Group link is http://steamcommunity.com/groups/ascfarm -->
|
||||
<Statistics type="bool" value="true"/>
|
||||
<!-- This switch defines if the account has card drops restricted -->
|
||||
<!-- Restricted card drops means that the account doesn't receive any steam cards until it plays the game for at least 2 hours -->
|
||||
<!-- As there is no magical way to detect it by ASF, I made this option config-based switch -->
|
||||
<!-- TIP: Based on this parameter, ASF will try to choose the most optimal cards farming algorithm for this account -->
|
||||
<CardDropsRestricted type="bool" value="false"/>
|
||||
|
||||
</configuration>
|
||||
<!-- This switch defines if the account should stay as "Offline" after logging in to Steam -->
|
||||
<!-- Please note that bot won't be able to respond to any commands when this property is set to "true" -->
|
||||
<!-- TIP: Setting this to "true" may be useful for primary accounts, to not show as online when you're not here -->
|
||||
<FarmOffline type="bool" value="false"/>
|
||||
|
||||
<!-- This switch defines if bot should handle offline messages when it sees them -->
|
||||
<!-- Basically it should be used only when "FarmOffline" property above is true, so bot can handle offline messages -->
|
||||
<!-- Reading offline messages will also mark them as received, therefore it should not be used if you want to keep them for later -->
|
||||
<HandleOfflineMessages type="bool" value="false"/>
|
||||
|
||||
<!-- This switch defines if bot should disconnect once farming is finished -->
|
||||
<!-- When no bots are active, ASF will shutdown as well -->
|
||||
<!-- Some people may want to keep their bots 24/7, other disconnect them after job is done -->
|
||||
<!-- Choose yourself what you prefer -->
|
||||
<ShutdownOnFarmingFinished type="bool" value="false"/>
|
||||
|
||||
<!-- Comma-separated list of IDs that should not be considered for farming -->
|
||||
<!-- Default value includes appIDs that are wrongly appearing on the profile, e.g. Monster Summer Sale -->
|
||||
<!-- TIP: Most likely you don't want to change it -->
|
||||
<Blacklist type="HashSet(uint)" value="303700,335590,368020,425280"/>
|
||||
|
||||
<!-- This switch enables statistics for me - bot will join Archi's SC Farm group and chat -->
|
||||
<!-- Consider leaving it at "true", this way I can check how many running bots are active -->
|
||||
<!-- That directly affects my willings to work on the project, as I can see how many users are actually using it -->
|
||||
<!-- TIP: Group link is http://steamcommunity.com/groups/ascfarm -->
|
||||
<Statistics type="bool" value="true"/>
|
||||
</configuration>
|
||||
|
||||
8
ArchiSteamFarm/config/minimal.xml
Normal file
8
ArchiSteamFarm/config/minimal.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<!-- This is minimalistic config to "just make ASF work" -->
|
||||
<!-- For full-fledged config, please take a look at example.xml -->
|
||||
<Enabled type="bool" value="false"/>
|
||||
<SteamLogin type="string" value="null"/>
|
||||
<SteamPassword type="string" value="null"/>
|
||||
</configuration>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json" version="8.0.1-beta1" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json" version="8.0.1-beta3" targetFramework="net45" />
|
||||
<package id="protobuf-net" version="2.0.0.668" targetFramework="net45" />
|
||||
<package id="SteamKit2" version="1.6.5" targetFramework="net45" />
|
||||
<package id="SteamKit2" version="1.7.0" targetFramework="net452" />
|
||||
</packages>
|
||||
64
README.md
64
README.md
@@ -1,26 +1,58 @@
|
||||
# ArchiSteamFarm
|
||||
ArchiSteamFarm
|
||||
===================
|
||||
|
||||
Big work-in-progress
|
||||
ASF is a C# application that allows you to farm steam cards using multiple steam accounts simultaneously. Unlike idle master which works only on one account at given time, requires steam client running in background, and launches additional processes imitiating "game playing" status, ASF doesn't require any steam client running in the background, doesn't launch any additional processes and is made to handle unlimited steam accounts at once. In addition to that, it's meant to be run on servers or other desktop-less machines, and features full Mono support, which makes it possible to launch on any Mono-supported operating system, such as Windows, Linux or OS X. ASF is based on, and possible, thanks to [SteamKit2](https://github.com/SteamRE/SteamKit).
|
||||
|
||||
Allows you to farm steam cards using multiple accounts simultaneously.
|
||||
ASF doesn't require and doesn't interfere in any way with Steam client. In addition to that, it no longer requires exclusive access to given account, which means that you can use your main account in Steam client, and use ASF for farming the same account at the same time. If you decide to launch a game, ASF will get disconnected, and resume farming once you finish playing your game, being as transparent as possible.
|
||||
|
||||
Each account is defined by it's own XML config in "config" directory.
|
||||
**Core features:**
|
||||
|
||||
Current functions:
|
||||
- Does not need Steam client running, or even a GUI. Fully based on SteamKit2 and reverse-engineered Steam protocol.
|
||||
- Automatically farm steam cards using any number of active accounts
|
||||
- Automatically farm available games using any number of active accounts
|
||||
- Automatically accept friend requests sent from master
|
||||
- Automatically accept all trades coming from master
|
||||
- Automatically accept all steam cd-keys sent via chat from master
|
||||
- SteamGuard / 2-factor-authentication support
|
||||
- Full Mono support, tested on Debian "9.0" Stretch (testing)
|
||||
- Possibility to choose the most efficient cards farming algorithm, based on given account
|
||||
- SteamGuard / SteamParental / 2FA support
|
||||
- Unique ASF 2FA mechanism allowing ASF to act as mobile authenticator (if needed)
|
||||
- ASF update notifications
|
||||
- Full Mono support, cross-OS compatibility
|
||||
|
||||
TODO:
|
||||
- Smart multi-games farming till every game reaches 2 hours, then one-by-one (similar to Idle Master) - Backend code is already here, just missing the logic and tests.
|
||||
- Possible integration with SteamTradeMatcher, bot can detect dupes and trade them automatically. Again, backend code is already here, just missing actual implementation.
|
||||
- Automatic sending of steam trades to master, after game is fully farmed.
|
||||
- Probably much more
|
||||
**Setting up:**
|
||||
|
||||
This is big WIP, so feel free to send pull requests if you wish.
|
||||
Each ASF bot is defined in it's own XML config file in `config` directory. ASF comes with included ```example.xml``` config file, on which you should base all of your bots. Simply copy ```example.xml``` to a new file, and edit properties inside. Don't forget to switch ```Enabled``` property to ```true``` once you're done, as this is the master switch which enables configured bot to launch. The most minimalistic setup to make ASF working is changing only ```Enabled```, ```SteamLogin``` and ```SteamPassword``` properties, everything else is more or less optional to enable additional features.
|
||||
|
||||
I'll release some releases later, when everything is tested and code cleaned up.
|
||||
After you set up all your bots (their configs), you should launch ```ASF.exe```. If your accounts require additional steps to unlock, such as Steam guard code, you'll need to enter those too after ASF tries to launch given bot. If everything ended properly, you should notice in the console output, as well as on your Steam, that all of your bots automatically started cards farming.
|
||||
|
||||
ASF doesn't require and doesn't interfere in any way with Steam client, which means that you can be logged in to Steam client as your primary account, and launch ASF at the same time, for any number of accounts, including your main one (if needed).
|
||||
|
||||
**Current Commands:**
|
||||
|
||||
- `!2fa` Generates temporary 2FA token for current bot instance
|
||||
- `!2fa <BOT>` Generates temporary 2FA token for given bot instance
|
||||
- `!2faoff` Deactivates 2FA for current bot instance
|
||||
- `!2faoff <BOT>` Deactivates 2FA for given bot instance
|
||||
- `!exit` Stops whole ASF
|
||||
- `!farm` Restarts cards farming module. ASF automatically executes that if any cd-key is successfully claimed
|
||||
- `!redeem <KEY>` Redeems cd-key on current bot instance. You can also paste cd-key directly to the chat
|
||||
- `!start <BOT>` Starts given bot instance
|
||||
- `!status` Prints current status of ASF
|
||||
- `!stop` Stops current bot instance
|
||||
- `!stop <BOT>` Stops given bot instance
|
||||
|
||||
> Commands can be executed via a private chat with your bot.
|
||||
> Remember that bot accepts commands only from ```SteamMasterID```. That property can be configured in the config.
|
||||
|
||||
**Supported / Tested Operating-Systems:**
|
||||
|
||||
- Windows 10 Professional/Enterprise Edition (Native)
|
||||
- Windows 8.1 Professional (Native)
|
||||
- Windows 7 Ultimate (Native)
|
||||
- Debian 9.0 Stretch (Mono)
|
||||
- Debian 8.1 Jessie (Mono)
|
||||
- OS X 10.11.1 (Mono)
|
||||
|
||||
However, any operating system [listed here](http://www.mono-project.com/docs/about-mono/supported-platforms/) should run ASF flawlessly.
|
||||
|
||||
**Need help or more info?**
|
||||
|
||||
Head over to our [wiki](https://github.com/JustArchi/ArchiSteamFarm/wiki) then.
|
||||
|
||||
12
SteamAuth/APIEndpoints.cs
Normal file
12
SteamAuth/APIEndpoints.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace SteamAuth
|
||||
{
|
||||
public static class APIEndpoints
|
||||
{
|
||||
public const string STEAMAPI_BASE = "https://api.steampowered.com";
|
||||
public const string COMMUNITY_BASE = "https://steamcommunity.com";
|
||||
public const string MOBILEAUTH_BASE = STEAMAPI_BASE + "/IMobileAuthService/%s/v0001";
|
||||
public static string MOBILEAUTH_GETWGTOKEN = MOBILEAUTH_BASE.Replace("%s", "GetWGToken");
|
||||
public const string TWO_FACTOR_BASE = STEAMAPI_BASE + "/ITwoFactorService/%s/v0001";
|
||||
public static string TWO_FACTOR_TIME_QUERY = TWO_FACTOR_BASE.Replace("%s", "QueryTime");
|
||||
}
|
||||
}
|
||||
277
SteamAuth/AuthenticatorLinker.cs
Normal file
277
SteamAuth/AuthenticatorLinker.cs
Normal file
@@ -0,0 +1,277 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SteamAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the linking process for a new mobile authenticator.
|
||||
/// </summary>
|
||||
public class AuthenticatorLinker
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set to register a new phone number when linking. If a phone number is not set on the account, this must be set. If a phone number is set on the account, this must be null.
|
||||
/// </summary>
|
||||
public string PhoneNumber = null;
|
||||
|
||||
/// <summary>
|
||||
/// Randomly-generated device ID. Should only be generated once per linker.
|
||||
/// </summary>
|
||||
public string DeviceID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// After the initial link step, if successful, this will be the SteamGuard data for the account. PLEASE save this somewhere after generating it; it's vital data.
|
||||
/// </summary>
|
||||
public SteamGuardAccount LinkedAccount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the authenticator has been fully finalized.
|
||||
/// </summary>
|
||||
public bool Finalized = false;
|
||||
|
||||
private SessionData _session;
|
||||
private CookieContainer _cookies;
|
||||
|
||||
public AuthenticatorLinker(SessionData session)
|
||||
{
|
||||
this._session = session;
|
||||
this.DeviceID = GenerateDeviceID();
|
||||
|
||||
this._cookies = new CookieContainer();
|
||||
session.AddCookies(_cookies);
|
||||
}
|
||||
|
||||
public LinkResult AddAuthenticator()
|
||||
{
|
||||
bool hasPhone = _hasPhoneAttached();
|
||||
if (hasPhone && PhoneNumber != null)
|
||||
return LinkResult.MustRemovePhoneNumber;
|
||||
if (!hasPhone && PhoneNumber == null)
|
||||
return LinkResult.MustProvidePhoneNumber;
|
||||
|
||||
if (!hasPhone)
|
||||
{
|
||||
if (!_addPhoneNumber())
|
||||
{
|
||||
return LinkResult.GeneralFailure;
|
||||
}
|
||||
}
|
||||
|
||||
var postData = new NameValueCollection();
|
||||
postData.Add("access_token", _session.OAuthToken);
|
||||
postData.Add("steamid", _session.SteamID.ToString());
|
||||
postData.Add("authenticator_type", "1");
|
||||
postData.Add("device_identifier", this.DeviceID);
|
||||
postData.Add("sms_phone_id", "1");
|
||||
|
||||
string response = SteamWeb.MobileLoginRequest(APIEndpoints.STEAMAPI_BASE + "/ITwoFactorService/AddAuthenticator/v0001", "POST", postData);
|
||||
if (response == null) return LinkResult.GeneralFailure;
|
||||
|
||||
var addAuthenticatorResponse = JsonConvert.DeserializeObject<AddAuthenticatorResponse>(response);
|
||||
if (addAuthenticatorResponse == null || addAuthenticatorResponse.Response == null)
|
||||
{
|
||||
return LinkResult.GeneralFailure;
|
||||
}
|
||||
|
||||
if (addAuthenticatorResponse.Response.Status == 29)
|
||||
{
|
||||
return LinkResult.AuthenticatorPresent;
|
||||
}
|
||||
|
||||
if (addAuthenticatorResponse.Response.Status != 1)
|
||||
{
|
||||
return LinkResult.GeneralFailure;
|
||||
}
|
||||
|
||||
this.LinkedAccount = addAuthenticatorResponse.Response;
|
||||
LinkedAccount.Session = this._session;
|
||||
LinkedAccount.DeviceID = this.DeviceID;
|
||||
|
||||
return LinkResult.AwaitingFinalization;
|
||||
}
|
||||
|
||||
public FinalizeResult FinalizeAddAuthenticator(string smsCode)
|
||||
{
|
||||
bool smsCodeGood = false;
|
||||
|
||||
var postData = new NameValueCollection();
|
||||
postData.Add("steamid", _session.SteamID.ToString());
|
||||
postData.Add("access_token", _session.OAuthToken);
|
||||
postData.Add("activation_code", smsCode);
|
||||
postData.Add("authenticator_code", "");
|
||||
int tries = 0;
|
||||
while (tries <= 30)
|
||||
{
|
||||
postData.Set("authenticator_code", tries == 0 ? "" : LinkedAccount.GenerateSteamGuardCode());
|
||||
postData.Add("authenticator_time", TimeAligner.GetSteamTime().ToString());
|
||||
|
||||
if(smsCodeGood)
|
||||
postData.Set("activation_code", "");
|
||||
|
||||
string response = SteamWeb.MobileLoginRequest(APIEndpoints.STEAMAPI_BASE + "/ITwoFactorService/FinalizeAddAuthenticator/v0001", "POST", postData);
|
||||
if (response == null) return FinalizeResult.GeneralFailure;
|
||||
|
||||
var finalizeResponse = JsonConvert.DeserializeObject<FinalizeAuthenticatorResponse>(response);
|
||||
|
||||
if (finalizeResponse == null || finalizeResponse.Response == null)
|
||||
{
|
||||
return FinalizeResult.GeneralFailure;
|
||||
}
|
||||
|
||||
if(finalizeResponse.Response.Status == 89)
|
||||
{
|
||||
return FinalizeResult.BadSMSCode;
|
||||
}
|
||||
|
||||
if(finalizeResponse.Response.Status == 88)
|
||||
{
|
||||
if(tries >= 30)
|
||||
{
|
||||
return FinalizeResult.UnableToGenerateCorrectCodes;
|
||||
}
|
||||
}
|
||||
|
||||
if (!finalizeResponse.Response.Success)
|
||||
{
|
||||
return FinalizeResult.GeneralFailure;
|
||||
}
|
||||
|
||||
if (finalizeResponse.Response.WantMore)
|
||||
{
|
||||
smsCodeGood = true;
|
||||
tries++;
|
||||
continue;
|
||||
}
|
||||
|
||||
this.LinkedAccount.FullyEnrolled = true;
|
||||
return FinalizeResult.Success;
|
||||
}
|
||||
|
||||
return FinalizeResult.GeneralFailure;
|
||||
}
|
||||
|
||||
private bool _addPhoneNumber()
|
||||
{
|
||||
var postData = new NameValueCollection();
|
||||
postData.Add("op", "add_phone_number");
|
||||
postData.Add("arg", PhoneNumber);
|
||||
postData.Add("sessionid", _session.SessionID);
|
||||
|
||||
string response = SteamWeb.Request(APIEndpoints.COMMUNITY_BASE + "/steamguard/phoneajax", "POST", postData, _cookies);
|
||||
if (response == null) return false;
|
||||
|
||||
var addPhoneNumberResponse = JsonConvert.DeserializeObject<AddPhoneResponse>(response);
|
||||
return addPhoneNumberResponse.Success;
|
||||
}
|
||||
|
||||
private bool _hasPhoneAttached()
|
||||
{
|
||||
var postData = new NameValueCollection();
|
||||
postData.Add("op", "has_phone");
|
||||
postData.Add("arg", "null");
|
||||
postData.Add("sessionid", _session.SessionID);
|
||||
|
||||
string response = SteamWeb.Request(APIEndpoints.COMMUNITY_BASE + "/steamguard/phoneajax", "POST", postData, _cookies);
|
||||
if (response == null) return false;
|
||||
|
||||
var hasPhoneResponse = JsonConvert.DeserializeObject<HasPhoneResponse>(response);
|
||||
return hasPhoneResponse.HasPhone;
|
||||
}
|
||||
|
||||
public enum LinkResult
|
||||
{
|
||||
MustProvidePhoneNumber, //No phone number on the account
|
||||
MustRemovePhoneNumber, //A phone number is already on the account
|
||||
AwaitingFinalization, //Must provide an SMS code
|
||||
GeneralFailure, //General failure (really now!)
|
||||
AuthenticatorPresent
|
||||
}
|
||||
|
||||
public enum FinalizeResult
|
||||
{
|
||||
BadSMSCode,
|
||||
UnableToGenerateCorrectCodes,
|
||||
Success,
|
||||
GeneralFailure
|
||||
}
|
||||
|
||||
private class AddAuthenticatorResponse
|
||||
{
|
||||
[JsonProperty("response")]
|
||||
public SteamGuardAccount Response { get; set; }
|
||||
}
|
||||
|
||||
private class FinalizeAuthenticatorResponse
|
||||
{
|
||||
[JsonProperty("response")]
|
||||
public FinalizeAuthenticatorInternalResponse Response { get; set; }
|
||||
|
||||
internal class FinalizeAuthenticatorInternalResponse
|
||||
{
|
||||
[JsonProperty("status")]
|
||||
public int Status { get; set; }
|
||||
|
||||
[JsonProperty("server_time")]
|
||||
public long ServerTime { get; set; }
|
||||
|
||||
[JsonProperty("want_more")]
|
||||
public bool WantMore { get; set; }
|
||||
|
||||
[JsonProperty("success")]
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
private class HasPhoneResponse
|
||||
{
|
||||
[JsonProperty("has_phone")]
|
||||
public bool HasPhone { get; set; }
|
||||
}
|
||||
|
||||
private class AddPhoneResponse
|
||||
{
|
||||
[JsonProperty("success")]
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
|
||||
public static string GenerateDeviceID()
|
||||
{
|
||||
using (var sha1 = new SHA1Managed())
|
||||
{
|
||||
RNGCryptoServiceProvider secureRandom = new RNGCryptoServiceProvider();
|
||||
byte[] randomBytes = new byte[8];
|
||||
secureRandom.GetBytes(randomBytes);
|
||||
|
||||
byte[] hashedBytes = sha1.ComputeHash(randomBytes);
|
||||
string random32 = BitConverter.ToString(hashedBytes).Replace("-", "").Substring(0, 32).ToLower();
|
||||
|
||||
return "android:" + SplitOnRatios(random32, new[] { 8, 4, 4, 4, 12 }, "-");
|
||||
}
|
||||
}
|
||||
|
||||
private static string SplitOnRatios(string str, int[] ratios, string intermediate)
|
||||
{
|
||||
string result = "";
|
||||
|
||||
int pos = 0;
|
||||
for (int index = 0; index < ratios.Length; index++)
|
||||
{
|
||||
result += str.Substring(pos, ratios[index]);
|
||||
pos = ratios[index];
|
||||
|
||||
if (index < ratios.Length - 1)
|
||||
result += intermediate;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
SteamAuth/Confirmation.cs
Normal file
15
SteamAuth/Confirmation.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SteamAuth
|
||||
{
|
||||
public class Confirmation
|
||||
{
|
||||
public string ConfirmationID;
|
||||
public string ConfirmationKey;
|
||||
public string ConfirmationDescription;
|
||||
}
|
||||
}
|
||||
36
SteamAuth/Properties/AssemblyInfo.cs
Normal file
36
SteamAuth/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SteamAuth")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SteamAuth")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("5ad0934e-f6c4-4ae5-83af-c788313b2a87")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
40
SteamAuth/SessionData.cs
Normal file
40
SteamAuth/SessionData.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Net;
|
||||
|
||||
namespace SteamAuth
|
||||
{
|
||||
public class SessionData
|
||||
{
|
||||
public string SessionID { get; set; }
|
||||
|
||||
public string SteamLogin { get; set; }
|
||||
|
||||
public string SteamLoginSecure { get; set; }
|
||||
|
||||
public string WebCookie { get; set; }
|
||||
|
||||
public string OAuthToken { get; set; }
|
||||
|
||||
public ulong SteamID { get; set; }
|
||||
|
||||
public void AddCookies(CookieContainer cookies)
|
||||
{
|
||||
cookies.Add(new Cookie("mobileClientVersion", "0 (2.1.3)", "/", ".steamcommunity.com"));
|
||||
cookies.Add(new Cookie("mobileClient", "android", "/", ".steamcommunity.com"));
|
||||
|
||||
cookies.Add(new Cookie("steamid", SteamID.ToString(), "/", ".steamcommunity.com"));
|
||||
cookies.Add(new Cookie("steamLogin", SteamLogin, "/", ".steamcommunity.com")
|
||||
{
|
||||
HttpOnly = true
|
||||
});
|
||||
|
||||
cookies.Add(new Cookie("steamLoginSecure", SteamLoginSecure, "/", ".steamcommunity.com")
|
||||
{
|
||||
HttpOnly = true,
|
||||
Secure = true
|
||||
});
|
||||
cookies.Add(new Cookie("Steam_Language", "english", "/", ".steamcommunity.com"));
|
||||
cookies.Add(new Cookie("dob", "", "/", ".steamcommunity.com"));
|
||||
cookies.Add(new Cookie("sessionid", this.SessionID, "/", ".steamcommunity.com"));
|
||||
}
|
||||
}
|
||||
}
|
||||
69
SteamAuth/SteamAuth.csproj
Normal file
69
SteamAuth/SteamAuth.csproj
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SteamAuth</RootNamespace>
|
||||
<AssemblyName>SteamAuth</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.8.0.1-beta3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="APIEndpoints.cs" />
|
||||
<Compile Include="AuthenticatorLinker.cs" />
|
||||
<Compile Include="Confirmation.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SessionData.cs" />
|
||||
<Compile Include="SteamGuardAccount.cs" />
|
||||
<Compile Include="SteamWeb.cs" />
|
||||
<Compile Include="TimeAligner.cs" />
|
||||
<Compile Include="UserLogin.cs" />
|
||||
<Compile Include="Util.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
28
SteamAuth/SteamAuth.sln
Normal file
28
SteamAuth/SteamAuth.sln
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.23107.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SteamAuth", "SteamAuth.csproj", "{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestBed", "..\TestBed\TestBed.csproj", "{8A732227-C090-4011-9F0A-51180CFE6271}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5AD0934E-F6C4-4AE5-83AF-C788313B2A87}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8A732227-C090-4011-9F0A-51180CFE6271}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8A732227-C090-4011-9F0A-51180CFE6271}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8A732227-C090-4011-9F0A-51180CFE6271}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8A732227-C090-4011-9F0A-51180CFE6271}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
419
SteamAuth/SteamGuardAccount.cs
Normal file
419
SteamAuth/SteamGuardAccount.cs
Normal file
@@ -0,0 +1,419 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SteamAuth
|
||||
{
|
||||
public class SteamGuardAccount
|
||||
{
|
||||
[JsonProperty("shared_secret")]
|
||||
public string SharedSecret { get; set; }
|
||||
|
||||
[JsonProperty("serial_number")]
|
||||
public string SerialNumber { get; set; }
|
||||
|
||||
[JsonProperty("revocation_code")]
|
||||
public string RevocationCode { get; set; }
|
||||
|
||||
[JsonProperty("uri")]
|
||||
public string URI { get; set; }
|
||||
|
||||
[JsonProperty("server_time")]
|
||||
public long ServerTime { get; set; }
|
||||
|
||||
[JsonProperty("account_name")]
|
||||
public string AccountName { get; set; }
|
||||
|
||||
[JsonProperty("token_gid")]
|
||||
public string TokenGID { get; set; }
|
||||
|
||||
[JsonProperty("identity_secret")]
|
||||
public string IdentitySecret { get; set; }
|
||||
|
||||
[JsonProperty("secret_1")]
|
||||
public string Secret1 { get; set; }
|
||||
|
||||
[JsonProperty("status")]
|
||||
public int Status { get; set; }
|
||||
|
||||
[JsonProperty("device_id")]
|
||||
public string DeviceID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if the authenticator has actually been applied to the account.
|
||||
/// </summary>
|
||||
[JsonProperty("fully_enrolled")]
|
||||
public bool FullyEnrolled { get; set; }
|
||||
|
||||
public SessionData Session { get; set; }
|
||||
|
||||
private static byte[] steamGuardCodeTranslations = new byte[] { 50, 51, 52, 53, 54, 55, 56, 57, 66, 67, 68, 70, 71, 72, 74, 75, 77, 78, 80, 81, 82, 84, 86, 87, 88, 89 };
|
||||
|
||||
public bool DeactivateAuthenticator(int scheme = 2)
|
||||
{
|
||||
var postData = new NameValueCollection();
|
||||
postData.Add("steamid", this.Session.SteamID.ToString());
|
||||
postData.Add("steamguard_scheme", scheme.ToString());
|
||||
postData.Add("revocation_code", this.RevocationCode);
|
||||
postData.Add("access_token", this.Session.OAuthToken);
|
||||
|
||||
try
|
||||
{
|
||||
string response = SteamWeb.MobileLoginRequest(APIEndpoints.STEAMAPI_BASE + "/ITwoFactorService/RemoveAuthenticator/v0001", "POST", postData);
|
||||
var removeResponse = JsonConvert.DeserializeObject<RemoveAuthenticatorResponse>(response);
|
||||
|
||||
if (removeResponse == null || removeResponse.Response == null || !removeResponse.Response.Success) return false;
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public string GenerateSteamGuardCode()
|
||||
{
|
||||
return GenerateSteamGuardCodeForTime(TimeAligner.GetSteamTime());
|
||||
}
|
||||
|
||||
public string GenerateSteamGuardCodeForTime(long time)
|
||||
{
|
||||
if (this.SharedSecret == null || this.SharedSecret.Length == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
byte[] sharedSecretArray = Convert.FromBase64String(this.SharedSecret);
|
||||
byte[] timeArray = new byte[8];
|
||||
|
||||
time /= 30L;
|
||||
|
||||
for (int i = 8; i > 0; i--)
|
||||
{
|
||||
timeArray[i - 1] = (byte)time;
|
||||
time >>= 8;
|
||||
}
|
||||
|
||||
HMACSHA1 hmacGenerator = new HMACSHA1();
|
||||
hmacGenerator.Key = sharedSecretArray;
|
||||
byte[] hashedData = hmacGenerator.ComputeHash(timeArray);
|
||||
byte[] codeArray = new byte[5];
|
||||
try
|
||||
{
|
||||
byte b = (byte)(hashedData[19] & 0xF);
|
||||
int codePoint = (hashedData[b] & 0x7F) << 24 | (hashedData[b + 1] & 0xFF) << 16 | (hashedData[b + 2] & 0xFF) << 8 | (hashedData[b + 3] & 0xFF);
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
codeArray[i] = steamGuardCodeTranslations[codePoint % steamGuardCodeTranslations.Length];
|
||||
codePoint /= steamGuardCodeTranslations.Length;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null; //Change later, catch-alls are bad!
|
||||
}
|
||||
return Encoding.UTF8.GetString(codeArray);
|
||||
}
|
||||
|
||||
public Confirmation[] FetchConfirmations()
|
||||
{
|
||||
string url = this.GenerateConfirmationURL();
|
||||
|
||||
CookieContainer cookies = new CookieContainer();
|
||||
this.Session.AddCookies(cookies);
|
||||
|
||||
string response = SteamWeb.Request(url, "GET", null, cookies);
|
||||
|
||||
/*So you're going to see this abomination and you're going to be upset.
|
||||
It's understandable. But the thing is, regex for HTML -- while awful -- makes this way faster than parsing a DOM, plus we don't need another library.
|
||||
And because the data is always in the same place and same format... It's not as if we're trying to naturally understand HTML here. Just extract strings.
|
||||
I'm sorry. */
|
||||
|
||||
Regex confIDRegex = new Regex("data-confid=\"(\\d+)\"");
|
||||
Regex confKeyRegex = new Regex("data-key=\"(\\d+)\"");
|
||||
Regex confDescRegex = new Regex("<div>((Confirm|Trade with|Sell -) .+)</div>");
|
||||
|
||||
if (response == null || !(confIDRegex.IsMatch(response) && confKeyRegex.IsMatch(response) && confDescRegex.IsMatch(response)))
|
||||
{
|
||||
if (response == null || !response.Contains("<div>Nothing to confirm</div>"))
|
||||
{
|
||||
throw new WGTokenInvalidException();
|
||||
}
|
||||
|
||||
return new Confirmation[0];
|
||||
}
|
||||
|
||||
MatchCollection confIDs = confIDRegex.Matches(response);
|
||||
MatchCollection confKeys = confKeyRegex.Matches(response);
|
||||
MatchCollection confDescs = confDescRegex.Matches(response);
|
||||
|
||||
List<Confirmation> ret = new List<Confirmation>();
|
||||
for (int i = 0; i < confIDs.Count; i++)
|
||||
{
|
||||
string confID = confIDs[i].Groups[1].Value;
|
||||
string confKey = confKeys[i].Groups[1].Value;
|
||||
string confDesc = confDescs[i].Groups[1].Value;
|
||||
Confirmation conf = new Confirmation()
|
||||
{
|
||||
ConfirmationDescription = confDesc,
|
||||
ConfirmationID = confID,
|
||||
ConfirmationKey = confKey
|
||||
};
|
||||
ret.Add(conf);
|
||||
}
|
||||
|
||||
return ret.ToArray();
|
||||
}
|
||||
|
||||
public async Task<Confirmation[]> FetchConfirmationsAsync()
|
||||
{
|
||||
string url = this.GenerateConfirmationURL();
|
||||
|
||||
CookieContainer cookies = new CookieContainer();
|
||||
this.Session.AddCookies(cookies);
|
||||
|
||||
string response = await SteamWeb.RequestAsync(url, "GET", null, cookies);
|
||||
|
||||
/*So you're going to see this abomination and you're going to be upset.
|
||||
It's understandable. But the thing is, regex for HTML -- while awful -- makes this way faster than parsing a DOM, plus we don't need another library.
|
||||
And because the data is always in the same place and same format... It's not as if we're trying to naturally understand HTML here. Just extract strings.
|
||||
I'm sorry. */
|
||||
|
||||
Regex confIDRegex = new Regex("data-confid=\"(\\d+)\"");
|
||||
Regex confKeyRegex = new Regex("data-key=\"(\\d+)\"");
|
||||
Regex confDescRegex = new Regex("<div>((Confirm|Trade with|Sell -) .+)</div>");
|
||||
|
||||
if (response == null || !(confIDRegex.IsMatch(response) && confKeyRegex.IsMatch(response) && confDescRegex.IsMatch(response)))
|
||||
{
|
||||
if (response == null || !response.Contains("<div>Nothing to confirm</div>"))
|
||||
{
|
||||
throw new WGTokenInvalidException();
|
||||
}
|
||||
|
||||
return new Confirmation[0];
|
||||
}
|
||||
|
||||
MatchCollection confIDs = confIDRegex.Matches(response);
|
||||
MatchCollection confKeys = confKeyRegex.Matches(response);
|
||||
MatchCollection confDescs = confDescRegex.Matches(response);
|
||||
|
||||
List<Confirmation> ret = new List<Confirmation>();
|
||||
for (int i = 0; i < confIDs.Count; i++)
|
||||
{
|
||||
string confID = confIDs[i].Groups[1].Value;
|
||||
string confKey = confKeys[i].Groups[1].Value;
|
||||
string confDesc = confDescs[i].Groups[1].Value;
|
||||
Confirmation conf = new Confirmation()
|
||||
{
|
||||
ConfirmationDescription = confDesc,
|
||||
ConfirmationID = confID,
|
||||
ConfirmationKey = confKey
|
||||
};
|
||||
ret.Add(conf);
|
||||
}
|
||||
|
||||
return ret.ToArray();
|
||||
}
|
||||
|
||||
public bool AcceptConfirmation(Confirmation conf)
|
||||
{
|
||||
return _sendConfirmationAjax(conf, "allow");
|
||||
}
|
||||
|
||||
public bool DenyConfirmation(Confirmation conf)
|
||||
{
|
||||
return _sendConfirmationAjax(conf, "cancel");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the Steam session. Necessary to perform confirmations if your session has expired or changed.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool RefreshSession()
|
||||
{
|
||||
string url = APIEndpoints.MOBILEAUTH_GETWGTOKEN;
|
||||
NameValueCollection postData = new NameValueCollection();
|
||||
postData.Add("access_token", this.Session.OAuthToken);
|
||||
|
||||
string response = SteamWeb.Request(url, "POST", postData);
|
||||
if (response == null) return false;
|
||||
|
||||
try
|
||||
{
|
||||
var refreshResponse = JsonConvert.DeserializeObject<RefreshSessionDataResponse>(response);
|
||||
if (refreshResponse == null || refreshResponse.Response == null || String.IsNullOrEmpty(refreshResponse.Response.Token))
|
||||
return false;
|
||||
|
||||
string token = this.Session.SteamID + "%7C%7C" + refreshResponse.Response.Token;
|
||||
string tokenSecure = this.Session.SteamID + "%7C%7C" + refreshResponse.Response.TokenSecure;
|
||||
|
||||
this.Session.SteamLogin = token;
|
||||
this.Session.SteamLoginSecure = tokenSecure;
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the Steam session. Necessary to perform confirmations if your session has expired or changed.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> RefreshSessionAsync()
|
||||
{
|
||||
string url = APIEndpoints.MOBILEAUTH_GETWGTOKEN;
|
||||
NameValueCollection postData = new NameValueCollection();
|
||||
postData.Add("access_token", this.Session.OAuthToken);
|
||||
|
||||
string response = await SteamWeb.RequestAsync(url, "POST", postData);
|
||||
if (response == null) return false;
|
||||
|
||||
try
|
||||
{
|
||||
var refreshResponse = JsonConvert.DeserializeObject<RefreshSessionDataResponse>(response);
|
||||
if (refreshResponse == null || refreshResponse.Response == null || String.IsNullOrEmpty(refreshResponse.Response.Token))
|
||||
return false;
|
||||
|
||||
string token = this.Session.SteamID + "%7C%7C" + refreshResponse.Response.Token;
|
||||
string tokenSecure = this.Session.SteamID + "%7C%7C" + refreshResponse.Response.TokenSecure;
|
||||
|
||||
this.Session.SteamLogin = token;
|
||||
this.Session.SteamLoginSecure = tokenSecure;
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _sendConfirmationAjax(Confirmation conf, string op)
|
||||
{
|
||||
string url = APIEndpoints.COMMUNITY_BASE + "/mobileconf/ajaxop";
|
||||
string queryString = "?op=" + op + "&";
|
||||
queryString += GenerateConfirmationQueryParams(op);
|
||||
queryString += "&cid=" + conf.ConfirmationID + "&ck=" + conf.ConfirmationKey;
|
||||
url += queryString;
|
||||
|
||||
CookieContainer cookies = new CookieContainer();
|
||||
this.Session.AddCookies(cookies);
|
||||
string referer = GenerateConfirmationURL();
|
||||
|
||||
string response = SteamWeb.Request(url, "GET", null, cookies, null);
|
||||
if (response == null) return false;
|
||||
|
||||
SendConfirmationResponse confResponse = JsonConvert.DeserializeObject<SendConfirmationResponse>(response);
|
||||
return confResponse.Success;
|
||||
}
|
||||
|
||||
public string GenerateConfirmationURL(string tag = "conf")
|
||||
{
|
||||
string endpoint = APIEndpoints.COMMUNITY_BASE + "/mobileconf/conf?";
|
||||
string queryString = GenerateConfirmationQueryParams(tag);
|
||||
return endpoint + queryString;
|
||||
}
|
||||
|
||||
public string GenerateConfirmationQueryParams(string tag)
|
||||
{
|
||||
if (String.IsNullOrEmpty(DeviceID))
|
||||
DeviceID = AuthenticatorLinker.GenerateDeviceID();
|
||||
|
||||
long time = TimeAligner.GetSteamTime();
|
||||
return "p=" + this.DeviceID + "&a=" + this.Session.SteamID.ToString() + "&k=" + _generateConfirmationHashForTime(time, tag) + "&t=" + time + "&m=android&tag=" + tag;
|
||||
}
|
||||
|
||||
private string _generateConfirmationHashForTime(long time, string tag)
|
||||
{
|
||||
byte[] decode = Convert.FromBase64String(this.IdentitySecret);
|
||||
int n2 = 8;
|
||||
if (tag != null)
|
||||
{
|
||||
if (tag.Length > 32)
|
||||
{
|
||||
n2 = 8 + 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
n2 = 8 + tag.Length;
|
||||
}
|
||||
}
|
||||
byte[] array = new byte[n2];
|
||||
int n3 = 8;
|
||||
while (true)
|
||||
{
|
||||
int n4 = n3 - 1;
|
||||
if (n3 <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
array[n4] = (byte)time;
|
||||
time >>= 8;
|
||||
n3 = n4;
|
||||
}
|
||||
if (tag != null)
|
||||
{
|
||||
Array.Copy(Encoding.UTF8.GetBytes(tag), 0, array, 8, n2 - 8);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
HMACSHA1 hmacGenerator = new HMACSHA1();
|
||||
hmacGenerator.Key = decode;
|
||||
byte[] hashedData = hmacGenerator.ComputeHash(array);
|
||||
string encodedData = Convert.ToBase64String(hashedData, Base64FormattingOptions.None);
|
||||
string hash = WebUtility.UrlEncode(encodedData);
|
||||
return hash;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null; //Fix soon: catch-all is BAD!
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Determine how to detect an invalid session.
|
||||
public class WGTokenInvalidException : Exception
|
||||
{
|
||||
}
|
||||
|
||||
private class RefreshSessionDataResponse
|
||||
{
|
||||
[JsonProperty("response")]
|
||||
public RefreshSessionDataInternalResponse Response { get; set; }
|
||||
internal class RefreshSessionDataInternalResponse
|
||||
{
|
||||
[JsonProperty("token")]
|
||||
public string Token { get; set; }
|
||||
|
||||
[JsonProperty("token_secure")]
|
||||
public string TokenSecure { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
private class RemoveAuthenticatorResponse
|
||||
{
|
||||
[JsonProperty("response")]
|
||||
public RemoveAuthenticatorInternalResponse Response { get; set; }
|
||||
|
||||
internal class RemoveAuthenticatorInternalResponse
|
||||
{
|
||||
[JsonProperty("success")]
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
private class SendConfirmationResponse
|
||||
{
|
||||
[JsonProperty("success")]
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
137
SteamAuth/SteamWeb.cs
Normal file
137
SteamAuth/SteamWeb.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SteamAuth
|
||||
{
|
||||
public class SteamWeb
|
||||
{
|
||||
/// <summary>
|
||||
/// Perform a mobile login request
|
||||
/// </summary>
|
||||
/// <param name="url">API url</param>
|
||||
/// <param name="method">GET or POST</param>
|
||||
/// <param name="data">Name-data pairs</param>
|
||||
/// <param name="cookies">current cookie container</param>
|
||||
/// <returns>response body</returns>
|
||||
public static string MobileLoginRequest(string url, string method, NameValueCollection data = null, CookieContainer cookies = null, NameValueCollection headers = null)
|
||||
{
|
||||
return Request(url, method, data, cookies, headers, APIEndpoints.COMMUNITY_BASE + "/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client");
|
||||
}
|
||||
|
||||
public static string Request(string url, string method, NameValueCollection data = null, CookieContainer cookies = null, NameValueCollection headers = null, string referer = APIEndpoints.COMMUNITY_BASE)
|
||||
{
|
||||
string query = (data == null ? string.Empty : string.Join("&", Array.ConvertAll(data.AllKeys, key => String.Format("{0}={1}", WebUtility.UrlEncode(key), WebUtility.UrlEncode(data[key])))));
|
||||
if (method == "GET")
|
||||
{
|
||||
url += (url.Contains("?") ? "&" : "?") + query;
|
||||
}
|
||||
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
|
||||
request.Method = method;
|
||||
request.Accept = "text/javascript, text/html, application/xml, text/xml, */*";
|
||||
request.UserAgent = "Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Google Nexus 4 - 4.1.1 - API 16 - 768x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30";
|
||||
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
|
||||
request.Referer = referer;
|
||||
|
||||
if (headers != null)
|
||||
{
|
||||
request.Headers.Add(headers);
|
||||
}
|
||||
|
||||
if (cookies != null)
|
||||
{
|
||||
request.CookieContainer = cookies;
|
||||
}
|
||||
|
||||
if (method == "POST")
|
||||
{
|
||||
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
|
||||
request.ContentLength = query.Length;
|
||||
|
||||
StreamWriter requestStream = new StreamWriter(request.GetRequestStream());
|
||||
requestStream.Write(query);
|
||||
requestStream.Close();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
|
||||
{
|
||||
if (response.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (StreamReader responseStream = new StreamReader(response.GetResponseStream()))
|
||||
{
|
||||
string responseData = responseStream.ReadToEnd();
|
||||
return responseData;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<string> RequestAsync(string url, string method, NameValueCollection data = null, CookieContainer cookies = null, NameValueCollection headers = null, string referer = APIEndpoints.COMMUNITY_BASE)
|
||||
{
|
||||
string query = (data == null ? string.Empty : string.Join("&", Array.ConvertAll(data.AllKeys, key => String.Format("{0}={1}", WebUtility.UrlEncode(key), WebUtility.UrlEncode(data[key])))));
|
||||
if (method == "GET")
|
||||
{
|
||||
url += (url.Contains("?") ? "&" : "?") + query;
|
||||
}
|
||||
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
|
||||
request.Method = method;
|
||||
request.Accept = "text/javascript, text/html, application/xml, text/xml, */*";
|
||||
request.UserAgent = "Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Google Nexus 4 - 4.1.1 - API 16 - 768x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30";
|
||||
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
|
||||
request.Referer = referer;
|
||||
|
||||
if (headers != null)
|
||||
{
|
||||
request.Headers.Add(headers);
|
||||
}
|
||||
|
||||
if (cookies != null)
|
||||
{
|
||||
request.CookieContainer = cookies;
|
||||
}
|
||||
|
||||
if (method == "POST")
|
||||
{
|
||||
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
|
||||
request.ContentLength = query.Length;
|
||||
|
||||
StreamWriter requestStream = new StreamWriter(request.GetRequestStream());
|
||||
requestStream.Write(query);
|
||||
requestStream.Close();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
HttpWebResponse response = (HttpWebResponse) await request.GetResponseAsync();
|
||||
|
||||
if (response.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (StreamReader responseStream = new StreamReader(response.GetResponseStream()))
|
||||
{
|
||||
string responseData = responseStream.ReadToEnd();
|
||||
return responseData;
|
||||
}
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
84
SteamAuth/TimeAligner.cs
Normal file
84
SteamAuth/TimeAligner.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SteamAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to help align system time with the Steam server time. Not super advanced; probably not taking some things into account that it should.
|
||||
/// Necessary to generate up-to-date codes. In general, this will have an error of less than a second, assuming Steam is operational.
|
||||
/// </summary>
|
||||
public class TimeAligner
|
||||
{
|
||||
private static bool _aligned = false;
|
||||
private static int _timeDifference = 0;
|
||||
|
||||
public static long GetSteamTime()
|
||||
{
|
||||
if (!TimeAligner._aligned)
|
||||
{
|
||||
TimeAligner.AlignTime();
|
||||
}
|
||||
return Util.GetSystemUnixTime() + _timeDifference;
|
||||
}
|
||||
|
||||
public static async Task<long> GetSteamTimeAsync()
|
||||
{
|
||||
if (!TimeAligner._aligned)
|
||||
{
|
||||
await TimeAligner.AlignTimeAsync();
|
||||
}
|
||||
return Util.GetSystemUnixTime() + _timeDifference;
|
||||
}
|
||||
|
||||
public static void AlignTime()
|
||||
{
|
||||
long currentTime = Util.GetSystemUnixTime();
|
||||
using (WebClient client = new WebClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
string response = client.UploadString(APIEndpoints.TWO_FACTOR_TIME_QUERY, "steamid=0");
|
||||
TimeQuery query = JsonConvert.DeserializeObject<TimeQuery>(response);
|
||||
TimeAligner._timeDifference = (int)(query.Response.ServerTime - currentTime);
|
||||
TimeAligner._aligned = true;
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task AlignTimeAsync()
|
||||
{
|
||||
long currentTime = Util.GetSystemUnixTime();
|
||||
WebClient client = new WebClient();
|
||||
try
|
||||
{
|
||||
string response = await client.UploadStringTaskAsync(new Uri(APIEndpoints.TWO_FACTOR_TIME_QUERY), "steamid=0");
|
||||
TimeQuery query = JsonConvert.DeserializeObject<TimeQuery>(response);
|
||||
TimeAligner._timeDifference = (int)(query.Response.ServerTime - currentTime);
|
||||
TimeAligner._aligned = true;
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
internal class TimeQuery
|
||||
{
|
||||
[JsonProperty("response")]
|
||||
internal TimeQueryResponse Response { get; set; }
|
||||
|
||||
internal class TimeQueryResponse
|
||||
{
|
||||
[JsonProperty("server_time")]
|
||||
public long ServerTime { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
254
SteamAuth/UserLogin.cs
Normal file
254
SteamAuth/UserLogin.cs
Normal file
@@ -0,0 +1,254 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace SteamAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles logging the user into the mobile Steam website. Necessary to generate OAuth token and session cookies.
|
||||
/// </summary>
|
||||
public class UserLogin
|
||||
{
|
||||
public string Username;
|
||||
public string Password;
|
||||
public ulong SteamID;
|
||||
|
||||
public bool RequiresCaptcha;
|
||||
public string CaptchaGID = null;
|
||||
public string CaptchaText = null;
|
||||
|
||||
public bool RequiresEmail;
|
||||
public string EmailDomain = null;
|
||||
public string EmailCode = null;
|
||||
|
||||
public bool Requires2FA;
|
||||
public string TwoFactorCode = null;
|
||||
|
||||
public SessionData Session = null;
|
||||
public bool LoggedIn = false;
|
||||
|
||||
private CookieContainer _cookies = new CookieContainer();
|
||||
|
||||
public UserLogin(string username, string password)
|
||||
{
|
||||
this.Username = username;
|
||||
this.Password = password;
|
||||
}
|
||||
|
||||
public LoginResult DoLogin()
|
||||
{
|
||||
var postData = new NameValueCollection();
|
||||
var cookies = _cookies;
|
||||
string response = null;
|
||||
|
||||
if (cookies.Count == 0)
|
||||
{
|
||||
//Generate a SessionID
|
||||
cookies.Add(new Cookie("mobileClientVersion", "0 (2.1.3)", "/", ".steamcommunity.com"));
|
||||
cookies.Add(new Cookie("mobileClient", "android", "/", ".steamcommunity.com"));
|
||||
cookies.Add(new Cookie("Steam_Language", "english", "/", ".steamcommunity.com"));
|
||||
|
||||
NameValueCollection headers = new NameValueCollection();
|
||||
headers.Add("X-Requested-With", "com.valvesoftware.android.steam.community");
|
||||
|
||||
SteamWeb.MobileLoginRequest("https://steamcommunity.com/login?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client", "GET", null, cookies, headers);
|
||||
}
|
||||
|
||||
postData.Add("username", this.Username);
|
||||
response = SteamWeb.MobileLoginRequest(APIEndpoints.COMMUNITY_BASE + "/login/getrsakey", "POST", postData, cookies);
|
||||
if (response == null || response.Contains("<BODY>\nAn error occurred while processing your request.")) return LoginResult.GeneralFailure;
|
||||
|
||||
var rsaResponse = JsonConvert.DeserializeObject<RSAResponse>(response);
|
||||
|
||||
if (!rsaResponse.Success)
|
||||
{
|
||||
return LoginResult.BadRSA;
|
||||
}
|
||||
|
||||
RNGCryptoServiceProvider secureRandom = new RNGCryptoServiceProvider();
|
||||
byte[] encryptedPasswordBytes;
|
||||
using (var rsaEncryptor = new RSACryptoServiceProvider())
|
||||
{
|
||||
var passwordBytes = Encoding.ASCII.GetBytes(this.Password);
|
||||
var rsaParameters = rsaEncryptor.ExportParameters(false);
|
||||
rsaParameters.Exponent = Util.HexStringToByteArray(rsaResponse.Exponent);
|
||||
rsaParameters.Modulus = Util.HexStringToByteArray(rsaResponse.Modulus);
|
||||
rsaEncryptor.ImportParameters(rsaParameters);
|
||||
encryptedPasswordBytes = rsaEncryptor.Encrypt(passwordBytes, false);
|
||||
}
|
||||
|
||||
string encryptedPassword = Convert.ToBase64String(encryptedPasswordBytes);
|
||||
|
||||
postData.Clear();
|
||||
postData.Add("username", this.Username);
|
||||
postData.Add("password", encryptedPassword);
|
||||
|
||||
postData.Add("twofactorcode", this.TwoFactorCode ?? "");
|
||||
|
||||
postData.Add("captchagid", this.RequiresCaptcha ? this.CaptchaGID : "-1");
|
||||
postData.Add("captcha_text", this.RequiresCaptcha ? this.CaptchaText : "");
|
||||
|
||||
postData.Add("emailsteamid", (this.Requires2FA || this.RequiresEmail) ? this.SteamID.ToString() : "");
|
||||
postData.Add("emailauth", this.RequiresEmail ? this.EmailCode : "");
|
||||
|
||||
postData.Add("rsatimestamp", rsaResponse.Timestamp);
|
||||
postData.Add("remember_login", "false");
|
||||
postData.Add("oauth_client_id", "DE45CD61");
|
||||
postData.Add("oauth_scope", "read_profile write_profile read_client write_client");
|
||||
postData.Add("loginfriendlyname", "#login_emailauth_friendlyname_mobile");
|
||||
postData.Add("donotcache", Util.GetSystemUnixTime().ToString());
|
||||
|
||||
response = SteamWeb.MobileLoginRequest(APIEndpoints.COMMUNITY_BASE + "/login/dologin", "POST", postData, cookies);
|
||||
if (response == null) return LoginResult.GeneralFailure;
|
||||
|
||||
var loginResponse = JsonConvert.DeserializeObject<LoginResponse>(response);
|
||||
|
||||
if (loginResponse.Message != null && loginResponse.Message.Contains("Incorrect login"))
|
||||
{
|
||||
return LoginResult.BadCredentials;
|
||||
}
|
||||
|
||||
if (loginResponse.CaptchaNeeded)
|
||||
{
|
||||
this.RequiresCaptcha = true;
|
||||
this.CaptchaGID = loginResponse.CaptchaGID;
|
||||
return LoginResult.NeedCaptcha;
|
||||
}
|
||||
|
||||
if (loginResponse.EmailAuthNeeded)
|
||||
{
|
||||
this.RequiresEmail = true;
|
||||
this.SteamID = loginResponse.EmailSteamID;
|
||||
return LoginResult.NeedEmail;
|
||||
}
|
||||
|
||||
if (loginResponse.TwoFactorNeeded && !loginResponse.Success)
|
||||
{
|
||||
this.Requires2FA = true;
|
||||
return LoginResult.Need2FA;
|
||||
}
|
||||
|
||||
if (loginResponse.Message != null && loginResponse.Message.Contains("too many login failures"))
|
||||
{
|
||||
return LoginResult.TooManyFailedLogins;
|
||||
}
|
||||
|
||||
if (loginResponse.OAuthData == null || loginResponse.OAuthData.OAuthToken == null || loginResponse.OAuthData.OAuthToken.Length == 0)
|
||||
{
|
||||
return LoginResult.GeneralFailure;
|
||||
}
|
||||
|
||||
if (!loginResponse.LoginComplete)
|
||||
{
|
||||
return LoginResult.BadCredentials;
|
||||
}
|
||||
else
|
||||
{
|
||||
var readableCookies = cookies.GetCookies(new Uri("https://steamcommunity.com"));
|
||||
var oAuthData = loginResponse.OAuthData;
|
||||
|
||||
SessionData session = new SessionData();
|
||||
session.OAuthToken = oAuthData.OAuthToken;
|
||||
session.SteamID = oAuthData.SteamID;
|
||||
session.SteamLogin = session.SteamID + "%7C%7C" + oAuthData.SteamLogin;
|
||||
session.SteamLoginSecure = session.SteamID + "%7C%7C" + oAuthData.SteamLoginSecure;
|
||||
session.WebCookie = oAuthData.Webcookie;
|
||||
session.SessionID = readableCookies["sessionid"].Value;
|
||||
this.Session = session;
|
||||
this.LoggedIn = true;
|
||||
return LoginResult.LoginOkay;
|
||||
}
|
||||
|
||||
return LoginResult.GeneralFailure;
|
||||
}
|
||||
|
||||
private class LoginResponse
|
||||
{
|
||||
[JsonProperty("success")]
|
||||
public bool Success { get; set; }
|
||||
|
||||
[JsonProperty("login_complete")]
|
||||
public bool LoginComplete { get; set; }
|
||||
|
||||
[JsonProperty("oauth")]
|
||||
public string OAuthDataString { get; set; }
|
||||
|
||||
public OAuth OAuthData
|
||||
{
|
||||
get
|
||||
{
|
||||
return OAuthDataString != null ? JsonConvert.DeserializeObject<OAuth>(OAuthDataString) : null;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("captcha_needed")]
|
||||
public bool CaptchaNeeded { get; set; }
|
||||
|
||||
[JsonProperty("captcha_gid")]
|
||||
public string CaptchaGID { get; set; }
|
||||
|
||||
[JsonProperty("emailsteamid")]
|
||||
public ulong EmailSteamID { get; set; }
|
||||
|
||||
[JsonProperty("emailauth_needed")]
|
||||
public bool EmailAuthNeeded { get; set; }
|
||||
|
||||
[JsonProperty("requires_twofactor")]
|
||||
public bool TwoFactorNeeded { get; set; }
|
||||
|
||||
[JsonProperty("message")]
|
||||
public string Message { get; set; }
|
||||
|
||||
internal class OAuth
|
||||
{
|
||||
[JsonProperty("steamid")]
|
||||
public ulong SteamID { get; set; }
|
||||
|
||||
[JsonProperty("oauth_token")]
|
||||
public string OAuthToken { get; set; }
|
||||
|
||||
[JsonProperty("wgtoken")]
|
||||
public string SteamLogin { get; set; }
|
||||
|
||||
[JsonProperty("wgtoken_secure")]
|
||||
public string SteamLoginSecure { get; set; }
|
||||
|
||||
[JsonProperty("webcookie")]
|
||||
public string Webcookie { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
private class RSAResponse
|
||||
{
|
||||
[JsonProperty("success")]
|
||||
public bool Success { get; set; }
|
||||
|
||||
[JsonProperty("publickey_exp")]
|
||||
public string Exponent { get; set; }
|
||||
|
||||
[JsonProperty("publickey_mod")]
|
||||
public string Modulus { get; set; }
|
||||
|
||||
[JsonProperty("timestamp")]
|
||||
public string Timestamp { get; set; }
|
||||
|
||||
[JsonProperty("steamid")]
|
||||
public ulong SteamID { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public enum LoginResult
|
||||
{
|
||||
LoginOkay,
|
||||
GeneralFailure,
|
||||
BadRSA,
|
||||
BadCredentials,
|
||||
NeedCaptcha,
|
||||
Need2FA,
|
||||
NeedEmail,
|
||||
TooManyFailedLogins,
|
||||
}
|
||||
}
|
||||
24
SteamAuth/Util.cs
Normal file
24
SteamAuth/Util.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace SteamAuth
|
||||
{
|
||||
public class Util
|
||||
{
|
||||
public static long GetSystemUnixTime()
|
||||
{
|
||||
return (long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
||||
}
|
||||
|
||||
public static byte[] HexStringToByteArray(string hex)
|
||||
{
|
||||
int hexLen = hex.Length;
|
||||
byte[] ret = new byte[hexLen / 2];
|
||||
for (int i = 0; i < hexLen; i += 2)
|
||||
{
|
||||
ret[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
4
SteamAuth/packages.config
Normal file
4
SteamAuth/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="8.0.1-beta3" targetFramework="net452" />
|
||||
</packages>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -106,7 +106,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Bson.BsonReader.Read">
|
||||
<summary>
|
||||
@@ -926,6 +926,25 @@
|
||||
Causes child objects to be indented according to the <see cref="P:Newtonsoft.Json.JsonTextWriter.Indentation"/> and <see cref="P:Newtonsoft.Json.JsonTextWriter.IndentChar"/> settings.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.IJsonBufferPool`1">
|
||||
<summary>
|
||||
Provides an interface for using pooled buffers.
|
||||
</summary>
|
||||
<typeparam name="T">The buffer type content.</typeparam>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.RentBuffer(System.Int32)">
|
||||
<summary>
|
||||
Rent a buffer from the pool. This buffer must be returned when it is no longer needed.
|
||||
</summary>
|
||||
<param name="minSize">The minimum required size of the buffer. The returned buffer may be larger.</param>
|
||||
<returns>The rented buffer from the pool.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.ReturnBuffer(`0[]@)">
|
||||
<summary>
|
||||
Return a buffer to the pool.
|
||||
</summary>
|
||||
<param name="buffer">The buffer that is being returned.</param>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.JsonConstructorAttribute">
|
||||
<summary>
|
||||
Instructs the <see cref="T:Newtonsoft.Json.JsonSerializer"/> to use the specified constructor when deserializing that object.
|
||||
@@ -1028,6 +1047,21 @@
|
||||
Load comments as a <see cref="T:Newtonsoft.Json.Linq.JValue"/> with type <see cref="F:Newtonsoft.Json.Linq.JTokenType.Comment"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.LineInfoHandling">
|
||||
<summary>
|
||||
Specifies how line information is handled when loading JSON.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Ignore">
|
||||
<summary>
|
||||
Ignore line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Load">
|
||||
<summary>
|
||||
Load line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.JsonLoadSettings">
|
||||
<summary>
|
||||
Specifies the settings used when loading JSON.
|
||||
@@ -1039,6 +1073,12 @@
|
||||
</summary>
|
||||
<value>The JSON comment handling.</value>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.Linq.JsonLoadSettings.LineInfoHandling">
|
||||
<summary>
|
||||
Gets or sets how JSON line info is handled when loading JSON.
|
||||
</summary>
|
||||
<value>The JSON line info handling.</value>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.JsonMergeSettings">
|
||||
<summary>
|
||||
Specifies the settings used when merging JSON.
|
||||
@@ -2167,7 +2207,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Linq.JTokenReader.Read">
|
||||
<summary>
|
||||
@@ -6074,6 +6114,11 @@
|
||||
The property must be defined in JSON and cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Required.DisallowNull">
|
||||
<summary>
|
||||
The property is not required but it cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.PreserveReferencesHandling">
|
||||
<summary>
|
||||
Specifies reference handling options for the <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
|
||||
@@ -6620,7 +6665,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonValidatingReader.Read">
|
||||
<summary>
|
||||
@@ -6685,6 +6730,11 @@
|
||||
</summary>
|
||||
<param name="reader">The <c>TextReader</c> containing the XML data to read.</param>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextReader.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the reader's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.Read">
|
||||
<summary>
|
||||
Reads the next JSON token from the stream.
|
||||
@@ -6723,7 +6773,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.Close">
|
||||
<summary>
|
||||
@@ -6871,6 +6921,11 @@
|
||||
Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the writer's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.Indentation">
|
||||
<summary>
|
||||
Gets or sets how many IndentChars to write for each level in the hierarchy when <see cref="T:Newtonsoft.Json.Formatting"/> is set to <c>Formatting.Indented</c>.
|
||||
@@ -7470,7 +7525,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonReader.Skip">
|
||||
<summary>
|
||||
Binary file not shown.
@@ -89,7 +89,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Bson.BsonReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -977,6 +977,25 @@
|
||||
Causes child objects to be indented according to the <see cref="P:Newtonsoft.Json.JsonTextWriter.Indentation"/> and <see cref="P:Newtonsoft.Json.JsonTextWriter.IndentChar"/> settings.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.IJsonBufferPool`1">
|
||||
<summary>
|
||||
Provides an interface for using pooled buffers.
|
||||
</summary>
|
||||
<typeparam name="T">The buffer type content.</typeparam>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.RentBuffer(System.Int32)">
|
||||
<summary>
|
||||
Rent a buffer from the pool. This buffer must be returned when it is no longer needed.
|
||||
</summary>
|
||||
<param name="minSize">The minimum required size of the buffer. The returned buffer may be larger.</param>
|
||||
<returns>The rented buffer from the pool.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.ReturnBuffer(`0[]@)">
|
||||
<summary>
|
||||
Return a buffer to the pool.
|
||||
</summary>
|
||||
<param name="buffer">The buffer that is being returned.</param>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.JsonConstructorAttribute">
|
||||
<summary>
|
||||
Instructs the <see cref="T:Newtonsoft.Json.JsonSerializer"/> to use the specified constructor when deserializing that object.
|
||||
@@ -1079,6 +1098,21 @@
|
||||
Load comments as a <see cref="T:Newtonsoft.Json.Linq.JValue"/> with type <see cref="F:Newtonsoft.Json.Linq.JTokenType.Comment"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.LineInfoHandling">
|
||||
<summary>
|
||||
Specifies how line information is handled when loading JSON.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Ignore">
|
||||
<summary>
|
||||
Ignore line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Load">
|
||||
<summary>
|
||||
Load line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.JPropertyDescriptor">
|
||||
<summary>
|
||||
Represents a view of a <see cref="T:Newtonsoft.Json.Linq.JProperty"/>.
|
||||
@@ -1179,6 +1213,12 @@
|
||||
</summary>
|
||||
<value>The JSON comment handling.</value>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.Linq.JsonLoadSettings.LineInfoHandling">
|
||||
<summary>
|
||||
Gets or sets how JSON line info is handled when loading JSON.
|
||||
</summary>
|
||||
<value>The JSON line info handling.</value>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.JsonMergeSettings">
|
||||
<summary>
|
||||
Specifies the settings used when merging JSON.
|
||||
@@ -2229,7 +2269,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Linq.JTokenReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -5124,6 +5164,11 @@
|
||||
The property must be defined in JSON and cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Required.DisallowNull">
|
||||
<summary>
|
||||
The property is not required but it cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.PreserveReferencesHandling">
|
||||
<summary>
|
||||
Specifies reference handling options for the <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
|
||||
@@ -5670,7 +5715,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonValidatingReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -5741,6 +5786,11 @@
|
||||
</summary>
|
||||
<param name="reader">The <c>TextReader</c> containing the XML data to read.</param>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextReader.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the reader's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.Read">
|
||||
<summary>
|
||||
Reads the next JSON token from the stream.
|
||||
@@ -5779,7 +5829,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -5933,6 +5983,11 @@
|
||||
Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the writer's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.Indentation">
|
||||
<summary>
|
||||
Gets or sets how many IndentChars to write for each level in the hierarchy when <see cref="T:Newtonsoft.Json.Formatting"/> is set to <c>Formatting.Indented</c>.
|
||||
@@ -6538,7 +6593,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
Binary file not shown.
@@ -89,7 +89,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Bson.BsonReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -973,6 +973,25 @@
|
||||
Floating point numbers are parsed to <see cref="F:Newtonsoft.Json.FloatParseHandling.Decimal"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.IJsonBufferPool`1">
|
||||
<summary>
|
||||
Provides an interface for using pooled buffers.
|
||||
</summary>
|
||||
<typeparam name="T">The buffer type content.</typeparam>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.RentBuffer(System.Int32)">
|
||||
<summary>
|
||||
Rent a buffer from the pool. This buffer must be returned when it is no longer needed.
|
||||
</summary>
|
||||
<param name="minSize">The minimum required size of the buffer. The returned buffer may be larger.</param>
|
||||
<returns>The rented buffer from the pool.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.ReturnBuffer(`0[]@)">
|
||||
<summary>
|
||||
Return a buffer to the pool.
|
||||
</summary>
|
||||
<param name="buffer">The buffer that is being returned.</param>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.JsonDictionaryAttribute">
|
||||
<summary>
|
||||
Instructs the <see cref="T:Newtonsoft.Json.JsonSerializer"/> how to serialize the collection.
|
||||
@@ -1151,6 +1170,21 @@
|
||||
Load comments as a <see cref="T:Newtonsoft.Json.Linq.JValue"/> with type <see cref="F:Newtonsoft.Json.Linq.JTokenType.Comment"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.LineInfoHandling">
|
||||
<summary>
|
||||
Specifies how line information is handled when loading JSON.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Ignore">
|
||||
<summary>
|
||||
Ignore line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Load">
|
||||
<summary>
|
||||
Load line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.JsonLoadSettings">
|
||||
<summary>
|
||||
Specifies the settings used when loading JSON.
|
||||
@@ -1162,6 +1196,12 @@
|
||||
</summary>
|
||||
<value>The JSON comment handling.</value>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.Linq.JsonLoadSettings.LineInfoHandling">
|
||||
<summary>
|
||||
Gets or sets how JSON line info is handled when loading JSON.
|
||||
</summary>
|
||||
<value>The JSON line info handling.</value>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.JsonMergeSettings">
|
||||
<summary>
|
||||
Specifies the settings used when merging JSON.
|
||||
@@ -2321,7 +2361,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Linq.JTokenReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -5332,6 +5372,11 @@
|
||||
The property must be defined in JSON and cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Required.DisallowNull">
|
||||
<summary>
|
||||
The property is not required but it cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.PreserveReferencesHandling">
|
||||
<summary>
|
||||
Specifies reference handling options for the <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
|
||||
@@ -5878,7 +5923,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonValidatingReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -5949,6 +5994,11 @@
|
||||
</summary>
|
||||
<param name="reader">The <c>TextReader</c> containing the XML data to read.</param>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextReader.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the reader's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.Read">
|
||||
<summary>
|
||||
Reads the next JSON token from the stream.
|
||||
@@ -5987,7 +6037,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -6141,6 +6191,11 @@
|
||||
Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the writer's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.Indentation">
|
||||
<summary>
|
||||
Gets or sets how many IndentChars to write for each level in the hierarchy when <see cref="T:Newtonsoft.Json.Formatting"/> is set to <c>Formatting.Indented</c>.
|
||||
@@ -6746,7 +6801,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
Binary file not shown.
@@ -106,7 +106,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Bson.BsonReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -1084,6 +1084,25 @@
|
||||
Causes child objects to be indented according to the <see cref="P:Newtonsoft.Json.JsonTextWriter.Indentation"/> and <see cref="P:Newtonsoft.Json.JsonTextWriter.IndentChar"/> settings.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.IJsonBufferPool`1">
|
||||
<summary>
|
||||
Provides an interface for using pooled buffers.
|
||||
</summary>
|
||||
<typeparam name="T">The buffer type content.</typeparam>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.RentBuffer(System.Int32)">
|
||||
<summary>
|
||||
Rent a buffer from the pool. This buffer must be returned when it is no longer needed.
|
||||
</summary>
|
||||
<param name="minSize">The minimum required size of the buffer. The returned buffer may be larger.</param>
|
||||
<returns>The rented buffer from the pool.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.ReturnBuffer(`0[]@)">
|
||||
<summary>
|
||||
Return a buffer to the pool.
|
||||
</summary>
|
||||
<param name="buffer">The buffer that is being returned.</param>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.IJsonLineInfo">
|
||||
<summary>
|
||||
Provides an interface to enable a class to return line and position information.
|
||||
@@ -2386,7 +2405,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -3030,6 +3049,11 @@
|
||||
</summary>
|
||||
<param name="reader">The <c>TextReader</c> containing the XML data to read.</param>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextReader.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the reader's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.Read">
|
||||
<summary>
|
||||
Reads the next JSON token from the stream.
|
||||
@@ -3068,7 +3092,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -3110,6 +3134,11 @@
|
||||
Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the writer's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.Indentation">
|
||||
<summary>
|
||||
Gets or sets how many IndentChars to write for each level in the hierarchy when <see cref="T:Newtonsoft.Json.Formatting"/> is set to <c>Formatting.Indented</c>.
|
||||
@@ -3557,7 +3586,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonValidatingReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -4080,6 +4109,21 @@
|
||||
Load comments as a <see cref="T:Newtonsoft.Json.Linq.JValue"/> with type <see cref="F:Newtonsoft.Json.Linq.JTokenType.Comment"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.LineInfoHandling">
|
||||
<summary>
|
||||
Specifies how line information is handled when loading JSON.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Ignore">
|
||||
<summary>
|
||||
Ignore line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Load">
|
||||
<summary>
|
||||
Load line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.Extensions">
|
||||
<summary>
|
||||
Contains the LINQ to JSON extension methods.
|
||||
@@ -6199,7 +6243,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Linq.JTokenReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -6782,6 +6826,12 @@
|
||||
</summary>
|
||||
<value>The JSON comment handling.</value>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.Linq.JsonLoadSettings.LineInfoHandling">
|
||||
<summary>
|
||||
Gets or sets how JSON line info is handled when loading JSON.
|
||||
</summary>
|
||||
<value>The JSON line info handling.</value>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.MergeArrayHandling">
|
||||
<summary>
|
||||
Specifies how JSON arrays are merged together.
|
||||
@@ -6966,6 +7016,11 @@
|
||||
The property must be defined in JSON and cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Required.DisallowNull">
|
||||
<summary>
|
||||
The property is not required but it cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Schema.Extensions">
|
||||
<summary>
|
||||
<para>
|
||||
Binary file not shown.
@@ -106,7 +106,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Bson.BsonReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -857,6 +857,25 @@
|
||||
Causes child objects to be indented according to the <see cref="P:Newtonsoft.Json.JsonTextWriter.Indentation"/> and <see cref="P:Newtonsoft.Json.JsonTextWriter.IndentChar"/> settings.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.IJsonBufferPool`1">
|
||||
<summary>
|
||||
Provides an interface for using pooled buffers.
|
||||
</summary>
|
||||
<typeparam name="T">The buffer type content.</typeparam>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.RentBuffer(System.Int32)">
|
||||
<summary>
|
||||
Rent a buffer from the pool. This buffer must be returned when it is no longer needed.
|
||||
</summary>
|
||||
<param name="minSize">The minimum required size of the buffer. The returned buffer may be larger.</param>
|
||||
<returns>The rented buffer from the pool.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.ReturnBuffer(`0[]@)">
|
||||
<summary>
|
||||
Return a buffer to the pool.
|
||||
</summary>
|
||||
<param name="buffer">The buffer that is being returned.</param>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.IJsonLineInfo">
|
||||
<summary>
|
||||
Provides an interface to enable a class to return line and position information.
|
||||
@@ -1947,7 +1966,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -2573,6 +2592,11 @@
|
||||
</summary>
|
||||
<param name="reader">The <c>TextReader</c> containing the XML data to read.</param>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextReader.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the reader's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.Read">
|
||||
<summary>
|
||||
Reads the next JSON token from the stream.
|
||||
@@ -2611,7 +2635,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -2653,6 +2677,11 @@
|
||||
Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the writer's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.Indentation">
|
||||
<summary>
|
||||
Gets or sets how many IndentChars to write for each level in the hierarchy when <see cref="T:Newtonsoft.Json.Formatting"/> is set to <c>Formatting.Indented</c>.
|
||||
@@ -3100,7 +3129,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonValidatingReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -3614,6 +3643,21 @@
|
||||
Load comments as a <see cref="T:Newtonsoft.Json.Linq.JValue"/> with type <see cref="F:Newtonsoft.Json.Linq.JTokenType.Comment"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.LineInfoHandling">
|
||||
<summary>
|
||||
Specifies how line information is handled when loading JSON.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Ignore">
|
||||
<summary>
|
||||
Ignore line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Load">
|
||||
<summary>
|
||||
Load line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.Extensions">
|
||||
<summary>
|
||||
Contains the LINQ to JSON extension methods.
|
||||
@@ -4517,6 +4561,12 @@
|
||||
</summary>
|
||||
<value>The JSON comment handling.</value>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.Linq.JsonLoadSettings.LineInfoHandling">
|
||||
<summary>
|
||||
Gets or sets how JSON line info is handled when loading JSON.
|
||||
</summary>
|
||||
<value>The JSON line info handling.</value>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.JsonMergeSettings">
|
||||
<summary>
|
||||
Specifies the settings used when merging JSON.
|
||||
@@ -5484,7 +5534,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Linq.JTokenReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -6231,6 +6281,11 @@
|
||||
The property must be defined in JSON and cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Required.DisallowNull">
|
||||
<summary>
|
||||
The property is not required but it cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Schema.Extensions">
|
||||
<summary>
|
||||
<para>
|
||||
Binary file not shown.
@@ -106,7 +106,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Bson.BsonReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -956,6 +956,25 @@
|
||||
Causes child objects to be indented according to the <see cref="P:Newtonsoft.Json.JsonTextWriter.Indentation"/> and <see cref="P:Newtonsoft.Json.JsonTextWriter.IndentChar"/> settings.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.IJsonBufferPool`1">
|
||||
<summary>
|
||||
Provides an interface for using pooled buffers.
|
||||
</summary>
|
||||
<typeparam name="T">The buffer type content.</typeparam>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.RentBuffer(System.Int32)">
|
||||
<summary>
|
||||
Rent a buffer from the pool. This buffer must be returned when it is no longer needed.
|
||||
</summary>
|
||||
<param name="minSize">The minimum required size of the buffer. The returned buffer may be larger.</param>
|
||||
<returns>The rented buffer from the pool.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.IJsonBufferPool`1.ReturnBuffer(`0[]@)">
|
||||
<summary>
|
||||
Return a buffer to the pool.
|
||||
</summary>
|
||||
<param name="buffer">The buffer that is being returned.</param>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.IJsonLineInfo">
|
||||
<summary>
|
||||
Provides an interface to enable a class to return line and position information.
|
||||
@@ -2197,7 +2216,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -2823,6 +2842,11 @@
|
||||
</summary>
|
||||
<param name="reader">The <c>TextReader</c> containing the XML data to read.</param>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextReader.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the reader's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.Read">
|
||||
<summary>
|
||||
Reads the next JSON token from the stream.
|
||||
@@ -2861,7 +2885,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonTextReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -2903,6 +2927,11 @@
|
||||
Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.BufferPool">
|
||||
<summary>
|
||||
Gets or sets the writer's character buffer pool.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.JsonTextWriter.Indentation">
|
||||
<summary>
|
||||
Gets or sets how many IndentChars to write for each level in the hierarchy when <see cref="T:Newtonsoft.Json.Formatting"/> is set to <c>Formatting.Indented</c>.
|
||||
@@ -3350,7 +3379,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.JsonValidatingReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -3864,6 +3893,21 @@
|
||||
Load comments as a <see cref="T:Newtonsoft.Json.Linq.JValue"/> with type <see cref="F:Newtonsoft.Json.Linq.JTokenType.Comment"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.LineInfoHandling">
|
||||
<summary>
|
||||
Specifies how line information is handled when loading JSON.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Ignore">
|
||||
<summary>
|
||||
Ignore line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Linq.LineInfoHandling.Load">
|
||||
<summary>
|
||||
Load line information.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.Extensions">
|
||||
<summary>
|
||||
Contains the LINQ to JSON extension methods.
|
||||
@@ -4787,6 +4831,12 @@
|
||||
</summary>
|
||||
<value>The JSON comment handling.</value>
|
||||
</member>
|
||||
<member name="P:Newtonsoft.Json.Linq.JsonLoadSettings.LineInfoHandling">
|
||||
<summary>
|
||||
Gets or sets how JSON line info is handled when loading JSON.
|
||||
</summary>
|
||||
<value>The JSON line info handling.</value>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Linq.JsonMergeSettings">
|
||||
<summary>
|
||||
Specifies the settings used when merging JSON.
|
||||
@@ -5772,7 +5822,7 @@
|
||||
<summary>
|
||||
Reads the next JSON token from the stream as a <see cref="T:System.Nullable`1"/>.
|
||||
</summary>
|
||||
<returns>A <see cref="T:System.String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
<returns>A <see cref="T:System.Nullable`1"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
</member>
|
||||
<member name="M:Newtonsoft.Json.Linq.JTokenReader.ReadAsDateTimeOffset">
|
||||
<summary>
|
||||
@@ -6528,6 +6578,11 @@
|
||||
The property must be defined in JSON and cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Newtonsoft.Json.Required.DisallowNull">
|
||||
<summary>
|
||||
The property is not required but it cannot be a null value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Newtonsoft.Json.Schema.Extensions">
|
||||
<summary>
|
||||
<para>
|
||||
BIN
packages/SteamKit2.1.6.5/SteamKit2.1.6.5.nupkg
vendored
BIN
packages/SteamKit2.1.6.5/SteamKit2.1.6.5.nupkg
vendored
Binary file not shown.
BIN
packages/SteamKit2.1.6.5/lib/net40/SteamKit2.dll
vendored
BIN
packages/SteamKit2.1.6.5/lib/net40/SteamKit2.dll
vendored
Binary file not shown.
BIN
packages/SteamKit2.1.7.0/SteamKit2.1.7.0.nupkg
vendored
Normal file
BIN
packages/SteamKit2.1.7.0/SteamKit2.1.7.0.nupkg
vendored
Normal file
Binary file not shown.
BIN
packages/SteamKit2.1.7.0/lib/net45/SteamKit2.dll
vendored
Normal file
BIN
packages/SteamKit2.1.7.0/lib/net45/SteamKit2.dll
vendored
Normal file
Binary file not shown.
@@ -821,6 +821,12 @@
|
||||
The connection timeout.
|
||||
</value>
|
||||
</member>
|
||||
<member name="P:SteamKit2.Internal.CMClient.DebugNetworkListener">
|
||||
<summary>
|
||||
Gets or sets the network listening interface. Use this for debugging only.
|
||||
For your convenience, you can use <see cref="T:SteamKit2.NetHookNetworkListener"/> class.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.Internal.CMClient.#ctor(System.Net.Sockets.ProtocolType)">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.Internal.CMClient"/> class with a specific connection type.
|
||||
@@ -1492,14 +1498,14 @@
|
||||
Smart list of CM servers.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SmartCMServerList.ScoreExpiryTimeSpan">
|
||||
<member name="P:SteamKit2.SmartCMServerList.BadConnectionMemoryTimeSpan">
|
||||
<summary>
|
||||
Determines after how much time a server's score should expire and be reset to it's base value.
|
||||
Determines how long a server's bad connection state is remembered for.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SmartCMServerList.ResetOldScores">
|
||||
<summary>
|
||||
Resets the scores of all servers which had their scores last updated a <see cref="P:SteamKit2.SmartCMServerList.ScoreExpiryTimeSpan"/> ago.
|
||||
Resets the scores of all servers which has a last bad connection more than <see cref="P:SteamKit2.SmartCMServerList.BadConnectionMemoryTimeSpan"/> ago.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SmartCMServerList.TryAdd(System.Net.IPEndPoint)">
|
||||
@@ -1516,9 +1522,18 @@
|
||||
<param name="endPoints">The collection of <see cref="T:System.Net.IPEndPoint"/>s to add.</param>
|
||||
<returns>false if any of the specified servers are already in the list, true otherwise.</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SmartCMServerList.ResetAllScores">
|
||||
<member name="M:SteamKit2.SmartCMServerList.MergeWithList(System.Collections.Generic.IEnumerable{System.Net.IPEndPoint})">
|
||||
<summary>
|
||||
Explicitly resets the quality of every stored server.
|
||||
Merges the list with a new list of servers provided to us by the Steam servers.
|
||||
This adds the new list of <see cref="T:System.Net.IPEndPoint"/>s to the beginning of the list,
|
||||
ensuring that any pre-existing servers are moved into their new place in order near
|
||||
the beginning of the list.
|
||||
</summary>
|
||||
<param name="listToMerge">The <see cref="T:System.Net.IPEndPoint"/>s to merge into this <see cref="T:SteamKit2.SmartCMServerList"/>.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SmartCMServerList.ResetBadServers">
|
||||
<summary>
|
||||
Explicitly resets the known state of all servers.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SmartCMServerList.Clear">
|
||||
@@ -1853,6 +1868,7 @@
|
||||
<summary>
|
||||
Requests details for a specific item of user generated content from the Steam servers.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamCloud.UGCDetailsCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="ugcId">The unique user generated content id.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamCloud.UGCDetailsCallback"/>.</returns>
|
||||
@@ -1861,6 +1877,7 @@
|
||||
<summary>
|
||||
Requests details for a specific file in the user's Cloud storage.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamCloud.SingleFileInfoCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="appid">The app id of the game.</param>
|
||||
<param name="filename">The path to the file being requested.</param>
|
||||
@@ -1870,6 +1887,7 @@
|
||||
<summary>
|
||||
Commit a Cloud file at the given path to make its UGC handle publicly visible.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamCloud.ShareFileCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="appid">The app id of the game.</param>
|
||||
<param name="filename">The path to the file being requested.</param>
|
||||
@@ -2009,9 +2027,8 @@
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamGameServer.LogOff">
|
||||
<summary>
|
||||
Logs the game server off of the Steam3 network.
|
||||
This method does not disconnect the client.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamUser.LoggedOffCallback"/>.
|
||||
Informs the Steam servers that this client wishes to log off from the network.
|
||||
The Steam server will disconnect the client, and a <see cref="T:SteamKit2.SteamClient.DisconnectedCallback"/> will be posted.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamGameServer.SendStatus(SteamKit2.SteamGameServer.StatusDetails)">
|
||||
@@ -2139,6 +2156,7 @@
|
||||
<summary>
|
||||
Requests a list of servers from the Steam game master server.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamMasterServer.QueryCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="details">The details for the request.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamMasterServer.QueryCallback"/>.</returns>
|
||||
@@ -2242,6 +2260,7 @@
|
||||
<summary>
|
||||
Adds a screenshot to the user's screenshot library. The screenshot image and thumbnail must already exist on the UFS.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamScreenshots.ScreenshotAddedCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="details">The details of the screenshot.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamScreenshots.ScreenshotAddedCallback"/>.</returns>
|
||||
@@ -2428,6 +2447,7 @@
|
||||
<summary>
|
||||
Sends a message.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamUnifiedMessages.ServiceMethodResponse"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<typeparam name="TResponse">The type of the protobuf object which is the response to the RPC call.</typeparam>
|
||||
<param name="expr">RPC call expression, e.g. x => x.SomeMethodCall(message);</param>
|
||||
@@ -2438,6 +2458,7 @@
|
||||
<summary>
|
||||
Sends a message.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamUnifiedMessages.ServiceMethodResponse"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<typeparam name="TRequest">The type of a protobuf object.</typeparam>
|
||||
<param name="name">Name of the RPC endpoint. Takes the format ServiceName.RpcName</param>
|
||||
@@ -2656,6 +2677,7 @@
|
||||
<summary>
|
||||
Enumerates the list of published files for the current logged in user.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamWorkshop.UserPublishedFilesCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="details">The specific details of the request.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamWorkshop.UserPublishedFilesCallback"/>.</returns>
|
||||
@@ -2664,6 +2686,7 @@
|
||||
<summary>
|
||||
Enumerates the list of subscribed files for the current logged in user.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamWorkshop.UserSubscribedFilesCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="details">The specific details of the request.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamWorkshop.UserSubscribedFilesCallback"/>.</returns>
|
||||
@@ -2672,6 +2695,7 @@
|
||||
<summary>
|
||||
Enumerates the list of published files for the current logged in user based on user action.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamWorkshop.UserActionPublishedFilesCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="details">The specific details of the request.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamWorkshop.UserActionPublishedFilesCallback"/>.</returns>
|
||||
@@ -2740,6 +2764,7 @@
|
||||
<summary>
|
||||
Enumerates the list of all published files on the Steam workshop.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamWorkshop.PublishedFilesCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="details">The specific details of the request.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamWorkshop.PublishedFilesCallback"/>.</returns>
|
||||
@@ -2767,6 +2792,7 @@
|
||||
<summary>
|
||||
Asks the Steam back-end for a leaderboard by name for a given appid.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamUserStats.FindOrCreateLeaderboardCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="appId">The AppID to request a leaderboard for.</param>
|
||||
<param name="name">Name of the leaderboard to request.</param>
|
||||
@@ -2776,6 +2802,7 @@
|
||||
<summary>
|
||||
Asks the Steam back-end for a leaderboard by name, and will create it if it's not yet.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamUserStats.FindOrCreateLeaderboardCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="appId">The AppID to request a leaderboard for.</param>
|
||||
<param name="name">Name of the leaderboard to create.</param>
|
||||
@@ -2787,6 +2814,7 @@
|
||||
<summary>
|
||||
Asks the Steam back-end for a set of rows in the leaderboard.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamUserStats.LeaderboardEntriesCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="appId">The AppID to request leaderboard rows for.</param>
|
||||
<param name="id">ID of the leaderboard to view.</param>
|
||||
@@ -2896,6 +2924,79 @@
|
||||
Gets the list of leaderboard entries this response contains.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobManager.StartJob(SteamKit2.AsyncJob)">
|
||||
<summary>
|
||||
Tracks a job with this manager.
|
||||
</summary>
|
||||
<param name="asyncJob">The asynchronous job to track.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobManager.TryCompleteJob(SteamKit2.JobID,SteamKit2.CallbackMsg)">
|
||||
<summary>
|
||||
Passes a callback to a pending async job.
|
||||
If the given callback completes the job, the job is removed from this manager.
|
||||
</summary>
|
||||
<param name="jobId">The JobID.</param>
|
||||
<param name="callback">The callback.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobManager.HeartbeatJob(SteamKit2.JobID)">
|
||||
<summary>
|
||||
Extends the lifetime of a job.
|
||||
</summary>
|
||||
<param name="jobId">The job identifier.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobManager.FailJob(SteamKit2.JobID)">
|
||||
<summary>
|
||||
Marks a certain job as remotely failed.
|
||||
</summary>
|
||||
<param name="jobId">The job identifier.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobManager.CancelPendingJobs">
|
||||
<summary>
|
||||
Cancels and clears all jobs being tracked.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobManager.SetTimeoutsEnabled(System.Boolean)">
|
||||
<summary>
|
||||
Enables or disables periodic checks for job timeouts.
|
||||
</summary>
|
||||
<param name="enable">Whether or not job timeout checks should be enabled.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobManager.CancelTimedoutJobs">
|
||||
<summary>
|
||||
This is called periodically to cancel and clear out any jobs that have timed out (no response from Steam).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobManager.GetJob(SteamKit2.JobID,System.Boolean)">
|
||||
<summary>
|
||||
Retrieves a job from this manager, and optionally removes it from tracking.
|
||||
</summary>
|
||||
<param name="jobId">The JobID.</param>
|
||||
<param name="andRemove">If set to <c>true</c>, this job is removed from tracking.</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:SteamKit2.AsyncJobFailedException">
|
||||
<summary>
|
||||
Thrown when Steam encounters a remote error with a pending <see cref="T:SteamKit2.AsyncJob"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobFailedException.#ctor">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.AsyncJobFailedException"/> class.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobFailedException.#ctor(System.String)">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.AsyncJobFailedException"/> class.
|
||||
</summary>
|
||||
<param name="message">The message that describes the error.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobFailedException.#ctor(System.String,System.Exception)">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.AsyncJobFailedException"/> class.
|
||||
</summary>
|
||||
<param name="message">The error message that explains the reason for the exception.</param>
|
||||
<param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>
|
||||
</member>
|
||||
<member name="T:SteamKit2.Callback`1">
|
||||
<summary>
|
||||
This utility class is used for binding a callback to a function.
|
||||
@@ -3229,19 +3330,20 @@
|
||||
Helper class to load servers from the Steam Directory Web API.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamDirectory.Initialize(System.Int32)">
|
||||
<member name="M:SteamKit2.SteamDirectory.Initialize(System.UInt32)">
|
||||
<summary>
|
||||
Initializes <see cref="T:SteamKit2.Internal.CMClient"/>'s server list with servers from the Steam Directory.
|
||||
</summary>
|
||||
<param name="cellid">Cell ID</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamDirectory.LoadAsync(System.Int32)">
|
||||
<member name="M:SteamKit2.SteamDirectory.LoadAsync(System.UInt32)">
|
||||
<summary>
|
||||
Load a list of servers from the Steam Directory.
|
||||
</summary>
|
||||
<param name="cellid">Cell ID</param>
|
||||
<returns>A <see cref="T:System.Threading.Tasks.Task"/> with the Result set to an enumerable list of <see cref="T:System.Net.IPEndPoint"/>s.</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamDirectory.LoadAsync(System.Int32,System.Threading.CancellationToken)">
|
||||
<member name="M:SteamKit2.SteamDirectory.LoadAsync(System.UInt32,System.Threading.CancellationToken)">
|
||||
<summary>
|
||||
Load a list of servers from the Steam Directory.
|
||||
</summary>
|
||||
@@ -3536,45 +3638,6 @@
|
||||
A <see cref="T:System.String"/> that represents this instance.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="T:SteamKit2.JobID">
|
||||
<summary>
|
||||
Represents an identifier of a network task known as a job.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:SteamKit2.JobID.Invalid">
|
||||
<summary>
|
||||
Represents an invalid JobID.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.JobID.#ctor">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.JobID"/> class.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.JobID.#ctor(System.UInt64)">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.JobID"/> class.
|
||||
</summary>
|
||||
<param name="jobId">The Job ID to initialize this instance with.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.JobID.op_Implicit(SteamKit2.JobID)~System.UInt64">
|
||||
<summary>
|
||||
Performs an implicit conversion from <see cref="T:SteamKit2.JobID"/> to <see cref="T:System.UInt64"/>.
|
||||
</summary>
|
||||
<param name="jobId">The Job ID.</param>
|
||||
<returns>
|
||||
The result of the conversion.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.JobID.op_Implicit(System.UInt64)~SteamKit2.JobID">
|
||||
<summary>
|
||||
Performs an implicit conversion from <see cref="T:System.UInt64"/> to <see cref="T:SteamKit2.JobID"/>.
|
||||
</summary>
|
||||
<param name="jobId">The Job ID.</param>
|
||||
<returns>
|
||||
The result of the conversion.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="T:SteamKit2.UGCHandle">
|
||||
<summary>
|
||||
Represents a single unique handle to a piece of User Generated Content.
|
||||
@@ -3699,6 +3762,195 @@
|
||||
<param name="encryptionKey">The encryption key.</param>
|
||||
<returns><c>true</c> if the file names were successfully decrypted; otherwise, <c>false</c>.</returns>
|
||||
</member>
|
||||
<member name="T:SteamKit2.JobID">
|
||||
<summary>
|
||||
Represents an identifier of a network task known as a job.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:SteamKit2.JobID.Invalid">
|
||||
<summary>
|
||||
Represents an invalid JobID.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.JobID.#ctor">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.JobID"/> class.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.JobID.#ctor(System.UInt64)">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.JobID"/> class.
|
||||
</summary>
|
||||
<param name="jobId">The Job ID to initialize this instance with.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.JobID.op_Implicit(SteamKit2.JobID)~System.UInt64">
|
||||
<summary>
|
||||
Performs an implicit conversion from <see cref="T:SteamKit2.JobID"/> to <see cref="T:System.UInt64"/>.
|
||||
</summary>
|
||||
<param name="jobId">The Job ID.</param>
|
||||
<returns>
|
||||
The result of the conversion.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.JobID.op_Implicit(System.UInt64)~SteamKit2.JobID">
|
||||
<summary>
|
||||
Performs an implicit conversion from <see cref="T:System.UInt64"/> to <see cref="T:SteamKit2.JobID"/>.
|
||||
</summary>
|
||||
<param name="jobId">The Job ID.</param>
|
||||
<returns>
|
||||
The result of the conversion.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.JobID.op_Implicit(SteamKit2.AsyncJob)~SteamKit2.JobID">
|
||||
<summary>
|
||||
Performs an implicit conversion from <see cref="T:SteamKit2.AsyncJob"/> to <see cref="T:SteamKit2.JobID"/>.
|
||||
</summary>
|
||||
<param name="asyncJob">The asynchronous job.</param>
|
||||
<returns>
|
||||
The result of the conversion.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="T:SteamKit2.AsyncJob">
|
||||
<summary>
|
||||
The base class for awaitable versions of a <see cref="P:SteamKit2.AsyncJob.JobID"/>.
|
||||
Should not be used or constructed directly, but rather with <see cref="T:SteamKit2.AsyncJob`1"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.AsyncJob.JobID">
|
||||
<summary>
|
||||
Gets the <see cref="P:SteamKit2.AsyncJob.JobID"/> for this job.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.AsyncJob.Timeout">
|
||||
<summary>
|
||||
Gets or sets the period of time before this job will be considered timed out and will be canceled. By default this is 10 seconds.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJob.AddResult(SteamKit2.CallbackMsg)">
|
||||
<summary>
|
||||
Adds a callback to the async job's result set.
|
||||
</summary>
|
||||
<param name="callback">The callback.</param>
|
||||
<returns><c>true</c> if this result completes the set; otherwise, <c>false</c>.</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJob.SetFailed(System.Boolean)">
|
||||
<summary>
|
||||
Sets this job as failed, either remotely or due to a message timeout.
|
||||
</summary>
|
||||
<param name="dueToRemoteFailure">
|
||||
If set to <c>true</c> this job is marked as failed because Steam informed us of a job failure;
|
||||
otherwise, this job has failed due to a message timeout.
|
||||
</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJob.Heartbeat">
|
||||
<summary>
|
||||
Marks this job as having received a heartbeat and extends the job's timeout.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:SteamKit2.AsyncJob`1">
|
||||
<summary>
|
||||
Represents an awaitable version of a <see cref="T:SteamKit2.JobID"/>.
|
||||
Can either be converted to a TPL <see cref="T:System.Threading.Tasks.Task"/> with <see cref="M:SteamKit2.AsyncJob`1.ToTask"/> or can be awaited directly.
|
||||
</summary>
|
||||
<typeparam name="T">The callback type that will be returned by this async job.</typeparam>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJob`1.#ctor(SteamKit2.SteamClient,SteamKit2.JobID)">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.AsyncJob`1" /> class.
|
||||
</summary>
|
||||
<param name="client">The <see cref="T:SteamKit2.SteamClient"/> that this job will be associated with.</param>
|
||||
<param name="jobId">The Job ID value associated with this async job.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJob`1.ToTask">
|
||||
<summary>
|
||||
Converts this <see cref="T:SteamKit2.AsyncJob`1"/> instance into a TPL <see cref="T:System.Threading.Tasks.Task`1"/>.
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJob`1.GetAwaiter">
|
||||
<summary>Gets an awaiter used to await this <see cref="T:SteamKit2.AsyncJob`1"/>.</summary>
|
||||
<returns>An awaiter instance.</returns>
|
||||
<remarks>This method is intended for compiler use rather than use directly in code.</remarks>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJob`1.AddResult(SteamKit2.CallbackMsg)">
|
||||
<summary>
|
||||
Adds a callback to the async job's result set. For an <see cref="T:SteamKit2.AsyncJob`1"/>, this always completes the set.
|
||||
</summary>
|
||||
<param name="callback">The callback.</param>
|
||||
<returns>Always <c>true</c>.</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJob`1.SetFailed(System.Boolean)">
|
||||
<summary>
|
||||
Sets this job as failed, either remotely or due to a message timeout.
|
||||
</summary>
|
||||
<param name="dueToRemoteFailure">
|
||||
If set to <c>true</c> this job is marked as failed because Steam informed us of a job failure;
|
||||
otherwise, this job has failed due to a message timeout.
|
||||
</param>
|
||||
</member>
|
||||
<member name="T:SteamKit2.AsyncJobMultiple`1">
|
||||
<summary>
|
||||
Represents an awaitable version of a <see cref="T:SteamKit2.JobID"/>.
|
||||
Can either be converted to a TPL <see cref="T:System.Threading.Tasks.Task"/> with <see cref="M:SteamKit2.AsyncJobMultiple`1.ToTask"/> or can be awaited directly.
|
||||
This type of async job can contain multiple callback results.
|
||||
</summary>
|
||||
<typeparam name="T">The callback type that will be returned by this async job.</typeparam>
|
||||
</member>
|
||||
<member name="T:SteamKit2.AsyncJobMultiple`1.ResultSet">
|
||||
<summary>
|
||||
The set of callback results for an <see cref="T:SteamKit2.AsyncJobMultiple`1"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.AsyncJobMultiple`1.ResultSet.Complete">
|
||||
<summary>
|
||||
Gets a value indicating whether this <see cref="T:SteamKit2.AsyncJobMultiple`1.ResultSet" /> is complete and contains every result sent by Steam.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.AsyncJobMultiple`1.ResultSet.Failed">
|
||||
<summary>
|
||||
Gets a value indicating whether the parent <see cref="T:SteamKit2.AsyncJobMultiple`1" /> received an incomplete result set and then encountered a remote failure.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.AsyncJobMultiple`1.ResultSet.Results">
|
||||
<summary>
|
||||
Gets a read only collection of callback results for this async job.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobMultiple`1.#ctor(SteamKit2.SteamClient,SteamKit2.JobID,System.Predicate{`0})">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.AsyncJob`1" /> class.
|
||||
</summary>
|
||||
<param name="client">The <see cref="T:SteamKit2.SteamClient"/> that this job will be associated with.</param>
|
||||
<param name="jobId">The Job ID value associated with this async job.</param>
|
||||
<param name="finishCondition">The condition that must be fulfilled for the result set to be considered complete.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobMultiple`1.ToTask">
|
||||
<summary>
|
||||
Converts this <see cref="T:SteamKit2.AsyncJob`1"/> instance into a TPL <see cref="T:System.Threading.Tasks.Task`1"/>.
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobMultiple`1.GetAwaiter">
|
||||
<summary>Gets an awaiter used to await this <see cref="T:SteamKit2.AsyncJob`1"/>.</summary>
|
||||
<returns>An awaiter instance.</returns>
|
||||
<remarks>This method is intended for compiler use rather than use directly in code.</remarks>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobMultiple`1.AddResult(SteamKit2.CallbackMsg)">
|
||||
<summary>
|
||||
Adds a callback to the async job's result set.
|
||||
</summary>
|
||||
<param name="callback">The callback.</param>
|
||||
<returns><c>true</c> if this result completes the set; otherwise, <c>false</c>.</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.AsyncJobMultiple`1.SetFailed(System.Boolean)">
|
||||
<summary>
|
||||
Sets this job as failed, either remotely or due to a message timeout.
|
||||
</summary>
|
||||
<param name="dueToRemoteFailure">
|
||||
If set to <c>true</c> this job is marked as failed because Steam informed us of a job failure;
|
||||
otherwise, this job has failed due to a message timeout.
|
||||
</param>
|
||||
</member>
|
||||
<member name="T:SteamKit2.MessageObject">
|
||||
<summary>
|
||||
Represents a <see cref="T:SteamKit2.KeyValue"/> backed MessageObject structure, which are often sent by the Steam servers.
|
||||
@@ -3840,6 +4092,60 @@
|
||||
The result of the operator.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="T:SteamKit2.IDebugNetworkListener">
|
||||
<summary>
|
||||
This is a debug utility, do not use it to implement your business logic.
|
||||
|
||||
This interface is used for logging network messages sent to and received from the Steam server that the client is connected to.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.IDebugNetworkListener.OnIncomingNetworkMessage(SteamKit2.EMsg,System.Byte[])">
|
||||
<summary>
|
||||
Called when a packet is received from the Steam server.
|
||||
</summary>
|
||||
<param name="msgType">Network message type of this packet message.</param>
|
||||
<param name="data">Raw packet data that was received.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.IDebugNetworkListener.OnOutgoingNetworkMessage(SteamKit2.EMsg,System.Byte[])">
|
||||
<summary>
|
||||
Called when a packet is about to be sent to the Steam server.
|
||||
</summary>
|
||||
<param name="msgType">Network message type of this packet message.</param>
|
||||
<param name="data">Raw packet data that will be sent.</param>
|
||||
</member>
|
||||
<member name="T:SteamKit2.NetHookNetworkListener">
|
||||
<summary>
|
||||
Dump any network messages sent to and received from the Steam server that the client is connected to.
|
||||
These messages are dumped to file, and can be analyzed further with NetHookAnalyzer, a hex editor, or your own purpose-built tools.
|
||||
|
||||
Be careful with this, sensitive data may be written to the disk (such as your Steam password).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.NetHookNetworkListener.#ctor">
|
||||
<summary>
|
||||
Will create a folder in path "%assembly%/nethook/%currenttime%/"
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.NetHookNetworkListener.#ctor(System.String)">
|
||||
<summary>
|
||||
Log to your own folder.
|
||||
</summary>
|
||||
<param name="path">Path to folder.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.NetHookNetworkListener.OnIncomingNetworkMessage(SteamKit2.EMsg,System.Byte[])">
|
||||
<summary>
|
||||
Called when a packet is received from the Steam server.
|
||||
</summary>
|
||||
<param name="msgType">Network message type of this packet message.</param>
|
||||
<param name="data">Raw packet data that was received.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.NetHookNetworkListener.OnOutgoingNetworkMessage(SteamKit2.EMsg,System.Byte[])">
|
||||
<summary>
|
||||
Called when a packet is about to be sent to the Steam server.
|
||||
</summary>
|
||||
<param name="msgType">Network message type of this packet message.</param>
|
||||
<param name="data">Raw packet data that will be sent.</param>
|
||||
</member>
|
||||
<member name="P:SteamKit2.UdpPacket.IsValid">
|
||||
<summary>
|
||||
Gets a value indicating whether this instance is valid.
|
||||
@@ -4356,7 +4662,7 @@
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamApps.PICSProductInfoCallback.ResponsePending">
|
||||
<summary>
|
||||
Gets if the are more product information responses pending
|
||||
Gets if there are more product information responses pending
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamApps.PICSProductInfoCallback.UnknownPackages">
|
||||
@@ -4507,6 +4813,7 @@
|
||||
<summary>
|
||||
Requests an app ownership ticket for the specified AppID.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.AppOwnershipTicketCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="appid">The appid to request the ownership ticket of.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamApps.AppOwnershipTicketCallback"/>.</returns>
|
||||
@@ -4515,6 +4822,7 @@
|
||||
<summary>
|
||||
Requests app information for a single app. Use the overload for requesting information on a batch of apps.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.AppInfoCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
|
||||
Consider using <see cref="o:SteamApps.PICSGetProductInfo"/> instead.
|
||||
</summary>
|
||||
@@ -4526,6 +4834,7 @@
|
||||
<summary>
|
||||
Requests app information for a single app. Use the overload for requesting information on a batch of apps.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.AppInfoCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
|
||||
Consider using <see cref="o:SteamApps.PICSGetProductInfo"/> instead.
|
||||
</summary>
|
||||
@@ -4537,6 +4846,7 @@
|
||||
<summary>
|
||||
Requests app information for a list of apps.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.AppInfoCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
|
||||
Consider using <see cref="o:SteamApps.PICSGetProductInfo"/> instead.
|
||||
</summary>
|
||||
@@ -4548,6 +4858,7 @@
|
||||
<summary>
|
||||
Requests app information for a list of apps.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.AppInfoCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
|
||||
Consider using <see cref="o:SteamApps.PICSGetProductInfo"/> instead.
|
||||
</summary>
|
||||
@@ -4559,6 +4870,7 @@
|
||||
<summary>
|
||||
Requests package information for a single package. Use the overload for requesting information on a batch of packages.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.PackageInfoCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
|
||||
Consider using <see cref="o:SteamApps.PICSGetProductInfo"/> instead.
|
||||
</summary>
|
||||
@@ -4570,6 +4882,7 @@
|
||||
<summary>
|
||||
Requests package information for a list of packages.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.PackageInfoCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
|
||||
Consider using <see cref="o:SteamApps.PICSGetProductInfo"/> instead.
|
||||
</summary>
|
||||
@@ -4591,15 +4904,27 @@
|
||||
<summary>
|
||||
Request the depot decryption key for a specified DepotID.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.DepotKeyCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="depotid">The DepotID to request a decryption key for.</param>
|
||||
<param name="appid">The AppID to request the decryption key for.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamApps.DepotKeyCallback"/>.</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamApps.PICSGetAccessTokens(System.Nullable{System.UInt32},System.Nullable{System.UInt32})">
|
||||
<summary>
|
||||
Request PICS access tokens for an app or package.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.PICSTokensCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="app">App id to request access token for.</param>
|
||||
<param name="package">Package id to request access token for.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamApps.PICSTokensCallback"/>.</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamApps.PICSGetAccessTokens(System.Collections.Generic.IEnumerable{System.UInt32},System.Collections.Generic.IEnumerable{System.UInt32})">
|
||||
<summary>
|
||||
Request PICS access tokens for a list of app ids and package ids
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.PICSTokensCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="appIds">List of app ids to request access tokens for.</param>
|
||||
<param name="packageIds">List of package ids to request access tokens for.</param>
|
||||
@@ -4609,6 +4934,7 @@
|
||||
<summary>
|
||||
Request changes for apps and packages since a given change number
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.PICSChangesCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="lastChangeNumber">Last change number seen.</param>
|
||||
<param name="sendAppChangelist">Whether to send app changes.</param>
|
||||
@@ -4619,6 +4945,7 @@
|
||||
<summary>
|
||||
Request product information for an app or package
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.PICSProductInfoCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="app">App id requested.</param>
|
||||
<param name="package">Package id requested.</param>
|
||||
@@ -4630,6 +4957,7 @@
|
||||
<summary>
|
||||
Request product information for a list of apps or packages
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.PICSProductInfoCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="apps">List of app ids requested.</param>
|
||||
<param name="packages">List of package ids requested.</param>
|
||||
@@ -4641,6 +4969,7 @@
|
||||
<summary>
|
||||
Request product information for a list of apps or packages
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.PICSProductInfoCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="apps">List of <see cref="T:SteamKit2.SteamApps.PICSRequest"/> requests for apps.</param>
|
||||
<param name="packages">List of <see cref="T:SteamKit2.SteamApps.PICSRequest"/> requests for packages.</param>
|
||||
@@ -4651,6 +4980,7 @@
|
||||
<summary>
|
||||
Request product information for an app or package
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.CDNAuthTokenCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="app">App id requested.</param>
|
||||
<param name="host_name">CDN host name being requested.</param>
|
||||
@@ -4660,6 +4990,7 @@
|
||||
<summary>
|
||||
Request a free license for given appid, can be used for free on demand apps
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.FreeLicenseCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="app">The app to request a free license for.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamApps.FreeLicenseCallback"/>.</returns>
|
||||
@@ -4668,6 +4999,7 @@
|
||||
<summary>
|
||||
Request a free license for given appids, can be used for free on demand apps
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamApps.FreeLicenseCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="apps">The apps to request a free license for.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamApps.FreeLicenseCallback"/>.</returns>
|
||||
@@ -5027,6 +5359,54 @@
|
||||
</summary>
|
||||
<value>The message.</value>
|
||||
</member>
|
||||
<member name="T:SteamKit2.SteamFriends.FriendMsgHistoryCallback">
|
||||
<summary>
|
||||
<para>This callback is fired in response to receiving historical messages.</para>
|
||||
See also <seealso cref="M:SteamKit2.SteamFriends.RequestOfflineMessages"/> and
|
||||
<seealso cref="M:SteamKit2.SteamFriends.RequestMessageHistory(SteamKit2.SteamID)"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamFriends.FriendMsgHistoryCallback.Result">
|
||||
<summary>
|
||||
Gets the result of the request.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamFriends.FriendMsgHistoryCallback.SteamID">
|
||||
<summary>
|
||||
Gets the SteamID of the user with whom these messages were exchanged.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamFriends.FriendMsgHistoryCallback.Messages">
|
||||
<summary>
|
||||
The messages exchanged with the user.
|
||||
Offline messages are marked by having set <see cref="P:SteamKit2.SteamFriends.FriendMsgHistoryCallback.FriendMessage.Unread"/> to <c>true</c>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:SteamKit2.SteamFriends.FriendMsgHistoryCallback.FriendMessage">
|
||||
<summary>
|
||||
Represents a single Message sent to or received from a friend
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamFriends.FriendMsgHistoryCallback.FriendMessage.SteamID">
|
||||
<summary>
|
||||
The SteamID of the User that wrote the message
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamFriends.FriendMsgHistoryCallback.FriendMessage.Unread">
|
||||
<summary>
|
||||
Whether or not the message has been read, i.e., is an offline message.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamFriends.FriendMsgHistoryCallback.FriendMessage.Message">
|
||||
<summary>
|
||||
The actual message
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamFriends.FriendMsgHistoryCallback.FriendMessage.Timestamp">
|
||||
<summary>
|
||||
The time (in UTC) when the message was sent
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:SteamKit2.SteamFriends.FriendAddedCallback">
|
||||
<summary>
|
||||
This callback is fired in response to adding a user to your friends list.
|
||||
@@ -5345,6 +5725,7 @@
|
||||
<summary>
|
||||
Sets the local user's persona name and broadcasts it over the network.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamFriends.PersonaChangeCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="name">The name.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamFriends.PersonaChangeCallback"/>.</returns>
|
||||
@@ -5359,6 +5740,7 @@
|
||||
<summary>
|
||||
Sets the local user's persona state and broadcasts it over the network.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamFriends.PersonaChangeCallback"/> callback.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="state">The state.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamFriends.PersonaChangeCallback"/>.</returns>
|
||||
@@ -5547,6 +5929,7 @@
|
||||
<summary>
|
||||
Ignores or unignores a friend on Steam.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamFriends.IgnoreFriendCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="steamId">The SteamID of the friend to ignore or unignore.</param>
|
||||
<param name="setIgnore">if set to <c>true</c>, the friend will be ignored; otherwise, they will be unignored.</param>
|
||||
@@ -5556,10 +5939,25 @@
|
||||
<summary>
|
||||
Requests profile information for the given <see cref="T:SteamKit2.SteamID"/>.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamFriends.ProfileInfoCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<param name="steamId">The SteamID of the friend to request the details of.</param>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamFriends.ProfileInfoCallback"/>.</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamFriends.RequestMessageHistory(SteamKit2.SteamID)">
|
||||
<summary>
|
||||
Requests the last few chat messages with a friend.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamFriends.FriendMsgHistoryCallback"/>
|
||||
</summary>
|
||||
<param name="steamId">SteamID of the friend</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamFriends.RequestOfflineMessages">
|
||||
<summary>
|
||||
Requests all offline messages.
|
||||
This also marks them as read server side.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamFriends.FriendMsgHistoryCallback"/>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamFriends.HandleMsg(SteamKit2.IPacketMsg)">
|
||||
<summary>
|
||||
Handles a client message. This should not be called directly.
|
||||
@@ -5920,6 +6318,18 @@
|
||||
</summary>
|
||||
<value>The CellID.</value>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamUser.LogOnDetails.LoginID">
|
||||
<summary>
|
||||
Gets or sets the LoginID. This number is used for identifying logon session.
|
||||
The purpose of this field is to allow multiple sessions to the same steam account from the same machine.
|
||||
This is because Steam Network doesn't allow more than one session with the same LoginID to access given account at the same time.
|
||||
If you want to establish more than one active session to given account, you must make sure that every session (to that account) has unique LoginID.
|
||||
By default LoginID is automatically generated based on machine's primary bind address, which is the same for all sessions.
|
||||
Null value will cause this property to be automatically generated based on default behaviour.
|
||||
If in doubt, set this property to null.
|
||||
</summary>
|
||||
<value>The LoginID.</value>
|
||||
</member>
|
||||
<member name="P:SteamKit2.SteamUser.LogOnDetails.AuthCode">
|
||||
<summary>
|
||||
Gets or sets the Steam Guard auth code used to login. This is the code sent to the user's email.
|
||||
@@ -6139,9 +6549,8 @@
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamUser.LogOff">
|
||||
<summary>
|
||||
Logs the user off of the Steam3 network.
|
||||
This method does not disconnect the client.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamUser.LoggedOffCallback"/>.
|
||||
Informs the Steam servers that this client wishes to log off from the network.
|
||||
The Steam server will disconnect the client, and a <see cref="T:SteamKit2.SteamClient.DisconnectedCallback"/> will be posted.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.SteamUser.SendMachineAuthResponse(SteamKit2.SteamUser.MachineAuthDetails)">
|
||||
@@ -6155,6 +6564,7 @@
|
||||
<summary>
|
||||
Requests a new WebAPI authentication user nonce.
|
||||
Results are returned in a <see cref="T:SteamKit2.SteamUser.WebAPIUserNonceCallback"/>.
|
||||
The returned <see cref="T:SteamKit2.AsyncJob`1"/> can also be awaited to retrieve the callback result.
|
||||
</summary>
|
||||
<returns>The Job ID of the request. This can be used to find the appropriate <see cref="T:SteamKit2.SteamUser.WebAPIUserNonceCallback"/>.</returns>
|
||||
</member>
|
||||
@@ -6181,37 +6591,6 @@
|
||||
then this will be <see cref="P:JobID.Invalid"/>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:SteamKit2.CallbackMsgExtensions">
|
||||
<summary>
|
||||
Useful extensions for ICallbackMsg
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.CallbackMsgExtensions.IsType``1(SteamKit2.ICallbackMsg)">
|
||||
<summary>
|
||||
Determines whether this callback is a certain type.
|
||||
</summary>
|
||||
<typeparam name="T">The type to check against.</typeparam>
|
||||
<returns>
|
||||
<c>true</c> if this callback is the type specified; otherwise, <c>false</c>.
|
||||
</returns>
|
||||
<exception cref="T:System.ArgumentNullException">
|
||||
<c>msg</c> is null.
|
||||
</exception>
|
||||
</member>
|
||||
<member name="M:SteamKit2.CallbackMsgExtensions.Handle``1(SteamKit2.ICallbackMsg,System.Action{``0})">
|
||||
<summary>
|
||||
Invokes the specified handler delegate if the callback matches the type parameter.
|
||||
</summary>
|
||||
<typeparam name="T">The type to check against.</typeparam>
|
||||
<param name="msg">The callback in question.</param>
|
||||
<param name="handler">The handler to invoke.</param>
|
||||
<returns>
|
||||
<c>true</c> if the callback matches and the handler was called; otherwise, <c>false</c>.
|
||||
</returns>
|
||||
<exception cref="T:System.ArgumentNullException">
|
||||
<c>msg</c> is null or <c>handler</c> is null.
|
||||
</exception>
|
||||
</member>
|
||||
<member name="T:SteamKit2.CallbackMsg">
|
||||
<summary>
|
||||
Represents the base object all callbacks are based off.
|
||||
@@ -6394,6 +6773,13 @@
|
||||
Gets the underlying <see cref="T:SteamKit2.SteamClient"/> for use in sending replies.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:SteamKit2.ClientMsgHandler.ExpectDisconnection">
|
||||
<summary>
|
||||
Gets or sets whether or not the related <see cref="T:SteamKit2.SteamClient" /> should imminently expect the server to close the connection.
|
||||
If this is true when the connection is closed, the <see cref="T:SteamKit2.SteamClient.DisconnectedCallback"/>'s <see cref="P:SteamKit2.SteamClient.DisconnectedCallback.UserInitiated"/> property
|
||||
will be set to <c>true</c>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.ClientMsgHandler.#ctor">
|
||||
<summary>
|
||||
Initializes a new instance of the <see cref="T:SteamKit2.ClientMsgHandler"/> class.
|
||||
@@ -7104,11 +7490,11 @@
|
||||
</summary>
|
||||
<param name="packet">The packet.</param>
|
||||
</member>
|
||||
<member name="M:SteamKit2.UdpConnection.SetNetEncryptionFilter(SteamKit2.NetFilterEncryption)">
|
||||
<member name="M:SteamKit2.UdpConnection.SetNetEncryptionFilter(SteamKit2.INetFilterEncryption)">
|
||||
<summary>
|
||||
Sets the network encryption filter for this connection
|
||||
</summary>
|
||||
<param name="filter">filter implementing <see cref="T:SteamKit2.NetFilterEncryption"/></param>
|
||||
<param name="filter">filter implementing <see cref="T:SteamKit2.INetFilterEncryption"/></param>
|
||||
</member>
|
||||
<member name="T:SteamKit2.NetMsgEventArgs">
|
||||
<summary>
|
||||
@@ -7166,11 +7552,11 @@
|
||||
</summary>
|
||||
<returns>The local IP.</returns>
|
||||
</member>
|
||||
<member name="M:SteamKit2.Connection.SetNetEncryptionFilter(SteamKit2.NetFilterEncryption)">
|
||||
<member name="M:SteamKit2.Connection.SetNetEncryptionFilter(SteamKit2.INetFilterEncryption)">
|
||||
<summary>
|
||||
Sets the network encryption filter for this connection
|
||||
</summary>
|
||||
<param name="filter">filter implementing <see cref="T:SteamKit2.NetFilterEncryption"/></param>
|
||||
<param name="filter">filter implementing <see cref="T:SteamKit2.INetFilterEncryption"/></param>
|
||||
</member>
|
||||
<member name="T:SteamKit2.KeyDictionary">
|
||||
<summary>
|
||||
@@ -7229,16 +7615,36 @@
|
||||
Decrypts an input byte array using AES/CBC/PKCS7 with a given key and IV
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.CryptoHelper.SymmetricEncryptWithIV(System.Byte[],System.Byte[],System.Byte[])">
|
||||
<summary>
|
||||
Performs an encryption using AES/CBC/PKCS7 with an input byte array and key, with a random IV prepended using AES/ECB/None
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.CryptoHelper.SymmetricEncrypt(System.Byte[],System.Byte[])">
|
||||
<summary>
|
||||
Performs an encryption using AES/CBC/PKCS7 with an input byte array and key, with a random IV prepended using AES/ECB/None
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.CryptoHelper.SymmetricEncryptWithHMACIV(System.Byte[],System.Byte[],System.Byte[])">
|
||||
<summary>
|
||||
Performs an encryption using AES/CBC/PKCS7 with an input byte array and key, with a IV (comprised of random bytes and the HMAC-SHA1 of the random bytes and plaintext) prepended using AES/ECB/None
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.CryptoHelper.SymmetricDecrypt(System.Byte[],System.Byte[])">
|
||||
<summary>
|
||||
Decrypts using AES/CBC/PKCS7 with an input byte array and key, using the random IV prepended using AES/ECB/None
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.CryptoHelper.SymmetricDecryptHMACIV(System.Byte[],System.Byte[],System.Byte[])">
|
||||
<summary>
|
||||
Decrypts using AES/CBC/PKCS7 with an input byte array and key, using the IV (comprised of random bytes and the HMAC-SHA1 of the random bytes and plaintext) prepended using AES/ECB/None
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.CryptoHelper.SymmetricDecrypt(System.Byte[],System.Byte[],System.Byte[]@)">
|
||||
<summary>
|
||||
Decrypts using AES/CBC/PKCS7 with an input byte array and key, using the random IV prepended using AES/ECB/None
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:SteamKit2.CryptoHelper.VerifyAndDecryptPassword(System.Byte[],System.String)">
|
||||
<summary>
|
||||
Verifies and performs a symmetricdecrypt on the input using the given password as a key
|
||||
@@ -1,3 +1,30 @@
|
||||
------------------------------------------------------------------------------
|
||||
v 1.7.0 Dec 21, 2015
|
||||
------------------------------------------------------------------------------
|
||||
* Added awaitable API for job-based messages. APIs which returned a `JobID` now return an `AsyncJob<>`, which can be used to asynchronously await for results. (pr #170)
|
||||
* Added `SteamApps.PICSGetAccessTokens` overload with singular parameters. (pr #190)
|
||||
* Added `SteamFriends.RequestMessageHistory` and `SteamFriends.RequestOfflineMessages` (pr #193)
|
||||
* Added the ability to connect to Developer instances of Steam (`EUniverse.Dev`). If anyone at Valve is using this internally, hi!
|
||||
* Added the ability to set a `LoginID` in `SteamUser.LogOnDetails` so that multiple instances can connect from the same host concurrenctly. (pr #217)
|
||||
* Added `SteamClient.DebugNetworkListener` API to intercept and log raw messages. (pr #204)
|
||||
* Added the ability to dump messages in NetHook2 format for debugging purposes. (pr #204)
|
||||
* Upgraded the encryption protocol used to communicate with the Steam servers.
|
||||
* Implemented protection against man-in-the-middle attacks. (pr #214)
|
||||
* Server List will now maintain ordering from Steam, increasing the chances of a successful and geographically local connection. (pr #218)
|
||||
* After calling `SteamUser.LogOff` or `SteamGameServer.LogOff`, `SteamClient.DisconnectedCallback.UserInitiated` will be `true`. (pr #205)
|
||||
* Fixed a crash when parsing a Steam ID of the format '[i:1:234]'.
|
||||
* Fixed a crash when logging on in an enviromnent where the hard disk has no serial ID, such as Hyper-V.
|
||||
* Fixed a bug when parsing a KeyValue file that contains a `/` followed by a newline. (pr #187)
|
||||
* Updated Steam enums and protobufs.
|
||||
* Updated game-related GC messages and protobufs.
|
||||
|
||||
BREAKING CHANGES
|
||||
* SteamKit2 now requires .NET 4.5 or equivalent (Mono 3.0), or higher.
|
||||
* Removed obsoleted `ICallbackMsg` extension methods `IsType<>` and `Handle<>`. (pr #221)
|
||||
* Game Coordinator base messages are now generated per-game, instead of relying on Dota 2. GC messages should use the base messages for their game, which is separated by namespace. (pr #180)
|
||||
* Cell IDs are now consistently `uint`s within `SteamDirectory`.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
v 1.6.5 Oct 17, 2015
|
||||
------------------------------------------------------------------------------
|
||||
BIN
tools/ILMerge.doc
Normal file
BIN
tools/ILMerge.doc
Normal file
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user