[1.5] HugsLib (11.0.3) Lightweight modding library

Started by UnlimitedHugs, December 15, 2016, 02:20:14 PM

Previous topic - Next topic

scuba156

Awesome update, the quickstarter is really useful. I don't know if your interested in this but thought I would share the idea since its what I do :)

You can read a save files mod identifiers with this function:
        public static List<string> ReadModIDs(string filepath) {
            Scribe.loader.InitLoadingMetaHeaderOnly(filepath);
            ScribeMetaHeaderUtility.LoadGameDataHeader(ScribeMetaHeaderUtility.ScribeHeaderMode.Map, false);
            Scribe.loader.FinalizeLoading();
            return ScribeMetaHeaderUtility.loadedModIdsList;
        }


Then you can activate those mods with something like:

List<string> modIDs = ReadModIDs(file);

ModsConfig.Reset();
foreach (string identifier in modIDs) {
    ModsConfig.SetActive(identifier, true);
}
ModsConfig.Save();


If you want to preserve the active mods after the restart, just copy the ModsConfig.xml file before setting the mods and copy it back after the restart loads the mods.

UnlimitedHugs

Quote from: kaptain_kavern on May 28, 2017, 01:58:25 PM
Here have some cakes
A thousand time thank you :p

You monster, I'm on a no-carb diet ;D
But it's the thought that counts, so you are most welcome :)

Quote from: scuba156 on May 29, 2017, 01:28:10 AM
Awesome update, the quickstarter is really useful. I don't know if your interested in this but thought I would share the idea since its what I do :)
You can read a save files mod identifiers with this function:

Hey, that's really cool. I'll stash it for later- maybe adding a "Match mod config" button to the load warning dialog would be useful to have.
Perhaps we could even subscribe to missing mods by making some calls to the Steamworks API. Pretty sizeable feature, but worth considering.
HugsLib - AllowTool - Remote Tech - Map Reroll - Defensive Positions: Github, Steam

scuba156

#212
Quote from: UnlimitedHugs on May 29, 2017, 08:38:19 AM
Perhaps we could even subscribe to missing mods by making some calls to the Steamworks API. Pretty sizeable feature, but worth considering.
Well here you go :)


protected Callback<ItemInstalled_t> m_ItemInstalled;

void OnItemInstalled(ItemInstalled_t pCallback) {
    Logger.Message("[" + ItemInstalled_t.k_iCallback + " - ItemInstalled] - " + pCallback.m_unAppID + " -- " + pCallback.m_nPublishedFileId);
    }


Init the Callback
m_ItemInstalled = Callback<ItemInstalled_t>.Create(OnItemInstalled);

Then you can subscribe to missing mods by their identifier (if its a steam mod) with

SteamUGC.SubscribeItem(new PublishedFileId_t(modIdentifier));


If you need to force the download after subscribing, then you can use the following:
       
protected Callback<DownloadItemResult_t> m_DownloadItemResult;

void OnDownloadItemResult(DownloadItemResult_t pCallback) {
    Logger.Message("[" + DownloadItemResult_t.k_iCallback + " - DownloadItemResult] - " + pCallback.m_unAppID + " -- " + pCallback.m_nPublishedFileId + " -- " + pCallback.m_eResult);
}

m_DownloadItemResult = Callback<DownloadItemResult_t>.Create(OnDownloadItemResult);
SteamUGC.DownloadItem(new PublishedFileId_t(modIdentifier));


You could store a list<PublishedFileId_t> of the mods needed, then just List.Remove(pCallback.m_nPublishedFileId) in the callback and then restart when the list is empty.

UnlimitedHugs

Quote from: scuba156 on May 29, 2017, 01:28:28 PM
Well here you go :)

Ask and ye shall receive, eh? :D
Very nice work. If you want, you could take this further and tie everything together in a controller for this feature. I'll put a UI on it an we'll fire it up. If not- that's all right, I'll get to it eventually.
I think this thing would benefit both players and devs alike- players can easily exchange saves, while devs could ask for a save to reliably reproduce a problem with a mod.
HugsLib - AllowTool - Remote Tech - Map Reroll - Defensive Positions: Github, Steam

scuba156

Quote from: UnlimitedHugs on May 29, 2017, 02:07:56 PM
Ask and ye shall receive, eh? :D
Very nice work. If you want, you could take this further and tie everything together in a controller for this feature. I'll put a UI on it an we'll fire it up. If not- that's all right, I'll get to it eventually.
I think this thing would benefit both players and devs alike- players can easily exchange saves, while devs could ask for a save to reliably reproduce a problem with a mod.
Only sometimes :p

I'm happy to do that, I think it would be useful to everyone, could put a check in on game load too. I'll start on it tomorrow as its 4:30am atm. Would you prefer a static class or create an instance when required? I think I might also be able to get the download status as a ulong, but I haven't tried that yet.

UnlimitedHugs

Quote from: scuba156 on May 29, 2017, 02:42:36 PM
I'm happy to do that, I think it would be useful to everyone, could put a check in on game load too. I'll start on it tomorrow as its 4:30am atm. Would you prefer a static class or create an instance when required? I think I might also be able to get the download status as a ulong, but I haven't tried that yet.

There is no rush- I have plenty of other modding work to keep me occupied at the moment.
I would go for an instance- we can always stick it in a singleton if need be. Also, easier to run automated tests on.
Download status might be nice, but optional- mods are small, and we could fill a progress bar by simply counting them.
HugsLib - AllowTool - Remote Tech - Map Reroll - Defensive Positions: Github, Steam

scuba156

Quote from: UnlimitedHugs on May 29, 2017, 03:08:38 PM
There is no rush- I have plenty of other modding work to keep me occupied at the moment.
I would go for an instance- we can always stick it in a singleton if need be. Also, easier to run automated tests on.
Download status might be nice, but optional- mods are small, and we could fill a progress bar by simply counting them.
Too late, I've already started :) It will probably be a week or two till I finish it and submit a pull request anyway.

I've done most of the important parts, and have a semi-working prototype. For whatever reason the callback isn't triggering atm, but it still subscribes to and downloads the mods. I might have to use a worker thread for it as each steamworks subscribe call locks the main thread for about half a second which quickly adds up. I agree about the download status, I've just added an int DownloadsRemaining property to get the progress for now.

I just had an thought, I wonder if it's possible to trigger steam to change to current RimWorld version. It might be possible to switch RimWorld versions between restarts, might need an external process to handle it though. Might be complicated but I might just have a look to see if its possible at some point.

I've never actually looked at the steamworks api before, it's quite interesting. It looks like it would be quite possible to have a mod that calculates a score based on survivors/days survived/faction relations/stockpile/etc and puts it on a leaderboard :D

UnlimitedHugs

#217
Quote from: scuba156 on May 30, 2017, 06:12:16 AM
Too late, I've already started :) It will probably be a week or two till I finish it and submit a pull request anyway.

I've done most of the important parts, and have a semi-working prototype. For whatever reason the callback isn't triggering atm, but it still subscribes to and downloads the mods. I might have to use a worker thread for it as each steamworks subscribe call locks the main thread for about half a second which quickly adds up. I agree about the download status, I've just added an int DownloadsRemaining property to get the progress for now.

I just had an thought, I wonder if it's possible to trigger steam to change to current RimWorld version. It might be possible to switch RimWorld versions between restarts, might need an external process to handle it though. Might be complicated but I might just have a look to see if its possible at some point.

I've never actually looked at the steamworks api before, it's quite interesting. It looks like it would be quite possible to have a mod that calculates a score based on survivors/days survived/faction relations/stockpile/etc and puts it on a leaderboard :D

To be frank, I'm having second thoughts about the mod downloading. It might be a better fit for a separate mod, seeing how non-steam players won't be able to take advantage of it.
How about we start with a basic mod config matcher for saves, and see where it goes from there. If mods are missing, it could give the player a list and offer to load anyway. We could include clickable links if it's a workshop mod.

Changing version sounds like a heap 'o trouble- even though I would appreciate that ability without the extra download in between. It's not something for the library, though.
Leaderboards are pretty neat- I also had a thought about making custom achievements for mods- which would be pretty cool, but Tynan would likely not be as enthusiastic about that :D

On a side note, I recall Zen saying something to the effect of workshop items being able to be downloaded without a Steam login. Sounds a bit shady, but might be interesting to investigate.
HugsLib - AllowTool - Remote Tech - Map Reroll - Defensive Positions: Github, Steam

scuba156

Its up to you of course. I will continue as its something I can use and could put it in its own separate mod if that's what we decide. It is possible to check if steam is active via Verse.SteamManager.HasInit && IsActive. I've also fixed the performance issue. RimWorld already has callbacks which it was rebuilding the list of steam mods every time, can just use a harmony patch to stop the rebuild if the callback is intended for us.

I'll write up a mod config matcher, and build links for it. I agree about the version changer, I'll have a look at it though, If Its too trouble then I'm not going to bother but would be neat.
Achievements would be really cool actually, I don't think you can create official steam achievements through steamworks but everything else about them is there. Just add a button in settings that displays them like mod settings.

AFAIK it's not possible with RimWorld as Tynan has it turned off, unless Zen knows of a different way.
http://steamworkshopdownloader.com/view/818773962

UnlimitedHugs

Quote from: scuba156 on May 30, 2017, 06:41:56 PM
Its up to you of course. I will continue as its something I can use and could put it in its own separate mod if that's what we decide. It is possible to check if steam is active via Verse.SteamManager.HasInit && IsActive. I've also fixed the performance issue. RimWorld already has callbacks which it was rebuilding the list of steam mods every time, can just use a harmony patch to stop the rebuild if the callback is intended for us.

I'll write up a mod config matcher, and build links for it. I agree about the version changer, I'll have a look at it though, If Its too trouble then I'm not going to bother but would be neat.
Achievements would be really cool actually, I don't think you can create official steam achievements through steamworks but everything else about them is there. Just add a button in settings that displays them like mod settings.

