Message de bienvenue
|
After Width: | Height: | Size: 314 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 611 KiB |
|
After Width: | Height: | Size: 560 KiB |
|
After Width: | Height: | Size: 560 KiB |
@@ -115,6 +115,18 @@
|
|||||||
"tie": "Égalité : la fiction tranche."
|
"tie": "Égalité : la fiction tranche."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"welcome": {
|
||||||
|
"title": "Bienvenue dans Les Oubliés",
|
||||||
|
"eyebrow": "Système",
|
||||||
|
"intro": "Bienvenue dans le système FoundryVTT des Oubliés.",
|
||||||
|
"developerLabel": "Développement du système :",
|
||||||
|
"publisherLabel": "Jeu édité par",
|
||||||
|
"helpLabel": "Aide intégrée :",
|
||||||
|
"helpLinkLabel": "Ouvrir l’aide du système",
|
||||||
|
"helpUnavailable": "le compendium d’aide n’est pas disponible pour le moment.",
|
||||||
|
"openHelp": "Ouvrir l’aide",
|
||||||
|
"close": "Fermer"
|
||||||
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"race": "Race",
|
"race": "Race",
|
||||||
"tribu": "Tribu",
|
"tribu": "Tribu",
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import * as models from "./models/index.mjs"
|
|||||||
import * as sheets from "./applications/sheets/_module.mjs"
|
import * as sheets from "./applications/sheets/_module.mjs"
|
||||||
|
|
||||||
const DEFAULT_PERSONNAGE_TOKEN_TEXTURE = "systems/fvtt-les-oublies/assets/tokens/border_token_oublies.webp"
|
const DEFAULT_PERSONNAGE_TOKEN_TEXTURE = "systems/fvtt-les-oublies/assets/tokens/border_token_oublies.webp"
|
||||||
|
const UBERWALD_URL = "https://www.uberwald.me"
|
||||||
|
const XII_SINGES_URL = "https://www.les12singes.com/84-les-oublies"
|
||||||
|
|
||||||
function ensureSystemStyles() {
|
function ensureSystemStyles() {
|
||||||
const href = `systems/${game.system.id}/css/les-oublies.css`
|
const href = `systems/${game.system.id}/css/les-oublies.css`
|
||||||
@@ -28,6 +30,53 @@ function usesFoundryDefaultTokenTexture(actor, data) {
|
|||||||
return !tokenTexture || tokenTexture === CONST.DEFAULT_TOKEN || tokenTexture === "icons/svg/mystery-man.svg"
|
return !tokenTexture || tokenTexture === CONST.DEFAULT_TOKEN || tokenTexture === "icons/svg/mystery-man.svg"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getHelpJournalEntry() {
|
||||||
|
const pack = game.packs.get(`${game.system.id}.aide-systeme`)
|
||||||
|
if (!pack) return null
|
||||||
|
|
||||||
|
const documents = await pack.getDocuments()
|
||||||
|
return documents[0] ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildWelcomeMessageContent(helpJournal) {
|
||||||
|
const helpContent = helpJournal
|
||||||
|
? await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||||
|
`@UUID[${helpJournal.uuid}]{${game.i18n.localize("LESOUBLIES.welcome.helpLinkLabel")}}`,
|
||||||
|
{ async: true },
|
||||||
|
)
|
||||||
|
: game.i18n.localize("LESOUBLIES.welcome.helpUnavailable")
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="les-oublies-chat-card les-oublies-welcome-chat">
|
||||||
|
<div class="chat-card-header">
|
||||||
|
<div>
|
||||||
|
<p class="chat-card-eyebrow">${game.i18n.localize("LESOUBLIES.welcome.eyebrow")}</p>
|
||||||
|
<h3>${game.i18n.localize("LESOUBLIES.welcome.title")}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chat-card-body">
|
||||||
|
<p>${game.i18n.localize("LESOUBLIES.welcome.intro")}</p>
|
||||||
|
<p>${game.i18n.localize("LESOUBLIES.welcome.developerLabel")} <a href="${UBERWALD_URL}" target="_blank" rel="noopener noreferrer">Uberwald</a>.</p>
|
||||||
|
<p>${game.i18n.localize("LESOUBLIES.welcome.publisherLabel")} <a href="${XII_SINGES_URL}" target="_blank" rel="noopener noreferrer">Les XII Singes</a>.</p>
|
||||||
|
<p><strong>${game.i18n.localize("LESOUBLIES.welcome.helpLabel")}</strong> ${helpContent}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async function showWelcomeMessage() {
|
||||||
|
const helpJournal = await getHelpJournalEntry()
|
||||||
|
const content = await buildWelcomeMessageContent(helpJournal)
|
||||||
|
|
||||||
|
await ChatMessage.create({
|
||||||
|
speaker: {
|
||||||
|
alias: game.system.title,
|
||||||
|
},
|
||||||
|
content,
|
||||||
|
whisper: [game.user.id],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
Hooks.once("init", function () {
|
Hooks.once("init", function () {
|
||||||
console.info("Les Oubliés | Initialisation du système")
|
console.info("Les Oubliés | Initialisation du système")
|
||||||
ensureSystemStyles()
|
ensureSystemStyles()
|
||||||
@@ -77,6 +126,10 @@ Hooks.once("init", function () {
|
|||||||
LesOubliesUtility.registerHandlebarsHelpers()
|
LesOubliesUtility.registerHandlebarsHelpers()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Hooks.once("ready", function () {
|
||||||
|
showWelcomeMessage()
|
||||||
|
})
|
||||||
|
|
||||||
Hooks.on("preCreateActor", function (actor, data) {
|
Hooks.on("preCreateActor", function (actor, data) {
|
||||||
if (actor.type !== "personnage") return
|
if (actor.type !== "personnage") return
|
||||||
if (!usesFoundryDefaultTokenTexture(actor, data)) return
|
if (!usesFoundryDefaultTokenTexture(actor, data)) return
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Aide du système",
|
||||||
|
"type": "JournalEntry",
|
||||||
|
"ownership": {
|
||||||
|
"default": 2
|
||||||
|
},
|
||||||
|
"flags": {
|
||||||
|
"core": {}
|
||||||
|
},
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"name": "Bienvenue",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Les Oubliés dans Foundry</h1><p>Cette aide de jeu présente le fonctionnement concret du système <strong>fvtt-les-oublies</strong> dans Foundry VTT. Elle est pensée pour une prise en main rapide autour de la fiche, des jets, du combat, de la magie et des compendiums fournis.</p><h2>Ce que fait le système</h2><ul><li>gère les acteurs <strong>Personnage</strong>, <strong>Compagnie</strong> et <strong>Créature</strong> ;</li><li>calcule les valeurs dérivées utiles, dont les points de vie liés à la taille ;</li><li>propose des dialogues dédiés pour les tests, confrontations, initiatives et dégâts ;</li><li>fournit des compendiums techniques pour les races, tribus, métiers, compétences, armes, armures, équipements, pouvoirs de compagnie et sortilèges.</li></ul><h2>Par où commencer ?</h2><ol><li>Créez un <strong>Personnage</strong>.</li><li>Assignez-lui une <strong>Race</strong>, une <strong>Tribu</strong> et un <strong>Métier</strong> par glisser-déposer.</li><li>Complétez ou ajustez ses compétences et son équipement.</li><li>Utilisez les boutons de la fiche pour lancer les jets utiles en jeu.</li></ol><p>Les pages suivantes détaillent chaque zone importante avec des captures d'écran prises dans le système lui-même.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Portrait et identité",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Lire la fiche personnage</h1><p>L'onglet <strong>Portrait</strong> concentre l'identité du personnage et les éléments de création qui structurent le reste de la fiche.</p><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-sheet-portrait.png\" alt=\"Fiche personnage des Oubliés, onglet Portrait.\" /><figcaption>La fiche personnage affiche immédiatement les références de race, de tribu et de métier.</figcaption></figure><h2>À retenir</h2><ul><li>La zone <strong>Race / Tribu / Métier</strong> accepte le glisser-déposer depuis les compendiums et remplace proprement la référence existante.</li><li>Un nouveau personnage reçoit automatiquement le token système <code>border_token_oublies.webp</code> tant qu'aucun token personnalisé n'a déjà été défini.</li><li>Les informations d'identité, les notes et les ressources principales restent modifiables directement sur la fiche.</li></ul><p>Le portrait sert surtout de synthèse et de point d'entrée avant de passer aux compétences et aux actions de jeu.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Compétences et profils",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Compétences et profils</h1><p>L'onglet <strong>Compétences</strong> présente les compétences regroupées par profil. Le système rappelle en permanence la logique <strong>Base + Profil = Valeur finale</strong>.</p><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-sheet-competences.png\" alt=\"Fiche personnage des Oubliés, onglet Compétences.\" /><figcaption>Chaque groupe affiche sa valeur de profil et les compétences qui en dépendent.</figcaption></figure><h2>Fonctionnement</h2><ul><li>Les compétences du personnage proviennent en pratique de la création, des compendiums ou d'ajouts manuels.</li><li>Les compétences fermées restent identifiables et peuvent demander une activation fictionnelle ou un apprentissage préalable.</li><li>Les domaines utiles (<em>Arts</em>, <em>Artisanat</em>, <em>Érudition</em>, <em>Langues</em>) peuvent être saisis sur les items concernés.</li></ul><p>Quand vous préparez un jet, c'est généralement la <strong>valeur finale</strong> affichée ici qu'il faut reporter dans le dialogue de résolution.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jets de test, confrontation et initiative",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Les jets principaux</h1><p>Le système embarque trois dialogues génériques : <strong>test</strong>, <strong>confrontation</strong> et <strong>initiative</strong>. Ils respectent le principe Songes / Cauchemar avec choix du dé retenu quand plusieurs dés sont en concurrence.</p><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-dialog-test.png\" alt=\"Dialogue de jet de test dans le système Les Oubliés.\" /><figcaption>Le jet de test permet de choisir la difficulté, le mode de jet et un éventuel dé supplémentaire.</figcaption></figure><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-dialog-confrontation.png\" alt=\"Dialogue de confrontation dans le système Les Oubliés.\" /><figcaption>La confrontation gère les deux camps, avec saisie manuelle ou sélection d'un adversaire cible.</figcaption></figure><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-dialog-initiative.png\" alt=\"Dialogue d'initiative dans le système Les Oubliés.\" /><figcaption>L'initiative s'appuie sur Rapidité puis applique l'arrondi supérieur avec plafond à 12.</figcaption></figure><h2>Comportements utiles</h2><ul><li>Le système gère les modes <strong>1d12</strong>, <strong>2d12</strong> Songes / Cauchemar et les variantes avec dé supplémentaire.</li><li>Le <strong>12 explosif</strong> et le <strong>1 naturel</strong> sont pris en compte dans la résolution.</li><li>La confrontation peut récupérer une cible sélectionnée sur la scène, mais reste utilisable en saisie libre si aucune cible n'est active.</li></ul><p>Après le lancer, le chat produit une carte de résultat dédiée avec le détail utile à la table.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Combat, dégâts et protections",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Combattre dans le système</h1><p>L'onglet <strong>Combat & Magie</strong> regroupe les actions de combat, les armes équipées et les aides à la résolution associées.</p><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-sheet-combat-magie.png\" alt=\"Fiche personnage des Oubliés, onglet Combat et magie.\" /><figcaption>Les actions de combat, les réserves de fils et la magie partagent le même onglet pour limiter les allers-retours.</figcaption></figure><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-dialog-degats.png\" alt=\"Dialogue de résolution des dégâts dans le système Les Oubliés.\" /><figcaption>Le helper de dégâts applique la base de l'arme, les modificateurs et la protection ciblée.</figcaption></figure><h2>Points importants</h2><ul><li>Le bouton <strong>Attaque</strong> ouvre une action contextualisée depuis l'arme portée.</li><li>Le bouton <strong>Dégâts</strong> ouvre un helper plutôt qu'un jet classique, conformément aux règles du jeu.</li><li>Les armes à taille variable tiennent compte de la <strong>taille réelle du porteur</strong> pour calculer les dégâts de base.</li><li>La protection de la cible peut être appliquée directement dans la résolution finale.</li></ul><p>Les cartes de chat qui en résultent sont compactes et conçues pour un usage fréquent en partie.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Magie, fils et globes",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Magie et réserves</h1><p>La moitié basse de l'onglet <strong>Combat & Magie</strong> gère les fils, les globes et les sortilèges du personnage.</p><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-sheet-combat-magie.png\" alt=\"Réserves de fils, globes et sortilèges dans la fiche personnage des Oubliés.\" /><figcaption>Les réserves personnelle et de compagnie sont directement manipulables depuis la fiche.</figcaption></figure><h2>Ce que permet la fiche</h2><ul><li>déplacer des <strong>fils de Songes</strong>, des <strong>fils de Cauchemar</strong> et des <strong>globes vides</strong> entre la réserve personnelle et la compagnie ;</li><li>lancer la <strong>récolte de fils</strong> depuis le bouton dédié ;</li><li>activer un <strong>sortilège</strong> depuis sa ligne sans passer par un jet générique quand les règles ne le demandent pas.</li></ul><p>Les dépenses de fils rendent automatiquement autant de globes vides à la réserve utilisée. Le système met ainsi l'accent sur la circulation des ressources plutôt que sur des sous-feuilles séparées.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Compendiums et glisser-déposer",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Utiliser les compendiums</h1><p>Les compendiums fournis par le système servent de base technique pour créer et enrichir les acteurs.</p><h2>Usages recommandés</h2><ul><li>glisser une <strong>race</strong>, une <strong>tribu</strong> ou un <strong>métier</strong> sur un personnage pour configurer rapidement sa création ;</li><li>ajouter des <strong>armes</strong>, <strong>armures</strong>, <strong>équipements</strong> et <strong>sortilèges</strong> depuis les packs dédiés ;</li><li>faire glisser un item embarqué depuis la fiche vers la sidebar des objets quand vous souhaitez l'extraire comme document autonome.</li></ul><h2>À savoir</h2><ul><li>Les compendiums du système sont volontairement <strong>techniques</strong> : les champs descriptifs riches ont été vidés pour rester dans le périmètre du système.</li><li>Les versions complètes des contenus sont destinées au module frère <strong>fvtt-les-oublies-base</strong>.</li></ul><p>Pour une table de jeu, le plus simple est donc d'utiliser ces compendiums comme bibliothèque de construction rapide, puis d'affiner directement sur la fiche si nécessaire.</p>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000002
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
2026/05/06-20:00:09.287368 7f612bfff6c0 Delete type=3 #1
|
||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000004
|
MANIFEST-000002
|
||||||
|
|||||||
@@ -1,15 +1 @@
|
|||||||
2026/05/06-10:42:52.439890 7fd39d7ec6c0 Recovering log #3
|
2026/05/06-20:00:09.149296 7f6174dfd6c0 Delete type=3 #1
|
||||||
2026/05/06-10:42:52.439947 7fd39d7ec6c0 Level-0 table #5: started
|
|
||||||
2026/05/06-10:42:52.443417 7fd39d7ec6c0 Level-0 table #5: 6826 bytes OK
|
|
||||||
2026/05/06-10:42:52.454459 7fd39d7ec6c0 Delete type=0 #3
|
|
||||||
2026/05/06-10:42:52.454587 7fd39d7ec6c0 Delete type=3 #2
|
|
||||||
2026/05/06-10:43:22.990986 7fd39cfeb6c0 Level-0 table #8: started
|
|
||||||
2026/05/06-10:43:22.991003 7fd39cfeb6c0 Level-0 table #8: 0 bytes OK
|
|
||||||
2026/05/06-10:43:22.997495 7fd39cfeb6c0 Delete type=0 #6
|
|
||||||
2026/05/06-10:43:23.019890 7fd39cfeb6c0 Manual compaction at level-0 from '!items!0wVpxy2XZYx6S5QR' @ 72057594037927935 : 1 .. '!items!wvt5PIveAgIdsK1T' @ 0 : 0; will stop at '!items!wvt5PIveAgIdsK1T' @ 35 : 1
|
|
||||||
2026/05/06-10:43:23.019900 7fd39cfeb6c0 Compacting 1@0 + 0@1 files
|
|
||||||
2026/05/06-10:43:23.023528 7fd39cfeb6c0 Generated table #9@0: 35 keys, 6826 bytes
|
|
||||||
2026/05/06-10:43:23.023563 7fd39cfeb6c0 Compacted 1@0 + 0@1 files => 6826 bytes
|
|
||||||
2026/05/06-10:43:23.030165 7fd39cfeb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
|
||||||
2026/05/06-10:43:23.030304 7fd39cfeb6c0 Delete type=2 #5
|
|
||||||
2026/05/06-10:43:23.050189 7fd39cfeb6c0 Manual compaction at level-0 from '!items!wvt5PIveAgIdsK1T' @ 35 : 1 .. '!items!wvt5PIveAgIdsK1T' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
2026/05/06-10:41:39.239714 7f66b3fff6c0 Delete type=3 #1
|
|
||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000004
|
MANIFEST-000002
|
||||||
|
|||||||
@@ -1,15 +1 @@
|
|||||||
2026/05/06-10:42:52.456918 7fd39e7ee6c0 Recovering log #3
|
2026/05/06-20:00:09.165377 7f612bfff6c0 Delete type=3 #1
|
||||||
2026/05/06-10:42:52.456943 7fd39e7ee6c0 Level-0 table #5: started
|
|
||||||
2026/05/06-10:42:52.460700 7fd39e7ee6c0 Level-0 table #5: 815 bytes OK
|
|
||||||
2026/05/06-10:42:52.470387 7fd39e7ee6c0 Delete type=0 #3
|
|
||||||
2026/05/06-10:42:52.470451 7fd39e7ee6c0 Delete type=3 #2
|
|
||||||
2026/05/06-10:43:22.984965 7fd39cfeb6c0 Level-0 table #8: started
|
|
||||||
2026/05/06-10:43:22.985000 7fd39cfeb6c0 Level-0 table #8: 0 bytes OK
|
|
||||||
2026/05/06-10:43:22.990909 7fd39cfeb6c0 Delete type=0 #6
|
|
||||||
2026/05/06-10:43:23.009491 7fd39cfeb6c0 Manual compaction at level-0 from '!items!3BnwI245d2H2cttB' @ 72057594037927935 : 1 .. '!items!ouVi1TDDGHMH7wRj' @ 0 : 0; will stop at '!items!ouVi1TDDGHMH7wRj' @ 2 : 1
|
|
||||||
2026/05/06-10:43:23.009499 7fd39cfeb6c0 Compacting 1@0 + 0@1 files
|
|
||||||
2026/05/06-10:43:23.012514 7fd39cfeb6c0 Generated table #9@0: 3 keys, 815 bytes
|
|
||||||
2026/05/06-10:43:23.012529 7fd39cfeb6c0 Compacted 1@0 + 0@1 files => 815 bytes
|
|
||||||
2026/05/06-10:43:23.019598 7fd39cfeb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
|
||||||
2026/05/06-10:43:23.019764 7fd39cfeb6c0 Delete type=2 #5
|
|
||||||
2026/05/06-10:43:23.050179 7fd39cfeb6c0 Manual compaction at level-0 from '!items!ouVi1TDDGHMH7wRj' @ 2 : 1 .. '!items!ouVi1TDDGHMH7wRj' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
2026/05/06-10:41:39.316793 7f66b37fe6c0 Delete type=3 #1
|
|
||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000004
|
MANIFEST-000002
|
||||||
|
|||||||
@@ -1,15 +1 @@
|
|||||||
2026/05/06-10:42:52.504965 7fd39d7ec6c0 Recovering log #3
|
2026/05/06-20:00:09.210742 7f6174dfd6c0 Delete type=3 #1
|
||||||
2026/05/06-10:42:52.505011 7fd39d7ec6c0 Level-0 table #5: started
|
|
||||||
2026/05/06-10:42:52.508141 7fd39d7ec6c0 Level-0 table #5: 4614 bytes OK
|
|
||||||
2026/05/06-10:42:52.518635 7fd39d7ec6c0 Delete type=0 #3
|
|
||||||
2026/05/06-10:42:52.518695 7fd39d7ec6c0 Delete type=3 #2
|
|
||||||
2026/05/06-10:43:23.071936 7fd39cfeb6c0 Level-0 table #8: started
|
|
||||||
2026/05/06-10:43:23.071953 7fd39cfeb6c0 Level-0 table #8: 0 bytes OK
|
|
||||||
2026/05/06-10:43:23.077983 7fd39cfeb6c0 Delete type=0 #6
|
|
||||||
2026/05/06-10:43:23.111647 7fd39cfeb6c0 Manual compaction at level-0 from '!items!1IhIUjv73YMttYW0' @ 72057594037927935 : 1 .. '!items!zrJvQTctIpfjIz7J' @ 0 : 0; will stop at '!items!zrJvQTctIpfjIz7J' @ 20 : 1
|
|
||||||
2026/05/06-10:43:23.111655 7fd39cfeb6c0 Compacting 1@0 + 0@1 files
|
|
||||||
2026/05/06-10:43:23.115172 7fd39cfeb6c0 Generated table #9@0: 27 keys, 4614 bytes
|
|
||||||
2026/05/06-10:43:23.115193 7fd39cfeb6c0 Compacted 1@0 + 0@1 files => 4614 bytes
|
|
||||||
2026/05/06-10:43:23.121954 7fd39cfeb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
|
||||||
2026/05/06-10:43:23.122015 7fd39cfeb6c0 Delete type=2 #5
|
|
||||||
2026/05/06-10:43:23.122144 7fd39cfeb6c0 Manual compaction at level-0 from '!items!zrJvQTctIpfjIz7J' @ 20 : 1 .. '!items!zrJvQTctIpfjIz7J' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
2026/05/06-10:41:39.548963 7f66b3fff6c0 Delete type=3 #1
|
|
||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000004
|
MANIFEST-000002
|
||||||
|
|||||||
@@ -1,15 +1 @@
|
|||||||
2026/05/06-10:42:52.472500 7fd39efef6c0 Recovering log #3
|
2026/05/06-20:00:09.180731 7f6175dff6c0 Delete type=3 #1
|
||||||
2026/05/06-10:42:52.472607 7fd39efef6c0 Level-0 table #5: started
|
|
||||||
2026/05/06-10:42:52.476439 7fd39efef6c0 Level-0 table #5: 6181 bytes OK
|
|
||||||
2026/05/06-10:42:52.486963 7fd39efef6c0 Delete type=0 #3
|
|
||||||
2026/05/06-10:42:52.487018 7fd39efef6c0 Delete type=3 #2
|
|
||||||
2026/05/06-10:43:22.997591 7fd39cfeb6c0 Level-0 table #8: started
|
|
||||||
2026/05/06-10:43:22.997612 7fd39cfeb6c0 Level-0 table #8: 0 bytes OK
|
|
||||||
2026/05/06-10:43:23.003434 7fd39cfeb6c0 Delete type=0 #6
|
|
||||||
2026/05/06-10:43:23.030431 7fd39cfeb6c0 Manual compaction at level-0 from '!items!19G5qBEMaflvGK28' @ 72057594037927935 : 1 .. '!items!zoKnkvQK4wPA0cvP' @ 0 : 0; will stop at '!items!zoKnkvQK4wPA0cvP' @ 35 : 1
|
|
||||||
2026/05/06-10:43:23.030439 7fd39cfeb6c0 Compacting 1@0 + 0@1 files
|
|
||||||
2026/05/06-10:43:23.033703 7fd39cfeb6c0 Generated table #9@0: 35 keys, 6181 bytes
|
|
||||||
2026/05/06-10:43:23.033732 7fd39cfeb6c0 Compacted 1@0 + 0@1 files => 6181 bytes
|
|
||||||
2026/05/06-10:43:23.039807 7fd39cfeb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
|
||||||
2026/05/06-10:43:23.039906 7fd39cfeb6c0 Delete type=2 #5
|
|
||||||
2026/05/06-10:43:23.050199 7fd39cfeb6c0 Manual compaction at level-0 from '!items!zoKnkvQK4wPA0cvP' @ 35 : 1 .. '!items!zoKnkvQK4wPA0cvP' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
2026/05/06-10:41:39.389376 7f67015ff6c0 Delete type=3 #1
|
|
||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000004
|
MANIFEST-000002
|
||||||
|
|||||||
@@ -1,15 +1 @@
|
|||||||
2026/05/06-10:42:52.553462 7fd39e7ee6c0 Recovering log #3
|
2026/05/06-20:00:09.256606 7f61755fe6c0 Delete type=3 #1
|
||||||
2026/05/06-10:42:52.553504 7fd39e7ee6c0 Level-0 table #5: started
|
|
||||||
2026/05/06-10:42:52.556942 7fd39e7ee6c0 Level-0 table #5: 4030 bytes OK
|
|
||||||
2026/05/06-10:42:52.566377 7fd39e7ee6c0 Delete type=0 #3
|
|
||||||
2026/05/06-10:42:52.566433 7fd39e7ee6c0 Delete type=3 #2
|
|
||||||
2026/05/06-10:43:23.065397 7fd39cfeb6c0 Level-0 table #8: started
|
|
||||||
2026/05/06-10:43:23.065421 7fd39cfeb6c0 Level-0 table #8: 0 bytes OK
|
|
||||||
2026/05/06-10:43:23.071751 7fd39cfeb6c0 Delete type=0 #6
|
|
||||||
2026/05/06-10:43:23.100865 7fd39cfeb6c0 Manual compaction at level-0 from '!items!1o5Kw4HzVNxm2LkJ' @ 72057594037927935 : 1 .. '!items!zIdc7oRRURJK1LCb' @ 0 : 0; will stop at '!items!zIdc7oRRURJK1LCb' @ 6 : 1
|
|
||||||
2026/05/06-10:43:23.100878 7fd39cfeb6c0 Compacting 1@0 + 0@1 files
|
|
||||||
2026/05/06-10:43:23.104865 7fd39cfeb6c0 Generated table #9@0: 8 keys, 4030 bytes
|
|
||||||
2026/05/06-10:43:23.104896 7fd39cfeb6c0 Compacted 1@0 + 0@1 files => 4030 bytes
|
|
||||||
2026/05/06-10:43:23.111409 7fd39cfeb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
|
||||||
2026/05/06-10:43:23.111517 7fd39cfeb6c0 Delete type=2 #5
|
|
||||||
2026/05/06-10:43:23.122135 7fd39cfeb6c0 Manual compaction at level-0 from '!items!zIdc7oRRURJK1LCb' @ 6 : 1 .. '!items!zIdc7oRRURJK1LCb' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
2026/05/06-10:41:39.785271 7f6700dfe6c0 Delete type=3 #1
|
|
||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000004
|
MANIFEST-000002
|
||||||
|
|||||||
@@ -1,15 +1 @@
|
|||||||
2026/05/06-10:42:52.489022 7fd39e7ee6c0 Recovering log #3
|
2026/05/06-20:00:09.195364 7f61755fe6c0 Delete type=3 #1
|
||||||
2026/05/06-10:42:52.489067 7fd39e7ee6c0 Level-0 table #5: started
|
|
||||||
2026/05/06-10:42:52.492225 7fd39e7ee6c0 Level-0 table #5: 2059 bytes OK
|
|
||||||
2026/05/06-10:42:52.502742 7fd39e7ee6c0 Delete type=0 #3
|
|
||||||
2026/05/06-10:42:52.502805 7fd39e7ee6c0 Delete type=3 #2
|
|
||||||
2026/05/06-10:43:23.003515 7fd39cfeb6c0 Level-0 table #8: started
|
|
||||||
2026/05/06-10:43:23.003534 7fd39cfeb6c0 Level-0 table #8: 0 bytes OK
|
|
||||||
2026/05/06-10:43:23.009396 7fd39cfeb6c0 Delete type=0 #6
|
|
||||||
2026/05/06-10:43:23.040005 7fd39cfeb6c0 Manual compaction at level-0 from '!items!FfQwxxtecQRrRAOX' @ 72057594037927935 : 1 .. '!items!uKW7eAe5nA8zgHNQ' @ 0 : 0; will stop at '!items!uKW7eAe5nA8zgHNQ' @ 2 : 1
|
|
||||||
2026/05/06-10:43:23.040012 7fd39cfeb6c0 Compacting 1@0 + 0@1 files
|
|
||||||
2026/05/06-10:43:23.043526 7fd39cfeb6c0 Generated table #9@0: 8 keys, 2059 bytes
|
|
||||||
2026/05/06-10:43:23.043551 7fd39cfeb6c0 Compacted 1@0 + 0@1 files => 2059 bytes
|
|
||||||
2026/05/06-10:43:23.049951 7fd39cfeb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
|
||||||
2026/05/06-10:43:23.050079 7fd39cfeb6c0 Delete type=2 #5
|
|
||||||
2026/05/06-10:43:23.050207 7fd39cfeb6c0 Manual compaction at level-0 from '!items!uKW7eAe5nA8zgHNQ' @ 2 : 1 .. '!items!uKW7eAe5nA8zgHNQ' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
2026/05/06-10:41:39.470099 7f6700dfe6c0 Delete type=3 #1
|
|
||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000004
|
MANIFEST-000002
|
||||||
|
|||||||
@@ -1,15 +1 @@
|
|||||||
2026/05/06-10:42:52.520730 7fd39e7ee6c0 Recovering log #3
|
2026/05/06-20:00:09.225835 7f612bfff6c0 Delete type=3 #1
|
||||||
2026/05/06-10:42:52.520772 7fd39e7ee6c0 Level-0 table #5: started
|
|
||||||
2026/05/06-10:42:52.523941 7fd39e7ee6c0 Level-0 table #5: 3420 bytes OK
|
|
||||||
2026/05/06-10:42:52.535782 7fd39e7ee6c0 Delete type=0 #3
|
|
||||||
2026/05/06-10:42:52.535848 7fd39e7ee6c0 Delete type=3 #2
|
|
||||||
2026/05/06-10:43:23.050346 7fd39cfeb6c0 Level-0 table #8: started
|
|
||||||
2026/05/06-10:43:23.050364 7fd39cfeb6c0 Level-0 table #8: 0 bytes OK
|
|
||||||
2026/05/06-10:43:23.058307 7fd39cfeb6c0 Delete type=0 #6
|
|
||||||
2026/05/06-10:43:23.078097 7fd39cfeb6c0 Manual compaction at level-0 from '!items!0xfnMEBzcDzn33u1' @ 72057594037927935 : 1 .. '!items!ucpCiBTGiqJ4vPoK' @ 0 : 0; will stop at '!items!ucpCiBTGiqJ4vPoK' @ 4 : 1
|
|
||||||
2026/05/06-10:43:23.078105 7fd39cfeb6c0 Compacting 1@0 + 0@1 files
|
|
||||||
2026/05/06-10:43:23.081777 7fd39cfeb6c0 Generated table #9@0: 7 keys, 3420 bytes
|
|
||||||
2026/05/06-10:43:23.081823 7fd39cfeb6c0 Compacted 1@0 + 0@1 files => 3420 bytes
|
|
||||||
2026/05/06-10:43:23.088900 7fd39cfeb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
|
||||||
2026/05/06-10:43:23.089029 7fd39cfeb6c0 Delete type=2 #5
|
|
||||||
2026/05/06-10:43:23.122115 7fd39cfeb6c0 Manual compaction at level-0 from '!items!ucpCiBTGiqJ4vPoK' @ 4 : 1 .. '!items!ucpCiBTGiqJ4vPoK' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
2026/05/06-10:41:39.629799 7f66b37fe6c0 Delete type=3 #1
|
|
||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000004
|
MANIFEST-000002
|
||||||
|
|||||||
@@ -1,15 +1 @@
|
|||||||
2026/05/06-10:42:52.568751 7fd39d7ec6c0 Recovering log #3
|
2026/05/06-20:00:09.271737 7f6174dfd6c0 Delete type=3 #1
|
||||||
2026/05/06-10:42:52.568899 7fd39d7ec6c0 Level-0 table #5: started
|
|
||||||
2026/05/06-10:42:52.572727 7fd39d7ec6c0 Level-0 table #5: 16649 bytes OK
|
|
||||||
2026/05/06-10:42:52.593776 7fd39d7ec6c0 Delete type=0 #3
|
|
||||||
2026/05/06-10:42:52.593835 7fd39d7ec6c0 Delete type=3 #2
|
|
||||||
2026/05/06-10:43:23.122256 7fd39cfeb6c0 Level-0 table #8: started
|
|
||||||
2026/05/06-10:43:23.122276 7fd39cfeb6c0 Level-0 table #8: 0 bytes OK
|
|
||||||
2026/05/06-10:43:23.128449 7fd39cfeb6c0 Delete type=0 #6
|
|
||||||
2026/05/06-10:43:23.148375 7fd39cfeb6c0 Manual compaction at level-0 from '!items!15iY8vCuisq7fgxC' @ 72057594037927935 : 1 .. '!items!zlacnrDvD6OQqSq9' @ 0 : 0; will stop at '!items!zlacnrDvD6OQqSq9' @ 49 : 1
|
|
||||||
2026/05/06-10:43:23.148382 7fd39cfeb6c0 Compacting 1@0 + 0@1 files
|
|
||||||
2026/05/06-10:43:23.151996 7fd39cfeb6c0 Generated table #9@0: 72 keys, 16649 bytes
|
|
||||||
2026/05/06-10:43:23.152009 7fd39cfeb6c0 Compacted 1@0 + 0@1 files => 16649 bytes
|
|
||||||
2026/05/06-10:43:23.158338 7fd39cfeb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
|
||||||
2026/05/06-10:43:23.158406 7fd39cfeb6c0 Delete type=2 #5
|
|
||||||
2026/05/06-10:43:23.158547 7fd39cfeb6c0 Manual compaction at level-0 from '!items!zlacnrDvD6OQqSq9' @ 49 : 1 .. '!items!zlacnrDvD6OQqSq9' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
2026/05/06-10:41:39.858447 7f66b3fff6c0 Delete type=3 #1
|
|
||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000004
|
MANIFEST-000002
|
||||||
|
|||||||
@@ -1,15 +1 @@
|
|||||||
2026/05/06-10:42:52.538075 7fd39d7ec6c0 Recovering log #3
|
2026/05/06-20:00:09.241097 7f6175dff6c0 Delete type=3 #1
|
||||||
2026/05/06-10:42:52.538162 7fd39d7ec6c0 Level-0 table #5: started
|
|
||||||
2026/05/06-10:42:52.541922 7fd39d7ec6c0 Level-0 table #5: 6762 bytes OK
|
|
||||||
2026/05/06-10:42:52.551592 7fd39d7ec6c0 Delete type=0 #3
|
|
||||||
2026/05/06-10:42:52.551647 7fd39d7ec6c0 Delete type=3 #2
|
|
||||||
2026/05/06-10:43:23.058483 7fd39cfeb6c0 Level-0 table #8: started
|
|
||||||
2026/05/06-10:43:23.058516 7fd39cfeb6c0 Level-0 table #8: 0 bytes OK
|
|
||||||
2026/05/06-10:43:23.065217 7fd39cfeb6c0 Delete type=0 #6
|
|
||||||
2026/05/06-10:43:23.089170 7fd39cfeb6c0 Manual compaction at level-0 from '!items!4aynfqE4U9hcdgMN' @ 72057594037927935 : 1 .. '!items!yUWIdLKCkSvQcMT7' @ 0 : 0; will stop at '!items!yUWIdLKCkSvQcMT7' @ 9 : 1
|
|
||||||
2026/05/06-10:43:23.089178 7fd39cfeb6c0 Compacting 1@0 + 0@1 files
|
|
||||||
2026/05/06-10:43:23.092608 7fd39cfeb6c0 Generated table #9@0: 11 keys, 6762 bytes
|
|
||||||
2026/05/06-10:43:23.092669 7fd39cfeb6c0 Compacted 1@0 + 0@1 files => 6762 bytes
|
|
||||||
2026/05/06-10:43:23.100615 7fd39cfeb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
|
||||||
2026/05/06-10:43:23.100731 7fd39cfeb6c0 Delete type=2 #5
|
|
||||||
2026/05/06-10:43:23.122126 7fd39cfeb6c0 Manual compaction at level-0 from '!items!yUWIdLKCkSvQcMT7' @ 9 : 1 .. '!items!yUWIdLKCkSvQcMT7' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
2026/05/06-10:41:39.711104 7f67015ff6c0 Delete type=3 #1
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import fs from "node:fs"
|
import fs from "node:fs"
|
||||||
|
|
||||||
import { buildPacks } from "./pack-builder.mjs"
|
import { buildPacks, SYSTEM_PACK_DEFINITIONS } from "./pack-builder.mjs"
|
||||||
|
|
||||||
const rootDir = path.resolve(import.meta.dirname, "..")
|
const rootDir = path.resolve(import.meta.dirname, "..")
|
||||||
const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf8"))
|
const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf8"))
|
||||||
@@ -10,6 +10,7 @@ const systemJson = JSON.parse(fs.readFileSync(path.join(rootDir, "system.json"),
|
|||||||
await buildPacks({
|
await buildPacks({
|
||||||
sourceRoot: path.join(rootDir, "packs-src"),
|
sourceRoot: path.join(rootDir, "packs-src"),
|
||||||
outputRoot: path.join(rootDir, "packs"),
|
outputRoot: path.join(rootDir, "packs"),
|
||||||
|
packDefinitions: SYSTEM_PACK_DEFINITIONS,
|
||||||
documentSystemId: systemJson.id,
|
documentSystemId: systemJson.id,
|
||||||
documentSystemVersion: packageJson.version,
|
documentSystemVersion: packageJson.version,
|
||||||
coreVersion: String(systemJson.compatibility?.verified ?? systemJson.compatibility?.minimum ?? ""),
|
coreVersion: String(systemJson.compatibility?.verified ?? systemJson.compatibility?.minimum ?? ""),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import crypto from "node:crypto"
|
|||||||
|
|
||||||
import { Level } from "level"
|
import { Level } from "level"
|
||||||
|
|
||||||
export const PACK_DEFINITIONS = [
|
export const CONTENT_PACK_DEFINITIONS = [
|
||||||
{ sourceFile: "armes.json", outputFolder: "armes", type: "Item" },
|
{ sourceFile: "armes.json", outputFolder: "armes", type: "Item" },
|
||||||
{ sourceFile: "armures.json", outputFolder: "armures", type: "Item" },
|
{ sourceFile: "armures.json", outputFolder: "armures", type: "Item" },
|
||||||
{ sourceFile: "equipements.json", outputFolder: "equipements", type: "Item" },
|
{ sourceFile: "equipements.json", outputFolder: "equipements", type: "Item" },
|
||||||
@@ -16,6 +16,11 @@ export const PACK_DEFINITIONS = [
|
|||||||
{ sourceFile: "sortileges.json", outputFolder: "sortileges", type: "Item" },
|
{ sourceFile: "sortileges.json", outputFolder: "sortileges", type: "Item" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const SYSTEM_PACK_DEFINITIONS = [
|
||||||
|
...CONTENT_PACK_DEFINITIONS,
|
||||||
|
{ sourceFile: "aide-systeme.json", outputFolder: "aide-systeme", type: "JournalEntry" },
|
||||||
|
]
|
||||||
|
|
||||||
function slugId(input) {
|
function slugId(input) {
|
||||||
const hash = crypto.createHash("sha256").update(input).digest()
|
const hash = crypto.createHash("sha256").update(input).digest()
|
||||||
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
@@ -26,22 +31,14 @@ function slugId(input) {
|
|||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
function toPackDocument(entry, index, {
|
function createDocumentStats({
|
||||||
documentSystemId,
|
documentSystemId,
|
||||||
documentSystemVersion,
|
documentSystemVersion,
|
||||||
coreVersion,
|
coreVersion,
|
||||||
createdTime,
|
createdTime,
|
||||||
lastModifiedBy = "Copilot",
|
lastModifiedBy = "Copilot",
|
||||||
} = {}) {
|
} = {}) {
|
||||||
const docId = slugId(`${entry.type}:${entry.name}`)
|
|
||||||
return {
|
return {
|
||||||
name: entry.name,
|
|
||||||
type: entry.type,
|
|
||||||
img: entry.img ?? "icons/svg/item-bag.svg",
|
|
||||||
system: entry.system ?? {},
|
|
||||||
effects: Array.isArray(entry.effects) ? entry.effects : [],
|
|
||||||
flags: entry.flags ?? {},
|
|
||||||
_stats: {
|
|
||||||
systemId: documentSystemId,
|
systemId: documentSystemId,
|
||||||
systemVersion: documentSystemVersion,
|
systemVersion: documentSystemVersion,
|
||||||
coreVersion,
|
coreVersion,
|
||||||
@@ -51,16 +48,105 @@ function toPackDocument(entry, index, {
|
|||||||
compendiumSource: null,
|
compendiumSource: null,
|
||||||
duplicateSource: null,
|
duplicateSource: null,
|
||||||
exportSource: null,
|
exportSource: null,
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toItemPackDocument(entry, index, options = {}) {
|
||||||
|
const docId = slugId(`${entry.type}:${entry.name}`)
|
||||||
|
return {
|
||||||
|
key: `!items!${docId}`,
|
||||||
|
value: {
|
||||||
|
name: entry.name,
|
||||||
|
type: entry.type,
|
||||||
|
img: entry.img ?? "icons/svg/item-bag.svg",
|
||||||
|
system: entry.system ?? {},
|
||||||
|
effects: Array.isArray(entry.effects) ? entry.effects : [],
|
||||||
|
flags: entry.flags ?? {},
|
||||||
|
_stats: createDocumentStats(options),
|
||||||
_id: docId,
|
_id: docId,
|
||||||
folder: null,
|
folder: null,
|
||||||
sort: index * 1000,
|
sort: index * 1000,
|
||||||
ownership: {
|
ownership: {
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
embedded: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toJournalPageDocument(entry, journalId, page, pageIndex, options = {}) {
|
||||||
|
const pageId = slugId(`JournalEntryPage:${entry.name}:${page.name ?? page.title ?? pageIndex}`)
|
||||||
|
return {
|
||||||
|
_id: pageId,
|
||||||
|
name: page.name ?? `Page ${pageIndex + 1}`,
|
||||||
|
type: page.type ?? "text",
|
||||||
|
title: {
|
||||||
|
show: page.title?.show ?? true,
|
||||||
|
level: page.title?.level ?? 1,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
format: page.text?.format ?? 1,
|
||||||
|
content: page.text?.content ?? "",
|
||||||
|
},
|
||||||
|
system: page.system ?? {},
|
||||||
|
image: page.image ?? {},
|
||||||
|
video: page.video ?? { controls: true, volume: 0.5 },
|
||||||
|
src: page.src ?? null,
|
||||||
|
category: page.category ?? null,
|
||||||
|
sort: page.sort ?? pageIndex * 1000,
|
||||||
|
ownership: page.ownership ?? { default: -1 },
|
||||||
|
flags: page.flags ?? {},
|
||||||
|
_stats: createDocumentStats(options),
|
||||||
|
_key: `!journal.pages!${journalId}.${pageId}`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toJournalPackDocument(entry, index, options = {}) {
|
||||||
|
const docId = slugId(`JournalEntry:${entry.name}`)
|
||||||
|
const pages = Array.isArray(entry.pages)
|
||||||
|
? entry.pages.map((page, pageIndex) => toJournalPageDocument(entry, docId, page, pageIndex, options))
|
||||||
|
: []
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: `!journal!${docId}`,
|
||||||
|
value: {
|
||||||
|
name: entry.name,
|
||||||
|
pages: pages.map((page) => page._id),
|
||||||
|
ownership: entry.ownership ?? { default: 0 },
|
||||||
|
flags: entry.flags ?? { core: {} },
|
||||||
|
_stats: createDocumentStats(options),
|
||||||
|
folder: null,
|
||||||
|
sort: entry.sort ?? index * 1000,
|
||||||
|
_id: docId,
|
||||||
|
categories: Array.isArray(entry.categories) ? entry.categories : [],
|
||||||
|
},
|
||||||
|
embedded: pages.map((page) => ({
|
||||||
|
key: page._key,
|
||||||
|
value: {
|
||||||
|
name: page.name,
|
||||||
|
type: page.type,
|
||||||
|
title: page.title,
|
||||||
|
text: page.text,
|
||||||
|
system: page.system,
|
||||||
|
image: page.image,
|
||||||
|
video: page.video,
|
||||||
|
src: page.src,
|
||||||
|
category: page.category,
|
||||||
|
sort: page.sort,
|
||||||
|
ownership: page.ownership,
|
||||||
|
flags: page.flags,
|
||||||
|
_stats: page._stats,
|
||||||
|
_id: page._id,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toPackDocument(entry, index, options = {}) {
|
||||||
|
if (entry.type === "JournalEntry") return toJournalPackDocument(entry, index, options)
|
||||||
|
return toItemPackDocument(entry, index, options)
|
||||||
|
}
|
||||||
|
|
||||||
async function buildPack({
|
async function buildPack({
|
||||||
sourcePath,
|
sourcePath,
|
||||||
outputPath,
|
outputPath,
|
||||||
@@ -95,7 +181,10 @@ async function buildPack({
|
|||||||
createdTime,
|
createdTime,
|
||||||
lastModifiedBy,
|
lastModifiedBy,
|
||||||
})
|
})
|
||||||
batch.put(`!items!${doc._id}`, JSON.stringify(doc))
|
batch.put(doc.key, JSON.stringify(doc.value))
|
||||||
|
for (const embedded of doc.embedded) {
|
||||||
|
batch.put(embedded.key, JSON.stringify(embedded.value))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
await batch.write()
|
await batch.write()
|
||||||
} finally {
|
} finally {
|
||||||
@@ -106,7 +195,7 @@ async function buildPack({
|
|||||||
export async function buildPacks({
|
export async function buildPacks({
|
||||||
sourceRoot,
|
sourceRoot,
|
||||||
outputRoot,
|
outputRoot,
|
||||||
packDefinitions = PACK_DEFINITIONS,
|
packDefinitions = SYSTEM_PACK_DEFINITIONS,
|
||||||
documentSystemId,
|
documentSystemId,
|
||||||
documentSystemVersion,
|
documentSystemVersion,
|
||||||
coreVersion,
|
coreVersion,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import fs from "node:fs"
|
import fs from "node:fs"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
|
|
||||||
import { PACK_DEFINITIONS, buildPacks } from "./pack-builder.mjs"
|
import { CONTENT_PACK_DEFINITIONS, SYSTEM_PACK_DEFINITIONS, buildPacks } from "./pack-builder.mjs"
|
||||||
|
|
||||||
const systemRoot = path.resolve(import.meta.dirname, "..")
|
const systemRoot = path.resolve(import.meta.dirname, "..")
|
||||||
const targetRoot = path.resolve(
|
const targetRoot = path.resolve(
|
||||||
@@ -20,10 +20,11 @@ const richFieldMap = Object.fromEntries(
|
|||||||
Object.entries(systemManifest.documentTypes?.Item ?? {}).map(([type, data]) => [type, data.htmlFields ?? []]),
|
Object.entries(systemManifest.documentTypes?.Item ?? {}).map(([type, data]) => [type, data.htmlFields ?? []]),
|
||||||
)
|
)
|
||||||
const coreVersion = String(systemManifest.compatibility?.verified ?? systemManifest.compatibility?.minimum ?? "")
|
const coreVersion = String(systemManifest.compatibility?.verified ?? systemManifest.compatibility?.minimum ?? "")
|
||||||
const basePackDefinitions = PACK_DEFINITIONS.map((pack) => ({
|
const basePackDefinitions = CONTENT_PACK_DEFINITIONS.map((pack) => ({
|
||||||
...pack,
|
...pack,
|
||||||
outputFolder: `base-${pack.outputFolder}`,
|
outputFolder: `base-${pack.outputFolder}`,
|
||||||
}))
|
}))
|
||||||
|
const contentPackNames = new Set(CONTENT_PACK_DEFINITIONS.map((pack) => pack.outputFolder))
|
||||||
|
|
||||||
function setDeepValue(target, propertyPath, value) {
|
function setDeepValue(target, propertyPath, value) {
|
||||||
const segments = String(propertyPath || "").split(".").filter(Boolean)
|
const segments = String(propertyPath || "").split(".").filter(Boolean)
|
||||||
@@ -142,6 +143,11 @@ function ensureTargetModuleScaffold() {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
packs: (systemManifest.packs ?? []).map((pack) => ({
|
packs: (systemManifest.packs ?? []).map((pack) => ({
|
||||||
|
// The base content module only mirrors content packs, not system journals or utility packs.
|
||||||
|
...pack,
|
||||||
|
}))
|
||||||
|
.filter((pack) => contentPackNames.has(pack.name))
|
||||||
|
.map((pack) => ({
|
||||||
...pack,
|
...pack,
|
||||||
name: `base-${pack.name}`,
|
name: `base-${pack.name}`,
|
||||||
path: `packs/base-${pack.name}`,
|
path: `packs/base-${pack.name}`,
|
||||||
@@ -201,7 +207,7 @@ pruneStalePackDirectories(targetPacksRoot, basePackDefinitions)
|
|||||||
await buildPacks({
|
await buildPacks({
|
||||||
sourceRoot: systemSourceRoot,
|
sourceRoot: systemSourceRoot,
|
||||||
outputRoot: path.join(systemRoot, "packs"),
|
outputRoot: path.join(systemRoot, "packs"),
|
||||||
packDefinitions: PACK_DEFINITIONS,
|
packDefinitions: SYSTEM_PACK_DEFINITIONS,
|
||||||
documentSystemId: systemManifest.id,
|
documentSystemId: systemManifest.id,
|
||||||
documentSystemVersion: systemPackage.version,
|
documentSystemVersion: systemPackage.version,
|
||||||
coreVersion,
|
coreVersion,
|
||||||
|
|||||||
@@ -235,6 +235,18 @@
|
|||||||
"PLAYER": "OBSERVER",
|
"PLAYER": "OBSERVER",
|
||||||
"ASSISTANT": "OWNER"
|
"ASSISTANT": "OWNER"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "JournalEntry",
|
||||||
|
"label": "Aide du système",
|
||||||
|
"name": "aide-systeme",
|
||||||
|
"path": "packs/aide-systeme",
|
||||||
|
"system": "fvtt-les-oublies",
|
||||||
|
"flags": {},
|
||||||
|
"ownership": {
|
||||||
|
"PLAYER": "OBSERVER",
|
||||||
|
"ASSISTANT": "OWNER"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packFolders": [
|
"packFolders": [
|
||||||
@@ -250,7 +262,8 @@
|
|||||||
"races",
|
"races",
|
||||||
"tribus",
|
"tribus",
|
||||||
"metiers",
|
"metiers",
|
||||||
"sortileges"
|
"sortileges",
|
||||||
|
"aide-systeme"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||