Skip to content

Commit

Permalink
fix: rework prefab helper (#266)
Browse files Browse the repository at this point in the history
  • Loading branch information
BoltonDev authored Nov 30, 2024
1 parent ce37627 commit 691fb20
Showing 4 changed files with 111 additions and 59 deletions.
100 changes: 56 additions & 44 deletions EXILED/Exiled.API/Features/PrefabHelper.cs
Original file line number Diff line number Diff line change
@@ -9,8 +9,6 @@ namespace Exiled.API.Features
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;

using Exiled.API.Enums;
@@ -23,83 +21,97 @@ namespace Exiled.API.Features
/// </summary>
public static class PrefabHelper
{
private static readonly Dictionary<PrefabType, GameObject> Stored = new();
/// <summary>
/// A <see cref="Dictionary{TKey,TValue}"/> containing all <see cref="PrefabType"/> and their corresponding <see cref="GameObject"/>.
/// </summary>
internal static readonly Dictionary<PrefabType, GameObject> Prefabs = new(Enum.GetValues(typeof(PrefabType)).Length);

/// <summary>
/// Gets a dictionary of <see cref="PrefabType"/> to <see cref="GameObject"/>.
/// Gets a <see cref="IReadOnlyDictionary{TKey,TValue}"/> of <see cref="PrefabType"/> and their corresponding <see cref="GameObject"/>.
/// </summary>
public static ReadOnlyDictionary<PrefabType, GameObject> PrefabToGameObject => new(Stored);
public static IReadOnlyDictionary<PrefabType, GameObject> PrefabToGameObject => Prefabs;

/// <summary>
/// Gets the prefab attribute of a prefab type.
/// Gets the <see cref="PrefabAttribute"/> from a <see cref="PrefabType"/>.
/// </summary>
/// <param name="prefabType">The prefab type.</param>
/// <returns>The <see cref="PrefabAttribute" />.</returns>
/// <param name="prefabType">The <see cref="PrefabType"/>.</param>
/// <returns>The corresponding <see cref="PrefabAttribute"/>.</returns>
public static PrefabAttribute GetPrefabAttribute(this PrefabType prefabType)
{
Type type = prefabType.GetType();
return type.GetField(Enum.GetName(type, prefabType)).GetCustomAttribute<PrefabAttribute>();
}

/// <summary>
/// Gets the prefab of the specified <see cref="PrefabType"/>.
/// Gets the <see cref="GameObject"/> of the specified <see cref="PrefabType"/>.
/// </summary>
/// <param name="prefabType">The <see cref="PrefabType"/>.</param>
/// <returns>Returns the <see cref="GameObject"/>.</returns>
public static GameObject GetPrefab(PrefabType prefabType)
{
if (Prefabs.TryGetValue(prefabType, out GameObject prefab))
return prefab;

return null;
}

/// <summary>
/// Tries to get the <see cref="GameObject"/> of the specified <see cref="PrefabType"/>.
/// </summary>
/// <param name="prefabType">The <see cref="PrefabType"/>.</param>
/// <param name="gameObject">The <see cref="GameObject"/> of the .</param>
/// <returns>Returns true if the <see cref="GameObject"/> was found.</returns>
public static bool TryGetPrefab(PrefabType prefabType, out GameObject gameObject)
{
gameObject = GetPrefab(prefabType);
return gameObject is not null;
}

/// <summary>
/// Gets a <see cref="Component"/> from the <see cref="GameObject"/> of the specified <see cref="PrefabType"/>.
/// </summary>
/// <param name="type">The <see cref="PrefabType"/> to get prefab of.</param>
/// <typeparam name="T">The <see cref="Component"/> to get.</typeparam>
/// <returns>Returns the prefab component as {T}.</returns>
public static T GetPrefab<T>(PrefabType type)
/// <param name="prefabType">The <see cref="PrefabType"/>.</param>
/// <typeparam name="T">The <see cref="Component"/> type.</typeparam>
/// <returns>Returns the <see cref="Component"/>.</returns>
public static T GetPrefab<T>(PrefabType prefabType)
where T : Component
{
if (!Stored.TryGetValue(type, out GameObject gameObject) || !gameObject.TryGetComponent(out T component))
return null;
if (Prefabs.TryGetValue(prefabType, out GameObject prefab) && prefab.TryGetComponent(out T component))
return component;

return component;
return null;
}

/// <summary>
/// Spawns a prefab on server.
/// Spawns the <see cref="GameObject"/> of the specified <see cref="PrefabType"/>.
/// </summary>
/// <param name="prefabType">The prefab type.</param>
/// <param name="position">The position to spawn the prefab.</param>
/// <param name="rotation">The rotation of the prefab.</param>
/// <returns>The <see cref="GameObject"/> instantied.</returns>
/// <param name="prefabType">The <see cref="PrefabType"/>.</param>
/// <param name="position">The <see cref="Vector3"/> position where the <see cref="GameObject"/> will spawn.</param>
/// <param name="rotation">The <see cref="Quaternion"/> rotation of the <see cref="GameObject"/>.</param>
/// <returns>Returns the <see cref="GameObject"/> instantied.</returns>
public static GameObject Spawn(PrefabType prefabType, Vector3 position = default, Quaternion rotation = default)
{
if (!Stored.TryGetValue(prefabType, out GameObject gameObject))
if (!TryGetPrefab(prefabType, out GameObject gameObject))
return null;

GameObject newGameObject = UnityEngine.Object.Instantiate(gameObject, position, rotation);
NetworkServer.Spawn(newGameObject);
return newGameObject;
}

/// <summary>
/// Spawns a prefab on server.
/// Spawns the <see cref="GameObject"/> of the specified <see cref="PrefabType"/>.
/// </summary>
/// <param name="prefabType">The prefab type.</param>
/// <param name="position">The position to spawn the prefab.</param>
/// <param name="rotation">The rotation of the prefab.</param>
/// <param name="prefabType">The <see cref="PrefabType"/>.</param>
/// <param name="position">The <see cref="Vector3"/> position where the <see cref="GameObject"/> will spawn.</param>
/// <param name="rotation">The <see cref="Quaternion"/> rotation of the <see cref="GameObject"/>.</param>
/// <typeparam name="T">The <see cref="Component"/> type.</typeparam>
/// <returns>The <see cref="Component"/> instantied.</returns>
/// <returns>Returns the <see cref="Component"/> of the <see cref="GameObject"/>.</returns>
public static T Spawn<T>(PrefabType prefabType, Vector3 position = default, Quaternion rotation = default)
where T : Component
{
T obj = UnityEngine.Object.Instantiate(GetPrefab<T>(prefabType), position, rotation);
NetworkServer.Spawn(obj.gameObject);
return obj;
}

/// <summary>
/// Loads all prefabs.
/// </summary>
internal static void LoadPrefabs()
{
Stored.Clear();

foreach (PrefabType prefabType in EnumUtils<PrefabType>.Values)
{
PrefabAttribute attribute = prefabType.GetPrefabAttribute();
Stored.Add(prefabType, NetworkClient.prefabs.FirstOrDefault(prefab => prefab.Key == attribute.AssetId || prefab.Value.name.Contains(attribute.Name)).Value);
}
GameObject gameObject = Spawn(prefabType, position, rotation);
return gameObject?.GetComponent<T>();
}
}
}
2 changes: 2 additions & 0 deletions EXILED/Exiled.Events/Events.cs
Original file line number Diff line number Diff line change
@@ -59,6 +59,7 @@ public override void OnEnabled()
Log.Info($"{(Config.UseDynamicPatching ? "Non-event" : "All")} patches completed in {watch.Elapsed}");
PlayerAuthenticationManager.OnInstanceModeChanged -= RoleAssigner.CheckLateJoin;

