mirror of
				https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
				synced 2025-10-26 09:20:49 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			84 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			GDScript
		
	
	
	
	
	
			
		
		
	
	
			84 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			GDScript
		
	
	
	
	
	
| class_name ModLoaderHookChain
 | |
| extends RefCounted
 | |
| ## Small class to keep the state of hook execution chains and move between mod hook calls.[br]
 | |
| ## For examples, see [method ModLoaderMod.add_hook].
 | |
| 
 | |
| 
 | |
| ## The reference object is usually the [Node] that the vanilla script is attached to. [br]
 | |
| ## If the hooked method is [code]static[/code], it will contain the [GDScript] itself.
 | |
| var reference_object: Object
 | |
| 
 | |
| var _callbacks: Array[Callable] = []
 | |
| var _callback_index := -1
 | |
| 
 | |
| 
 | |
| const LOG_NAME := "ModLoaderHookChain"
 | |
| 
 | |
| 
 | |
| # `callbacks` is kept as untyped Array for simplicity when creating a new chain.
 | |
| # This approach allows direct use of `[vanilla_method] + hooks` without the need to cast types with Array.assign().
 | |
| func _init(reference_object: Object, callbacks: Array) -> void:
 | |
| 	self.reference_object = reference_object
 | |
| 	_callbacks.assign(callbacks)
 | |
| 	_callback_index = callbacks.size()
 | |
| 
 | |
| 
 | |
| ## Will execute the next mod hook callable or vanilla method and return the result.[br]
 | |
| ## [br]
 | |
| ## [br][b]Parameters:[/b][br]
 | |
| ## - [param args] ([Array]): An array of all arguments passed into the vanilla function. [br]
 | |
| ## [br]
 | |
| ## [br][b]Returns:[/b][br]
 | |
| ## - [Variant]: Return value of the next function in the chain.[br]
 | |
| ## [br]
 | |
| ## Make sure to call this method [i][color=orange]once[/color][/i] somewhere in the [param mod_callable] you pass to [method ModLoaderMod.add_hook]. [br]
 | |
| func execute_next(args := []) -> Variant:
 | |
| 	var callback := _get_next_callback()
 | |
| 	if not callback:
 | |
| 		return
 | |
| 
 | |
| 	# Vanilla needs to be called without the hook chain being passed
 | |
| 	if _is_callback_vanilla():
 | |
| 		return callback.callv(args)
 | |
| 
 | |
| 	return callback.callv([self] + args)
 | |
| 
 | |
| 
 | |
| ## Same as [method execute_next], but asynchronous - it can be used if a method uses [code]await[/code]. [br]
 | |
| ## [br]
 | |
| ## [br][b]Parameters:[/b][br]
 | |
| ## - [param args] ([Array]): An array of all arguments passed into the vanilla function. [br]
 | |
| ## [br]
 | |
| ## [br][b]Returns:[/b][br]
 | |
| ## - [Variant]: Return value of the next function in the chain.[br]
 | |
| ## [br]
 | |
| ## This hook needs to be used if the vanilla method uses [code]await[/code] somewhere. [br]
 | |
| ## Make sure to call this method [i][color=orange]once[/color][/i] somewhere in the [param mod_callable] you pass to [method ModLoaderMod.add_hook]. [br]
 | |
| func execute_next_async(args := []) -> Variant:
 | |
| 	var callback := _get_next_callback()
 | |
| 	if not callback:
 | |
| 		return
 | |
| 
 | |
| 	# Vanilla needs to be called without the hook chain being passed
 | |
| 	if _is_callback_vanilla():
 | |
| 		return await callback.callv(args)
 | |
| 
 | |
| 	return await callback.callv([self] + args)
 | |
| 
 | |
| 
 | |
| func _get_next_callback() -> Variant:
 | |
| 	_callback_index -= 1
 | |
| 	if not _callback_index >= 0:
 | |
| 		ModLoaderLog.fatal(
 | |
| 			"The hook chain index should never be negative. " +
 | |
| 			"A mod hook has called execute_next twice or ModLoaderHookChain was modified in an unsupported way.",
 | |
| 			LOG_NAME
 | |
| 		)
 | |
| 		return
 | |
| 
 | |
| 	return _callbacks[_callback_index]
 | |
| 
 | |
| 
 | |
| func _is_callback_vanilla() -> bool:
 | |
| 	return _callback_index == 0
 | 