AFAIK it's not possible with RimWorld as Tynan has it turned off, unless Zen knows of a different way.
http://steamworkshopdownloader.com/view/818773962

Interesting, thank you for looking into all that.
An in-game achievement framework would be nice, and could even be synched with Steam cloud. Problem is that we don't really have that many beefy content mods for Rimworld yet that would leverage that system. Maybe sometime eventually.
A thought I had about the mod downloader: the matcher, once roller into HugsLib, could produce an event that the downloader mod would listen to- and rather than showing the missing mod list, the whole download sequence would happen. It's your project though, so I shouldn't poke my nose into it :)
Also, that link is a great find either way.
HugsLib - AllowTool - Remote Tech - Map Reroll - Defensive Positions: Github, Steam

scuba156

#220
Quote from: UnlimitedHugs on May 31, 2017, 01:23:15 PM
Interesting, thank you for looking into all that.
An in-game achievement framework would be nice, and could even be synched with Steam cloud. Problem is that we don't really have that many beefy content mods for Rimworld yet that would leverage that system. Maybe sometime eventually.
A thought I had about the mod downloader: the matcher, once roller into HugsLib, could produce an event that the downloader mod would listen to- and rather than showing the missing mod list, the whole download sequence would happen. It's your project though, so I shouldn't poke my nose into it :)
Also, that link is a great find either way.
I'm actually liking the achievement idea more and more, It might encourage some bigger mods, better custom scenarios/storytellers, some more content oriented mods rather than skins. It won't have a massive impact but more features available is always good. Could have a Def in the mod that defines the achievement details, and just have a method TriggerAchievement("nameofachievement").
I'll be writing a steam cloud sync manager soon anyway so I can always incorporate that into HugsLib once its finished, and use it for achievement sync.

Nice idea for the downloader, it should work nicely. The downloader will have Hugslib as a dependency anyway so it could use the trigger from there all the time. The downloader will have to have a restart function using Huglibs restarter anyway so I can pass any parameters to that. Always poke your nose in because it helps :)

UnlimitedHugs

Quote from: scuba156 on May 31, 2017, 03:15:37 PM
I'm actually liking the achievement idea more and more, It might encourage some bigger mods, better custom scenarios/storytellers, some more content oriented mods rather than skins. It won't have a massive impact but more features available is always good. Could have a Def in the mod that defines the achievement details, and just have a method TriggerAchievement("nameofachievement").
I'll be writing a steam cloud sync manager soon anyway so I can always incorporate that into HugsLib once its finished, and use it for achievement sync.

Nice idea for the downloader, it should work nicely. The downloader will have Hugslib as a dependency anyway so it could use the trigger from there all the time. The downloader will have to have a restart function using Huglibs restarter anyway so I can pass any parameters to that. Always poke your nose in because it helps :)

I have to be careful what I say- I might accidentally commit to a few weeks of work here :D
Just so we're clear- we're just tossing ideas around.
I do like the idea of the achievements- I have a few things in the pipe that might benefit from them. They do need more interesting features than just showing popups with pictures, though. The biggest attraction of the Steam ones, I think, is the social factor- it's a great conversation starter. Also, a point of pride as you get to admire them in a gallery and be inspired to get the rest of them.
HugsLib - AllowTool - Remote Tech - Map Reroll - Defensive Positions: Github, Steam

scuba156

#222
Quote from: UnlimitedHugs on May 31, 2017, 04:11:42 PM
I have to be careful what I say- I might accidentally commit to a few weeks of work here :D
Just so we're clear- we're just tossing ideas around.
I do like the idea of the achievements- I have a few things in the pipe that might benefit from them. They do need more interesting features than just showing popups with pictures, though. The biggest attraction of the Steam ones, I think, is the social factor- it's a great conversation starter. Also, a point of pride as you get to admire them in a gallery and be inspired to get the rest of them.
Haha of course. Everything here can be used as a reference if we end up doing it.

Each achievement could have an image, a title, a short description, and a value. In Settings, have a button to show an achievement UI which has tabs at the top and a close button. The achievement pop up should have an onclick action to show the UI.
First tab can be overall progress which shows things like percentage of total achievements gained and other things for users to show off. Second Tab could be a list of all available achievements sorted by unlocked ones. Another tab could show achievements per mod, with a floatmenu button to swap between mods.

If the community got involved, could provide a service for people to display their progress in their ludeon forums signature.

Could give it a leaderboard to increase the social aspect of it. Might have to protect it with a maximum number of mods that can register per developer or something so someone doesn't just create a heap of mods to inflate their score.

Edit:*Ahem* Can get an idea of what would be required and if it's better in a separate mod etc.

scuba156

#223
I ended up getting a bit carried away... complete with an OnClick event, and even animation to make it scroll up from the bottom of the screen, wait for a few seconds and then scroll back down.

[attachment deleted by admin due to age]