Large refactor to support steam3 appinfo

pull/8/head
azuisleet 14 years ago
parent 9a92d8b203
commit d6850b8f33

@ -16,31 +16,35 @@ namespace DepotDownloader
const string DEFAULT_DIR = "depots"; const string DEFAULT_DIR = "depots";
const int MAX_STORAGE_RETRIES = 500; const int MAX_STORAGE_RETRIES = 500;
static Steam3Session steam3; public static DownloadConfig Config = new DownloadConfig();
static bool CreateDirectories( int depotId, int depotVersion, ref string installDir ) private static Steam3Session steam3;
private static Steam3Session.Credentials steam3Credentials;
static bool CreateDirectories( int depotId, int depotVersion, out string installDir )
{ {
installDir = null;
try try
{ {
if ( installDir == null || installDir == "" ) if (ContentDownloader.Config.InstallDirectory == null || ContentDownloader.Config.InstallDirectory == "")
{ {
Directory.CreateDirectory( DEFAULT_DIR ); Directory.CreateDirectory( DEFAULT_DIR );
string depotPath = Path.Combine( DEFAULT_DIR, depotId.ToString() ); string depotPath = Path.Combine( DEFAULT_DIR, depotId.ToString() );
Directory.CreateDirectory( depotPath ); Directory.CreateDirectory( depotPath );
installDir = Path.Combine( depotPath, depotVersion.ToString() ); installDir = Path.Combine(depotPath, depotVersion.ToString());
Directory.CreateDirectory( installDir ); Directory.CreateDirectory(installDir);
} }
else else
{ {
Directory.CreateDirectory( installDir ); Directory.CreateDirectory(ContentDownloader.Config.InstallDirectory);
string serverFolder = CDRManager.GetDedicatedServerFolder( depotId ); string serverFolder = CDRManager.GetDedicatedServerFolder( depotId );
if ( serverFolder != null && serverFolder != "" ) if ( serverFolder != null && serverFolder != "" )
{ {
installDir = Path.Combine( installDir, serverFolder ); installDir = Path.Combine(ContentDownloader.Config.InstallDirectory, serverFolder);
Directory.CreateDirectory( installDir ); Directory.CreateDirectory(installDir);
} }
} }
} }
@ -109,6 +113,28 @@ namespace DepotDownloader
return false; return false;
} }
static bool TestIsFileIncluded(string filename)
{
if (!Config.UsingFileList)
return true;
foreach (string fileListEntry in Config.FilesToDownload)
{
if (fileListEntry.Equals(filename, StringComparison.OrdinalIgnoreCase))
return true;
}
foreach (Regex rgx in Config.FilesToDownloadRegex)
{
Match m = rgx.Match(filename);
if (m.Success)
return true;
}
return false;
}
static bool AccountHasAccess( int depotId ) static bool AccountHasAccess( int depotId )
{ {
if ( steam3 == null || steam3.Licenses == null ) if ( steam3 == null || steam3.Licenses == null )
@ -116,6 +142,7 @@ namespace DepotDownloader
foreach ( var license in steam3.Licenses ) foreach ( var license in steam3.Licenses )
{ {
// TODO: support PackageInfoRequest/Response, this is a steam2 dependency
if ( CDRManager.SubHasDepot( ( int )license.PackageID, depotId ) ) if ( CDRManager.SubHasDepot( ( int )license.PackageID, depotId ) )
return true; return true;
} }
@ -123,84 +150,223 @@ namespace DepotDownloader
return false; return false;
} }
static bool DepotHasSteam3Manifest( int depotId, int appId, out ulong manifest_id ) static bool AppIsSteam3(int appId)
{ {
if (steam3 == null || steam3.AppInfo == null) if (steam3 == null || steam3.AppInfoOverridesCDR == null)
{ {
manifest_id = 0;
return false; return false;
} }
string appkey = appId.ToString();
string depotkey = depotId.ToString();
foreach (var app in steam3.AppInfo) steam3.RequestAppInfo((uint)appId);
bool app_override;
if(!steam3.AppInfoOverridesCDR.TryGetValue((uint)appId, out app_override))
return false;
return app_override;
}
static KeyValue GetSteam3AppSection(int appId, EAppInfoSection section)
{
if (steam3 == null || steam3.AppInfo == null)
{
return null;
}
SteamApps.AppInfoCallback.AppInfo app;
if (!steam3.AppInfo.TryGetValue((uint)appId, out app))
{ {
KeyValue depots; return null;
if (app.AppID == appId && app.Sections.TryGetValue((int)EAppInfoSection.AppInfoSectionDepots, out depots)) }
{
// check depots for app KeyValue section_kv;
foreach (var depotkv in depots[appkey].Children) if (!app.Sections.TryGetValue((int)section, out section_kv))
{ {
if(depotkv.Name != depotkey) return null;
continue; }
var node = depotkv.Children return section_kv;
.Where(c => c.Name == "manifests").First().Children }
.Where(d => d.Name == "Public").First();
static ulong GetSteam3DepotManifest(int depotId, int appId)
{
if (appId == -1 || !AppIsSteam3(appId))
return 0;
KeyValue depots = GetSteam3AppSection(appId, EAppInfoSection.AppInfoSectionDepots);
KeyValue depotChild = depots[appId.ToString()][depotId.ToString()];
if (depotChild == null)
return 0;
var node = depotChild["manifests"]["Public"];
return UInt64.Parse(node.Value);
}
static string GetAppOrDepotName(int depotId, int appId)
{
if (appId == -1 || !AppIsSteam3(appId))
{
return CDRManager.GetDepotName(depotId);
}
else if (depotId == -1)
{
KeyValue info = GetSteam3AppSection(appId, EAppInfoSection.AppInfoSectionCommon);
if (info == null)
return String.Empty;
return info[appId.ToString()]["name"].AsString();
}
else
{
KeyValue depots = GetSteam3AppSection(appId, EAppInfoSection.AppInfoSectionDepots);
if (depots == null)
return String.Empty;
KeyValue depotChild = depots[appId.ToString()][depotId.ToString()];
if (depotChild == null)
return String.Empty;
return depotChild["name"].AsString();
}
}
public static void InitializeSteam3(string username, string password)
{
steam3 = new Steam3Session(
new SteamUser.LogOnDetails()
{
Username = username,
Password = password,
manifest_id = UInt64.Parse(node.Value);
return true;
}
} }
);
steam3Credentials = steam3.WaitForCredentials();
if (!steam3Credentials.HasSessionToken)
{
Console.WriteLine("Unable to get steam3 credentials.");
return;
} }
}
manifest_id = 0; private static ContentServerClient.Credentials GetSteam2Credentials(uint appId)
return false; {
if (steam3 == null || !steam3Credentials.HasSessionToken)
{
return null;
}
return new ContentServerClient.Credentials()
{
Steam2Ticket = new Steam2Ticket(steam3Credentials.Steam2Ticket),
AppTicket = steam3.AppTickets[appId],
SessionToken = steam3Credentials.SessionToken,
};
} }
public static void Download( int depotId, int appId, int depotVersion, int cellId, string username, string password, bool onlyManifest, bool gameServer, bool exclude, string installDir, string[] fileList ) public static void DownloadApp(int appId)
{ {
if ( !CreateDirectories( depotId, depotVersion, ref installDir ) ) if(steam3 != null)
steam3.RequestAppInfo((uint)appId);
if (!AccountHasAccess(appId))
{ {
Console.WriteLine( "Error: Unable to create install directories!" ); string contentName = GetAppOrDepotName(-1, appId);
Console.WriteLine("App {0} ({1}) is not available from this account.", appId, contentName);
return; return;
} }
ContentServerClient.Credentials credentials = null; List<int> depotIDs = null;
if (username != null) if (AppIsSteam3(appId))
{ {
// ServerCache.BuildAuthServers( username ); depotIDs = new List<int>();
credentials = GetCredentials((uint)depotId, (uint)appId, username, password); KeyValue depots = GetSteam3AppSection(appId, EAppInfoSection.AppInfoSectionDepots);
if (depots != null)
{
depots = depots[appId.ToString()];
foreach (var child in depots.Children)
{
if (child.Children.Count > 0)
{
depotIDs.Add(int.Parse(child.Name));
}
}
}
}
else
{
// steam2 path
depotIDs = CDRManager.GetDepotIDsForApp(appId, Config.DownloadAllPlatforms);
} }
if (!AccountHasAccess(depotId)) if (depotIDs == null || depotIDs.Count == 0)
{
Console.WriteLine("Couldn't find any depots to download for app {0}", appId);
return;
}
foreach (var depot in depotIDs)
{ {
string contentName = CDRManager.GetDepotName(depotId); // Steam2 dependency
int depotVersion = CDRManager.GetLatestDepotVersion(depot, Config.PreferBetaVersions);
if (depotVersion == -1)
{
Console.WriteLine("Error: Unable to find DepotID {0} in the CDR!", depot);
return;
}
DownloadDepot(depot, appId, depotVersion);
}
}
public static void DownloadDepot(int depotId, int appId, int depotVersion)
{
if(steam3 != null && appId > 0)
steam3.RequestAppInfo((uint)appId);
string contentName = GetAppOrDepotName(depotId, appId);
if (!AccountHasAccess(depotId))
{
Console.WriteLine("Depot {0} ({1}) is not available from this account.", depotId, contentName); Console.WriteLine("Depot {0} ({1}) is not available from this account.", depotId, contentName);
if (steam3 != null) return;
steam3.Disconnect(); }
string installDir;
if (!CreateDirectories(depotId, depotVersion, out installDir))
{
Console.WriteLine("Error: Unable to create install directories!");
return; return;
} }
ulong steam3_manifest; Console.WriteLine("Downloading \"{0}\" version {1} ...", contentName, depotVersion);
if ( DepotHasSteam3Manifest( depotId, appId, out steam3_manifest ) )
ulong manifestID = GetSteam3DepotManifest(depotId, appId);
if (manifestID > 0)
{ {
DownloadSteam3( credentials, depotId, depotVersion, cellId, steam3_manifest, installDir ); DownloadSteam3(depotId, depotVersion, manifestID, installDir);
} }
else else
{ {
DownloadSteam2( credentials, depotId, depotVersion, cellId, username, password, onlyManifest, gameServer, exclude, installDir, fileList ); // steam2 path
DownloadSteam2(depotId, depotVersion, installDir);
} }
if ( steam3 != null )
steam3.Disconnect();
} }
private static void DownloadSteam3( ContentServerClient.Credentials credentials, int depotId, int depotVersion, int cellId, ulong depot_manifest, string installDir ) private static void DownloadSteam3( int depotId, int depotVersion, ulong depot_manifest, string installDir )
{ {
steam3.RequestAppTicket((uint)depotId);
steam3.RequestDepotKey((uint)depotId);
Console.Write("Finding content servers..."); Console.Write("Finding content servers...");
List<IPEndPoint> serverList = steam3.steamClient.GetServersOfType(EServerType.ServerTypeCS); List<IPEndPoint> serverList = steam3.steamClient.GetServersOfType(EServerType.ServerTypeCS);
@ -209,7 +375,7 @@ namespace DepotDownloader
foreach(var endpoint in serverList) foreach(var endpoint in serverList)
{ {
cdnServers = CDNClient.FetchServerList(new CDNClient.ClientEndPoint(endpoint.Address.ToString(), endpoint.Port), cellId); cdnServers = CDNClient.FetchServerList(new CDNClient.ClientEndPoint(endpoint.Address.ToString(), endpoint.Port), Config.CellID);
if (cdnServers != null && cdnServers.Count > 0) if (cdnServers != null && cdnServers.Count > 0)
break; break;
@ -217,14 +383,14 @@ namespace DepotDownloader
if (cdnServers == null || cdnServers.Count == 0) if (cdnServers == null || cdnServers.Count == 0)
{ {
Console.WriteLine("Unable to find any steam3 content servers"); Console.WriteLine("Unable to find any Steam3 content servers");
return; return;
} }
Console.WriteLine(" Done!"); Console.WriteLine(" Done!");
Console.Write("Downloading depot manifest..."); Console.Write("Downloading depot manifest...");
CDNClient cdnClient = new CDNClient(cdnServers[0], credentials.AppTicket); CDNClient cdnClient = new CDNClient(cdnServers[0], steam3.AppTickets[(uint)depotId]);
if (!cdnClient.Connect()) if (!cdnClient.Connect())
{ {
@ -241,13 +407,11 @@ namespace DepotDownloader
} }
string manifestFile = Path.Combine(installDir, "manifest.bin"); string manifestFile = Path.Combine(installDir, "manifest.bin");
string keyFile = Path.Combine(installDir, "depotkey.bin");
File.WriteAllBytes(manifestFile, manifest); File.WriteAllBytes(manifestFile, manifest);
File.WriteAllBytes(keyFile, steam3.DepotKey);
DepotManifest depotManifest = new DepotManifest(manifest); DepotManifest depotManifest = new DepotManifest(manifest);
if (!depotManifest.DecryptFilenames(steam3.DepotKey)) if (!depotManifest.DecryptFilenames(steam3.DepotKeys[(uint)depotId]))
{ {
Console.WriteLine("\nUnable to decrypt manifest for depot {0}", depotId); Console.WriteLine("\nUnable to decrypt manifest for depot {0}", depotId);
return; return;
@ -258,6 +422,8 @@ namespace DepotDownloader
ulong complete_download_size = 0; ulong complete_download_size = 0;
ulong size_downloaded = 0; ulong size_downloaded = 0;
depotManifest.Files.Sort((x, y) => { return x.FileName.CompareTo(y.FileName); });
foreach (var file in depotManifest.Files) foreach (var file in depotManifest.Files)
{ {
complete_download_size += file.TotalSize; complete_download_size += file.TotalSize;
@ -276,10 +442,7 @@ namespace DepotDownloader
string dir_path = Path.GetDirectoryName(download_path); string dir_path = Path.GetDirectoryName(download_path);
int top = Console.CursorTop; Console.Write("{0:00.00}% Downloading {1}", ((float)size_downloaded / (float)complete_download_size) * 100.0f, download_path);
Console.WriteLine("00.00% Downloading {0}", download_path);
int top_post = Console.CursorTop;
Console.CursorTop = top;
if (!Directory.Exists(dir_path)) if (!Directory.Exists(dir_path))
Directory.CreateDirectory(dir_path); Directory.CreateDirectory(dir_path);
@ -292,7 +455,7 @@ namespace DepotDownloader
string chunkID = Utils.BinToHex(chunk.ChunkID); string chunkID = Utils.BinToHex(chunk.ChunkID);
byte[] encrypted_chunk = cdnClient.DownloadDepotChunk(depotId, chunkID); byte[] encrypted_chunk = cdnClient.DownloadDepotChunk(depotId, chunkID);
byte[] chunk_data = cdnClient.ProcessChunk(encrypted_chunk, steam3.DepotKey); byte[] chunk_data = cdnClient.ProcessChunk(encrypted_chunk, steam3.DepotKeys[(uint)depotId]);
fs.Seek((long)chunk.Offset, SeekOrigin.Begin); fs.Seek((long)chunk.Offset, SeekOrigin.Begin);
fs.Write(chunk_data, 0, chunk_data.Length); fs.Write(chunk_data, 0, chunk_data.Length);
@ -303,19 +466,18 @@ namespace DepotDownloader
Console.Write("{0:00.00}", ((float)size_downloaded / (float)complete_download_size) * 100.0f); Console.Write("{0:00.00}", ((float)size_downloaded / (float)complete_download_size) * 100.0f);
} }
Console.CursorTop = top_post; Console.WriteLine();
Console.CursorLeft = 0;
} }
} }
private static void DownloadSteam2( ContentServerClient.Credentials credentials, int depotId, int depotVersion, int cellId, string username, string password, bool onlyManifest, bool gameServer, bool exclude, string installDir, string[] fileList ) private static void DownloadSteam2( int depotId, int depotVersion, string installDir )
{ {
Console.Write("Finding content servers..."); Console.Write("Finding content servers...");
IPEndPoint[] contentServers = GetStorageServer(depotId, depotVersion, cellId); IPEndPoint[] contentServers = GetStorageServer(depotId, depotVersion, Config.CellID);
if (contentServers.Length == 0) if (contentServers == null || contentServers.Length == 0)
{ {
Console.WriteLine("\nError: Unable to find any content servers for depot {0}, version {1}", depotId, depotVersion); Console.WriteLine("\nError: Unable to find any Steam2 content servers for depot {0}, version {1}", depotId, depotVersion);
return; return;
} }
@ -335,7 +497,7 @@ namespace DepotDownloader
try try
{ {
csClient.Connect( contentServers[server] ); csClient.Connect( contentServers[server] );
session = csClient.OpenStorage( ( uint )depotId, ( uint )depotVersion, ( uint )cellId, credentials ); session = csClient.OpenStorage( ( uint )depotId, ( uint )depotVersion, ( uint )Config.CellID, GetSteam2Credentials((uint)depotId) );
} }
catch ( Steam2Exception ex ) catch ( Steam2Exception ex )
{ {
@ -367,29 +529,12 @@ namespace DepotDownloader
Console.WriteLine( " Done!" ); Console.WriteLine( " Done!" );
if ( onlyManifest )
File.Delete( txtManifest );
StringBuilder manifestBuilder = new StringBuilder(); StringBuilder manifestBuilder = new StringBuilder();
List<Regex> rgxList = new List<Regex>();
if ( fileList != null )
{
foreach ( string fileListentry in fileList )
{
try
{
Regex rgx = new Regex( fileListentry, RegexOptions.Compiled | RegexOptions.IgnoreCase );
rgxList.Add( rgx );
}
catch { continue; }
}
}
byte[] cryptKey = CDRManager.GetDepotEncryptionKey( depotId, depotVersion ); byte[] cryptKey = CDRManager.GetDepotEncryptionKey( depotId, depotVersion );
string[] excludeList = null; string[] excludeList = null;
if ( gameServer && exclude ) if ( Config.UsingExclusionList )
excludeList = GetExcludeList( session, manifest ); excludeList = GetExcludeList( session, manifest );
for ( int x = 0 ; x < manifest.Nodes.Count ; ++x ) for ( int x = 0 ; x < manifest.Nodes.Count ; ++x )
@ -398,7 +543,7 @@ namespace DepotDownloader
string downloadPath = Path.Combine( installDir, dirEntry.FullName.ToLower() ); string downloadPath = Path.Combine( installDir, dirEntry.FullName.ToLower() );
if ( onlyManifest ) if ( Config.DownloadManifestOnly )
{ {
if ( dirEntry.FileID == -1 ) if ( dirEntry.FileID == -1 )
continue; continue;
@ -407,44 +552,16 @@ namespace DepotDownloader
continue; continue;
} }
if ( gameServer && exclude && IsFileExcluded( dirEntry.FullName, excludeList ) ) if (Config.UsingExclusionList && IsFileExcluded(dirEntry.FullName, excludeList))
continue; continue;
if ( fileList != null ) if (!TestIsFileIncluded(dirEntry.FullName))
{ continue;
bool bMatched = false;
foreach ( string fileListEntry in fileList )
{
if ( fileListEntry.Equals( dirEntry.FullName, StringComparison.OrdinalIgnoreCase ) )
{
bMatched = true;
break;
}
}
if ( !bMatched )
{
foreach ( Regex rgx in rgxList )
{
Match m = rgx.Match( dirEntry.FullName );
if ( m.Success )
{
bMatched = true;
break;
}
}
}
if ( !bMatched )
continue;
string path = Path.GetDirectoryName( downloadPath ); string path = Path.GetDirectoryName(downloadPath);
if ( !Directory.Exists( path ) ) if (!Directory.Exists(path))
Directory.CreateDirectory( path ); Directory.CreateDirectory(path);
}
if ( dirEntry.FileID == -1 ) if ( dirEntry.FileID == -1 )
{ {
@ -470,7 +587,7 @@ namespace DepotDownloader
File.WriteAllBytes( downloadPath, file ); File.WriteAllBytes( downloadPath, file );
} }
if ( onlyManifest ) if ( Config.DownloadManifestOnly )
File.WriteAllText( txtManifest, manifestBuilder.ToString() ); File.WriteAllText( txtManifest, manifestBuilder.ToString() );
} }
@ -478,40 +595,6 @@ namespace DepotDownloader
} }
static ContentServerClient.Credentials GetCredentials( uint depotId, uint appId, string username, string password )
{
steam3 = new Steam3Session(
new SteamUser.LogOnDetails()
{
Username = username,
Password = password,
},
depotId,
appId
);
var steam3Credentials = steam3.WaitForCredentials();
if ( !steam3Credentials.HasSessionToken || steam3Credentials.AppTicket == null || steam3Credentials.Steam2Ticket == null )
{
Console.WriteLine( "Unable to get steam3 credentials." );
return null;
}
Steam2Ticket s2Ticket = new Steam2Ticket( steam3Credentials.Steam2Ticket );
ContentServerClient.Credentials credentials = new ContentServerClient.Credentials()
{
Steam2Ticket = s2Ticket,
AppTicket = steam3Credentials.AppTicket,
SessionToken = steam3Credentials.SessionToken,
};
return credentials;
}
static IPEndPoint[] GetStorageServer( int depotId, int depotVersion, int cellId ) static IPEndPoint[] GetStorageServer( int depotId, int depotVersion, int cellId )
{ {
foreach ( IPEndPoint csdServer in ServerCache.CSDSServers ) foreach ( IPEndPoint csdServer in ServerCache.CSDSServers )
@ -536,30 +619,6 @@ namespace DepotDownloader
return null; return null;
} }
static IPEndPoint GetAnyStorageServer()
{
foreach (IPEndPoint csdServer in ServerCache.CSDSServers)
{
ContentServerDSClient csdsClient = new ContentServerDSClient();
csdsClient.Connect(csdServer);
IPEndPoint[] servers = csdsClient.GetContentServerList();
if (servers == null)
{
Console.WriteLine("Warning: CSDS {0} returned empty server list.", csdServer);
continue;
}
if (servers.Length == 0)
continue;
return servers[PsuedoRandom.GetRandomInt(0, servers.Length - 1)];
}
return null;
}
static IPEndPoint GetAuthServer() static IPEndPoint GetAuthServer()
{ {
if ( ServerCache.AuthServers.Count > 0 ) if ( ServerCache.AuthServers.Count > 0 )

@ -70,6 +70,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="CDRManager.cs" /> <Compile Include="CDRManager.cs" />
<Compile Include="ContentDownloader.cs" /> <Compile Include="ContentDownloader.cs" />
<Compile Include="DownloadConfig.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServerCache.cs" /> <Compile Include="ServerCache.cs" />

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace DepotDownloader
{
class DownloadConfig
{
public int CellID { get; set; }
public bool DownloadAllPlatforms { get; set; }
public bool PreferBetaVersions { get; set; }
public bool DownloadManifestOnly { get; set; }
public string InstallDirectory { get; set; }
public bool UsingFileList { get; set; }
public List<string> FilesToDownload { get; set; }
public List<Regex> FilesToDownloadRegex { get; set; }
public bool UsingExclusionList { get; set; }
}
}

@ -4,6 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using SteamKit2; using SteamKit2;
using System.IO; using System.IO;
using System.Text.RegularExpressions;
namespace DepotDownloader namespace DepotDownloader
{ {
@ -40,41 +41,62 @@ namespace DepotDownloader
return; return;
} }
bool bDebot = true; bool bManifest = false;
bool bGameserver = true; bool bGameserver = true;
bool bApp = true; bool bApp = false;
int appId = -1;
int depotId = -1; int depotId = -1;
string gameName = GetStringParameter( args, "-game" ); string gameName = GetStringParameter( args, "-game" );
if ( gameName == null ) if ( gameName == null )
{ {
depotId = GetIntParameter( args, "-app" ); appId = GetIntParameter( args, "-app" );
bGameserver = false; bGameserver = false;
if ( depotId == -1 )
depotId = GetIntParameter(args, "-depot");
if (depotId == -1)
{ {
depotId = GetIntParameter( args, "-depot" ); depotId = GetIntParameter(args, "-manifest");
bApp = false;
if ( depotId == -1 )
{
depotId = GetIntParameter( args, "-manifest" );
bDebot = false;
if ( depotId == -1 ) if (depotId == -1 && appId == -1)
{ {
Console.WriteLine( "Error: -game, -app, -depot or -manifest not specified!" ); Console.WriteLine("Error: -game, -app, -depot or -manifest not specified!");
return; return;
} }
else if (depotId >= 0)
{
bManifest = true;
}
else if (appId >= 0)
{
bApp = true;
} }
} }
} }
ContentDownloader.Config.DownloadManifestOnly = bManifest;
int cellId = GetIntParameter(args, "-cellid");
if (cellId == -1)
{
cellId = 0;
Console.WriteLine(
"Warning: Using default CellID of 0! This may lead to slow downloads. " +
"You can specify the CellID using the -cellid parameter");
}
ContentDownloader.Config.CellID = cellId;
int depotVersion = GetIntParameter( args, "-version" ); int depotVersion = GetIntParameter( args, "-version" );
bool bBeta = HasParameter( args, "-beta" ); ContentDownloader.Config.PreferBetaVersions = HasParameter( args, "-beta" );
// this is a Steam2 option
if ( !bGameserver && !bApp && depotVersion == -1 ) if ( !bGameserver && !bApp && depotVersion == -1 )
{ {
int latestVer = CDRManager.GetLatestDepotVersion( depotId, bBeta ); int latestVer = CDRManager.GetLatestDepotVersion(depotId, ContentDownloader.Config.PreferBetaVersions);
if ( latestVer == -1 ) if ( latestVer == -1 )
{ {
@ -104,16 +126,6 @@ namespace DepotDownloader
} }
} }
int cellId = GetIntParameter( args, "-cellid" );
if ( cellId == -1 )
{
cellId = 0;
Console.WriteLine(
"Warning: Using default CellID of 0! This may lead to slow downloads. " +
"You can specify the CellID using the -cellid parameter" );
}
string fileList = GetStringParameter( args, "-filelist" ); string fileList = GetStringParameter( args, "-filelist" );
string[] files = null; string[] files = null;
@ -124,6 +136,24 @@ namespace DepotDownloader
string fileListData = File.ReadAllText( fileList ); string fileListData = File.ReadAllText( fileList );
files = fileListData.Split( new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries ); files = fileListData.Split( new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries );
ContentDownloader.Config.UsingFileList = true;
ContentDownloader.Config.FilesToDownload = new List<string>();
ContentDownloader.Config.FilesToDownloadRegex = new List<Regex>();
foreach (var fileEntry in files)
{
try
{
Regex rgx = new Regex(fileEntry, RegexOptions.Compiled | RegexOptions.IgnoreCase);
ContentDownloader.Config.FilesToDownloadRegex.Add(rgx);
}
catch
{
ContentDownloader.Config.FilesToDownload.Add(fileEntry);
continue;
}
}
Console.WriteLine( "Using filelist: '{0}'.", fileList ); Console.WriteLine( "Using filelist: '{0}'.", fileList );
} }
catch ( Exception ex ) catch ( Exception ex )
@ -132,50 +162,51 @@ namespace DepotDownloader
} }
} }
string username = GetStringParameter( args, "-username" ); string username = GetStringParameter(args, "-username");
string password = GetStringParameter( args, "-password" ); string password = GetStringParameter(args, "-password");
string installDir = GetStringParameter( args, "-dir" ); ContentDownloader.Config.InstallDirectory = GetStringParameter(args, "-dir");
bool bNoExclude = HasParameter( args, "-no-exclude" ); bool bNoExclude = HasParameter(args, "-no-exclude");
bool bAllPlatforms = HasParameter( args, "-all-platforms" ); ContentDownloader.Config.DownloadAllPlatforms = HasParameter(args, "-all-platforms");
if (username != null && password == null) if (username != null && password == null)
{ {
Console.Write( "Enter account password: " ); Console.Write("Enter account password: ");
password = Util.ReadPassword(); password = Util.ReadPassword();
Console.WriteLine(); Console.WriteLine();
} }
if ( !bGameserver && !bApp ) if (username != null)
{
ContentDownloader.InitializeSteam3(username, password);
}
if (bApp)
{
ContentDownloader.DownloadApp(appId);
}
else if ( !bGameserver )
{ {
ContentDownloader.Download( depotId, depotId, depotVersion, cellId, username, password, !bDebot, false, false, installDir, files ); ContentDownloader.DownloadDepot(depotId, appId, depotVersion);
} }
else else
{ {
List<int> depotIDs; if (!bNoExclude)
{
ContentDownloader.Config.UsingExclusionList = true;
}
if ( bGameserver ) List<int> depotIDs = CDRManager.GetDepotIDsForGameserver( gameName, ContentDownloader.Config.DownloadAllPlatforms );
depotIDs = CDRManager.GetDepotIDsForGameserver( gameName, bAllPlatforms );
else
depotIDs = CDRManager.GetDepotIDsForApp( depotId, bAllPlatforms );
foreach ( int currentDepotId in depotIDs ) foreach ( int currentDepotId in depotIDs )
{ {
depotVersion = CDRManager.GetLatestDepotVersion( currentDepotId, bBeta ); depotVersion = CDRManager.GetLatestDepotVersion(currentDepotId, ContentDownloader.Config.PreferBetaVersions);
if ( depotVersion == -1 ) if ( depotVersion == -1 )
{ {
Console.WriteLine( "Error: Unable to find DepotID {0} in the CDR!", currentDepotId ); Console.WriteLine( "Error: Unable to find DepotID {0} in the CDR!", currentDepotId );
return; return;
} }
string depotName = CDRManager.GetDepotName( currentDepotId ); ContentDownloader.DownloadDepot(currentDepotId, -1, depotVersion);
Console.WriteLine( "Downloading \"{0}\" version {1} ...", depotName, depotVersion );
int sourceId = depotId;
if (bGameserver)
sourceId = currentDepotId;
ContentDownloader.Download( currentDepotId, sourceId, depotVersion, cellId, username, password, false, bGameserver, !bNoExclude, installDir, files );
} }
} }
} }

