scionaltera / agony-engine Goto Github PK
View Code? Open in Web Editor NEWA modern, web based, procedurally generated MUD.
Home Page: https://agonyengine.com
License: MIT License
A modern, web based, procedurally generated MUD.
Home Page: https://agonyengine.com
License: MIT License
As a player I would like to retrieve an item from a container that I have placed it in so that it is not lost to me forever. The container must be in my inventory.
Syntax:
GET <item> <container>
Remove this parameter from the codebase. It is no longer necessary once players are being placed via start locations.
Investigate leaving Codeship for AWS CodeBuild, CodeDeploy and CodePipeline so that there is a complete continuous delivery pipeline that will automatically push freshly baked Docker containers to the ECS cluster.
The map generator will need a selection of a few "regular" tiles to choose from when it flood fills the map. In this case, something like this should work:
Create a tile flagged as IMPASSABLE
. These will be generated around the edges of the map to make it feel less square. Description doesn't matter since nobody will ever see it.
The name of the MUD should be configurable in application.yml
.
All places that show the MUD's name, such as the FTL templates, need to be updated to pull a value from the configuration.
When the map generator creates the first new map in the game, it should place one start location in a randomly selected, accessible room.
It used to work before I added inventories... 🙄
Now when it tries to delete the Actor
it's still associated with a GameMap
and can't be deleted. This relates to #91 and the solution to that issue should also solve this one.
Add some fields to Actor
to be able to track changes more easily.
All these fields should be NOT NULL
, so the migration will have to fill in values for existing rows.
Right now SAY is the only channel for communication and it's kind of hacked in. What we really need is channels as a first class thing with options for how messages are distributed. The set of channels I have in mind is:
SAY -> send to everyone in the same room as you
SHOUT -> send to everyone within a radius of 5(?) rooms
GOSSIP -> send to everyone in the game
TELL -> private message to one other person
ADMIN -> jury is out on the name, but only send to other admins (when there is such a thing)
Ideally the channels should be configurable somehow. Doesn't necessarily need to be via commands inside the game at this point, but through Spring config or a repeatable Flyway migration would be fine.
Somewhere in the production infrastructure there's an idle timeout. Not sure what is doing it yet, but after about 10 minutes the client's connection to the broker gets disconnected. :(
As a player I would like to put an item into a container so that I can better organize my inventory. The container must be in my inventory.
Syntax:
PUT <item> <container>
I keep hitting tab accidentally because I'm so used to tab completion in the shell, and it ends up kicking me back to the account screen. Not sure if it's possible, but it would be good to block the TAB key and just swallow it for now so you don't accidentally get out of the input box. (In the future I'd like to implement tab completion for commands, but that's out of scope for now.)
A simple command that displays the current software version and possibly the server start date, which you can get from ApplicationConfiguration
. Would be helpful to tell whether your change has been deployed yet on the server you are connected to.
As a player I would like a way to give an item directly to another player so I don't have to drop it on the ground, which could give an unintended player the opportunity to grab it.
Usage:
GIVE <item> <target>
The client seems to disconnect immediately on safari on iPhone. No greeting is shown.
It would be really handy if the title in your browser tab would update when you receive messages while the tab is out of focus. That way if someone logs into the game and talks to you while you're looking at something else you'd have a quick notification to let you know to check the game.
When you create an account or just log in the workflow takes you inside the game at the end. If you close your browser and come back, your session will recognize you and keep you authenticated but there is no way to get back in the game. There ought to be a "Play" button next to the "Logout" button that takes you back in, since you're already authenticated.
As a player I want the items in my inventory to be there after I quit and return to the game so I don't lose my stuff.
The game currently makes you drop all the items in your inventory on the floor before you leave the game, because the GameMap
that represents your inventory is cascade-deleted from the database when your Actor
is deleted. Instead, it would be great to be able to keep your inventory around and reattach it when you come back to the game.
"Fuzz" the edges of generated maps by filling in some random IMPASSABLE
rooms to obscure the square shape of the map for players. Don't create any inaccessible pockets and don't block off too much of the map.
This seems to happen a lot, both on the real game and locally, and it's pretty annoying. The client is good about reconnecting automatically but I'd like to actually get it fixed. I suspect it's actually a bug in ActiveMQ or SocksJS rather than something wrong with the MUD's code. There might be something I can fix through configuration in ActiveMQ, or something like that though.
I'm opening this issue to track any information leading to an answer.
The MoveCommand
needs to respect the IMPASSABLE
flag and not allow movement into blocked off rooms.
It turns out that Java has a mechanism to handle flag values, and I didn't have to roll my own. Here are the various pieces that need to be addressed:
WearLocation
and BodyPartCapability
are already enums but the places where we're using my Bitfield
need to have that replaced with EnumSet
.long
values (as we already do) and Apache commons EnumUtils
in an AttributeConverter. The Apache EnumUtils
appear to use the enum's ordinal which is not a great idea, but my current implementation is doing that too. Best case would be to move to a new solution that doesn't use ordinals. Instead, the enums could possibly define their own integer constants between 0 and 63.ChRoNoN's answer on this SO question is a pretty interesting approach.
See also KeaganFouche's answer here.
The second word in a sentence must be a noun (until we add modifiers). Refactor the command interface to accept the noun binding result rather than a list of tokens.
Since we don't have items or NPCs yet, nouns must refer to players. So... try to bind the nouns to players.
Now the game will support very simple commands like: LOOK SCION
Consider the following situation carefully: it would be very cool if a command could specify as part of its contract what it wants as arguments. What if the HIT command could specify HIT <logged in player in same room> instead of only HIT <player> as its valid syntax? Then the command parser could not even bother invoking the command if the noun didn't match precisely, and still generate a useful message like "Sorry, that player isn't in this room." instead of building all the error cases into every command. Doing this right will eliminate the need to write thousands of lines of boilerplate error checking.
Bind the first token in each input sentence to a command. Once the binding is complete, the command executor should pass the remaining tokens into the command to be executed. If the binding fails to look up a command, show the user a helpful error message.
If a user's input has been broken up into multiple sentences, each of those sentences should begin with a verb: GET SWORD THEN EQUIP SWORD THEN KILL GOBLIN -> GET SWORD. EQUIP SWORD. KILL GOBLIN.
The output from binding should be a new object that either contains or copies the value of the original token and contains a mapping to the command that should be executed. Later on, binding for nouns will also generate result objects (mapping tokens to the various objects in the game world) so when designing these objects, consider extensibility as an important factor.
For unauthenticated connections the request for the favicon gets redirected to the login page.
It is currently possible to log two sessions in using the same Actor.
The desired behavior is that logging a character in from a second session will "reconnect" it, closing any prior sessions. That way if your session does become disconnected you can connect back to it, but you shouldn't ever be able to get your character into the game more than once or control the same character from more than one client.
Note to myself to rewrite my AWS infrastructure for the ECS cluster that runs The Agony Engine in CloudFormation, and make it available with the project.
As a user that already has an account I would like to change my own password to maintain my account's security.
Commands have two parts:
The interface should, for now, accept a list of tokens as arguments. We have a little bit of a bootstrapping process we have to undertake here. The current interpreter tokenizes and does some basic sanitization of input. A later stage will map the tokens to parts of speech (verb, noun, modifier, etc.) and attempt to validate against a simple grammar. Then (still before the command has seen it) it will bind each token to an object. Verbs map to commands, nouns to objects in the game. Modifiers help guide the object lookup for nouns (i.e. "GET BLUE GEM" or "GET BEST SWORD"). The binding process will have to either wrap the tokens or convert them into different objects and the result of that is what would eventually be passed into the command. We don't have any of that yet, so for now we'll just take the tokens directly and refactor later.
The metadata allows for multiple names to be mapped to the same executable code. A good example for this would be the movement commands (N, E, S, W, U, D). There are a bunch of these commands but the code that runs could be exactly the same, just with a parameter to specify which direction the command moves you in. There's no reason to copy/paste six different classes for this. Another example could be HIT vs. KILL vs. ATTACK and any other synonyms for "try to kill the target". We probably want to map all those words to run the same code but we don't want to duplicate the code; just the pointer to the code.
Metadata should also let us sort the commands, first by "priority" and then alphabetically. We want "n" to map to NORTH, not to NOD or NAP. Eventually it will also be nice to have those mappings be configurable by admins inside the game at runtime, but that's out of scope for this ticket.
The build now has a message saying the dependency checker is out of date. Need to update the version and verify that the build still works with the new version.
Players can play, but messages generated by other players (e.g. SAY or movement) isn't being broadcast so it's effectively single player.
In MoveCommand
the first thing it needs to do is check the Actor
to see if it is capable of walking. This check is going to be repeated frequently for all sorts of things as more and more capabilities are added. It would make a lot of sense to turn it into an annotation on the command's invoke()
method. That way the InvokerService
could perform the check in a generic way before ever invoking the command method.
Make a token representation of a quoted string so that a command may implement invoke(QuotedString)
instead of just invoke()
. This will work toward supporting commands like SAY, TELL and GOSSIP.
You can see this happen with PURGE: there are two implementations of invoke()
and it's supposed to try binding your arguments to each implementation, find the best match and run that.
What actually happens is it tries to run both and displays both an error message and the successful output from the command. Less than ideal.
Another more subtle issue here is that there's no way to tell PURGE that (for example) you'd prefer it try to bind to items in your inventory before items on the floor. What if there were items that match your argument in both places? Which one is it going to choose first? The answer right now is that it's completely arbitrary and up to Java reflection to decide!
So there are two acceptance criteria for this issue:
invoke()
implementations could successfully bind.Currently if a command throws an exception there is no feedback to the user about it. They don't even see a new prompt, so it's unclear what happened or why. We probably don't want to show the text of the exception, but we should at least show a message saying something like "Oops! Something went wrong!" and give them a new prompt so they know they can still type commands.
Create a new entity StartLocation
to mark a room where players may enter the game. Alter the code that puts players into the game so that it finds a usable StartLocation
and puts the player there rather than using (0, 0) on the default map.
The Spring leaf is a nice icon but not really fitting for this project.
Putting a new favicon.ico
under src/main/resources/static
should override the leaf icon.
Here's a favicon generator: https://realfavicongenerator.net/
During development I have noticed that when I kill the MUD, recompile and start it back up I can get duplicates of my character in the world pretty reliably.
I believe this is due to a problem with the code in WebSocketResource.onSubscribe()
that tries to determine whether an Actor is already in the game or not. It tries to match the STOMP username and session ID, but when the game has been stopped and restarted the STOMP session will have been recreated.
Without taking a closer look I'm not sure what the exact remedy is for this, but I suspect it will involve storing a little more information somewhere so we can find our Actor
in the world more reliably. Maybe keeping the ID from the PlayerActorTemplate
on the Actor
would do the trick.
It would be nice to have a dynamically generated list of all the commands on the website so that visitors could have a reference they can look at in a second window rather than having to type HELP all the time in the game.
What could be really nice is to make every command object implement an interface that specified some methods like getDescription()
that the website and the HELP command could use to generate helpful documentation for each command. That way the text of the documentation for every command would live right there with the code and it would be easy to keep up to date. It would also be the same inside the game as it is on the website, and only ever need to be updated in one place.
I've only been using Java 8 so far for this project, but @jayyargh reports that the gradle version doesn't like Java 10. Looks like the problem can be solved by updating to the latest version of gradle.
To do that, we just need to change the version number in gradle/wrapper/gradle.properties
to the latest version. However, once that is changed the build needs to be tested thoroughly to make sure it still works reliably and that none of the gradle plugins become broken.
Create a simple map generator that will generate a map of random size, between 5 and 30 rooms in width. Flood fill all the rooms with a randomly selected WILDERNESS
tile from the map's tileset.
The account screen right now just has a Play button for every character. When you have an active session open and you look at the account screen from another browser it should change the Play button to an orange Reconnect button.
As a MUD operator I need a clean, configurable way to inject some HTML or Javascript to collect metrics about who visits my site so I can tell whether I'm getting visitors or not.
For example, a lot of people will want to use Google Analytics on their front page. AddThis is also very popular, and there are many other options. Some MUDs will want to use more than one provider.
Running the "AFK" command will toggle a flag true or false, stored on your Connection
object.
When the flag is false, everything is normal.
When it's true, you'll see a flag in LOOK and WHO that says [AFK]
, very similar to the [LINK DEAD]
flag. It's just there to show other people that you probably aren't looking at the game right now. For the time being it has no other effects, but in the future it could be used to protect you from unexpected combat or other dangers while you're away from the keyboard.
My "production" deployment of The Agony Engine lives in an AWS ECS cluster, is automatically built by CodeBuild and deployed by CodePipeline. Every time a PR is merged into master it triggers a build and deploy. The current behavior is that when the container you are connected to is brought down in the rolling deploy you get disconnected (that could potentially be resolved in the future) and it happens very suddenly, without any warning.
What if there were REST endpoints exposed on the game that GitHub and AWS could hit to produce notifications? "Code has been merged." "A build is starting." "A rolling deploy is starting." etc. So that inside the game you'd get messages to indicate that you may be disconnected soon and that new features are inbound.
Certainly not a big deal right now when there aren't any players and there isn't any game, but even if the disconnections got fixed it might be cool as a player to know when new features are being deployed.
If you put a color tag in an Actor
name it makes it very hard to interact with that object. The command interpreter should be smart enough to ignore color tags so you can still interact despite all the colors.
Some permutations to consider:
[red]red balloon
red [red]balloon
[dred]red [red]balloon
colorful [red]b[dyellow]a[yellow]l[green]l[blue]o[dmagenta]o[cyan]n
Other punctuation, symbols and emoji should get filtered out as well since the command interpreter will filter them out of the input tokens. For your consideration:
> l
(0, 2) Armory
Weapon and armor racks line the walls, and a practice dummy stands forlornly in the
corner.
Exits: east south
"armor" is here.
> get arm
No "target in same room" found for word: ARM
> get ""
You get "armor".
This seems like it could get refactored into an annotation similar to PasswordsMatch
.
Using the in-memory message broker we are limited to running only a single copy of the game at a time. With multiple copies they would each have their own in-memory simple message brokers that don't talk to one another and would be unable to route messages between the instances.
To get multiple instances to talk to one another we need a stand-alone message broker such as ActiveMQ or RabbitMQ (not sure if SQS will work?) that all instances can register with and route messages through.
Some additional key points:
If you are connected with two different characters in two browser tabs and restart the server, both tabs will automatically reconnect but they will both reconnect as the same character. The first tab in will be in a broken, un-playable state.
The expected behavior is that each of the tabs reconnects to the character it was originally connected as.
I have not yet verified that the behavior is the same on the public version of the game, but I would expect it to do the same thing.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.