From 2b15c50fa1fce32878b6704d6bdff71fbaec54cc Mon Sep 17 00:00:00 2001 From: James King Date: Thu, 17 Mar 2022 15:26:24 +0100 Subject: [PATCH] Legacy RemoteStorage based shared file downloading --- Facepunch.Steamworks/SteamRemoteStorage.cs | 5 + .../Structs/LegacySharedFile.cs | 139 ++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 Facepunch.Steamworks/Structs/LegacySharedFile.cs diff --git a/Facepunch.Steamworks/SteamRemoteStorage.cs b/Facepunch.Steamworks/SteamRemoteStorage.cs index 03cadb5..b189861 100644 --- a/Facepunch.Steamworks/SteamRemoteStorage.cs +++ b/Facepunch.Steamworks/SteamRemoteStorage.cs @@ -177,5 +177,10 @@ namespace Steamworks } } + public static async Task LegacyDownloadSharedFile( PublishedFileId fileId, uint priority = 1000 ) + { + var result = await Internal.UGCDownload( fileId.Value, priority ); + return result == null ? null : new LegacyDownloadResult( result.Value ); + } } } diff --git a/Facepunch.Steamworks/Structs/LegacySharedFile.cs b/Facepunch.Steamworks/Structs/LegacySharedFile.cs new file mode 100644 index 0000000..77e3ae7 --- /dev/null +++ b/Facepunch.Steamworks/Structs/LegacySharedFile.cs @@ -0,0 +1,139 @@ +using System; +using System.IO; + +namespace Steamworks.Data +{ + public readonly struct LegacyDownloadResult + { + public readonly Result Result; + public readonly PublishedFileId File; + public readonly AppId AppId; + public readonly Friend Owner; + public readonly int SizeInBytes; + public readonly string FileName; + + internal LegacyDownloadResult( in RemoteStorageDownloadUGCResult_t result ) + { + Result = result.Result; + File = result.File; + AppId = result.AppID; + SizeInBytes = result.SizeInBytes; + FileName = result.PchFileNameUTF8(); + Owner = new Friend( result.SteamIDOwner ); + } + + private class UgcStream : Stream + { + private readonly UGCHandle_t _handle; + private readonly int _sizeInBytes; + + private uint _offset; + private bool _closed; + + public UgcStream( UGCHandle_t handle, int sizeInBytes ) + { + _handle = handle; + _sizeInBytes = sizeInBytes; + } + + public override bool CanRead => true; + + public override bool CanSeek => true; + + public override bool CanWrite => false; + + public override long Length => _sizeInBytes; + + public override long Position { get => _offset; set => Seek( value, SeekOrigin.Begin ); } + + public override void Flush() { } + + public override unsafe int Read( byte[] buffer, int offset, int count ) + { + if ( _closed ) + { + throw new ObjectDisposedException( nameof( UgcStream ) ); + } + + count = Math.Min( count, (int) (_sizeInBytes - _offset) ); + + if ( offset + count > buffer.Length ) + { + throw new ArgumentOutOfRangeException( nameof(count), "Attempting to write beyond the end of the given buffer." ); + } + + fixed ( byte* ptr = buffer ) + { + var read = SteamRemoteStorage.Internal.UGCRead( _handle, (IntPtr) (ptr + offset), count, _offset, UGCReadAction.ontinueReading ); + _offset += (uint) read; + return read; + } + } + + public override long Seek( long offset, SeekOrigin origin ) + { + if ( _closed ) + { + throw new ObjectDisposedException( nameof( UgcStream ) ); + } + + switch ( origin ) + { + case SeekOrigin.Begin: + break; + + case SeekOrigin.Current: + offset += _offset; + break; + + case SeekOrigin.End: + offset += _sizeInBytes; + break; + } + + if ( offset < 0 ) + { + throw new Exception( "Attempted to seek before the start of the stream." ); + } + + if ( offset > _sizeInBytes ) + { + throw new Exception( "Attempted to seek beyond the end of the stream." ); + } + + return _offset = (uint) offset; + } + + public override void SetLength( long value ) + { + throw new NotImplementedException(); + } + + public override void Write( byte[] buffer, int offset, int count ) + { + throw new NotImplementedException(); + } + + public override void Close() + { + if ( _closed ) + { + return; + } + + _closed = true; + SteamRemoteStorage.Internal.UGCRead( _handle, IntPtr.Zero, 0, 0, UGCReadAction.lose ); + } + } + + public Stream OpenRead() + { + return new UgcStream( File.Value, SizeInBytes ); + } + + public override string ToString() + { + return FileName; + } + } +}