CustomNetworkManager.OnClientStarted += Handlers.Internal.ClientStarted.OnClientStarted;
SceneManager.sceneUnloaded += Handlers.Internal.SceneUnloaded.OnSceneUnloaded;
MapGeneration.SeedSynchronizer.OnGenerationFinished += Handlers.Internal.MapGenerated.OnMapGenerated;
UsableItemsController.ServerOnUsingCompleted += Handlers.Internal.Round.OnServerOnUsingCompleted;
@@ -91,6 +92,7 @@ public override void OnDisabled()

Unpatch();

CustomNetworkManager.OnClientStarted -= Handlers.Internal.ClientStarted.OnClientStarted;
SceneManager.sceneUnloaded -= Handlers.Internal.SceneUnloaded.OnSceneUnloaded;
MapGeneration.SeedSynchronizer.OnGenerationFinished -= Handlers.Internal.MapGenerated.OnMapGenerated;
UsableItemsController.ServerOnUsingCompleted -= Handlers.Internal.Round.OnServerOnUsingCompleted;
53 changes: 53 additions & 0 deletions EXILED/Exiled.Events/Handlers/Internal/ClientStarted.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// -----------------------------------------------------------------------
// <copyright file="ClientStarted.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.Handlers.Internal
{
using System.Collections.Generic;
using System.Linq;

using Exiled.API.Enums;
using Exiled.API.Features;
using Exiled.API.Features.Attributes;
using Mirror;
using PlayerRoles.Ragdolls;
using UnityEngine;

/// <summary>
/// Handles on client started event.
/// </summary>
internal static class ClientStarted
{
/// <summary>
/// Called once when the client is started.
/// </summary>
public static void OnClientStarted()
{
PrefabHelper.Prefabs.Clear();

Dictionary<uint, GameObject> prefabs = new();

foreach (KeyValuePair<uint, GameObject> prefab in NetworkClient.prefabs)
{
if(!prefabs.ContainsKey(prefab.Key))
prefabs.Add(prefab.Key, prefab.Value);
}

foreach (NetworkIdentity ragdollPrefab in RagdollManager.AllRagdollPrefabs)
{
if(!prefabs.ContainsKey(ragdollPrefab.assetId))
prefabs.Add(ragdollPrefab.assetId, ragdollPrefab.gameObject);
}

foreach (PrefabType prefabType in EnumUtils<PrefabType>.Values)
{
PrefabAttribute attribute = prefabType.GetPrefabAttribute();
PrefabHelper.Prefabs.Add(prefabType, prefabs.FirstOrDefault(prefab => prefab.Key == attribute.AssetId || prefab.Value.name.Contains(attribute.Name)).Value);
}
}
}
}
15 changes: 0 additions & 15 deletions EXILED/Exiled.Events/Handlers/Internal/MapGenerated.cs
Original file line number Diff line number Diff line change
@@ -7,25 +7,11 @@

namespace Exiled.Events.Handlers.Internal
{
using System;
using System.Collections.Generic;
using System.Linq;

using API.Features;
using API.Features.Items;
using API.Features.Pools;
using API.Structs;

using Exiled.API.Enums;
using Exiled.API.Extensions;
using Exiled.API.Features.Lockers;
using InventorySystem.Items.Firearms.Attachments;
using InventorySystem.Items.Firearms.Attachments.Components;

using MEC;

using Utils.NonAllocLINQ;

/// <summary>
/// Handles <see cref="Handlers.Map.Generated"/> event.
/// </summary>
@@ -46,7 +32,6 @@ internal static class MapGenerated
public static void OnMapGenerated()
{
Map.ClearCache();
PrefabHelper.LoadPrefabs();
Locker.ClearCache();

// TODO: Fix For (https://git.scpslgame.com/northwood-qa/scpsl-bug-reporting/-/issues/377)

0 comments on commit 691fb20

Please sign in to comment.