Skip to content

Commit

Permalink
Fix for Non-Public Mod Publishing (Tested) (#4326)
Browse files Browse the repository at this point in the history
  • Loading branch information
Solxanich committed Sep 13, 2024
1 parent eb67fa4 commit 56a6137
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 172,11 @@ internal void AddNonModOwnerPublishWarning(UIList uiList)
queryType = QueryType.SearchDirect
};

if (!WorkshopHelper.TryGetModDownloadItemsByInternalName(query, out List<ModDownloadItem> mods) || mods.Count != 1 || mods[0] == null) {
if (!WorkshopHelper.TryGetModDownloadItem(_dataObject.Name, out var mod) || mod == null) {
return;
}

ulong existingAuthorID = ulong.Parse(mods[0].OwnerId);
ulong existingAuthorID = ulong.Parse(mod.OwnerId);
if (existingAuthorID == 0 || existingAuthorID == Steamworks.SteamUser.GetSteamID().m_SteamID) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion patches/tModLoader/Terraria/ModLoader/UI/UIModPackItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 379,7 @@ private List<ModPubId_t> GetModPackBrowserIds()
}

var query = new QueryParameters() { searchModSlugs = _mods };
if (!WorkshopHelper.TryGetPublishIdByInternalName(query, out var modIds))
if (!WorkshopHelper.TryGetGroupPublishIdsByInternalName(query, out var modIds))
return new List<ModPubId_t>(); // query failed. TODO, actually show an error UI instead

var output = new List<ModPubId_t>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 160,6 @@ public struct QueryParameters
public enum QueryType
{
SearchAll,
SearchDirect
SearchDirect,
SearchUserPublishedOnly
}
26 changes: 20 additions & 6 deletions patches/tModLoader/Terraria/Social/Steam/SteamedWraps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,24 246,38 @@ public static EUGCQuery CalculateQuerySort(QueryParameters qParams)

