StoneHearth (Alpha 14)

image

I have been playing a very cute game:  StoneHearth.   I paid $24 for it on Steam, its in Very Early stages, and I don’t regret the purchase.

However, be aware that, as it stands right now, its not very challenging once you learn how to stay alive.

I put together one farmer (prevent starvation) and one footman (prevent death by first attacker), and then mostly left the game alone after that, and … everybody lived.  Overnight.  I’m sure they would have died of cold eventually as the seasons changed, if that were implemented.   But as it is, the game settles into a sustainable state, doesn’t devolve into chaos. 

Comparatively, I left City : Skylines running overnight and it did descend into chaos.  How?  by the one simple rule of “no-auto-bulldoze-condemned.”  It’s the one thing that left unmonitored, will destabilize everything.

Also, if you do silly things like dig tunnels to then fill with water, some algorithms crash (you can see some of that above) and stuff and things generally go haywire and people stop picking up stuff etc.  Performance and Bugs.

The concept, though, is solid.   I love watching the little hearthlings do their little lives.. I guess this is what the Sims was like.

The build tree took a little getting used to.  I couldn’t find a nice graphic on the web, so I tried making one in LucidCharts:

However, LucidCharts (Pro) does not appear to have an auto-re-flow option, and if I started getting the level of detail I wanted .. it would not have worked.

What other options do I have?   A little google searching found:  http://bl.ocks.org/d3noob/5141528, So I downloaded that code, and plugged in my own CSV file.   But ran into cross-origin problems.

So then I went with http://jsfiddle.net/skysigal/k3kdeu9L/ which I forked into my own .. http://jsfiddle.net/roLmyovw/2  :

image

Which is just not quite pretty.  Not as pretty as this kitten, anyway:

image

Which is my Princess Fifi Toupee.  She kept trying to step on the keyboard as I wrote this post.  https://www.instagram.com/p/BB27Zh1Fvko/?taken-by=mollymcmahan

So, I think I’m giving up on this game for now.    I played it for 8-9 hours.    Maybe not the best return, but I suspect I’ll play it again in the future.

dotnetmud: Hitting a wall on clients, hubs, and games

Till now, I’ve had this pretty simple layout:

The browser fires up a signal/R client, which connects to a signal/R server, which talks to a driver, which talks to a game-specific engine.

One signal/R client maps to a user in the game somewhere.

This Situation is not Covered:

You are standing in a spaceport

You see:

a ship

>> board ship

You are inside the ship.  you can ‘launch’ to launch the ship.

>> launch

 

At this point, something happens that tells the client “hey, start this other client up” – possibly in a new tab.    Maybe it leaves the current tab in place. The new client connects up to its own hub, with its own mudlib, and does its own kinds of commands. The user can then fly the ship around in space.  The space stuff doesn’t know that the ship is also a “mudlib” object.

This could also be used with Shop Transactions, or a Game of Uno, or whatever – custom client for custom situation, in the same user’s session.

What this Means

a) I need a different sort of Auth mechanism to bind the user to an Identity.  I think I’ll probably go ahead and use the stock website’s authentication methods to get myself an actual UserIdentity;  I don’t know if that would flow down into any signal/R client or not.

b) Every user can have MULTIPLE clients going on at any point in time.   

This is making my head hurt.  I’ll let it percolate.   For now, no cross-jumping between clients.

HOWEVER, I do want to move the <T> that I currently have on the Driver so that the Driver stands alone, and the Signal/R Hub is the one that knows about the mudlib GameSpecific. 

(dotnetmud) spacegame: accelerating to a planet

I shook some dust off some old braincells, and re-remembered some algebra.

My quandry, as hinted by previous post:  GIven that I’m 42000 units away from the planet, and I have a max acceleration of 100 units/(sec^2), how much do I accelerate in the direction of the planet?

Some googling finds this:   https://van.physics.illinois.edu/qa/listing.php?id=116

d = vt + (1/2)at2

I know my distance, 42000.  And I know my a, 100.   What I need to calculate is v.  But not the one in the equation – that’s starting velocity.

Reverse it.  At the planet, starting at v=0, what’s my final velocity when I get to distance d?

The velocity is v = at.  So if I can solve for t, then I can plug that in.

d = (1/2) att

tt = 2d/a

t = Math.sqrt(2*d/a)

