Limits
This page lists the limits and restrictions that apply to modules.
Callback Time Limit
A callback, including the entry file's top-level code, may run for at most 1 second. After that CONTROL stops it with the Lua error callback ran longer than the 1000 ms limit. Time spent inside a single CONTROL function call is not interrupted.
While a callback runs on the game's thread, the game waits for it. Keep Update() and Render() short.
Module Depth
- Module discovery: entry files in
modules\and up to three folders below it. See Module System. - require: names with up to four dot-separated parts, such as
require("ai.economy.farms.mill"). A fifth part makesrequirelog an error and returnnil. See require Behavior.
Multiplayer
- In a multiplayer match, modules run only when the match has cheats enabled. Without cheats, CONTROL treats the match as not running:
Init(),Update()andRender()are not called. - If CONTROL cannot tell whether a match is multiplayer, it treats it as multiplayer.
- The Agent Bridge is not available in multiplayer, even with cheats enabled.
Performance
Render()runs every frame. Do expensive work inUpdate()and keepRender()to drawing.GetClockMs()andGetModuleTelemetry()measure a module's own cost. The Module Telemetry view in the DEBUG menu shows every module and CONTROL's share of the frame. See Interface Options.- In Tournament Mode, the part of an
Update()call above 20 ms is added to the next update interval.
Sandbox
Modules have the Lua 5.4 base, string, table and math libraries. io, os, debug, coroutine, utf8 and package are not available.
These base functions are removed:
loadloadfiledofilemodulecollectgarbage
require is CONTROL's own version; see Module System. Use Log() for output; print() does not write to the log window.
Game API Timing
Most game functions need a running match. Called outside one, for example in Load() in the main menu, they log an error and return nil or a default value:
Lua error: Game API function called before the game started. Move this logic to Init(), Update() or End().
Game commands belong in Update(). See Commands outside Update.
Drawing
Draw functions (RenderText, RenderLine, RenderWorldCircle and the other Render* functions) work only inside Render(). Called from another callback, they raise an error.
Tournament Mode
With Tournament Mode on:
- Game commands outside
Update()are refused. - The functions below do nothing and return
nil,falseor an empty value. CONTROL logsTournament Mode blocked ...once per function and module load.
| Group | Functions |
|---|---|
| Engine | Log, SendChatMessage, SetCameraPosition, SetEngineUIVisibility, UnloadEngine, AssignAndLoadModule |
| Menu and session | DispatchStartGame, DispatchRestartGame, DispatchResignGame, DispatchQuitGame, DispatchLoadGame, GetAvailableSaveFiles, IsGamePaused, IsMenuOpen |
| Random maps | GetRandomMapControlCapabilities, GetRandomMapStartStatus, RefreshRandomMapSources, GetAvailableRandomMapSources, GetEffectiveRandomMapSeed, GetEffectiveRandomMapSource |
| Replays and speed | SetGamePaused, SetReplaySpeed, GetCurrentReplayFileName, SetGameSpeedMultiplier |
| Rendering | All Render* draw functions, GetScreenSize, IsOnScreen, IsWorldPosOnScreen, WorldToScreen, WorldToMinimap, GetZoom, GetCameraPosition |
| Game options | Every GameOptions method except SetAssignedPlayerCivilization |
Multithreading
With Multithreading on, each module runs on its own thread and reads a copy of the game state taken once per frame. Game commands are queued and carried out on the game's thread.
Render()is not called.- These functions do nothing and return
nil,falseor an empty value, and CONTROL logsMultithreading blocked ...once per function and module load:DispatchStartGame,DispatchRestartGame,DispatchResignGame,DispatchQuitGame,DispatchLoadGame,RefreshRandomMapSources,SetGamePaused,SetReplaySpeed,SetGameSpeedMultiplier,IPC.WaitForMessage,GetScreenSize,IsOnScreen,IsWorldPosOnScreen,WorldToScreen,WorldToMinimap,GetZoom,GetCameraPosition. ResourceTracker,VillagerOccupationandConstructionPlacementread the live game. TheirUpdate()raises an error.
Game-state copy
With Multithreading on, and while the Agent Bridge is on for any player, modules read a copy of the game state taken once per frame instead of the live game. These functions then behave differently:
GetFact,Player:GetFact,Object:GetAttributeandObject:GetObjectDatareturnnilfor values the copy does not hold.GetObjectTypeDatareturnsnilfor every field exceptObjectData.TRAIN_SITE.GetObjectTypeAttributereturnsnilfor every attribute exceptObjectAttribute.RADIUS_XandObjectAttribute.RADIUS_Y.CheckPlacement(),CanPlaceObject()andMapTile:IsBuildable()returnnil.GetMapTilereturnsnilfor a tile the assigned player has not explored, unless Modules See Everything is on.CalculatePathandObject:CalculatePathsearch the copied tiles instead of asking the game's pathfinder. The path moves between whole tiles that are explored and that nothing blocks, and is empty when the start or the target tile is not one of them.GetObjectsInAreacompares the object's exact position, not its tile.- Garrisoned units are in the copy, at the position of the object they are in. For them
GetGarrisonObject()returns that object, and only identity, class, type, owner, position andIsAlive()hold values; other methods return0,falseor an empty string.
IPC
| Limit | Value |
|---|---|
| Pipe name | 1 to 200 characters, no \ or /, must not start with AoE2Control |
Outbound message (IPC.Send) |
1 MiB |
| Messages waiting for one client | 1024 messages or 8 MiB |
| Inbound message | 1 MiB |
| Inbound messages waiting for the module | 1024 per module slot |
| Clients per pipe | 16 |
| Client that stops reading | disconnected after 5 seconds |
IPC.WaitForMessage |
waits at most 500 ms |
IPC API describes what happens when each limit is reached.
Agent Bridge
| Limit | Value |
|---|---|
| Request | 1 MiB |
| Response | 16 MiB |
| Programs per player | 1 session; it ends 30 seconds after its last request |
Actions per act request |
32 |
| Actions of one player waiting in the queue | 64 |
| Actors per action | 256 |
| Positions per placement query | 64 |
| Chat message | 200 characters |
act response |
waits at most 5 seconds for the game to run the actions |
| Connect, read, write | 5 seconds each |
Agent Bridge describes what happens when each limit is reached.