public static SteamAPICall_t GenerateAndSubmitModBrowserQuery(uint page, QueryParameters qP, string internalName = null)
{
if (SteamClient) {
UGCQueryHandle_t qHandle = SteamUGC.CreateQueryAllUGCRequest(CalculateQuerySort(qP), EUGCMatchingUGCType.k_EUGCMatchingUGCType_Items, new AppId_t(thisApp), new AppId_t(thisApp), page);
var qHandle = GetQueryHandle(page, qP);
if (qHandle == default)
return new();

if (SteamClient) {
ModifyQueryHandle(ref qHandle, qP);
FilterByInternalName(ref qHandle, internalName);

return SteamUGC.SendQueryUGCRequest(qHandle);
}
else if (SteamAvailable) {
UGCQueryHandle_t qHandle = SteamGameServerUGC.CreateQueryAllUGCRequest(CalculateQuerySort(qP), EUGCMatchingUGCType.k_EUGCMatchingUGCType_Items, new AppId_t(thisApp), new AppId_t(thisApp), page);

else { // assumes SteamAvailable as GetQueryHandle already checks this and is a required pre-req
ModifyQueryHandle(ref qHandle, qP);
FilterByInternalName(ref qHandle, internalName);

return SteamGameServerUGC.SendQueryUGCRequest(qHandle);
}
}

return new();
public static UGCQueryHandle_t GetQueryHandle(uint page, QueryParameters qP)
{
// To find unlisted / private / friends only mods on Steam Workshop that user can see but QueryAll does not, we have to side step to a custom query. - Solxan, July 30 2024
if (SteamClient && qP.queryType == QueryType.SearchUserPublishedOnly) {
return SteamUGC.CreateQueryUserUGCRequest(SteamUser.GetSteamID().GetAccountID(), EUserUGCList.k_EUserUGCList_Published, EUGCMatchingUGCType.k_EUGCMatchingUGCType_Items, EUserUGCListSortOrder.k_EUserUGCListSortOrder_CreationOrderDesc, new AppId_t(thisApp), new AppId_t(thisApp), page);
}

// These will only return visibility = public - Solxan, July 30 2024
if (SteamClient)
return SteamUGC.CreateQueryAllUGCRequest(CalculateQuerySort(qP), EUGCMatchingUGCType.k_EUGCMatchingUGCType_Items, new AppId_t(thisApp), new AppId_t(thisApp), page);
else if (SteamAvailable)
return SteamGameServerUGC.CreateQueryAllUGCRequest(CalculateQuerySort(qP), EUGCMatchingUGCType.k_EUGCMatchingUGCType_Items, new AppId_t(thisApp), new AppId_t(thisApp), page);

return default;
}

public static void FetchPlayTimeStats(UGCQueryHandle_t handle, uint index, out ulong hot, out ulong downloads)
Expand Down
80 changes: 43 additions & 37 deletions patches/tModLoader/Terraria/Social/Steam/WorkshopHelper.TML.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 74,19 @@ internal static bool TryGetModDownloadItem(string modSlug, out ModDownloadItem i
{
item = null;

var query = new QueryHelper.AQueryInstance(new QueryParameters() { searchModSlugs = new string[] { modSlug } });
if (!query.TrySearchByInternalName(out var items))
var query = new QueryHelper.AQueryInstance(new QueryParameters() { queryType = QueryType.SearchDirect });
if (!query.TrySearchByInternalName(modSlug, out item))
return false;

item = items[0];
return item != null; // TODO, return value is ambiguous between a connection error and the mod not existing on workshop, currently both are logged as an error and the item is skipped
if (item == null) {
// search of all mods that were published by this user - Does not work with co-published/non-owner
// this should catch private / friends-only visibility
query.queryParameters.queryType = QueryType.SearchUserPublishedOnly;
if (!query.TrySearchByInternalName(modSlug, out item))
return false;
}

return true;
}

// Should this be in SteamedWraps or here?
Expand All @@ -94,11 101,13 @@ internal static bool GetPublishIdLocal(TmodFile modFile, out ulong publishId)
}

/////// Used for Publishing ////////////////////
internal static bool TryGetPublishIdByInternalName(QueryParameters query, out List<string> modIds)
internal static bool TryGetGroupPublishIdsByInternalName(QueryParameters query, out List<string> modIds)
{
modIds = new List<string>();

if (!TryGetModDownloadItemsByInternalName(query, out List<ModDownloadItem> items))
var queryHandle = new QueryHelper.AQueryInstance(query);
// default search of all public mods. If fails, returns false
if (!queryHandle.TryGroupSearchByInternalName(out var items))
return false;

for (int i = 0; i < query.searchModSlugs.Length; i ) {
Expand All @@ -113,15 122,6 @@ internal static bool TryGetPublishIdByInternalName(QueryParameters query, out Li
return true;
}

internal static bool TryGetModDownloadItemsByInternalName(QueryParameters query, out List<ModDownloadItem> mods)
{
var queryHandle = new QueryHelper.AQueryInstance(query);
if (!queryHandle.TrySearchByInternalName(out mods))
return false;

return true;
}

/////// Workshop Version Calculation Helpers ////////////////////
private static (System.Version modV, System.Version tmlV) CalculateRelevantVersion(string mbDescription, NameValueCollection metadata)
{
Expand Down Expand Up @@ -383,34 383,44 @@ private IEnumerable<ModDownloadItem> ProcessPageResult()
/// Outputs a List of ModDownloadItems of equal length to QueryParameters.SearchModSlugs
/// Uses null entries to fill gaps to ensure length consistency
/// </summary>
internal bool TrySearchByInternalName(out List<ModDownloadItem> items)
internal bool TryGroupSearchByInternalName(out List<ModDownloadItem> items)
{
items = new List<ModDownloadItem>();

foreach (var slug in queryParameters.searchModSlugs) {
try {
WaitForQueryResult(SteamedWraps.GenerateAndSubmitModBrowserQuery(page: 1, queryParameters, internalName: slug));

if (_queryReturnCount == 0) {
Logging.tML.Info($"No Mod on Workshop with internal name: {slug}");
items.Add(null);
continue;
}

items.Add(GenerateModDownloadItemFromQuery(0));
}
catch {
// If Query Fails, we can't publish
if (!TrySearchByInternalName(slug, out var item))
return false;
}
finally {
ReleaseWorkshopQuery();
}

items.Add(item);
}

return true;
}

internal bool TrySearchByInternalName(string slug, out ModDownloadItem item)
{
item = null;

try {
WaitForQueryResult(SteamedWraps.GenerateAndSubmitModBrowserQuery(page: 1, queryParameters, internalName: slug));

if (_queryReturnCount == 0) {
Logging.tML.Info($"No Mod on Workshop with internal name: {slug}");
return true;
}

item = GenerateModDownloadItemFromQuery(0);
return true;
}
catch {
// If Query Fails, we can't publish
return false;
}
finally {
ReleaseWorkshopQuery();
}
}

/////// Run Queries ////////////////////

internal async Task WaitForQueryResultAsync(SteamAPICall_t query, CancellationToken token = default)
Expand Down Expand Up @@ -452,10 462,6 @@ internal ModDownloadItem GenerateModDownloadItemFromQuery(uint i)

PublishedFileId_t id = pDetails.m_nPublishedFileId;

if (pDetails.m_eVisibility != ERemoteStoragePublishedFileVisibility.k_ERemoteStoragePublishedFileVisibilityPublic) {
return null;
}

if (pDetails.m_eResult != EResult.k_EResultOK) {
Logging.tML.Warn("Unable to fetch mod PublishId#" id " information. " pDetails.m_eResult);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 22,24 @@ public override bool TryGetInfoForMod(TmodFile modFile, out FoundWorkshopEntryIn
{
info = null;
var query = new QueryParameters() {
searchModSlugs = new string[] { modFile.Name },
queryType = QueryType.SearchDirect
};

if (!WorkshopHelper.TryGetModDownloadItemsByInternalName(query, out List<ModDownloadItem> mods)) {
if (!WorkshopHelper.TryGetModDownloadItem(modFile.Name, out var mod)) {
IssueReporter.ReportInstantUploadProblem("tModLoader.NoWorkshopAccess");
return false;
}

currPublishID = 0;

if (!mods.Any() || mods[0] == null) {
// This logic is for using a local copy of Workshop.json to figure out what the publish ID is.
// It is currently unused and would need modifications to get the 'mod download item' for later.
/*
if (!AWorkshopEntry.TryReadingManifest( <GET PATH> Path.DirectorySeparatorChar "workshop.json", out info))
return false;
currPublishID = info.workshopEntryId;
mods[0] = Get Mod From Publish ID ()
*/
if (mod == null) {
return false;
}

currPublishID = ulong.Parse(mods[0].PublishId.m_ModPubId);
currPublishID = ulong.Parse(mod.PublishId.m_ModPubId);

// Update the subscribed mod to be the latest version published, so keeps all versions (stable, preview) together
WorkshopBrowserModule.Instance.DownloadItem(mods[0], uiProgress: null);
WorkshopBrowserModule.Instance.DownloadItem(mod, uiProgress: null);

// Grab the tags from workshop.json
ModOrganizer.WorkshopFileFinder.Refresh(new WorkshopIssueReporter()); // Force detection in case mod wasn't installed
Expand Down Expand Up @@ -206,7 196,7 @@ private static bool TryCalculateWorkshopDeps(ref NameValueCollection buildData)

if (buildData["modreferences"].Length > 0) {
var query = new QueryParameters() { searchModSlugs = buildData["modreferences"].Split(",") };
if (!WorkshopHelper.TryGetPublishIdByInternalName(query, out var modIds))
if (!WorkshopHelper.TryGetGroupPublishIdsByInternalName(query, out var modIds))
return false;

foreach (string modRef in modIds) {
Expand Down

0 comments on commit 56a6137

Please sign in to comment.