Steve's Persistent Unreal Data library

Overview

SPUD: Steve's Persistent Unreal Data library

What is it?

SPUD is a save game and streaming level persistence solution for Unreal Engine 4.

The 2 main core features:

  1. Save / Load game state easily
  2. Streamed levels retain their state as they unload / reload without a save needed

Some more details:

  • Easily mark actors in your levels as persistent
    • You implement ISpudObject, a marker interface with no required methods
  • Pick properties to save
    • By enabling the "SaveGame" option
  • Large number of property types supported, including arrays, references between objects, and custom structs
  • You can also manually mark non-level UObjects (e.g. GameInstance) for inclusion in the save
  • Dynamically spawned objects that exist at save are re-spawned on load
  • Level objects which have been destroyed are automatically re-destroyed on level load
  • Core details like transform, controller rotation and physics state are automatically saved
  • Usable in C++ or Blueprints

An introduction video:

Intro Video

Examples

This project contains the master documentation for this library, but if you want to see examples of its use, see the SPUD Examples project.

Support This Work!!

I've decided to open source this work because I think it's likely to be genuinely useful to people. I like sharing my work with others, and that also generally makes it better. But, it all takes extra effort over keeping it private!

If you appreciate me doing this, please consider ❤️ ❤️ Supporting my work on Patreon! ❤️ ❤️ Thanks!

Installing

Cloning

The best way is to clone this repository as a submodule; that way you can contribute pull requests if you want. The project should be placed in your project's Plugins folder.

> cd YourProject
> git submodule add https://github.com/sinbad/SPUD Plugins/SPUD
> git add ../.gitmodules
> git commit

Alternatively you can download the ZIP of this repo and place it in YourProject/Plugins/SPUD.

Referencing in C++

Edit YourProject.Build.cs and do something similar to this:

using System.IO;
using UnrealBuildTool;

public class SPUDExamples : ModuleRules
{
	private string PluginsPath
	{
		get { return Path.GetFullPath( Path.Combine( ModuleDirectory, "../../Plugins/" ) ); }
	}
	
	protected void AddSPUD() {
		// Linker
		PrivateDependencyModuleNames.AddRange(new string[] { "SPUD" });
		// Headers
		PublicIncludePaths.Add(Path.Combine( PluginsPath, "SPUD", "Source", "SPUD", "Public"));
	}

	public SPUDExamples(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
		
		AddSPUD();
	}
}

After adding this you should right-click your .uproject file and "Generate Visual Studio Project Files".

Basic Usage

VERY IMPORTANT

You MUST save all your levels before playing in editor (PIE). Failure to do so results in mis-categorisation of some level objects. The Output Log will dump an error about this when unsaved levels are detected.

To fix this, either:

  1. Use the menu option File -> Save All Levels before playing in the editor
  2. In Project Settings > Plugins > SPUD, enable the option Save All Levels On Play In Editor.

The latter option is your best bet for making sure you don't accidentally have strange bugs, at the expense of a slight delay to PIE if you have unsaved levels.

Do not report any bugs unless you've checked your levels are saved!!

The core functionality of SPUD is writing the state of chosen UObjects, including a chosen subset of their properties, to a persistent data format so it can be saved / loaded and kept consistent across map changes and streaming.

Automatically Persisting Actors

Actors present in your world can be picked up automatically. To do this, you opt-in your classes by implementing the interface ISpudObject. You can do this in C++:

class AMyActor : public AActor, public ISpudObject
{
...

or in Blueprints:

Implementing ISpudObject in Blueprints

You don't have to implement any methods on this interface, it is solely a marker so that SPUD will know to look at your object. Any actor marked this way will be automatically made persistent. This includes GameModes and GameStates.

Explicitly Persisting Global Objects

Global objects like GameInstance won't be picked up for persistence even if you implement ISpudObject, because they're not included in the world. However, you can opt these objects in to persistence so they also get saved:

	GetSpudSubsystem(GetWorld())->AddPersistentGlobalObjectWithName(this, "MyGameInstance");	

Global objects must always exist, SPUD won't re-create them on load, but it will re-populate their state.

Standard Persistent State

Just by opting the class in to SPUD persistence, the following state is automatically saved:

  • Hidden flag
  • Transform (Movable objects only)
  • Controller Rotation (Pawns only)
  • Physics velocities (Physics objects only)
  • Any Movement Component's velocity (e.g. player movement, projectile movement, if present)

Pick Properties to Save

In addition to the standard state, you can then tell SPUD to save additional properties of the object. You use the "SaveGame" UPROPERTY flag to do this.

In C++:

	UPROPERTY(SaveGame)
	int MySavedInt;

or Blueprints, in the advanced property details section:

Opting into SaveGame in Blueprints

For the most common case of an object in a level, that's it! Many types of property are supported. For more details, see Properties;

Destroyed Actors

If a level actor that implements ISpudObject is destroyed, that destruction will be made persistent by SPUD. Re-loading a map will automatically re-create that actor, but as part of the restore process SPUD will destroy it again, returning the world to the correct state. You don't need to do anything extra to make this work.

Runtime Spawned Actors

Actors which are not part of the level but are spawned at runtime, that also implement ISpudObject, will be automatically re-spawned on load.

However, because these objects need to be uniquely identified, you must give these classes a special FGuid property called SpudGuid.

For example:

	UPROPERTY()
	FGuid SpudGuid;

You don't have to assign a value to this property, SPUD will generate a GUID if it's blank. Also you should NOT mark it as SaveGame. It's not your save state, just some metadata SPUD needs to uniquely identify this object.

Saving and Loading

You can call any of the save / load methods on USpudSubSystem.

For example quick save/load In Blueprints: Save/Load in Blueprints

Or in C++:

auto SpudSystem = GetSpudSubsystem(GetWorld());
SpudSystem->QuickSaveGame();

There are many other methods for saving to named slots, listing save games and so on. When loading a game, the current map will always be unloaded, and the game will travel to the map in the save game (even if it's the same one). This ensures things are reset correctly before restoring state. For this reason, loading is asynchronous (see events on USpudSubSystem if you want to listen in on when loading completes).

A note on streaming

When it comes to streaming, persistence of level data happens automatically so long as streaming requests are routed through USpudSubSystem, which has methods to request streamed levels, or to withdraw a request (levels are streamed out when outstanding requests hit 0).

SPUD comes with a new streaming volume, ASpudStreamingVolume to make this easier to use. But you can call the streaming methods manually as well.

When you travel between maps, SPUD gets notified and will save state to the active game.

More information is available in Levels and Streaming

More details

License

The MIT License (MIT) Copyright © 2021 Steve Streeting

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Issues
  • `ISpudObject` should allow opting-out of saving Transform data

    `ISpudObject` should allow opting-out of saving Transform data

    In researching use of this plugin in our project, one particular issue keeps coming up. I believe that there should be a way to opt out of storing transform data for any implementor of ISpudObject.

    The first use case where storing the transform does not make sense is the case of a static actor. For instance, a blueprint with 1 or more static mesh components set to static mobility. This is commonly done on blueprint actors where you want baked lighting, but is not exclusive to that. Imagine as an example, a checkpoint altar that turns on a particle when the checkpoint is reached with static mesh having baked lighting.

    In the past (and I believe still currently), the engine prevented you from moving an actor containing any subcomponent with static mobility. So saving the transform is not helpful at best, and at worst, if the engine let you change the transform it would break your baked lighting.

    The second use case I see is any actor whose design-time placement is deliberate and critical. For instance, an actor that defines a spawn point for enemies. This actor would be placed throughout a level at design time and would have a SaveGame variable that tracks whether the spawner has been defeated.

    Developers are going to need to shift these over time as production continues, landscapes change and props are added. Unfortunately, if a user's save game automatically restores the transform of these actors, you're now undoing deliberate design. Say a rock was added directly on top of a spawner and the dev nudged the spawner to be on top of the rock, but when the game is loaded, the spawner is restored to be inside of the rock!

    "Hmm, works on my end, these users must be crazy." 🤣

    I believe a simple way to facilitate this would be to add a new function to either ISpudObject or ISpudObjectCallback e.g. bool ShouldSaveTransform() whose default implementation returns true but allows opting out of saving transforms. No doubt this would add a little bit of complexity to versioning, particularly if someone were to opt-in to saving transforms in a later version of the save file.

    Would a change like this be in line with your goal of this plug-in?

    opened by error454 12
  • SubscribeLevelObjectEvents hits

    SubscribeLevelObjectEvents hits "ensure"

    Hello @sinbad,

    There seems to be an Issue in USpudSubsystem::SubscribeLevelObjectEvents(ULevel* Level). I don't know what's exactly wrong due to time constraints on my side but will investigate as soon as possible.

    Here is a stack trace I was able to grab via BugSplat:

    [2021.08.10-07.55.43:737][691]LogSpudState: Warning: Skipping restore level Map_Hub_P, no data (this may be fine)
    [2021.08.10-07.55.43:737][691]LogOutputDevice: Warning: 
    
    Script Stack (0 frames):
    
    [2021.08.10-07.55.44:016][691]LogStats: FPlatformStackWalk::StackWalkAndDump -  0.278 s
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: === Handled ensure: ===
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: 
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: Ensure condition failed: InvocationList[ CurFunctionIndex ] != InDelegate [File:C:\BuildAgent\work\88f80d3383ccc93a\Engine\Source\Runtime\Core\Public\UObject/ScriptDelegates.h] [Line: 556]
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: 
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: Stack: 
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7ba2ce157 bg.exe!<lambda_7c081f6173193e48029482a76596c290>::operator()() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b55efc54 bg.exe!FSparseDelegateStorage::Add() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b4670de5 bg.exe!TSparseDynamicDelegate<FActorDestroyedSignature_MCSignature,AActor,FActorDestroyedSignatureInfoGetter>::__Internal_AddDynamic<USpudSubsystem>() [C:\BuildAgent\work\5fd5dbdab725171e\UnrealEngine\Engine\Source\Runtime\CoreUObject\Public\UObject\SparseDelegate.h:371]
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b46989ae bg.exe!USpudSubsystem::SubscribeLevelObjectEvents() [C:\BuildAgent\work\5fd5dbdab725171e\bg\Plugins\SPUD\Source\SPUD\Private\SpudSubsystem.cpp:791]
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b4684e23 bg.exe!USpudSubsystem::OnPostLoadMap() [C:\BuildAgent\work\5fd5dbdab725171e\bg\Plugins\SPUD\Source\SPUD\Private\SpudSubsystem.cpp:200]
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b467b63f bg.exe!TBaseUObjectMethodDelegateInstance<0,USpudSubsystem,void __cdecl(UWorld *),FDefaultDelegateUserPolicy>::ExecuteIfSafe() [C:\BuildAgent\work\5fd5dbdab725171e\UnrealEngine\Engine\Source\Runtime\Core\Public\Delegates\DelegateInstancesImpl.h:611]
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b85161e0 bg.exe!TMulticastDelegate<void __cdecl(UWorld * __ptr64),FDefaultDelegateUserPolicy>::Broadcast() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b8f19971 bg.exe!UEngine::LoadMap() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b8ec91b0 bg.exe!UEngine::Browse() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b8f38fc4 bg.exe!UEngine::TickWorldTravel() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b85fa430 bg.exe!UGameEngine::Tick() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b369edab bg.exe!FEngineLoop::Tick() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b36b3ecd bg.exe!GuardedMain() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b36b3f8a bg.exe!GuardedMainWrapper() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7b36c7670 bg.exe!WinMain() []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ff7ba021dde bg.exe!__scrt_common_main_seh() [D:\agent\_work\9\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288]
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ffba6717034 KERNEL32.DLL!UnknownFunction []
    [2021.08.10-07.55.44:016][691]LogOutputDevice: Error: [Callstack] 0x00007ffba6e82651 ntdll.dll!UnknownFunction []
    

    I can also provide a UE4MiniDump.dmp if that would help you.

    Cheers, Nikolaus

    opened by poettlr 12
  • Automated storing on travel does not work when using Seamless Travel

    Automated storing on travel does not work when using Seamless Travel

    Hello,

    It seems that Unreal is not calling the FCoreUObjectDelegates::PreLoadMap delegate when traveling using seamless travel. Therefore SPUD is not picking up the transition and is not storing data by default.

    There is a delegate defined in World FWorldDelegates::FOnSeamlessTravelStart that might do the trick. I currently do it manually via blueprint but will add this in my GameInstance to see if it resolves the issue.

    Cheers, Nikolaus

    opened by poettlr 12
  • Expose `ISpudObject` members to both C++ and BP

    Expose `ISpudObject` members to both C++ and BP

    Change the interface prototypes in ISpudObject to allow overriding in both BP and C++. BP can override via the normal interface override process and interface methods will just show up in the sidebar as expected. image

    C++ can override *_Implementation methods.

    Change existing calls to the interface functions in C++ to use the prescribed entry point that covers both C++ and BP use cases.

    I ran the 4 integration tests and tested this in the SPUDExamples project to make sure everything worked out as expected. It behaves as expected.

    opened by error454 10
  • Start a new level without saving the state of the current one

    Start a new level without saving the state of the current one

    Assume USpudSubsystem::CurrentState is Disabled. We want to load a level (not a saved game), and start SPUD after it is loaded. We do not want to save the state of the current level. UGameplayStatics::OpenLevel is async, so if we call USpudSubsystem::NewGame immediately after it, SPUD will be activated in the current level, and will then save the state of the current level, travel to the new one, and attempt to load its state. Using a level actor's BeginPlay to call USpudSubsystem::NewGame if USpudSubsystem::CurrentState is Disabled doesn't work: the actor's BeginPlay is called before FCoreUObjectDelegates::PostLoadMapWithWorld. But USpudSubsystem::NewGame calls SubscribeAllLevelObjectEvents, and USpudSubsystem::OnPostLoadMap does it too.

    My approach is to use USpudSubsystem::ForceReset() from an actor in the level (GameState), if USpudSubsystem::CurrentState is Disabled. This works, but doesn't fit the documented description of ForceReset().

    Maybe this scenario should be documented?

    opened by cbQB 8
  • Chaos vehicles not respawning even after changing to

    Chaos vehicles not respawning even after changing to "Always respawn"

    Vehicles don't respawn when loading a game, I know they inherit from APawn so by default they shouldn't. I have tried to set the respawn mode to "Always respawn" and I've added a SpudGuid, with no success.

    The vehicle is saved correctly as the data and the vehicles velocity is being restored on load.

    It could be that respawn mode doesn't work on any pawn, but I haven't tried it with anything else, pawns that can be possessed temporarily like vehicles and horses might benefit from being able to set them to respawn after loading a game

    opened by DoubleP90 8
  • SpudSystem Initialization

    SpudSystem Initialization

    Hello, What is the best way to add PersistentGlobalObjectWithName, for example GameInstance object or setting up Model. When I add it on GameInstance event init, I am keep getting warning: LogScript: Warning: Accessed None trying to read property CallFunc_GetGameInstanceSubsystem_ReturnValue Seems like SpudSystem is not initialized at this point, as I understand first is initialized GameInstance and then All Subsystems Inializations. Where I should place all init functions? Thank You, Regards

    ps. I am trying to achive this in blueprints

    opened by shoooxz 8
  • Declaration Shadows a Field of USpudStateCustomData

    Declaration Shadows a Field of USpudStateCustomData

    Hello,

    I was having issues compiling under clang for PS5 receiving these errors:

    ...\Plugins\SPUD\Source\SPUD\Public/SpudState.h(371,2): error : declaration shadows a field of 'USpudStateCustomData' [-Werror,-Wshadow]

    On line 371 of SpudState.h:

    UCLASS() class SPUD_API USpudStateCustomData : public UObject { ---> GENERATED_BODY()

    Any help with this issue would be much appreciated.

    Thanks! Andrew

    opened by renardmf 7
  • Hard references to asset objects are saved incorrectly

    Hard references to asset objects are saved incorrectly

    Hi again

    Declaring a hard object reference in c++ or blueprint for example:

    UPROPERTY(EditAnywhere, SaveGame, BlueprintReadWrite) class USoundBase* HardAudioAsset;

    Does not store or restore properly. They are not transient UObjects but they are treated as such. If you have a case of an object property that is null at the start but gets set to something (like an audio asset) and saved, it will save the class ID off:

    /Script/Engine.SoundWave

    And on restore create a new transient SoundWave and fill in the property. It should instead store only the asset path and restore that. In my own code I am checking if the object is an asset using IsAsset() and instead storing off the asset path and a special class ID to instead use StaticLoadObject against the asset path to fill in the ObjectProperty.

    Cheers Ryan

    opened by rfsheffer 7
  • Restoring Character/Controller/GameState not working in built project (UE5)

    Restoring Character/Controller/GameState not working in built project (UE5)

    ...because they get different names after each reload, and SPUD simply treats them just like any other level objects. Which would be fine if the assumption below were true:

    SpudState.cpp:253:

    	// FNames are constant within a level
    	const auto Name = SpudPropertyUtil::GetLevelActorName(Actor);
    

    Unfortunately, that's not true.

    UObjectGlobals.cpp:1891

    					if (!FPlatformProperties::HasEditorOnlyData() && GFastPathUniqueNameGeneration)
    					{
    						/*   Fast Path Name Generation
    						* A significant fraction of object creation time goes into verifying that the a chosen unique name is really unique.
    						* The idea here is to generate unique names using very high numbers and only in situations where collisions are
    						* impossible for other reasons.
    						*
    						* Rationale for uniqueness as used here.
    						* - Consoles do not save objects in general, and certainly not animation trees. So we could never load an object that would later clash.
    						* - We assume that we never load or create any object with a "name number" as large as, say, MAX_int32 / 2, other than via
    						*   HACK_FastPathUniqueNameGeneration.
    						* - After using one of these large "name numbers", we decrement the static UniqueIndex, this no two names generated this way, during the
    						*   same run, could ever clash.
    						* - We assume that we could never create anywhere near MAX_int32/2 total objects at runtime, within a single run.
    						* - We require an outer for these items, thus outers must themselves be unique. Therefore items with unique names created on the fast path
    						*   could never clash with anything with a different outer. For animation trees, these outers are never saved or loaded, thus clashes are
    						*   impossible.
    						*/
    						static TAtomic<int32> UniqueIndex(MAX_int32 - 1000);
    						NameNumber = --UniqueIndex;
    					}
    					else
    					{
    						NameNumber = UpdateSuffixForNextNewObject(Parent, Class, [](int32& Index) { ++Index; });
    					}
    

    In the Editor, both PIE and Standalone, it takes the latter path, using UpdateSuffixForNextNewObject and incrementing the counter. But in Windows built versions (UE5 at least), it takes the fast path, which uses non-repeating values.

    One way to solve this is to modify Unreal, e.g. add an opt-in/out mechanism per-class for the name generator. Not complicated, but only usable by those with a home-grown engine. And not particularly more elegant than the others.

    Another would be for SPUD to special-case these classes. Not very elegant.

    Yet another: adding a function in ISpudObject that allows the object to override it's name, as used for saved data lookup. And an implementation of the basic naming scheme, Blueprint-usable. Functionally equivalent to allowing the developer to use the classic naming scheme. A bit more flexible, but a regular person, who doesn't care about these detail, might wonder why this is not handled by SPUD directly (see option 2), if the problem is known and the system not usable without the fix anyway.

    opened by cbQB 6
  • Fix nested uobject

    Fix nested uobject

    Hi, I found problem what I believe are nested UObjects, but it should be in your master without any my changes so I want to let you know. I split pull request into 2 commits:

    • First is just added test that create Parent and 5 children classes. It is not nice code but I need all 6 classes different and this do it's job.
    • Second commit is potential fix.

    Repro with only first commit:

    • Run "SPUDTest.NestedObject" test in Session Frontend. It should fail that it can't restore objects.
    • Or better is to start editor with "-stompmalloc" parameter to enable stomp allocator which checks whether you write to invalid pointer and stop debugger much sooner which helps me very much to find problem.

    Context:

    Reason why it failed is connected to reference to value in FSpudClassMetadata::ClassDefinitions saved in USpudState::StoreObjectProperties in auto& ClassDef variable. And that when adding 5th element into ClassDefinitions in FSpudClassMetadata::FindOrAddClassDef the array is resized. Don't know whether resize after 4th element is Unreal default or some platform specific.

    Please check this callstack:

    USpudState::StoreObjectProperties(UObject * Obj, unsigned int PrefixID, TArray<unsigned int,TSizedDefaultAllocator<32>> & PropOffsets, FSpudClassMetadata & Meta, FMemoryWriter & Out, int StartDepth) Line 407
    USpudState::StorePropertyVisitor::StoreNestedUObjectIfNeeded(UObject * RootObject, FProperty * Property, unsigned int CurrentPrefixID, void * ContainerPtr, int Depth) Line 116
    USpudState::StorePropertyVisitor::VisitProperty(UObject * RootObject, FProperty * Property, unsigned int CurrentPrefixID, void * ContainerPtr, int Depth) Line 84
    SpudPropertyUtil::VisitPersistentProperties(UObject * RootObject, const UStruct * Definition, unsigned int PrefixID, void * ContainerPtr, bool IsChildOfSaveGame, int Depth, SpudPropertyUtil::PropertyVisitor & Visitor) Line 304
    SpudPropertyUtil::VisitPersistentProperties(UObject * RootObject, SpudPropertyUtil::PropertyVisitor & Visitor, int StartDepth) Line 277
    USpudState::StoreObjectProperties(UObject * Obj, unsigned int PrefixID, TArray<unsigned int,TSizedDefaultAllocator<32>> & PropOffsets, FSpudClassMetadata & Meta, FMemoryWriter & Out, int StartDepth) Line 407
    USpudState::StoreObjectProperties(UObject * Obj, FSpudPropertyData & Properties, FSpudClassMetadata & Meta, int StartDepth) Line 395
    USpudState::StoreGlobalObject(UObject * Obj, FSpudNamedObjectData * Data) Line 372
    USpudState::StoreGlobalObject(UObject * Obj, const FString & ID) Line 355
    FTestNestedObject::RunTest(const FString & Parameters) Line 312
    

    USpudState::StoreObjectProperties is there twice so auto& ClassDef is invalid when second call of this function resize ClassDefinitions array.

    I don't know whether there is better solution than just have array of pointers and create items dynamically instead of array of instances. So feel free to just use or rewrite just the test. I hope it will help.

    opened by Nesquick0 5
  • Support for FText and FMap property

    Support for FText and FMap property

    I tried to add support for FText which should be just copy of FName.

    Second is support for FMap serialization. I tried to do it similar to FArray so there is a lot copy/paste and that it will fit into your systems without any major changes. I have to figure out how to save property type unique which will contain both key type and value type. I added ESST_Max = 64 and calculate it as "KeyType * ESST_Max + ValueType". I think it gives enough space for more ESST_ types and still be unique for any type of key/value types combination.

    Also added tests for FText and some TMap types combination.

    opened by Nesquick0 3
Owner
Steve Streeting
Game developer. I previously created Ogre3D and SourceTree, and had a hand in Git LFS.
Steve Streeting
Warp speed Data Transfer (WDT) is an embeddedable library (and command line tool) aiming to transfer data between 2 systems as fast as possible over multiple TCP paths.

WDT Warp speed Data Transfer Design philosophy/Overview Goal: Lowest possible total transfer time - to be only hardware limited (disc or network bandw

Facebook 2.7k Jul 26, 2022
A small data-oriented and SIMD-optimized 3D rigid body physics library.

nudge Nudge is a small data-oriented and SIMD-optimized 3D rigid body physics library. For more information, see: http://rasmusbarr.github.io/blog/dod

null 235 Aug 7, 2022
A software C library designed to extract data attributes from network packets, server logs, and from structured events in general, in order to make them available for analysis

MMT-DPI A software C library desinged to extract data attributes from network packets, server logs, and from structured events in general, in odrder t

Montimage 3 Apr 14, 2022
Data Plane Development Kit

DPDK is a set of libraries and drivers for fast packet processing. It supports many processor architectures and both FreeBSD and Linux. The DPDK uses

DPDK 2k Aug 12, 2022
Realtime Client/Server app for Linux allowing joystick (and other HID) data to be transferred over a local network

netstick What is it? Netstick enables HID devices to be remotely connected between a "client" and "server" over a network connection. It allows the ke

null 29 Jul 24, 2022
Upload arbitrary data via Apple's Find My network.

Send My allows you to to upload abritrary data from devices without an internet connection by (ab)using Apple's Find My network. The data is broadcasted via Bluetooth Low Energy and forwarded by nearby Apple devices.

Positive Security 1.5k Jul 30, 2022
Wifi MQTT Data Logging via an esp8266 for the Ikea VINDRIKTNING PM2.5 air quality sensor

MQTT connectivity for the Ikea VINDRIKTNING This repository contains an ESP8266 firmware, which adds MQTT to the Ikea VINDRIKTNING PM2.5 air quality s

Sören Beye 865 Aug 5, 2022
Tool for Preventing Data Exfiltration with eBPF

bouheki: Tool for Preventing Data Exfiltration with eBPF bouheki is a KSRI implementation using LSM Hook by eBPF. Flexibility to apply restricted netw

mrtc0 44 Aug 3, 2022
WDT Warp speed Data Transfer

Warp speed Data Transfer (WDT) is an embeddedable library (and command line tool) aiming to transfer data between 2 systems as fast as possible over multiple TCP paths.

Meta Archive 2.7k Jul 26, 2022
Data-oriented networking playground for the reliable UDP transports

NetDynamics is a data-oriented networking playground for the reliable UDP transports. The application was created for stress testing and debugging a p

Stanislav Denisov 89 Aug 9, 2022
Mongoose Embedded Web Server Library - a multi-protocol embedded networking library with TCP/UDP, HTTP, WebSocket, MQTT built-in protocols, async DNS resolver, and non-blocking API.

Mongoose - Embedded Web Server / Embedded Networking Library Mongoose is a networking library for C/C++. It implements event-driven non-blocking APIs

Cesanta Software 8.6k Aug 8, 2022
C Hypertext Library - A library for writing web applications in C

CHL C Hypertext Library - A library for writing web applications in C #include <chl/chl.h> int main() { chl_set_default_headers(); chl_print_header

null 272 Jun 20, 2022
The C++ Network Library Project -- cross-platform, standards compliant networking library.

C++ Network Library Modern C++ network programming libraries. Join us on Slack: http://slack.cpp-netlib.org/ Subscribe to the mailing list: https://gr

C++ Network Library 1.9k Aug 9, 2022
C++ peer to peer library, built on the top of boost

Breep What is Breep? Breep is a c++ bridged peer to peer library. What does that mean? It means that even though the network is constructed as a peer

Lucas Lazare 112 Jul 15, 2022
Cross-platform, efficient, customizable, and robust asynchronous HTTP/WebSocket server C++14 library with the right balance between performance and ease of use

What Is RESTinio? RESTinio is a header-only C++14 library that gives you an embedded HTTP/Websocket server. It is based on standalone version of ASIO

Stiffstream 871 Aug 9, 2022
A C library for asynchronous DNS requests

c-ares This is c-ares, an asynchronous resolver library. It is intended for applications which need to perform DNS queries without blocking, or need t

c-ares 1.5k Aug 5, 2022
A C++ header-only HTTP/HTTPS server and client library

cpp-httplib A C++11 single-file header-only cross platform HTTP/HTTPS library. It's extremely easy to setup. Just include the httplib.h file in your c

null 7.5k Aug 5, 2022
Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and 10K connections problem solution

CppServer Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and

Ivan Shynkarenka 867 Aug 8, 2022
ENet reliable UDP networking library

Please visit the ENet homepage at http://enet.bespin.org for installation and usage instructions. If you obtained this package from github, the quick

Lee Salzman 2.2k Aug 9, 2022