Skip to content

Latest commit

 

History

History
239 lines (174 loc) · 14.6 KB

CONTRIBUTING.md

File metadata and controls

239 lines (174 loc) · 14.6 KB

Licensing

Aurora Station code is licensed under the GNU Affero General Public License version 3, which can be found in full in LICENSE-AGPL3.txt.

Commits with a git authorship date prior to 1420675200 +0000 (2015/01/08 00:00) are licensed under the GNU General Public License version 3, which can be found in full in LICENSE-GPL3.txt.

All commits whose authorship dates are not prior to 1420675200 +0000 are assumed to be licensed under AGPL v3, if you wish to license under GPL v3 please make this clear in the commit message and any added files.

All assets including icons and sound are under a Creative Commons 3.0 BY-SA license unless otherwise indicated.

GitHub Standards

Sub-licensing External Content

When does this section apply to me? When you are integrating content that is not licensed under AGPLv3 (code) or Creative Commons 3.0 BY-SA (icons and sounds). The most common application here is for icons and sounds gathered from an external source or repository.

As a contributor, you must do your utmost to pay respect to international copyright law. This means that, if copying code or content from an external source, you must be aware of what license it is published under. And you must ensure that the conditions of said license are followed when integrating the content into the codebase. (Sometimes this is not possible, and the content cannot be used.)

If you cannot locate or reasonably dicern authorship or the license associated with given content, we ask that you not submit it into a pull request.

As a courtesy, attribution of authorship is also encouraged, even if the license of the content does not require this outright. Generally this is done in the PR by declaring the source of the material, the author(s) (if known), and adding similar attributions to the relevant changelog entry (if applicable). This may be both done in the author field or within the plain text describing the change itself.

When reading the sub-sections that follow, note that these will be generalizations, and the specifics will be dictated by the license itself.

Code

Code from most other open source SS13 code bases is GPLv3 or AGPLv3. This means that it's free to be copied without any additional effort. Though any notes of authorship within the code files, if presents, must be kept intact. Be wary of Goon: their code is licensed under CC-BY-SA-NC and is not directly compatible with our codebase's license. Porting Goon code directly is highly discouraged as a result.

If the code is external, or licensed under something else (example being the TGS library), then ensure that the copyright notices within the file(s) (if present) are kept intact, and that a separate license file (if present in/packaged with the original source) is added to the repository. This generally means that you have to put all of the code you are porting in this manner into a modules/ sub folder, and stick the license file in there.

Other Assets (Sound, Icons)

If the material is distributed under CC-BY-SA 3.0, then it can go straight into the relevant folders, as long as you attribute the author(s) in the PR and changelog if they can be identified.

In any other case, create a subfolder somewhere in the relevant structure, stick the items in there, and provide a copy of the license with the content. Also, ensure that the license permits the intended use of the content in the appropriate manner.

Peer Review

All pull requests are subject to peer review prior to being merged. After said reviews, they are given a final once-over by a maintainer and then merged if good.

A feature pull request will require two reviews, with one of them being a community developer's. The other review can come from a "trusted reviewer" or a developer. Contributors who have shown that they are capable of properly reviewing pull requests can request the "trusted reviewer" role. There is also a minimum time-out of three days before a feature pull request can be merged. This is to ensure that there is enough time to review and discuss new additionsfrom the game.

A bug fix pull request will require two reviews, if it is to be merged in the first 24 hours, or one following the first 24 hours.

Prefer Atomic Pull-Requests

Pull requests should do one thing.

This means that a series of small, dependant pull requests is preferred over one large, monolithic one. Developers and maintainers may request that you break up a pull request into multiple smaller pull requests to enforce this standard at their discretion.

Small pull requests allow for easier reverting, easier (and faster!) reviewing and deliberation, and enable developers in the future to more easily locate all changes relevant to a potential issue.

Changelogs

Changelogs are automatically parsed from within the html/changelogs folder. A readme file exists there with specific information on how to create and manage changelogs. All pull requests which contain player-visible changes are required to have a changelog. Any others, like pull requests containing background system tweaks, minor optimizations, admin systems, etcetera, do not necessarily require a changelog.

Changelogs should be written in a concise and clear manner. There is no need for long winded explanations or too much detail (such as specific numbers, values, etcetera) in a changelog. If necessary, the PR can be tagged as wiki update for a wiki article to be written about it.

There also exist IC changelogs. These are presented in-game as a news article by NanoTrasen, and can be used to provide temporary fluff for in-game changes. To make use of these, simply put a IC changelog header into the description of the PR and write up the contents below it. An example:

IC Changelog

A new weapon was commissioned by NanoTrasen. It is currently being tested aboard the NSS Aurora

Coding Standards

Absolute Pathing

Absolute pathing has to be used for type, proc, and verb definitions. This is to make searching and reading easier.

An example of properly pathed code:

/obj/item/device/cake
	[cake code here]

/obj/item/device/cake/proc/eat_cake()
	[proc code here]

An example of badly pathed code:

/obj/item/device/cake
	[cake code here]

	proc/eat_cake()
		[proc code here]

Initialize() over New()

Since the implementation of the Stoned Master Controller, overrides of the New() proc have effectively become depracted in favour of Initialize() and LateInitialize(). In most cases, Initialize() is a drop-in replacement for New(), however, there are a few considerations to be taken into account when using this. Specifically, Initialize() must always return a initialization hint and must always call the superior definition via ..(). Usually these two are done together, either via the . = ..() semantics or with explicit return ..() statements.

LateInitialize() can be used to manage race conditions during map loading. In the middle of the game, when mapload = FALSE in Initialize(), LateInitialize() is called immediately after the specific atom's Initialize() call. However, if mapload = TRUE, which it does during map atom initialization, the LateInitialization() of an atom is called once all atoms have finished their Initialization() calls. Note that Initialize() needs to return INITIALIZE_HINT_LATELOAD in order for LateInitialization() to be called in either case.

Refer to the wiki article for further information.

qdel() and Destroy() usage

All objects with an applicable type need to be deleted by qdel(), as opposed to the regular del() proc. While conducting this action, make sure you remove all possible references to the object you assign for deletion after calling qdel(). This will enable the garbage collector to handle the objects assigned to it at its own pace, thus reducing lag in the long run.

An example of how to use qdel():

/obj/item/plate
	var/obj/item/cake/cake

/obj/item/plate/Initialize()
	. = ..()
	cake = new()

// Eat the cake and destroy the cake object.
/obj/item/plate/proc/eat_cake()
	qdel(cake)	// Call qdel()
	cake = null	// Set local reference to null to assist the GC.

The Destroy() proc for objects should be defined, if there are any special operations that need to be conducted when an object is assigned for destruction with qdel(). Normally, it would set all object references that that specific item may contain to null, and destroy them as necessary. It is important to know that the best case scenario for the garbage collector is this: an object passed to it should not reference, or be referenced by any other ingame object.

Note that any modified Destroy() proc must always call its superior definition ..() and must return a deletion hint. Usually the hint passed down from the superior definition is returned, via . = ..() or an explicit return ..() statement.

An example of how to define Destroy() for an item that needs it:

/obj/item/plate
	var/obj/item/cake/cake

/obj/item/plate/Initialize()
	. = ..()
	cake = new()

/obj/item/plate/Destroy()
	if (src.cake)	// We potentially have a reference.
		qdel(cake)	// Delete the referenced item -- this doesn't always have to be done.
		cake = null	// Set the pointer to null. This is the important bit.
					// All pointers that the plate item contains are now null. This will speed up the GC.

	return ..()		// Return the original definition of the proc.

