Créer un mod
Préparer les réglages effectifs du réseau
Une transformation pure avant les règles : portée de travaux, valeurs dérivées et tests sans partie.
Ce que prepareNetwork peut changer
Déclarez prepareNetwork dans signalMod quand plusieurs signaux participent à une même règle. Le callback reçoit les signaux observés du mod, avant leurs décisions. Il renvoie les réglages effectifs utilisés pour cette évaluation. Il n’enregistre aucun réglage, ne construit aucun signal et ne modifie pas les observations du jeu. Une portée de travaux, par exemple, peut activer une option sur les prochains signaux uniquement dans cette copie.
| Conserver | Transformer |
|---|---|
| Nombre et ordre des entrées, ID complet, modèle, lien nextSignal, observation et disponibilité. | Les valeurs effectives de settings, en produisant une copie des seuls signaux modifiés. |
| La différence entre inconnu, occupé et libre ; les frontières absentes du réseau du mod. | La politique métier explicite : portée, priorité entre sources, traitement d’une donnée inconnue. |
Source de travaux et portée entière
package wiki.prepared
import nimby.*
val work = Checkbox("work", "Zone de travaux", "Appliquer la règle de travaux de ce modèle.")
val workBlocks = NumberSetting("workBlocks", "Cantons suivants", maximum = 64,
defaultValue = 0, visibleWhen = work.name)
enum class Aspect { Closed, Open }
enum class Reason { Unknown, Clear, Work }
val model = signalModel(
SignalType("example.work", "Signal de travaux", "example_work", checkboxes = listOf(work)),
fallback = Indication(Aspect.Closed, Reason.Unknown)) {
number(workBlocks)
construction(listOf("closed.svg", "open.svg"))
rules {
if (!fresh || !routeKnown || block != Occupancy.Clear || observation.forcedStop || observation.lampFailed)
Indication(Aspect.Closed, Reason.Unknown)
else if (enabled(work)) Indication(Aspect.Closed, Reason.Work)
else Indication(Aspect.Open, Reason.Clear)
}
images { if (it.aspect == Aspect.Open) "open.svg" else "closed.svg" }
driving { if (it.aspect == Aspect.Open) AutomaticDriving.clear() else AutomaticDriving.stop() }
}
// Règle d’exemple : propagation par nextSignal, pas par distance physique.
// Zéro signifie la source seule. Aucun réglage dérivé n’est enregistré.
fun effectiveWorkSettings(signals: List<Signal>): List<Signal> {
val byId = signals.associateBy { it.id }
val affected = HashSet<Long>()
for (source in signals) {
if (source.type != model.type.id || source.settingsStatus != SettingsStatus.Present ||
!source.observation.fresh || source.settings[work.name] != true) continue
var current: Signal? = source
val seen = HashSet<Long>()
repeat(workBlocks.read(source.settings) + 1) {
val signal = current ?: return@repeat
if (!seen.add(signal.id) || signal.type != model.type.id ||
signal.settingsStatus != SettingsStatus.Present || !signal.observation.fresh) {
current = null
return@repeat
}
affected.add(signal.id)
current = byId[signal.nextSignal]
}
}
return signals.map { signal ->
if (signal.id in affected && signal.settings[work.name] != true)
signal.copy(settings = signal.settings + (work.name to true))
else signal
}
}
fun createPreparedMod() = signalMod("prepared-example", "Réglages préparés") {
signal(model)
prepareNetwork(::effectiveWorkSettings)
}
L’exemple choisit une règle simple : workBlocks vaut zéro pour la source seule et indique ensuite un nombre de liens nextSignal. Il prépare une table d’identifiants une fois, parcourt au plus 65 signaux par source et coupe aux cycles, modèles différents ou données indisponibles. Ce n’est pas une distance en mètres ni un calcul d’itinéraire. Le résultat original reste intact ; read et withValue de NumberSetting évitent de connaître le stockage du nombre.
Pour un paquet chargeable, ajoutez closed.svg et open.svg dans assets et utilisez ce modèle depuis votre point d’entrée signalMod(modInfo), avec metadata. Les identifiants et chemins du snippet sont des exemples : choisissez les vôtres et gardez-les stables après distribution.
Tester les données dérivées
Dans un test, appelez mod.prepareObservedNetwork(input) pour examiner les réglages préparés avec les gardes du SDK, ou mod.evaluateNetwork(input) pour vérifier les décisions finales. Vérifiez une portée nulle, une limite, un cycle, une frontière absente, une source retirée et une observation indisponible. Comparez aussi le réseau d’entrée après l’appel pour prouver qu’il n’a pas été modifié. N’appliquez pas deux fois la préparation au même résultat dérivé.