示例#1
0
        public static void LoadFromJsonData(VoxelWorld world, VoxelJsonData data, bool clearTemp = true)
        {
            if (clearTemp)
            {
                ClearTemp();
            }

            Dictionary <int, string> palette = new Dictionary <int, string>();

            for (int i = 0; i < data.palette.Length; i++)
            {
                palette.Add(data.palette[i].index, data.palette[i].id);
            }

            for (int i = 0; i < data.chunks.Length; i++)
            {
                int3 chunkPosition = new int3(data.chunks[i].position.x, data.chunks[i].position.y, data.chunks[i].position.z);

                NativeList <int2> blocks = new NativeList <int2>(Allocator.Temp);
                for (int j = 0; j < data.chunks[i].blocks.Length; j++)
                {
                    blocks.Add(new int2(data.chunks[i].blocks[j].x, data.chunks[i].blocks[j].y));
                }

                using (BinaryWriter w = new BinaryWriter(File.Open(SaveFile(chunkPosition, true), FileMode.OpenOrCreate)))
                {
                    WriteChunkInfo(w, chunkPosition, palette, blocks);
                }
            }

            world.RefreshWorld();
        }
示例#2
0
        private static void DumpLoadedChunksToTemp(VoxelWorld world)
        {
            ICollection <Chunk> loadedChunks = world.Chunks;

            foreach (Chunk chunk in loadedChunks)
            {
                if (chunk.changed)
                {
                    SaveChunk(chunk, true);
                }
            }
        }
示例#3
0
        /// <summary>
        /// Sets multiple blocks in the world.
        /// </summary>
        /// <param name="from">From world position.</param>
        /// <param name="to">To world position.</param>
        /// <param name="block">The block you want to set.</param>
        /// <param name="world">The world you want to get the block from. If null, the current active world will be used.</param>
        public static void SetBlocks(int3 from, int3 to, Block block, VoxelWorld world = null)
        {
            if (world == null)
            {
                world = VoxelWorld.Main;

                if (world == null)
                {
                    Debug.LogError("There's no world to set blocks in.");
                    return;
                }
            }

            world.SetBlocks(from, to, block);
        }
示例#4
0
        public static void SaveAllChunksToLocation(VoxelWorld world, string location)
        {
            List <Chunk> chunks       = LoadAllChunks(world, true);
            string       originalPath = SaveLocation;

            SaveLocation = location;

            for (int i = 0; i < chunks.Count; i++)
            {
                SaveChunk(chunks[i], false);
                chunks[i].Dispose();
            }

            SaveLocation = originalPath;
        }
示例#5
0
        /// <summary>
        /// Set a block in the world but it does NOT updates the terrain.
        /// </summary>
        /// <param name="position">The world position.</param>
        /// <param name="block">The block you want to set.</param>
        /// <param name="world">The world you want to get the block from. If null, the current active world will be used.</param>
        public static void SetBlockRaw(int3 position, Block block, VoxelWorld world = null)
        {
            if (world == null)
            {
                world = VoxelWorld.Main;

                if (world == null)
                {
                    Debug.LogError("There's no world to set a block in.");
                    return;
                }
            }

            world.SetBlockRaw(position, block);
        }
示例#6
0
        /// <summary>
        /// Gets a block from the world.
        /// </summary>
        /// <param name="position">The world position.</param>
        /// <param name="world">The world you want to get the block from. If null, the current active world will be used.</param>
        /// <returns>The block at the given position.</returns>
        public static Block GetBlock(int3 position, VoxelWorld world = null)
        {
            if (world == null)
            {
                world = VoxelWorld.Main;

                if (world == null)
                {
                    Debug.LogError("There's no world to get a block from.");
                    return(BlockProvider.GetBlock(BlockProvider.AIR_TYPE));
                }
            }

            return(world.GetBlock(position));
        }
示例#7
0
        private static List <Chunk> LoadAllChunks(VoxelWorld world, bool ignoreEmptyChunks)
        {
            DumpLoadedChunksToTemp(world);
            List <Chunk> chunks = new List <Chunk>();

            string[] tempChunks = Directory.GetFiles(TempSaveLocation, "*.bin");

            if (tempChunks != null && tempChunks.Length > 0)
            {
                for (int i = 0; i < tempChunks.Length; i++)
                {
                    Chunk chunk = new Chunk(world, int3.zero, new ChunkBlocks(Chunk.CHUNK_SIZE));
                    DeserializeChunk(chunk, tempChunks[i]);
                    if (ignoreEmptyChunks)
                    {
                        NativeArray <int> blocks = chunk.GetAllBlocks(Allocator.Temp);
                        bool empty = true;
                        for (int b = 0; b < blocks.Length; b++)
                        {
                            if (blocks[b] != BlockProvider.AIR_TYPE_ID)
                            {
                                empty = false;
                                break;
                            }
                        }

                        blocks.Dispose();

                        if (empty)
                        {
                            // Need to dispose the chunk here to avoid memory leak.
                            chunk.Dispose();
                            continue;
                        }
                    }

                    chunks.Add(chunk);
                }
            }

            return(chunks);
        }
示例#8
0
        private void OnEnable()
        {
            if (Main != null)
            {
                if (!dontDestroyOnLoad && Main != this)
                {
                    Debug.LogError("Multiple Voxel Worlds! There can only be one.", gameObject);
                }
                else
                {
                    Destroy(gameObject);
                }

                return;
            }

            if (Main == null)
            {
                Main = this;
            }
        }
示例#9
0
        public static VoxelJsonData GetJsonData(VoxelWorld world, bool ignoreEmptyChunks = false)
        {
            VoxelJsonData data = new VoxelJsonData(BlockProvider.GetBlockPalette());

            List <Chunk> chunks = LoadAllChunks(world, ignoreEmptyChunks);

            VoxelJsonChunkData[] chunkData = new VoxelJsonChunkData[chunks.Count];

            for (int i = 0; i < chunks.Count; i++)
            {
                chunkData[i] = new VoxelJsonChunkData(chunks[i]);
            }

            data.chunks = chunkData;

            for (int i = 0; i < chunks.Count; i++)
            {
                chunks[i].Dispose(true);
            }

            return(data);
        }
示例#10
0
 public Chunk(VoxelWorld world, int3 position)
 {
     this.world    = world;
     this.position = position;
 }
示例#11
0
 public static void LoadAllJson(VoxelWorld world, string json, bool clearTemp = true)
 {
     LoadFromJsonData(world, JsonUtility.FromJson <VoxelJsonData>(json), clearTemp);
 }
示例#12
0
        //public static void SaveAllJson(VoxelWorld world, string saveLocation = null)
        //{
        //    VoxelJsonData data = GetJsonData(world);

        //    string json = JsonUtility.ToJson(data, false);

        //    Debug.Log(json);
        //}

        public static string ToJson(VoxelWorld world, bool ignoreEmptyChunks = false, bool prettyPrint = false)
        {
            VoxelJsonData data = GetJsonData(world, ignoreEmptyChunks);

            return(ToJson(data, prettyPrint));
        }
示例#13
0
 private static void ResetStatics()
 {
     Main = null;
 }
示例#14
0
 /// <summary>
 /// Set a block in the world but it does NOT updates the terrain.
 /// </summary>
 /// <param name="x">The X position.</param>
 /// <param name="y">The Y position.</param>
 /// <param name="z">The Z position.</param>
 /// <param name="block">The block you want to set.</param>
 /// <param name="world">The world you want to get the block from. If null, the current active world will be used.</param>
 public static void SetBlockRaw(int x, int y, int z, Block block, VoxelWorld world = null)
 {
     SetBlockRaw(new int3(x, y, z), block, world);
 }
示例#15
0
 /// <summary>
 /// Set a block in the world and updates the terrain.
 /// </summary>
 /// <param name="x">The X position.</param>
 /// <param name="y">The Y position.</param>
 /// <param name="z">The Z position.</param>
 /// <param name="block">The block you want to set.</param>
 /// <param name="urgent">If true, the chunk will update as soon as possible.</param>
 /// <param name="world">The world you want to get the block from. If null, the current active world will be used.</param>
 public static void SetBlock(int x, int y, int z, Block block, bool urgent = true, VoxelWorld world = null)
 {
     SetBlock(new int3(x, y, z), block, urgent, world);
 }
示例#16
0
        /// <summary>
        /// Casts a ray into the world.
        /// </summary>
        /// <param name="ray">The ray to cast from.</param>
        /// <param name="hit">The output hit.</param>
        /// <param name="range">How far the ray reaches.</param>
        /// <param name="stopAtZero">Stop if the ray goes below Y position 0.</param>
        /// <param name="world">The world to cast the ray in.</param>
        /// <returns>True if it hit something.</returns>
        public static bool Raycast(Ray ray, out VoxelRaycastHit hit, float range, bool stopAtZero, VoxelWorld world = null)
        {
            if (world == null)
            {
                world = VoxelWorld.Main;
                if (world == null)
                {
                    throw new System.NullReferenceException("There's no world to raycast in.");
                }
            }

            // Position as we work through the raycast, starts at origin and gets updated as it reaches each block boundary on the route
            Vector3 pos = ray.origin;
            //Normalized direction of the ray
            Vector3 dir = ray.direction.normalized;

            //Transform the ray to match the rotation and position of the world:
            pos -= world.transform.position;
            pos -= new Vector3(0.5f, 0.5f, 0.5f);
            pos  = Quaternion.Inverse(world.gameObject.transform.rotation) * pos;
            dir  = Quaternion.Inverse(world.transform.rotation) * dir;

            // BlockPos to check if the block should be returned
            int3 bPos = new int3(Mathf.RoundToInt(pos.x), Mathf.RoundToInt(pos.y), Mathf.RoundToInt(pos.z));
            //Block pos that gets set to one block behind the hit block, useful for placing blocks at the hit location
            int3 adjacentBPos = bPos;

            // Positive copy of the direction
            Vector3 dirP = new Vector3(Math.Abs(dir.x), Math.Abs(dir.y), Math.Abs(dir.z));
            // The sign of the direction
            int3 dirS = new int3(dir.x > 0 ? 1 : -1, dir.y > 0 ? 1 : -1, dir.z > 0 ? 1 : -1);

            // Boundary will be set each step as the nearest block boundary to each direction
            Vector3 boundary;
            // dist will be set to the distance in each direction to hit a boundary
            Vector3 dist;

            //The block at bPos
            Block hitBlock     = world.GetBlock(bPos);
            bool  hitSomething = false;

            while (hitBlock.id == 0 && math.distance(ray.origin, pos) < range)
            {
                // Get the nearest upcoming boundary for each direction
                boundary.x = MakeBoundary(dirS.x, pos.x);
                boundary.y = MakeBoundary(dirS.y, pos.y);
                boundary.z = MakeBoundary(dirS.z, pos.z);

                //Find the distance to each boundary and make the number positive
                dist = boundary - pos;
                dist = new Vector3(Math.Abs(dist.x), Math.Abs(dist.y), Math.Abs(dist.z));

                // Divide the distance by the strength of the corresponding direction, the
                // lowest number will be the boundary we will hit first. This is like distance
                // over speed = time where dirP is the speed and the it's time to reach the boundary
                dist.x /= dirP.x;
                dist.y /= dirP.y;
                dist.z /= dirP.z;

                // Use the shortest distance as the distance to travel this step times each direction
                // to give us the position where the ray intersects the closest boundary
                if (dist.x < dist.y && dist.x < dist.z)
                {
                    pos += dist.x * dir;
                }
                else if (dist.y < dist.z)
                {
                    pos += dist.y * dir;
                }
                else
                {
                    pos += dist.z * dir;
                }

                // Set the block pos but use ResolveBlockPos because one of the components of pos will be exactly on a block boundary
                // and will need to use the corresponding direction sign to decide which side of the boundary to fall on
                adjacentBPos = bPos;
                bPos         = new int3(ResolveBlockPos(pos.x, dirS.x), ResolveBlockPos(pos.y, dirS.y), ResolveBlockPos(pos.z, dirS.z));
                hitBlock     = world.GetBlock(bPos);
                if (hitBlock.id != 0)
                {
                    hitSomething = true;
                }

                if (bPos.y <= 0 && stopAtZero)
                {
                    break;
                }

                // The while loop then evaluates if hitblock is a viable block to stop on and
                // if not does it all again starting from the new position
            }

            if (!hitSomething && stopAtZero)
            {
                bPos.y         = 0;
                adjacentBPos.y = 0;
            }

            hit = new VoxelRaycastHit()
            {
                block            = hitBlock,
                blockPosition    = bPos,
                adjacentPosition = adjacentBPos,
                direction        = dir,
                scenePosition    = pos
            };

            return(hitSomething);
        }
示例#17
0
 /// <summary>
 /// Gets a block from the world.
 /// </summary>
 /// <param name="x">The X position.</param>
 /// <param name="y">The Y position.</param>
 /// <param name="z">The Z position.</param>
 /// <param name="world">The world you want to get the block from. If null, the current active world will be used.</param>
 /// <returns>The block at the given position.</returns>
 public static Block GetBlock(int x, int y, int z, VoxelWorld world = null)
 {
     return(GetBlock(new int3(x, y, z), world));
 }
示例#18
0
 public Chunk(VoxelWorld world, int3 position, ChunkBlocks blocks) : this(world, position)
 {
     this.blocks = blocks;
 }
示例#19
0
 /// <summary>
 /// Sets multiple blocks in the world.
 /// </summary>
 /// <param name="fromX">From X position.</param>
 /// <param name="fromY">From Y position.</param>
 /// <param name="fromZ">From Z position.</param>
 /// <param name="toX">To X position.</param>
 /// <param name="toY">To Y position.</param>
 /// <param name="toZ">To Z position.</param>
 /// <param name="block">The block you want to set.</param>
 /// <param name="world">The world you want to get the block from. If null, the current active world will be used.</param>
 public static void SetBlocks(int fromX, int fromY, int fromZ, int toX, int toY, int toZ, Block block, VoxelWorld world = null)
 {
     SetBlocks(new int3(fromX, fromY, fromZ), new int3(toX, toY, toZ), block, world);
 }