diff --git a/Features/Enums/BlockType.cs b/Features/Enums/BlockType.cs
index 7555b98..8c6ac17 100644
--- a/Features/Enums/BlockType.cs
+++ b/Features/Enums/BlockType.cs
@@ -44,4 +44,9 @@ public enum BlockType
/// Represents a locker.
///
Locker = 7,
+
+ ///
+ /// Represents a Interactable.
+ ///
+ Interactable = 8,
}
diff --git a/Features/Enums/ToolGunObjectType.cs b/Features/Enums/ToolGunObjectType.cs
index 7c5a07b..b2f822a 100644
--- a/Features/Enums/ToolGunObjectType.cs
+++ b/Features/Enums/ToolGunObjectType.cs
@@ -11,7 +11,8 @@ public enum ToolGunObjectType
PlayerSpawnpoint = 6,
Capybara = 7,
Text = 8,
- Scp079Camera = 9,
- ShootingTarget = 10,
- Teleport = 11,
+ Interactable = 9,
+ Scp079Camera = 10,
+ ShootingTarget = 11,
+ Teleport = 12,
}
diff --git a/Features/ObjectSpawner.cs b/Features/ObjectSpawner.cs
index 821e3a6..64bb09c 100644
--- a/Features/ObjectSpawner.cs
+++ b/Features/ObjectSpawner.cs
@@ -14,6 +14,12 @@ public static PrimitiveObjectToy SpawnPrimitive(SerializablePrimitive serializab
return gameObject.GetComponent();
}
+ public static InvisibleInteractableToy SpawnInteractable(SerializableInteractable serializableInteractable)
+ {
+ GameObject gameObject = serializableInteractable.SpawnOrUpdateObject();
+ return gameObject.GetComponent();
+ }
+
public static SchematicObject SpawnSchematic(SerializableSchematic serializableSchematic)
{
GameObject? gameObject = serializableSchematic.SpawnOrUpdateObject();
diff --git a/Features/PrefabManager.cs b/Features/PrefabManager.cs
index c87ecfe..2953ed9 100644
--- a/Features/PrefabManager.cs
+++ b/Features/PrefabManager.cs
@@ -11,6 +11,8 @@ public static class PrefabManager
public static PrimitiveObjectToy PrimitiveObjectPrefab { get; private set; }
public static LightSourceToy LightSourcePrefab { get; private set; }
+
+ public static InvisibleInteractableToy InvisibleInteractableToy { get; private set; }
public static DoorVariant LczDoorPrefab { get; private set; }
public static DoorVariant HczDoorPrefab { get; private set; }
@@ -48,6 +50,12 @@ public static void RegisterPrefabs()
LightSourcePrefab = lightSourceToy;
continue;
}
+
+ if (gameObject.TryGetComponent(out InvisibleInteractableToy invisibleInteractableToy))
+ {
+ InvisibleInteractableToy = invisibleInteractableToy;
+ continue;
+ }
if (gameObject.TryGetComponent(out DoorVariant doorVariant))
{
diff --git a/Features/Serializable/MapSchematic.cs b/Features/Serializable/MapSchematic.cs
index e0e70aa..1bc2699 100644
--- a/Features/Serializable/MapSchematic.cs
+++ b/Features/Serializable/MapSchematic.cs
@@ -24,6 +24,8 @@ public MapSchematic(string mapName)
public Dictionary Primitives { get; set; } = [];
public Dictionary Lights { get; set; } = [];
+
+ public Dictionary Interactables { get; set; } = [];
public Dictionary Doors { get; set; } = [];
@@ -51,6 +53,7 @@ public MapSchematic Merge(MapSchematic other)
{
Primitives.AddRange(other.Primitives);
Lights.AddRange(other.Lights);
+ Interactables.AddRange(other.Interactables);
Doors.AddRange(other.Doors);
Workstations.AddRange(other.Workstations);
ItemSpawnpoints.AddRange(other.ItemSpawnpoints);
@@ -74,6 +77,7 @@ public void Reload()
Primitives.ForEach(kVP => SpawnObject(kVP.Key, kVP.Value));
Lights.ForEach(kVP => SpawnObject(kVP.Key, kVP.Value));
+ Interactables.ForEach(kVP => SpawnObject(kVP.Key, kVP.Value));
Doors.ForEach(kVP =>
{
Door? vanillaDoor = Door.Get(kVP.Key);
diff --git a/Features/Serializable/Schematics/SchematicBlockData.cs b/Features/Serializable/Schematics/SchematicBlockData.cs
index f2ee1c8..aa5df37 100644
--- a/Features/Serializable/Schematics/SchematicBlockData.cs
+++ b/Features/Serializable/Schematics/SchematicBlockData.cs
@@ -41,6 +41,7 @@ public GameObject Create(SchematicObject schematicObject, Transform parentTransf
BlockType.Light => CreateLight(),
BlockType.Pickup => CreatePickup(schematicObject),
BlockType.Workstation => CreateWorkstation(),
+ BlockType.Interactable => CreateInteractable(),
_ => CreateEmpty(true)
};
@@ -138,4 +139,16 @@ private GameObject CreateWorkstation()
return workstation.gameObject;
}
+
+ private GameObject CreateInteractable()
+ {
+ InvisibleInteractableToy interactableToy = GameObject.Instantiate(PrefabManager.InvisibleInteractableToy);
+ interactableToy.NetworkMovementSmoothing = 60;
+
+ interactableToy.NetworkShape = (InvisibleInteractableToy.ColliderShape)Convert.ToInt32(Properties["Shape"]);
+ interactableToy.NetworkInteractionDuration = float.Parse(Properties["InteractionDuration"].ToString());
+ interactableToy.NetworkIsLocked = bool.Parse(Properties["IsLocked"].ToString());
+
+ return interactableToy.gameObject;
+ }
}
diff --git a/Features/Serializable/SerializableInteractable.cs b/Features/Serializable/SerializableInteractable.cs
new file mode 100644
index 0000000..4e6d402
--- /dev/null
+++ b/Features/Serializable/SerializableInteractable.cs
@@ -0,0 +1,36 @@
+using AdminToys;
+using Room = LabApi.Features.Wrappers.Room;
+using Mirror;
+using ProjectMER.Features.Extensions;
+using ProjectMER.Features.Interfaces;
+using UnityEngine;
+
+namespace ProjectMER.Features.Serializable;
+
+public class SerializableInteractable : SerializableObject
+{
+ public InvisibleInteractableToy.ColliderShape Shape { get; set; } = InvisibleInteractableToy.ColliderShape.Box;
+ public float InteractionDuration { get; set; } = 5f;
+ public bool Locked { get; set; } = false;
+
+ public override GameObject SpawnOrUpdateObject(Room? room = null, GameObject? instance = null)
+ {
+ InvisibleInteractableToy interactableToy = instance == null ? UnityEngine.Object.Instantiate(PrefabManager.InvisibleInteractableToy) : instance.GetComponent();
+ Vector3 position = room.GetAbsolutePosition(Position);
+ Quaternion rotation = room.GetAbsoluteRotation(Rotation);
+ _prevIndex = Index;
+
+ interactableToy.transform.SetPositionAndRotation(position, rotation);
+ interactableToy.transform.localScale = Scale;
+ interactableToy.NetworkMovementSmoothing = 60;
+
+ interactableToy.NetworkShape = Shape;
+ interactableToy.NetworkInteractionDuration = InteractionDuration;
+ interactableToy.NetworkIsLocked = Locked;
+
+ if (instance == null)
+ NetworkServer.Spawn(interactableToy.gameObject);
+
+ return interactableToy.gameObject;
+ }
+}
\ No newline at end of file
diff --git a/Features/ToolGun/ToolGunItem.cs b/Features/ToolGun/ToolGunItem.cs
index 2d26ec1..6362371 100644
--- a/Features/ToolGun/ToolGunItem.cs
+++ b/Features/ToolGun/ToolGunItem.cs
@@ -20,6 +20,7 @@ public class ToolGunItem
{
{ ToolGunObjectType.Primitive, typeof(SerializablePrimitive) },
{ ToolGunObjectType.Light, typeof(SerializableLight) },
+ { ToolGunObjectType.Interactable, typeof(SerializableInteractable) },
{ ToolGunObjectType.Door, typeof(SerializableDoor) },
{ ToolGunObjectType.Workstation, typeof(SerializableWorkstation) },
{ ToolGunObjectType.ItemSpawnpoint, typeof(SerializableItemSpawnpoint)},