Scripting
Engine-owned documentation. This page describes reusable scripting runtime behavior in
Source/Common/ScriptSystem.*andSource/Scripting/; concrete game scripts, quests, rules, and content policy belong to the embedding project.
Purpose
The scripting layer is the contract between the C++ engine runtime and game-authored behavior. It exposes engine entities, global services, events, remote calls, value types, collections, reflection helpers, and tool/frontend helpers to script code while keeping C++ ownership, metadata, nullability, persistence, networking, and validation in the engine.
Read this page together with:
- GeneratedApiAndMetadata.md for generated metadata,
///@annotations, and codegen output. - Nullability.md for
T?andFO_NULLABLEcontracts across script/native boundaries. - EntityModel.md for entity, prototype, property, and holder concepts exposed to scripts.
- ServerRuntime.md and ClientRuntime.md for runtime events and script callback ownership.
- MapperTools.md for mapper-specific script helpers.
- ScriptMethodsMap.md for the native script method file map.
Source paths inspected
Source/Common/ScriptSystem.hSource/Common/ScriptSystem.cppSource/Scripting/AngelScript/AngelScriptScripting.hSource/Scripting/AngelScript/AngelScriptScripting.cppSource/Scripting/AngelScript/AngelScriptBackend.hSource/Scripting/AngelScript/AngelScriptBackend.cppSource/Scripting/AngelScript/AngelScriptAttributes.cppSource/Scripting/AngelScript/AngelScriptCall.cppSource/Scripting/AngelScript/AngelScriptEntity.cppSource/Scripting/AngelScript/AngelScriptGlobals.cppSource/Scripting/AngelScript/AngelScriptRemoteCalls.cppSource/Scripting/AngelScript/AngelScriptReflection.cppSource/Scripting/AngelScript/CoreScripts/*.fosSource/Scripting/*ScriptMethods.cppSource/Scripting/Mono/*.csSource/Scripting/Native/.keepaliveBuildTools/cmake/stages/ScriptsAndBaking.cmakeSource/Tests/Test_AngelScriptAttributes.cppSource/Tests/Test_AngelScriptBaker.cppSource/Tests/Test_AngelScriptBytecode.cppSource/Tests/Test_CommonScriptMethods.cppSource/Tests/Test_ScriptBuiltins.cppSource/Tests/Test_ScriptEntityOps.cppSource/Tests/Test_ServerScriptMethods.cpp
Layer map
The scripting subsystem has four layers:
- Common runtime facade —
Source/Common/ScriptSystem.h/.cppdefine the backend-agnosticScriptSystem,ScriptFuncDesc,ScriptFunc,FuncCallData,DataAccessor, native call adapters, init functions, loop callbacks, and type maps. - Backend implementation —
Source/Scripting/AngelScript/provides the current production backend. Mono and native scripting have placeholder/source roots, but AngelScript owns the implemented script compiler/runtime path in this tree. - Script-visible native methods —
Source/Scripting/*ScriptMethods.cppfiles contain///@ ExportMethodfunctions grouped by runtime side and receiver type. Codegen reads these annotations and emits method descriptors/wrappers. - Core script library and game scripts —
Source/Scripting/AngelScript/CoreScripts/*.fosprovides engine-owned reusable script-side helpers. Embedding projects add their own.fosfiles and metadata through project configuration and resource/script baking.
The engine owns the reusable bridge. The embedding project owns game scripts and chooses which features are enabled through project configuration, build presets, and .fomain inputs.
ScriptSystem: backend-neutral dispatch
ScriptSystem is the C++ runtime facade used by client, server, mapper, tests, and script-aware tools. Its main jobs are:
- register one or more
ScriptSystemBackendinstances withRegisterBackend(); - map C++ types to metadata descriptors with
MapScriptTypes()andMapEngineType()/MapEngineDictType(); - initialize modules with
InitModules(); - find and invoke global functions through
FindFunc(),CheckFunc(),CallFunc(), andCallAdminFunc(); - store
ScriptFuncDescentries from backends withAddGlobalScriptFunc(); - run registered init functions and loop callbacks through
AddInitFunc(),AddLoopCallback(), andProcessScriptEvents().
ScriptFunc<TRet, Args...> normalizes native arguments into FuncCallData and catches script exceptions so callers can continue after a failed script callback. NativeDataProvider and NativeDataCaller adapt C++ arrays, dictionaries, entities, callbacks, value types, and mutable references to the generic call representation.
This boundary is also where generated nullability checks are inserted. NativeDataProvider::CheckArgNotNull() and CheckReturnNotNull() are called by codegen-generated MethodDesc::Call lambdas, not only by the AngelScript adapter. See Nullability.md for the full contract.
AngelScript runtime path
InitAngelScriptScripting() in Source/Scripting/AngelScript/AngelScriptScripting.cpp prepares the AngelScript runtime, creates an AngelScriptBackend, registers it at ScriptSystemBackend::ANGELSCRIPT_BACKEND_INDEX, and loads binary scripts from resources.
CompileAngelScript() is the compiler-side entry point used by tools/tests. It creates a standalone ScriptSystem, registers metadata, compiles text script files, and returns bytecode.
AngelScriptBackend owns the concrete engine instance and module lifecycle:
RegisterMetadata()binds engine metadata and registers C++/script-visible types.BindRequiredStuff()registers arrays, dictionaries, strings, math/value types, globals, entity wrappers, remote callers, reflection helpers, and backend helpers.CompileTextScripts()preprocesses script source, adds script sections to a module, resolves includes, builds the module, and serializes bytecode.LoadBinaryScripts()loads compiled bytecode from resources at runtime.SetMessageCallback()/SendMessage()route compiler/runtime diagnostics to the caller.- cleanup callbacks and post-cleanup callbacks release backend-owned resources in a controlled order.
AngelScript is therefore used in two modes: compile-time tooling mode and runtime mode. The same metadata and type registration code must remain compatible with both.
Attributes, declarations, and metadata
Source/Scripting/AngelScript/AngelScriptAttributes.cpp parses engine-specific script attributes and declaration tags. Important contracts include:
- nullable
T?suffix stripping and propagation into metadata; ///@ Eventdeclarations and matching[[Event]]handlers;///@ RemoteCalldeclarations and matching[[ServerRemoteCall]],[[ClientRemoteCall]], or[[AdminRemoteCall]]implementations;- module/init-function priorities;
- callback attribute validation rules.
These attributes are source-level contracts. AngelScript sees normalized declarations after preprocessing, while engine metadata and analyzers retain the higher-level FOnline-specific meaning.
Entities and properties in scripts
Source/Scripting/AngelScript/AngelScriptEntity.cpp registers script object types for engine entities, singleton-like components, property accessors, entity event types, and method dispatch. It bridges generated metadata with AngelScript registration calls so script code can work with engine entities through script-visible names such as critters, items, maps, locations, players, prototypes, abstracts, statics, holders, and property-backed components.
Entity lifetime is still owned by the engine runtime:
- server scripts work against authoritative entities owned by
ServerEngineand managers; - client scripts work against view/client entities owned by
ClientEngine; - mapper scripts work against mapper-owned editor state;
- script handles must not be treated as persistence ownership.
Use EntityModel.md for entity/property/prototype ownership and Persistence.md for database boundaries.
Remote calls and event callbacks
Source/Scripting/AngelScript/AngelScriptRemoteCalls.cpp registers remote caller object types such as RemoteCaller and CritterRemoteCaller. Remote-call declarations are metadata-backed, and runtime handling is split by side:
- server-side command processing validates client-originated remote calls before invoking server script handlers;
- client-side runtime receives server-originated remote calls and dispatches client script handlers;
- admin remote calls use the
CallAdminFunc()path and require theAdminRemoteCallattribute.
Events and remote calls are intentionally separate concepts. Events describe engine/runtime lifecycle and gameplay notifications; remote calls describe network-addressable script entry points. Both rely on metadata signatures, nullability contracts, and generated descriptors.
Native script method exports
Native script APIs are grouped by file name:
Common*ScriptMethods.cpp— APIs shared by multiple sides, including global helpers and ImGui wrappers.Server*ScriptMethods.cpp— authoritative server APIs for game creation, persistence, movement, entity mutation, and player/critter/map/item/location operations.Client*ScriptMethods.cpp— client/view APIs for UI, resources, rendering-facing map operations, visible critters/items, audio/video, input, and local state.Mapper*ScriptMethods.cpp— mapper/editor APIs for creating, moving, selecting, saving, and organizing map entities.
Each exported function is marked with ///@ ExportMethod and normally starts with a side/type prefix such as Server_Map_, Client_Game_, Common_ImGui_, or Mapper_Game_. Codegen turns these declarations into script-visible method descriptors and backend call wrappers. See ScriptMethodsMap.md for the per-file map and counts.
When adding a method, route it to the side that owns the state it mutates. For example, authoritative item creation belongs under server methods, while sprite/UI helpers belong under client/common frontend methods.
Core scripts
The engine-owned AngelScript core library lives in Source/Scripting/AngelScript/CoreScripts/ and includes reusable modules such as:
Core.fosMath.fosTime.fosColors.fosInput.fosGui.fosSprite.fosLineTracer.fosSerializator.fosMapperCore.fosFixedDropMenu.fosTween.fos
Treat these files as engine library code. Game-specific script modules should live in the embedding project instead of expanding the engine core script library with project policy.
Build and baking flow
BuildTools/cmake/stages/ScriptsAndBaking.cmake wires script compilation into the project build:
FO_ANGELSCRIPT_SCRIPTINGenables theCompileAngelScriptcommand target.- The target runs the project AS compiler app (
${FO_DEV_NAME}_ASCompiler) with the main config arguments. CompileAngelScriptdepends onForceCodeGeneration, so script-visible generated metadata is current before compilation.FO_MONO_SCRIPTINGwiresCompileMonoScriptsthroughBuildTools/compile-mono-scripts.pyandFO_MONO_ASSEMBLIES/FO_MONO_SOURCE.BakeResourcesandForceBakeResourcesalso depend on code generation and run the project baker app.
Script compilation and resource baking are adjacent but not identical. Script compilation produces bytecode/runtime inputs; baking packages resources and metadata for runtime consumption. See BakingPipeline.md for resource baking.
Mono and native scripting roots
Source/Scripting/Mono/ contains C# support files such as AssemblyInfo.cs, BasicTypes.cs, Entity.cs, Initializator.cs, MapSprite.cs, and Link.xml. BuildTools can wire Mono compilation when FO_MONO_SCRIPTING is enabled.
Source/Scripting/Native/ currently contains .keepalive, marking the source-root location for native scripting integration. Do not document Native or Mono as equivalent to the AngelScript runtime unless the implementation and tests are expanded.
Tests to inspect
Script behavior is covered by focused tests:
Source/Tests/Test_AngelScriptAttributes.cpp— attribute parsing, nullable suffix handling, events, remote calls, and callback rules.Source/Tests/Test_AngelScriptBaker.cpp— AngelScript bytecode/resource baking path.Source/Tests/Test_AngelScriptBytecode.cpp— bytecode compilation/loading behavior.Source/Tests/Test_CommonScriptMethods.cpp— common exported methods.Source/Tests/Test_ServerScriptMethods.cpp— server exported methods.Source/Tests/Test_ScriptBuiltins.cpp— built-in script helpers/types.Source/Tests/Test_ScriptEntityOps.cpp— script/entity interactions.
Use these tests as executable documentation when changing script registration, generated wrappers, method signatures, nullability, event declarations, or remote-call dispatch.
Change routing
- Backend-neutral call ABI:
Source/Common/ScriptSystem.*. - AngelScript compiler/runtime lifecycle:
Source/Scripting/AngelScript/AngelScriptScripting.*andAngelScriptBackend.*. - Attribute syntax and nullable preprocessing:
Source/Scripting/AngelScript/AngelScriptAttributes.*and Nullability.md. - Script entity/property registration:
Source/Scripting/AngelScript/AngelScriptEntity.*plus EntityModel.md. - Remote caller registration/dispatch support:
Source/Scripting/AngelScript/AngelScriptRemoteCalls.*plus Networking.md. - Reflection helpers:
Source/Scripting/AngelScript/AngelScriptReflection.*. - Native exported methods:
Source/Scripting/*ScriptMethods.cppand ScriptMethodsMap.md. - Build target wiring:
BuildTools/cmake/stages/ScriptsAndBaking.cmakeand BuildToolsPipeline.md. - Generated metadata/codegen: GeneratedApiAndMetadata.md.
Validation checklist
- If signatures or annotations changed, regenerate code and inspect generated metadata/wrapper diffs.
- Compile AngelScript through the embedding project’s
CompileAngelScripttarget or equivalent AS compiler app. - Run the smallest affected script tests, starting with
Test_AngelScriptAttributes,Test_CommonScriptMethods,Test_ServerScriptMethods,Test_ScriptBuiltins, andTest_ScriptEntityOpsas applicable. - For nullable changes, run the nullability analyzers described in Nullability.md.
- For server/client/mapper method changes, validate the owning runtime path; do not rely only on compilation.
- Update ScriptMethodsMap.md when exported method files are added, removed, or materially regrouped.