public void Reset() { EditorSceneManager.NewScene(NewSceneSetup.EmptyScene); mockMesher = new MockMesher(mockGetComponent); mockMesher.CullFaces = true;//by default mesher is dependent on neighbour, as only the naive mesher is not mockProvider = new MockProvider(); mockComponentStorage = new Dictionary <Vector3Int, MockChunkComponent>(); mockPlayChunkID = Vector3Int.zero; mockLightManager = Substitute.For <ILightManager>(); mockLightManager.CreateGenerationJob(Arg.Any <Vector3Int>()) .Returns(args => { return(new BasicFunctionJob <LightmapGenerationJobResult>(() => new LightmapGenerationJobResult())); }); mockManager = Substitute.For <IChunkManager>(); mockManager.GetChunkComponent(Arg.Any <Vector3Int>()) .Returns(args => { var chunkId = (Vector3Int)args[0]; return(mockGetComponent(chunkId)); }); mockManager.GetManhattanDistanceFromPlayer(Arg.Any <Vector3Int>()) .Returns(args => { var chunkId = (Vector3Int)args[0]; return(MockGetPriorityOfChunk(chunkId)); }); worldLimits = new WorldSizeLimits(false, 0); worldLimits.Initalise(); mockManager.WorldLimits.Returns(worldLimits); }
public void SetTargetOfOutOfBoundsChunk() { worldLimits = new WorldSizeLimits(true, 8); worldLimits.Initalise(); mockManager.WorldLimits.Returns(worldLimits); MakePipeline(1000, 1, 1, true, includeLighting: true); var testChunkID = new Vector3Int(0, 8, 0);//This chunk is outside the vertical limits mockComponentStorage.Add(testChunkID, new MockChunkComponent() { ChunkID = testChunkID, Data = Substitute.For <IChunkData>() }); pipeline.AddWithData(testChunkID, pipeline.FullyGeneratedStage); AssertChunkStages(testChunkID, pipeline.FullyGeneratedStage); pipeline.SetTarget(testChunkID, pipeline.OwnStructuresStage); pipeline.Update(); //Nothing should have been downgraded, as the chunk is outside the vertical limits AssertChunkStages(testChunkID, pipeline.FullyGeneratedStage); }
private void SetupMocks(Vector3Int chunkDimensions, WorldSizeLimits worldSizeLimits = null, bool generateStructures = true) { if (worldSizeLimits == null) { worldSizeLimits = new WorldSizeLimits(false, 0); worldSizeLimits.Initalise(); } mockManager = Substitute.For <IChunkManager>(); mockManager.GenerateStructures.Returns(generateStructures); mockManager.WorldToChunkPosition(Arg.Any <Vector3>()).Returns(args => WorldToChunkPos((Vector3)args[0], chunkDimensions)); mockManager.WorldLimits.Returns(worldSizeLimits); mockManager.GetAllLoadedChunkIds().Returns((_) => statusMap.Keys.ToArray()); mockPipeline = Substitute.For <IChunkPipeline>(); mockPipeline.TerrainDataStage.Returns(0); mockPipeline.OwnStructuresStage.Returns(1); mockPipeline.FullyGeneratedStage.Returns(2); mockPipeline.RenderedStage.Returns(3); mockPipeline.CompleteStage.Returns(4); statusMap = new Dictionary <Vector3Int, int>(); //Mock set target to write to the status map instead mockManager .When(_ => _.SetTargetStageOfChunk(Arg.Any <Vector3Int>(), Arg.Any <int>(), Arg.Any <TargetUpdateMode>())) .Do(args => { Vector3Int pos = (Vector3Int)args[0]; int newStatus = (int)args[1]; var mode = (TargetUpdateMode)args[2]; if (statusMap.TryGetValue(pos, out var currentStatus)) { //If the pos exists, ensure update modes are respected if (newStatus > currentStatus && mode.allowsUpgrade()) { statusMap[pos] = newStatus; } else if (newStatus < currentStatus && mode.allowsDowngrade()) { statusMap[pos] = newStatus; } } else { //Otherwise, add the new pos and status statusMap[pos] = newStatus; } }); //Mock deactivate to remove from the status map mockManager .When(_ => _.TryDeactivateChunk(Arg.Any <Vector3Int>())) .Do(args => { Vector3Int pos = (Vector3Int)args[0]; statusMap.Remove(pos); }); player = Substitute.For <IVoxelPlayer>(); player.Position = Vector3.zero; }
public void Reset() { maxIntensity = LightValue.MaxIntensity; heightMapYValue = 0; chunkDimensions = new Vector3Int(16, 16, 16); chunkStorage = new Dictionary <Vector3Int, IChunkData>(); lampId = (VoxelTypeID)1; blockerId = (VoxelTypeID)2; voxelTypeManager = Substitute.For <IVoxelTypeManager>(); voxelTypeManager.LastVoxelID.Returns(blockerId); voxelTypeManager.GetLightProperties(Arg.Any <VoxelTypeID>()) .Returns((args) => { var typeId = (VoxelTypeID)args[0]; if (typeId.Equals(lampId)) { return(maxIntensity, maxIntensity); } else if (typeId.Equals(blockerId)) { return(0, maxIntensity); } return(0, 1); }); fullyGenerated = new HashSet <Vector3Int>(); chunkManager = Substitute.For <IChunkManager>(); chunkManager.IsChunkFullyGenerated(Arg.Any <Vector3Int>()) .Returns((args) => { var id = (Vector3Int)args[0]; return(fullyGenerated.Contains(id)); }); var worldLimits = new WorldSizeLimits(false, 0); worldLimits.Initalise(); chunkManager.WorldLimits.Returns(worldLimits); chunkManager.ChunkToWorldPosition(Arg.Any <Vector3Int>()) .Returns((args) => { var chunkId = (Vector3Int)args[0]; return(chunkId * chunkDimensions); }); chunkManager.GetReadOnlyChunkData(Arg.Any <Vector3Int>()) .Returns((args) => { var chunkId = (Vector3Int)args[0]; return(new RestrictedChunkData(GetMockChunkData(chunkId))); }); chunkManager.GetChunkData(Arg.Any <Vector3Int>()) .Returns((args) => { var chunkId = (Vector3Int)args[0]; return(GetMockChunkData(chunkId)); }); chunkManager.ChunkDimensions.Returns(chunkDimensions); IHeightMapProvider heightMapProvider = Substitute.For <IHeightMapProvider>(); heightMapProvider.GetHeightMapForColumn(Arg.Any <Vector2Int>()) .Returns((args) => { return(getFlatHeightMap(heightMapYValue)); }); lightManager = new LightManager(); lightManager.Initialise(voxelTypeManager, chunkManager, heightMapProvider); }
public ChunkPipelineManager(IChunkProvider chunkProvider, IChunkMesher chunkMesher, IChunkManager chunkManager, int maxDataPerUpdate, int maxMeshPerUpdate, int maxCollisionPerUpdate, bool structureGen = false, int maxStructurePerUpdate = 200, ILightManager lightManager = null) { getChunkComponent = chunkManager.GetChunkComponent; this.chunkProvider = chunkProvider; this.chunkMesher = chunkMesher; GenerateStructures = structureGen; worldLimits = chunkManager.WorldLimits; bool lighting = lightManager != null; bool meshDependentOnNeighbours = chunkMesher.CullFaces || lighting; Func <Vector3Int, float> priorityFunc = chunkManager.GetManhattanDistanceFromPlayer; int i = 0; var ScheduledForData = new PrioritizedBufferStage("ScheduledForData", i++, this, chunkManager.GetManhattanDistanceFromPlayer); stages.Add(ScheduledForData); var GeneratingData = new GenerateTerrainStage( "GeneratingTerrain", i++, this, maxDataPerUpdate); stages.Add(GeneratingData); TerrainDataStage = i; OwnStructuresStage = i; if (structureGen) { ///Wait until all neighbours including diagonal ones have their terrain data var waitForNeighbourTerrain = new WaitForNeighboursStage( "WaitForNeighbourTerrain", i++, this, true); stages.Add(waitForNeighbourTerrain); var scheduledForStructures = new PrioritizedBufferStage( "ScheduledForStructures", i++, this, priorityFunc); stages.Add(scheduledForStructures); var generatingStructures = new GenerateStructuresStage( "GeneratingStructures", i++, this, maxStructurePerUpdate); stages.Add(generatingStructures); ///At this point the chunk has generated all of its own structures. OwnStructuresStage = i; if (lighting) { PreLightGenWaitStage = i;//This is the wait stage before lighting } var waitingForAllNeighboursToHaveStructures = new WaitForNeighboursStage( "WaitForNeighbourStructures", i++, this, true); stages.Add(waitingForAllNeighboursToHaveStructures); } if (lighting) { if (!structureGen) { PreLightGenWaitStage = i; ///If structures are not generated, need a separate wait for neighbours. ///Otherwise, the wait at the end of the structure generation is sufficient. var waitingForNeighboursForLighting = new WaitForNeighboursStage( "WaitForNeighboursPreLights", i++, this, false ); stages.Add(waitingForNeighboursForLighting); } var scheduledForLighting = new PrioritizedBufferStage( "ScheduledForLights", i++, this, priorityFunc); stages.Add(scheduledForLighting); var generatingLights = new GenerateLightsStage("GeneratingLights", i++, this, lightManager.MaxChunksGeneratedPerUpdate, lightManager); stages.Add(generatingLights); } ///Passthrough stage to set chunkdata fully generated flag var preFullyGeneratedStage = new PassThroughApplyFunctionStage("PreFullGenerated", i++, this, (chunkId) => { var chunkData = getChunkComponent(chunkId).Data; if (chunkData.FullyGenerated) { var stageData = chunkStageMap.TryGetValue(chunkId, out var tmp) ? tmp : null; Debug.LogError($"Chunk data for {chunkId} was listed as fully generated before reaching the fully generated stage!"); } //The chunk is now fully generated, after having received both voxels and lighting. chunkData.FullyGenerated = true; }); stages.Add(preFullyGeneratedStage); FullyGeneratedStage = i; if (meshDependentOnNeighbours) { /// If mesh is dependent on neighbour chunks, add a waiting stage /// to wait until the neighbours of a chunk have their data before /// moving that chunk onwards through the pipeline. Diagonals are included /// in the neighbourhood if structureGen is on. stages.Add(new WaitForNeighboursStage("WaitForNeighboursPreMesh", i++, this, includeDiagonals: structureGen)); } else { ///Otherwise, the chunk can move onwards freely stages.Add(new PassThroughStage("GotAllData", i++, this)); } var ScheduledForMesh = new PrioritizedBufferStage("ScheduledForMesh", i++, this, priorityFunc); stages.Add(ScheduledForMesh); var GeneratingMesh = new GenerateMeshStage("GeneratingMesh", i++, this, maxMeshPerUpdate); stages.Add(GeneratingMesh); RenderedStage = i; stages.Add(new PassThroughStage("GotMesh", i++, this)); var ScheduledForCollisionMesh = new PrioritizedBufferStage( "ScheduledForCollisionMesh", i++, this, priorityFunc); stages.Add(ScheduledForCollisionMesh); var ApplyingCollisionMesh = new ApplyCollisionMeshStage( "ApplyingCollisionMesh", i++, this, maxCollisionPerUpdate); stages.Add(ApplyingCollisionMesh); //Final stage CompleteStage = i; stages.Add(new PassThroughStage("Complete", i++, this)); foreach (var stage in stages) { stage.Initialise(); } }