Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Folder-based move tree #882

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import type {
} from '@league-of-foundry-developers/foundry-vtt-types/src/types/helperTypes'
import ActorConfig from './module/actor/config'
import ItemConfig from './module/item/config'
import { IronFolder } from './module/folder/iron-folder'

declare global {
interface LenientGlobalVariableTypes {
Expand Down Expand Up @@ -78,8 +79,10 @@ Hooks.once('init', async () => {
mergeObject(CONFIG.Actor, ActorConfig)
mergeObject(CONFIG.Item, ItemConfig)

CONFIG.Item.compendiumIndexFields.push('system.dfid')
// Define custom Entity classes

CONFIG.Folder.documentClass = IronFolder
CONFIG.JournalEntry.documentClass = IronswornJournalEntry
CONFIG.JournalEntryPage.documentClass = IronswornJournalPage

Expand Down
29 changes: 19 additions & 10 deletions src/module/dataforged/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,13 @@ export async function importFromDataforged() {
})
// @ts-expect-error outdated typing
if (pack.folders.size > 0)
// @ts-expect-error outdated typing
await Folder.deleteDocuments(Array.from(pack.folders.keys()), {
pack: key
})
await getDocumentClass('Folder').deleteDocuments(
// @ts-expect-error outdated typing
Array.from(pack.folders.keys()),
{
pack: key
}
)
}

await Promise.all([
Expand Down Expand Up @@ -174,7 +177,7 @@ function movesForCategories(

async function processISMoves() {
const pack = 'foundry-ironsworn.ironswornmoves'
await Folder.createDocuments(
await getDocumentClass('Folder').createDocuments(
ISMoveCategories.map((moveCategory) => getMoveFolderData(moveCategory)),
{ pack, keepId: true }
)
Expand All @@ -186,7 +189,7 @@ async function processISMoves() {
}
async function processSFMoves() {
const pack = 'foundry-ironsworn.starforgedmoves'
await Folder.createDocuments(
await getDocumentClass('Folder').createDocuments(
SFMoveCategories.map((moveCategory) => getMoveFolderData(moveCategory)),
{ pack, keepId: true }
)
Expand Down Expand Up @@ -282,7 +285,7 @@ function assetsForTypes(types: IAssetType[]) {

async function processSFAssets() {
const pack = 'foundry-ironsworn.starforgedassets'
await Folder.createDocuments(
await getDocumentClass('Folder').createDocuments(
SFAssetTypes.map((assetType) => getAssetFolderData(assetType)),
{ pack, keepId: true }
)
Expand All @@ -295,7 +298,7 @@ async function processSFAssets() {

async function processISAssets() {
const pack = 'foundry-ironsworn.ironswornassets'
await Folder.createDocuments(
await getDocumentClass('Folder').createDocuments(
ISAssetTypes.map((assetType) => getAssetFolderData(assetType)),
{ pack, keepId: true }
)
Expand Down Expand Up @@ -383,7 +386,10 @@ async function processSFOracles() {
for (const category of SFOracleCategories) {
await processOracleCategory(category, toCreate)
}
await Folder.createDocuments(toCreate.Folder, { pack, keepId: true })
await getDocumentClass('Folder').createDocuments(toCreate.Folder, {
pack,
keepId: true
})
await OracleTable.createDocuments(toCreate.RollTable, {
pack,
keepId: true
Expand All @@ -401,7 +407,10 @@ async function processISOracles() {
for (const category of ISOracleCategories) {
await processOracleCategory(category, toCreate)
}
await Folder.createDocuments(toCreate.Folder, { pack, keepId: true })
await getDocumentClass('Folder').createDocuments(toCreate.Folder, {
pack,
keepId: true
})
await OracleTable.createDocuments(toCreate.RollTable, {
pack,
keepId: true
Expand Down
122 changes: 0 additions & 122 deletions src/module/features/custommoves.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,3 @@
import type { IMove, IMoveCategory } from 'dataforged'
import { ISMoveCategories, SFMoveCategories } from '../dataforged/data'
import type { IronswornItem } from '../item/item'
import { cachedDocumentsForPack } from './pack-cache'

export interface MoveCategory {
color: string | null
displayName: string
moves: Move[]
dataforgedCategory?: IMoveCategory
}

export interface Move {
color: string | null
displayName: string
moveItem: () => IronswornItem<'sfmove'>
dataforgedMove?: IMove
}

// For some reason, rollupJs mangles this

async function createMoveTree(
compendiumName: string,
categories: IMoveCategory[]
): Promise<MoveCategory[]> {
const ret = [] as MoveCategory[]

// Make sure compendium is loaded
const compendiumMoves = await cachedDocumentsForPack(compendiumName)

// Construct the base tree
for (const category of categories) {
ret.push(
walkCategory(category, compendiumMoves as Array<IronswornItem<'sfmove'>>)
)
}

// Add custom moves from well-known folder
await augmentWithFolderContents(ret)

// Fire the hook and allow extensions to modify the list
await Hooks.call('ironswornMoves', ret)

return ret
}

export async function createIronswornMoveTree(): Promise<MoveCategory[]> {
return await createMoveTree(
'foundry-ironsworn.ironswornmoves',
ISMoveCategories
)
}

export async function createStarforgedMoveTree(): Promise<MoveCategory[]> {
return await createMoveTree(
'foundry-ironsworn.starforgedmoves',
SFMoveCategories
)
}

// TODO dataforged has a key for move colours...., but they appear to have changed significantly since the last time i updated them! they'll be fixed for 2.0, but until then, here's a workaround.
export enum MoveCategoryColor {
Adventure = '#206087',
Expand All @@ -83,65 +23,3 @@ export enum MoveCategoryColor {
Threat = '#3F8C8A',
Threshold = '#1D1D1B'
}

function walkCategory(
category: IMoveCategory,
compendiumMoves: Array<IronswornItem<'sfmove'>>
): MoveCategory {
const newCategory: MoveCategory = {
// FIXME: revert to pulling directly from DF when it's fixed in 2.0
color: MoveCategoryColor[category.Name] ?? null,
displayName: game.i18n.localize(`IRONSWORN.MOVES.${category.Name}`),
dataforgedCategory: category,
moves: [] as Move[]
}

for (const move of category.Moves) {
const moveItem = compendiumMoves?.find((x) => x.system.dfid === move.$id)
if (moveItem != null) {
newCategory.moves.push({
color: category.Display.Color ?? null,
dataforgedMove: move,
displayName:
// TODO: ideally, alternate versions wouldn't have the same move at all! they'd be selectable within the move display. maybe a radio select, or expandable into its own tree? or displayed as a second text?
// 'alternate version' gets too long for a single line in many cases, so it gets trimmed
// move.Display.Title.replace(/alternate version/i, 'alt') ??
moveItem.name as string,
moveItem: () => moveItem
})
} else {
console.warn(`Couldn't find item for move ${move.$id}`)
}
}

return newCategory
}

async function augmentWithFolderContents(categories: MoveCategory[]) {
const name = game.i18n.localize('IRONSWORN.MOVES.Custom')
const folder = (game.items?.directory as any)?.folders.find(
(x) => x.name === name
) as Folder | undefined
if (folder == null || folder.contents.length == 0) return

// @ts-expect-error Exists only in FVTT v10 API
const color = (folder.color ?? null) as string | null

const customMoves = [] as Move[]
for (const moveItem of folder.contents) {
if (moveItem.documentName !== 'Item' || !moveItem.assert('sfmove')) continue
customMoves.push({
color,
displayName: moveItem.name ?? '(move)',
moveItem: () => moveItem
})
}

if (customMoves.length > 0) {
categories.push({
color,
displayName: name,
moves: customMoves
})
}
}
2 changes: 1 addition & 1 deletion src/module/features/sceneButtons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async function ensureFolder(...path: string[]): Promise<Folder | undefined> {
})
continue
}
parentFolder = await Folder.create({
parentFolder = await getDocumentClass('Folder').create({
type: 'Actor',
name,
parent: parentFolder?.id
Expand Down
26 changes: 26 additions & 0 deletions src/module/folder/iron-folder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { CONST } from '@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/module.mjs'
import type { ConfiguredDocumentClassForName } from '@league-of-foundry-developers/foundry-vtt-types/src/types/helperTypes'

type FolderDocumentClass =
ConfiguredDocumentClassForName<CONST.FOLDER_DOCUMENT_TYPES>
type FolderDocument = InstanceType<FolderDocumentClass>

/** Extends FVTT's Folder document with system-specific functionality. */
export class IronFolder<
DocType extends FolderDocument = FolderDocument
> extends Folder {}

export interface IronFolder<DocType extends FolderDocument = FolderDocument>
extends Folder {
type: DocType['documentName']
folder: this | null
children: this[]
get contents(): Array<
InstanceType<ConfiguredDocumentClassForName<this['type']>> & DocType
>
get ancestors(): this[]
getSubfolders(recursive?: boolean): this[]
getParentFolders(): this[]
}

export namespace IronFolder {}
106 changes: 106 additions & 0 deletions src/module/folder/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import type { FolderData } from '@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/module.mjs'
import type { FolderMetadata } from '@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/documents.mjs/baseFolder'
import type { ConfiguredDocumentClassForName } from '@league-of-foundry-developers/foundry-vtt-types/src/types/helperTypes'

declare global {
export interface FlagConfig {
Folder: {
'foundry-ironsworn'?: {
/** The Dataforged ID associated with this folder. */
dfid?: string
}
}
}

// Augmentations to fix stuff missing from LoFD types
export namespace foundry {
export namespace documents {
export class BaseFolder extends Document<
data.FolderData,
BaseFolder,
FolderMetadata
> {}
}
}

// fixes numerous missing properties caused by LoFD types having inheritance chains inconsistent with FVTT's source code
export interface Folder
extends Omit<
FolderData,
'update' | 'toObject' | 'toJSON' | 'type' | 'parent' | 'name'
> {
sort: number

/** @deprecated Since v10. Use `folder` instead. */
parent: this['folder']
/** The parent Folder which contains this Folder */
folder: InstanceType<ConfiguredDocumentClassForName<'Folder'>> | null
type: this['data']['type']

/**
* An array of other Folders which are the displayed children of this one. This differs from the results of
* {@link Folder.getSubfolders} because reports the subset of child folders which are displayed to the current User
* in the UI.
*/
children: Array<InstanceType<ConfiguredDocumentClassForName<'Folder'>>>

/**
* Return the list of ancestors of this folder, starting with the parent.
*/
get ancestors(): Array<
InstanceType<ConfiguredDocumentClassForName<'Folder'>>
>

/**
* Export all Documents contained in this Folder to a given Compendium pack.
* Optionally update existing Documents within the Pack by name, otherwise append all new entries.
* @param pack - A Compendium pack to which the documents will be exported
* @param options - Additional options which customize how content is exported. See {@link ClientDocumentMixin#toCompendium}
* @param {boolean} [options.updateByName=false] Update existing entries in the Compendium pack, matching by name
* @param {boolean} [options.keepId=false] Retain the original _id attribute when updating an entity
* @param {boolean} [options.keepFolders=false] Retain the existing Folder structure
* @param {string} [options.folder] A target folder id to which the documents will be exported
* @returns The updated Compendium Collection instance
*/
exportToCompendium<T extends this['type']>(
pack: CompendiumCollection<CompendiumCollection.Metadata & { type: T }>,
options?: {
updateByName?: boolean
keepId?: boolean
keepFolders?: boolean
}
): Promise<
CompendiumCollection<CompendiumCollection.Metadata & { type: T }>
>

/**
* Provide a dialog form that allows for exporting the contents of a Folder into an eligible Compendium pack.
* @param pack - A pack ID to set as the default choice in the select input
* @param options - Additional options passed to the Dialog.prompt method
* @returns A Promise which resolves or rejects once the dialog has been submitted or closed
*/
exportDialog(
pack: string,
options: Parameters<(typeof Dialog)['prompt']>[0]
): Promise<void>

/**
* Get the Folder documents which are sub-folders of the current folder, either direct children or recursively.
* @param recursive Identify child folders recursively, if false only direct children are returned (default: `false`)
* @returns An array of Folder documents which are subfolders of this one
*/
getSubfolders(
recursive?: boolean
): Array<InstanceType<ConfiguredDocumentClassForName<'Folder'>>>

/**
* Get the Folder documents which are parent folders of the current folder or any if its parents.
* @returns An array of Folder documents which are parent folders of this one
*/
getParentFolders(): Array<
InstanceType<ConfiguredDocumentClassForName<'Folder'>>
>
}
}

export {}
Loading
Loading