- Home /
Steamworks.NET and Steam Workshop
Has anyone here implemented the Steamworks.NET wrapper and used it to upload/download items to Steam Workshop? I'm looking for a simple C# script example of how to do this, and even willing to pay money for help :D
To provide more context: I have a level editor that saves one .txt file for level info, and one image file for the level preview. I just need a C# Steamworks.NET script that will upload those files to the Workshop, and then find them when downloaded from Workshop.
BU$$anonymous$$P
Really though... can anyone out there help me? Feels like I'm shouting for help in the dark here.
Answer by vitinho444 · Jan 02, 2017 at 07:58 PM
So I came across your question and seems like nobody knows the answer. I tried to search on google everything I could and no answers either. Tried to directly ask developers, no answer either. So I made it myself.
The problem was that Steamworks.net calls workshop stuff on the RemoteStorage part.
How to use my script:
Call the SaveToWorkshop function with the file details. This will upload the file to Steam cloud (I think it's mandatory (it will delete afterwards))
Done. You can check the Workshop page, the item is there.
Now to download:
Subscribe to the item you want to download.
Call "GetSubscribedItems" function in my script.
Call "GetItemContent(INDEX)" to download the contents of the INDEX item.
Check the itemContent property on the script.
This script was made by me for my game AffordaGolf and it suits my needs, but each case is a case, so you might want to change some things.
Good luck!
Here's the script I'm using in my game:
using UnityEngine;
using System.Collections.Generic;
using Steamworks;
/// <summary>
/// This class was created by Vitor Pêgas on 01/01/2017
/// </summary>
public class SteamWorkshop : MonoBehaviour {
public static SteamWorkshop singleton;
void Awake() { singleton = this; subscribedItemList = new List<PublishedFileId_t>(); }
private CallResult<RemoteStoragePublishFileResult_t> RemoteStoragePublishFileResult;
private CallResult<RemoteStorageEnumerateUserSubscribedFilesResult_t> RemoteStorageEnumerateUserSubscribedFilesResult;
private CallResult<RemoteStorageGetPublishedFileDetailsResult_t> RemoteStorageGetPublishedFileDetailsResult;
private CallResult<RemoteStorageDownloadUGCResult_t> RemoteStorageDownloadUGCResult;
private CallResult<RemoteStorageUnsubscribePublishedFileResult_t> RemoteStorageUnsubscribePublishedFileResult;
private PublishedFileId_t publishedFileID;
private UGCHandle_t UGCHandle;
public List<PublishedFileId_t> subscribedItemList;
public bool fetchedContent;
private string itemContent;
private string lastFileName;
void OnEnable()
{
RemoteStoragePublishFileResult = CallResult<RemoteStoragePublishFileResult_t>.Create(OnRemoteStoragePublishFileResult);
RemoteStorageEnumerateUserSubscribedFilesResult = CallResult<RemoteStorageEnumerateUserSubscribedFilesResult_t>.Create(OnRemoteStorageEnumerateUserSubscribedFilesResult);
RemoteStorageGetPublishedFileDetailsResult = CallResult<RemoteStorageGetPublishedFileDetailsResult_t>.Create(OnRemoteStorageGetPublishedFileDetailsResult);
RemoteStorageDownloadUGCResult = CallResult<RemoteStorageDownloadUGCResult_t>.Create(OnRemoteStorageDownloadUGCResult);
RemoteStorageUnsubscribePublishedFileResult = CallResult<RemoteStorageUnsubscribePublishedFileResult_t>.Create(OnRemoteStorageUnsubscribePublishedFileResult);
}
public string getContent()
{
return itemContent;
}
public void GetSubscribedItems()
{
SteamAPICall_t handle = SteamRemoteStorage.EnumerateUserSubscribedFiles(0);
RemoteStorageEnumerateUserSubscribedFilesResult.Set(handle);
}
/// <summary>
/// Gets the Item content (subscribed) to variable itemContent
/// When done downloading, fetchedContent will be TRUE.
/// </summary>
/// <param name="ItemID"></param>
public void GetItemContent(int ItemID)
{
fetchedContent = false;
publishedFileID = subscribedItemList[ItemID];
SteamAPICall_t handle = SteamRemoteStorage.GetPublishedFileDetails(publishedFileID, 0);
RemoteStorageGetPublishedFileDetailsResult.Set(handle);
}
public void DeleteFile(string filename)
{
bool ret = SteamRemoteStorage.FileDelete(filename);
}
/// <summary>
/// This functions saves a file to the workshop.
/// Make sure file size doesn't pass the steamworks limit on your app settings.
/// </summary>
/// <param name="fileName">File Name (actual physical file) example: map.txt</param>
/// <param name="fileData">File Data (actual file data)</param>
/// <param name="workshopTitle">Workshop Item Title</param>
/// <param name="workshopDescription">Workshop Item Description</param>
/// <param name="tags">Tags</param>
public void SaveToWorkshop(string fileName, string fileData, string workshopTitle, string workshopDescription, string[] tags)
{
lastFileName = fileName;
bool fileExists = SteamRemoteStorage.FileExists(fileName);
if(fileExists)
{
Debug.Log("A file already exists with that name!");
}
else
{
//Try to upload to Steam Cloud
bool upload = UploadFile(fileName, fileData);
if(!upload)
{
Debug.Log("Upload failed!");
}
else
{
UploadToWorkshop(fileName, workshopTitle, workshopDescription, tags);
}
}
}
private bool UploadFile(string fileName, string fileData)
{
byte[] Data = new byte[System.Text.Encoding.UTF8.GetByteCount(fileData)];
System.Text.Encoding.UTF8.GetBytes(fileData, 0, fileData.Length, Data, 0);
bool ret = SteamRemoteStorage.FileWrite(fileName, Data, Data.Length);
return ret;
}
private void UploadToWorkshop(string fileName, string workshopTitle, string workshopDescription, string[] tags)
{
SteamAPICall_t handle = SteamRemoteStorage.PublishWorkshopFile(fileName, null, SteamUtils.GetAppID(), workshopTitle, workshopDescription, ERemoteStoragePublishedFileVisibility.k_ERemoteStoragePublishedFileVisibilityPublic, tags, EWorkshopFileType.k_EWorkshopFileTypeCommunity);
RemoteStoragePublishFileResult.Set(handle);
}
public void Unsubscribe(PublishedFileId_t file)
{
SteamAPICall_t handle = SteamRemoteStorage.UnsubscribePublishedFile(file);
RemoteStorageUnsubscribePublishedFileResult.Set(handle);
}
///CallBacks
///
void OnRemoteStorageUnsubscribePublishedFileResult(RemoteStorageUnsubscribePublishedFileResult_t pCallback, bool bIOFailure)
{
Debug.Log("[" + RemoteStorageUnsubscribePublishedFileResult_t.k_iCallback + " - RemoteStorageUnsubscribePublishedFileResult] - " + pCallback.m_eResult + " -- " + pCallback.m_nPublishedFileId);
}
void OnRemoteStoragePublishFileResult(RemoteStoragePublishFileResult_t pCallback, bool bIOFailure)
{
if (pCallback.m_eResult == EResult.k_EResultOK)
{
publishedFileID = pCallback.m_nPublishedFileId;
DeleteFile(lastFileName);
}
}
void OnRemoteStorageEnumerateUserSubscribedFilesResult(RemoteStorageEnumerateUserSubscribedFilesResult_t pCallback, bool bIOFailure)
{
subscribedItemList = new List<PublishedFileId_t>();
for (int i = 0; i < pCallback.m_nTotalResultCount; i++)
{
PublishedFileId_t f = pCallback.m_rgPublishedFileId[i];
Debug.Log(f);
subscribedItemList.Add(f);
}
}
void OnRemoteStorageGetPublishedFileDetailsResult(RemoteStorageGetPublishedFileDetailsResult_t pCallback, bool bIOFailure)
{
if (pCallback.m_eResult == EResult.k_EResultOK)
{
UGCHandle = pCallback.m_hFile;
SteamAPICall_t handle = SteamRemoteStorage.UGCDownload(UGCHandle, 0);
RemoteStorageDownloadUGCResult.Set(handle);
}
}
void OnRemoteStorageDownloadUGCResult(RemoteStorageDownloadUGCResult_t pCallback, bool bIOFailure)
{
byte[] Data = new byte[pCallback.m_nSizeInBytes];
int ret = SteamRemoteStorage.UGCRead(UGCHandle, Data, pCallback.m_nSizeInBytes, 0, EUGCReadAction.k_EUGCRead_Close);
itemContent = System.Text.Encoding.UTF8.GetString(Data, 0, ret);
fetchedContent = true;
Debug.Log("content:" + itemContent);
}
}
Thank you very much!!
I ended up giving up on getting an answer here and got it figured out elsewhere. But I'm sure others will find this helpful too.
Thanks again!
Yeah no problem ;) I was almost giving up when I decided to just read every single line of code and see what it did, and I found it out.
Good luck ;)
@vitinho444 Awesome script!
I have a question:
Let's say I have something I have uploaded to Workshop already and I have since updated the content and wish to upload that to the same Workshop item, updating it to the latest version.
How would I go about that?
Very good question. Although my code doesn't cover, check out the S$$anonymous$$mworks.net example on RemoteStorage and UCG (or UGC i don't remember quite well) and there's the example of the option to update a already published workshop item with a new file.
Good luck :)
Hm, well I assure you that that's an exact copy of the code I'm using on my game and it works. Check out the S$$anonymous$$mworks.NET Test and go to the remote storage part and check if it works there.
Good luck :)
After modifying the code a little bit I can publish zip files along with preview images without any problems. Although when it comes to the downloading part, the subscribed items are getting listed in the console and m-eResult == EResult.k_EresultO$$anonymous$$ and my special download directory is getting created afterwards but no files are getting downloaded. I changed UGCDownload to UGCDownloadToLocation and I'm 100% sure that my path is right but still nothing is downloading. Any ideas ?
never$$anonymous$$d, fixed it :) turns out that UGCDownloadToLocation path requires the name of the file and the extension as well.
Thanks for that info. I wonder, how did you turn the zip file into a byte[] and vice-versa? Thank you!
Thanks and it is really helpful ! Just wanted to know if there is any other way to do it ,without subscribing to the content in workshop page?
I believe not. That's just how S$$anonymous$$m Workshop is setup. You have to subscribe items in order to download them. But there may be a way, I just don't know it. Check the S$$anonymous$$mworks docs, maybe you'll find something there.
Good luck.
Ohh I see this is the S$$anonymous$$mWorkshop way to store and restore stuff,I will look further in the docs,to achieve it without workshop. Thanks for the help.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Getting the Location of a Laptop 0 Answers
Using a class library in Unity [Free version] 1 Answer
Creating Scenes Programmatically From A Deployed Build in Unity 1 Answer