v = a * Math.sqrt(2*d/a).

Check the numbers in excel.   I set it up like this:

image

And plug in the formula to see how well it calculates speed:

image

The drift is due to the coarse 1 second time interval on the calculations, I’m pretty sure.

 

So, the answer is, if I’m 42000 u away from the planet, and I can thrust at 100 u/s^2, I want to be going 100 * Math.Sqrt(2*42000/100) = 2895 units/sec in the direction of the planet.

  • If I’m not going this speed, I need to boost in the direction of the planet.
  • If I’m going faster than this speed, I need to boost in the other direction.

To make up for inaccuracies, I’ll set the target velocity to match, say, 90% of my actual available acceleration.

I’m not accounting for my initial velocity at all, even if its not in the right direction.  The point is, at any point in space I can caluate what my velocity should be, and what direction it should be in, for the fastest approach to the planet.  Whatever I’m doing, change to match that.   It should be a nice curve, followed by some nice acceleration, followed by a turnaround, and then some deceleration with some waggles. 

Looking forward to implementing it.  No time tonight, so I just blogged about my resurrection of Physics 101 instead.   Super-excited.

DotNetMud: SpaceGame: Autopilot

After an aborted run at Rares Trading in Elite Dangerous (idea: pick up rares, go to Fehu, sell them, and then pick up missions there.  Problem: takes many hours to get enough worth selling), I took a look at writing an autopilot in my javascript space game (the part that is not yet Mud-like, but I intend for it to be).

Nice: Javascript has a Math.atan2(y,x) which _possibly_ avoids the x=0 problem that normal Math.atan() solutions do.  (arctangent gets you the angle to something so you know where to point the ship).

However, my code doesn’t work.  My ship very often points AWAY from the target, and applies FULL THRUST FOREVER.  This is NOT how you go somewhere.

There’s another aspect – I’m simulating “keyboard control”, ie, IsThrusting, IsLeft, IsRight.   For the ship to feel responsive when playing the game, need to have good numbers for these.  But with autopilot, there’s a lot of jigger (LRLRLRLR) because it continually overshoots its target.

So, here’s what I have to do for the relatively final solution:

  • Set up the ship so that there’s a finer gradient of control.
    • What I’ve seen other games do is, the longer you have it pressed, the more thrust you get, up to max.
      • This means I need to swap out my current keyboard handler (keyup, keydown) to change to a dictionary of “when was it pressed”, so that I can calculate how long its been held.
    • Or, I could go with W = 12.5% thrust, Ctrl-W = 25%, shift-W= 50%, and ctrl/shift = 100%.  Almost 8 stops.  More instantaneous full thrust available.
      • I want to avoid something where the autopilot can take a shortcut that’s not really available to a player.   So if I did the slow build up, I’d have to have the autopilot also do a slow build up.
  • Change how I do the maths for the autopilot.   Inputs to autopilot:  Who to go to, and what distance to orbit them at when we get there.
    • I see a few major layers.
    • First one is “close the distance”.   This would use the calculation of … http://physics.info/motion-equations/  … ouch, my brain hurts.   Basically, I need to find a solution for:
      • If I start at the orbit distance, and accelerate away at 75% thrust, what velocity am I at when I get to my current distance away?   Reverse that.  That’s the velocity towards the object that I want.   Call that V1.  I want it to shut off as I get close to the destination so that orbital stuff can kick in.
    • Second one is orbital force.   Skip this if I’m more than 2x the desired distance.
      • Figure out if I’m going clockwise or counter clockwise from the destination.  OR, just assume one direction for now.  clockwise.
      • Figure out the vector I need to be in a perfect circular orbit around the object at the desired distance.   Magnitude is known (previous post on orbital mechanics has link to the article), and Direction is 90 degrees from where the destination is.
      • That’s my desired vector V2.
    • Combine V1 and V2.  This is my desired vector V3
    • Look at my current vector V4 and figure out the change that needs to happen V5 = V3-V4.
      • Do a left/right thrust as needed to point me at that vector (do a smoothing function here).
      • if I’m pointing in relatively the right direction, do a thrust along that vector (do a smoothing function here).

This could be really fun.

Image: wikipedia

When Maths goes right

I found out I had been doing gravity wrong.

This is what I was getting:

image

There seemed to be gravity, but it was messy.

