Start here
Enforce Script basics
Everything you need to know before the first line of walker code – for people who can program a little, but have not modded Arma Reforger yet.
The tools
- Arma Reforger Tools (free on Steam) contain the Workbench: world editor, prefab editor, script editor and the compiler.
- Create your own addon in the Workbench launcher (Create new project). It gets its own folder under
Documents/My Games/ArmaReforgerWorkbench/addons/. - Scripts go into
Scripts/Game/<YourFolder>/inside the addon. Every.cfile there is compiled automatically – there is no list to register them in.
Enforce Script in two minutes
Enforce Script looks like C# or Java: classes, methods, if/for, strong types. A few things are
different:
| Thing | What it means |
|---|---|
vector | three floats (x, y, z). y is up, z is forward. v[0], v[1], v[2] read the parts. |
vector mat[4] | a transform: three axis vectors (right, up, forward) and the position in mat[3]. |
ref | strong reference for class members holding objects (ref array<int> m_aList). Without it the object can be deleted. |
override | required when you replace a method of the parent class. |
modded class X | changes an existing class (also vanilla ones) everywhere, without copying it. |
| angles | most engine angles are degrees, but some setters want radians – check the method comment. |
Components: how code gets into the game
You do not write a main(). You write a component and add it to a prefab (an entity template,
for example a vehicle) in the Workbench. A component always comes as a pair of classes:
// 1) the "Class" class: holds data shared by all instances; the editor props make it show up in the Workbench
[ComponentEditorProps(category: "MyMod", description: "Prints the speed of the vehicle")]
class MyMod_SpeedPrinterComponentClass : ScriptComponentClass
{
}
// 2) the component itself: one instance per entity
class MyMod_SpeedPrinterComponent : ScriptComponent
{
// [Attribute] = editable in the prefab editor, value saved in the prefab
[Attribute("1.0", desc: "Print every n seconds")]
protected float m_fInterval;
protected float m_fTimer;
//! called once when the entity is created
override void OnPostInit(IEntity owner)
{
super.OnPostInit(owner);
SetEventMask(owner, EntityEvent.FRAME); // without this, EOnFrame is never called
}
//! called every frame
override void EOnFrame(IEntity owner, float timeSlice)
{
m_fTimer += timeSlice; // timeSlice = seconds since the last frame
if (m_fTimer < m_fInterval)
return;
m_fTimer = 0;
Physics phys = owner.GetPhysics();
if (phys)
Print("Speed: " + (phys.GetVelocity().Length() * 3.6).ToString() + " km/h");
}
}
Compile (Script Editor → Compile and Reload), open a vehicle prefab, Add component → your component appears under the category you gave it. Drive the vehicle in the world editor (Play) and watch the log console.
Print output goes to the console of the Workbench and into console.log in the profile's logs folder. Logging is your main debugging tool – use it generously while building.Multiplayer in plain words
In multiplayer the same entity exists on the server and on every client. Your component runs on all of them. Three questions decide where code has to run:
| Question | Answer in code |
|---|---|
| Is this the server? | Replication.IsServer() – decides game rules, damage, who may do what. |
| Does this machine simulate the physics of this entity? | RplComponent.IsOwner() – only the owner should change velocities. |
| Is this only for looks? | Run it everywhere: animation, effects, sound, HUD. |
Two tools move information around:
[RplProp()]on a member variable: the server sets it, callsReplication.BumpMe(), and all clients receive the new value. Optionally a callback (onRplName) runs on the clients when it arrives.[RplRpc(...)]on a method: a call that is executed on another machine (client → server, server → owner, or to everybody).
SCR_PlayerController. RPCs sent from a vehicle component disappear without any error message. See Architecture for the pattern.Testing in multiplayer
- First test in the world editor (singleplayer = server and client in one).
- Then on a real dedicated server with a separate client. Things that work in the editor often break there, because the client is no longer the server and no longer the physics owner.
- Read both logs: the server's and the client's
console.log.