Compare commits

...

79 Commits

Author SHA1 Message Date
JustArchi
33df54365a Add !help + code review 2016-03-26 02:47:25 +01:00
JustArchi
4a6ae3064a Put NetHook2 in it's own directory + add small readme 2016-03-25 12:42:34 +01:00
JustArchi
84857e060b Add !pause + misc 2016-03-24 14:18:07 +01:00
JustArchi
3311f2a703 Make number of hours human-readable 2016-03-24 08:14:26 +01:00
JustArchi
5666ebf891 Bump 2016-03-23 19:04:27 +01:00
JustArchi
0ded4f3b80 Bump 2016-03-23 18:53:51 +01:00
JustArchi
4c9354308c Improve UI a little 2016-03-23 18:38:19 +01:00
JustArchi
0bcf2f35b7 Misc 2016-03-23 13:59:54 +01:00
JustArchi
b93d5187d6 Misc 2016-03-23 13:48:59 +01:00
JustArchi
1426922854 Misc 2016-03-23 13:42:16 +01:00
JustArchi
d8925f9409 Sync ConfigGenerator 2016-03-23 13:39:56 +01:00
JustArchi
4302029bee Be consistent 2016-03-23 13:31:11 +01:00
JustArchi
01a7800a44 Final touch on travis + readme 2016-03-23 13:26:03 +01:00
JustArchi
ab3cf5b8d0 Add travis build status 2016-03-23 13:13:04 +01:00
JustArchi
2ab9741fa8 Add travis integration 2016-03-23 13:09:17 +01:00
JustArchi
f1c3339764 Misc 2016-03-23 12:18:16 +01:00
JustArchi
da01d4eab3 Use self-compiled ILRepack 2016-03-23 12:09:26 +01:00
JustArchi
cd9bd5f0dd Misc 2016-03-22 20:20:04 +01:00
JustArchi
2602ac3623 Improve Start/Stop mechanisms 2016-03-22 20:18:47 +01:00
JustArchi
2fe8db712e Enable enhanced logging when Debug is enabled, #176 2016-03-22 18:45:30 +01:00
JustArchi
687b20bcb5 Misc 2016-03-22 17:33:08 +01:00
JustArchi
23d9dcffe7 Enable AccountPlayingDelay of 0, WCFHostname of null and add code for fixing fuckups 2016-03-22 17:26:39 +01:00
JustArchi
42623ffb5a Misc 2016-03-22 16:49:17 +01:00
JustArchi
214003edbd Misc 2016-03-22 16:42:53 +01:00
JustArchi
c21333b6e9 Further code optimizations 2016-03-22 16:41:17 +01:00
JustArchi
630f1c008c Bump 2016-03-22 16:09:33 +01:00
JustArchi
68977b7907 Code review 2016-03-22 16:04:15 +01:00
JustArchi
6dade5440e Greatly enhance Complex algorithm by reading hours from pages directly 2016-03-22 15:52:27 +01:00
JustArchi
10fcfae171 Misc 2016-03-22 13:02:31 +01:00
JustArchi
320055680b Bump 2016-03-22 11:39:20 +01:00
JustArchi
84a99c3696 Never load example and minimal configs
I'm getting tired of people not reading wiki
2016-03-22 11:28:59 +01:00
JustArchi
df415c8db5 Code review 2016-03-22 11:21:45 +01:00
JustArchi
9bc04640a1 Closes #175 2016-03-22 11:10:34 +01:00
JustArchi
d6c1bdb9b5 Misc 2016-03-22 09:01:12 +01:00
JustArchi
7276350f74 Fix rare restart issue 2016-03-22 08:53:55 +01:00
JustArchi
7d3c05088a Code review 2016-03-21 16:31:59 +01:00
JustArchi
41c2bd9131 Fix WCF in client mode 2016-03-21 06:34:26 +01:00
JustArchi
514a9f38c8 Don't allow to !farm when bot is not connected 2016-03-21 03:39:35 +01:00
JustArchi
5cc884639f Add tutorial and le voila 2016-03-20 10:01:04 +01:00
JustArchi
f77cb6d33b First nice version 2016-03-20 08:29:27 +01:00
JustArchi
b642f4b240 Fix fuckups 2016-03-20 06:42:19 +01:00
JustArchi
6de721089c Starts looking good 2016-03-20 06:41:12 +01:00
JustArchi
4bd48c399a Bump 2016-03-20 05:47:45 +01:00
JustArchi
2b3a5ff337 Work on extra GUI app 2016-03-20 05:27:30 +01:00
JustArchi
0387eb3746 Misc 2016-03-19 15:33:07 +01:00
JustArchi
3ebc6d618a Misc 2016-03-19 15:31:54 +01:00
JustArchi
92d9e10cb8 Bump 2016-03-19 12:03:39 +01:00
JustArchi
d0d670f1a5 Add warning for invalid protocols 2016-03-19 11:48:51 +01:00
JustArchi
3597c8f138 Make it possible to run steam client with UDP 2016-03-19 11:33:39 +01:00
JustArchi
8a8ec29b41 Fix OnBotShutdown() firing too fast 2016-03-18 20:56:23 +01:00
JustArchi
a3352d032d Bump 2016-03-18 20:45:31 +01:00
JustArchi
d5f8647fcc Misc 2016-03-18 20:36:13 +01:00
JustArchi
79a700d786 Fix group chat commands, #165 2016-03-18 20:35:42 +01:00
JustArchi
bc223f0644 Misc 2016-03-18 14:54:42 +01:00
JustArchi
2b0d82453b Speedup login by doing independent tasks in parallel 2016-03-18 14:47:52 +01:00
JustArchi
fa0150e745 Code review 2016-03-18 14:39:59 +01:00
JustArchi
c95d11ef66 Actually do not respond to non-authorized users at all 2016-03-18 14:13:04 +01:00
JustArchi
63b268f9c4 Bump 2016-03-18 14:09:24 +01:00
JustArchi
03d38f8a2a Fix derp, #165 2016-03-18 14:05:18 +01:00
JustArchi
c88d9bf123 Implement SteamOwnerID 2016-03-18 09:02:09 +01:00
JustArchi
053ebe15bb Prepare for SteamOwnerID 2016-03-18 03:52:36 +01:00
JustArchi
b03bfb6bbc Don't touch old log when disabled 2016-03-18 03:48:00 +01:00
JustArchi
e48867000e Add LogToFile, closes #168 2016-03-18 03:45:59 +01:00
JustArchi
e08cdbd74d Bump 2016-03-16 19:58:21 +01:00
JustArchi
0b4c585a58 Bump 2016-03-16 19:55:16 +01:00
JustArchi
6213e77fab Time to sleep 2016-03-15 07:09:30 +01:00
JustArchi
fccca6a4fc Misc 2016-03-15 07:04:31 +01:00
JustArchi
d4f4ec3401 Misc 2016-03-15 05:16:22 +01:00
JustArchi
b23dd3612d Misc 2016-03-15 05:15:22 +01:00
JustArchi
ca4fa4ac27 Packages update 2016-03-15 05:03:50 +01:00
JustArchi
5e53a208d5 Misc 2016-03-15 04:51:51 +01:00
JustArchi
895c69642d Add !owns, closes #159 2016-03-15 04:20:28 +01:00
JustArchi
765f9d29bb Fix version comparison bug (and bump to 2.0.1.0 to fix legacy versions) 2016-03-14 22:40:19 +01:00
JustArchi
99af5c86a5 Bump 2016-03-14 22:20:06 +01:00
JustArchi
0bb2b3ed5f Add UnobservedTaskExceptionHandler, thank you @Netshroud 2016-03-14 20:51:29 +01:00
JustArchi
4181f3ba21 Add workaround for broken GenerateMachineID(), #154 2016-03-14 20:38:17 +01:00
JustArchi
c189b398c0 Improve readability 2016-03-14 18:24:03 +01:00
JustArchi
de4fbf8b04 Accept only trade confirmations when dealing with trades 2016-03-14 18:13:33 +01:00
JustArchi
f91a558314 Bump 2016-03-13 22:58:52 +01:00
78 changed files with 9174 additions and 523 deletions

3
.gitignore vendored
View File