qdel() is not capable of handling the following types of objects:

  • file
  • savefile
  • SQLLite object
  • list objects.
  • turfs
  • areas (Note that these shouldn't be deleted at all)

You will have to use the regular del() proc to delete any object of that type (except for /turf, which should use ChangeTurf()).

More details on qdel, Garbage, and Destroy() are available on the wiki.

HTML styling for user output

All text output to the user, specially if the output operator << is used, should be formatted in proper HTML. DM text macros for styling, such as \red and \blue, are no longer to be used actively. This will enable the modification of used HTML styling later down the line, via the centralized .css files. It will also enable a switch from an output panel, to other output methods.

For reference, here are the standard span classes for user output, and the correlation between them and the DM text macros:

  • <span class='danger'></span> corresponds to \red and is bold.
  • <span class='warning'></span> also corresponds to \red and is not bold.
  • <span class='notice'></span> corresponds to \blue and is not bold.

There exist pre-processor macros for using these spans. span(class, text) which is the equivalent of typing a string that looks like this: "<span class='[class]'>[text]</span>" and macros such as SPAN_WARNING(text), SPAN_NOTICE(text), SPAN_DANGER(text). Using the SPAN_X() macros is preferred.

The stylesheet available for use within DM can be found in code/stylesheet.dm.

Usage of forceMove

In order to make Exited() and Entered() procs more reliable, the usage of forceMove() when forcibly moving one item to another location, be it another item or turf, is required. Directly changing an item's loc values will skip over calls to the aforementioned procs, thus making them less useful and more unreliable.

An example of improper item moving:

/proc/some_proc(var/obj/A, var/obj/B)
	A.loc = B	// Simply move A inside B.

An example of proper item moving:

/proc/some_proc(var/obj/A, var/obj/B)
	A.forceMove(B)	// This will call A.loc.Exited() and B.Entered().
					// The first method does not call either of those.

Regarding the variable usr

If at all possible, procs outside of verbs and Topic() should avoid reliance on usr, and instead use a custom argument to specify the user and its expected type. This makes it easier to reuse procs in chains where usr is not always defined, and combats against potential security flaws that relying on usr can bring.

usr must also always be validated to be the expected type!

Reserved argument names

All BYOND procs have a set list of variables which are implicitly defined in each proc. However, the DM compiler will allow you to reuse these names as names for your custom variables. This should be avoided at all costs, to improve the readability and understanding of code.

A list of reserved argument names instantiated with all procs:

  • vars being an alias of src.vars if src exists.
  • args
  • usr
  • src

Avoid in world loops

Due to the amount of instances in the world, utilizing an in world loop should be avoided in all instances. In large projects, specially when crawling for types that are not optimized internally by BYOND (only core built-in types are), crawling in world will surmount to a very large blocking loop and will almost certainly trigger the infinite loop warning. This forces the specific callstack to sleep at least once.

Note that a for-each loop without an explicit container specified will default to an in world loop. This is to say, the following two examples are equivalent:

for (var/client/C)
	qdel(C)

for (var/client/C in world)
	qdel(C)

Database prefixing

All tables for the database should be prefixed according to the following list:

  • ss13_ for tables in which ingame data is held.
  • discord_ for tables in which BOREALIS data is held.

HTML UI Standards

UI conversion policy

Due to our current situation with 5 different HTML UI systems we are now enforcing a policy that all new UIs should be made using the TGUI system. This policy also applies to editing existing UIs, with the following exceptions:

  1. Modification is security / severe bug fix.
  2. It is typo fix.
  3. Touched UI file is too large.
  4. TGUI can't accommodate that type of UI.

Globals

All globals must use the defines found in __defines/_globals.dm. This is to store globals inside the Global Controller, allowing us to view and edit them at runtime. Here are a few examples. GLOBAL_VAR(thing) will create a global variable var/thing accessed with GLOB.thing. GLOBAL_LIST_INIT(list_of_stuff, list("stuff", "thing")) will create a global list var/list/list_of_stuff = list("stuff, thing") accessed with GLOB.list_of_stuff. GLOBAL_DATUM_INIT(cake, /datum/cake, new) will create a global /datum/cake/cake and new it, accessed with GLOB.cake.