Steamworks Workshop Implementation?

Hi All,

I was wondering if UE4 has all the functions and implementation of SteamWorks Workshop? Such as uploading a file etc. Has anyone done this yet and how it can be integrated into a project?

My plan is to have a front end UMG menu, and upload a custom-made level created with my in-game level editor straight to Steam Workshop via the backend using C++. Is this possible as it stands in UE4 or will I need to do some custom coding in order to get this working?

Cheers,
Jon

Hi Shepard,

I’ve looked through the wiki and documentation but not seeing anything specific to Steam Workshop and uploading custom content to the workshop.

Cheers,
Jon

woops My bad , thats for multiplayer lol.

You’ll need to use the Steam SDK from valve and use that for workshop uploads, Yes that means you’ll have to write your own code for that . I suggest asking the ARK Survival evolved devs since they made a upload to steam button in their customised UE editor.

https://forums.unrealengine.com/forumdisplay.php?70-ARK-Survival-Evolved

I see, ok I’ll throw them a message and see what comes back. I’m looking to get something implemented seamlessly with an in-game menu, so hopefully since they have created custom editor functionality then I should be able to do something similar in-game.

Thanks for the info.

Cheers,
Jon

Any news on this? Would be nice to know if unreal engine 4 can be used to upload content to steam workshop…

Unfortunately i haven’t heard anything back from the ARK guys. And i haven’t looked into this too much yet but will be having a look in a few weeks i expect as i get some other tasks out of the way.

I see, thanks.

I actually did something like this a while ago, its pretty straight forward. What I achieved in my little project:

  • Get count of subscribed items in the workshop
  • Get the Workshop Item IDs
  • Get the name of a subscribed item
    If you take a look at the Steamworks API docs, you see its pretty easy to extend that stuff yourself. A bit of explaining:
    For every thing I describe here, you’ll need the steamapi.h because the OnlineSubsystem wrappers don’t support Workshop (UGC - User Generated Content) yet, so you need to put

#include "ThirdParty/Steamworks/Steamv132/sdk/public/steam/steam_api.h"

in the piece of code where you trying to use the Steam things. I nearly done some of the functions inside a blueprint function library so I can use WOrkshop functions from Blueprints. I’m not putting the Headers here, because it should be self-explaining. Getting the subscribed item count is really easy:



int32 USteamBlueprintFunctions::GetSubscribedItemCount()
{
    if (SteamAPI_Init())
    {
        return SteamUGC()->GetNumSubscribedItems();
    }
    else
    {
        return 0;
    }
}


Notice that SteamUGC() is the object to interact with if you want Workshop things. if the SteamAPI_Init() is false, then Steam is not running, so its just a crash safe thing.
Getting the Steam workshop item ids of things you subcribed is pretty easy also:



TArray<int32> USteamBlueprintFunctions::GetSubscribedItemIDs()
{
    TArray<int32> outArray;


    if (SteamAPI_Init())
    {
        PublishedFileId_t fileIds[16];
        int32 subItems = SteamUGC()->GetSubscribedItems(fileIds, 16);
        
        for (int i = 0; i < subItems; i++)
        {
            PublishedFileId_t id = fileIds*;
            outArray.Add(id);
        }
    }
    else
    {
        outArray.Add(0);
    }
    return outArray;
}


You see, if the SteamAPI is valid, it uses SteamUGC()->GetSubscribedItems() and puts the output file ids into the PublishedFileID_t array. The 16 is a predefined number of a maximum amount of results you want to get. Then I just add every id into the Unreal compatible array and return it.
To get for example the name of an workshop item, you need to dig a bit deeper. This is not made in blueprints by me yet, so I just show what I made inside my GameInstance so it runs at game start.
Getting Information from UGC content requests, as Steamworks says, a Callback because this one is latent, which means, it sends the request to the server, and you can only proceed if that is done. The header contents for this:



    void OnUGCRequestUGCDetails(SteamUGCRequestUGCDetailsResult_t *pResult, bool bIOFailure);
    CCallResult<USteamGameInstance, SteamUGCRequestUGCDetailsResult_t> m_callResultUGCRequestDetails;


The source for that:



    SteamAPICall_t hSteamAPICall = SteamUGC()->RequestUGCDetails(fileids[0], 20);
    m_callResultUGCRequestDetails.Set(hSteamAPICall, this, &USteamGameInstance::OnUGCRequestUGCDetails);


Notice that fileids is an array with subscribed file ids as described above, and I am just doing this for the first subscribed item, thats why it only gets index 0. With a for each loop, you could do this for all. The 20 is the max Age in seconds, which is like a timeout. If you request data and do not get an answer for X seconds, it will just return nothing. It stores this Call inside a SteamAPICall_t type variable, and this is all well-documentated on the Steamworks API docs. So the void OnUGCRequestUGCDetails is just a method I define which will be executed once the result was received. Which arguments those things take is also documented at Steamworks. Then in the code the m_callResultUGCRequestDetails.Set is just a function to set up a callback, taking the API call, the class (this in this case :D) and the method we want to call when we received the answer, and thats the method we defined earlier. Code of this method:



void USteamGameInstance::OnUGCRequestUGCDetails(SteamUGCRequestUGCDetailsResult_t *pResult, bool bIOFailure)
{
    if (bIOFailure)
    {
        return;
    }


    SteamUGCDetails_t hUGCDetails = pResult->m_details;
    GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Green, hUGCDetails.m_rgchTitle);
}


If we have an IO failure, we just return. If not, we store the details in the variable hUGCdetails, and then, you can pretty much do anything. I just did a debug message showing the title. Visual Studio will help you getting the variables out of hUGCDetails, because that contains a lot more than just the title. Hope i helped :slight_smile:

Wow, that’s more information than I was expecting from anyone. Thanks iUltimateLP! That’s amazing information! I’ll be looking into this shortly so you have saved myself and other developers a whole bunch of time and research!

Edit: It may be worth adding your information to the Wiki.

Yeah, I’ll do this once I found a small amout of time :smiley: Glad I could help

I wrote a “small” wiki article about this here: A new, community-hosted Unreal Engine Wiki - Announcements and Releases - Unreal Engine Forums

Thanks a lot!

Amazing stuff! Thanks iUltimateLP!

Hi Guys. I am trying to set this up and I have hit a brick wall. When I try to compile my blueprint function.



FString USteamworksLibrary::getPlayerSteamName() {
	FString SteamName; 
	if (SteamAPI_Init())
	{
		SteamName = "name";
	}
	else
	{
		SteamName = "Anon";
	}
	return SteamName;
}


The definition under the header file is



UCLASS()
class MUSICALRANGE_API USteamworksLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
		/*
		*Gets the Steam Nickname of the player
		*/
		UFUNCTION(BlueprintPure, Category = "Steamworks")
		static FString getPlayerSteamName();

};


I get the following error
Error SteamworksLibrary.cpp.obj : error LNK2019: unresolved external symbol __imp_SteamAPI_Init referenced in function “private: static class FString __cdecl USteamworksLibrary::getPlayerSteamName(void)” (?getPlayerSteamName@USteamworksLibrary@@CA?AVFString@@XZ)

I’ve been looking online for help, but it seems to be like the cause can be many different things, and I am baffled by this.
I am using Unreal Engine 4.14, custom compiled. Steamworks version is 132.

I also got a bunch of errors about Steamworks using strncpy, so I went ahead and changed them out in favor of strncpy_s.

EDIT.
Solved by adding the Dependencies that the tutorial said to add.



		PublicDependencyModuleNames.AddRange(new string] { "Core", 
            "CoreUObject",
            "Engine",
            "InputCore",
			"OnlineSubsystem", //From https://wiki.unrealengine.com/Steam_workshop
            "OnlineSubsystemUtils",
            "Steamworks"            //*/
        });


