Skip to content

Philosophy

Greg edited this page Jan 26, 2022 · 17 revisions

Data in files, logic in code

Keeping as much data as possible in files keeps the code clean and allows focus to be kept on the flow of logic. Data can also be easily re-loaded at runtime allowing for faster fixes and prototyping.

Flexibility with maps

Maps are a naturally efficient way of storing information taking up no more memory than necessary both in RAM and on disk. Every entity has a [Values] map for storing temporary (discarded on logout) and persistant (saved) data instead of hundreds of individual variables causing account saves to gradually grow in size over time as players use more content.

Definitions which read static cache data all have an Extras map for storing custom values inside the /data/definitions/ directory.

Strings are readable, special numbers are not

All entities have replacement unique string identifiers as strings are human friendly not only for reading code but also when inputting data: Want a yellow whip? ::item abyssal_whip_yellow no id look-up table required.

Requiring unique strings forces contextal and relational information about entities which might otherwise be identical: banker_lumbrdige, banker_varrock which can simplify transformations "${door.id}_closed".replace("closed", "open") however be cautious with this as name changes could break these implicit relationships. And even if all else fails you can still use the integer id as a string "4151".

Test content as well as systems

Tests are the proof that code written 6 months ago still works today and provides the confidence to make large fundamental changes without introducing new bugs or issues. The more content that is added over time, the more important this becomes.

Events

Entities each have a publisher for emitting events, these events can be subscribed to at any time allowing content to interact with each other without interweaving code.

entity.events.emit(Event(data))

// Global scope
on<Entity, Event>({ condition && isMet }, Priority.HIGH) {
}

// Local scope
val listener = entity.events.on<Entity, Event>({ condition && isMet }, Priority.HIGH) {
}

// Important to remove listeners in local scope to prevent leaking memory
entity.events.remove(listener)
Clone this wiki locally