Un pack de mods est une simple base SQLite. L’éditeur de mods est la façon confortable d’en écrire un, mais rien ne vous empêche d’ouvrir le fichier vous-même — et pour certains travaux c’est de loin le chemin le plus rapide :
- importer une saison réelle depuis un tableur ou un CSV ;
- renommer quarante sponsors, ou augmenter tous les salaires de 10 % ;
- générer un pack depuis un script, pour le régénérer dès que vos données sources changent ;
- lire le pack de quelqu’un d’autre pour voir comment il s’y est pris.
Cette page est la référence pour cela. Elle documente ce que le jeu lit réellement — colonne par colonne — et les règles qu’il suit. Rien ici n’est un détail privé : le chargeur est délibérément tolérant, et savoir à quel point il l’est, c’est ce qui permet d’écrire un pack à la main en confiance.
Vous n’avez jamais besoin de cette page pour faire un mod. L’éditeur de mods écrit toutes les tables décrites ici, vérifie votre travail et met à jour les packs anciens. Passez au SQL quand vous voulez des modifications en masse ou de la génération par script.
Ouvrir un pack
N’importe quel outil SQLite fonctionne — le fichier n’a ni en-tête maison, ni compression, ni chiffrement.
En graphique — DB Browser for SQLite est gratuit, tourne sous Windows, macOS et Linux, et édite les tables comme un tableur. C’est l’entrée la plus douce si vous n’avez jamais écrit de SQL : ouvrez le fichier, allez dans Parcourir les données, choisissez une table, tapez. Pensez à Écrire les modifications avant de fermer.
En ligne de commande — sqlite3 est livré avec macOS et la plupart des distributions Linux, et se télécharge en un petit fichier sous Windows :
sqlite3 my_pack.db
sqlite> .tables
sqlite> .schema teams
sqlite> SELECT name, country FROM teams ORDER BY sort;
sqlite> .quit
Depuis un script — Python embarque SQLite, ce qui fait d’un pack une sortie de build naturelle :
import sqlite3
db = sqlite3.connect("my_pack.db")
db.execute("UPDATE drivers SET salary = CAST(salary * 1.1 AS INTEGER)")
db.commit()
db.close()
Travaillez toujours sur une copie. Un pack est un seul fichier — le sauvegarder, c’est un glisser-déposer.
Les règles que suit le chargeur
Ces six règles sont ce qui rend l’édition à la main sûre. Elles méritent d’être lues avant le schéma lui-même.
1 — Toute table est optionnelle. Un pack qui n’a qu’une table drivers est valide. Une table absente signifie « cette section reste procédurale », jamais une erreur.
2 — Toute colonne est optionnelle. Le chargeur demande à SQLite quelles colonnes votre table possède réellement et sert le reste en NULL. Donc CREATE TABLE teams(name TEXT) fonctionne. Cela veut aussi dire qu’un pack écrit pour une version plus ancienne continue de se charger, et qu’une faute de frappe dans un nom de colonne n’est pas une erreur — la colonne n’est simplement jamais lue, et c’est le seul mode d’échec à surveiller.
3 — Les types sont tolérants. Chaque valeur est lue comme du texte, quel que soit le stockage. 12, "12" et même 12.0 arrivent tous comme le nombre 12 là où un nombre est attendu. Stockez ce qui vous arrange.
4 — Les lignes sont triées par sort. Ajoutez une colonne entière sort et les lignes sont lues dans cet ordre ; sans elle, elles viennent dans l’ordre d’insertion. L’ordre compte pour les écuries (la grille se construit dedans) et pour les manches du calendrier.
5 — Vide signifie « garder ce que le jeu a généré ». C’est la règle la plus utile de toutes. Une couleur vide garde la livrée générée, un car_index vide garde le modèle généré, un potentiel à 0 laisse le générateur fixer le plafond. Vous surchargez ce qui vous importe et laissez le reste tranquille.
6 — Une ligne fautive est ignorée, pas fatale. Une écurie sans nom, un circuit à moins de trois points, une ligne d’historique malformée — chacune est écartée seule. Le reste du pack se charge quand même.
meta — les réglages du pack lui-même
Deux colonnes, key et value, une ligne par réglage. Les clés ne sont pas sensibles à la casse.
| Clé | Valeur | Défaut |
|---|---|---|
name | Le nom affiché dans le sélecteur | le nom du fichier |
author | Votre nom — affiché avec le pack | — |
schema_version | Version de format de ce pack (actuelle : 2) | 1 |
min_game_version | Build minimum qui le comprend, ex. 0.5.4-6 | aucun |
scenario | new_series (vous arrivez en nouvelle écurie) ou imposed (vous reprenez une grille écrite) | new_series |
start_year | Année civile de la saison 1 | celle du jeu |
teams_mode · drivers_mode · sponsors_mode · suppliers_mode · circuits_mode | extend (s’ajoute au monde généré) ou replace (les vôtres seuls) | extend |
active_series | Liste CSV des championnats à faire courir, ex. PFS,PF2 | tous les actifs |
rules | Liste CSV d’identifiants de règlements, ex. points_classic_top6,quali_107 | ceux de la série |
replace accepte aussi only ; imposed accepte aussi takeover ou existing. Une valeur inconnue retombe sur le défaut au lieu d’échouer.
Deux clés sont une poignée de main avec le jeu, et c’est la raison pour laquelle un pack n’échoue jamais en silence :
- si
schema_versiondépasse ce que le build comprend, la ligne du pack dans le sélecteur le dit — « écrit pour un format plus récent » — et les parties illisibles sont ignorées ; - si
min_game_versionest plus récent que le build, la ligne dit « nécessite le jeu X ou plus récent ».
Renseignez les deux. Elles coûtent deux lignes et transforment un pack à moitié fonctionnel et mystérieux en un message clair.
CREATE TABLE meta(key TEXT, value TEXT);
INSERT INTO meta VALUES
('name', 'Saison 1994'),
('author', 'Votre nom'),
('schema_version', '2'),
('min_game_version', '0.5.4-6'),
('scenario', 'imposed'),
('start_year', '1994'),
('teams_mode', 'replace'),
('drivers_mode', 'replace');
teams
| Colonne | Signification |
|---|---|
id | Clé stable. Ce que visent pilotes, sponsors et fournisseurs. N’importe quelle chaîne unique. |
name | Nom affiché. Une ligne sans nom est ignorée. |
country | Nom de pays (Germany) ou code ISO (de) — les deux marchent |
budget_tier | small · medium · large — le comportement de l’écurie, pas seulement sa trésorerie |
budget_musd | Budget de départ en millions. Fixe aussi le palier, sauf si budget_tier dit autre chose |
reputation | 0-100 |
color1 · color2 · color3 | Hexadécimal, ex. #1A5FB4. Les trois vides = garder la livrée générée |
car_index | Modèle de voiture 0-11. Vide = garder le modèle généré (0 est une vraie voiture, pas « non défini ») |
livery · suit | Indices de variante ; 255 = généré |
logo | Un nom de ligne images, un chemin relatif au dossier mods, ou un simple nombre pour un logo intégré |
car_image | Un nom de ligne images pour un sprite de voiture personnalisé |
infra_engineering · _rnd · _chassis · _handling · _aero · _engine · _marketing · _scouting | Niveaux de département 0-10. 0 = garder le généré |
infra_academy | Idem, plafonné à 3 |
career_wins · career_titles · best_championship · founding_year | Palmarès, pour une histoire écrite |
history | Saisons passées en saison:position:victoires, séparées par ; ou des retours à la ligne |
L’infrastructure et le palmarès ne comptent vraiment qu’en scénario imposé, où la grille doit être une affaire qui tourne dès la première course.
drivers
| Colonne | Signification |
|---|---|
id | Clé stable |
first_name · last_name | Une ligne sans ni l’un ni l’autre est ignorée |
code | Code à trois lettres. Mis en majuscules au chargement ; un doublon est renommé en silence |
country | Code ISO — ici la valeur EST la clé du drapeau |
age | 1-55. Moins de 16 est permis pour un espoir : il vieillit, reste caché au Scouting jusqu’à 14 ans, et ne peut être titularisé avant que les règles d’âge de la série ne l’autorisent |
intelligence · pace · consistency · adaptability · stamina · aggressivity | Les six aptitudes, 1-20 |
pot_intelligence … pot_aggressivity | Leurs plafonds, 0-20. 0 = laisser le générateur décider |
curve_intelligence … curve_aggressivity | Identifiants de courbe de progression ; 255 = défaut. Un identifiant inconnu retombe sur le défaut au lieu de geler la stat |
salary | Par saison |
traits | Paires genre:palier séparées par des virgules, ex. 3:1,7:2 |
face_sheet · face_index · helmet_index | Portrait ; 255 = généré |
helmet_hue_0 · _1 · _2 | Teintes du casque. Les trois vides = généré |
team · team_id | Le baquet. team_id l’emporte si les deux sont renseignés |
role | primary · secondary · reserve |
contract_years | 0-5 |
career_starts · career_wins · career_podiums · career_titles · best_finish | Palmarès |
fame | 0-100 ; 0 garde la valeur calculée |
Deux pilotes par écurie, un par baquet. Deux pilotes primary dans la même écurie laissent la voiture 2 vide — et une voiture sans pilote ne prend pas le départ.
sponsors
| Colonne | Signification |
|---|---|
id | Clé stable |
name | Ignorée si vide |
sector | Secteur d’activité — pilote le logo procédural |
color | Hexadécimal |
budget · prominence | 1-10 |
origin | Nom de pays ou code ISO |
logo | Un nom de ligne images ou un chemin |
team · team_id | Le pré-signer à une écurie. Accepte une liste séparée par ; ou , |
Le premier sponsor d’une écurie devient son Principal, les suivants des Secondaires.
suppliers
| Colonne | Signification |
|---|---|
id | Clé stable |
name | Ignorée si vide |
category | engine · tires · fuel |
color · origin · logo | Comme les sponsors |
budget · size | 1-10 |
money_per_gp | Argent par course. Positif = il vous paie, négatif = vous le payez |
contract | partnership (exclusif) ou client. L’emporte sur le signe de money_per_gp |
duration | 0-5 saisons |
team · team_id | Pré-signature ; une liste, comme les sponsors |
Les statistiques techniques ont deux écritures, et les colonnes nommées sont la raison d’être de cette page. Quatre cases génériques (stat_a … stat_d) signifiaient autre chose selon la catégorie, ce qu’aucun outil tiers ne pouvait deviner. Écrivez plutôt les colonnes nommées — elles l’emportent dès qu’elles sont renseignées et non nulles :
| Catégorie | Colonnes nommées (0-10) |
|---|---|
engine | power · reliability · endurance · potential |
tires | performance · endurance · reliability · heat |
fuel | efficiency |
circuits
Les tracés dessinés à la main que porte le pack. L’éditeur de circuits écrit ces lignes, mais la géométrie est du texte brut : un script le peut aussi.
| Colonne | Signification |
|---|---|
id | Clé stable — ce que vise une manche du calendrier |
name | Ignorée si vide |
points | La ligne médiane. Paires x,y jointes par ;. Moins de trois points et la ligne est écartée |
country · city | Vide donne un lieu aléatoire mais stable |
target_km | Longueur du tour ; en dessous de 1, retombe à 5 km |
character | Le caractère du tracé — c’est ce que la simulation lit réellement |
preset | Identifiant de préréglage visuel |
start_finish · pit_entry · pit_exit | Positions le long du tour ; négatif ou absent = déduit |
year · downforce · tire_wear · overtaking | Stockés et affichés, mais non simulés — en jeu ces trois-là découlent du character |
calendar
Une ligne par manche, dans l’ordre sort, jusqu’à 24.
| Colonne | Signification |
|---|---|
kind | circuit = utiliser un circuit du pack ; toute autre valeur = tracé généré |
circuit · circuit_id | Lequel. circuit_id est essayé en premier |
character · target_km | Pour une manche générée |
Un pack qui porte un calendrier remplace la saison. Un pack qui porte des circuits sans calendrier verse ses tracés dans le pool mondial et les laisse gagner des manches tout seuls.
images
name (la clé que visent les autres tables) et data, les octets du PNG en BLOB. Les logos se dessinent en 195×195 ; un sprite de voiture personnalisé est une vue de profil tournée vers la droite sur fond transparent, 256 px de haut.
Insérer une image depuis la ligne de commande :
sqlite3 my_pack.db "INSERT INTO images(name, data) VALUES('lotus.png', readfile('lotus.png'))"
…ou depuis Python :
db.execute("INSERT INTO images(name, data) VALUES(?, ?)",
("lotus.png", open("lotus.png", "rb").read()))
Puis faites-y pointer une ligne : UPDATE teams SET logo = 'lotus.png' WHERE name = 'Lotus'.
Deux noms qui ne diffèrent que par la ponctuation (mon logo.png et mon-logo.png) se déballent vers le même fichier ; le premier le garde et le second reçoit un suffixe numéroté, si bien que rien n’est écrasé en silence.
Un pack minimal, de bout en bout
CREATE TABLE meta(key TEXT, value TEXT);
INSERT INTO meta VALUES
('name','Deux écuries'), ('schema_version','2'),
('min_game_version','0.5.4-6'), ('teams_mode','extend');
CREATE TABLE teams(sort INTEGER, id TEXT, name TEXT, country TEXT,
budget_tier TEXT, color1 TEXT, color2 TEXT);
INSERT INTO teams VALUES
(1,'t_alba','Alba Corse','Italy','large','#B3122C','#F2E8D5'),
(2,'t_nord','Nordwind GP','Germany','medium','#14304F','#C8D3DC');
CREATE TABLE drivers(sort INTEGER, id TEXT, first_name TEXT, last_name TEXT,
code TEXT, country TEXT, age INTEGER,
pace INTEGER, consistency INTEGER,
team_id TEXT, role TEXT);
INSERT INTO drivers VALUES
(1,'d_ros','Elio','Rossi','ROS','it',27,17,15,'t_alba','primary'),
(2,'d_ber','Karl','Berger','BER','de',31,15,17,'t_alba','secondary');
Voilà un pack complet et valide. Tout ce qui n’est pas mentionné reste procédural.
Vérifier son travail
Demandez au jeu ce qu’il voit. Lancez-le une fois depuis un terminal avec --list-mods : il affiche les dossiers qu’il scanne dans l’ordre, puis chaque pack, circuit et langue trouvés. C’est la première chose à lancer quand un pack n’apparaît pas.
mod folders (read in this order):
/home/vous/.local/share/TheUndercut/mods
/chemin/du/jeu/mods (does not exist)
packs:
my_pack
Lisez la ligne du pack dans le sélecteur. Le jeu y dit ce qu’il n’a compris qu’à moitié — un format plus récent, une version de jeu qu’il lui faut, ou deux écuries partageant un nom, ce qui rend les rattachements ambigus.
Ouvrez-le une fois dans l’éditeur de mods. Son onglet Audit attrape ce que le SQL ne peut pas voir : un second baquet vide, un pilote rattaché à une écurie inexistante, un code en double. Ouvrir un pack écrit à la main y appose aussi des identifiants stables là où il n’y en a pas, et c’est la meilleure chose qu’on puisse faire à un pack écrit à la main.
Pièges à connaître
- Une colonne mal orthographiée est silencieuse.
colour1n’est pascolor1; elle n’est simplement jamais lue. Si une modification semble sans effet, vérifiez d’abord l’orthographe contre cette page —PRAGMA table_info(teams)liste ce que votre table contient vraiment. - Les rattachements suivent
idd’abord, le nom ensuite. Donnez un identifiant à chaque ligne et renommer une écurie lui garde ses pilotes. Sans identifiants, renommer une écurie verse ses pilotes chez les agents libres. 0ne veut pas dire « non défini » partout. Il signifie garder le généré pour les potentiels, l’infrastructure et la renommée — maiscar_indexà0est une vraie voiture : laissez cette colonne vide pour garder le modèle généré.- Un pack ne s’applique qu’à la création d’une carrière. L’éditer ne change rien à une carrière déjà lancée. Commencez-en une nouvelle.
- Le fichier doit rester où il est. Logos et sprites de voiture y sont lus pendant toute la vie de la carrière.
- Écrivez vos modifications. Un navigateur graphique garde les changements dans une transaction en attente — fermez-le sans Écrire les modifications et rien n’a été enregistré.
À voir aussi
- Packs de mods — ce que chaque section veut dire en jeu
- Éditeur de mods — l’outil qui écrit tout cela pour vous
- Modder un circuit — dessiner les tracés que porte un pack
- Publier sur le Steam Workshop — partager le pack fini