Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ for short. Detailed introduction look [Gitbook](https://markamibox.github.io/wor
2. Delete NCMS_memload.dll (They can be installed together but not suggested)
3. Start the game with experimental mode enabled

It is recommended to subscribe to the NML item on the Steam Workshop to receive automatic updates
<strong><mark>It is recommended to subscribe to the NML item on the Steam Workshop to receive automatic updates</mark></strong>

### Android Installation

Expand All @@ -47,6 +47,9 @@ It is recommended to subscribe to the NML item on the Steam Workshop to receive
<h3 align="center">
<a href="https://github.com/WorldBoxOpenMods/ModLoader/issues/new?assignees=&labels=bug&projects=&template=bug-report-en.yaml&title=%5BBug%5D%3A+">
Report BUG</a>

<hr/>

</h3>

<h2 align="center">New to Modding?</h2>
Expand Down
1 change: 1 addition & 0 deletions api/AbstractListWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ protected virtual void ClearList()
/// <returns></returns>
public static new T CreateAndInit(string pWindowId)
{
WindowId = pWindowId;
ScrollWindow scroll_window = WindowCreator.CreateEmptyWindow(pWindowId, pWindowId + " Title");

GameObject window_object = scroll_window.gameObject;
Expand Down
2 changes: 1 addition & 1 deletion resources/commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4773c590604d5af711ff15ddc21b18f092234163
7638405b0ef105101a13d0bab0c91633fb3bc10f
30 changes: 20 additions & 10 deletions services/ModDownloadService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,6 @@ internal static string StripBBCode(string pText)
private static WorkshopDownloadQueue CreateQueue()
{
var download_queue = new WorkshopDownloadQueue(Steam, Install, Task.Delay, () => DateTime.UtcNow);
download_queue.Changed += entry =>
{
if (entry.State is DownloadState.Cancelled or DownloadState.Failed) SetPending(entry.Listing.Id, false);
};
return download_queue;
}

Expand All @@ -169,23 +165,37 @@ private static void SetPending(ulong pFileId, bool pPending)
/// </summary>
private static string Install(string pDirectory)
{
if (ulong.TryParse(Path.GetFileName(pDirectory), out ulong file_id)) SetPending(file_id, false);
ulong.TryParse(Path.GetFileName(pDirectory), out ulong file_id);
ModDeclare mod = ModInfoUtils.recogMod(pDirectory, false);
if (mod == null) return ErrorNotAMod;

if (mod.ModType != ModTypeEnum.NEOMOD) return ErrorNotAMod;

if (ModInfoUtils.TryGetRecognizedMod(mod.UID, out _))
if (ModInfoUtils.TryGetRecognizedMod(mod.UID, out ModDeclare recognized))
{
if (ModCompileLoadService.IsModLoaded(mod.UID)) restart_pending.Add(mod.UID);
if (ModCompileLoadService.IsModLoaded(mod.UID))
{
restart_pending.Add(mod.UID);
}
else
{
ModState state = WorldBoxMod.AllRecognizedMods.TryGetValue(recognized, out ModState current)
? current
: ModState.FAILED;
WorldBoxMod.AllRecognizedMods.Remove(recognized);
WorldBoxMod.AllRecognizedMods[mod] = ModInfoUtils.isModDisabled(mod.UID) ? ModState.DISABLED : state;
Comment on lines +185 to +186
ModDepenSolveService.EnsureNode(mod);
}

if (file_id != 0) SetPending(file_id, false);
return null;
}

// New to this computer: saved as disabled, so neither this session nor the next start loads it.
ModInfoUtils.setModDisabled(mod.UID, true);

// The startup scan only lists NeoModLoader-type Workshop mods; do the same here.
if (mod.ModType != ModTypeEnum.NEOMOD) return null;
if (string.IsNullOrEmpty(mod.RepoUrl)) mod.SetRepoUrlToWorkshopPage(Path.GetFileName(pDirectory));
ModInfoUtils.EnsureRecognizedMod(mod);
if (file_id != 0) SetPending(file_id, false);
return null;
}
}
1 change: 1 addition & 0 deletions services/ModManagerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ public static async Task<bool> DeleteAsync(InstalledMod pMod)
}

WorldBoxMod.AllRecognizedMods.Remove(declaration);
ModDepenSolveService.InitializeGraph(WorldBoxMod.AllRecognizedMods.Keys);
return true;
}

Expand Down
4 changes: 3 additions & 1 deletion services/ModWorkshopServiceUnix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,8 @@ public async Task<string> GetPersonaNameAsync(ulong pSteamId)
public async Task<string> GetDescriptionAsync(ulong pFileId)
{
ResultPage? page = await Query.Items.WithFileId(pFileId).WithLongDescription(true).GetPageAsync(1);
return page?.Entries.Select(item => item.Description).FirstOrDefault();
if (!page.HasValue) return null;
using ResultPage result_page = page.Value;
return result_page.Entries.Select(item => item.Description).FirstOrDefault();
}
}
4 changes: 3 additions & 1 deletion services/ModWorkshopServiceWindows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,8 @@ public async Task<string> GetPersonaNameAsync(ulong pSteamId)
public async Task<string> GetDescriptionAsync(ulong pFileId)
{
ResultPage? page = await Query.Items.WithFileId(pFileId).WithLongDescription(true).GetPageAsync(1);
return page?.Entries.Select(item => item.Description).FirstOrDefault();
if (!page.HasValue) return null;
using ResultPage result_page = page.Value;
return result_page.Entries.Select(item => item.Description).FirstOrDefault();
}
}
17 changes: 15 additions & 2 deletions ui/ModBrowserWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ private async Task LoadAsync()
{
WorkshopCatalog catalog = ModDownloadService.Catalog;
await catalog.LoadAsync();
if (query.Sort == ListingSort.Trending) await catalog.LoadTrendingAsync();
if (catalog.Status == CatalogStatus.Ready && query.Sort == ListingSort.Trending) await catalog.LoadTrendingAsync();
await ModDownloadService.Authors.RequestAsync(catalog.Items.Select(listing => listing.AuthorId));
}

