Skip to content

Commit

Permalink
Merge branch 'master' into docs
Browse files Browse the repository at this point in the history
  • Loading branch information
LeeTwentyThree committed Jun 28, 2023
2 parents 860f3ee + dad7ddd commit 2717a5c
Show file tree
Hide file tree
Showing 14 changed files with 499 additions and 4 deletions.
43 changes: 43 additions & 0 deletions .github/workflows/cla.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: "CLA Assistant"
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened,closed,synchronize]

# explicitly configure permissions, in case your GITHUB_TOKEN workflow permissions are set to read-only in repository settings
permissions:
actions: write
contents: write
pull-requests: write
statuses: write

jobs:
CLAAssistant:
runs-on: ubuntu-latest
steps:
- name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
uses: contributor-assistant/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret
# This token is required only if you have configured to store the signatures in a remote repository/organization
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with:
path-to-signatures: 'CLA/Signatures.json'
path-to-document: 'https://github.com/SubnauticaModding/Nautilus/blob/master/CLA/CLA.md' # e.g. a CLA or a DCO document
# branch should not be protected
branch: 'master'
# allowlist: user1,bot*

# the followings are the optional inputs - If the optional inputs are not given, then default values will be taken
#remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)
#remote-repository-name: enter the remote repository name where the signatures should be stored (Default is storing the signatures in the same repository)
#create-file-commit-message: 'For example: Creating file for storing CLA Signatures'
#signed-commit-message: 'For example: $contributorName has signed the CLA in $owner/$repo#$pullRequestNo'
#custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign'
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
#use-dco-flag: true - If you are using DCO instead of CLA
14 changes: 14 additions & 0 deletions CLA/CLA.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Subnautica Modding Nautilus CLA

This Contributor License Agreement (CLA) must be signed by any individual who wishes to contribute to the Nautilus API after June 20th, 2023. Given the challenges in obtaining approvals from all current and previous contributors for project-wide decisions, this agreement has become a necessity.

In the context of this document, "you" refers to the contributor and "we" refers to the Subnautica Modding organization (<https://github.com/SubnauticaModding>). A "contribution" is defined as any act of merging a contributor's work into this repository.

**By signing this CLA, you agree to be bound by the following statements, which apply to all current, previous, and future versions of the Nautilus API, and will remain in effect until this CLA is terminated or superseded**:

1. You grant the Subnautica Modding organization a non-exclusive, irrevocable, and transferable license to use, copy, prepare derivatives, distribute, and display your contribution on any licensing terms.
2. You also grant permission to the Subnautica Modding organization to make a fair license change without your approval. A "fair license change" will not have the intent to forbid future contributions or derivative works. A license change may occur following the unanimous decision of all maintainers, which includes anyone who has write access to the repository at the time of making the decision, but also requires the permission of all previous contributors who did not sign this CLA.

It is important to note that the Subnautica Modding organization will NEVER sell, commercialize, or otherwise restrict the open-source status of Nautilus.

If you have contributed to Nautilus in the past, you are not bound by the aforementioned statements until signing. However, you may be required to sign the CLA before future PRs are accepted. Please note that signing this CLA will affect all prior, current, and future contributions.
28 changes: 28 additions & 0 deletions CLA/Signatures.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"signedContributors": [
{
"name": "LeeTwentyThree",
"id": 31892011,
"comment_id": 1610283944,
"created_at": "2023-06-27T22:07:59Z",
"repoId": 123711758,
"pullRequestNo": 424
},
{
"name": "EldritchCarMaker",
"id": 97289845,
"comment_id": 1610293147,
"created_at": "2023-06-27T22:14:54Z",
"repoId": 123711758,
"pullRequestNo": 348
},
{
"name": "VELD-Dev",
"id": 36549174,
"comment_id": 1610296982,
"created_at": "2023-06-27T22:17:50Z",
"repoId": 123711758,
"pullRequestNo": 391
}
]
}
3 changes: 3 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Contributing

