npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ursamu/core

v0.4.14

Published

A Modern MUSH Server

Downloads

7

Readme

Ursamu

Ursamu is a modern implementation of a MUSH server, a text based, intertnet roleplaying game. This work is definitely done on the shoulders of giants. This Repo is also in a very alpha state and the api is surely destinied to change as I move towards a stable 1.0.

This repo represents the core or the ursamu engine. It has the bare essentials to start an URSAMU server. For more information about the core API, check out the documentation. warning! Still a work in progress!

Basic Usage

import { io } from "@ursamu/core";
import { createServer } from "http";

const server = createServer((req, res) => {});
io.attach(server);

server.listen(4201);

Adding Functions to the MUSCode Parser

Functions allow you to implement custom mushcode in your game. While you cna't currently create pure mushcode commands yet, a user CAN interpret code in their input string.

import { parser } from "@ursamu/core";

parser.add("add", (args) => parseInt(args[0]) + parseInt(args[1]));
parser.add("sub", (args) => parseInt(args[0]) - parseInt(args[1]));

// Using a function an anonymous function def, also including the
// optional parameter `data`.
parser.add("repeat", function (args, data) {
  const width = args[1] ? parseIng(args[1]) : data.width;
  return args[0].repeat(width);
});

// -> user input: think [sub(add(1,2),1)] >> 2
// -> user input: think [repeat(-,4)] >> ----

Commands

While softcoded commands are not yet available, it's very easy to add new 'hardcode' commands to UrsamMU. A command holds the following structure:

Cmd

  • name: string The name of the function. Used in +help.
  • pattern: string | RegExp The pattern for the command to match against. UrsamMI suppprts two kinds of patterns when you write your commands, string and regex (though honestly strings are processed and converted to regex under the hood). Regex allows for more powerful pattern matching. In regex, (group) matches will become the args array of the render property. Whene using strings, use wildcard * matching. To maych any input use an asterisk, if that input is optional use a question mark ? instead.
  • flags: string This is the flag expression the command enactor must pass before the command will match.
  • render: (ctx, args) => void This is where the business logic of the command goes. ctx represents the current context object being passed through the hooks.input.execute(ctx) run. Args repreresents any grouped matches from the the commands pattern.
import { addCmd } from "@ursamu/core";

addCmd({
  name: "test",
  pattern: "@test ?", //could allso be written as  /^@test\s+(.*)?/
  flags: "connected", // Must have connected flag to use.
  render: async (ctx) => send(ctx.id, `Testing!: ${args[0]}`),
});

Hooks

Hooks are middleware pipelines that can be used to modify data. There are serveral pre-defined hooks that you can utalize for the game, as well as a way to create your own custom hooks as needed by your addition or plugin. Data can be passed between hooks in a pipeline through the context: ctx object. Then, once done modifying the passed data, invoke the next() function to move onto the noext middleware in the pipeline.

import { hooks } from "@ursamu/core";

hooks.input.use((ctx, next) => {
  ctx.data.foo = "bar";
  ctx.data.original.msg = ctx.msg;
  next();
});

Then, when we need to run the middleware pipeline in our code, we can invoke the execute function to run our middleware chain.

import { hooks, io } from "@uesamu/coro";

io.on("connection", (socket: Socket) => {
  socket.join(socket.id);

  socket.on("message", (ctx) => {
    try {
      ctx = JSON.parse(ctx);
      ctx.id = socket.id;
      ctx.socket = socket;
      hooks.input.execute(ctx);
    } catch {
      ctx.id = socket.id;
      ctx.socket = socket;
      hooks.input.execute(ctx);
    }
  });
});

Flags

Coming soon

The Plugin System

The plugin system is simple to use! Simplpy put your code inside of a folder, export using default export, and call it in your main file whateveer that may be! It's the easiest way to expand upon a base UrsaMU installation. You can use whatever structure you want for your project, but in our example, our project structure is very simple:

- project
  - src
    - plugins
      plugin1.ts
    index.ts
  tsconfig.json

index.ts (using express)

import { plugins, io } from "@ursamu/core";
import { join } from "fs";
import { express } from "express";
import { createServer } from "http";

const app = express();
const server = createServer(app);
io.attach(server);

// I'm only inteterested in adding files with the js or ts  extension,
// or folders with an 'index.js' file available, and avoid files that
// end in '.d.ts'
plugins(join(__dirname, "./plugins/"), ["js", "ts"], [".d.ts"]);

server.listen(4201);

plugins/plugin1.ts

import { flags, parser, addCmd, send } from "@ursamu/core";

export default () => {
  // add commands
  addCmd({
    name: "test",
    pattern: ".test *",
    flags: "connected",
    render: async (ctx) => send(ctx.id, `Testing!: ${args[0]}`),
  });

  // add functions
  parser.add("add", (args) => parseInt(args[0]) + parseInt(args[1]));
  parser.add("sub", (args) => parseInt(args[0]) - parseInt(args[1]));

  parser.add("repeat", function (args, data) {
    const width = args[1] ? parseIng(args[1]) : data.width;
    return args[0].repeat(width);
  });

  // Add another flag with data!  :)
  flags.add({
    name: "foobar",
    cpde: "f".
    lock: "builder|staff+",
    lvl: 0,
    data: {
      some: "data",
    }
  })
};

Development

coming soon

License

MIT