Expand Down Expand Up @@ -199,11 +199,24 @@ private void UpdateBottomBar()

private void OnDownloadChanged(DownloadEntry pEntry)
{
if (ItemMap.TryGetValue(pEntry.Listing, out AbstractListWindowItem<ModListing> row))
AbstractListWindowItem<ModListing> row = null;
if (!ItemMap.TryGetValue(pEntry.Listing, out row))
{
row = ItemMap.Where(pair => pair.Key.Id == pEntry.Listing.Id).Select(pair => pair.Value).FirstOrDefault();
}

if (row != null)
{
((ModBrowserRow)row).UpdateStatus();
}

if (pEntry.State is DownloadState.Completed or DownloadState.Failed or DownloadState.Cancelled &&
query.Install != InstallFilter.All)
{
if (IsOpened) Refresh();
else needs_refresh = true;
}

if (IsOpened) UpdateBottomBar();
}

Expand Down
2 changes: 1 addition & 1 deletion ui/prefabs/ModBrowserRow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public override void Setup(ModListing pListing)
title.text = pListing.Title;
age.text = DescribeAge(DateTime.UtcNow - pListing.Updated);
thumbnail.sprite = InternalResourcesGetter.GetIcon();
WorkshopThumbnails.Request(pListing.PreviewUrl, sprite =>
WorkshopThumbnails.Request(pListing.PreviewUrl, this, sprite =>
{
// The pooled row may show another listing by the time the image arrives.
if (listing == pListing) thumbnail.sprite = sprite;
Expand Down
59 changes: 53 additions & 6 deletions utils/WorkshopThumbnails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ internal static class WorkshopThumbnails
private static readonly Dictionary<string, Sprite> sprites = new();
private static readonly Queue<string> load_order = new();
private static readonly Dictionary<string, List<Action<Sprite>>> waiting = new();
private static readonly Dictionary<string, HashSet<object>> owners_by_key = new();
private static readonly Dictionary<object, string> key_by_owner = new();
private static readonly SemaphoreSlim download_slots = new(max_parallel_downloads);
private static HttpClient http_client;

Expand All @@ -35,8 +37,9 @@ internal static class WorkshopThumbnails
/// Call <paramref name="pOnLoaded" /> with the preview at <paramref name="pUrl" />: at once when it is
/// cached, otherwise once it has loaded. It is not called when the image cannot be loaded.
/// </summary>
public static void Request(string pUrl, Action<Sprite> pOnLoaded)
public static void Request(string pUrl, object pOwner, Action<Sprite> pOnLoaded)
{
if (pOwner != null) AssignOwner(pOwner, pUrl == null ? null : UrlKey(pUrl));
if (string.IsNullOrEmpty(pUrl)) return;

string key = UrlKey(pUrl);
Expand Down Expand Up @@ -153,12 +156,28 @@ private static void Store(string pKey, Sprite pSprite)
{
sprites[pKey] = pSprite;
load_order.Enqueue(pKey);
if (load_order.Count <= memory_limit) return;
int inspected = 0;
while (load_order.Count > memory_limit && inspected < load_order.Count)
{
string oldest = load_order.Dequeue();
if (!sprites.TryGetValue(oldest, out Sprite oldest_sprite))
{
continue;
}

if (owners_by_key.TryGetValue(oldest, out HashSet<object> owners) && owners.Count > 0)
{
load_order.Enqueue(oldest);
inspected++;
continue;
}

string oldest = load_order.Dequeue();
UnityEngine.Object.Destroy(sprites[oldest].texture);
UnityEngine.Object.Destroy(sprites[oldest]);
sprites.Remove(oldest);
UnityEngine.Object.Destroy(oldest_sprite.texture);
UnityEngine.Object.Destroy(oldest_sprite);
sprites.Remove(oldest);
owners_by_key.Remove(oldest);
inspected = 0;
}
}

/// <summary>
Expand All @@ -176,4 +195,32 @@ private static string UrlKey(string pUrl)

return hash.ToString("x16");
}

private static void AssignOwner(object pOwner, string pKey)
{
if (key_by_owner.TryGetValue(pOwner, out string current))
{
if (current == pKey) return;

if (owners_by_key.TryGetValue(current, out HashSet<object> current_owners))
{
current_owners.Remove(pOwner);
}
}

if (pKey == null)
{
key_by_owner.Remove(pOwner);
return;
}

key_by_owner[pOwner] = pKey;
if (!owners_by_key.TryGetValue(pKey, out HashSet<object> owners))
{
owners = new HashSet<object>();
owners_by_key[pKey] = owners;
}

owners.Add(pOwner);
}
}
Loading