<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kevin Hoffman</title>
    <description>The latest articles on Forem by Kevin Hoffman (@autodidaddict).</description>
    <link>https://forem.com/autodidaddict</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F382180%2Fcbe8ac8c-3311-4833-88c3-5457a5eab83f.png</url>
      <title>Forem: Kevin Hoffman</title>
      <link>https://forem.com/autodidaddict</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/autodidaddict"/>
    <language>en</language>
    <item>
      <title>How I Ruined a Radar System</title>
      <dc:creator>Kevin Hoffman</dc:creator>
      <pubDate>Sat, 13 Feb 2021 16:09:16 +0000</pubDate>
      <link>https://forem.com/autodidaddict/how-i-ruined-a-radar-system-27m3</link>
      <guid>https://forem.com/autodidaddict/how-i-ruined-a-radar-system-27m3</guid>
      <description>&lt;h1&gt;
  
  
  The Backstory
&lt;/h1&gt;

&lt;p&gt;Around a year ago, I was working on a technology demonstration for my WebAssembly back-end, a project that would end up being called &lt;a href="https://wasmcloud.dev" rel="noopener noreferrer"&gt;wasmCloud&lt;/a&gt;. The demo was a game engine that ran in the cloud--a distributed &lt;a href="https://en.wikipedia.org/wiki/Entity_component_system" rel="noopener noreferrer"&gt;ECS&lt;/a&gt; (Entity/Component/System) architecture.&lt;/p&gt;

&lt;p&gt;This game allowed players to enter a shared, persistent, 3D sci-fi universe from web browsers and mobile devices alike. The ECS had a system called &lt;code&gt;radar&lt;/code&gt; that would, on each frame, populate the list of entities to appear on a player's radar GUI.&lt;/p&gt;

&lt;p&gt;After a few hundred people got into the game, we noticed the radar system would get a bit laggy. After it lagged, it eventually got so bad that the radar contacts being displayed in the GUI were &lt;em&gt;several seconds&lt;/em&gt; behind what was actually happening in real-time according to the &lt;code&gt;movement&lt;/code&gt; system. If we left the game running long enough, the radar system lag ultimately made the entire game unplayable and we had to restart it. &lt;/p&gt;

&lt;p&gt;Thankfully the fault did not lie with my underlying "WebAssembly in the cloud" technology, but rather with the naive radar algorithm.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Modeling Things as Humans Perceive them is Dangerous
&lt;/h1&gt;

&lt;p&gt;Some of us are old enough to have learned computer programming at a time when most professors thought Object-Oriented Programming was "the way".&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffmw0tj1ejsswj4pu6gzp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffmw0tj1ejsswj4pu6gzp.jpg" alt="This was the way"&gt;&lt;/a&gt;&lt;br&gt;
We were enthralled by our ability to create cats that could also be lions, chairs that could also be containers, animals that could roar or meow. It was the best time to be alive.&lt;/p&gt;

&lt;p&gt;But modeling things in a computer using the same perspective with which humans view that thing is often naive and, in many cases, highly inefficient or broken outright.&lt;/p&gt;

&lt;p&gt;My naive radar algorithm wasn't quite object oriented, but it was modeled the way a human might think about the problem. How do I know the list of radar beacons that are on my screen? You could model all the empty space in the universe and examine it for beacons, but we all know &lt;em&gt;that&lt;/em&gt; would be a ludicrous idea. Surely there was a better way.&lt;/p&gt;

&lt;p&gt;So my "better way" was this: During each entity-frame (a frame sent to a system for a specific entity) just find every radar beacon in the universe (this was an ECS, so I didn't care what entity to which the beacon &lt;em&gt;component&lt;/em&gt; was associated), do a euclidean distance check against the positions reported by all beacons in the universe and the radar range of the current &lt;code&gt;transceiver&lt;/code&gt; component. Anything less than the transceiver's range away would get dumped into the &lt;code&gt;radar_contacts&lt;/code&gt; component (a simple list with GUI hints for rendering).&lt;/p&gt;

&lt;p&gt;You see the problem here? A universe with 1000 radar beacons and 1000 transceivers (aka 1000 players) would make 1,000,000 loop iterations per root game frame. So, if the &lt;code&gt;radar&lt;/code&gt; system operated at 1hz (1 frame per second), it would have to finish those 1,000,000 loop iterations in under a second. If it didn't finish all of its work within its allotted frame time, it would get behind. Once behind, it would get more behind every frame, until it was eventually so behind that the UI was useless to players. Moreover, if the system needed to make message broker requests for any of those calculations, we're also looking at a million messages per second... just for radar.&lt;/p&gt;

&lt;p&gt;We knew this was garbage but it was a demo and we literally got the demo working the day before the conference, so nobody was about to go back in and re-architect radar, especially when we weren't demoing radar, we were demoing WebAssembly as a unit of deployed compute. We just rebooted the game universe once radar got behind. We also scaled out the number of &lt;code&gt;radar&lt;/code&gt; system instances we had running (each system was a &lt;code&gt;.wasm&lt;/code&gt; file/&lt;em&gt;actor&lt;/em&gt;), and that delayed the inevitable, but it didn't change the overall throughput requirements of &lt;em&gt;just&lt;/em&gt; the radar system from 1,000,000 requests/second.&lt;/p&gt;

&lt;h1&gt;
  
  
  This Should've Been The Way
&lt;/h1&gt;

&lt;p&gt;Having had a ton of time to lick my wounds from the defeat that came at the hands of the age-old villain, "rushing to meet a conference deadline", I'd like to think I know better now.&lt;/p&gt;

&lt;p&gt;Rather than modeling the universe in a way that required each &lt;code&gt;radar&lt;/code&gt; system's entity-frame (set/&lt;em&gt;archetype&lt;/em&gt; of components) to make a loop iteration/data request for every other player in the universe, we need to model the data in a way that &lt;em&gt;supports the way it will be used&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Each frame, for each player, the &lt;code&gt;radar&lt;/code&gt; system needs to know which other nav beacons are "within range" of the current player's radar receiver. So how do we reduce this to &lt;strong&gt;O(1)&lt;/strong&gt; cost instead of &lt;strong&gt;O(n^2)&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;There are a couple of techniques, and the first involves an optimization that I call "hash key buddies".&lt;/p&gt;

&lt;h1&gt;
  
  
  The Hash Key Buddy System
&lt;/h1&gt;

&lt;p&gt;If the vector of things that satisfies your request can be contained within a single hash key, then retrieving that list of things can be done in &lt;strong&gt;O(1)&lt;/strong&gt; cost! I'm sure smarter people have a much better name for this, but the idea is that your hash keys are &lt;em&gt;traversal paths through a binary space partition tree&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;I woke up one morning with this idea for recursively sub-dividing regions of space so that the path through these sub-divisions would be predictable. Turns out, this was invented decades ago and is called a &lt;a href="https://en.wikipedia.org/wiki/Binary_space_partitioning" rel="noopener noreferrer"&gt;Binary Space Partition&lt;/a&gt; tree.&lt;/p&gt;

&lt;p&gt;A BSP is basically a tree structure (there are many specializations, including &lt;strong&gt;k-d&lt;/strong&gt; trees, used for partitioning n-dimensional space) that divides some "space" into a binary tree. The organization of the tree is up to you--you choose what the leaf nodes contain for your needs. I discovered that there are also other kinds of trees that aren't binary that are optimized for different uses (which led me down a rabbit hole of searching and tab opening).&lt;/p&gt;

&lt;p&gt;In our case, we could have taken the 3-dimensional universe and sub-divide it in half recursively down to some depth that is a multiple of our universe size. At each "slice" step, we cut the universe in half and the left child and right child refer to the two divisions, respectively. We then recursively slice those children in half, and so on.&lt;/p&gt;

&lt;p&gt;What we're left with is "buckets". Many BSPs are designed so that a leaf is the smallest unit, e.g. a &lt;em&gt;point&lt;/em&gt; in a modeled space of &lt;em&gt;point regions&lt;/em&gt;. Here's where the "optimize for need" comes in.&lt;/p&gt;

&lt;p&gt;Identifying a bucket is like playing the Price is Right game of &lt;a href="https://priceisright.fandom.com/wiki/Plinko" rel="noopener noreferrer"&gt;Plinko&lt;/a&gt;. You start at the top (root node) and you traverse recursively by "turning left" or "turning right" until you reach a leaf node. You can then map a "left turn" to the number &lt;strong&gt;0&lt;/strong&gt; and a "right turn" to the number &lt;strong&gt;1&lt;/strong&gt;. What can we do with a "path of bits"? Why, we can turn them into real numbers of course, which can then be used as &lt;em&gt;hash keys&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;So let's say my world is 256x256x256 and I want to sub-divide it such that each leaf is 16x16x16, which is roughly the 3D radius of my most powerful radar receiver. If I take a player's location and recursively compare it against the "buckets" in the tree until I hit a leaf, I might take the path &lt;strong&gt;right-left-left-left&lt;/strong&gt;. This gives me a "bit path" of &lt;strong&gt;1000&lt;/strong&gt;, which is the number &lt;strong&gt;8&lt;/strong&gt; (side note: while there are math shortcuts to speed this up, the "slow" traversal to find the bucket is &lt;strong&gt;O(log2n)&lt;/strong&gt; cost). &lt;/p&gt;

&lt;p&gt;This has the very, &lt;em&gt;very&lt;/em&gt; useful side effect of making it so that everything in the same 16x16x16 region of space can have a "bit path", which I'll call the &lt;em&gt;position key&lt;/em&gt;, of &lt;strong&gt;8&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If I want the fastest radar &lt;em&gt;approximation&lt;/em&gt;, I can simply dump everyone in the same &lt;em&gt;position key&lt;/em&gt; region of space onto my radar display and call it done. This is &lt;strong&gt;O(1)&lt;/strong&gt; cost.&lt;/p&gt;

&lt;p&gt;What if I need it to be more accurate? You've probably figured out that this algorithm treats the imaginary boundaries between sub-regions of space as hard barriers that can block radar.&lt;/p&gt;

&lt;p&gt;In reality, if I'm in the top right corner of a region, my radar receiving sphere (assuming that's the shape) will overlap with a few other regions. Here's what's even more awesome about &lt;em&gt;hash buddy keys&lt;/em&gt;. The region of space that is &lt;em&gt;adjacent&lt;/em&gt; to mine is also &lt;em&gt;mathematically&lt;/em&gt; adjacent to my "buddy key".&lt;/p&gt;