I had been using the good old (G*m1*m2)/(r^2) equation.   However, in an effort to be smart, I calculated the (x2-x1) * (y2-y1) to be the (r^2) value..

WHICH IS TRUE.

And when you apply that force to an object of mass m1, the m1 disappears (F=ma; a=F/m) and you get the acceleration, the pull of gravity.

But, the kicker is, I then have to scale the normal vector out by that.   And the normal vector is…  just the x component .. is .. (x2-x1)/r. 

When you do the whole thing, the acceleration felt is proportional to 1/r^3, not r^2.

So I did that.  And I pulled out the gravitational constant, G, to use elsewhere (turns out you can calculate orbital velocities and periods as well). 

The result:

image

No matter where you start, no matter your initial velocity and direction (within reason), you get a nice orbit.

What’s more, I could use the maths where “velocity at distance r” can be calculated, as well as “radians per unit time” can be calculated, for a circular orbit.

This means, I could write an autopilot to get you in a circular orbit around a star or planet at a particular distance pretty easily.  I think.

However, I also found out that due to gravitational effects of planets,  it was very easy to get swept into the sun.. and then gravitationally flung out of the solar system.

So, I changed it when you get within the radius of a planet, gravity is about constant – like it would be at the surface.  “Airbrakes”, as it were.  

THIS HAS PROMISE!  I spent probably an half hour flying around in this simulation, gravity made it so interesting. 

source: https://github.com/sunnywiz/dotnetmud2015/blob/e5db82581382e43a721f0abc4a5c45710ed7fee4/canvasTest/solarSystemFlight.html

it needs one image from the same directory.  Otherwise, just run that file.

dotnetmud: space: gravity

image

playing with Html5 Canvas – doing a control loop with thrusters (blue) and rotation control —   adding in two fixed points which have gravity.

I’m using m/(r^2) here .. its not quite right, as the two objects are not orbiting each other.  I can’t get it to orbit nicely Smile 

I turned off the “clear canvas” bit so that the paths could be seen.

The red bits are drawing of the force lines due to gravity calculations.

dotnetmud: where to go next

As of https://github.com/sunnywiz/dotnetmud2015/tree/blog20160110, I have the following things working:

  • User logs in and provides a name.
  • User can move back and forth between two rooms (room directions are hooked up)
  • User can ‘look’ to see what’s in the room.  They will see other users there if they are there.
  • User can ‘say’ something in a room
  • User can ‘who’ to see who all are logged in
  • User can ‘shout’ to send a message to everybody regardless of which room they are in.

I am now at a crossroads.  There are many directions I can go.  I’m crossing things out as I decide that they are not the priority:

1. Develop the “mud” as a communication mud more:

  • Continue with all the communication stuff –  tell, emote.  
  • Add aliases for commands, like ‘e’ for east and ‘ for say and : for emote
  • Fix the say and shout so that the original command line is available rather than string[] arg (ie, I’m loosing whitespace)
  • add the Id() system so that objects can respond to nouns, so that ‘look <personname>’ works
  • Add last activity timestamp to user so that can detect idle time and show that in the who list
  • Show which room the user is in, in the who-list.

2.  Add in realms

  • Users can.. hook up a pointer to a git url ?  to point at their realm code. 
  • Mud sucks the code down, compiles it, loads/unloads appdomains, etc.
  • Might have some hidden difficulties here around MarshalByRefObj type stuff.
  • Maybe there’s an intermediate stopping point here – where I appdomain-unload-load the rooms that the users use as Lobby.

3. HTML/Pretty the mud

  • Right now the text being displayed to the user is all mono-spaced, no HTML allowed.
  • I could change that so that HTML was allowed.
  • As you enter a room, a picture of the room shows up.  
  • People get gravatar icons next to their names.
  • Add fun emoticons and stuff.
  • Who is shown in a table.

4. Clean up referencing

  • Move “driver” stuff into its own assembly.  Gets a DriverObject.  This does ObjectID and TypeURI stuff, and knows about IInteractive, and talks to the Signal/R Hub, but that’s about it.
  • Move “mudlib” stuff into its own assembly.  Gets its own MudLibObject which inherits from DriverObject.
  • clean up who references who, who finds who.   Use the .config file more to provide the links going in the wrong direction.
  • Move some stuff (like “inventory”, and “moveObject”) into the mudlib, rather than at the driver level.   These are text-based game things, and would not be (as) applicable for a Space-2D game.
  • Wrestle more with “should I directly map hub commands to the mudlib”, or make all communication with the hub generic.  Latter is more painful, but would work with more gametypes without changing the driver.

4.5 Deploy as a website to Azure

  • RIght now, it’s a console app.   Convert it to be a full website, which runs the hub in the background
    • I don’t know how Azure’s “free hosting” will work with a signal/r hub which wants to stay instantiated.   May have to put this on a paid plan
    • Luckily my work gives me an MSDN account now, and there’s free azure money there that’s use is or loose it.
    • Maybe put some stuff in like a welcome page.
    • Maybe do some integration with your identity as you log in coming from the MVC side rather than entirely in the mud.

5. Deal with Polling

  • For this, I’ll change the client so that it has panels:
    • One for “where you are”
    • One for “what you see here”
    • (future) One for your inventory
    • And then an updates window where “stuff” happens.
  • The poll cycle will be, once every X, if something has changed, refresh the where-you-are and what-you-see-here windows.
  • Additionally, for each user, give them a “how long they have been idle” thing on their short description
    • The poll should detect these changes and feed them down correctly.

If I get the above stuff done – definitely 4 and 5 – I think I’ll be in a place where I can start working on my 2D space game.

One day at a time, one session at a time.

DotNetMud: user verb actions, rooms with directions

image

  • This is a screen capture of my two browsers logged in.  Follow the arrows for when what happened, and you can see the messages delivered to the other player.

Implementation Details

There is now a structure by which items can state that they handle various verbs that the users could type in.   I use a JIT lookup to figure out what verbs are available to a player – verbs may be sourced from things in their inventory, in themselves, in the room they are in, or from other objects in the room they are in.

image

image

image

I created some more plumbing so that rooms are now aware of other rooms and can get directions to go to those rooms.

image

As a result, I added a tell_room driver level thing to make communication easier.  However, it needs to be updated to handle different messages, one for the person doing the action, and one for everybody else in the room.

Difficulties

The original mud was a single-threaded thing.  So whenever a command was executing, this_player() was “who was the command running for”. 

My version is multithreaded.  I have to pass around a lot more information – hence the “user action execution context” uaec above.  I had to know who the player was, what the verb was that was executing, etc.   There were several instances where I was using “this.SendOutput()” and the result was that user “Sunny” got messages intended for user “Bunny”.

I keep running into this problem – that I have to pass around “who the current player is”.  This will probably become a generic “execution context” like HttpContext is in web apps.

I also know that the verb system I have in place won’t work when we get monsters.   We need the ability to have a monster override a user’s ability to go in a certain direction easily.  The way this was done in the past was, the monster would override “east”.  In my current setup, this would not work as the dictionary of verbs wouldn’t get refreshed.       Then again, I’m leaving this whole verb things as a “Sample Mudlib” implementation, not part of the driver – all the driver does is get a command to the right user object and its done.

I also know that I need to create a MyStdObject that’s specific to the implemented mudlib.

Where Next

Probably the global player list – who – shout – say, emote, tell.

Possibly switch the client to be true HTML rather than monospaced font.    Philosophical question if I should do that or not.

And then, the hard bit:   Adding polling cycles.

If I can get polling cycles working here, then I’m ready for the space game version.

Code since the last blog post:    https://github.com/sunnywiz/dotnetmud2015/compare/7da38a6f…2497ec8

DotNetMud: Driver finding objects, singletons, etc.

image

 

In the original LPC land, the driver was the only way you could create an in-game object.  Along with this came several little things like:

  • The driver knew where every object was.
  • you could say new_object(“/path/to/object.cs”) and that’s how the driver knew where to grab its source.
  • the created objects were of two flavors – “/std/room/lobby” for example was the room that everybody would go to, but if you did a new_object on it, you’d get “/std/room/lobby#45”, which was a different object.  (this is called “prototyping”, and is also used by Javascript and Ruby)
  • you could USUALLY refer to an object by this string that represented the object.
  • Because of this deferment (string became an object), not everything in the mud loaded at the same time – there was some JIT loading going on.
  • The code was compiled at that point, so you could change the definition of the object and then create a new one of it.

In my DotNet world, I’m not limited by who can create which objects.    What to do?

Solution #1 – Don’t Manage it

