public CorridorBuilderMetadata(NitroxVector3 position, int rotation, bool hasTargetBase, NitroxInt3 targetCell) : base(typeof(BaseAddCorridorGhost)) { Position = position; Rotation = rotation; HasTargetBase = hasTargetBase; Cell = targetCell; }
protected override void Execute(CallArgs args) { NitroxInt3 batchId = new NitroxInt3(args.Get <int>(0), args.Get <int>(1), args.Get <int>(2)); List <Entity> entities = batchEntitySpawner.LoadUnspawnedEntities(batchId); SendMessage(args.Sender, $"Loaded {entities.Count} entities from batch {batchId}"); }
/** * It is suspected that 'cache' is a misnomer carried over from when UWE was actually doing procedurally * generated worlds. In the final release, this 'cache' has simply been baked into a final version that * we can parse. */ private void ParseCacheCells(NitroxInt3 batchId, string fileName, List <EntitySpawnPoint> spawnPoints) { using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { CellsFileHeader cellsFileHeader = serializer.Deserialize <CellsFileHeader>(stream); for (int cellCounter = 0; cellCounter < cellsFileHeader.NumCells; cellCounter++) { CellHeaderEx cellHeader = serializer.Deserialize <CellHeaderEx>(stream); byte[] serialData = new byte[cellHeader.DataLength]; stream.Read(serialData, 0, cellHeader.DataLength); ParseGameObjectsWithHeader(serialData, batchId, cellHeader.CellId, cellHeader.Level, spawnPoints, out bool wasLegacy); if (!wasLegacy) { byte[] legacyData = new byte[cellHeader.LegacyDataLength]; stream.Read(legacyData, 0, cellHeader.LegacyDataLength); ParseGameObjectsWithHeader(legacyData, batchId, cellHeader.CellId, cellHeader.Level, spawnPoints, out wasLegacy); byte[] waiterData = new byte[cellHeader.WaiterDataLength]; stream.Read(waiterData, 0, cellHeader.WaiterDataLength); ParseGameObjectsFromStream(new MemoryStream(waiterData), batchId, cellHeader.CellId, cellHeader.Level, spawnPoints); } } } }
public void Equals() { NitroxInt3 other1 = new NitroxInt3(5, 10, 15); NitroxInt3 other2 = new NitroxInt3(15, 10, 5); int3.Equals(other1).Should().BeTrue(); int3.Equals(other2).Should().BeFalse(); }
public List <EntitySpawnPoint> ParseBatchData(NitroxInt3 batchId) { List <EntitySpawnPoint> spawnPoints = new List <EntitySpawnPoint>(); ParseFile(batchId, "CellsCache", "baked-", "", spawnPoints); return(spawnPoints); }
public void LoadAllUnspawnedEntities(System.Threading.CancellationToken token) { IMap map = NitroxServiceLocator.LocateService <IMap>(); int totalEntites = 0; for (int x = 0; x < map.DimensionsInBatches.X; x++) { token.ThrowIfCancellationRequested(); for (int y = 0; y < map.DimensionsInBatches.Y; y++) { for (int z = 0; z < map.DimensionsInBatches.Z; z++) { NitroxInt3 batchId = new NitroxInt3(x, y, z); List <Entity> spawnedEntities = batchEntitySpawner.LoadUnspawnedEntities(batchId, true); lock (entitiesById) { lock (phasingEntitiesByAbsoluteCell) { foreach (Entity entity in spawnedEntities) { if (entity.ParentId != null) { Optional <Entity> opEnt = GetEntityById(entity.ParentId); if (opEnt.HasValue) { entity.Transform.SetParent(opEnt.Value.Transform); } else { Log.Error("Parent not Found! Are you sure it exists? " + entity.ParentId); } } List <Entity> entitiesInCell = GetEntities(entity.AbsoluteEntityCell); entitiesInCell.Add(entity); entitiesById.Add(entity.Id, entity); totalEntites++; } } } Log.Debug($"Loaded {spawnedEntities.Count} entities from batch ({x}, {y}, {z})"); } } if (totalEntites > 0) { Log.Info($"Loading: {(int)((totalEntites/ 504732.0) * 100)}%"); } } }
public AbsoluteEntityCell(NitroxVector3 worldSpace, int level) { Level = level; NitroxVector3 localPosition = (worldSpace + Map.Main.BatchDimensionCenter) / Map.Main.BatchSize; BatchId = NitroxInt3.Floor(localPosition); NitroxVector3 cell = (localPosition - BatchId) * GetCellsPerBlock(); CellId = NitroxInt3.Floor(new NitroxVector3(cell.X + 0.0001f, cell.Y + 0.0001f, cell.Z + 0.0001f)); }
public Optional <GameObject> Spawn(Entity entity, Optional <GameObject> parent, EntityCell cellRoot) { NitroxInt3 cellId = entity.AbsoluteEntityCell.CellId; NitroxInt3 batchId = entity.AbsoluteEntityCell.BatchId; cellRoot.liveRoot.name = $"CellRoot {cellId.X}, {cellId.Y}, {cellId.Z}; Batch {batchId.X}, {batchId.Y}, {batchId.Z}"; NitroxEntity.SetNewId(cellRoot.liveRoot, entity.Id); LargeWorldStreamer.main.cellManager.QueueForAwake(cellRoot); return(Optional.OfNullable(cellRoot.liveRoot)); }
private void ParseGameObjectsFromStream(Stream stream, NitroxInt3 batchId, NitroxInt3 cellId, int level, List <EntitySpawnPoint> spawnPoints) { LoopHeader gameObjectCount = serializer.Deserialize <LoopHeader>(stream); for (int goCounter = 0; goCounter < gameObjectCount.Count; goCounter++) { GameObject gameObject = DeserializeGameObject(stream); if (gameObject.TotalComponents > 0) { AbsoluteEntityCell absoluteEntityCell = new AbsoluteEntityCell(batchId, cellId, level); NitroxTransform transform = gameObject.GetComponent <NitroxTransform>(); spawnPoints.AddRange(entitySpawnPointFactory.From(absoluteEntityCell, transform, gameObject)); } } }
public void ParseFile(NitroxInt3 batchId, string pathPrefix, string prefix, string suffix, List <EntitySpawnPoint> spawnPoints) { string subnauticaPath = NitroxUser.SubnauticaPath; if (string.IsNullOrEmpty(subnauticaPath)) { return; } string path = Path.Combine(subnauticaPath, "Subnautica_Data", "StreamingAssets", "SNUnmanagedData", "Build18"); string fileName = Path.Combine(path, pathPrefix, $"{prefix}batch-cells-{batchId.X}-{batchId.Y}-{batchId.Z}{suffix}.bin"); if (!File.Exists(fileName)) { return; } ParseCacheCells(batchId, fileName, spawnPoints); }
public List <Entity> LoadUnspawnedEntities(NitroxInt3 batchId) { lock (parsedBatches) { if (parsedBatches.Contains(batchId)) { return(new List <Entity>()); } parsedBatches.Add(batchId); } DeterministicBatchGenerator deterministicBatchGenerator = new DeterministicBatchGenerator(seed, batchId); List <EntitySpawnPoint> spawnPoints = batchCellsParser.ParseBatchData(batchId); List <Entity> entities = SpawnEntities(spawnPoints, deterministicBatchGenerator); if (entities.Count == 0) { lock (emptyBatchesLock) { emptyBatches.Add(batchId); } } else { Log.Info("Spawning " + entities.Count + " entities from " + spawnPoints.Count + " spawn points in batch " + batchId); } for (int x = 0; x < entities.Count; x++) // Throws on duplicate Entities already but nice to know which ones { for (int y = 0; y < entities.Count; y++) { if (entities[x] == entities[y] && x != y) { Log.Error("Duplicate Entity detected! " + entities[x]); } } } return(entities); }
public void ParseFile(NitroxInt3 batchId, string pathPrefix, string prefix, string suffix, List <EntitySpawnPoint> spawnPoints) { List <string> errors = new List <string>(); string subnauticaPath = GameInstallationFinder.Instance.FindGame(errors); if (subnauticaPath == null) { Log.Error($"Could not locate Subnautica installation directory: {Environment.NewLine}{string.Join(Environment.NewLine, errors)}"); return; } string path = Path.Combine(subnauticaPath, "Subnautica_Data", "StreamingAssets", "SNUnmanagedData", "Build18"); string fileName = Path.Combine(path, pathPrefix, $"{prefix}batch-cells-{batchId.X}-{batchId.Y}-{batchId.Z}{suffix}.bin"); if (!File.Exists(fileName)) { return; } ParseCacheCells(batchId, fileName, spawnPoints); }
private void ParseGameObjectsWithHeader(byte[] data, NitroxInt3 batchId, NitroxInt3 cellId, int level, List <EntitySpawnPoint> spawnPoints, out bool wasLegacy) { wasLegacy = false; if (data.Length == 0) { return; } Stream stream = new MemoryStream(data); StreamHeader header = serializer.Deserialize <StreamHeader>(stream); if (ReferenceEquals(header, null)) { return; } ParseGameObjectsFromStream(stream, batchId, cellId, level, spawnPoints); wasLegacy = (header.Version < 9); return; }
public DeterministicBatchGenerator(string seed, NitroxInt3 batchId) { random = new Random(seed.GetHashCode() + batchId.GetHashCode()); }
public void Setup() { int3 = new NitroxInt3(5, 10, 15); }
public void Floor() { NitroxInt3.Floor(5.1f, 10.4f, 15.5f).Should().Be(int3); }
public void Ceil() { NitroxInt3.Ceil(4.1f, 9.4f, 14.5f).Should().Be(int3); }
public static Int3 ToUnity(this NitroxInt3 v) { return(new Int3(v.X, v.Y, v.Z)); }
public NitroxInt3 GetCellSize(NitroxInt3 blocksPerBatch) { return(GetCellSize(Level, blocksPerBatch)); }
public AbsoluteEntityCell(NitroxInt3 batchId, NitroxInt3 cellId, int level) { BatchId = batchId; CellId = cellId; Level = level; }
public BaseModuleRotationMetadata(NitroxInt3 cell, int direction) : base(typeof(BaseAddModuleGhost)) { Cell = cell; Direction = direction; }
public AnchoredFaceRotationMetadata(NitroxInt3 cell, int faceDirection, int faceType) : base(typeof(BaseAddFaceGhost)) { Cell = cell; Direction = faceDirection; FaceType = faceType; }
public DeterministicBatchGenerator(NitroxInt3 batchId) { random = new Random(batchId.GetHashCode()); }
public static NitroxInt3 GetCellSize(int level, NitroxInt3 blocksPerBatch) { // Our own implementation for BatchCells.GetCellSize, that works on the server and client. return(blocksPerBatch / GetCellsPerBlock(level)); }