Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Steam Workshop - Easy Steamworks Integration

Discussion in 'Assets and Asset Store' started by FreebordMAD, Mar 22, 2017.

  1. Rajmahal

    Rajmahal

    Joined:
    Apr 20, 2011
    Posts:
    2,101
    Are leaderboards and achievements the same thing? I thought they were different things but I don't know much about them
     
  2. Freznosis

    Freznosis

    Joined:
    Jul 16, 2014
    Posts:
    298
    Download the Steamworks.NET test and example projects and study it. It includes granting achievements, leader-boards, multiplayer lobbies, and pretty much every other function of Steamworks.

    Steamworks.NET Test
    Steamworks.NET Example
     
    FreebordMAD likes this.
  3. darkgriffin

    darkgriffin

    Joined:
    Nov 2, 2009
    Posts:
    113
    Edit: My test level from the below test just showed up in the workshop search in game. I still can't get to workshop in a browser or the steam client to check that part (or manage/unsub for that matter). But it seems at least some of the below issues might just be caused by the delay in steam enabling all the switches to make workshop tick for the game. My uploading popup is now broken (I can't type any names cause of a new interface focus issue, yay for editing fields losing focus while the user tries to type text), so I can't test further. Maybe it's best to just let this simmer for 24 hours or so and get back to it tomorrow.

    Does anyone know if Steam needs a game build uploaded for the workshop to show up in the steam client? I'm hoping just running in unity is enough to test this for now till I get my interface stable for a build. But if there are any "gotchas" for that situation, I'd love to hear them. Thanks!

    ---

    Hi, I'm trying to integrate this tool, but as this is my first ever steam game, I'm a bit lost. Does anyone have any "newbie tips" on how to use this?

    My levels are being stored in folders, each with a screenshot, and the level data in binary format. (the editor I made in Unity already saves a screenshot for publishing).

    I also have not put a build on steam yet for my game, as I am still developing/redoing some basics like menu navigation. I recently had to overhaul the game menus for controller support, and am still in the process of that. So I didn't want to break anything by having to upload a new steam build every half hour or so just to test stuff for 10 seconds. ;)

    I am trying to figure out how to do the following:

    • Call the prefab popup from my editor, disabling any editing interface if/as needed. My editor has a controller enabled interface with a lot of custom navigation code, so I need to be able to jump back and fourth between the pop up and the editor's own "upload to workshop" button eventually.
    • Set the level name directly to my existing level name data. The string is stored in a global in memory on the editor objects, so I think this should be pretty easy once I figure out what to access/set on the interface. The levels have display and file names different, so the workshop name is probably best used as the display name.
    • Use the existing screenshot from the editor's previous save call, instead of the prefab popup's image creation. This is because there are several layers of editor tools that should be hidden in the rendering, and because when the user saved the level it already created the screenshot. So there's no need to bother them with creating another one.
    • Actually get this to upload to the workshop. I think this might just be a matter of steam not having my workshop enabled yet. But the steam docs are very unclear what an "in progress" or "developer only" workshop looks like, or how long the process can take. (It's been over 3 hours already if that helps.) I can't browse the workshop using steam under my app id or game listing in the steam client. So maybe it is just not enabled yet? The checklist for workshop on the admin control panel for steam is all green.
    Ideally I could also do the following, but for now I would be happy just getting the above working.
    • View, download, and instantly play other user's levels from the main menu of the game. (I think the browsing scene stand alone you included will be a good start for this process, though it's pulling nothing at the moment.)
    • Manage the user's own levels.
    • Check if a given level in the editor is a "new" or "existing" workshop item, and submit the proper way (as "Update" or as "New Workshop Item"). I'm a little lost on how to check this. Should I store this locally, or is there a better way to check if a user has submitted the level name already? (File/folder names for levels can't change in my editor unless the user edits the files directly outside the game, if that's any help in searching or asking the steam workshop if something exists already to update an existing submission with the modified level.)
    So far what actually happened is that when I pressed my workshop submit button, my editor called up the workshop pop up, though the keyboard focus was pretty shaky. It kept losing focus and losing the typed content of the user. This might be on me from my controller support code in my game editor.

    I submitted a test level anyway. The upload pop up took a while to process, then for whatever reason the game booted out of my editor scene when it reached near 100%. It might have reached it, I don't know how to look up any logs for the plugin so I am not sure what happened. My controller might have also hit the "exit editor" button in my own interface under the pop up. Since I have never seen the actual upload process I don't know what to expect from the plugin.

    There's nothing submitted to the workshop as a result though.

    I would appreciate any general help or tips regarding how to get this working. The steam docs and control panel are very new and confusing to me, so don't assume I know anything about what I am doing. No tip is "too obvious" to be helpful for me. :)
     
    Last edited: Jun 18, 2018
  4. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    First of all, sorry for the very late replies!!!
    I was very busy with my regular job and got ill later...

    What is you current state, did things start to work?

    Don't know, but I don't think you need a built.

    What exactly is you current solution and what is the problem with it. Generally, you would use the code below on your button to trigger the popup and you can close the popup to return to your previous menu by clicking the X button.
    Code (CSharp):
    1. // tell which folder you want to upload
    2.  
    3. WorkshopItemUpdate createNewItemUsingGivenFolder = new WorkshopItemUpdate();
    4. createNewItemUsingGivenFolder.ContentPath = ...;
    5. // show the Steam Workshop item upload popup
    6.  
    7. ((SteamWorkshopPopupUpload)uMyGUI_PopupManager.Instance.ShowPopup("steam_ugc_upload"))
    8.    .UploadUI.SetItemData(createNewItemUsingGivenFolder);
    For createNewItemUsingGivenFolder from the above script set createNewItemUsingGivenFolder.Name = your name.

    For createNewItemUsingGivenFolder from the above script set createNewItemUsingGivenFolder.IconPath = your icon path. Remove the button to make screenshots from the popup.

    Did something changed now after waiting? It can take up to 24h for Steam to get updated.
    Have you logged in to the Steam web page with your developer account?
    All other users see no workshop till you have published it only your developer account works.
    Try replacing the APPID in the below link with yours and see if it comes up:
    https://steamcommunity.com/app/399900/workshop/

    Try disabling the built in ESI navigation optimizer by removing the tick from SteamWorkshopUIUpload.ImproveNavigationFocus.
    upload_2018-6-27_11-10-30.png

    Please try again and the send over the Unity editor log it gives detailed information on what happens.
    Don't forget to enable debugging first (enabled in all example scripts):
    Code (CSharp):
    1. SteamWorkshopMain.Instance.IsDebugLogEnabled = true;
    upload_2018-6-27_11-13-40.png
     
  5. electricpunch

    electricpunch

    Joined:
    Feb 18, 2014
    Posts:
    22
    Hello, we purchased this asset 2 days ago and integrated to our game. It works good but preview icons of levels not appear in levels browser menu. In Unity console we see errors:
    SteamWorkshopItemNode: DownloadPreview: could not load preview image at 'https://steamuserimages-a.akamaihd....453/228658DCA2068FB8FCD2D09E57AC8861D2DBC5BB/'
    504 Gateway Timeout
    UnityEngine.Debug:LogError(Object)
    LapinerTools.Steam.UI.<DownloadPreview>c__Iterator2:MoveNext() (at Assets/LapinerTools/Steam/Workshop/Scripts/UI/SteamWorkshopItemNode.cs:554)

    Can you please help? We didn't changed anything in your code.
     
  6. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    I'm, very sorry for the late reply, could you please provide me you AppID, then I can try the demo scenes with your game's AppID.
     
  7. joferjoe

    joferjoe

    Joined:
    Feb 2, 2016
    Posts:
    95
    Just bought the asset and it looks great so far :)

    But the upload example scene whenever i upload anything i get
    "OnItemUpdateCompleted (HELLOWORLD): failed! Limit exceeded!"
    And the upload fails

    Any idea on whats causing this?

    Is it just because of space war or is this a bug?
     
    kaifu2 likes this.
  8. shubhank008

    shubhank008

    Joined:
    Apr 3, 2014
    Posts:
    107
    Hey, I have been playing around with the asset and starting to get a grasp on it.
    We are integrating it in our own UI using SteamWorkshopMain.cs class and I believe there is one big oversight you might have made in your implementation.

    As far as I am aware, SteamWorkshop/UGC supports custom folder structure (aka sub-folders) but your code only checks file in root level of contentPath and so if anyone is using sub-folders structure, it will throw out the error:
    Upload: failed! No content to upload found!

    I believe the problem code is at line 468:
    string[] filesAtContentPath = System.IO.Directory.GetFiles(p_itemData.ContentPath);

    which should expect all and sub-folders and I think should be:
    string[] filesAtContentPath = System.IO.Directory.GetFiles(p_itemData.ContentPath , "*.*", System.IO.SearchOption.AllDirectories);
     
    Last edited: Sep 28, 2018
  9. shubhank008

    shubhank008

    Joined:
    Apr 3, 2014
    Posts:
    107
    Also, we are using Steam's own workshop portal to subscribe/manage the workshop items which are then downloaded by Steam Client itself. As such, we cannot find any methods or any way to get the list of current subscribed/installed workshop items in the asset/code.
    Steam UGC provides methods for it but so far, cannot find a way to manage workshop download/install outside of your asset's inbuilt browser.
     
  10. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    In the developer portal you set the max bytes limit per item. I assume that space war allows only a few KBs. Try uploading a very small text file or an empty one. Steam might have changed the upload limits for Space War.

    Yes, correct my issue, thanks for pointing to it, fix will be implemented in next version.

    That should work by design. If you subscribe something on the portal, then Steam will not let you start the game without downloading the content. Once content is downloaded it will be shown as such in the browser.
    See SteamWorkshopMain.ParseItem and SteamWorkshopMain.IsInstalled
    Code (CSharp):
    1.  
    2.                 IsOwned = p_itemDetails.m_ulSteamIDOwner == SteamUser.GetSteamID().m_SteamID,
    3.                 ...
    4.                 IsInstalled = IsInstalled(itemState),
    5.                 IsDownloading = IsDownloading(itemState),
    6.                 IsUpdateNeeded = IsUpdateNeeded(itemState),
     
  11. shubhank008

    shubhank008

    Joined:
    Apr 3, 2014
    Posts:
    107

    Actually what I meant to ask was a manual method to access the user's subscribed workshop items so we could fetch the content path to them and preview image/url. Thats what I could not find.
    I am using SteamUGC methods of Steamworks.Net framework but even in it, the PreviewURL method is not working and returning blank (even though the workshop item has a preview image).

    So what I asked in my previous post was, does your asset provide a interface or method to access installed workshop items and their properties (mainly content path, name, preview image/url).

    Also, does the asset not support creation of curated/paid items ? Official Steam Workshop implementation guide mentions a "FileType" can be provided to classify if a item is read-to-use or curated (which can be paid). So far, I couldn't find a curated item creation way with the asset.


    Would appreciate your help on this.
     
    Last edited: Oct 5, 2018
  12. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Please check the SteamWorkshopUpdateItemFromFolderExampleStatic script. If you upload levels with the ESI plugin, then you will find an XML file 'WorkshopItemInfo.xml' created. You could scan the steam workshop item folders and load that XML files. Use SteamWorkshopMain.Instance.GetItemUpdateFromFolder to load it into a WorkshopItemUpdate class instance. Then you can use the SteamNative.m_nPublishedFileId to load all the data you need. You can also use the IconPath property to load the ESI plugin level icon.

    In the SteamWorkshopMain class you will find the line below
    Code (CSharp):
    1. Execute<CreateItemResult_t>(SteamUGC.CreateItem(SteamUtils.GetAppID(), EWorkshopFileType.k_EWorkshopFileTypeCommunity), OnCreateItemCompleted);
    k_EWorkshopFileTypeCommunity is hardcoded. You can change it to what ever type you need or make it a variable.

    I hope that helps, please followup with your progress on all this.
     
  13. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Hello. I've bought this asset a long time ago and it has been working fine. Lately, though we're having problems with it on our Mac build. We're getting this "Could not find item!" error when subscribing or unsubscribing an item. It baffles me because it works well in PC build and in Unity editor. It's only broken on the Mac build.

    While rummaging through the code, the problem is in SteamWorkshopMain.OnSubscribeCallCompleted(). Somehow, p_callback.m_eResult is k_EResultOK but p_callback.m_nPublishedFileId is 0 (zero). In a working build, p_callback.m_nPublishedFileId is the ID of the workshop item.

    I can't deduce from the code why the value is zero because this value is supposed to come from Steam. We've reported this to Valve but they're not very helpful. They told me to look at debugging here but it's not very helpful. There's nothing in IPC logs that could tell me why the value given in SteamWorkshopMain.OnSubscribeCallCompleted() is different for Mac build.

    Do you have any more suggestions on how to debug this? Have you fixed this before?
     
  14. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Sorry for the late reply. Have you found a solution already?

    I currently have no Mac to check myself.
    Have you checked when the ID gets lost?

    Are the IDs valid when the list is loaded?
    WorkshopItem.SteamNative.m_nPublishedFileId

    Is the ID ok when calling SteamWorkshopMain.Subscribe?

    Cheers
    Denis
     
  15. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    This is what I'm trying to figure out. Since it's a callback, I presume that it is invoked by Steam. I can't trace it to the source of the caller.

    Yes, they are. The list of items are being displayed before subscribing to the item so the IDs must have been loaded. I have verified this through debugging.

    Yes. It only becomes zero when SteamWorkshopMain.OnSubscribeCallCompleted() is invoked. However, p_callback.m_eResult remains k_EResultOK. Why could it be k_EResultOK when the publishFileId is zero. The code is expecting the publishFileId value.
     
  16. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Ok.
    Is your steam client up to date?
    Is the item subscribed after the call or does it return ok, but changes nothing in Steam?
     
  17. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Yes, the Steam client is up to date.

    The item would be considered Subscribed on Steam's side, but the game will show an error message "Could not find subscribed item!" When the game is restarted, the item would be shown as subscribed.

    The same thing happens on unsubscribe.
     
  18. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    I'm not behind a PC for the next days and cannot look myself right now. However, you should be able to cache the ID and reuse it when you receive a 0.
    Alternatively, you could try the Steamworks.NET support, maybe someone had it there.
     
  19. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    I see. Is it safe to cache the ID to a local variable, then on SteamWorkshopMain.OnSubscribeCallCompleted(), I'll use the local variable if the passed ID is zero? Wouldn't there be a problem if a player subscribes say two items? Can I assume that the order of invocation of SteamWorkshopMain.OnSubscribeCallCompleted() is guaranteed? If it is, I can just store the IDs on a queue and use the front of the queue for every callback.
     
  20. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Unfortunately, it is not guaranteed. This means that you need to pass the ID directly to the callback. Extend OnSubscribeCallCompleted with an CachedItemID variable. Then call the subscription method of the Steam SDK with a lambda function, which will have the same parameters as OnSubscribeCallCompleted now, inside the lamda function scope use the ID given in SteamWorkshopMain.Subscribe.

    I don't have the code here. If you can just post the content of the Subscribe and the OnSubscribeCallCompleted, methods then I can rewrite them from my phone.
     
  21. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Here it is. I added the Debug.Log() calls for debugging.

    Code (CSharp):
    1.         public bool Subscribe(PublishedFileId_t p_fileId, System.Action<WorkshopItemEventArgs> p_onSubscribed) {
    2.             if (SteamManager.Initialized) {
    3.                 SetSingleShotEventHandler("OnSubscribed" + p_fileId, ref OnSubscribed, p_onSubscribed);
    4.                 Execute<RemoteStorageSubscribePublishedFileResult_t>(SteamUGC.SubscribeItem(p_fileId),
    5.                     OnSubscribeCallCompleted);
    6.  
    7.                 return true; // request started
    8.             }
    9.  
    10.             ErrorEventArgs errorArgs = ErrorEventArgs.CreateSteamNotInit();
    11.             InvokeEventHandlerSafely(p_onSubscribed, new WorkshopItemEventArgs(errorArgs));
    12.             HandleError("Subscribe: failed! ", errorArgs);
    13.  
    14.             return false; // no request, because there is no connection to steam
    15.         }
    16.  
    17.         private void OnSubscribeCallCompleted(RemoteStorageSubscribePublishedFileResult_t p_callback,
    18.             bool p_bIOFailure) {
    19.             Debug.Log($"OnSubscribeCallCompleted p_callback.m_eResult:{p_callback.m_eResult}");
    20.             if (CheckAndLogResult<RemoteStorageSubscribePublishedFileResult_t, WorkshopItemEventArgs>(
    21.                 "OnSubscribeCallCompleted", p_callback.m_eResult, p_bIOFailure,
    22.                 "OnSubscribed" + p_callback.m_nPublishedFileId, ref OnSubscribed)) {
    23.                 lock (m_lock) {
    24.                     Debug.Log($"OnSubscribeCallCompleted p_callback.m_nPublishedFileId:{p_callback.m_nPublishedFileId}");
    25.                     if (m_items.TryGetValue(p_callback.m_nPublishedFileId, out WorkshopItem item)) {
    26.                         // update state of the cached item
    27.                         item.IsSubscribed = true;
    28.                         EItemState itemState = (EItemState) SteamUGC.GetItemState(p_callback.m_nPublishedFileId);
    29.                         item.SteamNative.m_itemState = itemState;
    30.                         item.IsInstalled = IsInstalled(itemState);
    31.                         item.IsDownloading = IsDownloading(itemState);
    32.                         item.IsUpdateNeeded = IsUpdateNeeded(itemState);
    33.                         // start download if needed
    34.                         if ((item.IsUpdateNeeded || !item.IsInstalled) &&
    35.                             SteamUGC.DownloadItem(p_callback.m_nPublishedFileId, true)) {
    36.                             if (IsDebugLogEnabled) {
    37.                                 Debug.Log("OnSubscribeCallCompleted: started download for " +
    38.                                     p_callback.m_nPublishedFileId);
    39.                             }
    40.        
    41.                             if (!m_downloadingItems.Contains(p_callback.m_nPublishedFileId)) {
    42.                                 m_downloadingItems.Add(p_callback.m_nPublishedFileId);
    43.                             }
    44.        
    45.                             // update state again
    46.                             itemState = (EItemState) SteamUGC.GetItemState(p_callback.m_nPublishedFileId);
    47.                             item.SteamNative.m_itemState = itemState;
    48.                             item.IsInstalled = IsInstalled(itemState);
    49.                             item.IsDownloading = IsDownloading(itemState);
    50.                             item.IsUpdateNeeded = IsUpdateNeeded(itemState);
    51.                         } else {
    52.                             if (IsDebugLogEnabled) {
    53.                                 Debug.Log("OnSubscribeCallCompleted: subscribed to already installed item " +
    54.                                     p_callback.m_nPublishedFileId);
    55.                             }
    56.                         }
    57.        
    58.                         // inform listeners
    59.                         if (OnSubscribed != null) {
    60.                             InvokeEventHandlerSafely(OnSubscribed, new WorkshopItemEventArgs(item));
    61.                             ClearSingleShotEventHandlers("OnSubscribed" + p_callback.m_nPublishedFileId,
    62.                                 ref OnSubscribed);
    63.                         }
    64.                     } else {
    65.                         LogItems();
    66.                         ErrorEventArgs errorArgs = new ErrorEventArgs("Could not find item!");
    67.                         HandleError("OnSubscribeCallCompleted: failed! ", errorArgs);
    68.                         if (OnSubscribed != null) {
    69.                             CallSingleShotEventHandlers("OnSubscribed" + p_callback.m_nPublishedFileId,
    70.                                 new WorkshopItemEventArgs(errorArgs), ref OnSubscribed);
    71.                         } // call single shot event with error
    72.                     }
    73.                 }
    74.             }
    75.         }
     
  22. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Try the below. Note code is typed on a phone => might not compile please either correct or revert.

    Code (CSharp):
    1.         public bool Subscribe(PublishedFileId_t p_fileId, System.Action<WorkshopItemEventArgs> p_onSubscribed) {
    2.             if (SteamManager.Initialized) {
    3.                 SetSingleShotEventHandler("OnSubscribed" + p_fileId, ref OnSubscribed, p_onSubscribed);
    4.                 Execute<RemoteStorageSubscribePublishedFileResult_t>(SteamUGC.SubscribeItem(p_fileId),
    5.                     (RemoteStorageSubscribePublishedFileResult_t p_callback, bool p_bIOFailure) => { OnSubscribeCallCompleted(p_callback, p_bIOFailure, p_fileId); });
    6.  
    7.                 return true; // request started
    8.             }
    9.  
    10.             ErrorEventArgs errorArgs = ErrorEventArgs.CreateSteamNotInit();
    11.             InvokeEventHandlerSafely(p_onSubscribed, new WorkshopItemEventArgs(errorArgs));
    12.             HandleError("Subscribe: failed! ", errorArgs);
    13.  
    14.             return false; // no request, because there is no connection to steam
    15.         }
    16.  
    17.         private void OnSubscribeCallCompleted(RemoteStorageSubscribePublishedFileResult_t p_callback,
    18.             bool p_bIOFailure, PublishedFileId_t p_fileId) {
    19.  
    20.             // use cached value as it might get lost due to a Steam bug on MacOS
    21.             if (p_callback.m_nPublishedFileId == 0)
    22.             {
    23.                 p_callback.m_nPublishedFileId = p_fileId;
    24.             }
    25.  
    26.             Debug.Log($"OnSubscribeCallCompleted p_callback.m_eResult:{p_callback.m_eResult}");
    27.             if (CheckAndLogResult<RemoteStorageSubscribePublishedFileResult_t, WorkshopItemEventArgs>(
    28.                 "OnSubscribeCallCompleted", p_callback.m_eResult, p_bIOFailure,
    29.                 "OnSubscribed" + p_callback.m_nPublishedFileId, ref OnSubscribed)) {
    30.                 lock (m_lock) {
    31.                     Debug.Log($"OnSubscribeCallCompleted p_callback.m_nPublishedFileId:{p_callback.m_nPublishedFileId}");
    32.                     if (m_items.TryGetValue(p_callback.m_nPublishedFileId, out WorkshopItem item)) {
    33.                         // update state of the cached item
    34.                         item.IsSubscribed = true;
    35.                         EItemState itemState = (EItemState) SteamUGC.GetItemState(p_callback.m_nPublishedFileId);
    36.                         item.SteamNative.m_itemState = itemState;
    37.                         item.IsInstalled = IsInstalled(itemState);
    38.                         item.IsDownloading = IsDownloading(itemState);
    39.                         item.IsUpdateNeeded = IsUpdateNeeded(itemState);
    40.                         // start download if needed
    41.                         if ((item.IsUpdateNeeded || !item.IsInstalled) &&
    42.                             SteamUGC.DownloadItem(p_callback.m_nPublishedFileId, true)) {
    43.                             if (IsDebugLogEnabled) {
    44.                                 Debug.Log("OnSubscribeCallCompleted: started download for " +
    45.                                     p_callback.m_nPublishedFileId);
    46.                             }
    47.  
    48.                             if (!m_downloadingItems.Contains(p_callback.m_nPublishedFileId)) {
    49.                                 m_downloadingItems.Add(p_callback.m_nPublishedFileId);
    50.                             }
    51.  
    52.                             // update state again
    53.                             itemState = (EItemState) SteamUGC.GetItemState(p_callback.m_nPublishedFileId);
    54.                             item.SteamNative.m_itemState = itemState;
    55.                             item.IsInstalled = IsInstalled(itemState);
    56.                             item.IsDownloading = IsDownloading(itemState);
    57.                             item.IsUpdateNeeded = IsUpdateNeeded(itemState);
    58.                         } else {
    59.                             if (IsDebugLogEnabled) {
    60.                                 Debug.Log("OnSubscribeCallCompleted: subscribed to already installed item " +
    61.                                     p_callback.m_nPublishedFileId);
    62.                             }
    63.                         }
    64.  
    65.                         // inform listeners
    66.                         if (OnSubscribed != null) {
    67.                             InvokeEventHandlerSafely(OnSubscribed, new WorkshopItemEventArgs(item));
    68.                             ClearSingleShotEventHandlers("OnSubscribed" + p_callback.m_nPublishedFileId,
    69.                                 ref OnSubscribed);
    70.                         }
    71.                     } else {
    72.                         LogItems();
    73.                         ErrorEventArgs errorArgs = new ErrorEventArgs("Could not find item!");
    74.                         HandleError("OnSubscribeCallCompleted: failed! ", errorArgs);
    75.                         if (OnSubscribed != null) {
    76.                             CallSingleShotEventHandlers("OnSubscribed" + p_callback.m_nPublishedFileId,
    77.                                 new WorkshopItemEventArgs(errorArgs), ref OnSubscribed);
    78.                         } // call single shot event with error
    79.                     }
    80.                 }
    81.             }
    82.         }
     
    Last edited: Nov 24, 2018
  23. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Thanks! It's ok. I can handle a little compile error. Will let you know once I've integrated it.
     
    FreebordMAD likes this.
  24. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    It's working now. I'm able to subscribe and unsubcribe. The only correction is this line:
    Code (CSharp):
    1.             if (p_callback.m_nPublishedFileId.m_PublishedFileId == 0) {
    2.                 p_callback.m_nPublishedFileId = p_fileId;
    3.             }
    However, there are still other inconsistencies like WorkshopItem.SteamNative.m_details.m_rgchTags containing incomplete tags. Again, it's only happening in Mac build. It's so frustrating.
     
  25. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    I'm sorry that this is such a pain for you. Can you give me me more details regarding the m_rgchTags problem? Anything I can look up for you?

    You could also try to get help here (official Steamworks.NET Steam thread):
    https://steamcommunity.com/groups/steamworks/discussions/0/666827974770212954/

    By the way thanks for trying out the other OS X fix, I will add it to the next release.
     
  26. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    The tags returned are missing some characters. For example our system expects "language" tag but the returned one is "uage". I've checked the tags of the workshop item and they are correct.

    I tried updating Steamworks.NET to 11.0 but I'm getting this error: https://github.com/rlabrecque/Steamworks.NET/issues/180. So I reverted for now until this is fixed.
     
  27. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Ok, let's wait for the Steamworks.NET update. Please revert once you have tested it. I can dig out my old Mac and try helping if it is not fixed with version 12. Ok?
     
  28. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Have you tested it in Mac? Were you able to replicate it? I'm using El Capitan Version 10.11.6.
     
  29. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Not yet, I was hoping for Steamworks.NET 12 to be released, but it seems to take time...
    I will dig out my MacMini then and try to get it updated. However, it might take quite some time, since this things is super slow and getting it up to date will take some days already...
     
  30. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Yeah, the update is taking long. If it works on your end, I'd like to know what version of Steamworks.NET you are using.
     
  31. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Finally after buying a new cable (I had not a single device in my whole house left supporting DVI) - it also took me two hours to guess the password. Sorry for it taking so long.
    My next steps will be to reproduce the m_PublishedFileId == 0 error, then I will check for m_rgchTags.
    Regarding m_rgchTags can you please already tell me your AppID and the m_PublishedFileId that I should look for and compare in Win and Mac.
     
  32. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Hi @davenirline

    I could not reproduce any issues (not even your subscribe problem) with
    ESI Steam Workshop: v1.24
    (Steamwork.NET 10)
    MacOS: 10.10.1
    Steam Client: Nov 26 2018
    Unity: 5.2.3.f1

    Works with Unity Editor and built.

    I will now update my Mac to 10.10.5, this is the highest it supports and retry.
    [EDIT:] also the update didn't help to reproduce your problem.

    Maybe it has something to do with your app, I'm testing with SpaceWar. Can you confirm that if you get a fresh download from the Asset Store, then you have the same problems on the SpaceWar Workshop items in the demo scenes?
     
    Last edited: Jan 4, 2019
  33. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    I will check.
     
  34. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Btw, we're always using the latest of Unity. Right now, we're using Unity 2018.3.0f2. I have yet to check on Mac if the build with this new version of Unity would work.
     
  35. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Hi, any update on this from your side?
     
  36. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Still didn't work. I'm still getting clipped tags. I've made a workaround, though. I made our game to consider items with "uage" as a language mod. It's an ugly hack but it works.
     
  37. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    If you could give me your AppID and your FileID, the I could try myself, otherwise I cannot reproduce any issues, maybe my Mac is to old for this.
     
  38. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    App ID: 672630

    File ID: Not sure how to get this but we save Steam data in a local file. Here's one of them:

    SteamId="1425235658" Name="Traditional Chinese Localization 繁體中文 V.1.0.3"

    I hope that's the File ID.
     
  39. Jae-Hyun-Park

    Jae-Hyun-Park

    Joined:
    Aug 11, 2015
    Posts:
    1
    In your item upload sample scene,
    I got error "OnItemUpdateCompleted (1111): failed! Limit exceeded!"
    Item file size is very small 8KB.
    Do you know why?
     
  40. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Sound like your Workshop is not setup correctly, see documentation:

    • Login to partner.steamgames.com and open your game's App Admin page.
    • Under Technical Tools hit Edit Steamworks Settings.
    • Go to Application->Steam Cloud and set your data quotas e.g. 1048576000 for data per user and 1000 for number of files.
    • [optional] Tick Enable cloud support for developers only to hide your Workshop work until it is finished for public use.
    • Go to Workshop->General and tick Enable ISteamUGC for file transfer.
    • Go to Publish and apply your changes.
    • Steam might need a few hours for the changes to be applied -> be patient if it doesn't start to work instantly.

    http://www.freebord-game.com/index.php/steam-workshop-easy-steamworks-integration#doc_v1_00_link
    upload_2019-2-14_21-8-38.png
     
  41. Radu392

    Radu392

    Joined:
    Jan 6, 2016
    Posts:
    210
    Hi, your asset works pretty well! I can't find any information on how to get the path to where items were downloaded by the user though, using the 'Subscribe' button. I know it's in 'Steam\steamapps\workshop\content', but what method returns that?
     
  42. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Thanks for using ESI!

    Check the SteamWorkshopBrowseExampleStatic script.
    What you need is the WorkshopItem.InstalledLocalFolder property.
    (http://www.freebord-game.com/EasySt...ols_1_1_steam_1_1_data_1_1_workshop_item.html)

    To get an instance of the WorkshopItem you can subscribe to the SteamWorkshopUIBrowse.Instance.OnPlayButtonClick event.

    See also the SteamWorkshopUpdateOwnedItemExampleStatic script to see how you can load a list of your owned/subscribed items.

    Don't hesitate to revert with further questions
     
  43. timothy92

    timothy92

    Joined:
    Mar 7, 2016
    Posts:
    12
    Hey Denis

    I bought the level editor which is awesome and I've found really easy to implement, but I'm struggling with implementing this asset into my game Jumps

    This is what I've got so far, just from copy pasting code from the documentation

    Code (CSharp):
    1. public void UploadItem()
    2.     {
    3.         string dummyItemContentFolder = Path.Combine(Application.persistentDataPath, "DummyItemContentFolder" + System.DateTime.Now.Ticks); // use DateTime.Now.Ticks to create a unique folder for each upload
    4.         if (!Directory.Exists(dummyItemContentFolder)) { Directory.CreateDirectory(dummyItemContentFolder); }
    5.  
    6.         // create dummy content to upload
    7.         string dummyItemContentStr =
    8.             "Save your item/level/mod data here.\n" +
    9.             "It does not need to be a text file. Any file type is supported (binary, images, etc...).\n" +
    10.             "You can save multiple files, Steam items are folders (not single files).\n";
    11.         File.WriteAllText(Path.Combine(dummyItemContentFolder, "ItemData.txt"), dummyItemContentStr);
    12.  
    13.         // tell which folder you want to upload
    14.         WorkshopItemUpdate createNewItemUsingGivenFolder = new WorkshopItemUpdate();
    15.         createNewItemUsingGivenFolder.ContentPath = dummyItemContentFolder;
    16.  
    17.         // show the Steam Workshop item upload popup
    18.         ((SteamWorkshopPopupUpload)uMyGUI_PopupManager.Instance.ShowPopup("steam_ugc_upload"))
    19.            .UploadUI.SetItemData(createNewItemUsingGivenFolder);
    20.     }
    I call this function in the LE_ExampleEditor scene after creating a level, how should I modify this function so that it uploads my level? and once I've downloaded a level via the popup workshop browser, how do I load it to play?

    Thank you
     
  44. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Hi, check the attached script for uploading. This example is part of the file selection extension. It will let you choose from one of your saved levels. Alternatively replace the dummyItemContentStr with your saved level string.

    Use LE_LevelDatabase_SteamWorkshop constructor as below to define which levels to load.
    Code (CSharp):
    1. // load from local levels
    2. LE_LevelEditor.Extensions.LE_ExtensionInterface.FileSelectionInstance.LevelDB = new LE_LevelEditor.Extensions.LE_LevelDatabase_SteamWorkshop();
    3.  
    4. // load from downloaded levels - you need to find the Steam folder first
    5. LE_LevelEditor.Extensions.LE_ExtensionInterface.FileSelectionInstance.LevelDB = new LE_LevelEditor.Extensions.LE_LevelDatabase_SteamWorkshop(new string[]{ "c:\\Games\\Steam\\SteamApps\\workshop\\content\\537340\\" });
     

    Attached Files:

    Last edited: Aug 17, 2019
  45. timothy92

    timothy92

    Joined:
    Mar 7, 2016
    Posts:
    12
    Thank you, I'm getting closer to full implementation, slowly

    How do I find the Steam workshop content folder consistently? For example the folder is located at "D:/Program Files (x86)/Steam/steamapps/workshop/content/544310" on my computer but it could be different for others, e.g they could have their files on a different drive.

    It seems dodgey hard coding the file path.

    Also I'm still struggling to understand how to load downloaded levels with that code you gave me. ()
    Screenshot_1.png
    The documentation says nothing about implementing loading downloaded levels through the popup (if it does, it's escaped my search) and I don't know if its a lack of common programming sense or if I'm stupid but I've been trying to figure out how to do this for many hours and I really need your help.

    Thank you for your time
     
    Last edited: Aug 11, 2019
  46. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Hi Timothy,

    to save your and everybody else time, I have updated the example script.

    This code snipped uses the new method that you need to add to the SteamWorkshopMain class.
    Code (CSharp):
    1.         // use this line to allow loading levels stored in the game installation folder or the workshop download folder
    2.         LE_LevelEditor.Extensions.LE_ExtensionInterface.FileSelectionInstance.LevelDB = new LE_LevelEditor.Extensions.LE_LevelDatabase_SteamWorkshop(new string[]{ Application.persistentDataPath, SteamWorkshopMain.Instance.GetAppsWorkshopRootFolderPath() });
    Add this method to the SteamWorkshopMain class, using at the top of the cs file, method in the class:
    Code (CSharp):
    1. using Path = System.IO.Path;
    2.  
    3.  
    4.  
    5.         /// <summary>
    6.         /// Returns the workshop root folder of the current active game.
    7.         /// For example: c:\Games\Steam\steamapps\workshop\content\399900\
    8.         /// Returns null if Steam is not initialized.
    9.         /// </summary>
    10.         /// <returns>the workshop root folder of the current active game.
    11.         /// For example: c:\Games\Steam\steamapps\workshop\content\399900\
    12.         /// <c>null</c> if Steam is not initialized.</returns>
    13.         public string GetAppsWorkshopRootFolderPath()
    14.         {
    15.             if (SteamManager.Initialized)
    16.             {
    17.                 string appInstallFolder = "";
    18.                 SteamApps.GetAppInstallDir(SteamUtils.GetAppID(), out appInstallFolder, 2048);
    19.                 string steamAppsFolder = appInstallFolder.Substring(0, appInstallFolder.ToLowerInvariant().IndexOf("steamapps") + 9);
    20.                 return Path.Combine(Path.Combine(Path.Combine(steamAppsFolder, "workshop"), "content"), SteamUtils.GetAppID().m_AppId.ToString());
    21.             }
    22.             else
    23.             {
    24.                 return null;
    25.             }
    26.         }
    Also replace the LE_LevelDatabase_SteamWorkshop class with the attached.

    Use the code below from the example script to load a level in game mode.
    Code (CSharp):
    1.             LE_FileSelectionHelpers.SelectLevel(this, "Play Level", "Which level do you want to play?", (int p_selectedLevelIndex, LevelFile[] p_levelFiles)=>
    2.                 {
    3.                     // get level .txt file from folder and play it
    4.                     LE_ExtensionInterface.FileSelectionInstance.ReloadLevelName = p_levelFiles[p_selectedLevelIndex].PathData;
    5. #if UNITY_5_3_OR_NEWER
    6.                     SceneManager.LoadScene("LE_ExampleGame");
    7. #else
    8.                     Application.LoadLevel("LE_ExampleGame");
    9. #endif
    10.                 });
    Revert with further questions if needed.
     

    Attached Files:

    timothy92 likes this.
  47. KUNGENN

    KUNGENN

    Joined:
    Jun 8, 2017
    Posts:
    4
    Whenever I try to upload a file I get "OnCreateItemCompleted: failed! Called method busy - action not taken!".
    Do you know what I did wrong?
     
  48. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    Hi, sounds like Steam being busy. Are you sure that you are not calling the upload method twice? Could be e.g. due to OnGUI or Coroutine usage. Could it be that you are doing some other Steam stuff in parallel?
    Also, logout and restart Steam might help.
     
  49. KUNGENN

    KUNGENN

    Joined:
    Jun 8, 2017
    Posts:
    4
    EDIT: I fixed it. ISteamUGC wasn't enabled in steamworks, the site was translated to my language so i checked the wrong box :) I'll just leave the original text down there for others to read

    This is the code I use for uploading, almost everything is from the example except that the Save() function creates the savefile. The folder is created correctly but just isn't uploaded. The only other place I reference your tool is when you want to browse levels from the main menu. I have the steammanager on a gameobject but other than that I don't have any other steam stuff, so I dont know what could cause this.

    Code (CSharp):
    1. public void OpenSaveMenu()
    2.     {
    3.         // enable debug log
    4.         SteamWorkshopMain.Instance.IsDebugLogEnabled = true;
    5.  
    6.         // everything inside this folder will be uploaded with your item
    7.         string dummyItemContentFolder = Path.Combine(Application.persistentDataPath, "Level" + System.DateTime.Now.Ticks); // use DateTime.Now.Ticks to create a unique folder for each upload
    8.         if (!Directory.Exists(dummyItemContentFolder)) { Directory.CreateDirectory(dummyItemContentFolder); }
    9.  
    10.         File.WriteAllText(Path.Combine(dummyItemContentFolder, "new level"), Save().ToString());
    11.  
    12.         // tell which folder you want to upload
    13.         WorkshopItemUpdate createNewItemUsingGivenFolder = new WorkshopItemUpdate();
    14.         createNewItemUsingGivenFolder.ContentPath = dummyItemContentFolder;
    15.  
    16.         // show the Steam Workshop item upload popup
    17.         ((SteamWorkshopPopupUpload)uMyGUI_PopupManager.Instance.ShowPopup("steam_ugc_upload")).UploadUI.SetItemData(createNewItemUsingGivenFolder);
    18.  
    19.     }
     
    Last edited: Nov 19, 2019
    FreebordMAD likes this.
  50. FreebordMAD

    FreebordMAD

    Joined:
    Mar 15, 2013
    Posts:
    633
    I'm glad it works now!