## Contributor License Agreement
New contributions will not be accepted unless you agree to and sign [this CLA](CLA/CLA.md). The signing process is automatic and should not in any way affect your ability to contribute. This is only required to protect the repository against possible legal issues in the future.

## Preferred conventions and code style
* For commiting, we encourage [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary).
* We encourage [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) to be specified explicitly with no exceptions.
Expand Down
65 changes: 65 additions & 0 deletions Nautilus/Assets/PrefabTemplates/AssetBundleTemplate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

namespace Nautilus.Assets.PrefabTemplates;

/// <summary>
/// A PrefabTemplate used for loading objects in from asset bundles
/// </summary>
public class AssetBundleTemplate : PrefabTemplate
{
private static Dictionary<Assembly, AssetBundle> _loadedBundles = new Dictionary<Assembly, AssetBundle>();

/// <summary>
/// Instantiates a new AssetBundleTemplate
/// </summary>
/// <param name="bundle">The AssetBundle to load the asset from</param>
/// <param name="prefabName">The name of the prefab gameobject to load from the bundle</param>
/// <param name="info">The prefab info to base this template off of.</param>
public AssetBundleTemplate(AssetBundle bundle, string prefabName, PrefabInfo info) : base(info)
{
_prefab = bundle.LoadAsset<GameObject>(prefabName);
}

/// <summary>
/// Instantiates a new AssetBundleTemplate. Automatically loads the bundle by calling <see cref = "Utility.AssetBundleLoadingUtils.LoadFromAssetsFolder(Assembly, string)"/>,
/// which expects the bundle to be in your mod's Assets folder.
/// <para>Also caches the loaded bundle for future use.</para>
/// <para>If you are loading and using your bundle on your own, it's highly recommended to use the AssetBundle constructor overload instead.</para>
/// <para>Bundles are cached per Assembly, and won't work with mods that use multiple seperate bundles.</para>
/// </summary>
/// <param name="assetBundleFileName">The file name of the asset bundle. These often do not have file extensions.</param>
/// <param name="prefabName">The name of the prefab GameObject to load from the bundle.</param>
/// <param name="info">The prefab info to base this template off of.</param>
/// <param name="modAssembly">The <see cref="Assembly"/> of the mod that contains the given Asset Bundle. If left unassigned, this will be automatically set to
/// <see cref="Assembly.GetCallingAssembly"/>.</param>
public AssetBundleTemplate(string assetBundleFileName, string prefabName, PrefabInfo info, Assembly modAssembly = null) : base(info)
{
AssetBundle bundle;

var assembly = modAssembly ?? Assembly.GetCallingAssembly();

if (!_loadedBundles.TryGetValue(assembly, out bundle))
{
bundle = Utility.AssetBundleLoadingUtils.LoadFromAssetsFolder(assembly, assetBundleFileName);
_loadedBundles.Add(assembly, bundle);
}

_prefab = bundle.LoadAsset<GameObject>(prefabName);
}

private GameObject _prefab;

/// <inheritdoc/>
public override IEnumerator GetPrefabAsync(TaskResult<GameObject> gameObject)
{
gameObject.Set(_prefab);
yield return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@
In Subnautica, objects are created (obviously). Peepers spawn in the water around you. Titanium appears when outcrops are broken.
Your Seamoth is built in front of you as soon as you craft it. But how exactly is this done, and how can you recreate this in your own mods?

In reality there are many ways to do this. There are likely some that have yet to be discovered. Each method has its ups and downs,
In reality, there are countless ways to spawn prefabs into the world. Chances are some have not even been discovered yet. Each method has its ups and downs,
so it's a good idea to be familiar with all of them.

> [!IMPORTANT]
> If you are accessing a prefab for reference purposes (like reusing its materials for another prefab), then please do NOT instantiate it. Instead, access the prefab that was loaded directly,
*without* calling the Instantiate method. This works perfectly fine. You should only call Instantiate if you want it to appear in the world.

> [!IMPORTANT]
> Some prefabs (often modded ones) may be inactive by default, so it is suggested to call `SetActive(true)` on any instances of newly instantiated prefab.
## Asynchronous loading

---
Expand Down
4 changes: 2 additions & 2 deletions Nautilus/Documentation/tutorials/prefabs-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Subnautica and why they are important.
At the most basic levels, prefabs are simply [GameObjects](https://docs.unity3d.com/Manual/class-GameObject.html) that are instantiated into a scene. This is a Unity
Engine concept, and it applies for Subnautica modding as well.

In Subnautica, prefabs are essentially anything that exists in the world outside of terrain, the player, and a few other exceptions. This encompasses anything from
In Subnautica, prefabs are essentially anything that exists in the world outside of terrain and the player, with a few other exceptions. This encompasses anything from
creatures to base modules to unnamed rock formations and debris props. They are registered and managed by the `UWE.PrefabDatabase` class. Nautilus allows you to indirectly
register your own custom prefabs into this system.

Expand Down Expand Up @@ -41,4 +41,4 @@ Nautilus handles most of this for you, besides Pickupable.
- TechTag: Holds the TechType of your prefab. This is not required for prefabs, but is needed for *many* cases. It's nice because it lets you use the spawn command.
- LargeWorldEntity: Heavily recommended. Generally needed for a prefab to save properly. You also will want to set its `cellLevel` field to change its loading distance.
- SkyApplier: Required for proper shading whenever you have a custom model.
- Pickupable: Not required unless you are making an inventory item.
- Pickupable: Not required unless you are making an inventory item.
2 changes: 1 addition & 1 deletion Nautilus/Documentation/tutorials/story-goals.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Every Story Goal has an assigned Goal Type which determines the action that is e
This is the main class for interacting with the game's Story Goal system. It allows you to add goals to specific trackers and gives you full control over their actions on completion.

> [!WARNING]
> As of now, the `StoryGoalHandler` class is only designed to work for the first Subnautica game. Remember, you can [always contribute](https://github.com/SubnauticaModding/Nautilus/blob/master/Nautilus/Handlers/StoryGoalHandler_Subnautica.cs).
> As of now, the `StoryGoalHandler` class has only been tested for the first Subnautica game. If you notice any issues with Below Zero, remember you can [always contribute](https://github.com/SubnauticaModding/Nautilus/blob/master/Nautilus/Handlers/StoryGoalHandler.cs).
A more comprehensive overview of the class can be viewed [here](https://subnauticamodding.github.io/Nautilus/api/Nautilus.Handlers.StoryGoalHandler.html).

Expand Down
33 changes: 33 additions & 0 deletions Nautilus/Utility/ModMessages/BasicModMessageReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;

namespace Nautilus.Utility.ModMessages;

/// <summary>
/// Basic implementation of the abstract <see cref="ModMessageReader"/> that runs an action when a message with the given subject is received.
/// </summary>
public sealed class BasicModMessageReader : ModMessageReader
{
private string _subject;

private Action<object[]> _action;

/// <summary>
/// Creates a message reader that runs the given <paramref name="action"/> when a message with the given <paramref name="subject"/> is received.
/// </summary>
/// <param name="subject">The subject that this reader is looking for.</param>
/// <param name="action">The action that is run for any message with the given <paramref name="subject"/>.</param>
public BasicModMessageReader(string subject, Action<object[]> action)
{
_subject = subject;
_action = action;
}

/// <inheritdoc/>
protected internal override void OnReceiveMessage(ModMessage message)
{
if (message.Subject == _subject)
{
_action.Invoke(message.Contents);
}
}
}
29 changes: 29 additions & 0 deletions Nautilus/Utility/ModMessages/GlobalMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Collections.Generic;

namespace Nautilus.Utility.ModMessages;

internal class GlobalMessage
{
// the message's data

private ModMessage Message { get; }

// a list of all the addresses that have already received the message

private readonly List<string> _sentAddresses = new();

public GlobalMessage(ModMessage message)
{
Message = message;
}

public bool TrySendMessageToInbox(ModInbox inbox)
{
if (!inbox.AcceptsGlobalMessages || !inbox.IsAcceptingMessages || _sentAddresses.Contains(inbox.Address))
return false;

inbox.ReceiveMessage(Message);
_sentAddresses.Add(inbox.Address);
return true;
}
}
99 changes: 99 additions & 0 deletions Nautilus/Utility/ModMessages/ModInbox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;

namespace Nautilus.Utility.ModMessages;

/// <summary>
/// An object with an address. Receives mail and allows it to be read at any time. Any held messages (messages sent before this inbox was created) will not be read
/// until the <see cref="ReadAnyHeldMessages"/> method is called.
/// </summary>
public class ModInbox
{
private List<ModMessageReader> _messageReaders = new List<ModMessageReader>();

/// <summary>
/// The address of this inbox. Conventionally should match the mod's GUID.
/// </summary>
public string Address { get; }

/// <summary>
/// If <see langword="false"/>, this inbox will not automatically read messages and will instead put any received messages on hold. If you are setting this property to
/// <see langword="true"/> at a later time, you still need to call <see cref="ReadAnyHeldMessages"/> to catch up.
/// </summary>
public bool IsAcceptingMessages { get; set; }

/// <summary>
/// Determines whether this inbox can receive global messages or not.
/// </summary>
public bool AcceptsGlobalMessages { get; set; }

/// <summary>
/// Constructs an inbox with the given <paramref name="address"/>.
/// </summary>
/// <param name="address">The address of this inbox. Other mods will use this string to contact this mod. Conventionally should match the mod's GUID. This parameter should NOT be
/// changed if any other mod is already using it!</param>
/// <param name="acceptsGlobalMessages">Determines whether this inbox can receive global messages or not.</param>
/// <param name="acceptingAllMessages">If <see langword="false"/>, this inbox will not automatically read messages and will instead put any received messages on hold.</param>
public ModInbox(string address, bool acceptsGlobalMessages = false, bool acceptingAllMessages = true)
{
Address = address;
AcceptsGlobalMessages = acceptsGlobalMessages;
IsAcceptingMessages = acceptingAllMessages;
}

/// <summary>
/// Adds an object that reads and handles any received messages.
/// </summary>
/// <param name="reader">The instance of the <see cref="ModMessageReader"/> to register.</param>
public void AddMessageReader(ModMessageReader reader)
{
_messageReaders.Add(reader);
}

internal void ReceiveMessage(ModMessage message)
{
foreach (var reader in _messageReaders)
{
try
{
reader.OnReceiveMessage(message);
}
catch (Exception e)
{
InternalLogger.Error("Exception caught in messaging system: " + e);
}
}
}

internal bool ReceiveDataRequest(ModMessage message, out object returnValue)
{
foreach (var reader in _messageReaders)
{
try
{
if (reader.TryHandleDataRequest(message, out returnValue))
return true;
}
catch (Exception e)
{
InternalLogger.Error("Exception caught in messaging system: " + e);
}
}
returnValue = null;
return false;
}

/// <summary>
/// Reads any messages that were sent to this address before the inbox was created. This will NOT do anything if <see cref="IsAcceptingMessages"/> is <see langword="false"/>!!!
/// </summary>
public void ReadAnyHeldMessages()
{
if (!IsAcceptingMessages)
{
InternalLogger.Warn($"Calling ReadAnyHeldMessages on inbox '{Address}' when it is not accepting messages!");
return;
}

ModMessageSystem.SendHeldMessagesToInbox(this);
}
}
Loading

0 comments on commit 2717a5c

Please sign in to comment.