Giter Site home page Giter Site logo

bbuck / dragon-mud Goto Github PK

View Code? Open in Web Editor NEW
109.0 21.0 15.0 4.38 MB

A text-based game engine written in Go and scripted with Lua.

License: Other

Go 94.00% Makefile 0.24% Lua 5.76%
mud mud-server game-engine mud-engine lua golang plugin-system telnet

dragon-mud's Introduction

DragonMUD

Build Status Code Climate Issue Count Discord Channel Go Report Card

DragonMUD is a dream of mine, building a new MUD engine for experience and fun before building my own game on top of it. The engine will be a firm foundation for any kind of text based adventure (for now just Telnet, but eventually web and websocket versions as well). It will feature a plugin system allowing the core of the game to be moldable from the ground up into what you truly desire for your game.

Why should I use this?

That's really up to you. This project is for me, but I believe in sharing. I also feel yet another new MUD engine may inspire some new games to be created in the genre, which would be amazing. I'm a huge fan of MUDs and feel that new entries have kind of become almost non-existent. Perhaps a new game and an accessible low-setup server framework would make it easier for new games to be quickly created.

What exactly is it?

DragonMUD started life as an engine designed specifically for the MUD that I wanted to build, but before long it pivoted to being a base for text based multi-user games. Leverage the power of Lua running on top of Go, DragonMUD aims to provide a quick entry into the genre. Once you generate a new game you can immediately start adding plugins that the community has put together to piece your game together. Want classic rooms? Grab a plugin, what geographically organized rooms? Grab a plugin, want a mapping system? Grab a plugin -- if you can't find one, the build your own and share it with the community!

DragonMUD provides the foundation and the glue code to allow many different plugins to come together and form a cohesive bond, allowing you to build the text based game of your dreams (or non-game, if that's your thing).

What exactly is it not?

DragonMUD is engineered specifically for text based games running over TELNET. It doens't have to be games though, but it does need to function over TELNET. There are plans to provide an HTTP server with websocket support in the future but for the time being you should probably find another engine if you're looking to do anything that isn't text-based.

Why Go?

I love C and C++ but they're older and slightly more complex languages to set up and maintain. Go strives to be a "modern" C and was therefore a good choice in my opinion. It also supports concurrency out of the box in a very easy to use and understand way. It's also relatively low level enough for the purpose of a running a game server.

Why Lua?

I wanted to write my own language, and for a Ruby attempt at this project I actually did. You can find it here but it was a lot of work, has a lot of holes and is relatively unfamiliar to anyone who may or may not be used to scripting games. On the other hand, Lua has been around. It's been tested and it has a slew of core features that would be great to leverage. It's also very common among games as a scripting layer and became a prime choice to replace a custom built engine.

Roadmap

I have grandiose plans. At the moment, they're not divided into versions but as this project matures I will clean up and define these details more and more.

  • TravisCI integration to easily demonstrate stable builds
  • Code climate monitoring GPA of code, maintaining an A - B grade for overall project
  • Test suite to validate working state of features, capturing as many differing/edge cases as possible
  • Neo4j backed database features
    • Neo4j database connection library available to Lua (in development)
    • ActiveRecord-esque Entity framework for the scripts to leverage
  • Script engine for loading and executing Lua files.
  • Plugin system to allow for creation of whatever game one desires
  • Plugin manager (like go get but for DragonMUD plugins)
  • Telnet Server

Future

  • Web layer for defining and building any kind of web server on top of the chosen application

Contributing

Please reference CONTRIBUTING.md for details on becoming a contributor and/or collaborator.

Building From Source

To manage this project and ensure reproducible builds I chose to use the glide dependency manage for Go. What this means is that you'll need Glide to ensure you get the same build that I do. Please do not update any dependency without explicit reasoning to defend the upgrade. If required to install new dependencies you can simply do glide get. This will add the dependency to vendor/ which should not be committed.

So the process to set up for contributions is to fork it, and then go get your project:

go get github.com/bbuck/dragon-mud
cd $GOPATH/src/github.com/bbuck/dragon-mud
make get-glide
make get-deps

To build your project:

make install

And if make is not available**, then install with the following command:

glide install
go get github.com/onsi/ginkgo/ginkgo
go get github.com/jteeuwen/go-bindata/...
go-bindata -pkg assets -o assets/assets.go -prefix assets/raw assets/raw/...
go install github.com/bbuck/dragon-mud/cmd/...

** But keep in mind, make is used to engineer standard multi-step processes for building/installing so it's highly advantageous to get a version for your OS up and running to use in place of trying to do everything manually.

Contributors

Brandon Buck, @bbuck, [email protected]

License

Copyright 2016-2017 Brandon buck

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

dragon-mud's People

Contributors

bbuck avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dragon-mud's Issues

Avoid pzduniak/argon2, it's not up to date

My port of libargon2 implements an old, vulnerable version of the algorithm. Unfortunately I don't think that there is any pure Go implementation with a full featureset, but the closest you can get is go-argon2 using CGo, there's also my fork which includes the C code, so that the whole library is self-contained.

New Direction

More will come later, but for now the tl;dr is this:

Originally this was going to be a server oriented towards my rules and needs that allowed some basic scripting and customization and building your own world on top of my gameplay preferences. But I want this to be the "Rails" for MUD games, and making a one-trick pony codebase (as there are many) that would require some forking and modification to drastically change slowly lost it's appeal to me. So the new direction is to rip out all that old crap and overlay a strong base for scripting. Implement a nice plugin management system and let the games be built from the ground up entirely in custom scripts. DragonMUD will abstract most of the nuance details of having a MUD server (like all the standard library utilities you might expect, telnet connections, and other fun fair) while plugins will let you make your game do something awesome.

The idea of the plugins is to allow users to build modules and share them. Like a "MUD Room" plugin, and a "Crafted Spell" plugin and whatever plugins you want. More details will come on the specifics on those later. But basically DragonMUD will just be a base engine and then the rest of my game will be written in (still MIT licensed) plugins that will work with DragonMUD. So if you wanted to copy my game's gameplay and build your own world on top of it, you're still very much able to do that. But if you want to build something drastically different, then pick and chose what plugins work for you and write new ones to solve new problems.

Hopefully this works out much better.

Provide an 'init' command

Provide an 'init' command that will set up the current directory with necessary files and file structures to begin creation of a MUD server.

This will require configuration of the first pass design for project structure and is not guaranteed to be final project structure.

Create the Entity framework

Create a base class to interact with the database and load/save entities. This is not just a class to represent models but also a way to control access (in other words, thread safe ways) to database records.

Implement a "world growth" system.

This would function very similar to the way that World of Warcraft's "phased" zone system works. Players of certain growth states when traveling through an exit would enter a different (but intended to be the same) room. In other words, say you have a forest on fire, and quests that involve dousing the flames. You could have rooms with "fire" objects in them that can be doused and they re-spawn after being doused for other players to complete the quest later, and then once the quest is completed players still run through the forest on fire. This is not conducive to a feeling of "effect" and control on the game.

So we introduce a growth system to the forest. There exists two sets of rooms, one with fire spawns and one without (or just specific rooms if not the entire forest). Initially the player would always enter the initial growth state of the room which contains fire spawns. Upon completing the question, which would advance the players current growth state for those rooms, and then every time the player moves through an exit into those rooms they enter the second growth state of those rooms which lack the fire spawns and can feel as if their work to douse the fires has had a lasting effect on the game world.

Players of groups would have to be forced to enter a specific growth state, I would propose they always enter the lowest growth state of the party, so for solo players that is their growth state and for multiple players who ever has the lowest is the growth state of the party.

This would cause extra work for builders, but also give builders a lot more power when designing quests that effect the world. And from a players perspective, for events that don't need to be extremely lasting (like massive content updates that transform parts of the world) new players can experience "old" content without old players having to see this old content as they play in their "new" world.

Flesh out the 'serve' command

The basic version of the serve command has been implemented, which essentially prints some flavor text. In order to finish out basic MUD capabilities serve will need to run the server.

Update README

Move sections around in the README, make some sections more accurate.

Remove support for selecting databases and build for one.

So this one has required quite a bit of thought. I'll try and start from where I first began to where I finally made the decision.

When implementing the support for optional database support I watched the significant binary growth (not a major concern, but a minor one) due to the addition of more than one database connection library being part of the project, only one of which could be used at any one time. So I chose SQLite due to how easy it easy it is to configure and use although single access to the file could prove problematic later in development, but I wanted to nearly remove the barrier to entry for using this program. Then I chose to support MySQL, which I'm personally pretty burnt out on, because of it's popularity among the more experienced types. And then I chose PostgreSQL (at the time when I implemented this support) because it's my personal favorite.

Then comes the thoughts on random values for players. So I'm not sure how other systems handle this and it's probably a good idea to look but I don't care too much to do that research and I'm not really willing to have a "random values" table that's like player_id, value_name, value and them being strings, or finding some convoluted way to store the value like 10/number or having a value_type column in addition (and then possible a value_types table that relates too...). PostgreSQL has a great jsonb type with indexing and searching capabilities. Using it as a dynamic storage field I don't see leverage indexing but it could be great searching for a user with some random value, like phase values for certain rooms: select * from players where values->'forest_phase' = 'final'.

Anyways, aside from all that hooplah I've decided that using the jsonb type of PostgreSQL and not hacking or downgrading support into some text field just so I can use two database types with little-to-no JSON support (or similar). It's important to understand this is simply a decision based on how I want to handle "extra" values. With an "infinite" number of quests/phased rooms/instance locks and other random things like maybe randomly locking a user into only using an item once or drinking a potion once or opening something once or whatever. This a place to store values that may or may not grow or drastically change over time.

In addition to this change I will also be rolling out gorm support for a more raw Postgres connector that will leverage and support JSON/JSONB. This is a big change, or at least someone, as basic structure will be changing and a new migration methodology will have to be applied and implemented as well. I have some ideas already on how to handle this implementation that I've used in the past, although it's a totally new approach from "magic" fetching to more specific and less dynamic (which I can be okay with, depending on needs). I'm sure some form of and ORM needs to be implemented. But for the most part querying the database only needs to happen in server scripts not in-game scripts. So I think a more limited support here is fine. In-game scripts just need to be able to set values, probably something like player:SetGameValue("crystal_forest.phase", "growing") or something.

By now I'm rambling, so this is probably the best place to stop.

New Direction Placeholder

Placeholder for future tickets to keep Milestone from hitting 100% complete until a clearer end game can be assessed.

Implement authentication over TCP connection.

Connections should be handled by a state-storing client object and have to authenticate with a player record.

A good set of exit criteria:

  • (code) Represent connections as clients one fired off that stores state for the connection.
  • (interaction) User must authenticate by entering player name and password when prompted
  • (interaction) Once authenticated user is (for the time being) dropped into a global chat space.

Basic TCP Server

Provide the base for the TCP server implementation featuring a mechanism for players to authenticate on a connection and communicate in a shared room.

Script Engine implementation

Integrate Lua scripting engine with interface with easy to use interface and fail safely mentality (store errors for optional checking).

Review and address errors.

Review every point in the code where errors are reviewed and attempt to determine if providing more details is good and/or relevant.

Import .are files.

More of a placeholder issue until I have more information, but basically want to support importing .are (and potentially exporting) files.

Implement instanced rooms/room groups.

Just like in popular MMOs where certain dungeons or areas, upon entrance, spawn the player or groups own instance of that area. Allowing two groups to run the same dungeon at the same time without interfering with one another or causing problems.

This would allow exits to be marked as instance entrances which would spawn the room or a group of rooms for that player and/or group. Another usage of this would be to segment highly trafficked areas. Instead of dealing with 300 people in one room, the room could be segmented by instances of say, 50 players or so (not that this is the desired effect) and so forth.

To sum up reasons for instancing:

  • Ensure each player/group can experience certain dungeon content without having interference from other players
  • Allow segmenting highly populated areas to prevent unnecessary spam in chats
  • Allow for special one off versions of other rooms (conditional instancing) for certain quests.

Add an `init.lua`

When a new project is initialized with dragon init or when plugins are generated from (the future) dragon gen plugin the empty directories should contain a dummy init.lua file with a comment explaining it's purpose. Something like in commands:

-- This is the entry point for {plugin name} commands.

Address the "1 Emitter per State" policy and work to get one event emitter per stage of scripting.

I'm hijacking the "make engines thread safe" issue and completely changing it. Not even going to bother explaining what my goal was with the old ticket. Here's my concerns for the new issue:

  1. Right now, each engine gets it's own event emitter associated with it.
  2. Engine pools (like server level) have 10 emitters then
  3. Currently one emitter is targeted (at random basically)

This works. Mostly. So event handlers associated to that emitter are fired off accordingly. Again, this works. If that engine associated it's once handlers they get dropped off from that emitter after being fired, everything just works (kind of). Okay, so what's with the "kind of" here? Well.... there are now 9 other engines with 9 other emitters with 9 instances of "one time handlers" on them. If the event is fired again and of those 9 are selected (a 9/10 chance) then those "one time handlers" are fired for a second time. Rinse and repeat for 10 attempts.

Also, having a pool of 10 engines with 10 emitters leads to the need for the third point. Another layer has to be implemented to "randomly select" an engine/emitter to fire events too. So this is practically impossible when you introduce a game world with (potentially) thousands of engines floating around that might need to fire events for each other. What kind of system is not very complex that can be handle receiving and emitting events to thousands of receivers?!

Well. To simply, this is to address any concerns with having all engines in a certain tier share an emitter. So the system will have one server emitter for 10 engines (the default pool size), one client emitter for client level engines, and one emitter for game entities. This provides one point of entry for event handling on each level which allows the server level to freely emit events up and down (so the server handler can emit tick events, etc...) to client and all listening entities.

Secure Lua states

For the plugin system I'm going to need to have a custom require that allows me to arbitrarily restrict on the fly what files require can access and how. After all, this is meant to be safe for you to run on your computers using plugins for other sources so I want to make it as safe as I possibly can. It can't be 100% safe, be careful, but I can do my part.

Database integration

Provide database integration for PostgreSQL, MySQL and SQLite with SQLite being the default.

Revert engine meta values back to a map in a `Meta` field.

This will require adjusting how a lua.Engine handles converting func to a lua.Value type so that that the wrapping gopher-lua compliant function uses closures to keep a reference to the actual lua.Engine. While this doesn't eliminate the need for dynamic casting it does eliminate the concerns of having data arbitrarily overwritten, needing to whitelist them, and so forth.

Add a `render_in_layout` helper to templates module.

Excerpt from Mudcoders Slack (me babbling):

{{#source}}You{{/source}}{{^source}}{{source_name}}{{/source}} say{{^source}}s{{/source}}, "{{message}}"

[14:39]
But with the current engine it'd be {{source_name}} {{say_word}}, "{{message}}"

[14:39]
So practically no reason to use a template.

[14:41]
Which looks cleaner, for sure, but does less work.

[14:42]
Although this would probably lead to things like say_source.view = You say, "{{message}}" and say_viewer.view = "{{source_name}} says, "{{message}}" (edited)

[14:43]
Which I kind of like better, if I'm being honest.

[14:45]

function get_say_strings(source, message)
 say_data = {
   source_name = source:display_name(),
   message = message
 }
 return {
   source = templates.render("say_source", say_data),
   viewer = templates.render("say_viewer", say_data)
 }
end

[14:46]
I have resold myself on stricter templates.

[14:46]
That gives you DIY layouts and other things.

[14:47]
templates.render("layouts.menu", {body = templates.render("menus.room_builder", menu_data})

[14:49]
Or helpers: templates.render_in_layout("layouts.menu", "menus.room_builder", menu_data) that maps to the above as:

menu_data.content = templates.render("menus.room_builder", menu_data)
return templates.render("layouts.menu", menu_data)

Modify current template engine wrapper to support more than just `map[string]interface{}` types.

The current selected template engine is quick, but only supports map[string]interface{} types. This should be an obvious limitation, since a lot of the common structures that may need to be rendered are going to be handled as structs and not maps and requiring that all objects have a "build map before use" function or process is just unnecessary overhead. Sure, the reflection will add some weight, but I'd prefer simplicity in that case over tons of extra code.

Enforce movement delays to enable movement types.

Provide different forms of movement such as "walking" and "running." Each method of movement should burn different values of stamina (you can't run as long as you can walk) and have server enforced movement cooldowns, such as walking (normal movement) between rooms will prevent any other movement from happening for 1 seconds, while running will prevent another movement action for 0.5 or 0.8 seconds (numbers should be tweaked during testing).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.