As many of us are now aware, the scripting runtime used in Civilization VII is based on JavaScript. (More specifically, Google's V8)
There appears to be at least two V8 isolates (execution environments), Tuner and App UI. Though, I suspect there may be one or two more for gameplay scripts and map scripts. When scripts are loaded, they are loaded into their own V8 context (execution scope) within their respective isolate, keeping their global namespaces separate from another. There may also be a mod action that allows you to load multiple scripts into a single context, thus sharing the same global namespace.
Civilization VII uses the Coherent UI library, you can find its website here: https://coherent-labs.com/Documentation/cpp/index.html. Coherent also has a remote debugger which you can attach to Civilization VII and details on how to use it are in the Coherent documentation.
The ways I know of doing communication between scripts so far is by doing one of the following:
Looking through the files, you have probably also noticed some TypeScript files, typically these aren't run directly, but rather are compiled into JavaScript ahead of time, which appears to be how they are handled here, too. The content of these files should never actually be read by the game, and only seem to be included in the game's install for modders to reference and maybe down the line, use for type information in their own mods using TypeScript; when replacing base-game scripts, you do not need to replace any TypeScript code, only JavaScript.
The purpose of TypeScript is to help developers spot bugs and write code more confidently using duck-typed annotations that integrate with code editors (through Intellisense, linting, etc). A promising implication of its integration into their scripting codebase is that native functions exposed to the scripting environment, such as
Until the modding SDK comes out, I would suggest that you do not write mods in TypeScript, it may be tempting but it will be a lot more trouble than it's worth, given that we don't yet have the type information for any new native functions.
Attached is a script that you can run to dump up to more or less an entire JavaScript context, and the output I got from running it through Firetuner in the Tuner and App UI contexts. You can use this information to help you write mods in JavaScript, until we have a better solution for documentation. UPDATE: an improved version of the script is now attached as well, but I haven't got the time yet to run it on the game, be aware, it may take a while if called on global
To get information on an arbitrary object, you can invoke the
UPDATE: Attached are lists of the many internal events which can be accessed in scripts. Reporting events are not yet well understood, but the other kinds of events can be subscribed to with
I will update this post with new information as it becomes available and discovered.
There appears to be at least two V8 isolates (execution environments), Tuner and App UI. Though, I suspect there may be one or two more for gameplay scripts and map scripts. When scripts are loaded, they are loaded into their own V8 context (execution scope) within their respective isolate, keeping their global namespaces separate from another. There may also be a mod action that allows you to load multiple scripts into a single context, thus sharing the same global namespace.
Civilization VII uses the Coherent UI library, you can find its website here: https://coherent-labs.com/Documentation/cpp/index.html. Coherent also has a remote debugger which you can attach to Civilization VII and details on how to use it are in the Coherent documentation.
The ways I know of doing communication between scripts so far is by doing one of the following:
- Commands and operations event drivers e.g.
Game.PlayerOperations.sendRequest(GameContext.localPlayerID, PlayerOperationTypes.EXECUTE_SCRIPT, args)
- Object properties. e.g.
Game.setProperty("some_property", someValue)
andGame.getProperty("some_property")
- Coherent UI event driver e.g.
engine.trigger("some-event", param1, param2, ..., paramN)
- Persistent data e.g.
engine.createJSModel('g_SomeGlobal', someValue)
(accessed directly via global variables in other contexts of the same isolate)
ExposedMembers
as far as I can tell.Looking through the files, you have probably also noticed some TypeScript files, typically these aren't run directly, but rather are compiled into JavaScript ahead of time, which appears to be how they are handled here, too. The content of these files should never actually be read by the game, and only seem to be included in the game's install for modders to reference and maybe down the line, use for type information in their own mods using TypeScript; when replacing base-game scripts, you do not need to replace any TypeScript code, only JavaScript.
The purpose of TypeScript is to help developers spot bugs and write code more confidently using duck-typed annotations that integrate with code editors (through Intellisense, linting, etc). A promising implication of its integration into their scripting codebase is that native functions exposed to the scripting environment, such as
Units.get
or Game.setProperty
, are likely documented in a definitions file that we haven't been given access to yet, rather than requiring us to document them manually as we did in the past. I hope we will receive access to these definitions with the release of the modding SDK.Until the modding SDK comes out, I would suggest that you do not write mods in TypeScript, it may be tempting but it will be a lot more trouble than it's worth, given that we don't yet have the type information for any new native functions.
Attached is a script that you can run to dump up to more or less an entire JavaScript context, and the output I got from running it through Firetuner in the Tuner and App UI contexts. You can use this information to help you write mods in JavaScript, until we have a better solution for documentation. UPDATE: an improved version of the script is now attached as well, but I haven't got the time yet to run it on the game, be aware, it may take a while if called on global
this
.To get information on an arbitrary object, you can invoke the
dump
function with reference to the object and call JSON.stringify
on the result. e.g. JSON.stringify(dump(Players.get(GameContext.localPlayerID)), refReplacer())
to dump information on the Player class. If you are in a UI context you can also use the UI.setClipboardText
function with the dumped output as argument to copy it directly to your clipboard. Otherwise just minify the code and run it through firetuner to have the return get outputted in the console window, or separate the response into several 100 character segments and console.log it.UPDATE: Attached are lists of the many internal events which can be accessed in scripts. Reporting events are not yet well understood, but the other kinds of events can be subscribed to with
engine.on
. e.g. engine.on("NaturalWonderRevealed", onNaturalWonderRevealed)
.I will update this post with new information as it becomes available and discovered.
Attachments
Last edited: