Overthrow uses Enfusion engine's entity-component-based architecture with several established patterns for different types of components.
Manager components are singletons placed on the OVT_OverthrowGameMode.et
prefab and tasked with management of a single system or feature within the game mode.
class OVT_SomeManagerComponentClass: OVT_ComponentClass {};
class OVT_SomeManagerComponent: OVT_Component {
[Attribute("1", desc: "A parameter description")]
int m_iSomeParameter; //A parameter configurable in the Arma Reforger Tools
static OVT_SomeManagerComponent s_Instance;
static OVT_SomeManagerComponent GetInstance()
{
if (!s_Instance)
{
BaseGameMode pGameMode = GetGame().GetGameMode();
if (pGameMode)
s_Instance = OVT_SomeManagerComponent.Cast(pGameMode.FindComponent(OVT_SomeManagerComponent));
}
return s_Instance;
}
void Init(IEntity owner) { ... } //Is called manually by OVT_OverthrowGameMode for initialization if needed
void PostGameStart() { ... } //Is called manually by OVT_OverthrowGameMode after a new game is started
}
Controllers manage a single instance of an entity on the server (for example a base, town, camp etc), replication of the state of that instance to all clients, and persistence of that state if required in EPF. It is an OVT_Component
extended component attached to an entity that is spawned at runtime or added to the world in the editor.
Important: Controllers should NOT be singletons. They should register themselves with their respective manager in the constructor.
class OVT_SomeControllerComponentClass: OVT_ComponentClass {};
class OVT_SomeControllerComponent: OVT_Component
{
[Attribute("1", desc: "A parameter description")]
protected int m_iSomeParameter; //A parameter configurable in the Arma Reforger Tools
void OVT_SomeControllerComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
{
OVT_Global.GetManager().RegisterSomeController(this);
}
void Init(IEntity owner) { ... } //May not be called unless manager registration calls it manually
//use getters and setters to expose parameters
int GetSomeParameter() {return m_iSomeParameter;}
void SetSomeParameter(int someParameter){m_iSomeParameter = someParameter;}
}
Don't make monolithic controllers. Split their systems up as required with non-controller sub-components that manage a specific system on the same entity.
class OVT_SomeComponentClass: OVT_ComponentClass {};
class OVT_SomeComponent: OVT_Component
{
[Attribute("1", desc: "A parameter description")]
protected int m_iSomeParameter; //A parameter configurable in the Arma Reforger Tools
void Init(IEntity owner) { ... }
//use getters and setters to expose parameters
int GetSomeParameter() {return m_iSomeParameter;}
void SetSomeParameter(int someParameter){m_iSomeParameter = someParameter;}
}
Simple data classes should extend Managed
. These can be persisted easily if needed in EPF. They should not contain any [Attribute()]
decorators.
class OVT_TownData : Managed
{
[NonSerialized()]
int nonSerializedInteger; //do not persist this to EPF
vector location;
int anInteger;
}
Any reference to Managed classes must be a strong ref to ensure they are only garbage collected when no references remain. Always use "ref" keyword for arrays, maps and instances of Managed classes within arrays/maps.
class OVT_TownManagerComponent: OVT_Component
{
ref OVT_TownData m_SelectedTown;
ref array<ref OVT_TownData> m_Towns;
ref map<int, ref OVT_TownData> m_mTowns;
}
Note: You do not need to and cannot strong ref int, string, float, bool, IEntity or EntityID. Only class instances.
Store EntityID instead of IEntity references and always check if the entity still exists when fetching:
// Store the id
EntityID id = entity.GetID();
//Fetch it later
IEntity entity = GetGame().GetWorld().FindEntityByID(id);
if(!entity) return; //clean up anything you need to if the entity no longer exists
These components are deprecated and should not be extended: