akevitt

package module
v0.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 13, 2024 License: EUPL-1.2 Imports: 18 Imported by: 0

README

Akevitt

Akevitt is a MUD engine designed to be as modular, but powerfully minimal, as possible. This means that there are no "plugins" or "add-ons" that have narrow functionality. You get the infrastructure, information persistence, accounts, and other essentials done for you, while the rest is up to you. Strongly inspired by Evennia. What you can do with Akevitt is only limited by your imagination and technical skill in Go.

Features

  • Runs on an SSH server, meaning that, just like with Telnet, you can connect to an Akevitt game from almost any device available in the world.
  • Automatic database, meaning any game object (GObject) you create is tracked and survives reboots. You do not need to think about the database, ever.
  • Modularity. Use straight-forward API to create your objects, NPCs, rooms, or anything with, and place them all in one file or organised across as many files as you need.

How does Akevitt work?

The engine runs on a simple SSH server, which means that anybody with an SSH client installed on their computer can connect to the game and play in their terminal. Data is then stored in a small database that requires no external libraries or programs. It is all built into Akevitt. The server is entirely self-sufficient: nothing like SQLite is required.

What does Akevitt use to work?

The SSH server is implemented with ssh by Glider Labs. Database is Bolt, a simple non-relational key-value database, which is really all that is needed for a MUD. UI elements are implemented with tview. Basically, whatever challenges Akevitt meets, they are solved with the latest, mature libraries that the Go ecosystem has to offer. This leads to a robust infrastructure with the worst bugs eliminated before a single line of Akevitt's source was written.

Why this over Evennia?

Although Evennia is ambitious, and it certainly delivers in its rich feature set, it is quite bloated for what it is: over 350 MB of source just to get a simple MUD going? We can do better. Additionally, Python is very difficult to actually develop large projects in. pip is a nightmare. Maintainers of Python frequently introduce breaking changes in what are supposed to be minor versions of Python 3. Python virtual environments offer mixed results, most often not really solving the issue they are allegedly addressing. We can go on.

For end-users, it probably will not make a lick of difference whether their MUD runs on Akevitt or Evennia. However, for developers like us it makes a huge difference, and Akevitt is here to bring joy to developing MUDs, while retaining the ease of deploying complete games. If functional programming is more your speed, Akevitt is what you are looking for.

Licence & Attribution

Programming and design

Ivan Korchmit (c) 2023

Design and presentation

Maxwell Jensen (c) 2023

Licensed under European Union Public Licence 1.2. For more information, view LICENCE.

Documentation

Overview

Program written by Ivan Korchmit (c) 2023 Licensed under European Union Public Licence 1.2. For more information, view LICENCE or README

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AppendText added in v0.3.3

func AppendText(message string, chatlog *logview.LogView)

func BindRooms

func BindRooms(emptyExit Exit, room *Room, otherRooms ...*Room)

Binds room with an exit.

func CreateObject

func CreateObject[T GameObject](engine *Akevitt, session *ActiveSession, object T, params interface{}) (T, error)

func ErrorBox added in v0.3.3

func ErrorBox(message string, app *tview.Application, back tview.Primitive)

func FilterByType

func FilterByType[T any, TCollection any](collection []TCollection) []T

func Find

func Find[T comparable](collection []T, value T) bool

Finds `T` value of []T.

func FindByKey added in v0.3.3

func FindByKey[TCollection, T comparable](collection []TCollection, selector func(key TCollection) T, value T) *TCollection

func FindNeighboringRoomByName added in v0.3.3

func FindNeighboringRoomByName(currentRoom *Room, name string) (*Room, *Exit, error)

func FindObject

func FindObject[T GameObject](engine *Akevitt, session *ActiveSession, key uint64) (T, error)

Finds game object associated with an account in database.

func LogError added in v0.3.0

func LogError(message string)

func LogInfo added in v0.3.0

func LogInfo(message string)

func LogWarn added in v0.3.0

func LogWarn(message string)

func LoginScreen added in v0.3.3

func LoginScreen(engine *Akevitt, session *ActiveSession, nextScreen UIFunc) tview.Primitive

func LookupOfType

func LookupOfType[T GameObject](room Room) []T

func MapSlice

func MapSlice[T any, TResult any](l []T, callback func(v T) TResult) []TResult

Maps slice, similar to JavaScript's map method.

func NewEngine

func NewEngine() *akevittBuilder

Engine default constructor

func OocCmd added in v0.3.3

func OocCmd(engine *Akevitt, session *ActiveSession, command string) error

Out-of-character chat command

func RegistrationScreen added in v0.3.3

func RegistrationScreen(engine *Akevitt, session *ActiveSession, nextScreen UIFunc) tview.Primitive

func RemoveItem

func RemoveItem[T comparable](l []T, item T) []T

Removes item from collection and returns it.

func RemoveItemByIndex added in v0.3.3

func RemoveItemByIndex[T any](l []T, i int) []T

func SaveObject

func SaveObject[T Object](engine *Akevitt, obj T, category string, key uint64) error

Saves object to database.

Types

type Account

type Account struct {
	Username string
	Password string
}

Basic structure for storing credential information. After registering an account, the password is hashed in a proper way To create one you would need to invoke `engine.Register(username, password, session)`

func (*Account) Save

func (account *Account) Save(engine *Akevitt) error

Save account into a database

type ActiveSession

type ActiveSession struct {
	Account     *Account
	Application *tview.Application
	Data        map[string]any
}

type Akevitt

type Akevitt struct {
	// contains filtered or unexported fields
}

The engine instance which can be passed as an argument and provide some useful methods like Login, Register, Message, Dialogue, etc. Methods with name starting like Use should be called in a main function during the initialisation step. To actually run the engine, you must call Run function and pass the engine instance Example: fmt.Fatal(akevitt.Run[*MySessionStruct](engine))

func (*Akevitt) Dialogue

func (engine *Akevitt) Dialogue(dialogue *Dialogue, session *ActiveSession) error

Invokes dialogue event. Make sure you have installed the hook during initalisation.

func (*Akevitt) ExecuteCommand

func (engine *Akevitt) ExecuteCommand(command string, session *ActiveSession) error

Execute the command specified in a `command`. The command can be registered using the useRegisterCommand method. Returns an error if the given command not found or the result of associated function returns an error.

func (*Akevitt) GenerateKey

func (engine *Akevitt) GenerateKey(gameobject GameObject) (uint64, error)

Auto-increment uint64 key by object's name.

func (*Akevitt) GetCommands

func (engine *Akevitt) GetCommands() []string

Gets currently registered commands. This is useful if your game implements auto-completion.

func (*Akevitt) GetRoom

func (engine *Akevitt) GetRoom(key uint64) (*Room, error)

Obtains currently loaded rooms by key. It will return an error if room not found.

func (*Akevitt) GetSpawnRoom

func (engine *Akevitt) GetSpawnRoom() *Room

Get sspawn room if specified. Useful for setting character's initial room during its creation.

func (*Akevitt) GlobalLookup added in v0.3.0

func (engine *Akevitt) GlobalLookup(room *Room, name string) []GameObject

func (*Akevitt) Login

func (engine *Akevitt) Login(username, password string, session *ActiveSession) error

Login call to the database. Note: returns an error if the session is already active.

func (*Akevitt) Message

func (engine *Akevitt) Message(channel, message, username string, session *ActiveSession) error

Send the message to other current sessions

func (*Akevitt) Register

func (engine *Akevitt) Register(username, password, repeatPassword string, session *ActiveSession) error

Create an account Returns an error if account with the same username already exists

func (*Akevitt) Run added in v0.3.3

func (engine *Akevitt) Run() error

Run the given instance of engine. You should pass your own implementation of ActiveSession, so it can be controlled of how your game would behave

func (*Akevitt) SaveGameObject

func (engine *Akevitt) SaveGameObject(gameObject GameObject, key uint64, account *Account) error

Saves game object in a database associated with an account.

func (*Akevitt) SaveObject

func (engine *Akevitt) SaveObject(gameObject GameObject, key uint64) error

Saves object into a database.

func (*Akevitt) SubscribeToHeartBeat

func (engine *Akevitt) SubscribeToHeartBeat(interval int, fn func() error) error

type CommandFunc

type CommandFunc = func(engine *Akevitt, session *ActiveSession, arguments string) error

type DeadSessionFunc

type DeadSessionFunc = func(deadSession *ActiveSession, liveSessions []*ActiveSession, engine *Akevitt)

type Dialogue

type Dialogue struct {
	// contains filtered or unexported fields
}

Dialogue struct for creating dialogue-like events. The content is actually a UI element, so you implement merchants, dialogues, etc. You must call NewDialogue to get started.

func NewDialogue

func NewDialogue(title string) *Dialogue

Creates new instance of dialogue

func (*Dialogue) AddOption

func (dial *Dialogue) AddOption(title string, content tview.Primitive) *Dialogue

Add options to the dialogue

func (*Dialogue) End

func (dial *Dialogue) End() *Dialogue

Ends the dialogue with "Close" option

func (*Dialogue) GetContents

func (dial *Dialogue) GetContents() tview.Primitive

Gets the UI of dialogue

func (*Dialogue) GetOptions

func (dial *Dialogue) GetOptions() []*Dialogue

Gets an array of options

func (*Dialogue) GetTitle

func (dial *Dialogue) GetTitle() string

Gets title of an option

func (*Dialogue) Proceed

func (dial *Dialogue) Proceed(index int, session *ActiveSession, engine *Akevitt) error

Invokes engine.Dialogue of the specified index from options.

func (*Dialogue) SetContent

func (dial *Dialogue) SetContent(content tview.Primitive) *Dialogue

Accepts UI element to be displayed on user.

type DialogueFunc

type DialogueFunc = func(engine *Akevitt, session *ActiveSession, dialogue *Dialogue) error

type Exit

type Exit struct {
	Name string
	Room *Room
}

func IsRoomReachable

func IsRoomReachable[T Room](engine *Akevitt, session *ActiveSession, name string, currentRoomKey uint64) (*Exit, error)

Checks if current room specified reachable to another room.

type GameObject

type GameObject interface {
	Object
	GetName() string
	Create(engine *Akevitt, session *ActiveSession, params interface{}) error // Create an object wuth specified parameters.
}

Base of the gameobjects that can be involved in gameplay.

type MessageFunc

type MessageFunc = func(engine *Akevitt, session *ActiveSession, channel, message, username string) error

type Object

type Object interface {
	Save(engine *Akevitt) error // Save object into database
}

type Room

type Room struct {
	Name       string
	Exits      []*Exit
	Objects    []GameObject
	OnPreEnter func(*ActiveSession) error
}

func (*Room) GetKey

func (room *Room) GetKey() uint64

type Sessions

type Sessions = map[ssh.Session]*ActiveSession

type UIFunc

type UIFunc = func(engine *Akevitt, session *ActiveSession) tview.Primitive

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL