first commit

This commit is contained in:
2025-07-06 00:23:46 +02:00
commit 38f50c8819
1788 changed files with 112878 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
using System.Collections.Generic;
using NitroxModel.DataStructures.GameLogic;
using NitroxModel_Subnautica.DataStructures;
using NitroxServer.GameLogic.Entities;
namespace NitroxServer_Subnautica.GameLogic.Entities;
public class SimulationWhitelist : ISimulationWhitelist
{
/// <inheritdoc cref="ISimulationWhitelist.MovementWhitelist" />
public static readonly HashSet<NitroxTechType> MovementWhitelist = new()
{
TechType.Shocker.ToDto(),
TechType.Biter.ToDto(),
TechType.Blighter.ToDto(),
TechType.BoneShark.ToDto(),
TechType.Crabsnake.ToDto(),
TechType.CrabSquid.ToDto(),
TechType.Crash.ToDto(),
TechType.GhostLeviathan.ToDto(),
TechType.GhostLeviathanJuvenile.ToDto(),
TechType.GhostRayBlue.ToDto(),
TechType.GhostRayRed.ToDto(),
TechType.Mesmer.ToDto(),
TechType.LavaLizard.ToDto(),
TechType.LavaEyeye.ToDto(),
TechType.LavaBoomerang.ToDto(),
TechType.LargeFloater.ToDto(),
TechType.LargeKoosh.ToDto(),
TechType.SpineEel.ToDto(),
TechType.Spinefish.ToDto(),
TechType.Sandshark.ToDto(),
TechType.SeaDragon.ToDto(),
TechType.SeaEmperor.ToDto(),
TechType.SeaEmperorBaby.ToDto(),
TechType.SeaEmperorJuvenile.ToDto(),
TechType.SeaEmperorLeviathan.ToDto(),
TechType.ReaperLeviathan.ToDto(),
TechType.Stalker.ToDto(),
TechType.Warper.ToDto(),
TechType.Bladderfish.ToDto(),
TechType.Boomerang.ToDto(),
TechType.Cutefish.ToDto(),
TechType.Eyeye.ToDto(),
TechType.Jellyray.ToDto(),
TechType.GarryFish.ToDto(),
TechType.Gasopod.ToDto(),
TechType.HoleFish.ToDto(),
TechType.Hoopfish.ToDto(),
TechType.Hoverfish.ToDto(),
TechType.Oculus.ToDto(),
TechType.RabbitRay.ToDto(),
TechType.Reefback.ToDto(),
TechType.Reginald.ToDto(),
TechType.SeaTreader.ToDto(),
TechType.Skyray.ToDto(),
TechType.Spadefish.ToDto(),
TechType.Spinefish.ToDto(),
TechType.BlueAmoeba.ToDto(),
TechType.Shuttlebug.ToDto(),
TechType.CaveCrawler.ToDto(),
TechType.Floater.ToDto(),
TechType.LavaLarva.ToDto(),
TechType.Rockgrub.ToDto(),
TechType.Shuttlebug.ToDto(),
TechType.Bloom.ToDto(),
TechType.RockPuncher.ToDto(),
TechType.Peeper.ToDto(),
TechType.Jumper.ToDto(),
TechType.Constructor.ToDto()
};
/// <inheritdoc cref="ISimulationWhitelist.UtilityWhitelist" />
public static readonly HashSet<NitroxTechType> UtilityWhitelist = new()
{
TechType.CrashHome.ToDto()
};
HashSet<NitroxTechType> ISimulationWhitelist.MovementWhitelist => MovementWhitelist;
HashSet<NitroxTechType> ISimulationWhitelist.UtilityWhitelist => UtilityWhitelist;
}

View File

@@ -0,0 +1,15 @@
using NitroxModel.DataStructures.GameLogic.Entities;
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
using NitroxServer.GameLogic.Entities.Spawning;
using NitroxServer.Helper;
namespace NitroxServer_Subnautica.GameLogic.Entities.Spawning.EntityBootstrappers;
public class CrashHomeBootstrapper : IEntityBootstrapper
{
public void Prepare(ref WorldEntity entity, DeterministicGenerator deterministicBatchGenerator)
{
// Set 0 for spawnTime so that CrashHome.Update can spawn a Crash if Start() couldn't
entity.Metadata = new CrashHomeMetadata(0);
}
}

View File

@@ -0,0 +1,17 @@
using NitroxModel.DataStructures.GameLogic.Entities;
using NitroxServer.GameLogic.Entities.Spawning;
using NitroxServer.Helper;
namespace NitroxServer_Subnautica.GameLogic.Entities.Spawning;
public class GeyserBootstrapper : IEntityBootstrapper
{
public void Prepare(ref WorldEntity entity, DeterministicGenerator deterministicBatchGenerator)
{
entity = new GeyserWorldEntity(entity.Transform, entity.Level, entity.ClassId,
entity.SpawnedByServer, entity.Id, entity.TechType,
entity.Metadata, entity.ParentId, entity.ChildEntities,
XORRandom.NextFloat(), 15 * XORRandom.NextFloat());
// The value 15 doesn't mean anything in particular, it's just an initial eruption time window so geysers don't all erupt at the same time at first
}
}

View File

@@ -0,0 +1,125 @@
using NitroxModel.DataStructures;
using NitroxModel.DataStructures.GameLogic;
using NitroxModel.DataStructures.GameLogic.Entities;
using NitroxModel.DataStructures.Unity;
using NitroxServer.GameLogic.Entities.Spawning;
using NitroxServer.Helper;
using static NitroxServer_Subnautica.GameLogic.Entities.Spawning.ReefbackSpawnData;
namespace NitroxServer_Subnautica.GameLogic.Entities.Spawning;
public class ReefbackBootstrapper : IEntityBootstrapper
{
private readonly float creatureProbabilitySum = 0;
private readonly float plantsProbabilitySum = 0;
public ReefbackBootstrapper()
{
foreach (ReefbackSlotCreature creature in SpawnableCreatures)
{
creatureProbabilitySum += creature.Probability;
}
foreach (ReefbackSlotPlant plant in SpawnablePlants)
{
plantsProbabilitySum += plant.Probability;
}
}
public void Prepare(ref WorldEntity entity, DeterministicGenerator generator)
{
// From ReefbackLife.Initialize
if (entity.Transform.LocalScale.X <= 0.8f)
{
return;
}
// In case the grassIndex is chosen randomly
int grassIndex = XORRandom.NextIntRange(1, GRASS_VARIANTS_COUNT);
entity = new ReefbackEntity(entity.Transform, entity.Level, entity.ClassId,
entity.SpawnedByServer, entity.Id, entity.TechType,
entity.Metadata, entity.ParentId, entity.ChildEntities,
grassIndex, entity.Transform.Position);
NitroxTransform plantSlotsRootTransform = DuplicateTransform(PlantSlotsRootTransform);
plantSlotsRootTransform.SetParent(entity.Transform, false);
// ReefbackLife.SpawnPlants equivalent
for (int i = 0; i < PLANT_SLOTS_COUNT; i++)
{
NitroxTransform slotTransform = DuplicateTransform(PlantSlotsCoordinates[i]);
slotTransform.SetParent(plantSlotsRootTransform, false);
float random = XORRandom.NextFloat() * plantsProbabilitySum;
float totalProbability = 0f;
int chosenPlantIndex = 0;
for (int k = 0; k < SpawnablePlants.Count; k++)
{
totalProbability += SpawnablePlants[k].Probability;
if (random <= totalProbability)
{
chosenPlantIndex = k;
break;
}
}
ReefbackSlotPlant slotPlant = SpawnablePlants[chosenPlantIndex];
string randomId = slotPlant.ClassIds[XORRandom.NextIntRange(0, slotPlant.ClassIds.Count)];
NitroxId id = generator.NextId();
NitroxTransform plantTransform = new(slotTransform.Position, slotPlant.StartRotationQuaternion, NitroxVector3.One);
plantTransform.SetParent(plantSlotsRootTransform);
// It is necessary to set parent to null afterwards so that the entity doesn't accidentally modifies the transform by losing reference to the parent
plantTransform.SetParent(null, false);
ReefbackChildEntity plantEntity = new(plantTransform, entity.Level, randomId, true, id, NitroxTechType.None, null, entity.Id, [],
ReefbackChildEntity.ReefbackChildType.PLANT);
entity.ChildEntities.Add(plantEntity);
}
NitroxTransform creatureSlotsRootTransform = DuplicateTransform(CreatureSlotsRootTransform);
creatureSlotsRootTransform.SetParent(entity.Transform, false);
// ReefbackLife.SpawnCreatures equivalent
for (int i = 0; i < CREATURE_SLOTS_COUNT; i++)
{
NitroxTransform slotTransform = DuplicateTransform(CreatureSlotsCoordinates[i]);
slotTransform.SetParent(creatureSlotsRootTransform, false);
float random = XORRandom.NextFloat() * creatureProbabilitySum;
float totalProbability = 0f;
int chosenCreatureIndex = 0;
for (int k = 0; k < SpawnableCreatures.Count; k++)
{
totalProbability += SpawnableCreatures[k].Probability;
if (random <= totalProbability)
{
chosenCreatureIndex = k;
break;
}
}
ReefbackSlotCreature slotCreature = SpawnableCreatures[chosenCreatureIndex];
int spawnCount = XORRandom.NextIntRange(slotCreature.MinNumber, slotCreature.MaxNumber + 1);
for (int j = 0; j < spawnCount; j++)
{
NitroxId id = generator.NextId();
NitroxTransform creatureTransform = new(slotTransform.LocalPosition + XORRandom.NextInsideSphere(5f), slotTransform.LocalRotation, NitroxVector3.One);
creatureTransform.SetParent(CreatureSlotsRootTransform, false);
creatureTransform.SetParent(null, false);
ReefbackChildEntity creatureEntity = new(creatureTransform, entity.Level, slotCreature.ClassId, true, id, NitroxTechType.None, null, entity.Id, [],
ReefbackChildEntity.ReefbackChildType.CREATURE);
entity.ChildEntities.Add(creatureEntity);
}
}
}
private static NitroxTransform DuplicateTransform(NitroxTransform transform)
{
return new(transform.LocalPosition, transform.LocalRotation, transform.LocalScale);
}
}

