<?xml version="1.0"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>Virtual World R.E.  - Recent changes [en]</title>
		<link>https://wiki.re.virtualworld.fr/index.php/Special:RecentChanges</link>
		<description>Track the most recent changes to the wiki in this feed.</description>
		<language>en</language>
		<generator>MediaWiki 1.45.3</generator>
		<lastBuildDate>Thu, 02 Jul 2026 08:18:14 GMT</lastBuildDate>
		<item>
			<title>How to add a new borg</title>
			<link>https://wiki.re.virtualworld.fr/index.php?title=How_to_add_a_new_borg&amp;diff=1567&amp;oldid=1566</link>
			<guid isPermaLink="false">https://wiki.re.virtualworld.fr/index.php?title=How_to_add_a_new_borg&amp;diff=1567&amp;oldid=1566</guid>
			<description>&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 01:58, 2 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;Line 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Complete, precise description of how a &#039;&#039;&#039;new borg variant&#039;&#039;&#039; is added to &#039;&#039;Gotcha Force&#039;&#039; (GameCube, JPN &amp;lt;code&amp;gt;GG4J&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;main.dol&amp;lt;/code&amp;gt;), as implemented in the editor&#039;s &amp;lt;code&amp;gt;borg/table_externalize.rs&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;build_add_borg_iso&amp;lt;/code&amp;gt;).&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Complete, precise description of how a &#039;&#039;&#039;new borg variant&#039;&#039;&#039; is added to &#039;&#039;Gotcha Force&#039;&#039; (GameCube, JPN &amp;lt;code&amp;gt;GG4J&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;main.dol&amp;lt;/code&amp;gt;), as implemented in the &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;gotcha force &lt;/ins&gt;editor&#039;s &amp;lt;code&amp;gt;borg/table_externalize.rs&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;build_add_borg_iso&amp;lt;/code&amp;gt;).&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;All patches are applied to a &amp;#039;&amp;#039;&amp;#039;copy&amp;#039;&amp;#039;&amp;#039; of the disc image — never the original.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;All patches are applied to a &amp;#039;&amp;#039;&amp;#039;copy&amp;#039;&amp;#039;&amp;#039; of the disc image — never the original.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</description>
			<pubDate>Wed, 01 Jul 2026 23:58:18 GMT</pubDate>
			<dc:creator>Administrateur</dc:creator>
			<comments>https://wiki.re.virtualworld.fr/index.php/Talk:How_to_add_a_new_borg</comments>
		</item>
		<item>
			<title>How to add a new borg</title>
			<link>https://wiki.re.virtualworld.fr/index.php?title=How_to_add_a_new_borg&amp;diff=1566&amp;oldid=0</link>
			<guid isPermaLink="false">https://wiki.re.virtualworld.fr/index.php?title=How_to_add_a_new_borg&amp;diff=1566&amp;oldid=0</guid>
			<description>&lt;p&gt;Created page with &amp;quot;Complete, precise description of how a &amp;#039;&amp;#039;&amp;#039;new borg variant&amp;#039;&amp;#039;&amp;#039; is added to &amp;#039;&amp;#039;Gotcha Force&amp;#039;&amp;#039; (GameCube, JPN &amp;lt;code&amp;gt;GG4J&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;main.dol&amp;lt;/code&amp;gt;), as implemented in the editor&amp;#039;s &amp;lt;code&amp;gt;borg/table_externalize.rs&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;build_add_borg_iso&amp;lt;/code&amp;gt;).  All patches are applied to a &amp;#039;&amp;#039;&amp;#039;copy&amp;#039;&amp;#039;&amp;#039; of the disc image — never the original.  == 0. The core problem ==  A borg is identified by &amp;lt;code&amp;gt;borgTypeId = (class &amp;lt;&amp;lt; 8) | variant&amp;lt;/code&amp;gt;, which is also its asset file name &amp;lt;c...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Complete, precise description of how a &amp;#039;&amp;#039;&amp;#039;new borg variant&amp;#039;&amp;#039;&amp;#039; is added to &amp;#039;&amp;#039;Gotcha Force&amp;#039;&amp;#039; (GameCube, JPN &amp;lt;code&amp;gt;GG4J&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;main.dol&amp;lt;/code&amp;gt;), as implemented in the editor&amp;#039;s &amp;lt;code&amp;gt;borg/table_externalize.rs&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;build_add_borg_iso&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
