Architecture interne — RitnLib¶
Document interne mainteneur. Vue d'ensemble de la structure du code, des dépendances et des choix de conception. Mis à jour à chaque refactor structurel — section « Historique » en bas.
1. Identité¶
RitnLib est un mod-bibliothèque pour Factorio 2.0 (info.json.factorio_version = "2.0"). Il ne propose aucune entité, recette ou recherche de gameplay : il publie une API consommée par d'autres mods Ritn au moment du chargement.
Conséquence directe sur la lecture du code : la grande majorité des fichiers n'a pas vocation à s'exécuter dans la VM de RitnLib lui-même, mais à être require par des mods clients (au data stage, au settings stage, ou au control stage).
2. Vue d'ensemble en 4 couches¶
┌───────────────────────────────────────────────────────────────┐
│ Couche assets data prototypes/ │
│ fonts.lua, gui-style.lua (consommée par data stage │
│ d'un mod client via require) │
├───────────────────────────────────────────────────────────────┤
│ Couche classes classes/ │
│ ┌──────────────────┬──────────────────┬───────────────────┐ │
│ │ prototypes/ │ RitnClass/ │ LuaClass/ │ │
│ │ (data stage) │ (hybride) │ (runtime) │ │
│ │ RitnProto* │ Setting, │ Player, Surface, │ │
│ │ │ Inventory, │ Force, Entity, │ │
│ │ │ Ingredient, │ Event, Recipe, │ │
│ │ │ Prototype base, │ Technology, Gui │ │
│ │ │ Informatron, │ │ │
│ │ │ gui/Element, │ │ │
│ │ │ gui/Style │ │ │
│ └──────────────────┴──────────────────┴───────────────────┘ │
├───────────────────────────────────────────────────────────────┤
│ Couche utilities lualib/ │
│ table, string, json, other, gui, entity, LuaStyle │
│ vanilla/{util, crash-site, ores, types_*} │
│ informatron/{menu, pages} │
├───────────────────────────────────────────────────────────────┤
│ Couche fondation core/ │
│ class.lua → classFactory │
│ constants.lua → tints, colors, strings, types │
│ eventListener.lua → fork event_handler (statut incertain) │
│ interfaces.lua → remote.add_interface("RitnLib", {}) │
│ setup-classes.lua → chargeur des classes runtime │
├───────────────────────────────────────────────────────────────┤
│ Bootstrap defines.lua + control.lua │
│ ritnlib (global) + ritnlib.classFactory │
└───────────────────────────────────────────────────────────────┘
3. Entrypoints¶
| Stage | Fichier | Action |
|---|---|---|
| control | control.lua | require('core.setup-classes'), require('core.interfaces'), activation conditionnelle de gvv |
| data | aucun | Les fichiers prototypes/fonts.lua et prototypes/gui-style.lua existent mais ne sont pas chargés par RitnLib lui-même — un mod client doit les require explicitement |
| settings | aucun | La classe RitnLibSetting est un builder appelé depuis le settings stage d'un mod client |
⚠ La présence d'un dossier prototypes/ sans data.lua à la racine est intentionnelle : les assets y sont des fichiers prêts à require, exposés via ritnlib.defines.fonts et ritnlib.defines.gui_styles.
4. Registre global ritnlib¶
defines.lua construit un global ritnlib qui sert de registre de chemins :
ritnlib = {
defines = {
event, constants, other, table, string, json,
vanilla = { util, crash_site },
fonts, gui_styles, setup,
class = {
core,
prototype = { tech, ore, entity, item, recipe, group, subgroup,
category, fuelCategory, style, sprite, customInput,
utility = { constants } },
luaClass = { event, player, entity, force, surface, recipe, tech, gui },
ritnClass = { prototype, ingredient, inventory, setting, informatron },
gui = { element, style },
},
names = { font = {...} },
},
classFactory = <core/class.lua>,
}
Avantage : un consommateur ne hard-code aucun chemin de fichier ; il fait require(ritnlib.defines.class.luaClass.player). Si la lib réorganise ses fichiers, seul defines.lua change.
Dette identifiée :
- Plusieurs clés racine commentées DEPRECATED (defines.lua:17-25) — migration de paths inachevée.
- ritnlib.defines.event pointe vers __core__/lualib/event_handler et non vers core/eventListener.lua — incohérence à statuer (cf. ADR-R3-A à venir).
- Faute de frappe defaut* au lieu de default* pour les noms de fontes.
5. Système de classes¶
5.1 Factory ritnlib.classFactory¶
core/class.lua — factory de classes orientée objet en Lua 5.1 :
newclass(super, init): héritage par copie superficielle des champs du parent +__callconstructeur +:is_a().new(super, init): variante non utilisée ailleurs dans le dépôt → code mort à supprimer (cf. BUG-DEAD-001).
⚠ Pas de copie profonde des champs du parent : si le parent expose une table partagée, toutes les instances la partagent par référence. Concerné : RitnLibGui.list_valid, RitnLibGuiElement.hsp_valid.
5.2 Deux familles de classes¶
| Famille | Dossier | Mode de retour | Stage |
|---|---|---|---|
RitnLib* (runtime) |
classes/LuaClass/, classes/RitnClass/gui/, RitnLibInformatron, RitnLibInventory |
globales _G (assignation sans local) |
control |
RitnProto* / Ritn* (data + helpers) |
classes/prototypes/, RitnPrototype, RitnIngredient, RitnLibSetting |
local … return (require classique) |
data / settings |
⚠ Pollution _G : toutes les classes runtime s'inscrivent dans le namespace global. C'est un choix assumé qui rend l'usage côté consommateur très court (RitnLibPlayer(p)), mais bloque l'évolution vers des modules typés. À statuer (cf. ADR-R3-C).
5.3 Hiérarchies actuelles¶
RitnLibPlayer ◄── RitnLibGui ◄── RitnLibInformatron
RitnPrototype ◄── RitnProtoEntity, RitnProtoItem, RitnProtoRecipe,
RitnProtoTechnology, RitnProtoOre, RitnProtoSprite,
RitnProtoStyle, RitnProtoItemGroup,
RitnProtoItemSubgroup, RitnProtoFuelCategory,
RitnProtoCustomInput, RitnProtoUtilityConst
⚠ RitnProtoRecipeCategory NE devrait PAS être à part — bug d'héritage
(cf. BUG-005 dans debt/known-bugs.md)
6. Flux d'exécution¶
Bootstrap effectif (au chargement de Factorio)¶
Factorio → RitnLib/control.lua
├─► require('core.setup-classes')
│ └─► require('__RitnLib__.defines') [crée le global ritnlib]
│ └─► require(ritnlib.defines.class.core) [classFactory]
│ └─► require(...) × N classes runtime [s'auto-inscrivent en _G]
├─► require('core.interfaces')
│ └─► remote.add_interface("RitnLib", {}) [interface vide actuellement]
└─► require("__gvv__.gvv")() [conditionnel : si gvv actif]
Aucun handler script.on_event n'est enregistré, aucun accès à storage/global. RitnLib est passif côté runtime.
Bootstrap consommateur typique (data stage)¶
mod_client/data.lua
require("__RitnLib__/defines")
require(ritnlib.defines.fonts) -- data:extend({fonts ritn-*})
require(ritnlib.defines.gui_styles) -- mutations sur data.raw['gui-style'].default
local Recipe = require(ritnlib.defines.class.prototype.recipe)
Recipe("automation-science-pack"):setCount(10):addIngredient({"iron-plate", 3})
Bootstrap consommateur typique (control stage)¶
mod_client/control.lua
-- ritnlib est déjà chargé par RitnLib/control.lua
-- les classes RitnLib* sont déjà disponibles en _G
script.on_event(defines.events.on_player_died, function(event)
RitnLibInventory(game.get_player(event.player_index),
storage.inventory_snapshots):save(true)
end)
remote.add_interface("mod_client", {
gui_action_main = function(action, event, ...) ... end,
})
7. Persistance¶
| Aspect | Statut |
|---|---|
storage.X propre à RitnLib |
aucun |
global.X (alias 1.x) |
aucun |
script.register_metatable |
aucun |
| Méta-objets persistés | aucun |
RitnLib n'a aucune donnée persistante propre. Le seul cas d'état durable est RitnLibInventory, qui délègue la table de persistance au consommateur via le 2ᵉ paramètre du constructeur. Voir Persistance déléguée.
8. Évènements¶
- Aucun
script.on_eventdans le code de RitnLib (vérifié par grep). core/eventListener.luaest un fork deevent_handler(ZwerOxotnik) qui enregistreon_init/on_load/on_configuration_changed/on_event/on_nth_tickau moment du require. Mais ce fichier n'est jamais require parcontrol.luaetritnlib.defines.eventpointe ailleurs → statut indéterminé. Cf. ADR-R3-A.RitnLibEventest un wrapper d'event (normalise le payload) ; il est instancié par le consommateur dans ses propres handlers.
9. Interfaces remote¶
Exposées¶
| Nom | Méthodes | État |
|---|---|---|
"RitnLib" |
∅ | ◆ enregistrée mais vide |
"RitnLib" (variante Informatron, brouillon) |
informatron_menu, informatron_page_content |
⚠ commentée, non enregistrée (core/interfaces.lua:30) |
Consommées¶
| Mod cible | Fonctions | Localisation |
|---|---|---|
freeplay |
set_created_items, set_respawn_items, set_skip_intro, set_disable_crashsite |
lualib/other-functions.lua:421-452 |
silo_script |
set_no_victory |
lualib/other-functions.lua:445 |
DiscoScience |
setIngredientColor |
classes/LuaClass/RitnEvent.lua:238 |
<mod_name> (dynamique) |
gui_action_<gui_name> |
classes/LuaClass/RitnGui.lua:122 |
⚠ Aucune dépendance optionnelle n'est déclarée dans info.json. À ajouter au moins pour gvv, zk-lib, et les mods scénarios consommés.
10. APIs Factorio touchées (vue synthétique)¶
| Surface | Where | Usage type |
|---|---|---|
LuaPlayer.* |
RitnPlayer, RitnInventory, RitnGui, RitnInformatron | wrappers + GUI |
LuaSurface.find_entities_filtered, find_entity |
RitnSurface | recherche entité |
LuaForce.recipes/technologies/players |
RitnForce | navigation |
LuaForce.items_launched, rockets_launched |
RitnForce (:42-43) | ⚠ retiré en 2.0 |
LuaEntity.* |
RitnEntity, RitnTechnology, RitnSurface | manipulation entité |
data.raw[*] |
RitnPrototype + RitnProto* | mutation prototype |
data:extend({...}) |
Sprite, CustomInput, ItemGroup, ItemSubgroup, RecipeCategory, FuelCategory, Setting, fonts, gui-style | déclaration |
defines.{events,controllers,inventory,gui_type,disconnect_reason} |
RitnEvent, RitnPlayer, RitnInventory | résolutions |
game.create_inventory |
RitnInventory | snapshot |
remote.add_interface/call |
core/interfaces, other-functions, RitnGui, RitnEvent | IPC |
script.* (indirect) |
core/eventListener | handler agrégé |
mod-gui |
RitnGui | (require seul, usages commentés) |
resource-autoplace |
lualib/vanilla/ores | autoplace minerais |
__base__.prototypes.entity.sounds |
lualib/vanilla/ores | accès direct mod base |
11. Couches d'erreur résiduelles (synthèse)¶
Voir debt/known-bugs.md pour la liste exhaustive. Vue de surface :
- 🔴 14 bugs P0 identifiés (typos, références à champs non initialisés, héritages cassés).
- 🟠 10 zones API 1.x mortes en 2.0 (
recipe.normal/expensive,force.items_launched,hr_version,icon_mipmaps,event.created_entity,data.raw.lab.inputsformat mixte). - ⚠ 2 systèmes au statut indéterminé : fork
eventListener, intégration Informatron.
12. Sortie attendue post-refactor¶
| Version | Vague | Contenu |
|---|---|---|
0.10.0-fix |
R1 | Tous les P0 corrigés |
0.11.0 |
R2 | Compat 2.0 (purge 1.x) |
0.12.0 |
R3 | Décisions architecturales (ADR R3-A à R3-G) |
0.x.y+ |
R4 | Qualité continue |
Détails dans le plan de refactor.
Historique¶
| Date | Version pin | Changement |
|---|---|---|
| 2026-06-11 | 0.9.8 | Document initial (Phase 1 audit) |