Surface Stack

Written by me (Anixias).

global.surface_stack = ds_stack_create();
global.surface_is_set = false;

/// @arg id
function surface_set(surf)
{
	if (global.surface_is_set) surface_reset_target();
	
	surface_set_target(surf);
	ds_stack_push(global.surface_stack, surf);
	global.surface_is_set = true;
}

function surface_reset()
{
	if (global.surface_is_set)
	{
		surface_reset_target();
		global.surface_is_set = false;
	}
	ds_stack_pop(global.surface_stack);
	if (!ds_stack_empty(global.surface_stack))
	{
		var surf = ds_stack_top(global.surface_stack);
		if (surface_exists(surf))
		{
			surface_set_target(surf);
			global.surface_is_set = true;
		}
		else show_error("Error: Reset surface didn't exist", true);
	}
}

Usage

Simply replace surface_set_target and surface_reset_target throughout your code with surface_set and surface_reset, respectively. This allows you to nest surface rendering. I wrote it because I needed a global UI surface, but I use surfaces throughout the UI. This allows me to use surface rendering wherever I need it without worrying about resetting the surface target every time I need to render to a surface, since I can’t know at runtime whether I’m currently rendering to a surface or not.

You can also use global.surface_is_set to know if you are currently rendering to a surface, and ds_stack_top(global.surface_stack) to get the id of the surface you are currently rendering to.

Event Bus

Credit to u/galitork on reddit.com.

function Events() constructor {
	signals = [];
	
	static subscribe = function(event, fn) {
		var i = array_length(signals);
		
		signals[i] = {
			name: event,
			func: fn
		}
	}
	
	static unsubscribe = function(event) {
		var newSignals = [];
		var j = 0;
		
		for(var i = 0; i < array_length(signals); i++) {
			var signal = signals[i];
			
			if(signal.name != event) {
				newSignals[j] = signals[i];
				j++;
			}
		}
		
		signals = newSignals;
	}
	
	static emit = function(event, data) {
		for(var i = 0; i < array_length(signals); i++) {
			var signal = signals[i];
			
			if(signal.name == event) {
				signal.func(data);
			}
		}
	}
}