Skip to content

Commit 8e60bc8

Browse files
author
Roberto De Ioris
authored
Update MemoryManagement.md
1 parent 5a08182 commit 8e60bc8

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

docs/MemoryManagement.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,50 @@ import unreal_engine as ue
186186
# you can reference to Unreal classes with a string
187187
material = ue.new_object(ue.find_class('Material'), None, 'DumbMaterial001', ue.RF_PUBLIC|ue.RF_STANDALONE)
188188
```
189+
190+
191+
## UStruct
192+
193+
UStruct's are the UE representation of low-level C/C++ structs. They work both as POD (Plain Old Data, like in C) and as class-like objects (with methods, but no encapsulation). From the Blueprint point of view, UStruct's are POD (generally in the form of User Defined Structs), while in the C++ api, most of them have regular methods.
194+
195+
UStruct in the python api are passed by value (as there is no way to track them safely, so dangling pointers could spawn up all over the place), and this leads to some common headache:
196+
197+
```python
198+
from unreal_engine.structs import StaticMeshSourceModel, MeshBuildSettings
199+
lod1 = StaticMeshSourceModel(BuildSettings=MeshBuildSettings(bRecomputeNormals=False, bRecomputeTangents=True, bUseMikkTSpace=True, bBuildAdjacencyBuffer=True, bRemoveDegenerates=True))
200+
```
201+
202+
In this example we are generating a new LOD for a StaticMesh using the StaticMeshSourceModel UStruct (https://api.unrealengine.com/INT/API/Runtime/Engine/Engine/FStaticMeshSourceModel/index.html)
203+
204+
now you may think that the following code will modify the bRecomputeNormals of lod1:
205+
206+
```python
207+
# WRONG you are working on a copy !!!
208+
lod1.BuildSettings.bRecomputeNormals = True
209+
```
210+
211+
but (as you read in the comment) it is wrong as lod1.BuildSettings will return a copy of the original MeshBuildSettings UStruct, so technically you are updating a brand new structure that will be destroyed soon after.
212+
213+
Instead you should recreate and assign a whole new MeshBuildSettings:
214+
215+
```python
216+
lod1.BuildSettings = MeshBuildSettings(bRecomputeNormals=True, bRecomputeTangents=True, bUseMikkTSpace=True, bBuildAdjacencyBuffer=True, bRemoveDegenerates=True)
217+
```
218+
219+
If you need you can make a copy/clone of a struct to avoid copy/paste code:
220+
221+
```python
222+
mesh_build_settings = lod1.BuildSettings.clone()
223+
mesh_build_settings.bRecomputeNormals = True
224+
lod1.BuildSettings = mesh_build_settings
225+
```
226+
227+
This kind of work-mode is not very pythonic (and generally unintuitive) but it is the safest way to avoid very-hard-to-debug crashes triggered by dangling pointers generated by the way structures works in UE.
228+
229+
If instead, you know what you are doing, you can work in pass-by-ref mode with structures:
230+
231+
```python
232+
lod1.BuildSettings.ref().bRecomputeNormals = True
233+
```
234+
235+
The ref() method will return a new structure that contains a reference/pointer to the original one. This is possible as whenever we create a new UStruct we save its value as well as its pointer. Obviously ref() can point to a non valid memory area, in such a case expect any kind of evilness ;)

0 commit comments

Comments
 (0)