Skip to content

Commit

Permalink
feat: codegen docs (#167)
Browse files Browse the repository at this point in the history
* feat: codegen docs

* fix: typos
  • Loading branch information
zaucy authored Aug 5, 2024
1 parent 5624ab3 commit ab36afa
Show file tree
Hide file tree
Showing 13 changed files with 421 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</a>
<a
navItem
routerLink="/docs/overview"
routerLink="/docs"
routerLinkActive="active"
class="text-black flex">
<span>Documentation</span>
Expand Down
1 change: 1 addition & 0 deletions src/app/docs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ ng_project(
"//:node_modules/@angular/router",
"//src/app/docs/cpp-system-impl-wasm",
"//src/app/docs/ecs",
"//src/app/docs/extend",
"//src/app/docs/implementations",
"//src/app/docs/lang",
"//src/app/docs/overview",
Expand Down
13 changes: 12 additions & 1 deletion src/app/docs/docs-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ const routes: Routes = [
component: DocsComponent,
children: [
{
path: 'overview',
path: '',
component: OverviewComponent,
},
{
path: 'overview',
redirectTo: '',
},
{
path: 'lang',
component: LangComponent,
Expand Down Expand Up @@ -84,6 +88,13 @@ const routes: Routes = [
m => m.SystemImplRoutingModule,
),
},
{
path: 'extend',
loadChildren: () =>
import('./extend/extend-routing.module').then(
m => m.ExtendRoutingModule,
),
},
],
},
];
Expand Down
9 changes: 8 additions & 1 deletion src/app/docs/docs.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<ecsact-sidenav>
<ecsact-sidenav-section>
<a
routerLink="/docs/overview"
routerLink="/docs"
routerLinkActive="active"
[routerLinkActiveOptions]="{exact: true}"
>Overview</a
Expand Down Expand Up @@ -45,6 +45,13 @@
Implementing Systems
</a>
</ecsact-sidenav-section>

<ecsact-sidenav-section title="Extending Ecsact">
<a routerLink="/docs/extend/build-recipe" routerLinkActive="active"
>Build Recipe</a
>
<a routerLink="/docs/extend/codegen" routerLinkActive="active">Codegen</a>
</ecsact-sidenav-section>
</ecsact-sidenav>

<ecsact-content>
Expand Down
17 changes: 17 additions & 0 deletions src/app/docs/extend/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
load("//tools:ng.bzl", "ng_project")

package(default_visibility = ["//:__subpackages__"])

ng_project(
name = "extend",
srcs = glob([
"*.ts",
"*.html",
]),
deps = [
"//:node_modules/@angular/common",
"//:node_modules/@angular/core",
"//:node_modules/@angular/router",
"//src/components/prism",
],
)
3 changes: 3 additions & 0 deletions src/app/docs/extend/build-recipe.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<article>
<section>TODO: build recipe docs</section>
</article>
7 changes: 7 additions & 0 deletions src/app/docs/extend/build-recipe.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {Component} from '@angular/core';

@Component({
templateUrl: './build-recipe.component.html',
standalone: true,
})
export class ExtendBuildRecipeComponent {}
253 changes: 253 additions & 0 deletions src/app/docs/extend/codegen.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
<article>
<section>
<h1 id="codegen">Ecsact Codegen</h1>
<p>
Codegen is a core part of what makes Ecsact possible. It's used for
programming language support, creating database schemas, optimizing
runtime implementations, or collecting general information about your
Ecsact files.
</p>

<h1 id="how-to-use">How to use Ecsact Codegen</h1>
<p>
The typical way Ecsact codegen is used is via game engine integration
and/or the <a routerLink="/start/cli">Ecsact CLI</a> coupled with your
programming languages build system, but no matter where codegen is ran it
all boils down to
<a routerLink="/docs/extend/codegen" fragment="codegen-plugins"
>codegen plugins</a
>.
</p>

<h2 id="usage-integrations">Integrations</h2>
<p>
Ecsact game engine integrations likely run one or more codegen plugins to
better support Ecsact with the game engine. This can simply be language
wrappers/bindings or more detailed integral support. Typically these
codegen plugins are ran automatically when <code>.ecsact</code> change (if
recognized by the game engine.)
</p>
<p>
For example the Unity integration uses the C# Ecsact codegen plugin to
generate <code>.cs</code> files to make using Ecsact easier with Unity.
</p>
<p>
If you plan on making a custom engine integration please refer to the
<a routerLink="/start/custom">custom integration start page</a>.
</p>

<h2 id="usage-bazel">Bazel</h2>
<p>
The
<a href="https://github.com/ecsact-dev/rules_ecsact">rules_ecsact</a>
repository is the official bazel support for Ecsact. The
<code>ecsact_codegen</code> bazel rule is the best way to get started
generating code. <strong>More documentation to come.</strong>
</p>

<h2 id="usage-build-system">Other Build Systems</h2>
<p>
You're likely familiar with <em>some</em> build system for the programming
language you use. Ideally the programming language(s) you use have an
<em>official</em> build system. At this time Ecsact is probably not
supported as a first class citizen, but integrating with your build system
with the <a routerLink="/start/cli">Ecsact CLI</a> should be pretty
straight forward. Simply execute the Escact CLI
<code>codegen</code> subcommand with your ecsact files and the plugins you
want:
</p>
<pre><code prism language="bash">
ecsact codegen your_ecsact_file.ecsact --plugin=your_plugin
</code></pre>
<p>
See <a routerLink="/start/cli">Ecsact CLI start page</a> for more details.
</p>

<h1 id="well-known">Well Known Codegen Plugins</h1>
<p>
The Ecsact core development team maintains various codegen plugins. If you
create a codegen plugin and want it displayed here please open a pull
request or create an issue at our
<a href="https://github.com/ecsact-dev/website" target="_blank">
<span class="i24">open_in_new</span> website repository</a
>.
</p>

<h2 id="well-known-sdk">
Available in the <a routerLink="/start">Ecsact SDK</a>
</h2>
<p>
Plugins available in the Ecsact SDK can be listed with the
<a routerLink="/start/cli">Ecsact CLI</a> <code>config</code> subcommand:
</p>
<pre><code prism language="bash">
ecsact config builtin_plugins
</code></pre>
<ul>
@for (item of known_sdk_plugins; track item.href) {
<li>
<a [attr.href]="item.href" target="_blank"
><span class="i24">open_in_new</span> {{ item.title }}</a
>
<span> - {{ item.description }}</span>
</li>
}
</ul>

<h1 id="codegen-plugins">Codegen Plugins</h1>
<p>
Ecsact codegen plugins are dynamic libraries with 2 exported C functions.
Keep in mind during the development of Ecsact this API is likely to
change.
</p>

<h2 id="ecsact-plugin-name"><code>ecsact_plugin_name</code></h2>
<p>
The first is the plugin 'name'. A plugin name is both a name and the
extension of the output file the plugin is responsible for generating. For
example if you had an Ecsact file called
<code>example.ecsact</code> and you generated code with a plugin with the
name <code>my_plugin</code> you would get a file named
<code>example.ecsact.my_plugin</code>.
</p>
<pre><code prism language="c">const char* ecsact_plugin_name();</code></pre>
<p>
The return value is a <code>NULL-terminated</code> string with static
storage. In C it simply would be something like this.
</p>
<pre><code prism language="c">
const char* ecsact_plugin_name() {{'{'}}
return "my_plugin";
{{'}'}}
</code></pre>

<h2 id="ecsact-plugin"><code>ecsact_plugin</code></h2>
<p>
The second function is the plugin 'entry point'. The entry point is called
once for every Ecsact package. When implementing your plugin you have
access to all the
<a routerLink="/docs/runtime" fragment="meta">meta module</a> functions.
This gives you details about the various components, systems, fields and
more of the package.
</p>
<pre><code prism language="c">
void ecsact_codegen_plugin(
ecsact_package_id,
ecsact_codegen_write_fn_t,
ecsact_codegen_report_fn_t
);
</code></pre>
<p>
There are 2 functions that get passed into your entrypoint. A write
function and a report function. The write function is writes to the file
your generating and the report function is for reporting warnings and
errors to the user.
</p>

<p>
The write function takes a pointer to some bytes and the length of those
bytes and returns <code>void</code>.
</p>
<pre><code prism language="c">
void(const char*, int32_t);
</code></pre>

<p>
The report function is similar to the write function except it also takes
a report type enum as the first parameter.
</p>
<pre><code prism language="c">
void(ecsact_codegen_report_type, const char*, int32_t);
</code></pre>

<p>
The report types mean different things. There is some wiggle room on what
they mean so it may vary depending on the environment you're codegen
plugin is running in.
</p>

<table>
<tr>
<th>Report Type</th>
<th>Description</th>
</tr>
<tr>
<td><code>ECSACT_CODEGEN_REPORT_INFO</code></td>
<td>
Report some various information. May or may not be shown to the user.
Mostly used for debugging.
</td>
</tr>
<tr>
<td><code>ECSACT_CODEGEN_REPORT_WARNING</code></td>
<td>Warning that may or may not be shown to the user.</td>
</tr>
<tr>
<td><code>ECSACT_CODEGEN_REPORT_ERROR</code></td>
<td>
An error has occurred, but codegen may still continue. Must be shown
to user.
</td>
</tr>

<tr>
<td><code>ECSACT_CODEGEN_REPORT_ERROR</code></td>
<td>
An error has occurred and codegen may <strong>not</strong> continue.
Must be shown to user.
</td>
</tr>
</table>

<h2 id="codegen-cpp-wrapper" class="mt-4">Codegen C++ Wrapper</h2>
<p>
The C API can be a little daunting to use. The Ecsact core development
team uses a C++ wrapper for creating plugins. If you're using C++ to
develop your Ecsact plugin we highly recommend using it. To start using it
include the <code>ecsact/codegen/plugin.hh</code> header and construct the
<code>ecsact::codegen_plugin_context</code> object with the plugin's entry
point arguments.
</p>

<pre><code prism language="cpp">
#include "ecsact/codegen/plugin.hh" // C++ plugin wrapper
#include "ecsact/runtime/meta.hh" // C++ meta module wrapper

extern "C" auto ecsact_codegen_plugin(
ecsact_package_id pkg_id,
ecsact_codegen_write_fn_t write_fn,
ecsact_codegen_report_fn_t report_fn
) -> void {{'{'}}
auto ctx = ecsact::codegen_plugin_context{{'{'}}pkg_id, write_fn, report_fn{{'}'}};

ctx.writef("hello\n"); // write to file
ctx.info("its me!"); // report something

// Use the meta module C++ wrapper
for(auto comp_id : ecsact::meta::get_component_ids(ctx.package_id)) {{'{'}}
auto comp_name = ecsact::meta::component_name(comp_id);
ctx.writef("found component {{'{}'}}\n", comp_name);
{{'}'}}
{{'}'}}
</code></pre>

<p>
The various <code>ctx.*</code> methods wrap around
<a
href="https://en.cppreference.com/w/cpp/utility/format/format"
target="_blank"
><span class="i24">open_in_new</span> <code>std::format</code></a
>
so the same rules apply for writing/printing out various types.
</p>

<p>
There are other C++ utilities that the core team uses that can be found in
the
<a
href="https://github.com/ecsact-dev/ecsact_lang_cpp/blob/main/ecsact/cpp_codegen_plugin_util.hh"
><span class="i24">open_in_new</span> C++ language support repository</a
>.
</p>
</section>
</article>
Loading

0 comments on commit ab36afa

Please sign in to comment.