Thanks,

Hey guys. I am trying to make use of this tutorial to create a function using Steam_Callbacks to pause the game if the Steam overlay is enabled. However, I am stuck with the error “Runnable thread OnlineAsyncTaskThreadSteam DefaultInstance crashed.”

The Full Log File

The Header File

The CPP file

Basically, in the CPP, I get the callback to fire out


void FSteamworksCallbackAsync::OnSteamOverlayActive(GameOverlayActivated_t *CallbackData) {


Then, I copy the callback data. Someone said that it might get deleted to soon creating errors. Then I sometimes get to see the function go all the way to


			UE_LOG(LogSteamworks, Log, TEXT("Calling Event OnSteamOverlayIsActive"));
			MusicalRangeGameInstance->OnSteamOverlayIsActive(IsOverlayActive);
			UE_LOG(LogSteamworks, Log, TEXT("Music Should be paused now"));


I think I even see the game pause but a few moments later, it just crashes out. And I see the error:



[2017.02.28-16.09.42:373][638]LogThreadingWindows:Error: Runnable thread OnlineAsyncTaskThreadSteam DefaultInstance crashed.
[2017.02.28-16.09.42:373][638]LogWindows:Error: === Critical error: ===
[2017.02.28-16.09.42:373][638]LogWindows:Error: 
[2017.02.28-16.09.42:373][638]LogWindows:Error: Assertion failed: 0 [File:D:\UnrealEngine\UnrealEngine4-14\Engine\Source\Runtime\Core\Private\Windows\WindowsPlatformAtomics.cpp] [Line: 16] 
[2017.02.28-16.09.42:373][638]LogWindows:Error:


Thanks for any help.

Hi Motanum,

Are you able to launch the game via the Local Windows Debugger, place breakpoints throughout your CPP file and step through your code in visual studio to see which part of your code is causing the crash?

Also make sure you check where appropriate:



if(bIOFailure)
{
// log failure
     return;
}


Cheers,
Jon

I have solved my problem by using AsyncTask() before firing the blueprint node MusicalRangeInstance->OnSteamOverlayIsActive();

I have written an extensive guide on how to get Steam Overlay to pause the game.

The idea was that this would help me better understand Steamworks and get some practice for the Workshop Setup.

Cheers!

Awesome that you fixed it, I bet that AsyncTask thing will help other people as well!

And I am back here.

I am trying to follow the Item Creation guide on Steamworks Steam Workshop Implementation Guide (Steamworks Documentation)

But I am having problems with the line



SteamAPICall_t CreateItem( AppId_t nConsumerAppId, EWorkshopFileType eFileType )


So, I wrote the line



	SteamAPICall_t CreateItem(MRAppID, k_EWorkshopFileTypeCommunity); 


Where MRAppID was declared in the Header file as AppId_t MRAppID; And in the constructor of the class containting the function USteamManager is



	MRAppID = AppId_t(547670);


But I get the following error when trying to compile.



Error D:\Dropbox\MusicalRange-4.14\Source\MusicalRange\SteamManager.cpp(94) : error C2440: 'initializing': cannot convert from 'initializer list' to 'SteamAPICall_t'
Error D:\Dropbox\MusicalRange-4.14\Source\MusicalRange\SteamManager.cpp(94) : note: The initializer contains too many elements


And the comma in “(MRAppID, k_EWorkshopFileTypeCommunity)” highlights an error:



     AppId_t USteamManager::MRAppID

     Error: Expected a ')'


It also throws me the error if I try to just pass the function the AppID directly as 547670.

So, how am I supposed to actually pass the AppID of the game in the function?

Thanks,

EDIT. SOLVED I THINK, Gotta recompile and test.
SteamUGC()->CreateItem(MRAppID, k_EWorkshopFileTypeCommunity);