Resource Usage – Arma Reforger

From Bohemia Interactive Community
Jump to navigation Jump to search
m (Lou Montana moved page Arma Reforger:BaseContainer Usage to Arma Reforger:Resource Usage without leaving a redirect: Name standard)
(Fix phrasing, Add example)
Line 1: Line 1:
{{TOC|side}}
{{TOC|side}}
A {{Link/Enfusion|armaR|BaseContainer}} object is a data container obtained from a {{Link/Enfusion|armaR|Resource}} object. Due to how resources are managed, some safeties are required.
A {{Link/Enfusion|armaR|Resource}} object is a source of data through many classes ({{Link/Enfusion|armaR|BaseContainer}}, {{Link/Enfusion|armaR|IEntitySource}} etc).
Due to how resources are managed, some safeties are required.




== Good Practice ==
== Good Practice ==


Resources are managed by the engine, outside of script's reach. If the script loses reference to a Resource object, the engine may dispose of it instantly or at some point in the future, deleting also its related BaseContainer objects.
Resources are managed by the engine, outside of script's reach.
If the script loses reference to a Resource object, the engine may dispose of it instantly or at some point in the future, deleting also its related BaseContainer objects.
To avoid this, always keep a reference to the parent Resource.
To avoid this, always keep a reference to the parent Resource.


Line 41: Line 43:
| <enforce>
| <enforce>
// GetBaseContainer being the above method
// GetBaseContainer being the above method
BaseContainer baseContainer = GetBaseContainer(m_sPrefab); // not OK
BaseContainer baseContainer = GetBaseContainer(m_sPrefab);
string name = baseContainer.GetClassName(); // may result in a null pointer exception
string name = baseContainer.GetClassName(); // may result in a null pointer exception
</enforce>
</enforce>
| <enforce>
| <enforce>
Resource resource = Resource.Load(m_sPrefab);
Resource resource = Resource.Load(m_sPrefab);
BaseContainer baseContainer = GetBaseContainer(resource); // OK
BaseContainer baseContainer = GetBaseContainer(resource);
string name = baseContainer.GetClassName(); // fine as long as reference to resource is kept
string name = baseContainer.GetClassName(); // fine as long as a reference to resource is kept
</enforce>
|-
| <enforce>
// beware of loops!
array<ref BaseContainer> baseContainers = {}; // strong ref
Resource resource;
foreach (ResourceName resourceName : resourceNames)
{
resource = Resource.Load(resourceName);
if (!resource.IsValid())
continue;
 
 
baseContainers.Insert(resource.GetResource().ToBaseContainer());
// reference to resource is lost at each loop end
}
 
Process(baseContainers); // the array may contain nulls
</enforce>
| <enforce>
array<ref Resource> resources = {};
array<BaseContainer> baseContainers = {}; // weak ref
Resource resource;
foreach (ResourceName resourceName : resourceNames)
{
resource = Resource.Load(resourceName);
if (!resource.IsValid())
continue;
 
resources.Insert(resource);
baseContainers.Insert(resource.GetResource().ToBaseContainer());
// reference to resource is kept in the resources array
}
 
Process(baseContainers); // all references are kept
resources = null; // this can now be done without issue
</enforce>
</enforce>
|-
|-

Revision as of 17:55, 15 November 2023

A Resource object is a source of data through many classes (BaseContainer, IEntitySource etc). Due to how resources are managed, some safeties are required.


Good Practice

Resources are managed by the engine, outside of script's reach. If the script loses reference to a Resource object, the engine may dispose of it instantly or at some point in the future, deleting also its related BaseContainer objects. To avoid this, always keep a reference to the parent Resource.

Examples

Bad Example Good Example
static BaseContainer GetBaseContainer(ResourceName resourceName) { // the only reference to said Resource is here and will be lost at the end of the scope Resource resource = Resource.Load(resourceName); if (!resource.IsValid()) return null; return resource.GetResource().ToBaseContainer(); // resource's reference is dropped here // the returned BaseContainer may become null at any time, // even with a script's reference }
static BaseContainer GetBaseContainer(notnull Resource resource) { if (!resource.IsValid()) return null; return resource.GetResource().ToBaseContainer(); // resource's reference is managed by the method caller }
// GetBaseContainer being the above method BaseContainer baseContainer = GetBaseContainer(m_sPrefab); string name = baseContainer.GetClassName(); // may result in a null pointer exception
Resource resource = Resource.Load(m_sPrefab); BaseContainer baseContainer = GetBaseContainer(resource); string name = baseContainer.GetClassName(); // fine as long as a reference to resource is kept
// beware of loops! array<ref BaseContainer> baseContainers = {}; // strong ref Resource resource; foreach (ResourceName resourceName : resourceNames) { resource = Resource.Load(resourceName); if (!resource.IsValid()) continue; baseContainers.Insert(resource.GetResource().ToBaseContainer()); // reference to resource is lost at each loop end } Process(baseContainers); // the array may contain nulls
array<ref Resource> resources = {}; array<BaseContainer> baseContainers = {}; // weak ref Resource resource; foreach (ResourceName resourceName : resourceNames) { resource = Resource.Load(resourceName); if (!resource.IsValid()) continue; resources.Insert(resource); baseContainers.Insert(resource.GetResource().ToBaseContainer()); // reference to resource is kept in the resources array } Process(baseContainers); // all references are kept resources = null; // this can now be done without issue
N/A
// this is fine - a Managed instance is created, resource can be dropped // simplified, from SCR_BaseContainerTools.CreateInstanceFromPrefab() static Managed CreateInstanceFromPrefab(ResourceName prefab) { Resource resource = Resource.Load(prefab); if (!resource.IsValid()) return null; BaseContainer baseContainer = resource.GetResource().ToBaseContainer(); if (!baseContainer) return null; return BaseContainerTools.CreateInstanceFromContainer(baseContainer); // resource reference is dropped but the created instance will remain }