DepotDownloader: Removed Steam2 functionality.

pull/8/head
Nicholas Hastings 13 years ago
parent d531a7decc
commit 1a89871744

@ -1,454 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using SteamKit2;
using SteamKit2.Blob;
using ProtoBuf;
using System.IO.Compression;
// TODO: make these properties tofix this
#pragma warning disable 649
namespace DepotDownloader
{
[ProtoContract]
class CDR
{
[BlobField(1)]
[ProtoMember(1)]
public List<App> Apps;
[BlobField(2)]
[ProtoMember(2)]
public List<Sub> Subs;
}
[ProtoContract]
class App
{
[BlobField(2)]
[ProtoMember(1)]
public string Name;
[BlobField(1)]
[ProtoMember(2)]
public int AppID;
[BlobField(11)]
[ProtoMember(3)]
public int CurrentVersion;
[BlobField(10)]
[ProtoMember(4)]
public List<AppVersion> Versions;
[BlobField(12)]
[ProtoMember(5)]
public List<FileSystem> FileSystems;
[BlobField(14)]
[ProtoMember(6)]
public Dictionary<string, string> UserDefined;
[BlobField(16)]
[ProtoMember(7)]
public int BetaVersion;
}
[ProtoContract]
class Sub
{
[BlobField(1)]
[ProtoMember(1)]
public int SubID;
[BlobField(6)]
[ProtoMember(2)]
public List<int> AppIDs;
}
[ProtoContract]
class AppVersion
{
[BlobField(2)]
[ProtoMember(1)]
public uint VersionID;
[BlobField(5)]
[ProtoMember(2)]
public string DepotEncryptionKey;
[BlobField(6)]
[ProtoMember(3)]
public bool IsEncryptionKeyAvailable;
}
[ProtoContract]
class FileSystem
{
[BlobField(1)]
[ProtoMember(1)]
public int AppID;
[BlobField(2)]
[ProtoMember(2)]
public string Name;
[BlobField(4)]
[ProtoMember(3)]
public string Platform;
}
static class CDRManager
{
const string CDR_FILENAME = "cdr.proto";
static CDR cdrObj;
public static void Update()
{
Console.Write( "Updating CDR..." );
var hasCachedCDR = File.Exists(CDR_FILENAME);
if (DateTime.Now > ConfigCache.Instance.CDRCacheTime || !hasCachedCDR)
{
byte[] cdrHash = hasCachedCDR ? ConfigCache.Instance.CDRHash : null;
foreach (var configServer in ServerCache.ConfigServers)
{
try
{
ConfigServerClient csClient = new ConfigServerClient();
csClient.Connect(configServer);
byte[] tempCdr = csClient.GetContentDescriptionRecord(cdrHash);
if (tempCdr == null)
continue;
if (tempCdr.Length == 0)
break;
using (MemoryStream ms = new MemoryStream(tempCdr))
using (BlobReader reader = BlobReader.CreateFrom(ms))
cdrObj = (CDR)BlobTypedReader.Deserialize(reader, typeof(CDR));
using (FileStream fs = File.Open(CDR_FILENAME, FileMode.Create))
using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress))
ProtoBuf.Serializer.Serialize<CDR>(ds, cdrObj);
ConfigCache.Instance.CDRHash = SHAHash(tempCdr);
ConfigCache.Instance.CDRCacheTime = DateTime.Now.AddMinutes(30);
ConfigCache.Instance.Save(ConfigCache.CONFIG_FILENAME);
break;
}
catch (Exception e)
{
Console.WriteLine("Warning: Unable to download CDR from config server {0}: {1}", configServer, e.Message);
}
}
if(cdrObj != null)
{
Console.WriteLine(" Done!");
return;
}
else if (!File.Exists(CDR_FILENAME))
{
Console.WriteLine("Error: Unable to download CDR!");
return;
}
}
using (FileStream fs = File.Open(CDR_FILENAME, FileMode.Open))
using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Decompress))
cdrObj = ProtoBuf.Serializer.Deserialize<CDR>(ds);
Console.WriteLine(" Done!");
}
static App GetAppBlob( int appID )
{
return cdrObj.Apps.Find( app => app.AppID == appID );
}
static Sub GetSubBlob( int subID )
{
return cdrObj.Subs.Find( sub => sub.SubID == subID );
}
public static string GetDepotName( int depotId )
{
// Match hardcoded names from hldsupdatetool for certain HL1 depots
if ( depotId == 1 )
return "Half-Life Base Content";
else if ( depotId == 4 )
return "Linux Server Engine";
else if ( depotId == 5 )
return "Win32 Server Engine";
App app = GetAppBlob( depotId );
if ( app == null )
{
return null;
}
return app.Name;
}
public static int GetLatestDepotVersion( int depotId, bool beta )
{
App app = GetAppBlob( depotId );
if ( app == null )
{
return -1;
}
if ( beta && app.BetaVersion > app.CurrentVersion )
return app.BetaVersion;
return app.CurrentVersion;
}
public static byte[] GetDepotEncryptionKey( int depotId, int version )
{
App app = GetAppBlob( depotId );
if ( app == null )
{
return null;
}
foreach ( AppVersion ver in app.Versions )
{
if ( ver.VersionID == version )
{
if ( ver.IsEncryptionKeyAvailable )
return DecodeHexString( ver.DepotEncryptionKey );
break;
}
}
return null;
}
static byte[] DecodeHexString( string hex )
{
if ( hex == null )
return null;
int chars = hex.Length;
byte[] bytes = new byte[ chars / 2 ];
for ( int i = 0 ; i < chars ; i += 2 )
bytes[ i / 2 ] = Convert.ToByte( hex.Substring( i, 2 ), 16 );
return bytes;
}
public static List<int> GetDepotIDsForApp( int appId, bool allPlatforms )
{
List<int> depotIDs = new List<int>();
App appInfoBlob = GetAppBlob( appId );
if ( appInfoBlob == null )
{
return null;
}
PlatformID platform = Environment.OSVersion.Platform;
string platformStr = "";
if ( platform == PlatformID.Win32NT )
platformStr = "windows";
else if ( Util.IsMacOSX() )
platformStr = "macos";
if (appInfoBlob.FileSystems == null)
return depotIDs;
foreach ( var blobField in appInfoBlob.FileSystems )
{
string depotPlatform = blobField.Platform;
if ( depotPlatform == null ||
depotPlatform.Contains( platformStr ) ||
allPlatforms )
{
depotIDs.Add( blobField.AppID );
}
}
return depotIDs;
}
public static List<int> GetDepotIDsForGameserver( string gameName, bool allPlatforms )
{
List<int> appIDs = new List<int>();
App serverAppInfoBlob = GetAppBlob( 4 );
PlatformID platform = Environment.OSVersion.Platform;
bool goldSrc = false;
if ( gameName.Equals( "valve", StringComparison.OrdinalIgnoreCase ) )
goldSrc = true;
else
{
string platformSuffix = "";
int gameLen = gameName.Length;
if (platform == PlatformID.Win32NT)
platformSuffix = "-win32";
else if (platform == PlatformID.Unix && !Util.IsMacOSX())
platformSuffix = "-linux";
foreach (var blobField in serverAppInfoBlob.FileSystems)
{
string mountName = blobField.Name;
if (String.Compare(mountName, 0, gameName, 0, gameLen, true) == 0)
{
string suffix = mountName.Substring(gameLen);
if (suffix == "" ||
suffix == platformSuffix ||
allPlatforms && (suffix == "-win32" || suffix == "-linux"))
{
if ( blobField.AppID < 200 )
goldSrc = true;
appIDs.Add( blobField.AppID );
}
}
}
}
// For HL1 server installs, this is hardcoded in hldsupdatetool
if ( goldSrc )
{
// Win32 or Linux Server Engine
if ( allPlatforms )
{
appIDs.Add( 4 );
appIDs.Add( 5 );
}
else if ( platform == PlatformID.Win32NT )
appIDs.Add( 5 );
else if ( platform == PlatformID.Unix && !Util.IsMacOSX() )
appIDs.Add( 4 );
// Half-Life Base Content
appIDs.Add( 1 );
}
return appIDs;
}
public static string GetDedicatedServerFolder( int depotId )
{
App app = GetAppBlob( depotId );
if (app == null || app.UserDefined == null )
return null;
foreach ( var entry in app.UserDefined )
{
if ( entry.Key.Equals( "dedicatedserverfolder", StringComparison.OrdinalIgnoreCase ) )
{
return entry.Value;
}
}
return null;
}
public static void ListGameServers()
{
App serverAppInfoBlob = GetAppBlob( 4 );
List<string> sourceGames = new List<string>();
List<string> hl1Games = new List<string>();
List<string> thirdPartyGames = new List<string>();
// Hardcoded in hldsupdatetool
hl1Games.Add( "valve" );
foreach ( var blobField in serverAppInfoBlob.FileSystems )
{
int id = blobField.AppID;
string name = blobField.Name;
int suffixPos = name.LastIndexOf( "-win32" );
if ( suffixPos == -1 )
suffixPos = name.LastIndexOf( "-linux" );
if ( suffixPos > 0 )
name = name.Remove( suffixPos );
// These numbers come from hldsupdatetool
if ( id < 1000 )
{
if ( id < 200 )
{
if ( !hl1Games.Contains( name ) )
hl1Games.Add( name );
}
else
{
if ( !sourceGames.Contains( name ) )
sourceGames.Add( name );
}
}
else
{
if ( !thirdPartyGames.Contains( name ) )
thirdPartyGames.Add( name );
}
}
sourceGames.Sort( StringComparer.Ordinal );
hl1Games.Sort( StringComparer.Ordinal );
thirdPartyGames.Sort( StringComparer.Ordinal );
Console.WriteLine( "** 'game' options for Source DS install:\n" );
foreach ( string game in sourceGames )
Console.WriteLine( "\t\"{0}\"", game );
Console.WriteLine( "\n** 'game' options for HL1 DS install:\n");
foreach ( string game in hl1Games )
Console.WriteLine( "\t\"{0}\"", game );
Console.WriteLine( "\n** 'game' options for Third-Party game servers:\n" );
foreach ( string game in thirdPartyGames )
Console.WriteLine( "\t\"{0}\"", game );
}
public static bool SubHasDepot( int subId, int depotId )
{
Sub sub = GetSubBlob( subId );
if ( sub == null )
return false;
return sub.AppIDs.Contains( depotId );
}
static byte[] SHAHash( byte[] data )
{
using ( SHA1Managed sha = new SHA1Managed() )
{
byte[] output = sha.ComputeHash( data );
return output;
}
}
}
}