Don’t Jit-Load anything.  If users want a singleton, they have to implement Instance.   All assemblies are loaded into the same appdomain. To change code, have to restart the mud.

This is doable, like a Diku, but not where I want to go.   Writing that Instance stuff over and over gets old.    Granted, there’s all kinds of C# stuff you could do, but the target audience for LPC was beginner programmers and game designers, not code poets.  Less code the better..

Solution #2 – Overmanage it

I could go with “all code is on disk and I run the compiler against it to generate it and then suck it in”.   Not going there yet either.

Solution #3 – Put in a layer of Find_Object etc.

This is the route I went. 

  • I decided that rather than “/path/to/object.cs”, I’d use a URI scheme. 
  • I’m using “builtin://TYPENAME” as my current implementation of “yo, go find me an object”.
  • I’m giving two different methods in the driver – one to find a “singleton” (if it already exists, reuse it, else create it), and another to create a new one every time.
  • I’ve set up some internal properties in StdObject that (supposedly) on the driver (and other responsible code) should set.

What I’m doing is leaving open some possibilities:

  • realm://sunnywiz/classname   — this could be a per-wizard realm pointer.  maps to an assembly, that might be loaded into an appdomain.  (appdomain = .Net version of forget this code and reload it)
  • persistent://DotNetMud.Mudlib.Room/WizardingHallway57 – this could be a stub that creates a standard thing of sort and then rehydrates it based on a tag stored in a database.

I’m also not saying “Everybody must use the driver to create their in-game objects.”  No, I’m saying “if you want to use the driver, you can, and I’ll track things, but if you don’t, I can’t guarantee I can keep track of it.”

The code referenced by this blog post is at this diff:  https://github.com/sunnywiz/dotnetmud2015/compare/blog20160106…blog20160107

Here’s some of it running:

 image

DotNetMud: Its Alive!

Code: https://github.com/sunnywiz/dotnetmud2015/tree/blog20160106

Heading back home today, vacation is about over.   For my little pet project, its been a nice little run.  Here’s what I got done:

image

  • Two different browsers
  • Logging in as two different users
  • Input_to() is implemented to get the user’s name.
  • I have a standard room object to house the players
  • the players each have their own mud-object
  • I’m currently hardcoding the verb/action stuff, only does look()
  • Using Signal/R as the transport between client (browser) and server

Server side tour:

image

Mudhub

This is the Signal/R Hub.  It currently only has two methods / routines / channels – SendOutput and ReceiveInput.  It deals with new players connecting.

It tries to offload everything it can to Driver.  

Driver

Driver is what used to be the driver (efun) level stuff in the old LPC muds.   Its where these kinds of things live:

  • What’s the list of players?
  • send a message to a user
  • find me an object matching a string X  (eventually)

However, Driver does not pretend to know what kind of mud you want to write.  So for that purpose, it relies on IGameSpecifics – which I only have one implementation of – to deal with things like “what object do players use” and “what to do with a new connection”.

IGameSpecifics / SampleGameSpecifics

As mentioned above, this is effectively “master.cs” from the LPC days.   However, there’s not a lot of stuff in it about permissions, and stuff like that, as we’re not yet compiling C# code on the fly.

MudLib

These are all the things that would go into writing your own mud.  I have a standard room and user object, and a single room (Lobby).  The code for “look” is currently built into User, that will need to move out sometime.

Where to go

There are many places left to explore in this little codebase:

  • Standard rooms don’t yet have directions going to other rooms.  That’s probably the most important next thing.
  • Putting in a verb structure so that players, rooms, and objects in a player’s inventory, all get a chance to put in their own verbs.   (there’s many ways to optimize this, I’ll probably brute force it the first time)
  • There definitely is NOT any on-the-fly compilation going on.   Everything is precompiled.
  • I don’t have a method in place to covert a reference like “/core/Lobby” to an actual in-game object.  I have to make some design decisions there.    Do objects claim URI’s, or do I use the URI to detect where the code is at, or ..  ? This affects the next thing –
  • There is no database backend or persistence.  And there probably won’t be, because that’s not where I want to go, this is a sample.
  • There are player disconnections to be handled as well, and reconnections.
  • Once a verb structure is in place, there’s going to be ID() stuff where swords can say that they are the sword that needs to be picked up, for example.

Uh oh, time to go.   Lunch with the family.