Creating Child Games with UrsaMU
This guide explains how to create a child game using UrsaMU as a library.
Overview
A “child game” is a complete MU* game built on top of the UrsaMU engine. Unlike plugins, which extend the functionality of UrsaMU, a child game is a standalone application that uses UrsaMU as a library.
Creating a child game allows you to:
- Create a completely customized MU* experience
- Define your own game world, theme, and mechanics
- Distribute your game as a standalone application
- Maintain your game separately from the UrsaMU core
Getting Started
Prerequisites
Before creating a child game, ensure you have:
- Deno installed (version 1.37.0 or higher)
- Basic knowledge of TypeScript
- Understanding of MU* concepts
Installation
- Create a new directory for your game:
mkdir my-game
cd my-game
- Initialize a new Deno project:
deno init
- Install UrsaMU as a dependency:
# Add UrsaMU as a dependency in your deps.ts file
Project Structure
A typical child game project structure looks like this:
my-game/
├── config/ # Configuration files
│ ├── config.json # Main configuration
│ ├── text/ # Text files
│ └── plugins/ # Plugin configurations
├── src/ # Source code
│ ├── commands/ # Custom commands
│ ├── plugins/ # Custom plugins
│ ├── types/ # TypeScript type definitions
│ └── main.ts # Entry point
├── data/ # Database files (generated)
├── deps.ts # Dependencies
├── deno.json # Deno configuration
└── README.md # Documentation
Configuration
Basic Configuration
Create a config/config.json file with your game’s configuration:
{
"server": {
"port": 4201,
"host": "0.0.0.0"
},
"game": {
"name": "My Game",
"motd": "Welcome to My Game!",
"debug": false
},
"database": {
"path": "./data"
}
}
Text Files
UrsaMU uses text files for various game messages. Create a config/text directory and add your custom text files:
config/text/
├── connect.txt # Connection screen
├── motd.txt # Message of the day
└── welcome.txt # Welcome message for new players
Customization
Creating the Main File
Create a src/main.ts file as the entry point for your game:
import { mu } from "ursamu";
import { config } from "../config/mod.ts";
// Import your custom plugins
import myPlugin from "./plugins/myPlugin/mod.ts";
// Start the game
await mu({
config,
plugins: [
myPlugin,
// Add more custom plugins here
]
});
console.log("Game started!");
Custom Commands
Create custom commands in the src/commands directory:
// src/commands/hello.ts
import { addCmd } from "jsr:@ursamu/ursamu";
import type { IUrsamuSDK } from "jsr:@ursamu/ursamu";
addCmd({
name: "hello",
pattern: /^hello\s*(.*)/i,
lock: "connected",
exec: (u: IUrsamuSDK) => {
const target = u.cmd.args[0]?.trim() || "World";
u.send(`Hello, ${target}!`);
}
});
Custom Plugins
Create custom plugins in the src/plugins directory:
// src/plugins/myPlugin/mod.ts
import { IPlugin } from "ursamu";
const myPlugin: IPlugin = {
name: "my-plugin",
version: "1.0.0",
description: "A custom plugin for my game",
init: async () => {
console.log("My plugin initialized!");
return true;
},
remove: async () => {
console.log("My plugin removed!");
}
};
export default myPlugin;
Deployment
Running Your Game
Run your game with Deno:
deno run --allow-net --allow-read --allow-write --allow-env src/main.ts
Creating a Startup Script
Create a start.sh script for easier startup:
#!/bin/bash
deno run --allow-net --allow-read --allow-write --allow-env src/main.ts
Make it executable:
chmod +x start.sh
Docker Deployment
Create a Dockerfile for containerized deployment:
FROM denoland/deno:1.37.0
WORKDIR /app
COPY . .
RUN deno cache src/main.ts
EXPOSE 4201
CMD ["deno", "run", "--allow-net", "--allow-read", "--allow-write", "--allow-env", "src/main.ts"]
Build and run the Docker container:
docker build -t my-game .
docker run -p 4201:4201 my-game
Examples
Basic Child Game
Here’s a complete example of a basic child game:
// src/main.ts
import { mu } from "jsr:@ursamu/ursamu";
import welcomePlugin from "./plugins/welcome/mod.ts";
// Define configuration
const config = {
server: {
telnet: 4201,
ws: 4202,
http: 4203,
},
game: {
name: "My First MU",
motd: "Welcome to My First MU!"
}
};
// Start the game
await mu(config, [welcomePlugin]);
console.log(`${config.game.name} is running`);
// src/plugins/welcome/mod.ts
import { addCmd } from "jsr:@ursamu/ursamu";
import type { IPlugin, IUrsamuSDK } from "jsr:@ursamu/ursamu";
const welcomePlugin: IPlugin = {
name: "welcome",
version: "1.0.0",
description: "A welcome plugin for new players",
init: async () => {
// Register a welcome command
addCmd({
name: "welcome",
pattern: /^welcome\s*(.*)/i,
lock: "connected",
exec: (u: IUrsamuSDK) => {
const target = u.cmd.args[0]?.trim() || "friend";
u.send(`Welcome to our game, ${target}!`);
}
});
return true;
},
remove: async () => {
// Cleanup code here
}
};
export default welcomePlugin;
Advanced Child Game
For a more advanced example, see the UrsaMU Examples repository which contains complete child game examples with various features.
Customizing the Database
You can customize how your game uses the database:
// src/main.ts
import { mu } from "../deps.ts";
await mu({
config: {
// ... other config options
database: {
path: "./custom-data",
backupInterval: 3600000 // Backup every hour
}
}
});
Creating a Custom Theme
You can create a custom theme by overriding the default text files and adding custom CSS for the web interface:
// src/plugins/theme/mod.ts
import { IPlugin } from "../../../deps.ts";
const themePlugin: IPlugin = {
name: "custom-theme",
version: "1.0.0",
description: "Custom theme for my game",
init: async () => {
// Register custom CSS
// Set up custom colors
// Override default text files
return true;
}
};
export default themePlugin;
By following this guide, you can create a fully customized MU* game using UrsaMU as a foundation, while maintaining the flexibility to extend and modify it to suit your specific needs.