@ -15,9 +15,6 @@ namespace DepotDownloader
{ {
public bool HasSessionToken { get; set; } public bool HasSessionToken { get; set; }
public ulong SessionToken { get; set; } public ulong SessionToken { get; set; }
public byte[] AppTicket { get; set; }
public byte[] Steam2Ticket { get; set; } public byte[] Steam2Ticket { get; set; }
} }
@ -27,25 +24,21 @@ namespace DepotDownloader
private set; private set;
} }
public byte[] DepotKey { get; private set; } public Dictionary<uint, byte[]> AppTickets { get; private set; }
public Dictionary<uint, byte[]> DepotKeys { get; private set; }
public ReadOnlyCollection<SteamApps.AppInfoCallback.AppInfo> AppInfo { get; private set; } public Dictionary<uint, SteamApps.AppInfoCallback.AppInfo> AppInfo { get; private set; }
public Dictionary<uint, bool> AppInfoOverridesCDR { get; private set; }
public SteamClient steamClient; public SteamClient steamClient;
SteamUser steamUser; SteamUser steamUser;
SteamApps steamApps; SteamApps steamApps;
Thread callbackThread;
ManualResetEvent credentialHandle;
bool bConnected; bool bConnected;
bool bKeyResponse; bool bAborted;
DateTime connectTime; DateTime connectTime;
// input // input
uint depotId;
uint appId; // base
SteamUser.LogOnDetails logonDetails; SteamUser.LogOnDetails logonDetails;
// output // output
@ -54,25 +47,24 @@ namespace DepotDownloader
static readonly TimeSpan STEAM3_TIMEOUT = TimeSpan.FromSeconds( 30 ); static readonly TimeSpan STEAM3_TIMEOUT = TimeSpan.FromSeconds( 30 );
public Steam3Session( SteamUser.LogOnDetails details, uint depotId, uint appId ) public Steam3Session( SteamUser.LogOnDetails details )
{ {
this.depotId = depotId;
this.appId = appId;
this.logonDetails = details; this.logonDetails = details;
this.credentials = new Credentials(); this.credentials = new Credentials();
this.credentialHandle = new ManualResetEvent( false );
this.bConnected = false; this.bConnected = false;
this.bKeyResponse = false; this.bAborted = false;
this.AppTickets = new Dictionary<uint, byte[]>();
this.DepotKeys = new Dictionary<uint, byte[]>();
this.AppInfo = new Dictionary<uint, SteamApps.AppInfoCallback.AppInfo>();
this.AppInfoOverridesCDR = new Dictionary<uint, bool>();
this.steamClient = new SteamClient(); this.steamClient = new SteamClient();
this.steamUser = this.steamClient.GetHandler<SteamUser>(); this.steamUser = this.steamClient.GetHandler<SteamUser>();
this.steamApps = this.steamClient.GetHandler<SteamApps>(); this.steamApps = this.steamClient.GetHandler<SteamApps>();
this.callbackThread = new Thread( HandleCallbacks );
this.callbackThread.Start();
Console.Write( "Connecting to Steam3..." ); Console.Write( "Connecting to Steam3..." );
Connect(); Connect();
@ -80,20 +72,74 @@ namespace DepotDownloader
public Credentials WaitForCredentials() public Credentials WaitForCredentials()
{ {
this.credentialHandle.WaitOne(); do
{
HandleCallbacks();
}
while (!bAborted && (credentials.SessionToken == 0 || credentials.Steam2Ticket == null));
return credentials; return credentials;
} }
public void RequestAppInfo(uint appId)
{
if (bAborted || AppInfo.ContainsKey(appId))
return;
steamApps.GetAppInfo(appId);
do
{
HandleCallbacks();
}
while (!bAborted && !AppInfo.ContainsKey(appId));
}
public void RequestAppTicket(uint appId)
{
if (bAborted || AppTickets.ContainsKey(appId))
return;
steamApps.GetAppOwnershipTicket(appId);
do
{
HandleCallbacks();
}
while (!bAborted && !AppTickets.ContainsKey(appId));
}
public void RequestDepotKey(uint depotId)
{
if (bAborted || DepotKeys.ContainsKey(depotId))
return;
steamApps.GetDepotDecryptionKey(depotId);
do
{
HandleCallbacks();
}
while (!bAborted && !DepotKeys.ContainsKey(depotId));
}
void Connect() void Connect()
{ {
this.connectTime = DateTime.Now; this.connectTime = DateTime.Now;
this.steamClient.Connect(); this.steamClient.Connect();
} }
private void Abort()
{
bAborted = true;
Disconnect();
}
public void Disconnect() public void Disconnect()
{ {
steamUser.LogOff();
steamClient.Disconnect(); steamClient.Disconnect();
bConnected = false;
} }
void HandleCallbacks() void HandleCallbacks()
@ -104,14 +150,14 @@ namespace DepotDownloader
TimeSpan diff = DateTime.Now - connectTime; TimeSpan diff = DateTime.Now - connectTime;
if ( diff > STEAM3_TIMEOUT && !bConnected ) if (diff > STEAM3_TIMEOUT && !bConnected)
break; {
Abort();
if ( credentials.HasSessionToken && credentials.AppTicket != null && Licenses != null && credentials.Steam2Ticket != null && AppInfo != null && bKeyResponse )
break; break;
}
if ( callback == null ) if ( callback == null )
continue; break;
if ( callback.IsType<SteamClient.ConnectCallback>() ) if ( callback.IsType<SteamClient.ConnectCallback>() )
{ {
@ -121,8 +167,7 @@ namespace DepotDownloader
Console.Write( "Logging '{0}' into Steam3...", logonDetails.Username ); Console.Write( "Logging '{0}' into Steam3...", logonDetails.Username );
} }
else if ( callback.IsType<SteamUser.LogOnCallback>() )
if ( callback.IsType<SteamUser.LogOnCallback>() )
{ {
var msg = callback as SteamUser.LogOnCallback; var msg = callback as SteamUser.LogOnCallback;
@ -140,7 +185,7 @@ namespace DepotDownloader
else if ( msg.Result != EResult.OK ) else if ( msg.Result != EResult.OK )
{ {
Console.WriteLine( "Unable to login to Steam3: {0}", msg.Result ); Console.WriteLine( "Unable to login to Steam3: {0}", msg.Result );
steamUser.LogOff(); Abort();
break; break;
} }
@ -148,32 +193,23 @@ namespace DepotDownloader
Console.WriteLine( "Got Steam2 Ticket!" ); Console.WriteLine( "Got Steam2 Ticket!" );
credentials.Steam2Ticket = msg.Steam2Ticket; credentials.Steam2Ticket = msg.Steam2Ticket;
steamApps.GetAppInfo( appId );
steamApps.GetAppOwnershipTicket( depotId );
steamApps.GetDepotDecryptionKey( depotId );
} }
else if (callback.IsType<SteamApps.AppOwnershipTicketCallback>())
if ( callback.IsType<SteamApps.AppOwnershipTicketCallback>() )
{ {
var msg = callback as SteamApps.AppOwnershipTicketCallback; var msg = callback as SteamApps.AppOwnershipTicketCallback;
if ( msg.AppID != depotId )
continue;
if ( msg.Result != EResult.OK ) if ( msg.Result != EResult.OK )
{ {
Console.WriteLine( "Unable to get appticket for {0}: {1}", depotId, msg.Result ); Console.WriteLine( "Unable to get appticket for {0}: {1}", msg.AppID, msg.Result );
steamUser.LogOff(); Abort();
break; break;
} }
Console.WriteLine( "Got appticket for {0}!", depotId ); Console.WriteLine( "Got appticket for {0}!", msg.AppID );
credentials.AppTicket = msg.Ticket; AppTickets[msg.AppID] = msg.Ticket;
} }
else if (callback.IsType<SteamUser.SessionTokenCallback>())
if ( callback.IsType<SteamUser.SessionTokenCallback>() )
{ {
var msg = callback as SteamUser.SessionTokenCallback; var msg = callback as SteamUser.SessionTokenCallback;
@ -181,50 +217,47 @@ namespace DepotDownloader
credentials.SessionToken = msg.SessionToken; credentials.SessionToken = msg.SessionToken;
credentials.HasSessionToken = true; credentials.HasSessionToken = true;
} }
else if (callback.IsType<SteamApps.LicenseListCallback>())
if ( callback.IsType<SteamApps.LicenseListCallback>() )
{ {
var msg = callback as SteamApps.LicenseListCallback; var msg = callback as SteamApps.LicenseListCallback;
if ( msg.Result != EResult.OK ) if ( msg.Result != EResult.OK )
{ {
Console.WriteLine( "Unable to get license list: {0} ", msg.Result ); Console.WriteLine( "Unable to get license list: {0} ", msg.Result );
steamUser.LogOff(); Abort();
break; break;
} }
Console.WriteLine( "Got {0} licenses for account!", msg.LicenseList.Count ); Console.WriteLine( "Got {0} licenses for account!", msg.LicenseList.Count );
Licenses = msg.LicenseList; Licenses = msg.LicenseList;
} }
else if (callback.IsType<SteamApps.AppInfoCallback>())
if ( callback.IsType<SteamApps.AppInfoCallback>() )
{ {
var msg = callback as SteamApps.AppInfoCallback; var msg = callback as SteamApps.AppInfoCallback;
if (msg.AppsPending > 0 || msg.Apps.Count == 0 || msg.Apps[0].Status == SteamApps.AppInfoCallback.AppInfo.AppInfoStatus.Unknown) foreach (var app in msg.Apps)
{ {
Console.WriteLine("AppInfo did not contain the requested app id {0}", depotId); Console.WriteLine("Got AppInfo for {0}: {1}", app.AppID, app.Status);
steamUser.LogOff(); AppInfo.Add(app.AppID, app);
break;
KeyValue depots;
if (app.Sections.TryGetValue((int)EAppInfoSection.AppInfoSectionDepots, out depots))
{
if (depots[app.AppID.ToString()]["OverridesCDDB"].AsBoolean(false))
{
AppInfoOverridesCDR[app.AppID] = true;
}
}
} }
Console.WriteLine("Got AppInfo for {0}", msg.Apps[0].AppID);
AppInfo = msg.Apps;
} }
else if (callback.IsType<SteamApps.DepotKeyCallback>())
if (callback.IsType<SteamApps.DepotKeyCallback>())
{ {
var msg = callback as SteamApps.DepotKeyCallback; var msg = callback as SteamApps.DepotKeyCallback;
DepotKey = msg.DepotKey;
Console.WriteLine("Got depot key for {0} result: {1}", msg.DepotID, msg.Result); Console.WriteLine("Got depot key for {0} result: {1}", msg.DepotID, msg.Result);
bKeyResponse = true; DepotKeys[msg.DepotID] = msg.DepotKey;
} }
} }
credentialHandle.Set();
} }
} }

Loading…
Cancel
Save