View File

@@ -0,0 +1,133 @@
using System.Collections.Generic;
using NitroxModel.DataStructures.Unity;
namespace NitroxServer_Subnautica.GameLogic.Entities.Spawning;
/// <summary>
/// Data from <see cref="ReefbackSlotsData"/> generated by ReefbackLife_OnEnable_Patch.cs
/// </summary>
public static class ReefbackSpawnData
{
public const int PLANT_SLOTS_COUNT = 28;
public const int CREATURE_SLOTS_COUNT = 10;
public const int GRASS_VARIANTS_COUNT = 3;
public static readonly NitroxTransform PlantSlotsRootTransform = new(new(0f, 0.49f, -0.22f), new(0.5039341f, 0.4992565f, 0.4960347f, -0.5007424f), new(1f, 1f, 1f));
public static readonly NitroxTransform CreatureSlotsRootTransform = new(new(0f, 0f, 0f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f));
public static List<ReefbackSlotCreature> SpawnableCreatures { get; } =
[
new() { Probability = 1f, MinNumber = 1, MaxNumber = 2, ClassId = "3fcd548b-781f-46ba-b076-7412608deeef" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 2, ClassId = "fa4cfe65-4eaf-4d51-ba0d-e8cc9632fd47" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 2, ClassId = "0a993944-87d3-441e-b21d-6c314f723cc7" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 2, ClassId = "bf9ccd04-60af-4144-aaa1-4ac184c686c2" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 1, ClassId = "79c1aef0-e505-469c-ab36-c22c76aeae44" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 1, ClassId = "495befa0-0e6b-400d-9734-227e5a732f75" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 1, ClassId = "284ceeb6-b437-4aca-a8bd-d54f336cbef8" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 2, ClassId = "cf171ce2-e3d2-4cec-9757-60dbd480e486" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 2, ClassId = "d040bec1-0368-4f7c-aed6-93b5e1852d45" },
new() { Probability = 0.5f, MinNumber = 1, MaxNumber = 3, ClassId = "4064a71a-c464-4db2-942a-56391fe69951" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 1, ClassId = "ce23b9ee-fd98-4677-9919-20248356f7cf" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 1, ClassId = "8ffbb5b5-21b4-4687-9118-730d59330c9a" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 1, ClassId = "a7b70c23-8e57-43e0-ab39-e02a29341376" },
new() { Probability = 1f, MinNumber = 1, MaxNumber = 1, ClassId = "08cb3290-504b-4191-97ee-6af1588af5c0" },
];
public static List<ReefbackSlotPlant> SpawnablePlants { get; } =
[
new() { ClassIds = ["061af756-643c-42ad-9645-a522f1338084", "93a9886d-f2d3-4b6c-8e5f-216f569f82b2"], Probability = 1f, StartRotation = new(270f, 0f, 0f) },
new() { ClassIds = ["fc7c1098-13af-417a-8038-0053b65498e5", "61a5e0e6-01d5-4ae2-aea6-1186cd769025", "31834aae-35ce-49c1-b5ba-ac4227750679", "99cdec62-302b-4999-ba49-f50c73575a4d"], Probability = 2f, StartRotation = new(270f, 0f, 0f) },
new() { ClassIds = ["e80b22ff-064d-46ca-b71e-456d6b3426ab"], Probability = 1f, StartRotation = new(0f, 0f, 0f) },
new() { ClassIds = ["6d9e37de-f808-4621-a762-e0d6340b30dc"], Probability = 1f, StartRotation = new(270f, 0f, 0f) },
new() { ClassIds = ["242b7f63-7553-456b-8d16-b318040097ae", "1fcbf0f8-01fd-4454-a48d-3b3266e5b84e", "11bd0c8e-6d57-46cb-928a-f0e825726674", "7c55e785-a250-41ae-869d-c4be026f9ce6", "43a597df-da05-4f5f-92df-29d76c0b2f53", "133ae1eb-99ec-4b1d-b32b-9c9daf144b8f"], Probability = 1f, StartRotation = new(0f, 0f, 0f) },
new() { ClassIds = ["fb941ab6-9c74-4673-b6a5-2dcb40720d34"], Probability = 1f, StartRotation = new(270f, 0f, 0f) },
new() { ClassIds = ["7f656699-358a-416d-9ecd-f911e3d51bf1", "54dad6b2-77c8-4f9a-9294-2621ca296754"], Probability = 1f, StartRotation = new(225f, 0f, 0f) },
new() { ClassIds = ["e8047056-e202-49b3-829f-7458615103ac", "3dbab1b9-cc52-4da4-8633-89b33add18f4"], Probability = 1f, StartRotation = new(270f, 0f, 0f) },
new() { ClassIds = ["e0608e57-e9df-4f43-bb3a-8c56a42d2c1f", "1edd7411-8f1d-4e7a-8378-0ce7ccb6ea82", "48d6184a-320e-41d2-abca-5b96a94e72e0", "3d4d3892-e43a-45b1-85b8-4a6462257c79"], Probability = 0.3f, StartRotation = new(270f, 0f, 0f) },
new() { ClassIds = ["34b59c1d-876e-4962-a8f7-e205d189d2be", "1f384257-9d4a-4307-829f-024c0e1ce1c0", "0719b0fa-95df-4b37-a581-4f1e07424c62", "28fb4ab7-e1eb-4de3-89a9-98f54394e0f6"], Probability = 0.3f, StartRotation = new(270f, 0f, 0f) },
new() { ClassIds = ["2d970c98-6f77-4270-8be2-91dc863d15d5", "eb6634e5-3a58-4a0d-ae4e-b673e1fa51ea", "df03263c-ebfb-4e7c-b002-1ec3d67c1215", "c197a6ca-f910-43db-92ab-2e35e423a6f1"], Probability = 0.3f, StartRotation = new(270f, 0f, 0f) },
new() { ClassIds = ["70eb6270-bf5e-4d6a-8182-484ffcfd8de6", "f0713f3d-586b-4c71-88a3-18dd6c3dd2a4", "9a643563-9278-4c77-8bd2-f9b4b1a1053a", "4e31161e-c812-4c8c-bfd4-00cf4b743884"], Probability = 0.3f, StartRotation = new(270f, 0f, 0f) },
new() { ClassIds = ["171c6a5b-879b-4785-be7a-6584b2c8c442"], Probability = 1f, StartRotation = new(270f, 0f, 0f) },
new() { ClassIds = ["84794dd0-2c70-4239-9536-230d56811ad4"], Probability = 1f, StartRotation = new(0f, 0f, 0f) },
new() { ClassIds = ["aa1abbb9-716c-44b8-a2b8-cb4d9d0f22bb", "7ecc9cdd-3afc-4005-bff7-01ba62e95a03", "26940e53-d3eb-4770-ae99-6ce4335445d3", "c87e584c-7e38-4589-b408-8eca51f474c1", "a71da66c-6d43-45c1-bc7f-a789cfc61e46"], Probability = 2f, StartRotation = new(0f, 0f, 0f) },
new() { ClassIds = ["22bf7b03-8154-410b-a6fb-8ba315f68987", "450bf7b5-b6cf-4139-921f-3cb9ea505d5f", "c71f41ce-b586-4e85-896e-d25e8b5b9de0", "598c95d8-7420-4907-8f70-ba18b4e6adcb"], Probability = 1.5f, StartRotation = new(0f, 0f, 0f) },
new() { ClassIds = ["36fcb5c8-07f6-4d20-b026-f8c41b8e2358"], Probability = 1f, StartRotation = new(0f, 0f, 0f) },
new() { ClassIds = ["4525e0f3-9c9a-449f-8d6c-48088711ac99"], Probability = 1f, StartRotation = new(0f, 0f, 0f) },
new() { ClassIds = ["b707aa52-1a27-43c4-9500-f346befb8251"], Probability = 1f, StartRotation = new(0f, 0f, 0f) },
new() { ClassIds = ["1a806d20-dc8f-4e6e-9281-f353ed155abf"], Probability = 1f, StartRotation = new(0f, 0f, 0f) },
new() { ClassIds = ["4601400c-5e12-4e4a-9e45-4cab5f06a598"], Probability = 1f, StartRotation = new(0f, 0f, 0f) },
new() { ClassIds = ["31ccc496-c26b-4ed9-8e86-3334582d8d5b", "4bc33bd6-cfa1-46a7-bac8-074ba3b76044"], Probability = 3f, StartRotation = new(0f, 0f, 0f) },
];
public static List<NitroxTransform> CreatureSlotsCoordinates { get; } =
[
new(new(-22.9f, 17f, 0f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f)),
new(new(5.1f, 17.9f, 22.12f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f)),
new(new(5.1f, 17.9f, -11.6f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f)),
new(new(-5.1f, 17.9f, 5.57f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f)),
new(new(23.62f, 17.9f, 5.57f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f)),
new(new(-16.4f, 17.9f, 25.9f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f)),
new(new(-8.7f, 17.9f, -30.3f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f)),
new(new(15.4f, 17.9f, -30.3f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f)),
new(new(20.9f, 17.9f, -13.9f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f)),
new(new(-17.3f, 17.9f, 22.12f), new(0f, 0f, 0f, 1f), new(1f, 1f, 1f)),
];
public static List<NitroxTransform> PlantSlotsCoordinates { get; } =
[
new(new(-4.460001f, 0f, 10f), new(0.6152681f, -0.3477891f, -0.2830537f, 0.6483584f), new(1f, 1f, 1f)),
new(new(-3.481001f, 6.719f, 8.196002f), new(0.4696728f, -0.1773425f, -0.3922334f, 0.7707854f), new(1f, 1f, 1f)),
new(new(7.452f, 2.863f, 8.1f), new(0.5340302f, 0.3158718f, 0.2073223f, 0.7563427f), new(1f, 1f, 1f)),
new(new(5.12f, -7.519994f, 7.599998f), new(0.7192559f, 0.07982004f, -0.09835583f, 0.6831002f), new(1f, 1f, 1f)),
new(new(15.631f, 2.149f, 7.193f), new(0.4893234f, 0.05595651f, -0.1356857f, 0.8596632f), new(1f, 1f, 1f)),
new(new(7.3761f, 6.8008f, 6.9998f), new(-0.5506698f, -0.5092787f, -0.486309f, -0.4482206f), new(1f, 1f, 1f)),
new(new(20.231f, 6.098f, 3.22f), new(-0.580992f, -0.5104024f, 0.01308015f, -0.6338507f), new(1f, 1f, 1f)),
new(new(17.307f, -2.754f, 6.889f), new(-0.6737934f, -0.3733953f, -0.5835185f, -0.2570692f), new(1f, 1f, 1f)),
new(new(10.411f, -8.146f, 6.401f), new(-0.4313123f, -0.6596806f, -0.2941538f, -0.5406151f), new(1f, 1f, 1f)),
new(new(10.903f, -12.232f, 6.880001f), new(-0.7411356f, -0.3174673f, -0.1293507f, -0.5772356f), new(1f, 1f, 1f)),
new(new(-11.188f, 5.817f, 7.423f), new(-0.6473981f, 0.005354047f, -0.5044534f, -0.5712914f), new(1f, 1f, 1f)),
new(new(-7.186f, -5.598001f, 9.095995f), new(-0.5481309f, -0.3323998f, -0.6145787f, -0.4597346f), new(1f, 1f, 1f)),
new(new(18.337f, -9.234001f, 3.704004f), new(-0.54471f, -0.6272081f, -0.5153005f, -0.2106334f), new(1f, 1f, 1f)),
new(new(3.708f, 14.976f, 7.343f), new(-0.5388643f, -0.5702056f, -0.4023229f, -0.4718338f), new(1f, 1f, 1f)),
new(new(4.624f, -2.568f, 8.295f), new(-0.4445406f, -0.4816067f, -0.7076716f, -0.2638929f), new(1f, 1f, 1f)),
new(new(2.332f, -12.735f, 8.085f), new(-0.5660617f, -0.5615287f, -0.575052f, -0.1832343f), new(1f, 1f, 1f)),
new(new(8.237998f, 14.162f, 6.878995f), new(-0.3394944f, -0.7236302f, -0.4614432f, -0.3849328f), new(1f, 1f, 1f)),
new(new(-8.105976f, 1.567999f, 9.326996f), new(0.1392731f, -0.7048326f, -0.6932754f, -0.05642127f), new(1f, 1f, 1f)),
new(new(-11.8123f, -2.4774f, 7.2488f), new(-0.5196269f, -0.4540258f, -0.4950719f, -0.5279701f), new(1f, 1f, 1f)),
new(new(0.7281f, 3.8064f, 8.772f), new(-0.5932296f, -0.4087047f, -0.4483426f, -0.5291768f), new(1f, 1f, 1f)),
new(new(0.1910008f, -4.7408f, 8.755607f), new(-0.7313722f, -0.04450077f, -0.1555427f, -0.6625111f), new(1f, 1f, 1f)),
new(new(15.488f, 10.689f, 5.394005f), new(-0.6516617f, -0.3269425f, -0.2105236f, -0.6512492f), new(1f, 1f, 1f)),
new(new(21.61f, 0.04200077f, 4.873005f), new(-0.6519138f, -0.6227682f, -0.315786f, -0.2957152f), new(1f, 1f, 1f)),
new(new(-12.5287f, -10.26078f, 6.387112f), new(-0.3034183f, -0.62968f, -0.6713617f, -0.2464023f), new(1f, 1f, 1f)),
new(new(-10.744f, 10.656f, 6.481f), new(-0.4014427f, -0.5361503f, -0.452841f, -0.5884911f), new(1f, 1f, 1f)),
new(new(-1.322f, -8.544998f, 8.412007f), new(-0.3098519f, -0.268013f, -0.6520668f, -0.6379418f), new(1f, 1f, 1f)),
new(new(0.9206981f, 11.9358f, 7.261901f), new(-0.2040951f, -0.5998042f, -0.6168172f, -0.4670296f), new(1f, 1f, 1f)),
new(new(9.23f, -0.908f, 9.564f), new(-0.6778914f, -0.05161315f, 0.0538789f, -0.7313663f), new(1f, 1f, 1f)),
];
/// <summary>
/// Based on <see cref="ReefbackSlotsData.ReefbackSlotCreature"/>
/// </summary>
public struct ReefbackSlotCreature
{
public int MinNumber;
public int MaxNumber;
public float Probability;
public string ClassId;
}
/// <summary>
/// Based on <see cref="ReefbackSlotsData.ReefbackSlotPlant"/>
/// </summary>
public struct ReefbackSlotPlant
{
public List<string> ClassIds;
public float Probability;
public NitroxVector3 StartRotation
{
set => StartRotationQuaternion = NitroxQuaternion.FromEuler(value);
}
public NitroxQuaternion StartRotationQuaternion;
}
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
namespace NitroxServer_Subnautica.GameLogic.Entities.Spawning
{
public static class SlotsHelper
{
private static Dictionary<EntitySlotData.EntitySlotType, EntitySlot.Type> typeMapping = new Dictionary<EntitySlotData.EntitySlotType, EntitySlot.Type>
{
{ EntitySlotData.EntitySlotType.Small, EntitySlot.Type.Small },
{ EntitySlotData.EntitySlotType.Medium, EntitySlot.Type.Medium },
{ EntitySlotData.EntitySlotType.Large, EntitySlot.Type.Large },
{ EntitySlotData.EntitySlotType.Tall, EntitySlot.Type.Tall },
{ EntitySlotData.EntitySlotType.Creature, EntitySlot.Type.Creature }
};
public static List<EntitySlot.Type> ConvertSlotTypes(EntitySlotData.EntitySlotType entitySlotType)
{
List<EntitySlot.Type> slotsTypes = new List<EntitySlot.Type>();
foreach (KeyValuePair<EntitySlotData.EntitySlotType, EntitySlot.Type> mapping in typeMapping)
{
EntitySlotData.EntitySlotType slotType = mapping.Key;
EntitySlot.Type type = mapping.Value;
if ((entitySlotType & slotType) == slotType)
{
slotsTypes.Add(type);
}
}
return slotsTypes;
}
}
}

View File

@@ -0,0 +1,14 @@
using NitroxModel.DataStructures.GameLogic.Entities;
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
using NitroxServer.GameLogic.Entities.Spawning;
using NitroxServer.Helper;
namespace NitroxServer_Subnautica.GameLogic.Entities.Spawning;
public class StayAtLeashPositionBootstrapper : IEntityBootstrapper
{
public void Prepare(ref WorldEntity spawnedEntity, DeterministicGenerator generator)
{
spawnedEntity.Metadata = new StayAtLeashPositionMetadata(spawnedEntity.Transform.Position);
}
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using NitroxModel.DataStructures.GameLogic;
using NitroxModel.DataStructures.GameLogic.Entities;
using NitroxModel_Subnautica.DataStructures;
using NitroxServer.GameLogic.Entities.Spawning;
using NitroxServer.Helper;
using NitroxServer_Subnautica.GameLogic.Entities.Spawning.EntityBootstrappers;
namespace NitroxServer_Subnautica.GameLogic.Entities.Spawning;
public class SubnauticaEntityBootstrapperManager : IEntityBootstrapperManager
{
private static readonly Dictionary<NitroxTechType, IEntityBootstrapper> entityBootstrappersByTechType = new()
{
[TechType.CrashHome.ToDto()] = new CrashHomeBootstrapper(),
[TechType.ReaperLeviathan.ToDto()] = new StayAtLeashPositionBootstrapper(),
[TechType.SeaDragon.ToDto()] = new StayAtLeashPositionBootstrapper(),
[TechType.GhostLeviathan.ToDto()] = new StayAtLeashPositionBootstrapper(),
};
private static readonly Dictionary<string, IEntityBootstrapper> entityBootstrappersByClassId = new()
{
["ce0b4131-86e2-444b-a507-45f7b824a286"] = new GeyserBootstrapper(),
["8d3d3c8b-9290-444a-9fea-8e5493ecd6fe"] = new ReefbackBootstrapper()
};
public void PrepareEntityIfRequired(ref WorldEntity spawnedEntity, DeterministicGenerator generator)
{
if (entityBootstrappersByTechType.TryGetValue(spawnedEntity.TechType, out IEntityBootstrapper bootstrapper) ||
(!string.IsNullOrEmpty(spawnedEntity.ClassId) && entityBootstrappersByClassId.TryGetValue(spawnedEntity.ClassId, out bootstrapper)))
{
bootstrapper.Prepare(ref spawnedEntity, generator);
}
}
}

View File

@@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Linq;
using NitroxModel.DataStructures.GameLogic;
using NitroxModel.DataStructures.Unity;
using NitroxModel_Subnautica.DataStructures;
using NitroxServer.GameLogic.Entities.Spawning;
using NitroxServer.UnityStubs;
namespace NitroxServer_Subnautica.GameLogic.Entities.Spawning
{
public class SubnauticaEntitySpawnPointFactory : EntitySpawnPointFactory
{
private readonly Dictionary<string, EntitySpawnPoint> spawnPointsByUid = new Dictionary<string, EntitySpawnPoint>();
public override List<EntitySpawnPoint> From(AbsoluteEntityCell absoluteEntityCell, NitroxTransform transform, GameObject gameObject)
{
List<EntitySpawnPoint> spawnPoints = new List<EntitySpawnPoint>();
EntitySlotsPlaceholder entitySlotsPlaceholder = gameObject.GetComponent<EntitySlotsPlaceholder>();
if (gameObject.CreateEmptyObject)
{
SerializedEntitySpawnPoint entitySpawnPoint = new(gameObject.SerializedComponents, gameObject.Layer, absoluteEntityCell, transform);
HandleParenting(spawnPoints, entitySpawnPoint, gameObject);
spawnPoints.Add(entitySpawnPoint);
}
else if (!ReferenceEquals(entitySlotsPlaceholder, null))
{
foreach (EntitySlotData entitySlotData in entitySlotsPlaceholder.slotsData)
{
List<EntitySlot.Type> slotTypes = SlotsHelper.ConvertSlotTypes(entitySlotData.allowedTypes);
List<string> stringSlotTypes = slotTypes.Select(s => s.ToString()).ToList();
EntitySpawnPoint entitySpawnPoint = new(absoluteEntityCell,
entitySlotData.localPosition.ToDto(),
entitySlotData.localRotation.ToDto(),
stringSlotTypes,
entitySlotData.density,
entitySlotData.biomeType.ToString());
HandleParenting(spawnPoints, entitySpawnPoint, gameObject);
}
}
else
{
EntitySpawnPoint entitySpawnPoint = new(absoluteEntityCell, transform.LocalPosition, transform.LocalRotation, transform.LocalScale, gameObject.ClassId);
HandleParenting(spawnPoints, entitySpawnPoint, gameObject);
}
return spawnPoints;
}
private void HandleParenting(List<EntitySpawnPoint> spawnPoints, EntitySpawnPoint entitySpawnPoint, GameObject gameObject)
{
if (gameObject.Parent != null && spawnPointsByUid.TryGetValue(gameObject.Parent, out EntitySpawnPoint parent))
{
entitySpawnPoint.Parent = parent;
parent.Children.Add(entitySpawnPoint);
}
spawnPointsByUid[gameObject.Id] = entitySpawnPoint;
if (gameObject.Parent == null)
{
spawnPoints.Add(entitySpawnPoint);
}
}
}
}