@@ -12,6 +12,9 @@ ArchiSteamFarm/config/*
ArchiSteamFarm/log.txt
ArchiSteamFarm/debug/*
# Ignore out
out/
#################
## Eclipse
#################

10
.travis.yml Normal file
View File

@@ -0,0 +1,10 @@
sudo: false
language: csharp
solution: ArchiSteamFarm.sln
git:
depth: 10
mono:
- weekly
- latest

View File

@@ -1,12 +1,17 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
VisualStudioVersion = 14.0.24720.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
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConfigGenerator", "ConfigGenerator\ConfigGenerator.csproj", "{C3F6FE68-5E75-415E-BEA1-1E7C16D6A433}"
ProjectSection(ProjectDependencies) = postProject
{35AF7887-08B9-40E8-A5EA-797D8B60B30C} = {35AF7887-08B9-40E8-A5EA-797D8B60B30C}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +26,10 @@ Global
{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
{C3F6FE68-5E75-415E-BEA1-1E7C16D6A433}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3F6FE68-5E75-415E-BEA1-1E7C16D6A433}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3F6FE68-5E75-415E-BEA1-1E7C16D6A433}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3F6FE68-5E75-415E-BEA1-1E7C16D6A433}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -265,6 +265,36 @@ namespace ArchiSteamFarm {
}
}
// TODO: Please remove me immediately after https://github.com/SteamRE/SteamKit/issues/254 gets fixed
internal void HackedLogOn(SteamUser.LogOnDetails details) {
if (!Client.IsConnected) {
return;
}
SteamID steamID = new SteamID(details.AccountID, details.AccountInstance, Client.ConnectedUniverse, EAccountType.Individual);
var logon = new ClientMsgProtobuf<CMsgClientLogon>(EMsg.ClientLogon);
logon.Body.obfustucated_private_ip = details.LoginID.Value;
logon.ProtoHeader.client_sessionid = 0;
logon.ProtoHeader.steamid = steamID.ConvertToUInt64();
logon.Body.account_name = details.Username;
logon.Body.password = details.Password;
logon.Body.should_remember_password = details.ShouldRememberPassword;
logon.Body.protocol_version = MsgClientLogon.CurrentProtocol;
logon.Body.client_os_type = (uint) details.ClientOSType;
logon.Body.client_language = details.ClientLanguage;
logon.Body.cell_id = details.CellID;
logon.Body.steam2_ticket_request = details.RequestSteam2Ticket;
logon.Body.client_package_version = 1771;
logon.Body.auth_code = details.AuthCode;
logon.Body.two_factor_code = details.TwoFactorCode;
logon.Body.login_key = details.LoginKey;
logon.Body.sha_sentryfile = details.SentryFileHash;
logon.Body.eresult_sentryfile = (int) (details.SentryFileHash != null ? EResult.OK : EResult.FileNotFound);
Client.Send(logon);
}
/*
_ _ _ _
| | | | __ _ _ __ __| || | ___ _ __ ___

View File

@@ -76,7 +76,7 @@
<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.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\packages\Newtonsoft.Json.8.0.3\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">
@@ -160,20 +160,20 @@
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent Condition=" '$(OS)' != 'Unix' AND '$(ConfigurationName)' == 'Release' ">
mkdir "$(TargetDir)out" "$(TargetDir)out\config"
copy "$(TargetDir)config\ASF.json" "$(TargetDir)out\config"
copy "$(TargetDir)config\example.json" "$(TargetDir)out\config"
copy "$(TargetDir)config\minimal.json" "$(TargetDir)out\config"
"$(SolutionDir)tools\ILRepack.exe" /ndebug /internalize /parallel /targetplatform:v4 /wildcards /out:"$(TargetDir)out\ASF.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll"
del "$(TargetDir)out\ASF.exe.config"
mkdir "$(SolutionDir)out\config"
copy "$(TargetDir)config\ASF.json" "$(SolutionDir)out\config"
copy "$(TargetDir)config\example.json" "$(SolutionDir)out\config"
copy "$(TargetDir)config\minimal.json" "$(SolutionDir)out\config"
"$(SolutionDir)tools\ILRepack\ILRepack.exe" /ndebug /internalize /parallel /targetplatform:v4 /wildcards /out:"$(SolutionDir)out\ASF.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll"
del "$(SolutionDir)out\ASF.exe.config"
</PostBuildEvent>
<PostBuildEvent Condition=" '$(OS)' == 'Unix' AND '$(ConfigurationName)' == 'Release' ">
mkdir -p "$(TargetDir)out" "$(TargetDir)out/config"
cp "$(TargetDir)config/ASF.json" "$(TargetDir)out/config"
cp "$(TargetDir)config/example.json" "$(TargetDir)out/config"
cp "$(TargetDir)config/minimal.json" "$(TargetDir)out/config"
mono -O=all "$(SolutionDir)tools/ILRepack.exe" /ndebug /internalize /parallel /targetplatform:v4 /wildcards /out:"$(TargetDir)out/ASF.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll"
rm "$(TargetDir)out/ASF.exe.config"
mkdir -p "$(SolutionDir)out/config"
cp "$(TargetDir)config/ASF.json" "$(SolutionDir)out/config"
cp "$(TargetDir)config/example.json" "$(SolutionDir)out/config"
cp "$(TargetDir)config/minimal.json" "$(SolutionDir)out/config"
mono -O=all "$(SolutionDir)tools/ILRepack/ILRepack.exe" /ndebug /internalize /parallel /targetplatform:v4 /wildcards /out:"$(SolutionDir)out/ASF.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll"
rm "$(SolutionDir)out/ASF.exe.config"
</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -31,6 +31,7 @@ using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace ArchiSteamFarm {
internal sealed class ArchiWebHandler {
@@ -147,13 +148,58 @@ namespace ArchiSteamFarm {
bool? isLoggedIn = await IsLoggedIn().ConfigureAwait(false);
if (isLoggedIn.HasValue && !isLoggedIn.Value) {
Logging.LogGenericInfo("Reconnecting because our sessionID expired!", Bot.BotName);
Task.Run(async () => await Bot.Restart().ConfigureAwait(false)).Forget();
Bot.RestartIfRunning().Forget();
return true;
}
return false;
}
internal async Task<Dictionary<uint, string>> GetOwnedGames() {
if (SteamID == 0) {
return null;
}
string request = SteamCommunityURL + "/profiles/" + SteamID + "/games/?xml=1";
XmlDocument response = null;
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
response = await WebBrowser.UrlGetToXML(request, Cookie).ConfigureAwait(false);
}
if (response == null) {
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
return null;
}
XmlNodeList xmlNodeList = response.SelectNodes("gamesList/games/game");
if (xmlNodeList == null || xmlNodeList.Count == 0) {
return null;
}
Dictionary<uint, string> result = new Dictionary<uint, string>(xmlNodeList.Count);
foreach (XmlNode xmlNode in xmlNodeList) {
XmlNode appNode = xmlNode.SelectSingleNode("appID");
if (appNode == null) {
continue;
}
uint appID;
if (!uint.TryParse(appNode.InnerText, out appID)) {
continue;
}
XmlNode nameNode = xmlNode.SelectSingleNode("name");
if (nameNode == null) {
continue;
}
result[appID] = nameNode.InnerText;
}
return result;
}
internal List<Steam.TradeOffer> GetTradeOffers() {
if (string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) {
return null;

File diff suppressed because it is too large Load Diff

View File

@@ -57,10 +57,10 @@ namespace ArchiSteamFarm {
}
}
[JsonProperty(Required = Required.AllowNull)]
[JsonProperty]
private string _LoginKey;
[JsonProperty(Required = Required.AllowNull)]
[JsonProperty]
private SteamGuardAccount _SteamGuardAccount;
private string FilePath;

View File

@@ -39,12 +39,12 @@ namespace ArchiSteamFarm {
private readonly ManualResetEvent FarmResetEvent = new ManualResetEvent(false);
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
private readonly Bot Bot;
private readonly Timer Timer;
private bool ManualMode = false;
private bool NowFarming = false;
internal bool ManualMode { get; private set; }
private bool NowFarming;
internal CardsFarmer(Bot bot) {
if (bot == null) {
@@ -53,7 +53,7 @@ namespace ArchiSteamFarm {
Bot = bot;
if (Program.GlobalConfig.IdleFarmingPeriod > 0 && Timer == null) {
if (Program.GlobalConfig.IdleFarmingPeriod > 0) {
Timer = new Timer(
async e => await CheckGamesForFarming().ConfigureAwait(false),
null,
@@ -63,32 +63,9 @@ namespace ArchiSteamFarm {
}
}
internal static HashSet<uint> GetGamesToFarmSolo(ConcurrentDictionary<uint, float> gamesToFarm) {
if (gamesToFarm == null) {
return null;
}
HashSet<uint> result = new HashSet<uint>();
foreach (KeyValuePair<uint, float> keyValue in gamesToFarm) {
if (keyValue.Value >= 2) {
result.Add(keyValue.Key);
}
}
return result;
}
internal static uint GetAnyGameToFarm(ConcurrentDictionary<uint, float> gamesToFarm) {
if (gamesToFarm == null) {
return 0;
}
return gamesToFarm.Keys.FirstOrDefault();
}
internal async Task<bool> SwitchToManualMode(bool manualMode) {
internal async Task SwitchToManualMode(bool manualMode) {
if (ManualMode == manualMode) {
return false;
return;
}
ManualMode = manualMode;
@@ -98,69 +75,18 @@ namespace ArchiSteamFarm {
await StopFarming().ConfigureAwait(false);
} else {
Logging.LogGenericInfo("Now running in Automatic Farming mode", Bot.BotName);
Task.Run(async () => await StartFarming().ConfigureAwait(false)).Forget();
StartFarming().Forget();
}
return true;
}
internal bool FarmMultiple(ConcurrentDictionary<uint, float> appIDs) {
if (appIDs.Count == 0) {
return true;
}
float maxHour = 0;
foreach (float hour in appIDs.Values) {
if (hour > maxHour) {
maxHour = hour;
}
}
CurrentGamesFarming.Clear();
CurrentGamesFarming.TrimExcess();
foreach (uint appID in appIDs.Keys) {
CurrentGamesFarming.Add(appID);
}
Logging.LogGenericInfo("Now farming: " + string.Join(", ", appIDs.Keys), Bot.BotName);
if (Farm(maxHour, appIDs.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.TrimExcess();
CurrentGamesFarming.Add(appID);
Logging.LogGenericInfo("Now farming: " + appID, Bot.BotName);
if (await Farm(appID).ConfigureAwait(false)) {
float 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() {
if (NowFarming || ManualMode) {
return;
}
await Semaphore.WaitAsync().ConfigureAwait(false);
if (ManualMode) {
if (NowFarming || ManualMode) {
Semaphore.Release(); // We have nothing to do, don't forget to release semaphore
return;
}
@@ -187,7 +113,6 @@ namespace ArchiSteamFarm {
uint appID = gamesToFarmSolo.First();
if (await FarmSolo(appID).ConfigureAwait(false)) {
farmedSomething = true;
Logging.LogGenericInfo("Done farming: " + appID, Bot.BotName);
gamesToFarmSolo.Remove(appID);
gamesToFarmSolo.TrimExcess();
} else {
@@ -196,7 +121,7 @@ namespace ArchiSteamFarm {
}
}
} else {
if (FarmMultiple(GamesToFarm)) {
if (FarmMultiple()) {
Logging.LogGenericInfo("Done farming: " + string.Join(", ", GamesToFarm.Keys), Bot.BotName);
} else {
NowFarming = false;
@@ -207,10 +132,9 @@ namespace ArchiSteamFarm {
} else { // If we have unrestricted card drops, we use simple algorithm
Logging.LogGenericInfo("Chosen farming algorithm: Simple", Bot.BotName);
while (GamesToFarm.Count > 0) {
uint appID = GetAnyGameToFarm(GamesToFarm);
uint appID = GamesToFarm.Keys.FirstOrDefault();
if (await FarmSolo(appID).ConfigureAwait(false)) {
farmedSomething = true;
Logging.LogGenericInfo("Done farming: " + appID, Bot.BotName);
} else {
NowFarming = false;
return;
@@ -225,7 +149,7 @@ namespace ArchiSteamFarm {
// We finished our queue for now, make sure that everything is indeed farmed before proceeding further
// Some games could be added in the meantime
if (await IsAnythingToFarm().ConfigureAwait(false)) {
Task.Run(async () => await StartFarming().ConfigureAwait(false)).Forget();
StartFarming().Forget();
return;
}
@@ -234,6 +158,10 @@ namespace ArchiSteamFarm {
}
internal async Task StopFarming() {
if (!NowFarming) {
return;
}
await Semaphore.WaitAsync().ConfigureAwait(false);
if (!NowFarming) {
@@ -243,15 +171,41 @@ namespace ArchiSteamFarm {
Logging.LogGenericInfo("Sending signal to stop farming", Bot.BotName);
FarmResetEvent.Set();
for (byte i = 0; i < 5 && NowFarming; i++) {
Logging.LogGenericInfo("Waiting for reaction...", Bot.BotName);
Logging.LogGenericInfo("Waiting for reaction...", Bot.BotName);
for (byte i = 0; i < Program.GlobalConfig.HttpTimeout && NowFarming; i++) {
await Utilities.SleepAsync(1000).ConfigureAwait(false);
}
if (NowFarming) {
Logging.LogGenericWarning("Timed out!", Bot.BotName);
}
FarmResetEvent.Reset();
Logging.LogGenericInfo("Farming stopped!", Bot.BotName);
Semaphore.Release();
}
internal async Task RestartFarming() {
await StopFarming().ConfigureAwait(false);
await StartFarming().ConfigureAwait(false);
}
private static HashSet<uint> GetGamesToFarmSolo(ConcurrentDictionary<uint, float> gamesToFarm) {
if (gamesToFarm == null) {
return null;
}
HashSet<uint> result = new HashSet<uint>();
foreach (KeyValuePair<uint, float> keyValue in gamesToFarm) {
if (keyValue.Value >= 2) {
result.Add(keyValue.Key);
}
}
return result;
}
private async Task<bool> IsAnythingToFarm() {
if (NowFarming) {
return true;
@@ -291,7 +245,7 @@ namespace ArchiSteamFarm {
CheckPage(htmlDocument); // Because we fetched page number 1 already
} else {
byte currentPage = page; // We need a copy of variable being passed when in for loops
tasks.Add(Task.Run(async () => await CheckPage(currentPage).ConfigureAwait(false)));
tasks.Add(CheckPage(currentPage));
}
}
await Task.WhenAll(tasks).ConfigureAwait(false);
@@ -300,16 +254,6 @@ namespace ArchiSteamFarm {
return false;
}
// If we have restricted card drops, actually do check hours of all games that are left to farm
if (Bot.BotConfig.CardDropsRestricted) {
tasks = new List<Task>(GamesToFarm.Count);
Logging.LogGenericInfo("Checking hours...", Bot.BotName);
foreach (uint appID in GamesToFarm.Keys) {
tasks.Add(Task.Run(async () => await CheckHours(appID).ConfigureAwait(false)));
}
await Task.WhenAll(tasks).ConfigureAwait(false);
}
return true;
}
@@ -318,19 +262,26 @@ namespace ArchiSteamFarm {
return;
}
HtmlNodeCollection htmlNodeCollection = htmlDocument.DocumentNode.SelectNodes("//a[@class='btn_green_white_innerfade btn_small_thin']");
if (htmlNodeCollection == null) {
HtmlNodeCollection htmlNodes = htmlDocument.DocumentNode.SelectNodes("//div[@class='badge_title_stats']");
if (htmlNodes == null) {
return;
}
foreach (HtmlNode htmlNode in htmlNodeCollection) {
string steamLink = htmlNode.GetAttributeValue("href", null);
foreach (HtmlNode htmlNode in htmlNodes) {
HtmlNode farmingNode = htmlNode.SelectSingleNode(".//a[@class='btn_green_white_innerfade btn_small_thin']");
if (farmingNode == null) {
continue; // This game is not needed for farming
}
string steamLink = farmingNode.GetAttributeValue("href", null);
if (string.IsNullOrEmpty(steamLink)) {
Logging.LogNullError("steamLink", Bot.BotName);
continue;
}
uint appID = (uint) Utilities.OnlyNumbers(steamLink);
if (appID == 0) {
Logging.LogNullError("appID", Bot.BotName);
continue;
}
@@ -338,8 +289,28 @@ namespace ArchiSteamFarm {
continue;
}
// We assume that every game has at least 2 hours played, until we actually check them
GamesToFarm[appID] = 2;
HtmlNode timeNode = htmlNode.SelectSingleNode(".//div[@class='badge_title_stats_playtime']");
if (timeNode == null) {
Logging.LogNullError("timeNode", Bot.BotName);
continue;
}
string hoursString = timeNode.InnerText;
if (string.IsNullOrEmpty(hoursString)) {
Logging.LogNullError("hoursString", Bot.BotName);
continue;
}
hoursString = Regex.Match(hoursString, @"[0-9\.,]+").Value;
float hours;
if (string.IsNullOrEmpty(hoursString)) {
hours = 0;
} else {
hours = float.Parse(hoursString, CultureInfo.InvariantCulture);
}
GamesToFarm[appID] = hours;
}
}
@@ -356,41 +327,6 @@ namespace ArchiSteamFarm {
CheckPage(htmlDocument);
}
private async Task CheckHours(uint appID) {
if (appID == 0) {
return;
}
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetGameCardsPage(appID).ConfigureAwait(false);
if (htmlDocument == null) {
Logging.LogNullError("htmlDocument", Bot.BotName);
return;
}
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//div[@class='badge_title_stats_playtime']");
if (htmlNode == null) {
Logging.LogNullError("htmlNode", Bot.BotName);
return;
}
string hoursString = htmlNode.InnerText;
if (string.IsNullOrEmpty(hoursString)) {
Logging.LogNullError("hoursString", Bot.BotName);
return;
}
hoursString = Regex.Match(hoursString, @"[0-9\.,]+").Value;
float hours;
if (string.IsNullOrEmpty(hoursString)) {
hours = 0;
} else {
hours = float.Parse(hoursString, CultureInfo.InvariantCulture);
}
GamesToFarm[appID] = hours;
}
private async Task CheckGamesForFarming() {
if (NowFarming || ManualMode || !Bot.SteamClient.IsConnected) {
return;
@@ -418,7 +354,66 @@ namespace ArchiSteamFarm {
return !htmlNode.InnerText.Contains("No card drops");
}
private bool FarmMultiple() {
if (GamesToFarm.Count == 0) {
return true;
}
float maxHour = 0;
foreach (KeyValuePair<uint, float> game in GamesToFarm) {
CurrentGamesFarming.Add(game.Key);
if (game.Value > maxHour) {
maxHour = game.Value;
}
}
if (maxHour >= 2) {
CurrentGamesFarming.Clear();
CurrentGamesFarming.TrimExcess();
return true;
}
Logging.LogGenericInfo("Now farming: " + string.Join(", ", CurrentGamesFarming), Bot.BotName);
if (FarmHours(maxHour, CurrentGamesFarming)) {
CurrentGamesFarming.Clear();
CurrentGamesFarming.TrimExcess();
return true;
} else {
CurrentGamesFarming.Clear();
CurrentGamesFarming.TrimExcess();
return false;
}
}
private async Task<bool> FarmSolo(uint appID) {
if (appID == 0) {
return true;
}
CurrentGamesFarming.Add(appID);
Logging.LogGenericInfo("Now farming: " + appID, Bot.BotName);
if (await Farm(appID).ConfigureAwait(false)) {
CurrentGamesFarming.Clear();
CurrentGamesFarming.TrimExcess();
float hours;
if (GamesToFarm.TryRemove(appID, out hours)) {
TimeSpan timeSpan = TimeSpan.FromHours(hours);
Logging.LogGenericInfo("Done farming: " + appID + " after " + timeSpan.ToString(@"hh\:mm") + " hours of playtime!", Bot.BotName);
}
return true;
} else {
CurrentGamesFarming.Clear();
CurrentGamesFarming.TrimExcess();
return false;
}
}
private async Task<bool> Farm(uint appID) {
if (appID == 0) {
return false;
}
Bot.ArchiHandler.PlayGames(appID);
bool success = true;
@@ -429,6 +424,11 @@ namespace ArchiSteamFarm {
success = false;
break;
}
// Don't forget to update our GamesToFarm hours
float timePlayed = Program.GlobalConfig.FarmingDelay / 60.0F;
GamesToFarm[appID] += timePlayed;
keepFarming = await ShouldFarm(appID).ConfigureAwait(false);
Logging.LogGenericInfo("Still farming: " + appID, Bot.BotName);
}
@@ -438,7 +438,11 @@ namespace ArchiSteamFarm {
return success;
}
private bool Farm(float maxHour, ICollection<uint> appIDs) {
private bool FarmHours(float maxHour, HashSet<uint> appIDs) {
if (maxHour < 0 || appIDs == null || appIDs.Count == 0) {
return false;
}
if (maxHour >= 2) {
return true;
}
@@ -447,7 +451,6 @@ namespace ArchiSteamFarm {
bool success = true;
while (maxHour < 2) {
Logging.LogGenericInfo("Still farming: " + string.Join(", ", appIDs), Bot.BotName);
if (FarmResetEvent.WaitOne(60 * 1000 * Program.GlobalConfig.FarmingDelay)) {
success = false;
break;
@@ -455,15 +458,12 @@ namespace ArchiSteamFarm {
// Don't forget to update our GamesToFarm hours
float timePlayed = Program.GlobalConfig.FarmingDelay / 60.0F;
foreach (KeyValuePair<uint, float> gameToFarm in GamesToFarm) {
if (!appIDs.Contains(gameToFarm.Key)) {
continue;
}
GamesToFarm[gameToFarm.Key] = gameToFarm.Value + timePlayed;
foreach (uint appID in appIDs) {
GamesToFarm[appID] += timePlayed;
}
maxHour += timePlayed;
Logging.LogGenericInfo("Still farming: " + string.Join(", ", appIDs), Bot.BotName);
}
Bot.ResetGamesPlayed();

View File

@@ -26,6 +26,7 @@ using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
namespace ArchiSteamFarm {
internal sealed class GlobalConfig {
@@ -35,6 +36,13 @@ namespace ArchiSteamFarm {
Experimental
}
private const byte DefaultMaxFarmingTime = 10;
private const byte DefaultFarmingDelay = 5;
private const byte DefaultHttpTimeout = 60;
private const ushort DefaultWCFPort = 1242;
private static readonly ProtocolType DefaultSteamProtocol = ProtocolType.Tcp;
// This is hardcoded blacklist which should not be possible to change
internal static readonly HashSet<uint> GlobalBlacklist = new HashSet<uint> { 267420, 303700, 335590, 368020, 425280 };
@@ -48,13 +56,19 @@ namespace ArchiSteamFarm {
internal EUpdateChannel UpdateChannel { get; private set; } = EUpdateChannel.Stable;
[JsonProperty(Required = Required.DisallowNull)]
internal byte MaxFarmingTime { get; private set; } = 10;
internal ProtocolType SteamProtocol { get; private set; } = DefaultSteamProtocol;
[JsonProperty(Required = Required.DisallowNull)]
internal ulong SteamOwnerID { get; private set; } = 0;
[JsonProperty(Required = Required.DisallowNull)]
internal byte MaxFarmingTime { get; private set; } = DefaultMaxFarmingTime;
[JsonProperty(Required = Required.DisallowNull)]
internal byte IdleFarmingPeriod { get; private set; } = 3;
[JsonProperty(Required = Required.DisallowNull)]
internal byte FarmingDelay { get; private set; } = 5;
internal byte FarmingDelay { get; private set; } = DefaultFarmingDelay;
[JsonProperty(Required = Required.DisallowNull)]
internal byte AccountPlayingDelay { get; private set; } = 5;
@@ -69,17 +83,24 @@ namespace ArchiSteamFarm {
internal bool ForceHttp { get; private set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
internal byte HttpTimeout { get; private set; } = 60;
internal byte HttpTimeout { get; private set; } = DefaultHttpTimeout;
[JsonProperty]
internal string WCFHostname { get; set; } = "localhost";
[JsonProperty(Required = Required.DisallowNull)]
internal string WCFHostname { get; private set; } = "localhost";
internal ushort WCFPort { get; private set; } = DefaultWCFPort;
[JsonProperty(Required = Required.DisallowNull)]
internal ushort WCFPort { get; private set; } = 1242;
internal bool LogToFile { get; private set; } = true;
[JsonProperty(Required = Required.DisallowNull)]
internal bool Statistics { get; private set; } = true;
// TODO: Please remove me immediately after https://github.com/SteamRE/SteamKit/issues/254 gets fixed
[JsonProperty(Required = Required.DisallowNull)]
internal bool HackIgnoreMachineID { get; private set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
internal HashSet<uint> Blacklist { get; private set; } = new HashSet<uint>(GlobalBlacklist);
@@ -97,6 +118,40 @@ namespace ArchiSteamFarm {
return null;
}
// SK2 supports only TCP and UDP steam protocols
// Ensure that user can't screw this up
switch (globalConfig.SteamProtocol) {
case ProtocolType.Tcp:
case ProtocolType.Udp:
break;
default:
Logging.LogGenericWarning("Configured SteamProtocol is invalid: " + globalConfig.SteamProtocol + ". Value of " + DefaultSteamProtocol + " will be used instead");
globalConfig.SteamProtocol = DefaultSteamProtocol;
break;
}
// User might not know what he's doing
// Ensure that he can't screw core ASF variables
if (globalConfig.MaxFarmingTime == 0) {
Logging.LogGenericWarning("Configured MaxFarmingTime is invalid: " + globalConfig.MaxFarmingTime + ". Value of " + DefaultMaxFarmingTime + " will be used instead");
globalConfig.MaxFarmingTime = DefaultMaxFarmingTime;
}
if (globalConfig.FarmingDelay == 0) {
Logging.LogGenericWarning("Configured FarmingDelay is invalid: " + globalConfig.FarmingDelay + ". Value of " + DefaultFarmingDelay + " will be used instead");
globalConfig.FarmingDelay = DefaultFarmingDelay;
}
if (globalConfig.HttpTimeout == 0) {
Logging.LogGenericWarning("Configured HttpTimeout is invalid: " + globalConfig.HttpTimeout + ". Value of " + DefaultHttpTimeout + " will be used instead");
globalConfig.HttpTimeout = DefaultHttpTimeout;
}
if (globalConfig.WCFPort == 0) {
Logging.LogGenericWarning("Configured WCFPort is invalid: " + globalConfig.WCFPort + ". Value of " + DefaultWCFPort + " will be used instead");
globalConfig.WCFPort = DefaultWCFPort;
}
return globalConfig;
}

View File

@@ -31,18 +31,18 @@ namespace ArchiSteamFarm {
internal static class Logging {
private static readonly object FileLock = new object();
internal static bool? LogToFile { get; set; } = null;
private static bool LogToFile = false;
internal static void Init() {
if (!LogToFile.HasValue) {
LogToFile = true;
}
LogToFile = Program.GlobalConfig.LogToFile;
lock (FileLock) {
try {
File.Delete(Program.LogFile);
} catch (Exception e) {
LogGenericException(e);
if (LogToFile) {
lock (FileLock) {
try {
File.Delete(Program.LogFile);
} catch (Exception e) {
LogGenericException(e);
}
}
}
}
@@ -69,7 +69,7 @@ namespace ArchiSteamFarm {
}
Log("[!] EXCEPTION: " + previousMethodName + "() <" + botName + "> " + exception.Message);
Log("[!] StackTrace: " + exception.StackTrace);
Log("[!] StackTrace:" + Environment.NewLine + exception.StackTrace);
if (exception.InnerException != null) {
LogGenericException(exception.InnerException, botName, previousMethodName);
@@ -123,7 +123,7 @@ namespace ArchiSteamFarm {
} catch { }
}
if (LogToFile.GetValueOrDefault()) {
if (LogToFile) {
lock (FileLock) {
try {
File.AppendAllText(Program.LogFile, loggedMessage);

View File

@@ -45,6 +45,7 @@ namespace ArchiSteamFarm {
SteamParentalPIN,
RevocationCode,
TwoFactorAuthentication,
WCFHostname
}
internal enum EMode : byte {
@@ -54,26 +55,27 @@ namespace ArchiSteamFarm {
Server // Normal + WCF server
}
private const string GithubReleaseURL = "https://api.github.com/repos/JustArchi/ArchiSteamFarm/releases"; // GitHub API is HTTPS only
internal const string ASF = "ASF";
internal const string ConfigDirectory = "config";
internal const string DebugDirectory = "debug";
internal const string LogFile = "log.txt";
internal const string GithubRepo = "JustArchi/ArchiSteamFarm";
internal const string GlobalConfigFile = ASF + ".json";
internal const string GlobalDatabaseFile = ASF + ".db";
private const string GithubReleaseURL = "https://api.github.com/repos/" + GithubRepo + "/releases"; // GitHub API is HTTPS only
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
internal static readonly Version Version = Assembly.GetName().Version;
private 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 Assembly Assembly = Assembly.GetExecutingAssembly();
private static readonly string ExecutableFile = Assembly.Location;
private static readonly string ExecutableName = Path.GetFileName(ExecutableFile);
private static readonly string ExecutableDirectory = Path.GetDirectoryName(ExecutableFile);
private static readonly WCF WCF = new WCF();
internal static readonly string Version = Assembly.GetName().Version.ToString();
internal static GlobalConfig GlobalConfig { get; private set; }
internal static GlobalDatabase GlobalDatabase { get; private set; }
internal static bool ConsoleIsBusy { get; private set; } = false;
@@ -144,10 +146,12 @@ namespace ArchiSteamFarm {
return;
}
Logging.LogGenericInfo("Local version: " + Version + " | Remote version: " + releaseResponse.Tag);
Version newVersion = new Version(releaseResponse.Tag);
if (string.Compare(Version, releaseResponse.Tag, StringComparison.Ordinal) >= 0) { // If local version is the same or newer than remote version
if (GlobalConfig.AutoUpdates && AutoUpdatesTimer == null) {
Logging.LogGenericInfo("Local version: " + Version + " | Remote version: " + newVersion);
if (Version.CompareTo(newVersion) >= 0) { // If local version is the same or newer than remote version
if (AutoUpdatesTimer == null && GlobalConfig.AutoUpdates) {
Logging.LogGenericInfo("ASF will automatically check for new versions every 24 hours");
AutoUpdatesTimer = new Timer(
async e => await CheckForUpdate().ConfigureAwait(false),
@@ -240,34 +244,15 @@ namespace ArchiSteamFarm {
Logging.LogGenericInfo("Update process is finished! ASF will now restart itself...");
await Utilities.SleepAsync(5000);
if (!Restart()) {
// Make sure that we won't try updating again in this case
if (AutoUpdatesTimer != null) {
AutoUpdatesTimer.Dispose();
AutoUpdatesTimer = null;
}
// Inform user about failure
Logging.LogGenericWarning("ASF could not restart itself, you may need to restart it manually!");
await Utilities.SleepAsync(5000);
}
Restart();
}
internal static void Exit(int exitCode = 0) {
Environment.Exit(exitCode);
}
internal static bool Restart() {
internal static void Restart() {
try {
if (Process.Start(ExecutableFile, string.Join(" ", Environment.GetCommandLineArgs().Skip(1))) != null) {
Exit();
return true;
} else {
return false;
}
Process.Start(ExecutableFile, string.Join(" ", Environment.GetCommandLineArgs().Skip(1)));
Environment.Exit(0);
} catch (Exception e) {
Logging.LogGenericException(e);
return false;
}
}
@@ -279,7 +264,7 @@ namespace ArchiSteamFarm {
}).Forget();
}
internal static string GetUserInput(string botLogin, EUserInputType userInputType, string extraInformation = null) {
internal static string GetUserInput(EUserInputType userInputType, string botName = null, string extraInformation = null) {
if (userInputType == EUserInputType.Unknown) {
return null;
}
@@ -289,36 +274,38 @@ namespace ArchiSteamFarm {
ConsoleIsBusy = true;
switch (userInputType) {
case EUserInputType.DeviceID:
Console.Write("<" + botLogin + "> Please enter your Device ID (including \"android:\"): ");
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter your Device ID (including \"android:\"): ");
break;
case EUserInputType.Login:
Console.Write("<" + botLogin + "> Please enter your login: ");
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter your login: ");
break;
case EUserInputType.Password:
Console.Write("<" + botLogin + "> Please enter your password: ");
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter your password: ");
break;
case EUserInputType.PhoneNumber:
Console.Write("<" + botLogin + "> Please enter your full phone number (e.g. +1234567890): ");
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter your full phone number (e.g. +1234567890): ");
break;
case EUserInputType.SMS:
Console.Write("<" + botLogin + "> Please enter SMS code sent on your mobile: ");
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter SMS code sent on your mobile: ");
break;
case EUserInputType.SteamGuard:
Console.Write("<" + botLogin + "> Please enter the auth code sent to your email: ");
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter the auth code sent to your email: ");
break;
case EUserInputType.SteamParentalPIN:
Console.Write("<" + botLogin + "> Please enter steam parental PIN: ");
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "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...");
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "PLEASE WRITE DOWN YOUR REVOCATION CODE: " + extraInformation);
Console.Write("Hit enter once ready...");
break;
case EUserInputType.TwoFactorAuthentication:
Console.Write("<" + botLogin + "> Please enter your 2 factor auth code from your authenticator app: ");
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter your 2 factor auth code from your authenticator app: ");
break;
case EUserInputType.WCFHostname:
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter your WCF hostname: ");
break;
default:
Console.Write("<" + botLogin + "> Please enter not documented yet value of \"" + userInputType + "\": ");
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter not documented yet value of \"" + userInputType + "\": ");
break;
}
result = Console.ReadLine();
@@ -341,6 +328,7 @@ namespace ArchiSteamFarm {
}
Logging.LogGenericInfo("No bots are running, exiting");
Thread.Sleep(5000);
ShutdownResetEvent.Set();
}
@@ -349,14 +337,14 @@ namespace ArchiSteamFarm {
if (GlobalConfig == null) {
Logging.LogGenericError("Global config could not be loaded, please make sure that ASF.json exists and is valid!");
Thread.Sleep(5000);
Exit(1);
Environment.Exit(1);
}
GlobalDatabase = GlobalDatabase.Load();
if (GlobalDatabase == null) {
Logging.LogGenericError("Global database could not be loaded!");
Thread.Sleep(5000);
Exit(1);
Environment.Exit(1);
}
ArchiWebHandler.Init();
@@ -369,13 +357,6 @@ namespace ArchiSteamFarm {
switch (arg) {
case "--client":
Mode = EMode.Client;
Logging.LogToFile = false;
break;
case "--log":
Logging.LogToFile = true;
break;
case "--no-log":
Logging.LogToFile = false;
break;
case "--server":
Mode = EMode.Server;
@@ -392,10 +373,10 @@ namespace ArchiSteamFarm {
continue;
}
Logging.LogGenericInfo("Command sent: \"" + arg + "\"");
Logging.LogGenericInfo("Command sent: " + arg);
// We intentionally execute this async block synchronously
Logging.LogGenericInfo("Response received: \"" + WCF.SendCommand(arg) + "\"");
Logging.LogGenericInfo("Response received: " + WCF.SendCommand(arg));
/*
Task.Run(async () => {
Logging.LogGenericNotice("WCF", "Response received: " + await WCF.SendCommand(arg).ConfigureAwait(false));
@@ -414,8 +395,17 @@ namespace ArchiSteamFarm {
Logging.LogGenericException((Exception) args.ExceptionObject);
}
private static void Main(string[] args) {
private static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs args) {
if (sender == null || args == null) {
return;
}
Logging.LogGenericException(args.Exception);
}
private static void Init(string[] args) {
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler;
Logging.LogGenericInfo("Archi's Steam Farm, version " + Version);
Directory.SetCurrentDirectory(ExecutableDirectory);
@@ -440,11 +430,11 @@ namespace ArchiSteamFarm {
// If debugging is on, we prepare debug directory prior to running
if (GlobalConfig.Debug) {
if (Directory.Exists(Program.DebugDirectory)) {
Directory.Delete(Program.DebugDirectory, true);
if (Directory.Exists(DebugDirectory)) {
Directory.Delete(DebugDirectory, true);
Thread.Sleep(1000); // Dirty workaround giving Windows some time to sync
}
Directory.CreateDirectory(Program.DebugDirectory);
Directory.CreateDirectory(DebugDirectory);
SteamKit2.DebugLog.AddListener(new Debugging.DebugListener(Path.Combine(Program.DebugDirectory, "debug.txt")));
SteamKit2.DebugLog.Enabled = true;
@@ -455,7 +445,7 @@ namespace ArchiSteamFarm {
// If we ran ASF as a client, we're done by now
if (Mode == EMode.Client) {
return;
Environment.Exit(0);
}
// From now on it's server mode
@@ -464,7 +454,7 @@ namespace ArchiSteamFarm {
if (!Directory.Exists(ConfigDirectory)) {
Logging.LogGenericError("Config directory doesn't exist!");
Thread.Sleep(5000);
Exit(1);
Environment.Exit(1);
}
CheckForUpdate().Wait();
@@ -472,14 +462,21 @@ namespace ArchiSteamFarm {
// Before attempting to connect, initialize our list of CMs
Bot.RefreshCMs(GlobalDatabase.CellID).Wait();
bool isRunning = false;
foreach (var configFile in Directory.EnumerateFiles(ConfigDirectory, "*.json")) {
string botName = Path.GetFileNameWithoutExtension(configFile);
if (botName.Equals(ASF)) {
continue;
switch (botName) {
case ASF:
case "example":
case "minimal":
continue;
}
Bot bot = new Bot(botName);
if (bot.BotConfig == null || !bot.BotConfig.Enabled) {
if (bot.BotConfig != null && bot.BotConfig.Enabled) {
isRunning = true;
} else {
Logging.LogGenericInfo("Not starting this instance because it's disabled in config file", botName);
}
}
@@ -489,23 +486,28 @@ namespace ArchiSteamFarm {
string botName = Path.GetFileNameWithoutExtension(configFile);
Logging.LogGenericWarning("Found legacy " + botName + ".xml config file, it will now be converted to new ASF V2.0 format!");
Bot bot = new Bot(botName);
if (bot.BotConfig == null || !bot.BotConfig.Enabled) {
if (bot.BotConfig != null && bot.BotConfig.Enabled) {
isRunning = true;
} else {
Logging.LogGenericInfo("Not starting this instance because it's disabled in config file", botName);
}
}
// CONVERSION END
// Check if we got any bots running
OnBotShutdown();
if (!isRunning) {
OnBotShutdown();
}
}
private static void Main(string[] args) {
Init(args);
// Wait for signal to shutdown
ShutdownResetEvent.WaitOne();
// We got a signal to shutdown, consider giving user some time to read the message
Thread.Sleep(5000);
// This is over, cleanup only now
WCF.StopServer();
// We got a signal to shutdown
Environment.Exit(0);
}
}
}

View File

@@ -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("2.0.0.9")]
[assembly: AssemblyFileVersion("2.0.0.9")]
[assembly: AssemblyVersion("2.0.2.0")]
[assembly: AssemblyFileVersion("2.0.2.0")]

View File

@@ -22,6 +22,7 @@
*/
using SteamAuth;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -34,8 +35,9 @@ namespace ArchiSteamFarm {
private static readonly SemaphoreSlim InventorySemaphore = new SemaphoreSlim(1);
private readonly Bot Bot;
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
private volatile byte ParsingTasks = 0;
private readonly SemaphoreSlim TradesSemaphore = new SemaphoreSlim(1);
private byte ParsingTasks = 0;
internal static async Task LimitInventoryRequestsAsync() {
await InventorySemaphore.WaitAsync().ConfigureAwait(false);
@@ -53,18 +55,27 @@ namespace ArchiSteamFarm {
Bot = bot;
}
internal async void CheckTrades() {
if (ParsingTasks >= 2) {
internal async Task CheckTrades() {
bool shouldRun = false;
lock (TradesSemaphore) {
if (ParsingTasks < 2) {
ParsingTasks++;
shouldRun = true;
}
}
if (!shouldRun) {
return;
}
ParsingTasks++;
await TradesSemaphore.WaitAsync().ConfigureAwait(false);
await Semaphore.WaitAsync().ConfigureAwait(false);
await ParseActiveTrades().ConfigureAwait(false);
Semaphore.Release();
lock (TradesSemaphore) {
ParsingTasks--;
}
ParsingTasks--;
TradesSemaphore.Release();
}
private async Task ParseActiveTrades() {
@@ -81,7 +92,7 @@ namespace ArchiSteamFarm {
}
await Task.WhenAll(tasks).ConfigureAwait(false);
await Bot.AcceptAllConfirmations().ConfigureAwait(false);
await Bot.AcceptConfirmations(Confirmation.ConfirmationType.Trade).ConfigureAwait(false);
}
private async Task ParseTrade(Steam.TradeOffer tradeOffer) {

View File

@@ -42,6 +42,10 @@ namespace ArchiSteamFarm {
private Client Client;
internal static void Init() {
if (string.IsNullOrEmpty(Program.GlobalConfig.WCFHostname)) {
Program.GlobalConfig.WCFHostname = Program.GetUserInput(Program.EUserInputType.WCFHostname);
}
URL = "http://" + Program.GlobalConfig.WCFHostname + ":" + Program.GlobalConfig.WCFPort + "/ASF";
}
@@ -113,12 +117,12 @@ namespace ArchiSteamFarm {
return "ERROR: Couldn't find any bot named: " + botName;
}
Logging.LogGenericInfo("Received command: \"" + input + "\"");
Logging.LogGenericInfo("Received command: " + input);
string command = '!' + input;
string output = bot.HandleMessage(command).Result; // TODO: This should be asynchronous
string output = bot.Response(Program.GlobalConfig.SteamOwnerID, command).Result; // TODO: This should be asynchronous
Logging.LogGenericInfo("Answered to command: \"" + input + "\" with: \"" + output + "\"");
Logging.LogGenericInfo("Answered to command: " + input + " with: " + output);
return output;
}
}

View File

@@ -31,18 +31,20 @@ 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 MaxConnections = 10; // Defines maximum number of connections per ServicePoint. Be careful, as it also defines maximum number of sockets in CLOSE_WAIT state
internal const byte MaxIdleTime = 15; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it
internal const byte MaxRetries = 5; // Defines maximum number of retries, UrlRequest() does not handle retry by itself (it's app responsibility)
private const byte MaxConnections = 10; // Defines maximum number of connections per ServicePoint. Be careful, as it also defines maximum number of sockets in CLOSE_WAIT state
private const byte MaxIdleTime = 15; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it
private static readonly string DefaultUserAgent = "ArchiSteamFarm/" + Program.Version;
private static readonly HttpClient HttpClient = new HttpClient(new HttpClientHandler {
UseCookies = false
}) {
Timeout = TimeSpan.FromSeconds(30)
Timeout = TimeSpan.FromSeconds(60)
};
internal static void Init() {
@@ -155,6 +157,28 @@ namespace ArchiSteamFarm {
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(e);
return null;
}
return xmlDocument;
}
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;
@@ -190,7 +214,16 @@ namespace ArchiSteamFarm {
}
}
if (responseMessage == null || !responseMessage.IsSuccessStatusCode) {
if (responseMessage == null) {
return null;
}
if (!responseMessage.IsSuccessStatusCode) {
if (Program.GlobalConfig.Debug) {
Logging.LogGenericError("Request: " + request + "failed!");
Logging.LogGenericError("Status code: " + responseMessage.StatusCode);
Logging.LogGenericError("Content: " + await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false));
}
return null;
}

View File

@@ -2,6 +2,8 @@
"Debug": false,
"AutoUpdates": true,
"UpdateChannel": 1,
"SteamProtocol": 6,
"SteamOwnerID": 0,
"MaxFarmingTime": 10,
"IdleFarmingPeriod": 3,
"FarmingDelay": 5,
@@ -12,7 +14,9 @@
"HttpTimeout": 60,
"WCFHostname": "localhost",
"WCFPort": 1242,
"LogToFile": true,
"Statistics": true,
"HackIgnoreMachineID": false,
"Blacklist": [
267420,
303700,

View File

@@ -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.2" targetFramework="net452" />
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net451" />
<package id="protobuf-net" version="2.0.0.668" targetFramework="net45" />
<package id="SteamKit2" version="1.7.0" targetFramework="net452" />
</packages>

View File

@@ -0,0 +1,86 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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 Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
namespace ConfigGenerator {
internal class ASFConfig {
internal static HashSet<ASFConfig> ASFConfigs = new HashSet<ASFConfig>();
internal string FilePath { get; set; }
protected ASFConfig() {
ASFConfigs.Add(this);
}
protected ASFConfig(string filePath) : this() {
FilePath = filePath;
}
internal virtual void Save() {
lock (FilePath) {
try {
File.WriteAllText(FilePath, JsonConvert.SerializeObject(this, Formatting.Indented));
} catch (Exception e) {
Logging.LogGenericException(e);
}
}
}
internal virtual void Remove() {
string queryPath = Path.GetFileNameWithoutExtension(FilePath);
lock (FilePath) {
foreach (var configFile in Directory.EnumerateFiles(Program.ConfigDirectory, queryPath + ".*")) {
try {
File.Delete(configFile);
} catch (Exception e) {
Logging.LogGenericException(e);
}
}
}
ASFConfigs.Remove(this);
}
internal virtual void Rename(string botName) {
if (string.IsNullOrEmpty(botName)) {
return;
}
string queryPath = Path.GetFileNameWithoutExtension(FilePath);
lock (FilePath) {
foreach (var file in Directory.EnumerateFiles(Program.ConfigDirectory, queryPath + ".*")) {
try {
File.Move(file, Path.Combine(Program.ConfigDirectory, botName + Path.GetExtension(file)));
} catch (Exception e) {
Logging.LogGenericException(e);
}
}
FilePath = Path.Combine(Program.ConfigDirectory, botName + ".json");
}
}
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
</configuration>

View File

@@ -0,0 +1,130 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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 Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
namespace ConfigGenerator {
internal sealed class BotConfig : ASFConfig {
[JsonProperty(Required = Required.DisallowNull)]
public bool Enabled { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public bool StartOnLaunch { get; set; } = true;
[JsonProperty]
public string SteamLogin { get; set; } = null;
[JsonProperty]
public string SteamPassword { get; set; } = null;
[JsonProperty]
public string SteamParentalPIN { get; set; } = "0";
[JsonProperty]
public string SteamApiKey { get; set; } = null;
[JsonProperty(Required = Required.DisallowNull)]
public ulong SteamMasterID { get; set; } = 0;
[JsonProperty(Required = Required.DisallowNull)]
public ulong SteamMasterClanID { get; set; } = 0;
[JsonProperty(Required = Required.DisallowNull)]
public bool CardDropsRestricted { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public bool DismissInventoryNotifications { get; set; } = true;
[JsonProperty(Required = Required.DisallowNull)]
public bool FarmOffline { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public bool HandleOfflineMessages { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public bool ForwardKeysToOtherBots { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public bool DistributeKeys { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public bool UseAsfAsMobileAuthenticator { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public bool ShutdownOnFarmingFinished { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public bool SendOnFarmingFinished { get; set; } = false;
[JsonProperty]
public string SteamTradeToken { get; set; } = null;
[JsonProperty(Required = Required.DisallowNull)]
public byte SendTradePeriod { get; set; } = 0;
[JsonProperty(Required = Required.DisallowNull)]
public byte AcceptConfirmationsPeriod { get; set; } = 0;
[JsonProperty]
public string CustomGamePlayedWhileIdle { get; set; } = null;
[JsonProperty(Required = Required.DisallowNull)]
public List<uint> GamesPlayedWhileIdle { get; set; } = new List<uint>();
internal static BotConfig Load(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
return null;
}
if (!File.Exists(filePath)) {
return new BotConfig(filePath);
}
BotConfig botConfig;
try {
botConfig = JsonConvert.DeserializeObject<BotConfig>(File.ReadAllText(filePath));
} catch (Exception e) {
Logging.LogGenericException(e);
return new BotConfig(filePath);
}
botConfig.FilePath = filePath;
return botConfig;
}
// This constructor is used only by deserializer
private BotConfig() : base() { }
private BotConfig(string filePath) : base(filePath) {
FilePath = filePath;
GamesPlayedWhileIdle.Add(0);
Save();
}
}
}

View File

@@ -0,0 +1,128 @@
<?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>{C3F6FE68-5E75-415E-BEA1-1E7C16D6A433}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ConfigGenerator</RootNamespace>
<AssemblyName>ConfigGenerator</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>
</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>cirno.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.8.0.3\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.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ASFConfig.cs" />
<Compile Include="BotConfig.cs" />
<Compile Include="DialogBox.cs" />
<Compile Include="EnhancedPropertyGrid.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Debugging.cs" />
<Compile Include="GlobalConfig.cs" />
<Compile Include="ConfigPage.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Logging.cs" />
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tutorial.cs" />
<EmbeddedResource Include="ConfigPage.resx">
<DependentUpon>ConfigPage.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="cirno.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent Condition=" '$(OS)' != 'Unix' AND '$(ConfigurationName)' == 'Release' ">
"$(SolutionDir)tools\ILRepack\ILRepack.exe" /ndebug /internalize /parallel /targetplatform:v4 /wildcards /out:"$(SolutionDir)out\ASF-GUI.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll"
del "$(SolutionDir)out\ASF-GUI.exe.config"
</PostBuildEvent>
<PostBuildEvent Condition=" '$(OS)' == 'Unix' AND '$(ConfigurationName)' == 'Release' ">
mono -O=all "$(SolutionDir)tools/ILRepack/ILRepack.exe" /ndebug /internalize /parallel /targetplatform:v4 /wildcards /out:"$(SolutionDir)out/ASF-GUI.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll"
rm "$(SolutionDir)out/ASF-GUI.exe.config"
</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">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,57 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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 System.IO;
using System.Windows.Forms;
namespace ConfigGenerator {
internal class ConfigPage : TabPage {
internal readonly ASFConfig ASFConfig;
private EnhancedPropertyGrid EnhancedPropertyGrid;
internal ConfigPage(ASFConfig config) : base() {
if (config == null) {
return;
}
ASFConfig = config;
RefreshText();
EnhancedPropertyGrid = new EnhancedPropertyGrid(config);
Controls.Add(EnhancedPropertyGrid);
}
internal void RefreshText() {
Text = Path.GetFileNameWithoutExtension(ASFConfig.FilePath);
}
private void InitializeComponent() {
SuspendLayout();
ResumeLayout(false);
}
}
}

View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
</root>

View File

@@ -0,0 +1,35 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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.
*/
namespace ConfigGenerator {
internal static class Debugging {
#if DEBUG
internal static readonly bool IsDebugBuild = true;
#else
internal static readonly bool IsDebugBuild = false;
#endif
internal static bool IsReleaseBuild => !IsDebugBuild;
}
}

View File

@@ -0,0 +1,119 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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 System;
using System.Drawing;
using System.Windows.Forms;
namespace ConfigGenerator {
class DialogBox {
public static DialogResult InputBox(string title, string promptText, out string value) {
if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(promptText)) {
value = null;
return DialogResult.Abort;
}
Form form = new Form();
Label label = new Label();
TextBox textBox = new TextBox();
textBox.Width = 1000;
Button buttonOk = new Button();
Button buttonCancel = new Button();
form.Text = title;
label.Text = promptText;
buttonOk.Text = "OK";
buttonCancel.Text = "Cancel";
buttonOk.DialogResult = DialogResult.OK;
buttonCancel.DialogResult = DialogResult.Cancel;
label.SetBounds(9, 20, 372, 13);
textBox.SetBounds(12, 36, 372, 20);
buttonOk.SetBounds(228, 72, 75, 23);
buttonCancel.SetBounds(309, 72, 75, 23);
label.AutoSize = true;
textBox.Anchor = textBox.Anchor | AnchorStyles.Right;
buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
form.ClientSize = new Size(396, 107);
form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel });
form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height);
form.FormBorderStyle = FormBorderStyle.FixedDialog;
form.StartPosition = FormStartPosition.CenterScreen;
form.MinimizeBox = false;
form.MaximizeBox = false;
form.AcceptButton = buttonOk;
form.CancelButton = buttonCancel;
DialogResult dialogResult = form.ShowDialog();
value = textBox.Text;
return dialogResult;
}
public static DialogResult YesNoBox(string title, string promptText) {
if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(promptText)) {
return DialogResult.Abort;
}
Form form = new Form();
Label label = new Label();
Button buttonOk = new Button();
Button buttonCancel = new Button();
form.Text = title;
label.Text = promptText;
buttonOk.Text = "Yes";
buttonCancel.Text = "No";
buttonOk.DialogResult = DialogResult.Yes;
buttonCancel.DialogResult = DialogResult.No;
label.SetBounds(9, 20, 372, 13);
buttonOk.SetBounds(228, 50, 75, 23);
buttonCancel.SetBounds(309, 50, 75, 23);
label.AutoSize = true;
buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
form.ClientSize = new Size(396, 80);
form.Controls.AddRange(new Control[] { label, buttonOk, buttonCancel });
form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height);
form.FormBorderStyle = FormBorderStyle.FixedDialog;
form.StartPosition = FormStartPosition.CenterScreen;
form.MinimizeBox = false;
form.MaximizeBox = false;
form.AcceptButton = buttonOk;
form.CancelButton = buttonCancel;
DialogResult dialogResult = form.ShowDialog();
return dialogResult;
}
}
}

View File

@@ -0,0 +1,73 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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 System.Windows.Forms;
namespace ConfigGenerator {
internal sealed class EnhancedPropertyGrid : PropertyGrid {
private ASFConfig ASFConfig;
internal EnhancedPropertyGrid(ASFConfig config) : base() {
if (config == null) {
return;
}
ASFConfig = config;
SelectedObject = config;
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
Dock = DockStyle.Fill;
HelpVisible = false;
ToolbarVisible = false;
}
protected override void OnPropertyValueChanged(PropertyValueChangedEventArgs e) {
if (e == null) {
return;
}
base.OnPropertyValueChanged(e);
ASFConfig.Save();
BotConfig botConfig = ASFConfig as BotConfig;
if (botConfig != null) {
if (botConfig.Enabled) {
Tutorial.OnAction(Tutorial.EPhase.BotEnabled);
if (!string.IsNullOrEmpty(botConfig.SteamLogin) && !string.IsNullOrEmpty(botConfig.SteamPassword)) {
Tutorial.OnAction(Tutorial.EPhase.BotReady);
}
}
return;
}
GlobalConfig globalConfig = ASFConfig as GlobalConfig;
if (globalConfig != null) {
if (globalConfig.SteamOwnerID != 0) {
Tutorial.OnAction(Tutorial.EPhase.GlobalConfigReady);
}
return;
}
}
}
}

View File

@@ -0,0 +1,172 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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 Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
namespace ConfigGenerator {
internal sealed class GlobalConfig : ASFConfig {
internal enum EUpdateChannel : byte {
Unknown,
Stable,
Experimental
}
private const byte DefaultMaxFarmingTime = 10;
private const byte DefaultFarmingDelay = 5;
private const byte DefaultHttpTimeout = 60;
private const ushort DefaultWCFPort = 1242;
private static readonly ProtocolType DefaultSteamProtocol = ProtocolType.Tcp;
// This is hardcoded blacklist which should not be possible to change
internal static readonly HashSet<uint> GlobalBlacklist = new HashSet<uint> { 267420, 303700, 335590, 368020, 425280 };
[JsonProperty(Required = Required.DisallowNull)]
public bool Debug { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public bool AutoUpdates { get; set; } = true;
[JsonProperty(Required = Required.DisallowNull)]
public EUpdateChannel UpdateChannel { get; set; } = EUpdateChannel.Stable;
[JsonProperty(Required = Required.DisallowNull)]
public ProtocolType SteamProtocol { get; set; } = DefaultSteamProtocol;
[JsonProperty(Required = Required.DisallowNull)]
public ulong SteamOwnerID { get; set; } = 0;
[JsonProperty(Required = Required.DisallowNull)]
public byte MaxFarmingTime { get; set; } = DefaultMaxFarmingTime;
[JsonProperty(Required = Required.DisallowNull)]
public byte IdleFarmingPeriod { get; set; } = 3;
[JsonProperty(Required = Required.DisallowNull)]
public byte FarmingDelay { get; set; } = DefaultFarmingDelay;
[JsonProperty(Required = Required.DisallowNull)]
public byte AccountPlayingDelay { get; set; } = 5;
[JsonProperty(Required = Required.DisallowNull)]
public byte LoginLimiterDelay { get; set; } = 7;
[JsonProperty(Required = Required.DisallowNull)]
public byte InventoryLimiterDelay { get; set; } = 3;
[JsonProperty(Required = Required.DisallowNull)]
public bool ForceHttp { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public byte HttpTimeout { get; set; } = DefaultHttpTimeout;
[JsonProperty]
public string WCFHostname { get; set; } = "localhost";
[JsonProperty(Required = Required.DisallowNull)]
public ushort WCFPort { get; set; } = DefaultWCFPort;
[JsonProperty(Required = Required.DisallowNull)]
public bool LogToFile { get; set; } = true;
[JsonProperty(Required = Required.DisallowNull)]
public bool Statistics { get; set; } = true;
// TODO: Please remove me immediately after https://github.com/SteamRE/SteamKit/issues/254 gets fixed
[JsonProperty(Required = Required.DisallowNull)]
public bool HackIgnoreMachineID { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
public List<uint> Blacklist { get; set; } = new List<uint>();
internal static GlobalConfig Load(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
return null;
}
if (!File.Exists(filePath)) {
return new GlobalConfig(filePath);
}
GlobalConfig globalConfig;
try {
globalConfig = JsonConvert.DeserializeObject<GlobalConfig>(File.ReadAllText(filePath));
} catch (Exception e) {
Logging.LogGenericException(e);
return new GlobalConfig(filePath);
}
globalConfig.FilePath = filePath;
// SK2 supports only TCP and UDP steam protocols
// Ensure that user can't screw this up
switch (globalConfig.SteamProtocol) {
case ProtocolType.Tcp:
case ProtocolType.Udp:
break;
default:
Logging.LogGenericWarning("Configured SteamProtocol is invalid: " + globalConfig.SteamProtocol + ". Value of " + DefaultSteamProtocol + " will be used instead");
globalConfig.SteamProtocol = DefaultSteamProtocol;
break;
}
// User might not know what he's doing
// Ensure that he can't screw core ASF variables
if (globalConfig.MaxFarmingTime == 0) {
Logging.LogGenericWarning("Configured MaxFarmingTime is invalid: " + globalConfig.MaxFarmingTime + ". Value of " + DefaultMaxFarmingTime + " will be used instead");
globalConfig.MaxFarmingTime = DefaultMaxFarmingTime;
}
if (globalConfig.FarmingDelay == 0) {
Logging.LogGenericWarning("Configured FarmingDelay is invalid: " + globalConfig.FarmingDelay + ". Value of " + DefaultFarmingDelay + " will be used instead");
globalConfig.FarmingDelay = DefaultFarmingDelay;
}
if (globalConfig.HttpTimeout == 0) {
Logging.LogGenericWarning("Configured HttpTimeout is invalid: " + globalConfig.HttpTimeout + ". Value of " + DefaultHttpTimeout + " will be used instead");
globalConfig.HttpTimeout = DefaultHttpTimeout;
}
if (globalConfig.WCFPort == 0) {
Logging.LogGenericWarning("Configured WCFPort is invalid: " + globalConfig.WCFPort + ". Value of " + DefaultWCFPort + " will be used instead");
globalConfig.WCFPort = DefaultWCFPort;
}
return globalConfig;
}
// This constructor is used only by deserializer
private GlobalConfig() : base() { }
private GlobalConfig(string filePath) : base(filePath) {
FilePath = filePath;
Blacklist.AddRange(GlobalBlacklist);
Save();
}
}
}

View File

@@ -0,0 +1,93 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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 System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
namespace ConfigGenerator {
internal static class Logging {
internal static void LogGenericInfo(string message) {
if (string.IsNullOrEmpty(message)) {
return;
}
MessageBox.Show(message, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
internal static void LogGenericWTF(string message, [CallerMemberName] string previousMethodName = "") {
if (string.IsNullOrEmpty(message)) {
return;
}
MessageBox.Show(previousMethodName + "() " + message, "WTF", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
internal static void LogGenericError(string message, [CallerMemberName] string previousMethodName = "") {
if (string.IsNullOrEmpty(message)) {
return;
}
MessageBox.Show(previousMethodName + "() " + message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
internal static void LogGenericException(Exception exception, [CallerMemberName] string previousMethodName = "") {
if (exception == null) {
return;
}
MessageBox.Show(previousMethodName + "() " + exception.Message + Environment.NewLine + exception.StackTrace, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
if (exception.InnerException != null) {
LogGenericException(exception.InnerException, previousMethodName);
}
}
internal static void LogGenericWarning(string message, [CallerMemberName] string previousMethodName = "") {
if (string.IsNullOrEmpty(message)) {
return;
}
MessageBox.Show(previousMethodName + "() " + message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
internal static void LogNullError(string nullObjectName, [CallerMemberName] string previousMethodName = "") {
if (string.IsNullOrEmpty(nullObjectName)) {
return;
}
LogGenericError(nullObjectName + " is null!", previousMethodName);
}
[Conditional("DEBUG")]
internal static void LogGenericDebug(string message, [CallerMemberName] string previousMethodName = "") {
if (string.IsNullOrEmpty(message)) {
return;
}
MessageBox.Show(previousMethodName + "() " + message, "Debug", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}

78
ConfigGenerator/MainForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,78 @@
namespace ConfigGenerator {
partial class MainForm {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.MainTab = new System.Windows.Forms.TabControl();
this.SuspendLayout();
//
// MainTab
//
this.MainTab.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.MainTab.Appearance = System.Windows.Forms.TabAppearance.Buttons;
this.MainTab.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.MainTab.HotTrack = true;
this.MainTab.Location = new System.Drawing.Point(14, 14);
this.MainTab.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.MainTab.Multiline = true;
this.MainTab.Name = "MainTab";
this.MainTab.SelectedIndex = 0;
this.MainTab.Size = new System.Drawing.Size(854, 745);
this.MainTab.SizeMode = System.Windows.Forms.TabSizeMode.Fixed;
this.MainTab.TabIndex = 1;
this.MainTab.Selected += new System.Windows.Forms.TabControlEventHandler(this.MainTab_Selected);
this.MainTab.Deselecting += new System.Windows.Forms.TabControlCancelEventHandler(this.MainTab_Deselecting);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScroll = true;
this.ClientSize = new System.Drawing.Size(882, 774);
this.Controls.Add(this.MainTab);
this.Cursor = System.Windows.Forms.Cursors.Default;
this.DoubleBuffered = true;
this.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.HelpButton = true;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "MainForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "ASF Config Generator";
this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.MainForm_HelpButtonClicked);
this.Load += new System.EventHandler(this.MainForm_Load);
this.Shown += new System.EventHandler(this.MainForm_Shown);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TabControl MainTab;
}
}

200
ConfigGenerator/MainForm.cs Normal file
View File

@@ -0,0 +1,200 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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 System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
namespace ConfigGenerator {
public partial class MainForm : Form {
private const byte ReservedTabs = 3;
private ConfigPage ASFTab;
private TabPage RemoveTab = new TabPage() {
Text = "-",
};
private TabPage RenameTab = new TabPage() {
Text = "~",
};
private TabPage NewTab = new TabPage() {
Text = "+",
};
private TabPage OldTab;
public MainForm() {
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e) {
if (sender == null || e == null) {
return;
}
ASFTab = new ConfigPage(GlobalConfig.Load(Path.Combine(Program.ConfigDirectory, Program.GlobalConfigFile)));
MainTab.TabPages.Add(ASFTab);
foreach (var configFile in Directory.EnumerateFiles(Program.ConfigDirectory, "*.json")) {
string botName = Path.GetFileNameWithoutExtension(configFile);
switch (botName) {
case Program.ASF:
case "example":
case "minimal":
continue;
}
MainTab.TabPages.Add(new ConfigPage(BotConfig.Load(configFile)));
Tutorial.Enabled = false;
}
MainTab.TabPages.AddRange(new TabPage[] { RemoveTab, RenameTab, NewTab });
Tutorial.OnAction(Tutorial.EPhase.Start);
}
private void MainTab_Selected(object sender, TabControlEventArgs e) {
if (sender == null || e == null) {
return;
}
if (e.TabPage == RemoveTab) {
ConfigPage configPage = OldTab as ConfigPage;
if (configPage == null) {
MainTab.SelectedIndex = -1;
return;
}
if (configPage == ASFTab) {
MainTab.SelectedTab = ASFTab;
Logging.LogGenericError("You can't remove global config!");
return;
}
MainTab.SelectedTab = configPage;
if (DialogBox.YesNoBox("Removal", "Do you really want to remove this config?") != DialogResult.Yes) {
return;
}
MainTab.SelectedIndex = 0;
configPage.ASFConfig.Remove();
MainTab.TabPages.Remove(configPage);
} else if (e.TabPage == RenameTab) {
ConfigPage configPage = OldTab as ConfigPage;
if (configPage == null) {
MainTab.SelectedIndex = -1;
return;
}
if (configPage == ASFTab) {
MainTab.SelectedTab = ASFTab;
Logging.LogGenericError("You can't rename global config!");
return;
}
MainTab.SelectedTab = configPage;
string input;
if (DialogBox.InputBox("Rename", "Your new bot name:", out input) != DialogResult.OK) {
return;
}
if (string.IsNullOrEmpty(input)) {
Logging.LogGenericError("Your bot name is empty!");
return;
}
configPage.ASFConfig.Rename(input);
configPage.RefreshText();
} else if (e.TabPage == NewTab) {
ConfigPage configPage = OldTab as ConfigPage;
if (configPage == null) {
MainTab.SelectedIndex = -1;
return;
}
MainTab.SelectedTab = configPage;
Tutorial.OnAction(Tutorial.EPhase.BotNickname);
string input;
if (DialogBox.InputBox("New", "Your new bot name:", out input) != DialogResult.OK) {
return;
}
if (string.IsNullOrEmpty(input)) {
Logging.LogGenericError("Your bot name is empty!");
return;
}
foreach (ASFConfig config in ASFConfig.ASFConfigs) {
if (Path.GetFileNameWithoutExtension(config.FilePath).Equals(input)) {
Logging.LogGenericError("Bot with such name exists already!");
return;
}
}
input = Path.Combine(Program.ConfigDirectory, input + ".json");
ConfigPage newConfigPage = new ConfigPage(BotConfig.Load(input));
MainTab.TabPages.Insert(MainTab.TabPages.Count - ReservedTabs, newConfigPage);
MainTab.SelectedTab = newConfigPage;
Tutorial.OnAction(Tutorial.EPhase.BotNicknameFinished);
} else if (e.TabPage == ASFTab) {
Tutorial.OnAction(Tutorial.EPhase.GlobalConfigOpened);
}
}
private void MainTab_Deselecting(object sender, TabControlCancelEventArgs e) {
if (sender == null || e == null) {
return;
}
OldTab = e.TabPage;
}
private void MainForm_Shown(object sender, EventArgs e) {
if (sender == null || e == null) {
return;
}
Tutorial.OnAction(Tutorial.EPhase.Shown);
}
private void MainForm_HelpButtonClicked(object sender, System.ComponentModel.CancelEventArgs e) {
if (sender == null || e == null) {
return;
}
e.Cancel = true;
Tutorial.OnAction(Tutorial.EPhase.Help);
Process.Start("https://github.com/JustArchi/ArchiSteamFarm/wiki/Configuration");
Tutorial.OnAction(Tutorial.EPhase.HelpFinished);
}
}
}

File diff suppressed because it is too large Load Diff

101
ConfigGenerator/Program.cs Normal file
View File

@@ -0,0 +1,101 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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 System;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ConfigGenerator {
internal static class Program {
internal const string ASF = "ASF";
internal const string ConfigDirectory = "config";
internal const string GlobalConfigFile = ASF + ".json";
private const string ASFDirectory = "ArchiSteamFarm";
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
private static readonly string ExecutableFile = Assembly.Location;
private static readonly string ExecutableName = Path.GetFileName(ExecutableFile);
private static readonly string ExecutableDirectory = Path.GetDirectoryName(ExecutableFile);
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main() {
Init();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
private static void Init() {
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler;
Directory.SetCurrentDirectory(ExecutableDirectory);
// Allow loading configs from source tree if it's a debug build
if (Debugging.IsDebugBuild) {
// Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up
for (byte i = 0; i < 4; i++) {
Directory.SetCurrentDirectory("..");
if (Directory.Exists(ASFDirectory)) {
Directory.SetCurrentDirectory(ASFDirectory);
break;
}
}
// If config directory doesn't exist after our adjustment, abort all of that
if (!Directory.Exists(ConfigDirectory)) {
Directory.SetCurrentDirectory(ExecutableDirectory);
}
}
if (!Directory.Exists(ConfigDirectory)) {
Logging.LogGenericError("Config directory could not be found!");
Environment.Exit(1);
}
}
private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) {
if (sender == null || args == null) {
return;
}
Logging.LogGenericException((Exception) args.ExceptionObject);
}
private static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs args) {
if (sender == null || args == null) {
return;
}
Logging.LogGenericException(args.Exception);
}
}
}

View 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("ConfigGenerator")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConfigGenerator")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[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("c3f6fe68-5e75-415e-bea1-1e7c16d6a433")]
// 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")]

View File

@@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ConfigGenerator.Properties {
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if ((resourceMan == null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ConfigGenerator.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ConfigGenerator.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings) (global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,97 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Ł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.
*/
namespace ConfigGenerator {
internal static class Tutorial {
internal enum EPhase : byte {
Unknown,
Start,
Shown,
Help,
HelpFinished,
BotNickname,
BotNicknameFinished,
BotEnabled,
BotReady,
GlobalConfigOpened,
GlobalConfigReady,
}
internal static bool Enabled { get; set; } = true;
private static EPhase NextPhase = EPhase.Start;
internal static void OnAction(EPhase phase) {
if (!Enabled || phase != NextPhase) {
return;
}
switch (phase) {
case EPhase.Unknown:
break;
case EPhase.Start:
Logging.LogGenericInfo("Hello there! I noticed that you're using ASF Config Generator for the first time, so let me help you a bit.");
break;
case EPhase.Shown:
Logging.LogGenericInfo("You can now notice the main ASF Config Generator screen, it's really easy to use!");
Logging.LogGenericInfo("At the top of the window you can notice currently loaded configs, and 3 extra buttons for removing, renaming and adding new ones.");
Logging.LogGenericInfo("In the middle of the window you will be able to configure all config properties that are available for you.");
Logging.LogGenericInfo("In the top right corner you can find help button [?] which will redirect you to ASF wiki where you can find more information.");
Logging.LogGenericInfo("Please click the help button to continue.");
break;
case EPhase.Help:
Logging.LogGenericInfo("That's right! On ASF wiki you can find detailed help about every config property you're going to configure in a moment.");
break;
case EPhase.HelpFinished:
Logging.LogGenericInfo("Alright, let's start configuring our ASF. Click on the plus [+] button to add your first steam account to ASF!");
break;
case EPhase.BotNickname:
Logging.LogGenericInfo("That's right! You'll be asked for your bot name now. A good example would be a nickname that you're using for the steam account you're configuring right now, or any other name of your choice which will be easy for you to connect with bot instance that is being configured.");
break;
case EPhase.BotNicknameFinished:
Logging.LogGenericInfo("As you can see your bot config is now ready to configure!");
Logging.LogGenericInfo("First thing that you want to do is switching \"Enabled\" property from False to True, try it!");
break;
case EPhase.BotEnabled:
Logging.LogGenericInfo("That's right! Now your bot instance is enabled. You need to configure at least 2 more config properties - \"SteamLogin\" and \"SteamPassword\". The tutorial will continue after you're done with it. Remember to visit ASF wiki by clicking the help icon if you're unsure how given property should be configured!");
break;
case EPhase.BotReady:
Logging.LogGenericInfo("If the data you put is proper, then your bot is ready to run! We need to do only one more thing now. Visit global ASF config, which is labelled as \"ASF\" on your config tab.");
break;
case EPhase.GlobalConfigOpened:
Logging.LogGenericInfo("While bot config affects only given bot instance you're configuring, global config affects whole ASF process, including all configured bots.");
Logging.LogGenericInfo("In order to fully configure your ASF, I suggest to fill \"SteamOwnerID\" property. Remember, if you don't know what to put, help button is always there for you!");
break;
case EPhase.GlobalConfigReady:
Logging.LogGenericInfo("Your ASF is now ready! Simply launch ASF process by double-clicking ASF.exe binary and if you did everything properly, you should now notice that ASF logs in on your account and starts farming. If you have SteamGuard or 2FA authorization enabled, ASF will ask you for that once");
Logging.LogGenericInfo("Congratulations! You've done everything that is needed in order to make ASF \"work\". I highly recommend reading the wiki now, as ASF offers some really neat features for you to configure, such as offline farming or deciding upon most efficient cards farming algorithm.");
Logging.LogGenericInfo("If you'd like to add another steam account for farming, simply click the plus [+] button and add another instance. You can also rename bots and remove them with 2 other buttons. Good luck!");
Enabled = false;
break;
}
NextPhase++;
}
}
}

BIN
ConfigGenerator/cirno.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net451" />
</packages>

View File

@@ -1,7 +1,12 @@
ArchiSteamFarm
===================
[![Build status](https://ci.appveyor.com/api/projects/status/yi0y25nipcb1j1yj?svg=true)](https://ci.appveyor.com/project/JustArchi/archisteamfarm) [![GitHub release](https://img.shields.io/github/release/JustArchi/ArchiSteamFarm.svg)](https://github.com/JustArchi/ArchiSteamFarm/releases/latest) [![Github All Releases](https://img.shields.io/github/downloads/JustArchi/ArchiSteamFarm/total.svg)](https://github.com/JustArchi/ArchiSteamFarm/releases) [![Paypal donate](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HD2P2P3WGS5Y4) [![Steam donate](https://img.shields.io/badge/steam-donate-yellow.svg)](https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_)
[![Build Status (Windows)](https://img.shields.io/appveyor/ci/JustArchi/ArchiSteamFarm.svg?label=Windows)](https://ci.appveyor.com/project/JustArchi/ArchiSteamFarm)
[![Build Status (Mono)](https://img.shields.io/travis/JustArchi/ArchiSteamFarm.svg?label=Mono)](https://travis-ci.org/JustArchi/ArchiSteamFarm)
[![GitHub Release](https://img.shields.io/github/release/JustArchi/ArchiSteamFarm.svg?label=Latest)](https://github.com/JustArchi/ArchiSteamFarm/releases/latest)
[![Github All Releases](https://img.shields.io/github/downloads/JustArchi/ArchiSteamFarm/total.svg?label=Downloads)](https://github.com/JustArchi/ArchiSteamFarm/releases)
[![Paypal Donate](https://img.shields.io/badge/Paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HD2P2P3WGS5Y4)
[![Steam Donate](https://img.shields.io/badge/Steam-donate-yellow.svg)](https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_)
---

View File

@@ -33,7 +33,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="8.0.2" targetFramework="net452" />
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net451" />
</packages>

Binary file not shown.

Binary file not shown.

View File

@@ -604,6 +604,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -1058,6 +1064,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeArrayHandling">
<summary>
Specifies how JSON arrays are merged together.
@@ -1075,6 +1087,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.JPropertyDescriptor">
<summary>
Represents a view of a <see cref="T:Newtonsoft.Json.Linq.JProperty"/>.
@@ -3511,9 +3538,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -6646,7 +6673,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="!:DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="!:DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="!:DataContractAttribute"/>.
</summary>
</member>

Binary file not shown.

View File

@@ -627,6 +627,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -1190,6 +1196,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeArrayHandling">
<summary>
Specifies how JSON arrays are merged together.
@@ -1207,6 +1219,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.JRaw">
<summary>
Represents a raw JSON string.
@@ -3605,9 +3632,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -5688,7 +5715,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="T:System.Runtime.Serialization.DataContractAttribute"/>.
</summary>
</member>

Binary file not shown.

View File

@@ -699,6 +699,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -1173,6 +1179,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeArrayHandling">
<summary>
Specifies how JSON arrays are merged together.
@@ -1190,6 +1202,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.JRaw">
<summary>
Represents a raw JSON string.
@@ -3715,9 +3742,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -5896,7 +5923,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="T:System.Runtime.Serialization.DataContractAttribute"/>.
</summary>
</member>

Binary file not shown.

View File

@@ -778,6 +778,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -5094,6 +5100,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.JProperty">
<summary>
Represents a JSON property.
@@ -6670,9 +6682,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -6821,6 +6833,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.MemberSerialization">
<summary>
Specifies the member serialization options for the <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
@@ -6834,7 +6861,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="T:System.Runtime.Serialization.DataContractAttribute"/>.
</summary>
</member>

View File

@@ -610,6 +610,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -4588,6 +4594,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.JToken">
<summary>
Represents an abstract JSON token.
@@ -5961,9 +5973,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -6086,6 +6098,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.MemberSerialization">
<summary>
Specifies the member serialization options for the <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
@@ -6099,7 +6126,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="T:System.Runtime.Serialization.DataContractAttribute"/>.
</summary>
</member>

View File

@@ -650,6 +650,12 @@
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.#ctor(System.Boolean)">
<summary>
Initializes a new instance of the <see cref="T:Newtonsoft.Json.Converters.StringEnumConverter"/> class.
</summary>
<param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
</member>
<member name="M:Newtonsoft.Json.Converters.StringEnumConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)">
<summary>
Writes the JSON representation of the object.
@@ -4858,6 +4864,12 @@
</summary>
<value>The method used when merging JSON arrays.</value>
</member>
<member name="P:Newtonsoft.Json.Linq.JsonMergeSettings.MergeNullValueHandling">
<summary>
Gets or sets how how null value properties are merged.
</summary>
<value>How null value properties are merged.</value>
</member>
<member name="T:Newtonsoft.Json.Linq.JToken">
<summary>
Represents an abstract JSON token.
@@ -6249,9 +6261,9 @@
</member>
<member name="M:Newtonsoft.Json.Linq.JValue.CreateUndefined">
<summary>
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.
Creates a <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.
</summary>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> null value.</returns>
<returns>A <see cref="T:Newtonsoft.Json.Linq.JValue"/> undefined value.</returns>
</member>
<member name="P:Newtonsoft.Json.Linq.JValue.Type">
<summary>
@@ -6383,6 +6395,21 @@
<member name="F:Newtonsoft.Json.Linq.MergeArrayHandling.Merge">
<summary>Merge array items together, matched by index.</summary>
</member>
<member name="T:Newtonsoft.Json.Linq.MergeNullValueHandling">
<summary>
Specifies how null value properties are merged.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Ignore">
<summary>
The content's null value properties will be ignored during merging.
</summary>
</member>
<member name="F:Newtonsoft.Json.Linq.MergeNullValueHandling.Merge">
<summary>
The content's null value properties will be merged.
</summary>
</member>
<member name="T:Newtonsoft.Json.MemberSerialization">
<summary>
Specifies the member serialization options for the <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
@@ -6396,7 +6423,7 @@
</member>
<member name="F:Newtonsoft.Json.MemberSerialization.OptIn">
<summary>
Only members must be marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
Only members marked with <see cref="T:Newtonsoft.Json.JsonPropertyAttribute"/> or <see cref="T:System.Runtime.Serialization.DataMemberAttribute"/> are serialized.
This member serialization mode can also be set by marking the class with <see cref="T:System.Runtime.Serialization.DataContractAttribute"/>.
</summary>
</member>

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tools/ILRepack/ILRepack.exe Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

17
tools/NetHook2/README.md Normal file
View File

@@ -0,0 +1,17 @@
NetHook2
===================
This tool is used for reverse-engineering of Steam client. It's capable of hooking and recording network traffic sent/received by the client. If you're not trying to implement missing SK2 functionality in ASF, then please do not proceed.
1. Launch Steam client
2. Execute ```hook.bat```
3. Reproduce the functionality you're trying to add
4. Execute ```unhook.bat```
5. Use ```NetHookAnalyzer2.exe``` for analyzing recorded log (which can be found in your Steam directory)
- Source of the ```NetHook2.dll``` can be found **[here](https://github.com/SteamRE/SteamKit/tree/master/Resources/NetHook2)**
- Source of the ```NetHookAnalyzer2.exe``` can be found **[here](https://github.com/SteamRE/SteamKit/tree/master/Resources/NetHookAnalyzer2)**
===================
There is absolutely no guarantee that this will even work for you, not to mention the consequences from hooking the external DLL into steam client. You're on your own.