diff --git a/Facepunch.Steamworks.Test/Client/Workshop.cs b/Facepunch.Steamworks.Test/Client/Workshop.cs new file mode 100644 index 0000000..721cabb --- /dev/null +++ b/Facepunch.Steamworks.Test/Client/Workshop.cs @@ -0,0 +1,51 @@ +using System; +using System.Text; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Linq; + +namespace Facepunch.Steamworks.Test +{ + [TestClass] + [DeploymentItem( Config.LibraryName + ".dll" )] + [DeploymentItem( "steam_appid.txt" )] + public class WorkshopTest + { + [TestMethod] + public void Query() + { + using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) + { + Assert.IsTrue( client.IsValid ); + + var Query = client.Workshop.CreateQuery(); + + Query.Run(); + + // Block, wait for result + // (don't do this in realtime) + Query.Block(); + + Assert.IsFalse( Query.IsRunning ); + + // results + + Console.WriteLine( "Searching" ); + + Query.SearchText = "shit"; + Query.Run(); + + // Block, wait for result + // (don't do this in realtime) + Query.Block(); + + for ( int i=0; i<100; i++ ) + { + client.Update(); + Thread.Sleep( 10 ); + } + } + } + + } +} diff --git a/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj b/Facepunch.Steamworks.Test/Facepunch.Steamworks.Test.csproj index 20a9a43..dc48076 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/Callbacks/Workshop.cs b/Facepunch.Steamworks/Callbacks/Workshop.cs new file mode 100644 index 0000000..e831514 --- /dev/null +++ b/Facepunch.Steamworks/Callbacks/Workshop.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using Facepunch.Steamworks.Interop; + +namespace Facepunch.Steamworks.Callbacks.Workshop +{ + internal class QueryCompleted : CallResult + { + public override int CallbackId { get { return Callbacks.Index.UGC + 1; } } + + [StructLayout( LayoutKind.Sequential )] + internal struct Data + { + internal ulong Handle; + internal int Result; + internal uint m_unNumResultsReturned; + internal uint m_unTotalMatchingResults; + [MarshalAs(UnmanagedType.I1)] + internal bool m_bCachedData; // indicates whether this data was retrieved from the local on-disk cache + }; + } + + +} diff --git a/Facepunch.Steamworks/Facepunch.Steamworks.csproj b/Facepunch.Steamworks/Facepunch.Steamworks.csproj index a59cc55..1bdff4c 100644 --- a/Facepunch.Steamworks/Facepunch.Steamworks.csproj +++ b/Facepunch.Steamworks/Facepunch.Steamworks.csproj @@ -116,6 +116,7 @@ + @@ -135,6 +136,7 @@ + diff --git a/Facepunch.Steamworks/Interfaces/Workshop.cs b/Facepunch.Steamworks/Interfaces/Workshop.cs new file mode 100644 index 0000000..39d5a21 --- /dev/null +++ b/Facepunch.Steamworks/Interfaces/Workshop.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using Facepunch.Steamworks.Callbacks.Networking; +using Facepunch.Steamworks.Callbacks.Workshop; +using Facepunch.Steamworks.Interop; +using Valve.Steamworks; + +namespace Facepunch.Steamworks +{ + public class Workshop + { + internal const ulong InvalidHandle = 0xffffffffffffffff; + + internal ISteamUGC ugc; + internal BaseSteamworks steamworks; + + internal Workshop( BaseSteamworks sw, ISteamUGC ugc ) + { + this.ugc = ugc; + this.steamworks = sw; + + // sw.AddCallback( onP2PConnectionRequest, P2PSessionRequest.CallbackId ); + + } + + public enum Order + { + RankedByVote = 0, + RankedByPublicationDate = 1, + AcceptedForGameRankedByAcceptanceDate = 2, + RankedByTrend = 3, + FavoritedByFriendsRankedByPublicationDate = 4, + CreatedByFriendsRankedByPublicationDate = 5, + RankedByNumTimesReported = 6, + CreatedByFollowedUsersRankedByPublicationDate = 7, + NotYetRated = 8, + RankedByTotalVotesAsc = 9, + RankedByVotesUp = 10, + RankedByTextSearch = 11, + RankedByTotalUniqueSubscriptions = 12, + }; + + public enum QueryType + { + Items = 0, // both mtx items and ready-to-use items + Items_Mtx = 1, + Items_ReadyToUse = 2, + Collections = 3, + Artwork = 4, + Videos = 5, + Screenshots = 6, + AllGuides = 7, // both web guides and integrated guides + WebGuides = 8, + IntegratedGuides = 9, + UsableInGame = 10, // ready-to-use items and integrated guides + ControllerBindings = 11, + GameManagedItems = 12, // game managed items (not managed by users) + All = ~0, // return everything + }; + + public WorkshopQuery CreateQuery() + { + var q = new WorkshopQuery(); + q.workshop = this; + return q; + } + + public class WorkshopQuery + { + internal ulong Handle; + internal QueryCompleted Callback; + + public QueryType QueryType { get; set; } = QueryType.All; + public Order Order { get; set; } = Order.RankedByPublicationDate; + + public string SearchText { get; set; } + + /// + /// Page starts at 1 !! + /// + public int Page { get; set; } = 1; + internal Workshop workshop; + + public void Run() + { + if ( Callback != null ) + return; + + if ( Page <= 0 ) + throw new System.Exception( "Page should be 1 or above" ); + + Handle = workshop.ugc.CreateQueryAllUGCRequest( (uint)Order, (uint)QueryType, workshop.steamworks.AppId, workshop.steamworks.AppId, (uint)Page ); + + if ( !string.IsNullOrEmpty( SearchText ) ) + workshop.ugc.SetSearchText( Handle, SearchText ); + + Callback = new QueryCompleted(); + Callback.Handle = workshop.ugc.SendQueryUGCRequest( Handle ); + Callback.OnResult = OnResult; + workshop.steamworks.AddCallResult( Callback ); + } + + void OnResult( QueryCompleted.Data data ) + { + Callback.Dispose(); + Callback = null; + + Console.WriteLine( "Results: " + data.m_unTotalMatchingResults ); + } + + public bool IsRunning + { + get { return Callback != null; } + } + + /// + /// Don't call this in production! + /// + public void Block() + { + workshop.steamworks.Update(); + + while ( IsRunning ) + { + System.Threading.Thread.Sleep( 10 ); + workshop.steamworks.Update(); + } + } + } + } +}