All patches are applied to a &amp;#039;&amp;#039;&amp;#039;copy&amp;#039;&amp;#039;&amp;#039; of the disc image — never the original.&lt;br /&gt;
&lt;br /&gt;
== 0. The core problem ==&lt;br /&gt;
&lt;br /&gt;
A borg is identified by &amp;lt;code&amp;gt;borgTypeId = (class &amp;lt;&amp;lt; 8) | variant&amp;lt;/code&amp;gt;, which is also its asset file name &amp;lt;code&amp;gt;pl[CC][VV].pzz&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Internally, &amp;#039;&amp;#039;everything&amp;#039;&amp;#039; that describes a borg is split across &amp;#039;&amp;#039;&amp;#039;per-class tables hardcoded in the DOL&amp;#039;&amp;#039;&amp;#039;. Each table is an array of &amp;#039;&amp;#039;&amp;#039;16 base pointers&amp;#039;&amp;#039;&amp;#039; (one per class); each base pointer addresses a contiguous sub-table of &amp;lt;code&amp;gt;variantCount[class]&amp;lt;/code&amp;gt; fixed-stride records. The per-class variant count is read from a single shared array:&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;g_BorgVariantCounts&amp;lt;/code&amp;gt; @ &amp;lt;code&amp;gt;0x802c2a20&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; — &amp;lt;code&amp;gt;byte[16]&amp;lt;/code&amp;gt;, one variant count per class (sum = 227), &amp;#039;&amp;#039;&amp;#039;shared by every borg table&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
So to add one variant to a class you must grow &amp;#039;&amp;#039;&amp;#039;all&amp;#039;&amp;#039;&amp;#039; of these tables &amp;#039;&amp;#039;&amp;#039;in lockstep&amp;#039;&amp;#039;&amp;#039; and bump the count, otherwise the new variant indexes past the end of every sub-table → crash.&lt;br /&gt;
&lt;br /&gt;
== 1. The 12 parallel tables (BORG_TABLES registry) ==&lt;br /&gt;
&lt;br /&gt;
All are indexed by &amp;lt;code&amp;gt;(class, variant)&amp;lt;/code&amp;gt; and all grow together:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! # !! Table !! base-array VA !! stride !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;g_BorgStatTables&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802dc974&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x0c&amp;lt;/code&amp;gt; || GF-energy cost (6 shorts, one per level)&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;g_BorgValue2Table&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802f23e8&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; || type / element index&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;g_BorgLevelStatTable&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802f2ecc&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x0c&amp;lt;/code&amp;gt; || detail-panel level stat&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;g_BorgVariantFlags&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802dca80&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; || per-variant flags&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;g_BorgGroupTable&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802f21d8&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; || encyclopedia group id&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;g_BorgLevelThresholdTables&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802f2fd8&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; || XP-curve index&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;g_BorgParamTables&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802f1f48&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x168&amp;lt;/code&amp;gt; || HP + weapon ammo/recharge (the large one, ~81 KB)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;g_BorgSetupTables&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802d27dc&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt; || pointer to the &amp;lt;code&amp;gt;GF_BorgSetup_CnVm&amp;lt;/code&amp;gt; function&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;g_ForceAssetTable&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; || &amp;lt;code&amp;gt;0x802cfb3c&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt; || &amp;#039;&amp;#039;&amp;#039;the &amp;lt;code&amp;gt;.pzz&amp;lt;/code&amp;gt; model AFS fid&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;g_BorgName&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x80350698&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt; || pointer to the name string (Shift-JIS)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;g_BorgPartEffectTables&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802d1b1c&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt; || attachment-part bone re-pin records&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;g_BorgInitAttachSelectorTables&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802c98fc&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; || init-time attach-object selector&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Every accessor materializes its base array with the same shape (&amp;lt;code&amp;gt;lis reg, hi&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;addi/subi base, reg, lo&amp;lt;/code&amp;gt;), which is why all 12 can be handled uniformly.&lt;br /&gt;
&lt;br /&gt;
== 2. The key idea: clone an existing variant ==&lt;br /&gt;
&lt;br /&gt;
The new variant is a &amp;#039;&amp;#039;&amp;#039;byte-exact clone of an existing variant&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;clone_from&amp;lt;/code&amp;gt;). No new data is invented. Because that variant&amp;#039;s records &amp;#039;&amp;#039;&amp;#039;already live in the DOL&amp;#039;&amp;#039;&amp;#039;, there is nothing to load — the process simply copies what is already there. The clone therefore inherits valid stats/HP/setup/parts/moveset/name and is a working borg immediately.&lt;br /&gt;
&lt;br /&gt;
== 3. The boot-hook grow (the mechanism) ==&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Why NOT the deferred AFS externalization gate ===&lt;br /&gt;
&lt;br /&gt;
There is an alternative path that copies the tables into a runtime buffer loaded from the AFS. It has a &amp;#039;&amp;#039;&amp;#039;fatal flaw for a grown variant&amp;#039;&amp;#039;&amp;#039;: the new variant reads the table slot, and if the async AFS load has not published yet (mid-scene / async timing) the slot still points at the original DOL base array → the new variant indexes out of bounds → crash. It is &amp;#039;&amp;#039;&amp;#039;rejected&amp;#039;&amp;#039;&amp;#039; for add-a-borg.&lt;br /&gt;
&lt;br /&gt;
=== 3.2 The boot hook (synchronous, before any read) ===&lt;br /&gt;
&lt;br /&gt;
The grow runs at a verified, post-AFS-mount, single-shot boot point, strictly &amp;#039;&amp;#039;before&amp;#039;&amp;#039; any borg table is read:&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;GROW_HOOK_VA&amp;lt;/code&amp;gt; = &amp;lt;code&amp;gt;0x800881a0&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; — originally &amp;lt;code&amp;gt;bl 0x800881d8&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;GF_AFS_LoadPostInitAudioStreams&amp;lt;/code&amp;gt;). It is replaced with a &amp;lt;code&amp;gt;bl&amp;lt;/code&amp;gt; to the grow routine.&lt;br /&gt;
* The routine &amp;#039;&amp;#039;&amp;#039;re-issues&amp;#039;&amp;#039;&amp;#039; the displaced &amp;lt;code&amp;gt;bl 0x800881d8&amp;lt;/code&amp;gt; itself first, so nothing is skipped.&lt;br /&gt;
&lt;br /&gt;
Three memory regions are used (all are zero-padding &amp;quot;caves&amp;quot;, checked empty before writing, so a wrong DOL can never be silently clobbered):&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Cave A — config @ &amp;lt;code&amp;gt;0x800034dc&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;: 12 descriptors of &amp;lt;code&amp;gt;GROW_ENTRY_SIZE = 0x0c&amp;lt;/code&amp;gt; bytes each: &amp;lt;code&amp;gt;{ base_va (u32), copy_bytes (u16), stride (u16), clone_off (u16), override_fid (u16) }&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;copy_bytes = count[class] * stride&amp;lt;/code&amp;gt; (the original sub-table length) and &amp;lt;code&amp;gt;clone_off = clone_from * stride&amp;lt;/code&amp;gt; (the source record offset).&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Cave B — routine @ &amp;lt;code&amp;gt;0x800035b0&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;: the grow routine (built by &amp;lt;code&amp;gt;assemble_grow_routine&amp;lt;/code&amp;gt;).&lt;br /&gt;
* The hook @ &amp;lt;code&amp;gt;0x800881a0&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== 3.3 The routine algorithm (per table) ===&lt;br /&gt;
&lt;br /&gt;
# Re-issue the displaced &amp;lt;code&amp;gt;bl 0x800881d8&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Allocate &amp;lt;code&amp;gt;copy_bytes + stride&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; from the &amp;#039;&amp;#039;&amp;#039;persistent GF global heap&amp;#039;&amp;#039;&amp;#039; via &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;GF_QueueGlobalAssetLoad&amp;lt;/code&amp;gt; @ &amp;lt;code&amp;gt;0x8002a878&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; — &amp;#039;&amp;#039;not&amp;#039;&amp;#039; the HSD pool.&lt;br /&gt;
#* &amp;#039;&amp;#039;RE-confirmed reason:&amp;#039;&amp;#039; the HSD pool allocator stores its free-list links &amp;#039;&amp;#039;&amp;#039;inside freed payload&amp;#039;&amp;#039;&amp;#039;, so on a scene transition the buffer&amp;#039;s first bytes get clobbered to 0 → a null low-class base → &amp;lt;code&amp;gt;GF_GetBorgStat&amp;lt;/code&amp;gt; reads a null pointer → crash. The GF global heap is created once at boot and never reset, so it survives every scene. This early in boot it is nearly empty (~15 MB free) → no OOM.&lt;br /&gt;
#* If the alloc returns 0 (OOM), the table is &amp;#039;&amp;#039;&amp;#039;skipped&amp;#039;&amp;#039;&amp;#039; (its base pointer stays original — never a write-through-null).&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Byte-copy&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;copy_bytes&amp;lt;/code&amp;gt; bytes from &amp;lt;code&amp;gt;base[class0]&amp;lt;/code&amp;gt; (the original sub-table) into the new buffer.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Byte-copy&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;stride&amp;lt;/code&amp;gt; bytes from &amp;lt;code&amp;gt;base[class0] + clone_off&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;clone_from&amp;lt;/code&amp;gt; record) to &amp;lt;code&amp;gt;new + copy_bytes&amp;lt;/code&amp;gt; — this &amp;#039;&amp;#039;&amp;#039;appends the new variant&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;override_fid&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (only &amp;lt;code&amp;gt;g_ForceAssetTable&amp;lt;/code&amp;gt;): if non-zero, write it (u32) &amp;#039;&amp;#039;&amp;#039;over&amp;#039;&amp;#039;&amp;#039; the appended entry, so the new variant&amp;#039;s &amp;lt;code&amp;gt;.pzz&amp;lt;/code&amp;gt; slot points at its &amp;#039;&amp;#039;&amp;#039;own&amp;#039;&amp;#039;&amp;#039; copy instead of the cloned source fid.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Publish&amp;#039;&amp;#039;&amp;#039;: &amp;lt;code&amp;gt;base[class0] = new&amp;lt;/code&amp;gt; (swap in the grown sub-table).&lt;br /&gt;
# Next table; then &amp;lt;code&amp;gt;blr&amp;lt;/code&amp;gt; back to the hook.&lt;br /&gt;
&lt;br /&gt;
Synchronous, no async, no scene-state wait → &amp;#039;&amp;#039;&amp;#039;the grown table is live before anything reads it&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Note on class:&amp;#039;&amp;#039;&amp;#039; the routine grows the &amp;#039;&amp;#039;&amp;#039;class-0&amp;#039;&amp;#039;&amp;#039; slot (&amp;lt;code&amp;gt;base[0]&amp;lt;/code&amp;gt;) of each table. The built-and-tested case is therefore &amp;#039;&amp;#039;&amp;#039;class 0 → &amp;lt;code&amp;gt;pl000d&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;, cloned from &amp;lt;code&amp;gt;pl0000&amp;lt;/code&amp;gt; (Normal Ninja). The &amp;quot;make it real&amp;quot; steps below are parameterised by &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt;; extending the grow itself to an arbitrary class means pointing each descriptor&amp;#039;s &amp;lt;code&amp;gt;base_va&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;base_array + class*4&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 4. The independent, editable .pzz ==&lt;br /&gt;
&lt;br /&gt;
The disc is &amp;#039;&amp;#039;&amp;#039;100 % full&amp;#039;&amp;#039;&amp;#039; (exactly &amp;lt;code&amp;gt;0x57058000&amp;lt;/code&amp;gt; = 1.4 GB GameCube capacity; &amp;lt;code&amp;gt;afs_data.afs&amp;lt;/code&amp;gt; is the last file, with 0 internal gaps). A borg &amp;lt;code&amp;gt;.pzz&amp;lt;/code&amp;gt; is ~1 MB. The space is reclaimed by exploiting the asset map: &amp;#039;&amp;#039;&amp;#039;the game loads borgs only via the &amp;lt;code&amp;gt;.pzz&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; listed in &amp;lt;code&amp;gt;g_ForceAssetTable&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;GF_InitForce&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;FUN_800415c4&amp;lt;/code&amp;gt;), so the separate &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;pl*_mdl.arc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;pl*mot.bin&amp;lt;/code&amp;gt; blocks (~60 MB) are unreferenced build artifacts&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
So (&amp;lt;code&amp;gt;build_add_borg_iso&amp;lt;/code&amp;gt;, step 1a):&lt;br /&gt;
&lt;br /&gt;
# Extract the source &amp;lt;code&amp;gt;.pzz&amp;lt;/code&amp;gt; (fid from the &amp;lt;code&amp;gt;g_ForceAssetTable&amp;lt;/code&amp;gt; catalog).&lt;br /&gt;
# &amp;lt;code&amp;gt;pick_unused_borg_asset_drops&amp;lt;/code&amp;gt;: pick enough &amp;lt;code&amp;gt;pl*_mdl.arc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;pl*mot.bin&amp;lt;/code&amp;gt; entries (&amp;#039;&amp;#039;&amp;#039;highest fid first&amp;#039;&amp;#039;&amp;#039;, so the fewest trailing entries relocate) to free the clone&amp;#039;s sector-aligned size.&lt;br /&gt;
# &amp;lt;code&amp;gt;afs_repack_drop_append&amp;lt;/code&amp;gt;: &amp;#039;&amp;#039;&amp;#039;repack the AFS contiguously in place&amp;#039;&amp;#039;&amp;#039; — dropped entries → TOC &amp;lt;code&amp;gt;0/0&amp;lt;/code&amp;gt;, survivors pack down (cumulative AFS resolution requires contiguity), the clone &amp;lt;code&amp;gt;.pzz&amp;lt;/code&amp;gt; appended at the new tail, the Filename-Directory pointer @ &amp;lt;code&amp;gt;0x7FFF8&amp;lt;/code&amp;gt; nulled — all within the existing extent, &amp;#039;&amp;#039;&amp;#039;no disc grow&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
# The copy&amp;#039;s fid becomes the descriptor&amp;#039;s &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;override_fid&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; for &amp;lt;code&amp;gt;g_ForceAssetTable&amp;lt;/code&amp;gt; → the new variant gets its &amp;#039;&amp;#039;&amp;#039;own, independently-editable topology&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Every other table keeps the plain clone (&amp;lt;code&amp;gt;override_fid = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== 5. Making the variant real and selectable (3 DOL patches) ==&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;g_BorgVariantCounts[class]++&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (@ &amp;lt;code&amp;gt;0x802c2a20 + class&amp;lt;/code&amp;gt;) → the game iterates the new variant.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;VS validity-mask bit&amp;#039;&amp;#039;&amp;#039;: &amp;lt;code&amp;gt;VS_MASK_VA 0x802f1f88 + class*8&amp;lt;/code&amp;gt; is a per-class 64-bit mask (low word = variants 0..31); set &amp;lt;code&amp;gt;1 &amp;lt;&amp;lt; new_variant&amp;lt;/code&amp;gt; → the variant can spawn in VS.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Default-roster splice&amp;#039;&amp;#039;&amp;#039;: the &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;-terminated id list (pointer @ &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;0x8035a388&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;, read by &amp;lt;code&amp;gt;GF_BuildDefaultRoster&amp;lt;/code&amp;gt;) — read the live list, insert &amp;lt;code&amp;gt;new_id&amp;lt;/code&amp;gt; before the &amp;lt;code&amp;gt;0xffff&amp;lt;/code&amp;gt; terminator, write the extended list into a free cave word at &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;0x802b00ec&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;.text1&amp;lt;/code&amp;gt; tail), and repoint the list pointer at it → a &amp;#039;&amp;#039;&amp;#039;new game&amp;#039;&amp;#039;&amp;#039; grants the new borg.&lt;br /&gt;
&lt;br /&gt;
== 6. The Gecko equivalent (add_borg_gecko, RAM-only) ==&lt;br /&gt;
&lt;br /&gt;
A Gecko code cannot touch the AFS on disc, so there is &amp;#039;&amp;#039;&amp;#039;no own &amp;lt;code&amp;gt;.pzz&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;: the new variant &amp;#039;&amp;#039;&amp;#039;shares&amp;#039;&amp;#039;&amp;#039; the clone&amp;#039;s &amp;lt;code&amp;gt;.pzz&amp;lt;/code&amp;gt; (all &amp;lt;code&amp;gt;override_fid = 0&amp;lt;/code&amp;gt;). It emits Gecko &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;04&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;06&amp;lt;/code&amp;gt; codes for:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;06&amp;lt;/code&amp;gt; — the 12-table grow config @ &amp;lt;code&amp;gt;0x800034dc&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;06&amp;lt;/code&amp;gt; — the grow routine @ &amp;lt;code&amp;gt;0x800035b0&amp;lt;/code&amp;gt; (it re-issues &amp;lt;code&amp;gt;bl 0x800881d8&amp;lt;/code&amp;gt; itself);&lt;br /&gt;
* &amp;lt;code&amp;gt;04&amp;lt;/code&amp;gt; — the boot hook @ &amp;lt;code&amp;gt;0x800881a0&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;bl&amp;lt;/code&amp;gt; to the routine;&lt;br /&gt;
* &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; — the variant-count bump @ &amp;lt;code&amp;gt;0x802c2a20 + class&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;04&amp;lt;/code&amp;gt; — the VS-mask bit;&lt;br /&gt;
* &amp;lt;code&amp;gt;06&amp;lt;/code&amp;gt; — the roster list @ &amp;lt;code&amp;gt;0x802b00ec&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;04&amp;lt;/code&amp;gt; — the roster-pointer repoint @ &amp;lt;code&amp;gt;0x8035a388&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Addresses are masked &amp;lt;code&amp;gt;&amp;amp; 0x01FFFFFF&amp;lt;/code&amp;gt; to the MEM1-relative form the base codes expect.&lt;br /&gt;
&lt;br /&gt;
== 7. Verification status ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tool-level VERIFIED&amp;#039;&amp;#039;&amp;#039;: 96 unit tests pass; &amp;lt;code&amp;gt;build_add_borg_iso_on_a_copy&amp;lt;/code&amp;gt; produces &amp;lt;code&amp;gt;GF-Loader7.iso&amp;lt;/code&amp;gt; where the catalog surfaces the added &amp;lt;code&amp;gt;(0,13)&amp;lt;/code&amp;gt; borg with its &amp;#039;&amp;#039;&amp;#039;own fid&amp;#039;&amp;#039;&amp;#039; (a byte-exact copy of &amp;lt;code&amp;gt;pl0000&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;counts 13→14&amp;lt;/code&amp;gt;, VS-mask bit 13 set, roster pointer repointed, and the grow routine + hook + per-table descriptors landed byte-for-byte.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;NOT yet confirmed in-game&amp;#039;&amp;#039;&amp;#039;: the final proof is to boot &amp;lt;code&amp;gt;GF-Loader7.iso&amp;lt;/code&amp;gt; in Dolphin, start a &amp;#039;&amp;#039;&amp;#039;new game&amp;#039;&amp;#039;&amp;#039;, and confirm that &amp;lt;code&amp;gt;pl000d&amp;lt;/code&amp;gt; &amp;#039;&amp;#039;&amp;#039;and the other borgs&amp;#039;&amp;#039;&amp;#039; render (battle + garage) — which would empirically confirm that the dropped &amp;lt;code&amp;gt;pl*_mdl.arc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;pl*mot.bin&amp;lt;/code&amp;gt; are truly unused.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
Add-a-borg = &amp;#039;&amp;#039;&amp;#039;12 tables grown in lockstep by a synchronous boot-hook grow&amp;#039;&amp;#039;&amp;#039; (clone of an existing variant, allocated from the persistent GF heap) &amp;#039;&amp;#039;&amp;#039;+ an own editable &amp;lt;code&amp;gt;.pzz&amp;lt;/code&amp;gt; reclaimed by an in-place AFS repack&amp;#039;&amp;#039;&amp;#039; (dropping unused &amp;lt;code&amp;gt;pl*_mdl&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;pl*mot&amp;lt;/code&amp;gt; artifacts) &amp;#039;&amp;#039;&amp;#039;+ 3 DOL patches&amp;#039;&amp;#039;&amp;#039; (variant count, VS mask, default roster). Everything is applied to a copy of the disc.&lt;br /&gt;
&lt;br /&gt;
== Key addresses ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Symbol !! VA !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;g_BorgVariantCounts&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802c2a20&amp;lt;/code&amp;gt; || per-class variant counts (bump target)&lt;br /&gt;
|-&lt;br /&gt;
| grow config (Cave A) || &amp;lt;code&amp;gt;0x800034dc&amp;lt;/code&amp;gt; || 12 × &amp;lt;code&amp;gt;0x0c&amp;lt;/code&amp;gt;-byte grow descriptors&lt;br /&gt;
|-&lt;br /&gt;
| grow routine (Cave B) || &amp;lt;code&amp;gt;0x800035b0&amp;lt;/code&amp;gt; || the synchronous grow routine&lt;br /&gt;
|-&lt;br /&gt;
| boot hook || &amp;lt;code&amp;gt;0x800881a0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;bl 0x800881d8&amp;lt;/code&amp;gt; retargeted to the routine&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GF_QueueGlobalAssetLoad&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x8002a878&amp;lt;/code&amp;gt; || persistent-heap alloc&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;g_ForceAssetTable&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;0x802cfb3c&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;.pzz&amp;lt;/code&amp;gt; fid table (gets &amp;lt;code&amp;gt;override_fid&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| AFS FD pointer || file offset &amp;lt;code&amp;gt;0x7FFF8&amp;lt;/code&amp;gt; || nulled after repack&lt;br /&gt;
|-&lt;br /&gt;
| VS validity mask || &amp;lt;code&amp;gt;0x802f1f88 + class*8&amp;lt;/code&amp;gt; || spawn-enable bit&lt;br /&gt;
|-&lt;br /&gt;
| default-roster pointer || &amp;lt;code&amp;gt;0x8035a388&amp;lt;/code&amp;gt; || repointed to the spliced list&lt;br /&gt;
|-&lt;br /&gt;
| roster list cave || &amp;lt;code&amp;gt;0x802b00ec&amp;lt;/code&amp;gt; || the extended &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;-terminated id list&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Gotcha Force]]&lt;br /&gt;
[[Category:Reverse Engineering]]&lt;/div&gt;</description>
			<pubDate>Wed, 01 Jul 2026 23:49:37 GMT</pubDate>
			<dc:creator>Administrateur</dc:creator>
			<comments>https://wiki.re.virtualworld.fr/index.php/Talk:How_to_add_a_new_borg</comments>
		</item>
		<item>
			<title>Gotcha Force</title>
			<link>https://wiki.re.virtualworld.fr/index.php?title=Gotcha_Force&amp;diff=1565&amp;oldid=1541</link>
			<guid isPermaLink="false">https://wiki.re.virtualworld.fr/index.php?title=Gotcha_Force&amp;diff=1565&amp;oldid=1541</guid>
			<description>&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;Game assets implementation&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 01:44, 2 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l304&quot;&gt;Line 304:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 304:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[Motions]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[Motions]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[Borg - data file]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [[Borg - data file]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* [[How to add a new borg]]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;See also [https://github.com/Virtual-World-RE/NeoGF/tree/main/doc our documentation] available on github.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;See also [https://github.com/Virtual-World-RE/NeoGF/tree/main/doc our documentation] available on github.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</description>
			<pubDate>Wed, 01 Jul 2026 23:44:58 GMT</pubDate>
			<dc:creator>Administrateur</dc:creator>
			<comments>https://wiki.re.virtualworld.fr/index.php/Talk:Gotcha_Force</comments>
		</item>
</channel></rss>