/// <summary> /// Save block data /// </summary> private void SaveDataInWorldDictionary() { return; if (isTerrainModified && blocks.IsCreated) { // TODO: save parameters //NativeArray<BlockParameter> blockParameterKeys = blockParameters.GetKeyArray(Allocator.Temp); //NativeArray<short> blockParameterValues = blockParameters.GetValueArray(Allocator.Temp); ChunkSaveData data = new ChunkSaveData(blocks.ToArray()); SerializableVector2Int serializableChunkPos = SerializableVector2Int.FromVector2Int(ChunkPosition); // add new key or update existing data if (World.WorldSave.savedChunks.ContainsKey(serializableChunkPos)) { World.WorldSave.savedChunks[serializableChunkPos] = data; } else { World.WorldSave.savedChunks.Add(serializableChunkPos, data); } //blockParameterKeys.Dispose(); //blockParameterValues.Dispose(); } }
/// <summary> /// Get the voxeldata for a chunk location from file /// </summary> /// <returns>False if the chunk is empty</returns> static bool GetDataForChunkFromFile(Chunk.ID chunkId, string levelName, out ChunkSaveData chunkData) { chunkData = default; IFormatter formatter = new BinaryFormatter(); Stream readStream = new FileStream( GetChunkDataFileName(chunkId, levelName), FileMode.Open, FileAccess.Read, FileShare.Read ) { Position = 0 }; var fileData = formatter.Deserialize(readStream); if (fileData is ChunkSaveData) { chunkData = (ChunkSaveData)fileData; readStream.Close(); return(true); } readStream.Close(); return(false); }
public Chunk(ChunkSaveData data) { Id = data.Id; if (current_id <= data.Id) { current_id = data.Id + 1; } X = data.X; Z = data.Z; Blocks = new List <Block>(); Block_Groups = new List <BlockGroup>(); GameObject = new GameObject(string.Format("Chunk_({0},{1})#{2}", X, Z, Id)); GameObject.transform.parent = Map.Instance.Block_Container.transform; GameObject.SetActive(true); Average_Elevation = 0; foreach (BlockSaveData block_data in data.Blocks) { Block block = Block.Load(block_data, GameObject); block.Chunk = this; Blocks.Add(block); } foreach (BlockGroupSaveData group_data in data.Block_Groups) { BlockGroup group = BlockGroup.Load(group_data, this); Block_Groups.Add(group); } }
protected override IChunkData InitialiseChunkDataFromSaved(ChunkSaveData chunkSaveData, Vector3Int chunkId) { var data = chunkDataFactory.Create(chunkId, chunkManager.ChunkDimensions, chunkSaveData.voxels); data.SetRotationsFromArray(chunkSaveData.rotatedEntries); return(data); }
public void Save(ChunkSaveData chunkData) { Vector2Int position = chunkData.position; Debug.Log("Saving changes to chunk " + position); FileInfo fileInfo = new FileInfo(worldDirectory + "/" + GetFileName(position)); WriteChunk(fileInfo, chunkData); }
public void Add(ChunkSaveData chunk) { if (data == null) { CustomLogger.Instance.Error("Start_Saving needs to be called before Add"); } else { data.Chunks.Add(chunk); } }
public bool Load(ChunkSaveData saveData) { if (saveData.densityMap.Length != nativeCollectionStash.densityMap.Length) { Debug.LogError($"Size of loaded chunk {key.origin} does not match the current chunk size"); return(false); } nativeCollectionStash.densityMap.CopyFrom(saveData.densityMap); ScheduleRefreshDensitiesJob(); return(true); }
private void ReadChunk(FileInfo file, ChunkSaveData saveData) { //while (busy) System.Threading.Thread.Sleep(4); busy = true; byte[] buffer = new byte[4]; using (FileStream stream = new FileStream(file.FullName, FileMode.Open)) { while (stream.Position < stream.Length) { stream.Read(buffer, 0, 4); saveData.changes.Add(new ChunkSaveData.C(buffer[0], buffer[1], buffer[2], buffer[3])); } } busy = false; }
public ChunkSaveData Load(Vector2Int position) { ChunkSaveData saveData = new ChunkSaveData(position); FileInfo fileInfo = new FileInfo(worldDirectory + "/" + GetFileName(position)); if (fileInfo.Exists) { ReadChunk(fileInfo, saveData); //Debug.Log("SaveManager loaded changes to chunk " + saveData.position); } else { } return(saveData); }
public void Save() { ChunkSaveData data = new ChunkSaveData(); data.Id = Id; data.X = X; data.Z = Z; data.Blocks = new List <BlockSaveData>(); foreach (Block block in Blocks) { data.Blocks.Add(block.Save_Data); } data.Block_Groups = new List <BlockGroupSaveData>(); foreach (BlockGroup group in Block_Groups) { data.Block_Groups.Add(group.Save_Data); } SaveManager.Instance.Add(data); }
private void SaveChunkData(ChunkSaveData data) { foreach (ChunkData chunkData in data.ChunkData) { string fileName = "C:/MinecraftUnity/Data/chunks" + "/" + chunkData.Name + ".mindata"; FileStream file; if (File.Exists(fileName)) { file = File.OpenWrite(fileName); } else { file = File.Create(fileName); } BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(file, chunkData); file.Close(); } }
private void WriteChunk(FileInfo file, ChunkSaveData saveData) { //while (busy) System.Threading.Thread.Sleep(4); busy = true; byte[] buffer = new byte[4]; using (FileStream stream = new FileStream(file.FullName, FileMode.Create)) { for (int i = 0; i < saveData.changes.Count; ++i) { buffer[0] = saveData.changes[i].x; buffer[1] = saveData.changes[i].y; buffer[2] = saveData.changes[i].z; buffer[3] = saveData.changes[i].b; stream.Write(buffer, 0, 4); } } Debug.Log("SaveManager saved changes to chunk " + saveData.position); busy = false; }
/* private void Update() * { * if(Input.GetKeyDown(KeyCode.F5)) * { * SaveFile(); * } * if(Input.GetKeyDown(KeyCode.F6)) * { * LoadFile(); * } * }*/ private void SaveFile() { string fileName = "C:/MinecraftUnity/Data" + "/ save.mindata"; FileStream file; if (File.Exists(fileName)) { file = File.OpenWrite(fileName); } else { file = File.Create(fileName); } GameData data = new GameData(GetPlayerPosition()); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(file, data); file.Close(); ChunkSaveData chunksData = new ChunkSaveData(); SaveChunkData(chunksData); }
/// <summary> /// Only to be used by jobs /// Save a chunk to file /// </summary> /// <param name="legalLevelSaveName">The level name, only consisting of legal characters. See: IllegalCharactersForFileName</param> static public void SaveChunkDataToFile(Coordinate chunkId, string legalLevelSaveName, ChunkSaveData chunkData) { /*IFormatter formatter = new BinaryFormatter(); * CheckForSaveDirectory(levelName); * Stream stream = new FileStream(GetChunkDataFileName(chunkId, legalLevelSaveName), FileMode.Create, FileAccess.Write, FileShare.None); * formatter.Serialize(stream, chunkData); * stream.Close();*/ }
protected abstract IChunkData InitialiseChunkDataFromSaved(ChunkSaveData chunkSaveData, Vector3Int chunkId);
public void LoadTerrain() //also loads structures INFO { blocks = new byte[16, 256, 16]; Vector2Int worldPos = position * 16; for (int z = 0; z < 16; ++z) { for (int x = 0; x < 16; ++x) { if (worldInfo.type == WorldInfo.Type.Flat) { for (int y = 4; y < 256; ++y) { blocks[x, y, z] = BlockTypes.AIR; } blocks[x, 3, z] = BlockTypes.GRASS; blocks[x, 2, z] = BlockTypes.DIRT; blocks[x, 1, z] = BlockTypes.DIRT; blocks[x, 0, z] = BlockTypes.BEDROCK; continue; } worldX = position.x * 16 + x; worldZ = position.y * 16 + z; int bottomHeight = 0; float hills = noise.GetPerlin(worldX * 4f + 500, worldZ * 4f) * 0.5f + .5f; if (worldInfo.type == WorldInfo.Type.FloatingIslands) { float distanceToSpawn = Vector2.Distance(new Vector2(worldX, worldZ), Vector2.zero); float bigIsland = Mathf.Clamp01((250f - distanceToSpawn) / 250f); float i1 = noise.GetPerlin(worldX * .5f, worldZ * .5f); float i2 = noise.GetPerlin(worldX * 1f, worldZ * 1f); float i3 = noise.GetPerlin(worldX * 5f, worldZ * 5f); float height = Mathf.Min(i1, i2) + bigIsland + (i3 * 0.02f); height = Mathf.Clamp01(height - 0.1f) / 0.9f; height = Mathf.Pow(height, 1f / 2); if (height == 0) { for (int y = 0; y < 256; ++y) { blocks[x, y, z] = BlockTypes.AIR; } continue; } hills *= height; //smooth edge bottomHeight = (int)(SURFACE_HEIGHT - (height * 80)); } int hillHeight = (int)(SURFACE_HEIGHT + (hills * 16)); float bedrock = noise.GetPerlin(worldX * 64f, worldZ * 64f) * 0.5f + 0.5f; int bedrockHeight = (int)(1 + bedrock * 4); for (int y = 0; y < 256; ++y) { if (y > hillHeight || y < bottomHeight) { blocks[x, y, z] = BlockTypes.AIR; continue; } if (y < bedrockHeight) { blocks[x, y, z] = BlockTypes.BEDROCK; continue; } if (y > hillHeight - 4) { if (GenerateCaves(x, y, z, 0.2f)) { continue; } if (y == hillHeight) { blocks[x, y, z] = BlockTypes.GRASS; //blocks[x, y, z] = BlockTypes.AIR; //TEMP continue; } blocks[x, y, z] = BlockTypes.DIRT; //blocks[x, y, z] = BlockTypes.AIR; //TEMP continue; } else { if (GenerateCaves(x, y, z, 0f)) { continue; } if (GenerateOres(x, y, z)) { continue; } blocks[x, y, z] = BlockTypes.STONE; //blocks[x, y, z] = BlockTypes.AIR; //TEMP continue; } } } } string hash = World.activeWorld.info.seed.ToString() + position.x.ToString() + position.y.ToString(); int structuresSeed = hash.GetHashCode(); System.Random rnd = new System.Random(structuresSeed); structures = new List <StructureInfo>(); bool[,] spotsTaken = new bool[16, 16]; if (worldInfo.type != WorldInfo.Type.Flat) { //cave entrances if (rnd.Next() < STRUCTURE_CHANCE_CAVE_ENTRANCE) { int h = 255; while (h > 0) { if (blocks[8, h, 8] != BlockTypes.AIR) { structures.Add(new StructureInfo(new Vector3Int(0, h + 6, 0), Structure.Type.CAVE_ENTRANCE, rnd.Next())); break; } h--; } } //trees for (int y = 2; y < 14; ++y) { for (int x = 2; x < 14; ++x) { if (rnd.Next() < STRUCTURE_CHANCE_TREE) { if (IsSpotFree(spotsTaken, new Vector2Int(x, y), 2)) { spotsTaken[x, y] = true; int height = 255; while (height > 0) { if (blocks[x, height, y] == BlockTypes.GRASS) { structures.Add(new StructureInfo(new Vector3Int(x, height + 1, y), Structure.Type.OAK_TREE, rnd.Next())); break; } height--; } } } } } } if (rnd.Next() < STRUCTURE_CHANCE_WELL) { if (IsSpotFree(spotsTaken, new Vector2Int(7, 7), 3)) { //Debug.Log("Spot is free"); int minH = 255; int maxH = 0; bool canPlace = true; for (int y = 5; y < 11; ++y) { for (int x = 5; x < 11; ++x) { for (int h = 255; h > -1; h--) { byte b = blocks[x, h, y]; if (b != BlockTypes.AIR) { //Debug.Log(b); canPlace &= (b == BlockTypes.GRASS); minH = Mathf.Min(minH, h); maxH = Mathf.Max(maxH, h); break; } } } } canPlace &= Mathf.Abs(minH - maxH) < 2; if (canPlace) { Debug.Log("spawning well structure"); for (int y = 5; y < 11; ++y) { for (int x = 5; x < 11; ++x) { spotsTaken[x, y] = true; } } int h = 255; while (h > 0) { if (blocks[7, h, 7] != BlockTypes.AIR) { structures.Add(new StructureInfo(new Vector3Int(7, h + 1, 7), Structure.Type.WELL, rnd.Next())); break; } h--; } } } } //already load changes from disk here (apply later) saveData = SaveDataManager.instance.Load(position); terrainReady = true; //Debug.Log($"Chunk {position} terrain ready"); }
private void Update() { // Exit Sample if (Input.GetKey(KeyCode.Escape)) { foreach (var disposable in TestWorld.disposeList) { disposable.Dispose(); } Application.Quit(); #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #endif } // Exit Sample and destroy saves if (Input.GetKey(KeyCode.RightBracket) && Input.GetKey(KeyCode.Escape)) { foreach (var disposable in TestWorld.disposeList) { disposable.Dispose(); } ChunkSaveData.DeleteAll(); Application.Quit(); #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #endif } // Hide and lock cursor when right mouse button pressed if (Input.GetMouseButtonDown(1)) { Cursor.lockState = CursorLockMode.Locked; } // Unlock and show cursor when right mouse button released if (Input.GetMouseButtonUp(1)) { Cursor.visible = true; Cursor.lockState = CursorLockMode.None; } // Rotation if (Input.GetMouseButton(1)) { var mouseMovement = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y") * (invertY ? 1 : -1)); var mouseSensitivityFactor = mouseSensitivityCurve.Evaluate(mouseMovement.magnitude); m_TargetCameraState.yaw += mouseMovement.x * mouseSensitivityFactor; m_TargetCameraState.pitch += mouseMovement.y * mouseSensitivityFactor; } // Translation var translation = GetInputTranslationDirection() * Time.deltaTime; // Speed up movement when shift key held if (Input.GetKey(KeyCode.LeftShift)) { translation *= 10.0f; } // Modify movement by a boost factor (defined in Inspector and modified in play mode through the mouse scroll wheel) boost += Input.mouseScrollDelta.y * 0.2f; translation *= Mathf.Pow(2.0f, boost); m_TargetCameraState.Translate(translation); // Framerate-independent interpolation // Calculate the lerp amount, such that we get 99% of the way to our target in the specified time var positionLerpPct = 1f - Mathf.Exp(Mathf.Log(1f - 0.99f) / positionLerpTime * Time.deltaTime); var rotationLerpPct = 1f - Mathf.Exp(Mathf.Log(1f - 0.99f) / rotationLerpTime * Time.deltaTime); m_InterpolatingCameraState.LerpTowards(m_TargetCameraState, positionLerpPct, rotationLerpPct); m_InterpolatingCameraState.UpdateTransform(transform); }
public void LoadTerrain() //also loads structures INFO { blocks = new byte[16, 256, 16]; light = new byte[16, 256, 16]; Vector2Int worldPos = position * 16; for (int z = 0; z < 16; ++z) { for (int x = 0; x < 16; ++x) { int noiseX = worldPos.x + x; int noiseZ = worldPos.y + z; float height = SimplexNoise.Noise.CalcPixel2D(noiseX, noiseZ + 50000, 0.01f); height = height * 16 + 64; int heightInt = (int)height; float bedrock = SimplexNoise.Noise.CalcPixel2D(noiseX, noiseZ + 50000, 1f); bedrock = bedrock * 3 + 1; int bedrockInt = (int)bedrock; for (int y = 0; y < 256; ++y) { //bedrock if (y < bedrockInt) { blocks[x, y, z] = BlockTypes.BEDROCK; continue; } //air if (y > heightInt) { blocks[x, y, z] = BlockTypes.AIR; continue; } //ores float o1 = SimplexNoise.Noise.CalcPixel3D(noiseX + 50000, y, noiseZ, 0.1f); float o2 = SimplexNoise.Noise.CalcPixel3D(noiseX + 40000, y, noiseZ, 0.1f); float o3 = SimplexNoise.Noise.CalcPixel3D(noiseX + 30000, y, noiseZ, 0.04f); float o4 = SimplexNoise.Noise.CalcPixel3D(noiseX + 60000, y, noiseZ, 0.1f); float o5 = SimplexNoise.Noise.CalcPixel3D(noiseX + 70000, y, noiseZ, 0.1f); float o6 = SimplexNoise.Noise.CalcPixel3D(noiseX + 80000, y, noiseZ, 0.03f); float heightGradient = Mathf.Pow(Mathf.Clamp01(y / 128f), 2f); //caves float c1 = SimplexNoise.Noise.CalcPixel3D(noiseX, y, noiseZ, 0.1f); float c2 = SimplexNoise.Noise.CalcPixel3D(noiseX, y, noiseZ, 0.04f); float c3 = SimplexNoise.Noise.CalcPixel3D(noiseX, y, noiseZ, 0.02f); float c4 = SimplexNoise.Noise.CalcPixel3D(noiseX, y, noiseZ, 0.01f); c1 += (heightGradient); if (c1 < .5 && c2 < .5 && c3 < .5 && c4 < .5) { blocks[x, y, z] = BlockTypes.AIR; continue; } //grass level if (y == heightInt) { blocks[x, y, z] = BlockTypes.GRASS; continue; } //dirt if (y >= heightInt - 4) { blocks[x, y, z] = BlockTypes.DIRT; continue; } o5 += (heightGradient); if (y < 64 && o5 < .04) { blocks[x, y, z] = BlockTypes.GOLD; continue; } if (y < 16 && Mathf.Pow(o2, 4f) > .7 && o3 < .1) { blocks[x, y, z] = BlockTypes.DIAMOND; continue; } if (o4 < .1 && o6 > .8) { blocks[x, y, z] = BlockTypes.IRON; continue; } if (o1 < .08) { blocks[x, y, z] = BlockTypes.COAL; continue; } //remaining is stone blocks[x, y, z] = BlockTypes.STONE; continue; } } } string hash = World.activeWorld.info.seed.ToString() + position.x.ToString() + position.y.ToString(); int structuresSeed = hash.GetHashCode(); //Debug.Log("Chunk structures seed is " + structuresSeed); System.Random rnd = new System.Random(structuresSeed); structures = new List <StructureInfo>(); bool[,] spotsTaken = new bool[16, 16]; //cave entrances if (rnd.Next() < STRUCTURE_CHANCE_CAVE_ENTRANCE) { int h = 255; while (h > 0) { if (blocks[8, h, 8] != BlockTypes.AIR) { structures.Add(new StructureInfo(new Vector3Int(0, h + 6, 0), Structure.Type.CAVE_ENTRANCE, rnd.Next())); //Debug.Log($"Adding cave entrance at {position.x} {position.y}"); break; } h--; } } //trees for (int y = 2; y < 14; ++y) { for (int x = 2; x < 14; ++x) { if (rnd.Next() < STRUCTURE_CHANCE_TREE) { if (IsSpotFree(spotsTaken, new Vector2Int(x, y), 2)) { spotsTaken[x, y] = true; int height = 255; while (height > 0) { if (blocks[x, height, y] == BlockTypes.GRASS) { structures.Add(new StructureInfo(new Vector3Int(x, height + 1, y), Structure.Type.OAK_TREE, rnd.Next())); break; } height--; } } } } } if (rnd.Next() < STRUCTURE_CHANCE_WELL) { if (IsSpotFree(spotsTaken, new Vector2Int(7, 7), 3)) { //Debug.Log("Spot is free"); int minH = 255; int maxH = 0; bool canPlace = true; for (int y = 5; y < 11; ++y) { for (int x = 5; x < 11; ++x) { for (int h = 255; h > -1; h--) { byte b = blocks[x, h, y]; if (b != BlockTypes.AIR) { //Debug.Log(b); canPlace &= (b == BlockTypes.GRASS); minH = Mathf.Min(minH, h); maxH = Mathf.Max(maxH, h); break; } } } } canPlace &= Mathf.Abs(minH - maxH) < 2; if (canPlace) { Debug.Log("spawning well structure"); for (int y = 5; y < 11; ++y) { for (int x = 5; x < 11; ++x) { spotsTaken[x, y] = true; } } int h = 255; while (h > 0) { if (blocks[7, h, 7] != BlockTypes.AIR) { structures.Add(new StructureInfo(new Vector3Int(7, h + 1, 7), Structure.Type.WELL, rnd.Next())); break; } h--; } } } } //already load changes from disk here (apply later) saveData = SaveDataManager.instance.Load(position); terrainReady = true; //Debug.Log($"Chunk {position} terrain ready"); }
public void Save(ChunkSaveData saveData) { saveData.densityMap = new float[nativeCollectionStash.densityMap.Length]; nativeCollectionStash.densityMap.CopyToFast(saveData.densityMap); }