Skip to content

Commit

Permalink
Playset support (#452)
Browse files Browse the repository at this point in the history
  • Loading branch information
cwegrzyn committed Aug 9, 2024
1 parent f7a14ef commit bc0c842
Show file tree
Hide file tree
Showing 90 changed files with 4,349 additions and 1,361 deletions.
2 changes: 1 addition & 1 deletion data/starforged.supplement.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"datasworn_version": "0.1.0",
"ruleset": "starforged",
"title": "Iron Vault support for Ironsworn: Starforged",
"description": "Collection of utility oracles for use with Starforged",
"description": "Collection of utility oracles and assets for use with Starforged",
"authors": [
{
"name": "Iron Vault Dev Team"
Expand Down
2 changes: 1 addition & 1 deletion data/sundered-isles.supplement.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"license": "MIT",
"url": "https://ironvault.quest",
"datasworn_version": "0.1.0",
"ruleset": "sundered_isles",
"ruleset": "starforged",
"oracles": {
"templates": {
"_id": "oracle_collection:sundered_isles_supp/templates",
Expand Down
2 changes: 1 addition & 1 deletion data/sundered-isles.supplement.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ date: "2024-07-16"
license: "MIT"
url: "https://ironvault.quest"
datasworn_version: 0.1.0
ruleset: sundered_isles
ruleset: starforged
oracles:
templates:
_id: oracle_collection:sundered_isles_supp/templates
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@types/electron": "npm:@ophidian/electron-types@^24.3.1",
"@types/jest": "^29.5.12",
"@types/js-yaml": "^4.0.9",
"@types/lodash.ismatch": "^4.4.9",
"@types/lodash.merge": "^4.6.9",
"@types/node": "^20.12.12",
"@types/obsidian-typings": "npm:obsidian-typings@^1.1.6",
Expand All @@ -61,6 +62,7 @@
"js-yaml": "^4.1.0",
"kdljs": "^0.2.0",
"lit-html": "^3.1.3",
"lodash.ismatch": "^4.4.0",
"lodash.merge": "^4.6.2",
"loglevel": "^1.9.1",
"minisearch": "^6.3.0",
Expand Down
18 changes: 18 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 20 additions & 1 deletion src/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { syntaxTree } from "@codemirror/language";
import { CampaignDataContext } from "campaigns/context";
import { IDataContext } from "datastore/data-context";
import { rootLogger, setLogLevel } from "logger";
import loglevel from "loglevel";
import { App, getLinkpath, parseLinktext } from "obsidian";
import { OracleRoller } from "oracles/roller";
import { ProgressIndex } from "tracks/indexer";
import { CharacterTracker } from "./character-tracker";
import { Datastore } from "./datastore";
Expand All @@ -27,8 +30,24 @@ export class IronVaultAPI {
return this.plugin.progressTracks;
}

get globalDataContext(): IDataContext {
return this.plugin.datastore.dataContext;
}

/** Active campaign context */
get activeCampaignContext(): CampaignDataContext | undefined {
return this.plugin.campaignManager.lastActiveCampaignContext();
}

/** A campaign data context if available, otherwise global. */
get activeDataContext(): IDataContext {
return this.activeCampaignContext ?? this.globalDataContext;
}

public async roll(oracle: string): Promise<RollWrapper> {
return this.datastore.roller.roll(oracle);
return new OracleRoller(this.plugin, this.activeDataContext.oracles).roll(
oracle,
);
}

public stripLinks(input: string): string {
Expand Down
76 changes: 44 additions & 32 deletions src/assets/asset-block.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,73 @@
import { Asset } from "@datasworn/core/dist/Datasworn";
import { html, render } from "lit-html";

import { CampaignDataContext } from "campaigns/context";
import IronVaultPlugin from "index";
import { MarkdownRenderChild } from "obsidian";
import { FileBasedCampaignWatch } from "sidebar/sidebar-block";
import renderAssetCard from "./asset-card";

export default function registerAssetBlock(plugin: IronVaultPlugin) {
plugin.registerMarkdownCodeBlockProcessor(
"iron-vault-asset",
async (source, el: AssetBlockContainerEl, _ctx) => {
// We can't render blocks until datastore is ready.
await plugin.datastore.waitForReady;
if (!el.assetRenderer) {
const asset = AssetBlockRenderer.getAsset(plugin, source);
if (!asset) {
render(html`<p>No such asset: ${source}</p>`, el);
return;
}
el.assetRenderer = new AssetBlockRenderer(el, plugin, asset);
}
await el.assetRenderer.render();
(source, el: HTMLElement, ctx) => {
ctx.addChild(new AssetBlockRenderer(el, plugin, source, ctx.sourcePath));
},
);
}

interface AssetBlockContainerEl extends HTMLElement {
assetRenderer?: AssetBlockRenderer;
}

class AssetBlockRenderer {
contentEl: HTMLElement;
plugin: IronVaultPlugin;
asset: Asset;
class AssetBlockRenderer extends MarkdownRenderChild {
campaignSource: FileBasedCampaignWatch;

constructor(contentEl: HTMLElement, plugin: IronVaultPlugin, asset: Asset) {
this.contentEl = contentEl;
this.plugin = plugin;
this.asset = asset;
constructor(
contentEl: HTMLElement,
readonly plugin: IronVaultPlugin,
readonly source: string,
sourcePath: string,
) {
super(contentEl);
this.campaignSource = this.addChild(
new FileBasedCampaignWatch(
plugin.app.vault,
plugin.campaignManager,
sourcePath,
).onUpdate(() => this.render()),
);
}

static getAsset(plugin: IronVaultPlugin, source: string) {
const trimmed = source.trim().toLowerCase();
getAsset(dataContext: CampaignDataContext) {
const trimmed = this.source.trim().toLowerCase();
return (
plugin.datastore.assets.get(trimmed) ||
[...plugin.datastore.assets.values()].find(
dataContext.assets.get(trimmed) ||
[...dataContext.assets.values()].find(
(a) => a.name.toLowerCase() === trimmed,
)
);
}

async render() {
const dataContext = this.campaignSource.campaignContext;
if (!dataContext) {
render(
html`<article class="error">
Asset block may only be used within a campaign folder.
</article>`,
this.containerEl,
);
return;
}
const asset = this.getAsset(dataContext);
if (!asset) {
render(html`<p>No such asset: ${this.source}</p>`, this.containerEl);
return;
}
render(
renderAssetCard(this.plugin, {
id: this.asset._id,
renderAssetCard(this.plugin, dataContext, {
id: asset._id,
abilities: [true, false, false],
options: {},
controls: {},
}),
this.contentEl,
this.containerEl,
);
}
}
4 changes: 3 additions & 1 deletion src/assets/asset-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { TemplateResult, html } from "lit-html";
import { map } from "lit-html/directives/map.js";
import { range } from "lit-html/directives/range.js";

import { IDataContext } from "datastore/data-context";
import { produce } from "immer";
import IronVaultPlugin from "index";
import { repeat } from "lit-html/directives/repeat.js";
Expand All @@ -36,12 +37,13 @@ export function makeDefaultSheetAsset(asset: Asset) {

export default function renderAssetCard(
plugin: IronVaultPlugin,
dataContext: IDataContext,
sheetAsset: IronVaultSheetAssetSchema,
updateAsset?: (asset: Asset) => void,
) {
let asset;
try {
asset = integratedAssetLens(plugin.datastore).get(sheetAsset);
asset = integratedAssetLens(dataContext).get(sheetAsset);
} catch (e) {
// @ts-expect-error it's just an error. Let it crash if there's no message.
return html`<article class="iron-vault-asset-card">Error: ${e.message}</a>`;
Expand Down
21 changes: 13 additions & 8 deletions src/assets/asset-modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import { html, render } from "lit-html";
import { App, Modal } from "obsidian";

import { Asset } from "@datasworn/core/dist/Datasworn";
import { addAssetToCharacter } from "characters/commands";
import { IDataContext } from "datastore/data-context";
import IronVaultPlugin from "index";
import renderAssetCard, { makeDefaultSheetAsset } from "./asset-card";
import { addAssetToCharacter } from "characters/commands";

export class AssetModal extends Modal {
plugin: IronVaultPlugin;
asset: Asset;

constructor(app: App, plugin: IronVaultPlugin, asset: Asset) {
constructor(
app: App,
readonly plugin: IronVaultPlugin,
readonly dataContext: IDataContext,
readonly asset: Asset,
) {
super(app);
this.plugin = plugin;
this.asset = asset;
}

openAsset(asset: Asset) {
Expand All @@ -24,7 +25,11 @@ export class AssetModal extends Modal {
contentEl.toggleClass("iron-vault-modal", true);
render(
html`
${renderAssetCard(this.plugin, makeDefaultSheetAsset(asset))}
${renderAssetCard(
this.plugin,
this.dataContext,
makeDefaultSheetAsset(asset),
)}
<button
type="button"
@click=${() => {
Expand Down
8 changes: 4 additions & 4 deletions src/assets/asset-picker-modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export class AssetPickerModal extends Modal {
</button>
${renderAssetCard(
this.plugin,
this.actionContext,
makeDefaultSheetAsset(asset),
)}
</div>
Expand All @@ -155,10 +156,10 @@ export class AssetPickerModal extends Modal {
> = {};
const results = filter
? this.searchIdx.search(filter)
: [...this.plugin.datastore.assets.values()].map((m) => ({ id: m._id }));
: [...this.actionContext.assets.values()].map((m) => ({ id: m._id }));
let total = 0;
for (const res of results) {
const asset = this.plugin.datastore.assets.get(res.id)!;
const asset = this.actionContext.assets.get(res.id)!;
if (!asset) {
console.error("couldn't find asset for", res);
continue;
Expand Down Expand Up @@ -192,8 +193,7 @@ export class AssetPickerModal extends Modal {
boost: { name: 2 },
},
});
// TODO: use the current context
idx.addAll([...this.plugin.datastore.assets.values()]);
idx.addAll([...this.actionContext.assets.values()]);
return idx;
}
}
Loading

0 comments on commit bc0c842

Please sign in to comment.