Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/verify-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Verify Successful Build

on:
pull_request:
types:
- opened
- reopened
- synchronize
branches:
- bleeding-edge
- stable

jobs:
build:
name: Verify Successful Build
runs-on: ubuntu-latest

steps:
- name: Checkout Repo
uses: actions/checkout@v4

- name: Clone Game Assemblies
run: |
git clone https://x-access-token:${{ secrets.GH_PAT }}@github.com/KaBooMa/ScheduleOneAssemblies.git ./ScheduleOneAssemblies

- name: Setup .NET
uses: actions/setup-dotnet@v4

- name: Restore .NET Dependencies
run: dotnet restore

- name: Run .NET Build for Mono
run: dotnet build ./S1API/S1API.csproj -c Mono -f netstandard2.1

- name: Run .NET Build for Il2Cpp
run: dotnet build ./S1API/S1API.csproj -c Il2Cpp -f netstandard2.1
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
obj/
bin/
*.user
*Assemblies/

# Local assembly references
ScheduleOneAssemblies/
15 changes: 12 additions & 3 deletions S1API/DeadDrops/DeadDropInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using S1Economy = ScheduleOne.Economy;
#endif

using System.Linq;
using S1API.Internal.Abstraction;
using S1API.Storages;
using UnityEngine;
Expand All @@ -13,7 +14,7 @@ namespace S1API.DeadDrops
/// <summary>
/// Represents a dead drop in the scene.
/// </summary>
public class DeadDropInstance : ISaveable
public class DeadDropInstance : IGUIDReference
{
/// <summary>
/// INTERNAL: Stores a reference to the game dead drop instance.
Expand All @@ -32,16 +33,24 @@ public class DeadDropInstance : ISaveable
internal DeadDropInstance(S1Economy.DeadDrop deadDrop) =>
S1DeadDrop = deadDrop;

/// <summary>
/// INTERNAL: Gets a dead drop from a GUID value.
/// </summary>
/// <param name="guid"></param>
/// <returns></returns>
internal static DeadDropInstance? GetFromGUID(string guid) =>
DeadDropManager.All.FirstOrDefault(deadDrop => deadDrop.GUID == guid);

/// <summary>
/// The unique identifier assigned for this dead drop.
/// </summary>
public string GUID =>
S1DeadDrop.GUID.ToString();

/// <summary>
/// The storage container associated with this dead drop.
/// </summary>
public StorageInstance StorageInstance =>
public StorageInstance Storage =>
_cachedStorage ??= new StorageInstance(S1DeadDrop.Storage);

/// <summary>
Expand Down
66 changes: 66 additions & 0 deletions S1API/Internal/Abstraction/GUIDReferenceConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Reflection;
using Newtonsoft.Json;
using S1API.Internal.Utils;

namespace S1API.Internal.Abstraction
{
/// <summary>
/// INTERNAL: JSON Converter to handle GUID referencing classes when saved and loaded.
/// </summary>
internal class GUIDReferenceConverter : JsonConverter
{
/// <summary>
/// TODO
/// </summary>
/// <param name="objectType"></param>
/// <returns></returns>
public override bool CanConvert(Type objectType) =>
typeof(IGUIDReference).IsAssignableFrom(objectType);

/// <summary>
/// TODO
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
/// <param name="serializer"></param>
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value is IGUIDReference reference)
{
writer.WriteValue(reference.GUID);
}
else
{
writer.WriteNull();
}
}

/// <summary>
/// TODO
/// </summary>
/// <param name="reader"></param>
/// <param name="objectType"></param>
/// <param name="existingValue"></param>
/// <param name="serializer"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
string? guid = reader.Value?.ToString();
if (string.IsNullOrEmpty(guid))
return null;

MethodInfo? getGUIDMethod = ReflectionUtils.GetMethod(objectType, "GetFromGUID", BindingFlags.NonPublic | BindingFlags.Static);
if (getGUIDMethod == null)
throw new Exception($"The type {objectType.Name} does not have a valid implementation of the GetFromGUID(string guid) method!");

return getGUIDMethod.Invoke(null, new object[] { guid });
}

/// <summary>
/// TODO
/// </summary>
public override bool CanRead => true;
}
}
14 changes: 14 additions & 0 deletions S1API/Internal/Abstraction/IGUIDReference.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace S1API.Internal.Abstraction
{
/// <summary>
/// INTERNAL: Represents a class that should serialize by GUID instead of values directly.
/// This is important to utilize on instances such as dead drops, item definitions, etc.
/// </summary>
internal interface IGUIDReference
{
/// <summary>
/// The GUID associated with the object.
/// </summary>
public string GUID { get; }
}
}
28 changes: 28 additions & 0 deletions S1API/Internal/Abstraction/IRegisterable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace S1API.Internal.Abstraction
{
/// <summary>
/// INTERNAL: Provides rigidity for registerable instance wrappers.
/// </summary>
internal interface IRegisterable
{
/// <summary>
/// INTERNAL: Called upon creation of the instance.
/// </summary>
void CreateInternal();

/// <summary>
/// INTERNAL: Called upon destruction of the instance.
/// </summary>
void DestroyInternal();

/// <summary>
/// Called upon creation of the instance.
/// </summary>
void OnCreated();

/// <summary>
/// Called upon destruction of the instance.
/// </summary>
void OnDestroyed();
}
}
47 changes: 41 additions & 6 deletions S1API/Internal/Abstraction/ISaveable.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,49 @@
namespace S1API.Internal.Abstraction
#if (MONO)
using System.Collections.Generic;
#elif (IL2CPP)
using Il2CppSystem.Collections.Generic;
#endif

using Newtonsoft.Json;

namespace S1API.Internal.Abstraction
{
/// <summary>
/// INTERNAL: Represents a class that should serialize by GUID instead of values directly.
/// This is important to utilize on instanced objects such as dead drops.
/// INTERNAL: Provides rigidity for saveable instance wrappers.
/// </summary>
internal interface ISaveable
internal interface ISaveable : IRegisterable
{
/// <summary>
/// The GUID assocated with the object.
/// INTERNAL: Called when saving the instance.
/// </summary>
public string GUID { get; }
/// <param name="path">Path to save to.</param>
/// <param name="extraSaveables">Manipulation of the base game saveable lists.</param>
void SaveInternal(string path, ref List<string> extraSaveables);

/// <summary>
/// INTERNAL: Called when loading the instance.
/// </summary>
/// <param name="folderPath"></param>
void LoadInternal(string folderPath);

/// <summary>
/// Called when saving the instance.
/// </summary>
void OnSaved();

/// <summary>
/// Called when loading the instance.
/// </summary>
void OnLoaded();

/// <summary>
/// INTERNAL: Standard serialization settings to apply for all saveables.
/// </summary>
internal static JsonSerializerSettings SerializerSettings =>
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
Converters = new System.Collections.Generic.List<JsonConverter>() { new GUIDReferenceConverter() }
};
}
}
55 changes: 55 additions & 0 deletions S1API/Internal/Abstraction/Registerable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
namespace S1API.Internal.Abstraction
{
/// <summary>
/// INTERNAL: A registerable base class for use internally.
/// Not intended for modder use.
/// </summary>
public abstract class Registerable : IRegisterable
{
/// <summary>
/// TODO
/// </summary>
void IRegisterable.CreateInternal() =>
CreateInternal();

/// <summary>
/// TODO
/// </summary>
internal virtual void CreateInternal() =>
OnCreated();

/// <summary>
/// TODO
/// </summary>
void IRegisterable.DestroyInternal() =>
DestroyInternal();

/// <summary>
/// TODO
/// </summary>
internal virtual void DestroyInternal() =>
OnDestroyed();

/// <summary>
/// TODO
/// </summary>
void IRegisterable.OnCreated() =>
OnCreated();

/// <summary>
/// TODO
/// </summary>
protected virtual void OnCreated() { }

/// <summary>
/// TODO
/// </summary>
void IRegisterable.OnDestroyed() =>
OnDestroyed();

/// <summary>
/// TODO
/// </summary>
protected virtual void OnDestroyed() { }
}
}
Loading