diff --git a/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj b/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj
index e5daa38..6b37a7a 100644
--- a/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj
+++ b/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj
@@ -89,6 +89,7 @@
+
diff --git a/Facepunch.Steamworks.Test/UgcEditor.cs b/Facepunch.Steamworks.Test/UgcEditor.cs
new file mode 100644
index 0000000..46da119
--- /dev/null
+++ b/Facepunch.Steamworks.Test/UgcEditor.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Steamworks.Data;
+
+namespace Steamworks
+{
+ [TestClass]
+ [DeploymentItem( "steam_api64.dll" )]
+ public class UgcEditor
+ {
+ [TestMethod]
+ public async Task CreateFile()
+ {
+ var result = await Ugc.Editor.NewCommunityFile
+ .WithTitle( "Unit Test Created Item" )
+ .WithDescription( "This item was created by Facepunch Steamworks unit tests.\n\n" +
+ "It should have technically been deleted so you should never get to " +
+ "read this unless something terrible has happened." )
+ .SubmitAsync();
+
+ Assert.IsTrue( result.Success );
+ Assert.AreNotEqual( result.FileId.Value, 0 );
+
+ var deleted = await SteamUGC.DeleteFileAsync( result.FileId );
+ Assert.IsTrue( deleted );
+
+ }
+ }
+
+}
diff --git a/Facepunch.Steamworks/SteamUgc.cs b/Facepunch.Steamworks/SteamUgc.cs
index 7ea00ce..b9caf9f 100644
--- a/Facepunch.Steamworks/SteamUgc.cs
+++ b/Facepunch.Steamworks/SteamUgc.cs
@@ -28,5 +28,10 @@ namespace Steamworks
}
}
+ public static async Task DeleteFileAsync( PublishedFileId fileId )
+ {
+ var r = await Internal.DeleteItem( fileId );
+ return r?.Result == Result.OK;
+ }
}
}
\ No newline at end of file
diff --git a/Facepunch.Steamworks/Structs/UgcEditor.cs b/Facepunch.Steamworks/Structs/UgcEditor.cs
new file mode 100644
index 0000000..f51a15e
--- /dev/null
+++ b/Facepunch.Steamworks/Structs/UgcEditor.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Steamworks.Data;
+
+using QueryType = Steamworks.Ugc.Query;
+
+namespace Steamworks.Ugc
+{
+ public struct Editor
+ {
+ PublishedFileId fileId;
+
+ bool creatingNew;
+ WorkshopFileType creatingType;
+ AppId consumerAppId;
+
+ internal Editor( WorkshopFileType filetype ) : this()
+ {
+ creatingNew = true;
+ creatingType = filetype;
+ }
+
+ ///
+ /// Create a Normal Workshop item that can be subscribed to
+ ///
+ public static Editor NewCommunityFile => new Editor( WorkshopFileType.Community );
+
+ ///
+ /// Workshop item that is meant to be voted on for the purpose of selling in-game
+ ///
+ public static Editor NewMicrotransactionFile => new Editor( WorkshopFileType.Microtransaction );
+
+ public Editor ForAppId( AppId id ) { this.consumerAppId = id; return this; }
+
+
+ string Title;
+ public Editor WithTitle( string t ) { this.Title = t; return this; }
+
+ string Description;
+ public Editor WithDescription( string t ) { this.Description = t; return this; }
+
+
+ public async Task SubmitAsync()
+ {
+ var result = default( PublishResult );
+
+ //
+ // Item Create
+ //
+ if ( creatingNew )
+ {
+ if ( consumerAppId == 0 )
+ consumerAppId = SteamClient.AppId;
+
+ result.Result = Steamworks.Result.Fail;
+
+ var created = await SteamUGC.Internal.CreateItem( consumerAppId, creatingType );
+ if ( !created.HasValue ) return result;
+
+ result.Result = created.Value.Result;
+
+ if ( result.Result != Steamworks.Result.OK )
+ return result;
+
+ fileId = created.Value.PublishedFileId;
+ result.NeedsWorkshopAgreement = created.Value.UserNeedsToAcceptWorkshopLegalAgreement;
+ result.FileId = fileId;
+
+ await Task.Delay( 500 );
+ }
+
+ result.FileId = fileId;
+
+ //
+ // Item Update
+ //
+ {
+ var handle = SteamUGC.Internal.StartItemUpdate( consumerAppId, fileId );
+ if ( handle == 0xffffffffffffffff )
+ return result;
+
+ if ( Title != null ) SteamUGC.Internal.SetItemTitle( handle, Title );
+ if ( Description != null ) SteamUGC.Internal.SetItemDescription( handle, Description );
+
+ result.Result = Steamworks.Result.Fail;
+
+ var updated = await SteamUGC.Internal.SubmitItemUpdate( handle, "" );
+ if ( !updated.HasValue ) return result;
+
+ result.Result = updated.Value.Result;
+
+ if ( result.Result != Steamworks.Result.OK )
+ return result;
+
+ result.NeedsWorkshopAgreement = updated.Value.UserNeedsToAcceptWorkshopLegalAgreement;
+ result.FileId = fileId;
+
+ }
+
+ return result;
+ }
+ }
+
+ public struct PublishResult
+ {
+ public bool Success => Result == Steamworks.Result.OK;
+
+ public Steamworks.Result Result;
+ public PublishedFileId FileId;
+
+ ///
+ /// https://partner.steamgames.com/doc/features/workshop/implementation#Legal
+ ///
+ public bool NeedsWorkshopAgreement;
+ }
+}
\ No newline at end of file