Angelscript/docs/manual/doc_adv_dynamic_build.html

147 lines
13 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.18"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>AngelScript: Dynamic compilations</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(document).ready(function() { init_search(); });
/* @license-end */
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectlogo"><img alt="Logo" src="aslogo_small.png"/></td>
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">AngelScript
</div>
</td>
<td> <div id="MSearchBox" class="MSearchBoxInactive">
<span class="left">
<img id="MSearchSelect" src="search/mag_sel.png"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
alt=""/>
<input type="text" id="MSearchField" value="Search" accesskey="S"
onfocus="searchBox.OnSearchFieldFocus(true)"
onblur="searchBox.OnSearchFieldFocus(false)"
onkeyup="searchBox.OnSearchFieldChange(event)"/>
</span><span class="right">
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
</span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.18 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search');
/* @license-end */
</script>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(document).ready(function(){initNavTree('doc_adv_dynamic_build.html',''); initResizable(); });
/* @license-end */
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<div class="PageDoc"><div class="header">
<div class="headertitle">
<div class="title">Dynamic compilations </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>There are various forms of dynamic compilations of scripts. In the following subtopics I try to explain the theory of them and give some information on how they can be implemented.</p>
<h1><a class="anchor" id="doc_adv_dynamic_build_ondemand"></a>
On demand builds</h1>
<p>The most common form of dynamic compilations is building new modules on demand, i.e. as they are needed. When using this the application or game engine is typically designed to have separate scripts to perform different tasks, e.g. menu handling, different types of AI controllers, player controller, etc. If these separate scripts have an abstraction layer through the application to interact with each other it is very easy to build the scripts on demand.</p>
<p>To build a new script on demand, simply get a new module, add the needed script sections to it and build it just as you would when <a class="el" href="doc_compile_script.html">building the first script</a>. As each module is independent the previously existing module will be unaffected.</p>
<p>Each module can be configured to see a <a class="el" href="doc_adv_access_mask.html">different application interface</a>, so there is no need to create different engine instances.</p>
<p>Though modules are independent, they can still interact with each other if the application provides the interface for that. To make the communication between modules easier one can chose to use <a class="el" href="doc_script_shared.html">shared script entities</a>. Shared script entities will be compiled only once by the first module that includes the code. Any subsequent module that also include the code for the shared entity will reuse what was built by the first module, i.e. will share the internal type and bytecode.</p>
<p>Another option is to <a class="el" href="doc_global_import.html">import global functions</a> from a previously compiled module. In this case the application must make sure the function that exports the functions is compiled first, then after building the module that imports the function the application must call the <a class="el" href="classas_i_script_module.html#a3f0c215576adefd922c2cc95d16b55d8">asIScriptModule::BindAllImportedFunctions</a> so conclude the imports.</p>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="doc_samples_game.html">Game sample</a></dd></dl>
<h1><a class="anchor" id="doc_adv_dynamic_build_incr"></a>
Incremental builds</h1>
<p>Besides the ordinary <a class="el" href="doc_compile_script.html">compilation of scripts</a> and subsequent <a class="el" href="doc_call_script_func.html">executions</a>, AngelScript also support dynamically compiling additional <a class="el" href="classas_i_script_module.html#a1258d7cfeed965f36ba312beeb49e81c">functions</a> and <a class="el" href="classas_i_script_module.html#a34850e152dcdcb58c53a2b6929cebf77">global variables</a> to incrementally add to the scope of a module. These functions and variables will become part of the scope, just as if they had been included in the initial script compilation which means that subsequent executions or incremental compilations can use them.</p>
<p>It is also possible to dynamically remove <a class="el" href="classas_i_script_module.html#a54b6f8e09787ad20880f73bc97a8ef10">functions</a> and <a class="el" href="classas_i_script_module.html#aac10878c3d16f18ace4db881f7a1bb11">variables</a>. Doing so doesn't immediately discard the functions or variables, so other functions that still refer to them will not fail when executing them. They will however no longer be visible for new compilations or when searching for functions or variables in the module.</p>
<p>This kind of dynamic compilations is most useful when dealing with user interaction, e.g. an ingame console, or perhaps event handlers, e.g. a trigger on a GUI button click.</p>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="doc_addon_helpers.html">ExecuteString() add-on</a>, <a class="el" href="doc_samples_console.html">Console sample</a></dd></dl>
<h1><a class="anchor" id="doc_adv_dynamic_build_hot"></a>
Hot reloading scripts</h1>
<p>Hot reloading is most often used when quick change &amp; test cycles are wanted. It is quite common for game engines to have a debug mode that continuously monitors the script files to detect any updates that are made, and when detected automatically reloads the scripts without restarting the game. This allows the developers, for example, to quickly change the behaviour of the AI and immediately see the result without having to play through the entire level over and over again.</p>
<p>Hot reloading without preserving the state of existing objects is quite trivial. Simply discard everything, reload the scripts, and create new objects. On the other hand, hot reloading scripts while preserving the state of existing objects can be quite tricky, but is also the most rewarding when implemented successfully.</p>
<p>The first part to reloading while preserving the state is keeping track of the object instances so the application knows which objects needs to be serialized when a module is hot reloaded. It is entirely up to the application to build and maintain this mapping.</p>
<p>The second part is knowing which script files that will trigger a reload when changed. When building the module the application needs to store the list of the files that were added to it. If you use the standard <a class="el" href="doc_addon_build.html">script builder add-on</a>, then it provides methods to enumerate the included sections or files.</p>
<p>The third part is the hardest, and that is to implement the actual serialization. Serializing object members of value types is normally quite trivial, simply <a class="el" href="doc_adv_reflection.html#doc_adv_reflection_vars">enumerate the object properties</a> and store a name-value pair for each. Serializing object members of reference types needs some consideration, as depending on the object that is referred to, either you will be able to store the actual pointer, or you will need to store some kind of descriptor as the referred to object will also be recreated during the reload.</p>
<p>Once all the objects that will need to be recreated after the reload have been serialized for backup, the module can be rebuilt using the normal procedure for <a class="el" href="doc_compile_script.html">compiling a script</a>. Afterwards the serialized objects needs to be recreated. Once created you'll enumerate the members and set their values or references according to the backed up data.</p>
<h2><a class="anchor" id="doc_adv_dynamic_build_hot_1"></a>
Things to consider</h2>
<ul>
<li>Design the engine and script interface with hot reloading in mind from the start. Hot reloading is much easier to implement the less complex interface you have, e.g. script objects that can only interact with other script objects indirectly through the application will not be able to hold references to objects unknown by the application.</li>
<li><a class="el" href="doc_script_shared.html">Shared script entities</a> will not be recompiled if some module or existing object (including those pending destruction in the garbage collector) still refers to the code. It's recommended that you minimize the use of shared entities to where necessary so as to minimize the need to modify them.</li>
<li>The <a class="el" href="classas_i_script_context.html">asIScriptContext</a> cannot be serialized so avoid reloading scripts that may still be referred to by a context, e.g. in a suspended state. It is quite likely that the application will crash if the module is reloaded while a context has one of the functions on the callstack.</li>
<li>Before discarding the original objects, consider doing a test compilation of the modified scripts in a temporary module first, and only go ahead with the hot reloading if the test compilation is successful. That way you can catch compilation errors that would otherwise cause the recreation of the new objects to fail.</li>
<li>When recreating object instances you can take advantage of the method <a class="el" href="classas_i_script_engine.html#a9de3c5e4465f699ad698740d6037e1a6">asIScriptEngine::CreateUninitializedScriptObject</a> to create the objects without actually executing the script class constructor, which may have unwanted side effects during the reload.</li>
<li>Decide what to do when the script modifications introduces new object properties or removes existing properties, as you will not be able to restore the exact same object state then. Perhaps the new property can be filled with some default value to allow the continuation of the execution? Or perhaps the script itself can have a special event handler to provide the initial value of the new member?</li>
<li>The <a class="el" href="doc_addon_serializer.html">Serializer</a> add-on has been implemented to aid the implementation of hot reloading scripts, though it may not suit all types of applications.</li>
</ul>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="doc_addon_serializer.html">Serializer</a>, <a class="el" href="doc_adv_reflection.html">Reflection</a> </dd></dl>
</div></div><!-- contents -->
</div><!-- PageDoc -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="footer">Generated on Sat Dec 5 2020 23:20:24 for AngelScript by
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.18 </li>
</ul>
</div>
</body>
</html>