6.1 KiB
6.1 KiB
Guide: Creating New OSIRIS Objects
This guide explains how to properly create new object types in OSIRIS that integrate with the Rhai scripting engine and context storage.
Step-by-Step Process
1. Create the Object Module
Create a new file in the appropriate directory under src/objects/:
src/objects/legal/for legal objectssrc/objects/money/for financial objectssrc/objects/heroledger/for HeroLedger objects- etc.
2. Define the Object Struct
CRITICAL: The struct MUST derive crate::DeriveObject to automatically implement the Object trait.
use crate::store::BaseData;
use serde::{Deserialize, Serialize};
/// Your object description
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, crate::DeriveObject)]
pub struct YourObject {
/// Base data for object storage (REQUIRED)
pub base_data: BaseData,
/// Your custom fields
pub title: String,
pub status: YourStatus,
// ... other fields
}
Required traits:
Debug- for debuggingClone- required by Object traitSerialize, Deserialize- for JSON serializationPartialEq- for comparisonscrate::DeriveObject- CRITICAL - auto-implements Object trait
Required field:
base_data: BaseData- MUST be present for object storage
3. Implement Constructor and Methods
impl YourObject {
/// Create a new object
pub fn new(id: u32) -> Self {
let base_data = BaseData::with_id(id, String::new());
Self {
base_data,
title: String::new(),
status: YourStatus::default(),
// ... initialize other fields
}
}
/// Fluent builder methods
pub fn title(mut self, title: impl ToString) -> Self {
self.title = title.to_string();
self
}
// ... other methods
}
4. Create Rhai Bindings Module
Create rhai.rs in the same directory:
use ::rhai::plugin::*;
use ::rhai::{CustomType, Dynamic, Engine, EvalAltResult, Module, TypeBuilder};
use super::{YourObject, YourStatus};
/// Register your modules with the Rhai engine
pub fn register_your_modules(parent_module: &mut Module) {
// Register custom types
parent_module.set_custom_type::<YourObject>("YourObject");
parent_module.set_custom_type::<YourStatus>("YourStatus");
// Merge functions
let your_module = exported_module!(rhai_your_module);
parent_module.merge(&your_module);
}
#[export_module]
mod rhai_your_module {
use super::YourObject;
use ::rhai::EvalAltResult;
// Constructor
#[rhai_fn(name = "new_your_object", return_raw)]
pub fn new_your_object(id: i64) -> Result<YourObject, Box<EvalAltResult>> {
Ok(YourObject::new(id as u32))
}
// Builder methods
#[rhai_fn(name = "title", return_raw)]
pub fn set_title(
obj: YourObject,
title: String,
) -> Result<YourObject, Box<EvalAltResult>> {
Ok(obj.title(title))
}
// Getters
#[rhai_fn(name = "title", pure)]
pub fn get_title(obj: &mut YourObject) -> String {
obj.title.clone()
}
}
// CustomType implementations
impl CustomType for YourObject {
fn build(mut builder: TypeBuilder<Self>) {
builder.with_name("YourObject");
}
}
impl CustomType for YourStatus {
fn build(mut builder: TypeBuilder<Self>) {
builder.with_name("YourStatus");
}
}
5. Update Module Exports
In mod.rs of your object category:
pub mod your_object;
pub mod rhai;
pub use your_object::{YourObject, YourStatus};
pub use rhai::register_your_modules;
In src/objects/mod.rs:
pub mod your_category;
pub use your_category::{YourObject, YourStatus};
6. Register in Engine (CRITICAL STEP)
In src/engine.rs, add the save registration in the OsirisPackage definition:
def_package! {
pub OsirisPackage(module) : StandardPackage {
// ... existing registrations ...
// Add your object's save method
FuncRegistration::new("save")
.set_into_module(module, |ctx: &mut OsirisContext, obj: crate::objects::YourObject| ctx.save_object(obj));
// ... existing registrations ...
// Register your modules
register_your_modules(module);
}
}
Also add the import at the top of engine.rs:
use crate::objects::your_category::rhai::register_your_modules;
7. Create Example Script
Create examples/engine/XX_your_object.rhai:
print("=== Your Object Example ===\n");
// Get context
let ctx = get_context(["alice", "bob"]);
// Create object
let obj = new_your_object(1)
.title("Example Title");
print("Object created: " + obj.title());
// Store in context
ctx.save(obj);
print("Object stored");
print("\n=== Example Complete ===");
Checklist
Before considering your object complete, verify:
- Struct derives
crate::DeriveObject - Struct has
base_data: BaseDatafield - Rhai module created with
register_*_modulesfunction - Custom types registered with
set_custom_type - Module exported in
mod.rsfiles - Save method registered in
src/engine.rs - Module registration added to
OsirisPackageinsrc/engine.rs - Example script created and tested
- Example runs successfully with
cargo run --example engine examples/engine/XX_your_object.rhai
Common Mistakes to Avoid
- Forgetting
crate::DeriveObject- Without this, the Object trait won't be implemented - Missing
base_datafield - Required for all storable objects - Not registering save in engine.rs - The save method MUST be in engine.rs, not context.rs
- Not calling
set_custom_type- Rhai won't recognize your type - Not merging the exported module - Your functions won't be available
Example: Contract Object
See the Contract object implementation as a reference:
- Struct:
src/objects/legal/contract.rs - Rhai bindings:
src/objects/legal/rhai.rs - Module exports:
src/objects/legal/mod.rsandsrc/objects/mod.rs - Engine registration:
src/engine.rs(line ~110 and ~138) - Example:
examples/engine/12_contract.rhai