Page cover image

🌟Community Hooks

How to get started with submitting community-driven hook changes, requests and additions.

Here are instructions to how to implement your own hooks for the general public using Carbon.

Metadata

For documentation purposes, it's important to properly describe what the hook does, properly identify its ID and flags.

Documentation

These attributes are entirely used by the documentation code-generation system of which outputs can be found here.

  • Info attribute, can be multiple.

    [MetadataAttribute.Info("This hook does this and that.")]
    [MetadataAttribute.Info("This hook also does that and the other.")]

  • Parameter attribute, can be multiple. Are the exact parameter types and a readable name shown in the example.

    [MetadataAttribute.Parameter("dabloons", typeof(int))]
    [MetadataAttribute.Parameter("entity", typeof(BaseEntity))]

  • Return attribute, can only be one or none. It's the displayed return type in the generated example of the hook.

    [MetadataAttribute.Return(typeof(bool))]

Implementation

A primary requirement is the location of the patch, as well as the Prefix, Postfix and/or Transpiler methods.

Attribute

Above the previous metadata attributes (or regardless of the position), you need to add the following attribute, defining the location of the patch.

[HookAttribute.Patch("OnHookName", "OnHookName [main]", typeof(Type), "Method", new System.Type[] { /* Method params */ })]

Notice! If the method you're trying to patch does not have any arguments, please still keep the new System.Type[] { } present.

Patch

We use regular Harmony patches for our hooks, so depending on the purpose of your hook, you may choose to use between a Prefix, Postfix and/or Transpiler.

For example:

public static bool Prefix(BasePlayer ply, ref PatrolHelicopterAI __instance, out bool __result)
{
	if (HookCaller.CallStaticHook(1610282469, __instance, ply) is bool boolean)
	{
		__result = boolean;
		
		// Disallow original code from executing
		return false;
	}
	__result = default;
	
	// Allow original code to execute
	return true;
}

We do not use Interface.CallHook for our hook system which use direct hook name strings, instead we use hook identifiers as they're way faster to process.

We use almost exactly the same system Rust uses with StringPool to get numeric identifiers out of string values.

You can generate your own hook identifier, with our website.

Under this format: https://carbonmod.gg/mdhash/?hook=MyHookName

It should look something like this: 499798872, which then used in the HookCaller, like this:

HookCaller.CallStaticHook(499798872, <params>);

Submission — Pull Request

To get started with submitting your hook(s), please do the following;

  • Fork our Carbon.Hooks.Community repository.

  • Make your changes & commit to the fork.

    • Please use the correct sub-folder which should be treated as the category of the hook.

    • As well as the naming of the hook file should match the hook name. Like src/Category/MyHookName.cs.

  • Create a pull request for us to review and merge.

    • Please describe within your commit what the purpose of the hook is.

Once all that is done, you'll find your hook(s) in the hook page marked as a Carbon-only hook.

Last updated