Hi! Is this plugin compatible with Lyra?
Hi there seems to be some issues with my save, can you tell me why?
This is a normal save
Did I set something wrong that caused it to not be saved correctly?
Email me log files if you get any warning from the save plugin.
(not any random logs of anything besides save data)
Hi. I like the plugin but I am having some problems saving and loading the main character in a shipping build. I see a note about “invalidating” the SGUID in the documentation but don’t quite understand. In editor the character loads but in shipping build it doesn’t.
Could you possibly advise? Thank you!
I actually fixed this I think but I have another but possibly relevant question. Is there any way for connected clients to load their own data? At the moment it seems connected clients try to load the server’s data. Appreciate your advice!
I am guessing I might need to save on each client’s game instance and load from a replicated class once in the game?
Yes you would have to run the save and load locally.
Thanks a lot for the swift response! Sorry to bother you further but what classes would you have the Savior load and save logic in so each server+client saves/loads to their own data?
At the moment I have it all in the pawn which works fine for the server but obviously not for the clients when I call server travel between levels.
I believe each client has its own GameInstance object and Subsystems that you can create/use for custom behavior.
How did you fix this?
Usually you just set the SGUID of your player pawn to 0000-0000 at event Begin Play.
Confirmed, the solution is as Bruno says. Setting to all 0’s seems to work fine
Still struggling to get clients to save and load to their own game instance when connected to a session but thats a different matter!
Hi , there how should quicksave look like ? (that i can save all informations without menu popup and choosing save slot in bp for main character?) all three nodes should be in specific order or i should choose one node (save game world)?. Or how it should be done without calling the widget ? Thank you in advance for any info
“Save Game World” already calls by itself the other 2. Loading, the same.
Hi Bruno,
I came across a few faulty returns in the Savior.cpp class. RemoveDataRecordByGUID and RemoveDataRecordByRef functions to be exact; they will always return failed.
void USavior::RemoveDataRecordByGUID(const FGuid &ID, ESaviorResult &Result) {
FName Item = NAME_None;
//
for (auto IT = SlotData.Records.CreateConstIterator(); IT; ++IT) {
const FSaviorRecord &Record = IT->Value;
if (Record.GUID==ID){Item=IT->Key;break;}
}
//
if (!Item.IsNone()) {
SlotData.Records.Remove(Item);
Result = ESaviorResult::Success;
}
//
Result = ESaviorResult::Failed;
}
there is no return once the Result turns out to be a success, and therefore always falls through onto the Failed state.
I always work from a “backwards” perspective; always return false unless every check has been ticked.
Perhaps something like this would work;
void USavior::RemoveDataRecordByGUID(const FGuid& ID, ESaviorResult& Result)
{
Result = ESaviorResult::Failed; // Result is by definition always false regardless where we end up inside our function (by preemptively returning for instance) ...
FName Item = NAME_None;
for (auto IT = SlotData.Records.CreateConstIterator(); IT; ++IT)
{
const FSaviorRecord& Record = IT->Value;
if (Record.GUID == ID)
{
Item = IT->Key;
break;
}
}
if (!Item.IsNone())
{
SlotData.Records.Remove(Item);
Result = ESaviorResult::Success; // ... unless we tick all of our checkboxes at the end of our code scope.
}
}
I have also modified some critical pieces in your load / save functions (particularly for saving materials) to be able to get it to work with Packaged / Shipping builds.
Long story short: if you try to save InstancedDynamicMaterials, they will be saved by name (InstancedDynamicMaterial_0, _1, _2, _3 and so on). If you we’re to resave lets say a newly applied material on slot 0 with a new InstancedDynamicMaterial, it would return _4 on slot 0. Upon reloading your level, applying new InstancedDynamicMaterials onto your actors, there is no instanced material with suffix _4, let alone be it on slot 0, and therefore no materials will be loaded properly (as they are referenced by name) instead of by index.
Edit: I am aware that from a proper coding standard, you’d try to first get the InstancedDynamicMaterial if it already exists on a particular slot, before applying a new one, but in our huge code base that workflow is unfortunately not always guaranteed. In our case, and in most cases in general, its safer to work index-based than name based.
Our solution is still working very well after a year in use now. Let me know if you’d be interested to look at it, I’d like to send you the code to your email for you to have a look at it, perhaps if it successfully passes your code review, you’d like to ship it natively with your plugin. This may help other people experiencing the same problems we were facing, and it would save me quite some time re-customizing your code base every update
Thank you, I will take a look soon.
Lots of stuff to deal with right now.
How would we get this to work with Data Layers? Instead of loading the level, I have my main menu in it’s own data layer, and we would have the data layers for where the player’s at load the data layer the player will be in. But how would we load the data?
If you are talking about world data layers on Unreal 5, the “Load Game World” automatically restores the visibility of data layers.
If you want to manually restore data layers visibility from save manually, there’s no node on the plugin for this, I would have to add one for you.
But I have to wait for the current submission review by the Marketplace staff before adding new functions, they take a while to review plugin updates.
That would be awesome. I can just wait till then. It would be cool if this plugin would be adapted to data layers, as they’re becoming more prominent in development.