From 3f029d8af442c6ba618b70cb7ec1d3355a607848 Mon Sep 17 00:00:00 2001 From: Luke Carr Date: Tue, 30 Apr 2024 00:28:30 +0100 Subject: [PATCH] docs: migrated to new docs site --- docs/.gitignore | 178 +++++++++++++++++- docs/.vitepress/config.mts | 70 +++++++ docs/.vitepress/theme/index.ts | 17 ++ docs/.vitepress/theme/style.css | 92 +++++++++ docs/README.md | 15 ++ docs/book.toml | 6 - docs/bun.lockb | Bin 0 -> 49853 bytes docs/package.json | 15 ++ docs/src/SUMMARY.md | 24 --- docs/src/concepts/evaluator.md | 26 ++- docs/src/concepts/rule.md | 4 +- docs/src/concepts/ruleset.md | 8 +- docs/src/index.md | 68 +++++++ docs/src/inspiration.md | 4 +- docs/src/introduction.md | 40 ---- docs/src/overview.md | 17 +- docs/src/performance.md | 10 +- docs/src/public/hero.svg | 10 + docs/src/public/mimir-dark.svg | 26 +++ docs/src/public/mimir-light.svg | 26 +++ docs/src/public/powerful.svg | 1 + docs/src/quick-start.md | 20 ++ .../repeated-evaluations.md | 0 docs/src/{use-cases => recipes}/tips.md | 24 ++- docs/src/{changelog.md => release-notes.md} | 2 +- docs/src/serialisation.md | 16 ++ docs/src/serialization.md | 14 -- docs/src/tutorial.md | 22 --- docs/tsconfig.json | 27 +++ 29 files changed, 646 insertions(+), 136 deletions(-) create mode 100644 docs/.vitepress/config.mts create mode 100644 docs/.vitepress/theme/index.ts create mode 100644 docs/.vitepress/theme/style.css create mode 100644 docs/README.md delete mode 100644 docs/book.toml create mode 100755 docs/bun.lockb create mode 100644 docs/package.json delete mode 100644 docs/src/SUMMARY.md create mode 100644 docs/src/index.md delete mode 100644 docs/src/introduction.md create mode 100644 docs/src/public/hero.svg create mode 100644 docs/src/public/mimir-dark.svg create mode 100644 docs/src/public/mimir-light.svg create mode 100644 docs/src/public/powerful.svg create mode 100644 docs/src/quick-start.md rename docs/src/{use-cases => recipes}/repeated-evaluations.md (100%) rename docs/src/{use-cases => recipes}/tips.md (77%) rename docs/src/{changelog.md => release-notes.md} (99%) create mode 100644 docs/src/serialisation.md delete mode 100644 docs/src/serialization.md delete mode 100644 docs/src/tutorial.md create mode 100644 docs/tsconfig.json diff --git a/docs/.gitignore b/docs/.gitignore index 7585238..2aa00cf 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1 +1,177 @@ -book +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +.vitepress/cache \ No newline at end of file diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts new file mode 100644 index 0000000..19d5d7d --- /dev/null +++ b/docs/.vitepress/config.mts @@ -0,0 +1,70 @@ +import { defineConfig } from 'vitepress' + +export default defineConfig({ + title: "Mímir", + description: "Contextual query engine for dynamic video games.", + srcDir: "src", + + themeConfig: { + logo: { + light: "/mimir-light.svg", + dark: "/mimir-dark.svg", + }, + + siteTitle: false, + + footer: { + message: "Made with ❤️ in Exeter", + copyright: "Copyright © 2024 Subtale" + }, + + nav: [ + { text: 'Home', link: '/' }, + { text: 'Guide', link: '/overview' }, + { text: 'Release notes', link: '/release-notes' }, + { text: 'API Reference', link: 'https://docs.rs/subtale-mimir' }, + ], + + sidebar: [ + { + text: 'Introduction', + items: [ + { text: 'High-level overview', link: '/overview' }, + { text: 'Quick start', link: '/quick-start' }, + { text: 'Inspiration', link: '/inspiration' }, + ] + }, + { + text: 'Concepts', + items: [ + { text: 'Evaluator', link: '/concepts/evaluator' }, + { text: 'Query', link: '/concepts/query' }, + { text: 'Rule', link: '/concepts/rule' }, + { text: 'Ruleset', link: '/concepts/ruleset' }, + ] + }, + { + text: 'Recipes', + items: [ + { text: 'Loading screen tips', link: '/recipes/tips' }, + { text: 'Repeated evaluations', link: '/recipes/repeated-evaluations' }, + ] + }, + { + text: 'Miscellaneous', + items: [ + { text: 'Performance', link: '/performance' }, + { text: 'Serialisation', link: '/serialisation' }, + ] + } + ], + + socialLinks: [ + { icon: 'github', link: 'https://github.com/subtalegames/mimir' }, + { icon: 'x', link: 'https://x.com/subtalegames' }, + { icon: 'instagram', link: 'https://instagram.com/subtalegames' }, + { icon: 'youtube', link: 'https://youtube.com/@subtalegames' }, + { icon: 'discord', link: 'https://discord.subtale.com' }, + ] + } +}) diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..def4cfc --- /dev/null +++ b/docs/.vitepress/theme/index.ts @@ -0,0 +1,17 @@ +// https://vitepress.dev/guide/custom-theme +import { h } from 'vue' +import type { Theme } from 'vitepress' +import DefaultTheme from 'vitepress/theme' +import './style.css' + +export default { + extends: DefaultTheme, + Layout: () => { + return h(DefaultTheme.Layout, null, { + // https://vitepress.dev/guide/extending-default-theme#layout-slots + }) + }, + enhanceApp({ app, router, siteData }) { + // ... + } +} satisfies Theme diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css new file mode 100644 index 0000000..03618e5 --- /dev/null +++ b/docs/.vitepress/theme/style.css @@ -0,0 +1,92 @@ +:root { + --vp-c-default-1: var(--vp-c-gray-1); + --vp-c-default-2: var(--vp-c-gray-2); + --vp-c-default-3: var(--vp-c-gray-3); + --vp-c-default-soft: var(--vp-c-gray-soft); + + --vp-c-brand-1: #5686f3; + --vp-c-brand-2: #5686f3; + --vp-c-brand-3: #2060d3; + --vp-c-brand-soft: var(--vp-c-indigo-soft); + + --vp-c-tip-1: var(--vp-c-brand-1); + --vp-c-tip-2: var(--vp-c-brand-2); + --vp-c-tip-3: var(--vp-c-brand-3); + --vp-c-tip-soft: var(--vp-c-brand-soft); + + --vp-c-warning-1: var(--vp-c-yellow-1); + --vp-c-warning-2: var(--vp-c-yellow-2); + --vp-c-warning-3: var(--vp-c-yellow-3); + --vp-c-warning-soft: var(--vp-c-yellow-soft); + + --vp-c-danger-1: var(--vp-c-red-1); + --vp-c-danger-2: var(--vp-c-red-2); + --vp-c-danger-3: var(--vp-c-red-3); + --vp-c-danger-soft: var(--vp-c-red-soft); + + --vp-button-brand-border: transparent; + --vp-button-brand-text: var(--vp-c-white); + --vp-button-brand-bg: var(--vp-c-brand-3); + --vp-button-brand-hover-border: transparent; + --vp-button-brand-hover-text: var(--vp-c-white); + --vp-button-brand-hover-bg: var(--vp-c-brand-2); + --vp-button-brand-active-border: transparent; + --vp-button-brand-active-text: var(--vp-c-white); + --vp-button-brand-active-bg: #cadff4; + + --vp-home-hero-name-color: transparent; + --vp-home-hero-name-background: -webkit-linear-gradient( + 120deg, + #2060d3 30%, + #5686f3 + ); + + --vp-home-hero-image-background-image: linear-gradient( + -45deg, + #5686f3 50%, + #cadff4 50% + ); + --vp-home-hero-image-filter: blur(44px); + + --vp-custom-block-tip-border: transparent; + --vp-custom-block-tip-text: var(--vp-c-text-1); + --vp-custom-block-tip-bg: var(--vp-c-brand-soft); + --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft); + --vp-code-color: #090242; +} + +@media (min-width: 640px) { + :root { + --vp-home-hero-image-filter: blur(56px); + } +} + +@media (min-width: 960px) { + :root { + --vp-home-hero-image-filter: blur(68px); + } +} + +:root.dark { + --vp-home-hero-image-background-image: linear-gradient( + -45deg, + #0b3c93, + #051f4f + ); + + --vp-code-color: #f0f0f1; +} + +.DocSearch { + --docsearch-primary-color: var(--vp-c-brand-1) !important; +} + +a.title > span { + font-size: 23px; + margin-top: 7px; + color: #090242; +} + +.dark a.title > span { + color: #ffffff; +} \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..66130bb --- /dev/null +++ b/docs/README.md @@ -0,0 +1,15 @@ +# docs + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.ts +``` + +This project was created using `bun init` in bun v1.0.33. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/docs/book.toml b/docs/book.toml deleted file mode 100644 index 2448a70..0000000 --- a/docs/book.toml +++ /dev/null @@ -1,6 +0,0 @@ -[book] -authors = ["Luke Carr"] -language = "en" -multilingual = false -src = "src" -title = "Mímir" diff --git a/docs/bun.lockb b/docs/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..9d48b6e8f0863d1ba0592d79ac7373db459cb074 GIT binary patch literal 49853 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 literal 0 HcmV?d00001 diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..4c68b79 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,15 @@ +{ + "private": true, + "devDependencies": { + "@types/bun": "latest", + "vitepress": "^1.1.4" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "scripts": { + "dev": "vitepress dev", + "build": "vitepress build", + "preview": "vitepress preview" + } +} \ No newline at end of file diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md deleted file mode 100644 index 4ff927c..0000000 --- a/docs/src/SUMMARY.md +++ /dev/null @@ -1,24 +0,0 @@ -# Introduction - -[Introduction](./introduction.md) -[High-level overview](./overview.md) -[Inspiration](./inspiration.md) -[Tutorial](./tutorial.md) -[Changelog](./changelog.md) - -# Concepts - -- [Evaluator](./concepts/evaluator.md) -- [Query](./concepts/query.md) -- [Rule](./concepts/rule.md) -- [Ruleset](./concepts/ruleset.md) - -# Use cases - -- [Loading screen tips](./use-cases/tips.md) -- [Repeated evaluations](./use-cases/repeated-evaluations.md) - -# Miscellaneous - -- [Performance](./performance.md) -- [Serialization](./serialization.md) diff --git a/docs/src/concepts/evaluator.md b/docs/src/concepts/evaluator.md index 6f9be76..d165dd4 100644 --- a/docs/src/concepts/evaluator.md +++ b/docs/src/concepts/evaluator.md @@ -16,16 +16,20 @@ You can choose to create your own implementation of the trait, or use the provid In the real world, an evaluator represents a condition that must be true for a contextual event to take place. However, events will typically have many evaluators that need to evaluate to true, not just one! -> ℹ️ An NPC might query Mímir to ensure that they're only commenting on another NPC's behaviour if they've not exhibited the same behaviour previously (to avoid being hypocritical). +::: tip +An NPC might query Mímir to ensure that they're only commenting on another NPC's behaviour if they've not exhibited the same behaviour previously (to avoid being hypocritical). +::: ## FloatEvaluator -> ⚠️ To use the pre-made `FloatEvaluator` implementation, you must enable the `float` feature in your project's `Cargo.toml`: -> -> ```toml -> [dependencies] -> subtale-mimir = { version = "0.5.0", features = ["float"] } -> ``` +::: warning +To use the pre-made `FloatEvaluator` implementation, you must enable the `float` feature in your project's `Cargo.toml`: + +```toml +[dependencies] +subtale-mimir = { version = "0.5.0", features = ["float"] } +``` +::: The `FloatEvaluator` is a built-in implementation of the `Evaluator` trait, allowing you to define evaluators that match against floating-point numbers. @@ -41,7 +45,9 @@ enum FloatEvaluator { If you're interested in how we've implemented the `Evaluator` trait for `FloatEvaluator`, check out the [source code on GitHub][float-src]! -> ℹ️ `FloatRangeBound` is an enum that holds a boundary value that can be inclusive (`FloatRangeBound::Inclusive(f64)`) or exclusive (`FloatRangeBound::Exclusive(f64)`). +::: info +`FloatRangeBound` is an enum that holds a boundary value that can be inclusive (`FloatRangeBound::Inclusive(f64)`) or exclusive (`FloatRangeBound::Exclusive(f64)`). +::: ### Helper functions @@ -55,7 +61,9 @@ Several helper functions are exposed to easily instantiate `FloatEvaluator` with | `FloatEvaluator::gte(5.)` | `FloatEvaluator::GreaterThan(FloatRangeBound::Inclusive(5.))` | `x ≥ 5` | | `FloatEvaluator::range(5., 10.)` | `FloatEvaluator::InRange(FloatRangeBound::Inclusive(5.), RangeFloatRangeBoundBound::Exclusive(10.))` | `5 ≤ x < 10` | -> ℹ️ `FloatEvaluator::range` is designed to mimic the functionality of [Python's built-in range function][py-range]. +::: info +`FloatEvaluator::range` is designed to mimic the functionality of [Python's built-in range function][py-range]. +::: ### Floating-point equality diff --git a/docs/src/concepts/rule.md b/docs/src/concepts/rule.md index 82502c0..7eb6ef1 100644 --- a/docs/src/concepts/rule.md +++ b/docs/src/concepts/rule.md @@ -29,7 +29,9 @@ assert!(rule.evaluate(&query)); In the above example, the rule evaluates to true for the supplied query because it's expecting 5 enemies to be killed (`enemies_killed`), and the query confirms the fact that 5 (`2.5 + 1.5 + 1`) have been killed. -> ℹ️ Our generic outcome type (`Outcome`) for the example is just a standard boolean value (`true`). In the real-world, you'd probably use a more complex enum to denote different types of outcome (e.g. dialog, animation). +::: tip +Our generic outcome type (`Outcome`) for the example is just a standard boolean value (`true`). In the real-world, you'd probably use a more complex enum to denote different types of outcome (e.g. dialog, animation). +::: ## Insertion order diff --git a/docs/src/concepts/ruleset.md b/docs/src/concepts/ruleset.md index 20cd9aa..d0b0def 100644 --- a/docs/src/concepts/ruleset.md +++ b/docs/src/concepts/ruleset.md @@ -11,7 +11,9 @@ where } ``` -> ℹ️ Check out the [ruleset storage section](/performance.html#ruleset-storage) on the performance page for further details on how Mímir represents rulesets in Rust to improve performance when evaluating queries against them. +::: tip +Check out the [ruleset storage section](/performance.html#ruleset-storage) on the performance page for further details on how Mímir represents rulesets in Rust to improve performance when evaluating queries against them. +::: ## Evaluation @@ -51,4 +53,6 @@ In the above example, we define a ruleset with two rules. Both rules require tha The first query evaluates to the simpler rule, because the query does not satisfy the doors opened requirement. However, the second query evaluates to the more complex rule because the query *does* satistfy the doors opened requirement. -> ℹ️ In the second query, although the simpler rule is satisfied, Mímir does not evaluate it as true because it's less specific (i.e. contains fewer evaluators). +::: info +In the second query, although the simpler rule is satisfied, Mímir does not evaluate it as true because it's less specific (i.e. contains fewer evaluators). +::: diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..1f1e8e9 --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,68 @@ +--- +layout: home + +hero: + name: "Mímir" + text: "Contextual query engine for dynamic video games." + tagline: "Game logic expressed as queryable rules." + image: + src: /hero.svg + alt: Brain illustration + actions: + - theme: brand + text: Get Started + link: /markdown-examples + - theme: brand + text: API Reference + link: https://docs.rs/subtale-mimir + - theme: alt + text: More Subtale Open Source + link: https://github.com/subtalegames + +features: + - icon: 📋 + title: Rule-based events + details: Compose rules from predicates that trigger outcomes in your game's world. + - icon: ⚡️ + title: Optimised ruleset storage + details: Process groups of rules efficiently, avoiding unnecessary evaluations. + - icon: 🛟 + title: Compile-time safety + details: Catch errors in your game's ruleset at compile-time, not runtime. +--- + +## Quickstart + +Add `subtale-mimir = "0.6"` to your `Cargo.toml` file's `[dependencies]` section, then declare your game's first ruleset: + +```rust +use subtale_mimir::prelude::*; + +fn main() { + let mut rule = Rule::new("You killed 5 enemies!"); + rule.insert("enemies_killed", FloatEvaluator::EqualTo(5.)); + + let mut more_specific_rule = Rule::new("You killed 5 enemies and opened 2 doors!"); + more_specific_rule.insert("enemies_killed", FloatEvaluator::EqualTo(5.)); + more_specific_rule.insert("doors_opened", FloatEvaluator::gte(2.)); + + let ruleset = Ruleset::new(vec![rule, more_specific_rule]); + + let mut query = Query::new(); + query.insert("enemies_killed", 2.5 + 1.5 + 1.); + + assert_eq!( + ruleset.evaluate(&query).first().unwrap().outcome, + "You killed 5 enemies!" + ); + + let mut more_specific_query = Query::new(); + more_specific_query.insert("enemies_killed", 2.5 + 1.5 + 1.); + more_specific_query.insert("doors_opened", 10.); + + assert_eq!( + ruleset.evaluate(&more_specific_query).first().unwrap().outcome, + "You killed 5 enemies and opened 2 doors!" + ); +} +``` diff --git a/docs/src/inspiration.md b/docs/src/inspiration.md index a25719f..ccb29c9 100644 --- a/docs/src/inspiration.md +++ b/docs/src/inspiration.md @@ -9,6 +9,8 @@ Mímir is heavily inspired (both in concept and general architecture) by [Elan R -Fundamentally speaking, Mímir is simply a Rust implementation of Elan's proposed system for dynamic dialog. However, Mímir does offer some differences and/or extensions that cater specifically to games developed internally at Subtale. +Fundamentally speaking, Mímir is simply a Rust implementation of Elan's proposed system for dynamic dialogue. + +However, Mímir does offer some differences and/or extensions that cater specifically to games developed internally at Subtale, as well as expanding in scope to include general purpose rule evaluation (not limited to dialogue). [gdc]: https://www.youtube.com/watch?v=tAbBID3N64A \ No newline at end of file diff --git a/docs/src/introduction.md b/docs/src/introduction.md deleted file mode 100644 index 5fa8a58..0000000 --- a/docs/src/introduction.md +++ /dev/null @@ -1,40 +0,0 @@ -# Introduction - -Mímir is a contextual query engine for video games with dynamic events (e.g. dialog, animations) driven by their current world's state. - -```rs - use subtale_mimir::prelude::*; - - // create a rule requiring that five enemies have been killed - let mut rule = Rule::new("You killed 5 enemies!"); - // Rule<&str, f64, FloatEvaluator, &str> - rule.insert("enemies_killed", FloatEvaluator::EqualTo(5.)); - - // create a more specific rule that also requires at least 2 doors to have been opened - let mut more_specific_rule = Rule::new("You killed 5 enemies and opened 2 doors!"); - more_specific_rule.insert("enemies_killed", FloatEvaluator::EqualTo(5.)); - more_specific_rule.insert("doors_opened", FloatEvaluator::gte(2.)); - - // bundle the rules into a ruleset - let ruleset = Ruleset::new(vec![rule, more_specific_rule]); - - // run a query against the ruleset - let mut query = Query::new(); - // Query<&str, f64> - query.insert("enemies_killed", 2.5 + 1.5 + 1.); - - assert_eq!( - ruleset.evaluate(&query).unwrap().outcome, - "You killed 5 enemies!" - ); - - // run a more specific query against the ruleset - let mut more_specific_query = Query::new(); - more_specific_query.insert("enemies_killed", 2.5 + 1.5 + 1.); - more_specific_query.insert("doors_opened", 10.); - - assert_eq!( - ruleset.evaluate(&more_specific_query).unwrap().outcome, - "You killed 5 enemies and opened 2 doors!" - ); - ``` diff --git a/docs/src/overview.md b/docs/src/overview.md index af96cb6..f9dbba3 100644 --- a/docs/src/overview.md +++ b/docs/src/overview.md @@ -2,16 +2,25 @@ ## Queries -Your game's world is defined as a collection of facts: the player killed x amount of enemies, an NPC has opened y amount of doors, the player is currently near z NPC, etc. +Your game's world is defined as a collection of facts, such as: + +* the player killed x amount of enemies +* an NPC has opened y amount of doors +* the player is currently near z NPC In Mímir, facts are collected together into a map ([`Query`](/concepts/query.html)), where the key is the unique identifier of the fact, and the value is the fact's value. ## Rules and evaluators -Also, your game will (most likey!) have predefined rules that define behaviour that should occur when one or more facts are true. We represent rules as a map ([`Rule`](/concepts/rule.html)), where the key is the unique identifier of the fact, and the value is a predicate ([`Evaluator`](/concepts/evaluator.html)) that is evaluated against the fact's value. +Also, your game will (most likely!) have predefined rules that define behaviour that should occur when one or more facts are true. + +We represent rules as a map ([`Rule`](/concepts/rule.html)), where the key is the unique identifier of the fact, and the value is a predicate ([`Evaluator`](/concepts/evaluator.html)) that is evaluated against the fact's value. ## Rulesets -Finally, rules can be stored together in collections known as rulesets ([`Ruleset`](/concepts/ruleset.html)). Rulesets allow a query to be evaluated against many rules at once: Mímir will always look to match a query against the rule in the ruleset with the most requirements (i.e. more specific). +Finally, rules can be stored together in collections known as rulesets ([`Ruleset`](/concepts/ruleset.html)). + +Rulesets allow a query to be evaluated against many rules at once: Mímir will always look to match a query against the rule in the ruleset with the most requirements (i.e. more specific). -> ℹ️ If multiple rules with the same specificity are matched within a ruleset, one is chosen at random. +::: tip +If multiple rules with the same specificity are matched within a ruleset, one is chosen at random. diff --git a/docs/src/performance.md b/docs/src/performance.md index 351f7fc..36c5a61 100644 --- a/docs/src/performance.md +++ b/docs/src/performance.md @@ -1,4 +1,4 @@ -# Performance (WIP) +# Performance ## Ruleset storage @@ -6,7 +6,9 @@ Because Mímir evaluates rulesets by returning the most specific rule for a give However, this does mean that care should be taken when invoking `ruleset.append(...)` to introduce more rules into a ruleset, as this function also triggers the underlying collection to be sorted again after the new rules are appended. -> ℹ️ In production, we recommend that rulesets are only manipulated during your game's loading state, and then only evaluated during your game's main loop. +::: tip +In production, we recommend that rulesets are only manipulated during your game's loading state, and then only evaluated during your game's main loop. +::: ## Multiple rulesets @@ -14,4 +16,6 @@ Where possible, you should look to divide your game's entire database of rules i For example, you might want to partition your rules into individual rulesets for each level/map/region of your game. Otherwise, you'll be subjecting yourself to an unnecessary performance cost by having Mímir evaluate rules that have no relevance to the game's current state. -> ℹ️ The specific implementation of a system as described above is outside the scope of Mímir. +::: info +The specific implementation of a system as described above is outside the scope of Mímir. +::: diff --git a/docs/src/public/hero.svg b/docs/src/public/hero.svg new file mode 100644 index 0000000..547b004 --- /dev/null +++ b/docs/src/public/hero.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/docs/src/public/mimir-dark.svg b/docs/src/public/mimir-dark.svg new file mode 100644 index 0000000..90da4e8 --- /dev/null +++ b/docs/src/public/mimir-dark.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/src/public/mimir-light.svg b/docs/src/public/mimir-light.svg new file mode 100644 index 0000000..8965d6e --- /dev/null +++ b/docs/src/public/mimir-light.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/src/public/powerful.svg b/docs/src/public/powerful.svg new file mode 100644 index 0000000..f45d122 --- /dev/null +++ b/docs/src/public/powerful.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/src/quick-start.md b/docs/src/quick-start.md new file mode 100644 index 0000000..9c43dbb --- /dev/null +++ b/docs/src/quick-start.md @@ -0,0 +1,20 @@ +# Quick start + +This guide serves as a tutorial for newcomers to Mímir; a hypothetical scenario is established for a game and then an exemplar, step-by-step implementation is provided. + +## Scenario + +You're working on an open-world game: more specifically, there's a non-linear quest tree (i.e. the player is free to explore and start/complete quests as they please). + +You've decided that you'd like your game's dialogue to be more *aware* of what's happened. Specifically, you'd like NPCs to make different remarks depending on what the player has (or hasn't) already done. + +This scenario can be easily achieved with Mímir and, more importantly, is exactly the kind of scenario Mímir was designed for. With this in mind, let's get started! + +## Installation + +Start off by adding Mímir to your project's `Cargo.toml`, including the optional `float` feature (whose relevance will be explained later): + +```toml +[dependencies] +subtale-mimir = { version = "0.6", features = ["float"] } +``` diff --git a/docs/src/use-cases/repeated-evaluations.md b/docs/src/recipes/repeated-evaluations.md similarity index 100% rename from docs/src/use-cases/repeated-evaluations.md rename to docs/src/recipes/repeated-evaluations.md diff --git a/docs/src/use-cases/tips.md b/docs/src/recipes/tips.md similarity index 77% rename from docs/src/use-cases/tips.md rename to docs/src/recipes/tips.md index 6b9d39f..f31b9d5 100644 --- a/docs/src/use-cases/tips.md +++ b/docs/src/recipes/tips.md @@ -32,13 +32,17 @@ let mut finished_level_three = Rule::new(Outcome::Tip { }); ``` -> ℹ️ In a production environment (i.e. distributing your game), it makes more sense to serialize your tips during development and include them in your distributed assets, ready to be [deserialized at runtime](/serialization.html)! +::: tip +In a production environment (i.e. distributing your game), it makes more sense to serialize your tips during development and include them in your distributed assets, ready to be [deserialized at runtime](/serialization.html)! +::: ### Adding requirements Without [evaluators](/concepts/evaluator.html) (requirements), these tips are pretty useless. Let's add some! -> ⚠️ The `FloatEvaluator` implementation used in this example requires enabling the `float` feature in your project's `Cargo.toml`! +::: warning +The `FloatEvaluator` implementation used in this example requires enabling the `float` feature in your project's `Cargo.toml`! +::: ```rs just_died.insert( @@ -55,9 +59,11 @@ finished_level_three.insert( // `last_level_completed`: this logic is outside of Mímir's scope! ``` -> ℹ️ In the above example, we mimick a `bool` by checking if the float's value is equal to `1.0` (`FloatEvaluator::EqualTo(1.)`). -> -> Alternatively, you could write your own implementation of `Evaluator` that can evaluate boolean values. +::: tip +In the above example, we mimic a `bool` by checking if the float's value is equal to `1.0` (`FloatEvaluator::EqualTo(1.)`). + +Alternatively, you could write your own implementation of `Evaluator` that can evaluate boolean values. +::: ## Bundling the tips @@ -67,9 +73,11 @@ Now let's bundle the tips into a [ruleset](/concepts/ruleset.html) so we can eva let tips = Ruleset::new(vec![just_died, finished_level_three]); ``` -> ⚠️ As outlined on the [performance page](/performance.html#ruleset-storage), invoking `Ruleset::new` is expensive! -> -> Instead of creating the ruleset each time your game enters a loading screen state, you should setup your ruleset once during your game's initial load. +::: warning +As outlined on the [performance page](/performance.html#ruleset-storage), invoking `Ruleset::new` is expensive! + +Instead of creating the ruleset each time your game enters a loading screen state, you should setup your ruleset once during your game's initial load. +::: ## Retrieving a valid tip diff --git a/docs/src/changelog.md b/docs/src/release-notes.md similarity index 99% rename from docs/src/changelog.md rename to docs/src/release-notes.md index 85794d2..7affcab 100644 --- a/docs/src/changelog.md +++ b/docs/src/release-notes.md @@ -1,4 +1,4 @@ -# Changelog +# Release notes Visit the [releases page on GitHub][releases] for a list of all historical releases. diff --git a/docs/src/serialisation.md b/docs/src/serialisation.md new file mode 100644 index 0000000..ae2ed17 --- /dev/null +++ b/docs/src/serialisation.md @@ -0,0 +1,16 @@ +# Serialisation + +Evaluators (including the `FloatEvaluator` implementation), rules, and rulesets are all (de)serialisable using [serde][serde] if you enable the respective feature in your project's `Cargo.toml`: + +```toml +[dependencies] +subtale-mimir = { version = "0.5.1", features = ["serde"] } +``` + +This makes it easy for you to serialise rulesets into a persistent medium (i.e. files) during your game's development process, bundle them with your game, and deserialise them at runtime. + +::: tip +This also means that Mímir can effortlessly support modding by allowing you to deserialize and load user-defined rulesets at runtime. +::: + +[serde]: https://serde.rs/ \ No newline at end of file diff --git a/docs/src/serialization.md b/docs/src/serialization.md deleted file mode 100644 index 33581f4..0000000 --- a/docs/src/serialization.md +++ /dev/null @@ -1,14 +0,0 @@ -# Serialization - -Evaluators (including the `FloatEvaluator` implementation), rules, and rulesets are all (de)serializable using [serde][serde] if you enable the respective feature in your project's `Cargo.toml`: - -```toml -[dependencies] -subtale-mimir = { version = "0.5.1", features = ["serde"] } -``` - -This makes it easy for you to serialize rulesets into a persistent medium (i.e. files) during your game's development process, bundle them with your game, and deserialize them at runtime. - -> ℹ️ This also means that Mímir can effortlessly support modding by allowing you to deserialize and load user-defined rulesets at runtime. - -[serde]: https://serde.rs/ \ No newline at end of file diff --git a/docs/src/tutorial.md b/docs/src/tutorial.md deleted file mode 100644 index 336dfcc..0000000 --- a/docs/src/tutorial.md +++ /dev/null @@ -1,22 +0,0 @@ -# Tutorial (WIP) - -This guide serves as a tutorial for newcomers to Mímir; a hypothetical scenario is established for a game and then an exemplar, step-by-step implementation is provided. - -## Scenario - -You're working on a game that is an "open world": more specifically, there is a non-linear quest tree (i.e. the player is free to explore and start/complete quests as they please). - -As a game designer, you've decided that you'd like your game's dialogue to be more "aware" of what has happened. You'd like NPCs to make different remarks depending on what the player has/hasn't already done. - -This scenario can be easily achieved with Mímir; let's get started! - -## Steps - -### Installation - -Start off by adding Mímir to your project's `Cargo.toml`, including the optional `float` feature (whose relevance will be explained later): - -```toml -[dependencies] -subtale-mimir = { version = "0.5.1", features = ["float"] } -``` diff --git a/docs/tsconfig.json b/docs/tsconfig.json new file mode 100644 index 0000000..0fef23a --- /dev/null +++ b/docs/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +}