diff --git a/docs/pages/index.mdx b/docs/pages/index.mdx index e17c2a07..89740303 100644 --- a/docs/pages/index.mdx +++ b/docs/pages/index.mdx @@ -11,7 +11,6 @@ Command machines, turn chests into shops and doors into toll gates. Build curren On the following pages you'll learn about: -- [Programs](/programs): Smart contracts that define the rules of your onchain entities -- [Apps](/apps): Custom user interfaces that integrate with the native client +- [Programs](/programs): How programs work - [Bots](/bots): How to automate tasks in DUST - [Examples](/examples/swap-chest): Practical end-to-end use cases diff --git a/docs/pages/apps/dustkit.md b/docs/pages/programs/custom-uis/dustkit.md similarity index 100% rename from docs/pages/apps/dustkit.md rename to docs/pages/programs/custom-uis/dustkit.md diff --git a/docs/pages/apps/index.md b/docs/pages/programs/custom-uis/index.md similarity index 99% rename from docs/pages/apps/index.md rename to docs/pages/programs/custom-uis/index.md index 002aefd0..a953f86b 100644 --- a/docs/pages/apps/index.md +++ b/docs/pages/programs/custom-uis/index.md @@ -1,4 +1,4 @@ -# Introduction +# Custom UIs The DUST client supports embedded apps - web apps that integrate directly into the game client UI and interact with in-game objects and physics. Apps let developers build on top of the world and extend the game client with custom functionality like shops and marketplaces. diff --git a/docs/pages/apps/registration.md b/docs/pages/programs/custom-uis/registration.md similarity index 84% rename from docs/pages/apps/registration.md rename to docs/pages/programs/custom-uis/registration.md index 03ca025f..ac1edf69 100644 --- a/docs/pages/apps/registration.md +++ b/docs/pages/programs/custom-uis/registration.md @@ -1,5 +1,11 @@ # Registration +Smart contract programs deployed to the DUST world will automatically show up in the explorer. You can also register a custom UI for your program in 3 different places: + +- sidebar: a list of global apps +- spawn screen: a list of apps shown on the spawn screen +- when interacting with smart items: shown when a user interacts with a smart object with your program attached + ## Preview an app in the client Before registering an app to make it available to everyone, you can preview your app in the production client by using the `debug-app` URL parameter. @@ -34,7 +40,7 @@ To make an app available in everyone's client, you have to register it in the gl ## Register a contextual app -To show a contextual app when interacting with an entity that has [your program installed](../programs/registration.md), your program needs to implement the [`appConfigURI` function](https://github.com/dustproject/dust/blob/main/packages/dustkit/contracts/IAppConfigURI.sol). +To show a contextual app when interacting with an entity that has your program installed, your program needs to implement the [`appConfigURI` function](https://github.com/dustproject/dust/blob/main/packages/dustkit/contracts/IAppConfigURI.sol). ```solidity // SPDX-License-Identifier: MIT diff --git a/docs/pages/programs/index.md b/docs/pages/programs/index.md index 65cfa018..f637d654 100644 --- a/docs/pages/programs/index.md +++ b/docs/pages/programs/index.md @@ -1,102 +1,17 @@ -Programs represent an abstraction layer that enables dynamic behavior and programmable logic for entities within DUST. Programs offer a flexible mechanism for extending entity functionality through custom logic that can respond to various in-world events. +## Programs -## Core Concepts +![program diagram](/program-diagram.png) -Programs in this architecture are defined by several key abstractions: +Programs can read from the world and influence it via smart objects. -- **ProgramId**: A unique identifier that references a specific program implementation (the underlying value is a MUD `ResourceId`) -- **EntityId**: A unique identifier for entities within the world (ForceFields, Chests, etc) -- **Program**: Smart contracts (MUD systems) which can be attached to specific entities to define their behavior +The state of the world is stored in MUD tables. You can see the full list of tables on the mud.config. -### Event-Driven Architecture +To read the tables in a smart contract, you import the table library and then pass in the keys. To read the tables in an app/script, you can call a getter or use an indexer (eg. MUD stash). -Programs follow an event-driven architecture where system contracts invoke program hooks in response to specific actions. This pattern allows for: +Programs can be attached to smart objects in the world (eg chests, force fields), and the world will call your program for certain interactions. -1. **Decoupling**: World systems and programs are loosely coupled, communicating through well-defined interfaces -2. **Extensibility**: New hooks can be added without modifying core systems -3. **Composability**: A program can be attached to different types of entities, and optionally implement the hooks related to those entity types +Smart contract programs deployed to the DUST world will automatically show up in the explorer. You can also register a custom UI for your program in 3 different places: -### ProgramId and Resource Management - -The `ProgramId` type serves as the fundamental reference to program implementations. It is defined as: - -```solidity -type ProgramId is bytes32; -``` - -Programs are registered as systems within the MUD framework, and `ProgramId`s encode the corresponding `ResourceId` of the system. - -### Program Attachment and Validation - -The `ProgramSystem` contract manages the attachment and detachment of programs to entities: - -```solidity -function attachProgram(EntityId caller, EntityId target, ProgramId program, bytes calldata extraData) public { - // Validation logic - // ... - - EntityProgram._set(target, program); - - program.callOrRevert(abi.encodeCall(IAttachHook.onAttachProgram, (caller, target, extraData))); - - // Notification logic - // ... -} - -function detachProgram(EntityId caller, EntityId target, bytes calldata extraData) public { - // Validation logic - // ... - - ProgramId program = target.getProgram(); - - bytes memory onDetachProgram = abi.encodeCall(IDetachProgramHook.onDetachProgram, (caller, target, extraData)); - - (EnergyData memory machineData, ) = updateMachineEnergy(forceField); - if (machineData.energy > 0) { - program.callOrRevert(onDetachProgram); - } else { - program.call({ gas: SAFE_PROGRAM_GAS, hook: onDetachProgram }); - } - - EntityProgram._deleteRecord(target); - - // Notification logic - // ... -} -``` - -A key aspect of program attachment is the validation process. Before a program can be attached to an entity, it must pass validation checks: - -1. The program must be registered as a private system -2. If the entity being programmed is within an active ForceField, the forcefield's program `validateProgram` hook must accept the attachment -3. The program itself must accept the attachment through the `onAttachProgram` hook - -This multi-layered validation ensures that only appropriate programs can be attached to entities, maintaining the integrity of the world. - -### Gas Safety Mechanisms - -To prevent malicious or poorly implemented programs from consuming excessive gas, calls with a fixed amount of gas are used. Safe calls are only used for hooks that correspond to actions that the entity might be incentivized to prevent (e.g. `onHit`). - -The `SAFE_PROGRAM_GAS` constant (set to 1,000,000 gas units) limits the gas available to safe program calls, preventing the program from consuming all the gas available in the transaction. - -## Program Execution in Context - -### Machine Interactions - -Programs can respond to interactions with machines, such as when a player fuels a machine: - -```solidity -function fuelMachine(EntityId callerEntityId, EntityId machineEntityId, uint16 fuelAmount) public { - // Validation and fuel logic - // ... - - // Call program hook - ProgramId program = baseEntityId.getProgram(); - program.callOrRevert(abi.encodeCall(IFuelHook.onFuel, (callerEntityId, baseEntityId, fuelAmount, ""))); - - // Notification logic - // ... -} -``` - -This allows machines to execute custom logic when they receive fuel, potentially triggering complex behaviors or state changes. +- sidebar: a list of global apps +- spawn screen: a list of apps shown on the spawn screen +- when interacting with smart items: shown when a user interacts with a smart object with your program attached diff --git a/docs/pages/data-model.md b/docs/pages/programs/reading-the-world.md similarity index 98% rename from docs/pages/data-model.md rename to docs/pages/programs/reading-the-world.md index 79cbd337..916b1a86 100644 --- a/docs/pages/data-model.md +++ b/docs/pages/programs/reading-the-world.md @@ -1,4 +1,4 @@ -# Data Model +# Reading The World DUST is built using [MUD](https://mud.dev/), and so the [mud.config.ts](https://github.com/dustproject/dust/blob/main/packages/world/mud.config.ts) defines all the different entities and components. Here we look at 2 specific kinds of data and how to read them. @@ -95,7 +95,7 @@ SELECT "entityId", "x", "y", "z" FROM "EntityPosition" WHERE "entityId" = '0x01c This shows the player is at `[1380, 79, -2434]`. -### Reading In A Program +### Reading In A Smart Contract ```solidity import { EntityId, EntityTypeLib } from "@dust/world/src/types/EntityId.sol"; @@ -185,7 +185,7 @@ SELECT "owner", "slot", "entityId", "objectType", "amount" FROM "InventorySlot" This shows all the items the player has. eg, the player has 4 WheatSeeds (id 134) in slot 2. -### Reading In A Program +### Reading In A Smart Contract ```solidity import { InventorySlot, InventorySlotData } from "@dust/world/src/codegen/tables/InventorySlot.sol"; diff --git a/docs/pages/programs/smart-objects/index.md b/docs/pages/programs/smart-objects/index.md new file mode 100644 index 00000000..4dbd6e5e --- /dev/null +++ b/docs/pages/programs/smart-objects/index.md @@ -0,0 +1,96 @@ +# Smart Objects + +Programs can be attached to smart objects in the world (eg chests, force fields), and the world will call your program for certain interactions. + +## Core Concepts + +Programs in this architecture are defined by several key abstractions: + +- **ProgramId**: A unique identifier that references a specific program implementation (the underlying value is a MUD `ResourceId`) +- **EntityId**: A unique identifier for entities within the world (ForceFields, Chests, etc) +- **Program**: Smart contracts (MUD systems) which can be attached to specific entities to define their behavior + +### ProgramId and Resource Management + +The `ProgramId` type serves as the fundamental reference to program implementations. It is defined as: + +```solidity +type ProgramId is bytes32; +``` + +Programs are registered as systems within the MUD framework, and `ProgramId`s encode the corresponding `ResourceId` of the system. + +### Program Attachment and Validation + +The `ProgramSystem` contract manages the attachment and detachment of programs to entities: + +```solidity +function attachProgram(EntityId caller, EntityId target, ProgramId program, bytes calldata extraData) public { + // Validation logic + // ... + + EntityProgram._set(target, program); + + program.callOrRevert(abi.encodeCall(IAttachHook.onAttachProgram, (caller, target, extraData))); + + // Notification logic + // ... +} + +function detachProgram(EntityId caller, EntityId target, bytes calldata extraData) public { + // Validation logic + // ... + + ProgramId program = target.getProgram(); + + bytes memory onDetachProgram = abi.encodeCall(IDetachProgramHook.onDetachProgram, (caller, target, extraData)); + + (EnergyData memory machineData, ) = updateMachineEnergy(forceField); + if (machineData.energy > 0) { + program.callOrRevert(onDetachProgram); + } else { + program.call({ gas: SAFE_PROGRAM_GAS, hook: onDetachProgram }); + } + + EntityProgram._deleteRecord(target); + + // Notification logic + // ... +} +``` + +A key aspect of program attachment is the validation process. Before a program can be attached to an entity, it must pass validation checks: + +1. The program must be registered as a private system +2. If the entity being programmed is within an active ForceField, the forcefield's program `validateProgram` hook must accept the attachment +3. The program itself must accept the attachment through the `onAttachProgram` hook + +This multi-layered validation ensures that only appropriate programs can be attached to entities, maintaining the integrity of the world. + +### Gas Safety Mechanisms + +To prevent malicious or poorly implemented programs from consuming excessive gas, calls with a fixed amount of gas are used. Safe calls are only used for hooks that correspond to actions that the entity might be incentivized to prevent (e.g. `onHit`). + +The `SAFE_PROGRAM_GAS` constant (set to 1,000,000 gas units) limits the gas available to safe program calls, preventing the program from consuming all the gas available in the transaction. + +## Program Execution in Context + +### Machine Interactions + +Programs can respond to interactions with machines, such as when a player fuels a machine: + +```solidity +function fuelMachine(EntityId callerEntityId, EntityId machineEntityId, uint16 fuelAmount) public { + // Validation and fuel logic + // ... + + // Call program hook + ProgramId program = baseEntityId.getProgram(); + program.callOrRevert(abi.encodeCall(IFuelHook.onFuel, (callerEntityId, baseEntityId, fuelAmount, ""))); + + // Notification logic + // ... +} +``` + +This allows machines to execute custom logic when they receive fuel, potentially triggering complex behaviors or state changes. diff --git a/docs/pages/programs/reference.md b/docs/pages/programs/smart-objects/reference.md similarity index 100% rename from docs/pages/programs/reference.md rename to docs/pages/programs/smart-objects/reference.md diff --git a/docs/pages/programs/registration.md b/docs/pages/programs/smart-objects/registration.md similarity index 100% rename from docs/pages/programs/registration.md rename to docs/pages/programs/smart-objects/registration.md diff --git a/docs/public/program-diagram.png b/docs/public/program-diagram.png new file mode 100644 index 00000000..ef5f844b Binary files /dev/null and b/docs/public/program-diagram.png differ diff --git a/docs/vocs.config.ts b/docs/vocs.config.ts index f33732b7..5c840040 100644 --- a/docs/vocs.config.ts +++ b/docs/vocs.config.ts @@ -9,25 +9,36 @@ export default defineConfig({ sidebar: [ { text: "Overview", - items: [ - { text: "Introduction", link: "/" }, - { text: "Data Model", link: "/data-model" }, - ], + items: [{ text: "Introduction", link: "/" }], }, { - text: "Programs (contracts)", + text: "Programs", items: [ { text: "Introduction", link: "/programs" }, - { text: "Registration", link: "/programs/registration" }, - { text: "Reference", link: "/programs/reference" }, - ], - }, - { - text: "Apps (client)", - items: [ - { text: "Introduction", link: "/apps" }, - { text: "Registration", link: "/apps/registration" }, - { text: "DustKit", link: "/apps/dustkit" }, + { text: "Reading The World", link: "/programs/reading-the-world" }, + { + text: "Smart Objects", + link: "/programs/smart-objects", + collapsed: false, + items: [ + { text: "Overview", link: "/programs/smart-objects" }, + { + text: "Registration", + link: "/programs/smart-objects/registration", + }, + { text: "Reference", link: "/programs/smart-objects/reference" }, + ], + }, + { + text: "Custom UIs", + link: "/programs/custom-uis", + collapsed: false, + items: [ + { text: "Overview", link: "/programs/custom-uis" }, + { text: "Dustkit", link: "/programs/custom-uis/dustkit" }, + { text: "Registration", link: "/programs/custom-uis/registration" }, + ], + }, ], }, {