&lt;p&gt;If my algorithm does some quick back-of-napkin math to figure out the other region into which my radar sphere extends, I can get an &lt;em&gt;exact&lt;/em&gt; list of all the nav beacons in my range by doing a euclidean distance check on those in my own region and the adjacent region, making the cost &lt;strong&gt;O(n)&lt;/strong&gt; where &lt;code&gt;n&lt;/code&gt; in this case is the aggregate number of beacons that could reside in those regions. This is less efficient than the previous, but still deals with a &lt;em&gt;much&lt;/em&gt; smaller value of &lt;code&gt;n&lt;/code&gt;. Further, the smaller the sub-division the fewer the number of entities I need to check during each frame (but also the smaller the player's perceived radar range).&lt;/p&gt;

&lt;p&gt;So, in short, if you need to support a query like "give me everything in my sub-region of the world" or you do a 2-pass filter, which is "euclidean distance filter everything within my sub-region or collection of sub-regions", then using a BSP traversal path as a key for a hash map of vectors could be a ridiculously fast optimization. If you need to do anything other than just dump the bucket items into some other component, then &lt;em&gt;this solution does not scale&lt;/em&gt;. This kind of modeling can cause a "zone crash", where a single "bucket" or approximation region contains so many items that you now have the original problem I described--&lt;em&gt;it takes longer to process the items in the bucket than you have latency in your frame budget&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Using a Full K-D Tree
&lt;/h1&gt;

&lt;p&gt;It was at this point that I started scratching my head. If my needs go beyond the "give me everyone in my bucket" level of precision, can I optimize the traversal of the bucket inhabitants so that I can get the list of people in radar range &lt;em&gt;faster&lt;/em&gt; than &lt;strong&gt;O(n)&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;You bet you can, and this is where things get pretty awesome. If I organize the list of nav beacons in this bucket by the sub-region of space they're in, then I might be able to do a traversal that's cheaper or shorter than by calculating &lt;code&gt;n&lt;/code&gt; distance squares. &lt;/p&gt;

&lt;p&gt;Of course, organizing the items in a leaf bucket into a tree is really just the same thing as &lt;em&gt;making the root tree taller&lt;/em&gt; or more deep. Remember that any node in a tree is just another tree.&lt;/p&gt;

&lt;p&gt;I briefly mentioned earlier that another way you can model this problem is to take a "point list" (the locations of all the nav beacons in the universe) and then every single nav beacon becomes a leaf on this tree.&lt;/p&gt;

&lt;p&gt;Because every point in this tree is a leaf, the "hash key" now refers to only one coordinate in space. Coincidentally, this also means that your K-D tree implementation needs to handle multiple "things" existing in the same position.&lt;/p&gt;

&lt;p&gt;This is where, at least to this nerd's mind, things get beautiful. Now, to find the list of all nav beacons that are within some euclidean distance of a point of origin, this is just a graph traversal starting at the radar receiver's leaf, and collecting all nav beacons within &lt;code&gt;n&lt;/code&gt; traversal hops.&lt;/p&gt;

&lt;h1&gt;
  
  
  Transient Data Structures
&lt;/h1&gt;

&lt;p&gt;I want to make one more point before my bloviation comes to an end. This point is that all too often we just assume that data is stored in just one canonical way for its lifetime. This assumption creeps throughout our code and propagates needless inefficiencies everywhere.&lt;/p&gt;

&lt;p&gt;In the case of a k-d tree mapping a point region, this structure might not be optimized for keys changing. Mutating a k-d tree in place requires a re-organization of the entire tree.&lt;/p&gt;

&lt;p&gt;If a ship's position changes every frame, then it will be re-organized within this tree every frame. If all 1,000 ships are assumed to be moving, then what we really want to do is construct this k-d tree &lt;em&gt;anew&lt;/em&gt; at the beginning of each frame rather than incurring the re-sort/re-organization cost of each move during the &lt;code&gt;movement&lt;/code&gt; system frames. The point here is that given what we know of the data and the rate of change, it's &lt;em&gt;faster to build this structure from scratch&lt;/em&gt; every frame than it is to mutate it in place.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;In summary, my point here is that thinking of space and the objects within space from a human perspective led me down a horribly inefficient road. &lt;/p&gt;

&lt;p&gt;Thinking about space and the objects within it as data structures that are read-optimized or write-optimized for specific purposes means that my systems can now get &lt;em&gt;a lot&lt;/em&gt; more work done per frame, which means I can have more systems doing more interesting things in my simulation and I don't have to worry about them getting behind and exceeding their frame latency budget.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;p.s. - fun fact: &lt;a href="https://en.wikipedia.org/wiki/Open_Location_Code" rel="noopener noreferrer"&gt;Open Location Code&lt;/a&gt;s, also called "place keys" are just ascii-encoded traversal paths through polar coordinate sub-divisions of the planet!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>radar</category>
      <category>algorithms</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Invoking Functions on Distributed Game Objects</title>
      <dc:creator>Kevin Hoffman</dc:creator>
      <pubDate>Fri, 29 May 2020 15:52:30 +0000</pubDate>
      <link>https://forem.com/autodidaddict/invoking-functions-on-distributed-game-objects-37b1</link>
      <guid>https://forem.com/autodidaddict/invoking-functions-on-distributed-game-objects-37b1</guid>
      <description>&lt;p&gt;This is the second post in my series on developing a modern MUD using &lt;a href="https://wascc.dev"&gt;waSCC&lt;/a&gt; and WebAssembly; taking old-school monolithic concepts from the MUD worlds of yore and migrating them to the new, cloud-native, wasm-based future. &lt;/p&gt;

&lt;p&gt;I've found that writing posts like this &lt;em&gt;before&lt;/em&gt; coding helps me organize my thoughts and saves me some time when I get to the IDE. I like to call this method &lt;em&gt;blog-ahead compilation&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  LPC Function Calls
&lt;/h1&gt;

&lt;p&gt;In LPC, there are countless reasons why a block of code might need to invoke a function on another game object. This could be in combat to reduce hitpoints, it could be the code that changes the state of a set of armor from &lt;code&gt;unworn&lt;/code&gt; to &lt;code&gt;worn&lt;/code&gt;, a sword from &lt;code&gt;sheathed&lt;/code&gt; to &lt;code&gt;wielded&lt;/code&gt;, etc. We need to make function calls to buy things from stores, to send text messages to players, to flip quest bits when a player places an ancient relic in the base of a fountain. The list goes on. &lt;/p&gt;

&lt;p&gt;In the world of the single-process monolith, function invocation is pretty simple, and in LPC it looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;my_object&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;call_other&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In most variants of LPC that I remember, you were able to make function calls in either an OOP-like (the "arrow") fashion or the regular C style syntax.&lt;/p&gt;

&lt;p&gt;What's important to notice about this code is that the variable &lt;code&gt;my_object&lt;/code&gt; is an instance variable just like any other, and is sitting in memory directly in the monolithic process.&lt;/p&gt;

&lt;p&gt;If we need to invoke a function call on a game object in a world where game objects are &lt;em&gt;spread across a cluster of driver processes&lt;/em&gt;, then we need to re-think things quite a bit.&lt;/p&gt;

&lt;h1&gt;
  
  
  Managing Distributed Game Objects
&lt;/h1&gt;

&lt;p&gt;One possible way to deal with distributing game objects is to just simply distribute instances across a grid and then provide some kind of RPC plumbing to allow remote invocation. This means that for every single game object active in the virtual world, there is an instance variable consuming a stack pointer and heap memory somewhere in a process in the cluster. &lt;/p&gt;

&lt;p&gt;This feels inefficient to me, like we're reaching for the safety blanket of old techniques because that's what we're familiar with. The only reason we want to manage game object instances like traditional language primitive objects is because these things have &lt;em&gt;state&lt;/em&gt; exposed through simple fields or properties. In the cloud, we don't want stateful, long-running variables.&lt;/p&gt;

&lt;p&gt;Further, if each of these long-running stateful variables is actually a WebAssembly interpreter (since our user code is all wasm actors), that's a ton of duplicated overhead per game object. If we get to hundreds of thousands of game objects, this will absolutely not scale well.&lt;/p&gt;

&lt;p&gt;Instead, what we want to do is load the &lt;em&gt;prototype&lt;/em&gt; of the game object, and then provide per-instance data as parameters to each function call. This means that the prototype remains stateless, and every function call is able to be executed by the prototype (the actor wasm code). &lt;/p&gt;

&lt;p&gt;With this approach, we can have a single actor like &lt;code&gt;std/sword&lt;/code&gt; handle all function invocations for all of the thousands of instances of swords in the game. If the path through &lt;code&gt;/std/sword&lt;/code&gt; starts to get too "hot", then we can simply spin up more copies of this prototype on different nodes in the cluster and distribute load across them.&lt;/p&gt;

&lt;p&gt;If the function call needs state for processing, it'll query it from a K/V store or cache or get it as part of the call (those are optimization details I can worry about later).&lt;/p&gt;

&lt;h1&gt;
  
  
  Making Distributed Game Object Function Calls
&lt;/h1&gt;

&lt;p&gt;Recall that an instance of an object in an LPMud is a combination of its prototype and some form of unique instance identifier. Our distributed mudlib capability provider can keep track of the mapping between what the game calls a prototype (e.g. &lt;code&gt;std/sword&lt;/code&gt; or &lt;code&gt;areas/kevin/dragon1&lt;/code&gt;) and what waSCC calls an actor. waSCC uses URL-friendly encodings of &lt;a href="https://ed25519.cr.yp.to/"&gt;ed25519&lt;/a&gt; keys to uniquely and globally identify actors. Our mudlib will keep a mapping between the game prototype name and the public key of an actor, so that it can hide the complexity of those public keys from developers and convert a content-developer-friendly function call like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Sword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/std/sword#5672458"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;sword&lt;/span&gt;&lt;span class="nf"&gt;.wield&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;into code like the following that is safely hidden from game content creators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;public_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obid&lt;/span&gt;&lt;span class="nf"&gt;.pk&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;obid&lt;/span&gt;&lt;span class="nf"&gt;.instance&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// a value like ("MB4OLDIC3TCZ4Q4TGGOVAZC43VXFE2JQVRAXQMQFXUCREOOFEKOKZTY2", "562478")&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;RootGameObject&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;public_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Could do &amp;amp;RootGameObject::from_objectid(obid) as a shortcut&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt; &lt;span class="err"&gt;.&lt;/span&gt; &lt;span class="py"&gt;.

sword&lt;/span&gt;&lt;span class="nf"&gt;.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;this_interactive&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"wield"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt; &lt;span class="c1"&gt;// This is an RPC efun&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, the &lt;code&gt;call&lt;/code&gt; function would then forward an invocation up to the mudlib capability provider (running in the waSCC host process) and in turn execute the appropriate network code to find the prototype, build context, invoke the function, and return the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Note on Polymorphism
&lt;/h2&gt;

&lt;p&gt;I don't want to support inheritance in this MUD because wasm modules (actors, game objects) are intended to be treated as freestanding, portable units of compute. Trying to build inheritance into them would be an affront to WebAssembly, in my opinion.&lt;/p&gt;

&lt;p&gt;But, I do want to be able to treat things similarly and allow code to be shared. How do we deal with the fact that all weapons can be wielded? What if I want to make a scenario where a chair can be wielded or a cardboard box can be worn as armor? &lt;strong&gt;&lt;em&gt;That's a topic for an upcoming blog post&lt;/em&gt;&lt;/strong&gt;, because translating the flexibility of LPC's multiple inheritance hierarchies into freestanding WebAssembly modules without forcing a ton of code duplication is no small task. &lt;/p&gt;

&lt;h1&gt;
  
  
  Managing Per-Call Context
&lt;/h1&gt;

&lt;p&gt;When we invoke the &lt;code&gt;wield&lt;/code&gt; function on a sword, we need some context in order to properly deal with that call. This context is especially important because the actor in which this function resides is &lt;em&gt;stateless&lt;/em&gt; by design. &lt;/p&gt;

&lt;p&gt;We need to know &lt;em&gt;who&lt;/em&gt; wielded the sword. We also needed to know &lt;em&gt;which&lt;/em&gt; sword this is, and the values of all of the variables currently set on that sword.&lt;/p&gt;

&lt;p&gt;An absolutely &lt;strong&gt;crucial&lt;/strong&gt; aspect of LPC that I enjoyed so long ago is that wizards were able to be productive and create programmatic content without needing to know the underlying details of how the MUD and game driver worked. In my case, I spent months building an entire area with no knowledge of the intricate interplay between the mudlib and game driver, or what the difference was between library functions and external functions.&lt;/p&gt;

&lt;p&gt;If this actor-based wasm MUD is going to be successful, we need to be able to hide the irrelevant details so content creators can easily do their jobs.&lt;/p&gt;

&lt;p&gt;To keep the API clean, I don't want wizards to have to code things like &lt;code&gt;context.get_something("foo")&lt;/code&gt; over and over again, nor do I want them to know the details of how we're representing context internally. Instead, the context will be transparently set in a variable hidden in the mudlib actor API prior to the invocation of a function. If a function call needs context, then it can obtain it from the underlying variables.&lt;/p&gt;

&lt;p&gt;Let's take a look at some sample Rust wasm code that might be found in &lt;code&gt;/std/sword.wasm&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;public_functions!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;wield&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;wield&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Sword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;this_object&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ti&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;this_interactive&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ti&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"You wield the sword. Is it glowing??"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;say&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ti&lt;/span&gt;&lt;span class="nf"&gt;.third_person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; 
      &lt;span class="s"&gt;" wields the sword. It begins to glow!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="nf"&gt;.set_wielded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;em&gt;looks&lt;/em&gt; like super simple code, but there's a "metric crap-ton" of complicated things happening, and that's &lt;strong&gt;&lt;em&gt;as the world should be&lt;/em&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Feature developers should write simple logic, and boilerplate and plumbing belongs elsewhere.&lt;/p&gt;

&lt;p&gt;Let's take it apart step by step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;this_interactive()&lt;/code&gt; returns a &lt;code&gt;&amp;amp;dyn Interactive&lt;/code&gt;, a game object reference that supports core functionality, plus &lt;em&gt;interactive&lt;/em&gt; functionality (it can send and receive text). All of this is done inside the wasm module boundary through the mudlib API by accessing the thread-safe (actors are single-threaded) context that was hydrated prior to invocation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;write()&lt;/code&gt; sends a text message to the interactive thing (which could be a player or a game-controlled NPC). This creates a remote invocation request that will bubble out across the wasm boundary, through the mudlib &lt;em&gt;capability provider&lt;/em&gt;, across the network to the prototype for the current interactive object (e.g. &lt;code&gt;/std/player&lt;/code&gt;). Context is built remotely prior to invoking the &lt;code&gt;say&lt;/code&gt; function in the player prototype (which is a waSCC-hosted actor).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;say&lt;/code&gt; sends a text message to every object listed in the inventory of the room the wielder is standing in &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;this_object()&lt;/code&gt; is essentially the "self" reference, and is a &lt;code&gt;&amp;amp;dyn GameObject&lt;/code&gt; which is in turn automatically cast to &lt;code&gt;&amp;amp;dyn Sword&lt;/code&gt; via supertrait casting.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;set_wielded&lt;/code&gt; makes a call to the host's key-value capability to set the &lt;code&gt;wielded&lt;/code&gt; value of actor &lt;code&gt;Mxxxxx....x&lt;/code&gt; instance &lt;code&gt;12345&lt;/code&gt; in the distributed cache.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these functions could fail, which can in turn cause &lt;code&gt;wield&lt;/code&gt; to fail, which would eventually send a message to the player that typed &lt;code&gt;wield sword&lt;/code&gt;, which would ultimately be delivered via socket over the telnet connection (or web socket to the browser client).&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Building an elastically scalable cloud-native online multiplayer world is a &lt;em&gt;difficult&lt;/em&gt; thing. However, my hypothesis is that as developers building business functionality day in and day out in the cloud, we deal with a lot of the same problems. &lt;/p&gt;

&lt;p&gt;If we remain vigilant about hiding complexity from feature developers (in the case of our MUD, &lt;em&gt;wizards writing actors&lt;/em&gt;), then we can make the act of creating clean, crisp, secure, functional code an actual &lt;strong&gt;joy&lt;/strong&gt;, and maybe writing code won't suck as much as it does today.&lt;/p&gt;

&lt;p&gt;p.s. all of the code in this post is purely hypothetical, and will likely change radically once I sit down to code some of this up.&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>mud</category>
      <category>rust</category>
      <category>wascc</category>
    </item>
    <item>
      <title>WebAssembly in the Cloud - Will it MUD? ⚔️</title>
      <dc:creator>Kevin Hoffman</dc:creator>
      <pubDate>Fri, 22 May 2020 23:58:48 +0000</pubDate>
      <link>https://forem.com/autodidaddict/webassembly-in-the-cloud-will-it-mud-4g14</link>
      <guid>https://forem.com/autodidaddict/webassembly-in-the-cloud-will-it-mud-4g14</guid>
      <description>&lt;h1&gt;
  
  
  Overview of MUDs
&lt;/h1&gt;

&lt;p&gt;Throughout my career, one of the first things that I've done when encountering a new technology is ask myself whether this technology can be used to create a &lt;a href="https://en.wikipedia.org/wiki/MUD"&gt;MUD&lt;/a&gt;, a &lt;em&gt;multi-user dungeon&lt;/em&gt; (or &lt;em&gt;dimension&lt;/em&gt;). MUDs, at least historically, are multi-user, online, text-based adventure games. It's quite possible that there are some MUDs that are older than some of the people reading this post. &lt;em&gt;Just because a technology is old doesn't mean it's bad&lt;/em&gt;. I'm going to over-simplify a bit, but MUDs tend to come in two flavors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data-Driven - an &lt;em&gt;engine&lt;/em&gt; presents a gaming experience by reading from a fixed-schema set of data&lt;/li&gt;
&lt;li&gt;Code-Driven - a &lt;em&gt;driver&lt;/em&gt; (what we nowadays would call a &lt;em&gt;virtual machine&lt;/em&gt;) loads user/wizard-supplied code files on demand to provide the gaming experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I personally have no interest in the former. For the latter, the best example of a code-driven MUD is the famous &lt;a href="https://en.wikipedia.org/wiki/LPMud"&gt;LPMud&lt;/a&gt;. An LPMud has 3 core components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The game driver (virtual machine)&lt;/strong&gt; - This is a stateful process that runs on a host, providing a network interface and exposes a suite of "efuns" (external functions) to LPC code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The mudlib&lt;/strong&gt; - Code written in &lt;a href="https://en.wikipedia.org/wiki/LPC_(programming_language)"&gt;LPC&lt;/a&gt; that provides the foundation of the game, e.g. weapons, objects, economy, guilds, magic, rooms, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User (wizard) Code&lt;/strong&gt; - Code written in LPC by players of the game. This code utilizes the mudlib to create the virtual world in which players inhabit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LPC is a &lt;em&gt;blueprint&lt;/em&gt; or &lt;em&gt;prototype&lt;/em&gt; based language. Every file (e.g. &lt;code&gt;lib/weapons/sword.c&lt;/code&gt;) is a game object. If a game object can be &lt;em&gt;cloned&lt;/em&gt;, then multiple instances of the blueprint can exist in memory. In the case of a sword, the blueprint object is &lt;code&gt;lib/weapons/sword&lt;/code&gt; and a specific instance of a sword (the one my character is wielding that is worn and about to break, for example) might be &lt;code&gt;lib/weapons/sword#127&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before I get into how any of this relates to WebAssembly, let's take a look at a sample bit of LPC code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;inherit&lt;/span&gt; &lt;span class="s"&gt;"/lib/room"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;set_short&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a simple room"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;set_long&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A simple room in a simple building."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;set_description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This is a simple room in a simple building.  It is very nice."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;add_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"north"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/realms/descartes/north_room"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code might exist in a file like &lt;code&gt;areas/kevin/simple_room.c&lt;/code&gt;. It should be fairly obvious the benefits of having user-created code like this rather than admin-defined fixed data. This lets the game evolve over time and get more and more features that can be supplied by users rather than a single core developer.&lt;/p&gt;

&lt;h1&gt;
  
  
  waSCC Overview
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://wascc.dev"&gt;waSCC&lt;/a&gt;, &lt;em&gt;WebAssembly Secure Capabilities Connector&lt;/em&gt;, is a WebAssembly host runtime that dynamically binds cloud native capabilities to &lt;em&gt;actors&lt;/em&gt; (WebAssembly modules). The goal of waSCC is to let developers define pure business logic and deploy it in a small, secure WebAssembly module that is completely decoupled from the capabilities that satisfy non-functional requirements.&lt;/p&gt;

&lt;p&gt;As I was developing waSCC, one thought kept gnawing at the back of my brain: &lt;em&gt;can I use waSCC to let people write MUD code as wasm actors?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I think the answer is &lt;strong&gt;&lt;em&gt;yes&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  waSCC as an Evolution of LPMud
&lt;/h1&gt;

&lt;p&gt;Back in the good old days, an LPMud was a single process running on a machine to which players would &lt;code&gt;telnet&lt;/code&gt; in order to play. If we're going to build a modern MUD, then it needs to be a distributed, cloud-native system that can dynamically scale to handle changes in load. Thankfully, this is precisely what &lt;strong&gt;waSCC&lt;/strong&gt; is designed to do.&lt;/p&gt;

&lt;p&gt;Recall the 3 components of an LPMud:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Game Driver (VM)&lt;/li&gt;
&lt;li&gt;Mudlib (LPC)&lt;/li&gt;
&lt;li&gt;User Code (LPC)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;waSCC is a WebAssembly host, and as such is a &lt;em&gt;virtual machine&lt;/em&gt; that executes wasm modules. This means we can probably use waSCC runtime hosts as components of a distributed game driver.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;mudlib&lt;/strong&gt; is a core set of functionality that is securely exposed to user code that provides foundational building blocks for creating virtual worlds and game experiences. A waSCC &lt;em&gt;capability provider&lt;/em&gt; seems like an ideal way to provide a mudlib. User code could make requests of the mudlib to do everything from set state (remember this is a distributed system, state isn't local to a process) to communicate with players, trigger weather events, initiate combat, and much more.&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;user code&lt;/strong&gt; in an LPMud is written in LPC. User code in a waSCC-based MUD would be written in &lt;em&gt;any language&lt;/em&gt; that compiles to a waSCC-compliant actor &lt;code&gt;.wasm&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;As a thought experiment, let's take a look at what it might look like to re-write the previous LPC example as a Rust-based waSCC actor (for information on creating waSCC actors, check out &lt;a href="https://wascc.dev/tutorials/first-actor/"&gt;this tutorial&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[macro_use]&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt; &lt;span class="n"&gt;wasmud_mudlib&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;mudlib&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;gameobject_handlers!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nn"&gt;mudlib&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;msgs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;mudlib&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;msgs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CreateMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HandlerResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;mudlib&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;room&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Perform default room setup&lt;/span&gt;

    &lt;span class="nf"&gt;set_short&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a simple room"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;set_long&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A simple room in a simple building."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;set_description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This is a simple room in a simple building.  It is very nice."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;add_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"north"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/realms/descartes/north_room"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks pretty similar to the original LPC code, but what you &lt;em&gt;don't&lt;/em&gt; see here is that because this is a WebAssembly module running under a waSCC host, it's automatically getting enterprise-grade scalability and security and a pile of other features.&lt;/p&gt;

&lt;p&gt;We can continue down this road and see what it might look like for the room to clone an NPC and move it into the room upon creation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;mudlib&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;msgs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CreateMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HandlerResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;mudlib&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;room&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Perform default room setup&lt;/span&gt;

    &lt;span class="nf"&gt;set_short&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a simple room"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;set_long&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A simple room in a simple building."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;set_description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This is a simple room in a simple building.  It is very nice."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;add_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"north"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/realms/descartes/north_room"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dragon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;clone_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/npcs/dragon"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;dragon&lt;/span&gt;&lt;span class="nf"&gt;.move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;this_object&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cool new stuff here is &lt;code&gt;clone_object&lt;/code&gt; and the &lt;code&gt;move&lt;/code&gt; function on the &lt;code&gt;dragon&lt;/code&gt; variable. In traditional LPC, since it was running in a single monolith, code like this would directly instantiate the &lt;code&gt;dragon.c&lt;/code&gt; file by running it through the VM interpreter and then immediately add the dragon &lt;em&gt;reference&lt;/em&gt; (e.g. &lt;code&gt;/npcs/dragon#1284&lt;/code&gt;) to the room's &lt;code&gt;_inventory&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;This code, by virtue of running under waSCC, is &lt;em&gt;far more powerful&lt;/em&gt;. The &lt;code&gt;clone_object&lt;/code&gt; function will ask the mudlib provider to instantiate another actor (&lt;code&gt;/npcs/dragon.wasm&lt;/code&gt;). Our user code does not care &lt;em&gt;where&lt;/em&gt; or &lt;em&gt;how&lt;/em&gt; this dragon is instantiated. Next, calling &lt;code&gt;move&lt;/code&gt; on the dragon will ask the (distributed) mudlib to move the dragon into this room, triggering all appropriate real-time events and dealing with all the ugly things in the background like replication, eventual consistency, etc.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;In conclusion, it is my hypothesis that we can use waSCC, actors, and secure capability providers to create a MUD that lets players write code that looks and feels as simple as the original LPC, but automatically deals with running in a distributed, dynamically scaling, multi-user environment in the cloud.&lt;/p&gt;

&lt;p&gt;I would love to hear your thoughts on this as a potential project. Do you think it's a good idea? Should I continue a series of blog posts as I attempt to write some of this MUD in waSCC? Let me know!&lt;/p&gt;

&lt;p&gt;To stay up to date, you can keep in touch with me on &lt;a href="https://twitter.com/KevinHoffman"&gt;Twitter&lt;/a&gt; and you can check out the &lt;a href="https://github.com/wascc"&gt;waSCC&lt;/a&gt; organization on GitHub.&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>mud</category>
      <category>rust</category>
      <category>wascc</category>
    </item>
  </channel>
</rss>