@ -1,103 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProtoBuf;
using System.IO;
using System.IO.Compression;
using System.Net;
namespace DepotDownloader
{
[ProtoContract]
class ConfigCache
{
public const string CONFIG_FILENAME = "config.proto";
public static ConfigCache Instance = Load(CONFIG_FILENAME);
[ProtoContract]
class IPEndpointSurrogate
{
[ProtoMember(1)]
private byte[] address;
[ProtoMember(2)]
private int port;
public IPEndpointSurrogate()
{
}
public IPEndpointSurrogate(byte[] address, int port)
{
this.address = address;
this.port = port;
}
public static implicit operator IPEndPoint(IPEndpointSurrogate ip)
{
if (ip == null || ip.address == null)
return null;
return new IPEndPoint(new IPAddress(ip.address), ip.port);
}
public static implicit operator IPEndpointSurrogate(IPEndPoint ip)
{
if (ip == null)
return null;
return new IPEndpointSurrogate(ip.Address.GetAddressBytes(), ip.Port);
}
}
[ProtoMember(1)]
public byte[] CDRHash { get; set; }
[ProtoMember(2)]
public DateTime CDRCacheTime { get; set; }
[ProtoMember(3)]
public ServerList ConfigServers { get; set; }
[ProtoMember(4)]
public ServerList CSDSServers { get; set; }
[ProtoMember(5)]
public DateTime ServerCacheTime { get; set; }
public static ConfigCache Load(string filename)
{
ProtoBuf.Meta.RuntimeTypeModel.Default.Add(typeof(IPEndPoint), true).SetSurrogate(typeof(IPEndpointSurrogate));
if(!File.Exists(filename))
return new ConfigCache();
try
{
using (FileStream fs = File.Open(filename, FileMode.Open))
using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Decompress))
return ProtoBuf.Serializer.Deserialize<ConfigCache>(ds);
}
catch (IOException)
{
File.Delete(filename);
}
catch (Exception e)
{
Console.WriteLine("Unable to load config cache: {0}", e.Message);
}
return new ConfigCache();
}
public void Save(string filename)
{
try
{
using (FileStream fs = File.Open(filename, FileMode.Create))
using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress))
ProtoBuf.Serializer.Serialize<ConfigCache>(ds, this);
}
catch (IOException)
{
}
}
}
}

@ -24,45 +24,16 @@ namespace DepotDownloader
private static Steam3Session steam3;
private static Steam3Session.Credentials steam3Credentials;
private static IPEndPoint lastSteam2ContentServer;
private abstract class IDepotDownloadInfo
{
public int id { get; protected set; }
public string installDir { get; protected set; }
public string contentName { get; protected set; }
public abstract DownloadSource GetDownloadType();
}
private sealed class DepotDownloadInfo2 : IDepotDownloadInfo
private sealed class DepotDownloadInfo
{
public int version { get; private set; }
public IPEndPoint[] contentServers = null;
public Steam2Manifest manifest = null;
public List<int> NodesToDownload = new List<int>();
public byte[] cryptKey = null;
public override DownloadSource GetDownloadType() { return DownloadSource.Steam2; }
public DepotDownloadInfo2(int id, int version, string installDir, string contentName)
{
this.id = id;
this.version = version;
this.installDir = installDir;
this.contentName = contentName;
}
}
public int id { get; private set; }
public string installDir { get; private set; }
public string contentName { get; private set; }
private sealed class DepotDownloadInfo3 : IDepotDownloadInfo
{
public ulong manifestId { get; private set; }
public byte[] depotKey;
public override DownloadSource GetDownloadType() { return DownloadSource.Steam3; }
public DepotDownloadInfo3(int depotid, ulong manifestId, string installDir, string contentName)
public DepotDownloadInfo(int depotid, ulong manifestId, string installDir, string contentName)
{
this.id = depotid;
this.manifestId = manifestId;
@ -71,7 +42,7 @@ namespace DepotDownloader
}
}
static bool CreateDirectories( int depotId, uint depotVersion, DownloadSource source, out string installDir )
static bool CreateDirectories( int depotId, uint depotVersion, out string installDir )
{
installDir = null;
try
@ -91,16 +62,6 @@ namespace DepotDownloader
Directory.CreateDirectory(ContentDownloader.Config.InstallDirectory);
installDir = ContentDownloader.Config.InstallDirectory;
if (source == DownloadSource.Steam2)
{
string serverFolder = CDRManager.GetDedicatedServerFolder(depotId);
if (serverFolder != null && serverFolder != "")
{
installDir = Path.Combine(ContentDownloader.Config.InstallDirectory, serverFolder);
Directory.CreateDirectory(installDir);
}
}
}
}
catch
@ -111,63 +72,6 @@ namespace DepotDownloader
return true;
}
static string[] GetExcludeList( ContentServerClient.StorageSession session, Steam2Manifest manifest )
{
string[] excludeList = null;
for ( int x = 0 ; x < manifest.Nodes.Count ; ++x )
{
var dirEntry = manifest.Nodes[ x ];
if ( dirEntry.Name == "exclude.lst" &&
dirEntry.FullName.StartsWith( "reslists" + Path.DirectorySeparatorChar ) &&
( dirEntry.Attributes & Steam2Manifest.Node.Attribs.EncryptedFile ) == 0 )
{
string excludeFile = Encoding.UTF8.GetString( session.DownloadFile( dirEntry ) );
if ( Environment.OSVersion.Platform == PlatformID.Win32NT )
excludeFile = excludeFile.Replace( '/', Path.DirectorySeparatorChar );
else
excludeFile = excludeFile.Replace( '\\', Path.DirectorySeparatorChar );
excludeList = excludeFile.Split( new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries );
break;
}
}
return excludeList;
}
static bool IsFileExcluded( string file, string[] excludeList )
{
if ( excludeList == null || file.Length < 1 )
return false;
foreach ( string e in excludeList )
{
int wildPos = e.IndexOf( "*" );
if ( wildPos == -1 )
{
if ( file.StartsWith( e ) )
return true;
continue;
}
if ( wildPos == 0 )
{
if ( e.Length == 1 || file.EndsWith( e.Substring( 1 ) ) )
return true;
continue;
}
string start = e.Substring( 0, wildPos );
string end = e.Substring( wildPos + 1, e.Length - wildPos - 1 );
if ( file.StartsWith( start ) && file.EndsWith( end ) )
return true;
}
return false;
}
static bool TestIsFileIncluded(string filename)
{
if (!Config.UsingFileList)
@ -193,7 +97,7 @@ namespace DepotDownloader
static bool AccountHasAccess( int depotId, bool appId=false )
{
if ( steam3 == null || (steam3.Licenses == null && steam3.steamUser.SteamID.AccountType != EAccountType.AnonUser) )
return CDRManager.SubHasDepot( 0, depotId );
return false;
IEnumerable<uint> licenseQuery;
if ( steam3.steamUser.SteamID.AccountType == EAccountType.AnonUser )
@ -221,47 +125,11 @@ namespace DepotDownloader
return true;
}
}
if ( CDRManager.SubHasDepot( ( int )license, depotId ) )
return true;
}
return false;
}
static bool AppIsSteam3(int appId)
{
if (steam3 == null || steam3.AppInfoOverridesCDR == null)
{
return false;
}
steam3.RequestAppInfo((uint)appId);
bool app_override;
if(!steam3.AppInfoOverridesCDR.TryGetValue((uint)appId, out app_override))
return false;
KeyValue depots = GetSteam3AppSection(appId, EAppInfoSection.Depots);
foreach (KeyValue depotChild in depots.Children)
{
if (depotChild == null)
return false;
int id;
if (!int.TryParse(depotChild.Name, out id))
continue;
var nodes = depotChild["manifests"].Children;
var nodes_encrypted = depotChild["encryptedmanifests"].Children;
if (nodes.Count == 0 && nodes_encrypted.Count == 0)
return false;
}
return true;
}
internal static KeyValue GetSteam3AppSection( int appId, EAppInfoSection section )
{
if (steam3 == null || steam3.AppInfo == null)
@ -300,30 +168,6 @@ namespace DepotDownloader
return section_kv;
}
enum DownloadSource
{
Steam2,
Steam3
}
static DownloadSource GetAppDownloadSource(int appId)
{
if (appId == -1 || !AppIsSteam3(appId))
return DownloadSource.Steam2;
KeyValue config = GetSteam3AppSection(appId, EAppInfoSection.Config);
int contenttype = config["contenttype"].AsInteger(0);
// EContentDownloadSourceType?
if (contenttype != 3)
{
Console.WriteLine("Warning: App {0} does not advertise contenttype as steam3, but has steam3 depots", appId);
}
return DownloadSource.Steam3;
}
static uint GetSteam3AppChangeNumber(int appId)
{
if (steam3 == null || steam3.AppInfo == null)
@ -342,7 +186,7 @@ namespace DepotDownloader
static uint GetSteam3AppBuildNumber(int appId, string branch)
{
if (appId == -1 || !AppIsSteam3(appId))
if (appId == -1)
return 0;
@ -363,7 +207,7 @@ namespace DepotDownloader
static ulong GetSteam3DepotManifest(int depotId, int appId, string branch)
{
if (appId == -1 || !AppIsSteam3(appId))
if (appId == -1)
return 0;
KeyValue depots = GetSteam3AppSection(appId, EAppInfoSection.Depots);
@ -416,11 +260,7 @@ namespace DepotDownloader
static string GetAppOrDepotName(int depotId, int appId)
{
if (appId == -1 || !AppIsSteam3(appId))
{
return CDRManager.GetDepotName(depotId);
}
else if (depotId == -1)
if (depotId == -1)
{
KeyValue info = GetSteam3AppSection(appId, EAppInfoSection.Common);
@ -474,22 +314,7 @@ namespace DepotDownloader
steam3.Disconnect();
}
private static ContentServerClient.Credentials GetSteam2Credentials(uint appId)
{
if (steam3 == null || !steam3Credentials.IsValid)
{
return null;
}
return new ContentServerClient.Credentials()
{
Steam2Ticket = steam3Credentials.Steam2Ticket,
AppTicket = steam3.AppTickets[appId],
SessionToken = steam3Credentials.SessionToken,
};
}
public static void DownloadApp(int appId, int depotId, string branch, bool bListOnly=false)
public static void DownloadApp(int appId, int depotId, string branch)
{
if(steam3 != null)
steam3.RequestAppInfo((uint)appId);
@ -501,30 +326,20 @@ namespace DepotDownloader
return;
}
List<int> depotIDs = null;
var depotIDs = new List<int>();
KeyValue depots = GetSteam3AppSection(appId, EAppInfoSection.Depots);
if (AppIsSteam3(appId))
if (depots != null)
{
depotIDs = new List<int>();
KeyValue depots = GetSteam3AppSection(appId, EAppInfoSection.Depots);
if (depots != null)
foreach (var child in depots.Children)
{
foreach (var child in depots.Children)
int id = -1;
if (int.TryParse(child.Name, out id) && child.Children.Count > 0 && (depotId == -1 || id == depotId))
{
int id = -1;
if (int.TryParse(child.Name, out id) && child.Children.Count > 0 && (depotId == -1 || id == depotId))
{
depotIDs.Add(id);
}
depotIDs.Add(id);
}
}
}
else
{
// steam2 path
depotIDs = CDRManager.GetDepotIDsForApp(appId, Config.DownloadAllPlatforms);
}
if (depotIDs == null || (depotIDs.Count == 0 && depotId == -1))
{
@ -537,105 +352,22 @@ namespace DepotDownloader
return;
}
if ( bListOnly )
{
Console.WriteLine( "\n {0} Depots:", appId );
foreach ( var depot in depotIDs )
{
var depotName = CDRManager.GetDepotName( depot );
Console.WriteLine( "{0} - {1}", depot, depotName );
}
return;
}
var infos2 = new List<DepotDownloadInfo2>();
var infos3 = new List<DepotDownloadInfo3>();
var infos = new List<DepotDownloadInfo>();
foreach (var depot in depotIDs)
{
int depotVersion = 0;
if ( !AppIsSteam3( appId ) )
{
// Steam2 dependency
depotVersion = CDRManager.GetLatestDepotVersion(depot, Config.PreferBetaVersions);
if (depotVersion == -1)
{
Console.WriteLine("Error: Unable to find DepotID {0} in the CDR!", depot);
return;
}
}
IDepotDownloadInfo info = GetDepotInfo(depot, depotVersion, appId, branch);
DepotDownloadInfo info = GetDepotInfo(depot, appId, branch);
if (info != null)
{
if (info.GetDownloadType() == DownloadSource.Steam2)
infos2.Add((DepotDownloadInfo2)info);
else if (info.GetDownloadType() == DownloadSource.Steam3)
infos3.Add((DepotDownloadInfo3)info);
infos.Add(info);
}
}
if( infos2.Count() > 0 )
DownloadSteam2( infos2 );
if( infos3.Count() > 0 )
DownloadSteam3( infos3 );
}
public static void DownloadDepotsForGame(string game, string branch)
{
var infos2 = new List<DepotDownloadInfo2>();
var infos3 = new List<DepotDownloadInfo3>();
List<int> depotIDs = CDRManager.GetDepotIDsForGameserver(game, ContentDownloader.Config.DownloadAllPlatforms);
foreach (var depot in depotIDs)
{
int depotVersion = CDRManager.GetLatestDepotVersion(depot, ContentDownloader.Config.PreferBetaVersions);
if (depotVersion == -1)
{
Console.WriteLine("Error: Unable to find DepotID {0} in the CDR!", depot);
ContentDownloader.ShutdownSteam3();
continue;
}
IDepotDownloadInfo info = GetDepotInfo(depot, depotVersion, 0, branch);
if (info.GetDownloadType() == DownloadSource.Steam2)
{
infos2.Add((DepotDownloadInfo2)info);
}
else if (info.GetDownloadType() == DownloadSource.Steam3)
{
infos3.Add((DepotDownloadInfo3)info);
}
}
if (infos2.Count() > 0)
DownloadSteam2(infos2);
if (infos3.Count() > 0)
DownloadSteam3(infos3);
}
public static void DownloadDepot(int depotId, int depotVersion, string branch, int appId = 0)
{
IDepotDownloadInfo info = GetDepotInfo(depotId, depotVersion, appId, branch);
if (info.GetDownloadType() == DownloadSource.Steam2)
{
var infos = new List<DepotDownloadInfo2>();
infos.Add((DepotDownloadInfo2)info);
DownloadSteam2(infos);
}
else if (info.GetDownloadType() == DownloadSource.Steam3)
{
var infos = new List<DepotDownloadInfo3>();
infos.Add((DepotDownloadInfo3)info);
DownloadSteam3(infos);
}
if( infos.Count() > 0 )
DownloadSteam3( infos );
}
static IDepotDownloadInfo GetDepotInfo(int depotId, int depotVersion, int appId, string branch)
static DepotDownloadInfo GetDepotInfo(int depotId, int appId, string branch)
{
if(steam3 != null && appId > 0)
steam3.RequestAppInfo((uint)appId);
@ -649,17 +381,10 @@ namespace DepotDownloader
return null;
}
DownloadSource source = GetAppDownloadSource(appId);
uint uVersion = (uint)depotVersion;
if (source == DownloadSource.Steam3)
{
uVersion = GetSteam3AppBuildNumber(appId, branch);
}
uint uVersion = GetSteam3AppBuildNumber(appId, branch);
string installDir;
if (!CreateDirectories(depotId, uVersion, source, out installDir))
if (!CreateDirectories(depotId, uVersion, out installDir))
{
Console.WriteLine("Error: Unable to create install directories!");
return null;
@ -668,37 +393,28 @@ namespace DepotDownloader
if(steam3 != null)
steam3.RequestAppTicket((uint)depotId);
if (source == DownloadSource.Steam3)
ulong manifestID = GetSteam3DepotManifest(depotId, appId, branch);
if (manifestID == 0)
{
ulong manifestID = GetSteam3DepotManifest(depotId, appId, branch);
if (manifestID == 0)
{
Console.WriteLine("Depot {0} ({1}) missing public subsection or manifest section.", depotId, contentName);
return null;
}
steam3.RequestDepotKey( ( uint )depotId, ( uint )appId );
if (!steam3.DepotKeys.ContainsKey((uint)depotId))
{
Console.WriteLine("No valid depot key for {0}, unable to download.", depotId);
return null;
}
byte[] depotKey = steam3.DepotKeys[(uint)depotId];
var info = new DepotDownloadInfo3( depotId, manifestID, installDir, contentName );
info.depotKey = depotKey;
return info;
Console.WriteLine("Depot {0} ({1}) missing public subsection or manifest section.", depotId, contentName);
return null;
}
else
steam3.RequestDepotKey( ( uint )depotId, ( uint )appId );
if (!steam3.DepotKeys.ContainsKey((uint)depotId))
{
// steam2 path
var info = new DepotDownloadInfo2(depotId, depotVersion, installDir, contentName);
return info;
Console.WriteLine("No valid depot key for {0}, unable to download.", depotId);
return null;
}
byte[] depotKey = steam3.DepotKeys[(uint)depotId];
var info = new DepotDownloadInfo( depotId, manifestID, installDir, contentName );
info.depotKey = depotKey;
return info;
}
private static void DownloadSteam3( List<DepotDownloadInfo3> depots )
private static void DownloadSteam3( List<DepotDownloadInfo> depots )
{
foreach (var depot in depots)
{
@ -908,245 +624,6 @@ namespace DepotDownloader
}
}
private static ContentServerClient.StorageSession GetSteam2StorageSession(IPEndPoint [] contentServers, ContentServerClient csClient, int depotId, int depotVersion)
{
ContentServerClient.StorageSession session = null;
if (csClient.IsConnected && contentServers.Contains(lastSteam2ContentServer))
{
try
{
session = csClient.OpenStorage( (uint)depotId, (uint)depotVersion, (uint)Config.CellID, null, false );
return session;
}
catch ( Steam2Exception )
{
csClient.Disconnect();
}
}
int tries = 0;
int counterSocket = 0, counterSteam2 = 0;
for (int i = 0; ; i++)
{
IPEndPoint endpoint = contentServers[i % contentServers.Length];
try
{
csClient.Connect( endpoint );
session = csClient.OpenStorage( (uint)depotId, (uint)depotVersion, (uint)Config.CellID, GetSteam2Credentials( (uint)depotId ), true );
lastSteam2ContentServer = endpoint;
break;
}
catch ( SocketException )
{
counterSocket++;
}
catch ( Steam2Exception )
{
csClient.Disconnect();
counterSteam2++;
}
if (((i + 1) % contentServers.Length) == 0)
{
if (++tries > MAX_CONNECT_RETRIES)
{
Console.WriteLine("\nGiving up finding Steam2 content server.");
return null;
}
Console.WriteLine("\nSearching for content servers... (socket error: {0}, steam2 error: {1})", counterSocket, counterSteam2);
counterSocket = 0;
counterSteam2 = 0;
Thread.Sleep(1000);
}
}
return session;
}
private static void DownloadSteam2( List<DepotDownloadInfo2> depots )
{
Console.WriteLine("Found depots:");
foreach (var depot in depots)
{
Console.WriteLine("- {0}\t{1} (version {2})", depot.id, depot.contentName, depot.version);
}
Console.Write("Finding content servers...");
foreach( var depot in depots )
{
depot.contentServers = GetStorageServer(depot.id, depot.version, Config.CellID);
if (depot.contentServers == null || depot.contentServers.Length == 0)
{
Console.WriteLine("\nError: Unable to find any Steam2 content servers for depot {0}, version {1}", depot.id, depot.version);
return;
}
}
Console.WriteLine(" Done!");
ContentServerClient csClient = new ContentServerClient();
csClient.ConnectionTimeout = TimeSpan.FromSeconds(STEAM2_CONNECT_TIMEOUT_SECONDS);
ContentServerClient.StorageSession session;
foreach (var depot in depots)
{
session = GetSteam2StorageSession(depot.contentServers, csClient, depot.id, depot.version);
if (session == null)
continue;
Console.Write(String.Format("Downloading manifest for depot {0}...", depot.id));
string txtManifest = Path.Combine(depot.installDir, string.Format("manifest_{0}.txt", depot.id));
Steam2ChecksumData checksums = null;
StringBuilder manifestBuilder = new StringBuilder();
string[] excludeList = null;
depot.cryptKey = CDRManager.GetDepotEncryptionKey(depot.id, depot.version);
depot.manifest = session.DownloadManifest();
Console.WriteLine(" Done!");
if (Config.UsingExclusionList)
excludeList = GetExcludeList(session, depot.manifest);
// Build a list of files that need downloading.
for (int x = 0; x < depot.manifest.Nodes.Count; ++x)
{
var dirEntry = depot.manifest.Nodes[x];
string downloadPath = Path.Combine(depot.installDir, dirEntry.FullName.ToLower());
if (Config.DownloadManifestOnly)
{
if (dirEntry.FileID == -1)
continue;
manifestBuilder.Append(string.Format("{0}\n", dirEntry.FullName));
continue;
}
if (Config.UsingExclusionList && IsFileExcluded(dirEntry.FullName, excludeList))
continue;
if (!TestIsFileIncluded(dirEntry.FullName))
continue;
string path = Path.GetDirectoryName(downloadPath);
if (path != "" && !Directory.Exists(path))
Directory.CreateDirectory(path);
if ( dirEntry.FileID == -1 )
{
if ( !Directory.Exists( downloadPath ) )
{
// this is a directory, so lets just create it
Directory.CreateDirectory( downloadPath );
}
continue;
}
if (checksums == null)
{
// Skip downloading checksums if we're only interested in manifests.
Console.Write(String.Format("Downloading checksums for depot {0}...", depot.id));
checksums = session.DownloadChecksums();
Console.WriteLine(" Done!");
}
FileInfo fi = new FileInfo(downloadPath);
if (fi.Exists)
{
// Similar file, let's check checksums
if (fi.Length == dirEntry.SizeOrCount &&
Util.ValidateSteam2FileChecksums(fi, checksums.GetFileChecksums(dirEntry.FileID)))
{
// checksums OK
float perc = ((float)x / (float)depot.manifest.Nodes.Count) * 100.0f;
Console.WriteLine("{0,6:#00.00}%\t{1}", perc, downloadPath);
continue;
}
// Unlink the current file before we download a new one.
// This will keep symbolic/hard link targets from being overwritten.
fi.Delete();
}
depot.NodesToDownload.Add(x);
}
if (Config.DownloadManifestOnly)
{
File.WriteAllText(txtManifest, manifestBuilder.ToString());
return;
}
}
foreach( var depot in depots )
{
Console.Write("Downloading requested files from depot {0}... ", depot.id);
if ( depot.NodesToDownload.Count == 0 )
Console.WriteLine("none needed.");
else
Console.WriteLine();
session = GetSteam2StorageSession(depot.contentServers, csClient, depot.id, depot.version);
if(session == null)
continue;
for ( int x = 0 ; x < depot.NodesToDownload.Count ; ++x )
{
var dirEntry = depot.manifest.Nodes[ depot.NodesToDownload[ x ] ];
string downloadPath = Path.Combine( depot.installDir, dirEntry.FullName.ToLower() );
float perc = ( ( float )x / ( float )depot.NodesToDownload.Count ) * 100.0f;
Console.WriteLine("{0,6:#00.00}%\t{1}", perc, downloadPath);
using (var fs = new FileStream(downloadPath, FileMode.Create))
{
session.DownloadFileToStream(dirEntry, fs, ContentServerClient.StorageSession.DownloadPriority.High, depot.cryptKey);
}
}
}
csClient.Disconnect();
}
static IPEndPoint[] GetStorageServer( int depotId, int depotVersion, int cellId )
{
foreach ( IPEndPoint csdServer in ServerCache.CSDSServers )
{
ContentServer[] servers;
try
{
ContentServerDSClient csdsClient = new ContentServerDSClient();
csdsClient.Connect( csdServer );
servers = csdsClient.GetContentServerList( (uint)depotId, (uint)depotVersion, (uint)cellId );
}
catch ( SocketException )
{
servers = null;
continue;
}
if ( servers == null )
{
Console.WriteLine( "Warning: CSDS {0} rejected the given depotid or version!", csdServer );
continue;
}
if ( servers.Length == 0 )
continue;
return servers.OrderBy(x => x.Load).Select(x => x.StorageServer).ToArray();
}
return null;
}
static string EncodeHexString( byte[] input )
{
return input.Aggregate( new StringBuilder(),

@ -8,7 +8,6 @@ namespace DepotDownloader
{
class Program
{
static void Main( string[] args )
{
if ( args.Length == 0 )
@ -19,40 +18,14 @@ namespace DepotDownloader
DebugLog.Enabled = false;
ServerCache.Build();
CDRManager.Update();
if (HasParameter( args, "-list" ) )
{
CDRManager.ListGameServers();
return;
}
bool bGameserver = true;
bool bApp = false;
bool bListDepots = HasParameter(args, "-listdepots");
bool bDumpManifest = HasParameter( args, "-manifest" );
int appId = GetIntParameter( args, "-app" );
int depotId = GetIntParameter( args, "-depot" );
int appId = -1;
int depotId = -1;
string gameName = GetStringParameter( args, "-game" );
if ( gameName == null )
if ( appId == -1 )
{
appId = GetIntParameter( args, "-app" );
bGameserver = false;
depotId = GetIntParameter( args, "-depot" );
if ( depotId == -1 && appId == -1 )
{
Console.WriteLine( "Error: -game, -app, or -depot not specified!" );
return;
}
else if ( appId >= 0 )
{
bApp = true;
}
Console.WriteLine( "Error: -app not specified!" );
return;
}
ContentDownloader.Config.DownloadManifestOnly = bDumpManifest;
@ -70,39 +43,6 @@ namespace DepotDownloader
ContentDownloader.Config.PreferBetaVersions = HasParameter( args, "-beta" );
ContentDownloader.Config.BetaPassword = GetStringParameter( args, "-betapassword" );
// this is a Steam2 option
if ( !bGameserver && !bApp && depotVersion == -1 )
{
int latestVer = CDRManager.GetLatestDepotVersion(depotId, ContentDownloader.Config.PreferBetaVersions);
if ( latestVer == -1 )
{
Console.WriteLine( "Error: Unable to find DepotID {0} in the CDR!", depotId );
return;
}
string strVersion = GetStringParameter( args, "-version" );
if ( strVersion != null && strVersion.Equals( "latest", StringComparison.OrdinalIgnoreCase ) )
{
Console.WriteLine( "Using latest version: {0}", latestVer );
depotVersion = latestVer;
}
else if ( strVersion == null )
{
// this could probably be combined with the above
Console.WriteLine( "No version specified." );
Console.WriteLine( "Using latest version: {0}", latestVer );
depotVersion = latestVer;
}
else
{
Console.WriteLine( "Available depot versions:" );
Console.WriteLine( " Oldest: 0" );
Console.WriteLine( " Newest: {0}", latestVer );
return;
}
}
string fileList = GetStringParameter( args, "-filelist" );
string[] files = null;
@ -142,7 +82,6 @@ namespace DepotDownloader
string username = GetStringParameter(args, "-username");
string password = GetStringParameter(args, "-password");
ContentDownloader.Config.InstallDirectory = GetStringParameter(args, "-dir");
bool bNoExclude = HasParameter(args, "-no-exclude");
ContentDownloader.Config.DownloadAllPlatforms = HasParameter(args, "-all-platforms");
string branch = GetStringParameter(args, "-branch") ?? GetStringParameter(args, "-beta") ?? "Public";
@ -154,46 +93,7 @@ namespace DepotDownloader
}
ContentDownloader.InitializeSteam3(username, password);
if (bApp)
{
ContentDownloader.DownloadApp(appId, depotId, branch, bListDepots);
}
else if ( !bGameserver )
{
ContentDownloader.DownloadDepot(depotId, depotVersion, branch, appId);
}
else
{
if (!bNoExclude)
{
ContentDownloader.Config.UsingExclusionList = true;
}
List<int> depotIDs = CDRManager.GetDepotIDsForGameserver( gameName, ContentDownloader.Config.DownloadAllPlatforms );
if ( depotIDs.Count == 0 )
{
Console.WriteLine( "Error: No depots for specified game '{0}'", gameName );
return;
}
if ( bListDepots )
{
Console.WriteLine( "\n '{0}' Depots:", gameName );
foreach ( var depot in depotIDs )
{
var depotName = CDRManager.GetDepotName( depot );
Console.WriteLine( "{0} - {1}", depot, depotName );
}
}
else
{
ContentDownloader.DownloadDepotsForGame( gameName, branch );
}
}
ContentDownloader.DownloadApp(appId, depotId, branch);
ContentDownloader.ShutdownSteam3();
}
@ -238,28 +138,18 @@ namespace DepotDownloader
Console.WriteLine( "\nUse: depotdownloader <parameters> [optional parameters]\n" );
Console.WriteLine( "Parameters:" );
Console.WriteLine( "\t-depot #\t\t\t- the DepotID to download." );
Console.WriteLine( "\t OR" );
Console.WriteLine( "\t-app #\t\t\t\t- the AppID to download." );
Console.WriteLine( "\t OR" );
Console.WriteLine( "\t-game name\t\t\t- the HLDSUpdateTool game server to download." );
Console.WriteLine( "\t OR" );
Console.WriteLine( "\t-list\t\t\t\t- print list of game servers that can be downloaded using -game." );
Console.WriteLine( "\t OR" );
Console.WriteLine( "\t-dumpcdr-xml\t\t\t- exports CDR to XML (cdrdump.xml)." );
Console.WriteLine("\t-app #\t\t\t\t- the AppID to download.");
Console.WriteLine();
Console.WriteLine( "\t-version [# or \"latest\"]\t- the version of the depot to download. Uses latest if none specified.\n" );
Console.WriteLine( "Optional Parameters:" );
Console.WriteLine( "\t-depot #\t\t\t- the DepotID to download." );
Console.WriteLine( "\t-cellid #\t\t\t- the CellID of the content server to download from." );
Console.WriteLine( "\t-username user\t\t\t- the username of the account to login to for restricted content." );
Console.WriteLine( "\t-password pass\t\t\t- the password of the account to login to for restricted content." );
Console.WriteLine( "\t-dir installdir\t\t\t- the directory in which to place downloaded files." );
Console.WriteLine( "\t-filelist filename.txt\t\t- a list of files to download (from the manifest). Can optionally use regex to download only certain files." );
Console.WriteLine( "\t-no-exclude\t\t\t- don't exclude any files when downloading depots with the -game parameter." );
Console.WriteLine( "\t-all-platforms\t\t\t- downloads all platform-specific depots when -game or -app is used." );
Console.WriteLine( "\t-all-platforms\t\t\t- downloads all platform-specific depots when -app is used." );
Console.WriteLine( "\t-beta\t\t\t\t- download beta version of depots if available." );
Console.WriteLine( "\t-listdepots\t\t\t- When used with -app or -game, only list relevant depotIDs and quit." );
Console.WriteLine( "\t-manifest\t\t\t- downloads a human readable manifest for any depots that would be downloaded." );
}
}

@ -1,99 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net;
using SteamKit2;
namespace DepotDownloader
{
static class ServerCache
{
public static ServerList ConfigServers { get; private set; }
public static ServerList CSDSServers { get; private set; }
static ServerCache()
{
ConfigServers = new ServerList();
CSDSServers = new ServerList();
}
public static void Build()
{
Console.Write( "\nBuilding Steam2 server cache..." );
if (DateTime.Now > ConfigCache.Instance.ServerCacheTime)
{
foreach (IPEndPoint gdServer in GeneralDSClient.GDServers)
{
BuildServer(gdServer, ConfigServers, ESteam2ServerType.ConfigServer);
BuildServer(gdServer, CSDSServers, ESteam2ServerType.CSDS);
}
if (ConfigServers.Count > 0 && CSDSServers.Count > 0)
{
ConfigCache.Instance.ConfigServers = ConfigServers;
ConfigCache.Instance.CSDSServers = CSDSServers;
ConfigCache.Instance.ServerCacheTime = DateTime.Now.AddDays(30);
ConfigCache.Instance.Save(ConfigCache.CONFIG_FILENAME);
Console.WriteLine(" Done!");
return;
} else if(ConfigCache.Instance.CSDSServers == null || ConfigCache.Instance.ConfigServers == null)
{
Console.WriteLine(" Unable to get server list");
return;
}
}
ConfigServers = ConfigCache.Instance.ConfigServers;
CSDSServers = ConfigCache.Instance.CSDSServers;
Console.WriteLine( " Done!" );
}
private static void BuildServer( IPEndPoint gdServer, ServerList list, ESteam2ServerType type )
{
try
{
GeneralDSClient gdsClient = new GeneralDSClient();
gdsClient.Connect( gdServer );
IPEndPoint[] servers = gdsClient.GetServerList( type );
list.AddRange( servers );
gdsClient.Disconnect();
}
catch(Exception)
{
Console.WriteLine( "Warning: Unable to connect to GDS {0} to get list of {1} servers.", gdServer, type );
}
}
}
class ServerList : List<IPEndPoint>
{
public new void AddRange( IEnumerable<IPEndPoint> endPoints )
{
foreach ( IPEndPoint endPoint in endPoints )
Add( endPoint );
}
public new void Add( IPEndPoint endPoint )
{
if ( this.HasServer( endPoint ) )
return;
base.Add( endPoint );
}
public bool HasServer( IPEndPoint endPoint )
{
foreach ( var server in this )
{
if ( server.Equals( endPoint ) )
return true;
}
return false;
}
}
}

@ -16,11 +16,10 @@ namespace DepotDownloader
{
public bool LoggedOn { get; set; }
public ulong SessionToken { get; set; }
public Steam2Ticket Steam2Ticket { get; set; }
public bool IsValid
{
get { return LoggedOn; }// && SessionToken > 0 && Steam2Ticket != null; }
get { return LoggedOn; }
}
}
@ -399,12 +398,6 @@ namespace DepotDownloader
credentials.LoggedOn = true;
if (loggedOn.Steam2Ticket != null)
{
Console.WriteLine("Got Steam2 Ticket!");
credentials.Steam2Ticket = loggedOn.Steam2Ticket;
}
if (ContentDownloader.Config.CellID == 0)
{
Console.WriteLine("Using Steam3 suggested CellID: " + loggedOn.CellID);

Loading…
Cancel
Save