Binary Compressed Save System, Save Entire Dynamically Generated Worlds! ♥ Rama

Hey there,

Using RamaSaveSystem for some time now and realy enjoy using it. However I currently have issues with hotreload related to this plugin. Im sure it was not there in the first place. Using the Plugin from C++.

To use the component I include


 #include "RamaSaveComponent"

For it to work, the Module must be added to …build.cs file of the project.


 PublicDependencyModuleNames.AddRange(new string] { "RamaSaveSystem" });

But adding the Module to the PublicDependencyModuleNames (or PrivateDependencyModuleNames) prevents me from hotreloading my game.
Compiling from the Editor brings up:

CompilerResultsLog:Error: Error LINK : fatal error LNK1181: Eingabedatei “C:\Program Files\Epic Games\UE_4.16\Engine\Plugins\Marketplace\RamaSaveSystem\Intermediate\Build\Win64\UE4Editor\Development\UE4Editor-RamaSaveSystem-5263.lib” kann nicht ge?ffnet werden.

It states that ‘UE4Editor-RamaSaveSystem-5263.lib’ cannot be opened. This error occours in the first place cause the module is implemented using


IMPLEMENT_MODULE(FDefaultGameModuleImpl, RamaSaveSystem);

FDefaultGameModuleImpl declares the module as game modules and thus as a modules that is considerred for hotreloading.

I was able to reproduce this in a new project (UE 4.16). Using it from pure Blueprint there are no issues. Compiling with no hotreload (Editor closed) does not cause any issues either.

Can anyone confirm this? Am I using it wrong?

Thanks.

@Rama

Could you please add a functionality of automatic screenshot thumbnail capture when saving game (in VR too, but it’s fine to snap it from just one eye) and association between savegame and screenshot thumbnail (so it can be displayed somehow easily in the Load Game menu for a respective savegame) ?

Three questions:

  1. Is there a way to offer a proof of purchase to get updates as they come, without waiting on Epic updating Marketplace (which has been disastrously slow recently)?

  2. Let’s say I keep updating my game, add new enemies, weapons, stats, etc. Is updated game going to be compatible with old savegames ?

  3. Same as #2, but also when updating engine ?

Thanks

Whoa I am happy to be the recipient of your only Forum post! I presume your question was answerd by now via my posts on the main page: https://www.unrealengine.com/marketp…ma-save-system

Any questions let me know!

:heart:

Rama




[quote="motorsep, post:44, topic:69032"]

Three questions:

1. Is there a way to offer a proof of purchase to get updates as they come, without waiting on Epic updating Marketplace (which has been disastrously slow recently)?

2. Let's say I keep updating my game, add new enemies, weapons, stats, etc. Is updated game going to be compatible with old savegames ?

3. Same as #2, but also when updating engine ?


Thanks
[/QUOTE]


1. Yes you can do that, just email me to get new versions in advance, I agree the 4.17 took Epic Marketplace pplz a long time, and I had my update ready within 2 hours of the new release of 4.17

2. I have an internal binary file versioning system to ensure backwards compatibility, so yes I am definitiely accounting for that with all future updates of the plugin. 

3. Engine updates don't usually affect my binary file structure since it is designed by my own choices, so only my own choices should affect it, and I am doing #2 so it should be fine :)

Very nice to hear from you!

♥

Rama

I agree such a feature would be great, my issue is that capturing the viewport involves a lot of code and work on the user’s end, you have to use a custom GameViewport class that the user has to properly set in ther config file. It’s a lot of steps the end user will have to understand for the whole system to work and a lot of code on my end to try and multi thread the scene capture / bmp resizing process so as to minimize any lag to the ned player. It’s quite a Feature and will require a signnificant amount of development time to get done right, where right = 1. easy to use 2. doesn’t hitcht he game even briefly during capture (so autosaves don’t hitch the game), 3 = is properly documented, 4 = doesn’t crash ever.

I’ve been quitely processing all of the above and trying to plan the best route, so it’s definitely on my to do list :slight_smile:

:heart:

Rama

Hey, I’m working on a project which need . I am trying to use use UE4Duino plugin in C++. I added dependency to Myproject.build.cs and exported the class by adding UE4DUINO_API right after the class keyword in plugin source header file. Still I cannot include plugin in my working code and it says " Cannot open include file: ‘Serial.h’: No such file or directory Serial_test D:\UE4_Projects\Mocap_test_corrected\Serial_test\Source\Serial_test\charact1.cpp 5". Please assist me with this Rama. thank you

How to Save and Load Runtime-created Instanced Static Meshes Using the Rama Save System

**Sample Project For You <~~~~~~~~~~~~~~~~~**

Dear Community,

I’ve created an instanced static mesh saving/loading example for you.

Instructions in the level itself, very small download (9mb)

It shows you in very small amount of code how to do what you want, including for an ISM actor that doesnt even exist when the game first starts!

See the Level Blueprint for instructions.

http://www.lightningfitness.org/ue4c…veISM_4_16.zip

:slight_smile:

Rama

Hey Rama,

I just came about the need of versioning the save files. Did you consider that in your work yet? As a file loads the actors directly, every versioning needs to happen inside of the actor class itself.
One versioning thing I just came about is renaming of parameters (member variables). As your save system uses UPROPERTY to save/load the members by name, loading is broken when renaming happens. Would be nice to have something like:

Before loading: Remap the actor class. Like:


 RamaSaveVersioning_RemapClass(FString oldClassName, FString newClassName); 

Would be nice to use string for the new/old class name. Using UClass would need the old class still to exist. FString would make it possible to delete the unused stuff.

During actor load within RamaSave_PreLoad:


 RamaSaveVersioning_RenameProperty(UClass class, FString oldPropertyName, FString newPropertyName);  

Cheers.

These are excellent points, even as a starting point it would be great if:

  1. I added user-chosen global version number in plugin settings
  2. I gave you the opportunity to rename a property on load that you know you changed the name of, so that you can redirect my system to the new name.
  3. Probably renaming a class can be done the same way, where I give you chance to change the class name before trying to load it.

I will work on this soon

:slight_smile:

Rama

How is it going with this to-do item? :slight_smile:

Awesome, thank you.

Hi Rama,

Is there a way of accessing the compressed save data without writing it to disk? From what I can see, It simply happens at the end of CompressAndWriteToFile the CompressedData is cleared. The Use case here is to compress small amounts of data and store the byte streams on a server as a sort of “cloud data”,

I’m still about versioning stuff. Adding and removing properties seems to be handled nicely by the save system as only properties that match by name are loaded. But that causes issues when changing the datatype of a property. Lets say you have a



UPROPERTY(SaveGame)
FString ID;


and for what ever reason it changed to



UPROPERTY(SaveGame)
int32 ID;


That will definitly break as the name matches and the binary data is simply copied over the property memory, in the worst case reaching beyond the memory allocated for the new data type.

I for sure could give the int32 ID another name like int32 IDInt. However the old FString ID would need to further exist and should NEVER get removed. If it is removed and for what ever reason someone creates a float ID, old save files will break again.
Well, if we know that struct is going to get saved, we could make a comment above that FString ID that notes it should never get removed for save reasons. However if someone makes that edit that does not now that the struct is getting saved somewhere (could also happen by mistake), he will likely just remove the FString ID.

How are you handling an issue like that?

I actually completed a versioning pass and will be uploading to marketplace soon :slight_smile:

Rama

Hey, Rama! Great plugin here :slight_smile: I’ve got a quick question. I’m having trouble getting the SaveGame tag to work properly with this system. As an example, here’s a value I’m trying to save on my pawn:


// Specifies what state this AI unit should default to when behavior tree has no clear demand
UPROPERTY(Category = "AI", EditAnywhere, BlueprintReadOnly, SaveGame)
EAIState defaultState;

That doesn’t seem to do anything. If I add this variable to the OwningActorVarsToSave array, it saves/loads just fine. Are my expectations off about how to use this SaveGame tag?

Gah! I found the value to set under “Project Settings” in order to enable this.

Another quick question…I’m assigning specific “alarms” that are placed in the level for my AI units to set off when they see the player using a variable like this:


// Alarm associated w/ this unit
UPROPERTY(Category = "AI|Alarmed", EditInstanceOnly, BlueprintReadWrite, meta = (EditCondition = "!bAssignClosestAlarm"), SaveGame)
AAlarm* AI_alarm;

Trying to save that pointer gives the following error:

RamaSave: Error: The variable ~ AI_alarm ~ found in Sentinel_Pawn_C >> This type of UObject Ptr cannot be saved/loaded directly. Save individual variable values and recreate in Actor Fully Loaded Event <3 Rama
RamaSave: Error: Rama Save System ~ Cancelling ~ Actor vars could not be saved for Sentinel_Pawn5

Am I correct in understanding there isn’t a workflow to save off pointers to actors like this? I’ve reviewed all the videos for ensuring pointers to actors that are saved/loaded remain intact, but I’m not saving/loading the alarm here. Just referencing it on another actor that’s being saved/loaded.

Manged to find a (gross) work around for now. If there’s a better way to do this, would love to hear it!


void APFCharacter::OnPreSave(URamaSaveComponent* SaveComponent)
{
    if (AI_alarm != nullptr)
        AI_alarmName = AI_alarm->GetFName();
}

void APFCharacter::OnFullyLoaded(URamaSaveComponent* SaveComponent, FString LevelPackageName)
{
    if (AI_alarmName != NAME_None)
    {
        for (TActorIterator<AAlarm> ActorItr(GetWorld()); ActorItr; ++ActorItr)
        {
            if (AI_alarmName == ActorItr->GetFName())
                AI_alarm = *ActorItr;
        }
    }
}

Aaaaannnnddd…one more thing…I found this new delegate I added to be pretty useful for making adjustments to an actor before it’s destroyed for a load. I’m triggering it in RamaSave_ClearLevel.


DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FRamaSavePreLoadDestroySignature, class URamaSaveComponent*, RamaSaveComponent);

As an example, I’m saving mines in the environment and their detonation effects are triggered in EndPlay. That delegate above allows me to not play those effects when it’s getting destroyed in preparation for a load.

[USER=“43607”]Masonic Studios[/USER]

Hi there!

Your new delegate sounds like fun! I will add that one :slight_smile:

Rama

Hey, Rama. I’ve been finding that it’d be super useful having a way for the Rama Save System to communicate generically about save events. That is to say, you can bind save event delegates on the RamaSaveComponent for specific actor save events, but there’s no way for the save system to message save events in a more generic, non-actor specific sort of way.

One solution I thought might be nice is to create a RamaSaveGameStateInterface that you can implement for your game state so the RamaSaveSystem can trigger save events at the game state level (e.g. when all actors are done saving or loading).

Does that make sense? If not, maybe I’ll just implement and pass it along to you.