Voxel Chunk error
I had been following a tutorial on voxel worlds until I got to a part where it started crashing every time I started the scene. As far as I can tell it only crashes when one of the world position coordinates are a negative, but I've been working for weeks on someway to fix it, but no matter what I do it always crashes. Here's the error data.
StackOverflowException: The requested operation caused a stack overflow.
at (wrapper managed-to-native) System.ValueType.InternalEquals(object,object,object[]&)
at System.ValueType.DefaultEquals (System.Object o1, System.Object o2) [0x00031] in <7d97106330684add86d080ecf65bfe69>:0
at System.ValueType.Equals (System.Object obj) [0x00000] in <7d97106330684add86d080ecf65bfe69>:0
at System.Collections.Generic.ObjectEqualityComparer`1[T].Equals (T x, T y) [0x00010] in <7d97106330684add86d080ecf65bfe69>:0
at System.Collections.Generic.Dictionary`2[TKey,TValue].FindEntry (TKey key) [0x00056] in <7d97106330684add86d080ecf65bfe69>:0
at System.Collections.Generic.Dictionary`2[TKey,TValue].TryGetValue (TKey key, TValue& value) [0x00000] in <7d97106330684add86d080ecf65bfe69>:0
at World.GetChunk (System.Int32 x, System.Int32 y, System.Int32 z) [0x00066] in C:\Users\maria\Voxel Stuff 2\Assets\WorldData\World.cs:39
at World.GetBlock (System.Int32 x, System.Int32 y, System.Int32 z) [0x00001] in C:\Users\maria\Voxel Stuff 2\Assets\WorldData\World.cs:47
at Chunk.GetBlock (System.Int32 x, System.Int32 y, System.Int32 z) [0x00031] in C:\Users\maria\Voxel Stuff 2\Assets\WorldData\Chunk.cs:79
at World.GetBlock (System.Int32 x, System.Int32 y, System.Int32 z) [0x00017] in C:\Users\maria\Voxel Stuff 2\Assets\WorldData\World.cs:49
at Chunk.GetBlock (System.Int32 x, System.Int32 y, System.Int32 z) [0x00031] in C:\Users\maria\Voxel Stuff 2\Assets\WorldData\Chunk.cs:79
at World.GetBlock (System.Int32 x, System.Int32 y, System.Int32 z) [0x00017] in C:\Users\maria\Voxel Stuff 2\Assets\WorldData\World.cs:49
at Chunk.GetBlock (System.Int32 x, System.Int32 y, System.Int32 z) [0x00031] in C:\Users\maria\Voxel Stuff 2\Assets\WorldData\Chunk.cs:79
at World.GetBlock (System.Int32 x, System.Int32 y, System.Int32 z) [0x00017] in C:\Users\maria\Voxel Stuff 2\Assets\WorldData\World.cs:49
It continues like this until it ends. World Script: using System.Collections; using System.Collections.Generic; using UnityEngine;
public class World : MonoBehaviour
{
public GameObject chunkPrefab;
public Dictionary<WorldPos, Chunk> chunks = new Dictionary<WorldPos, Chunk>();
public bool ChunkExist;
public int blocksGetSet;
void Start(){
blocksGetSet = Chunk.chunkSize;
for (int x = -1; x < 1; x++){
for (int y = -1; y < 1; y++){
for (int z = -1; z < 1; z++){
CreateChunk(x * 16, y * 16, z * 16);
}
}
}
}
public Chunk GetChunk(int x, int y, int z){
WorldPos pos = new WorldPos();
int multiple = Chunk.chunkSize;
if (x < 0){
pos.x = Mathf.FloorToInt(x / multiple) * multiple;
}
if (x < 0){
pos.y = Mathf.FloorToInt(y / multiple) * multiple;
}
if (x < 0){
pos.z = Mathf.CeilToInt(z / multiple) * multiple;
}
Chunk chunkContainer = null;
chunks.TryGetValue(pos, out chunkContainer);
return chunkContainer;
}
public Block GetBlock(int x, int y, int z)
{
Chunk containerChunk = GetChunk(x, y, z);
if (containerChunk != null) {
Block block = containerChunk.GetBlock(x - containerChunk.pos.x, y - containerChunk.pos.y, z - containerChunk.pos.z);
return block;
}
else {
return new BlockAir();
}
}
public void SetBlock(int xi, int x, int yi, int y, int zi, int z, Block block){
int xii = xi + x;
int yii = yi + y;
int zii = zi + z;
Chunk chunk = GetChunk(xii, yii, zii);
if (chunk != null){
int newx = Chunk.chunkSize;
int newy = Chunk.chunkSize;
int newz = Chunk.chunkSize;
if (x == -1){
newx = -Chunk.chunkSize;
}
if (y == -1){
newx = -Chunk.chunkSize;
}
if (z == -1){
newx = -Chunk.chunkSize;
}
if (x > -1 && x < Chunk.chunkSize){
newx = 0;
}
if (y > -1 && y < Chunk.chunkSize){
newy = 0;
}
if (z > -1 && z < Chunk.chunkSize){
newz = 0;
}
chunk.SetBlock(x - newx, y - newy, z - newz, block);
chunk.update = true;
}
}
public void CreateChunk(int x, int y, int z){
WorldPos worldPos = new WorldPos(x, y, z);
Chunk chunk = null;
chunks.TryGetValue(worldPos, out chunk);
ChunkExist = false;
if (chunk != null){
ChunkExist = true;
}
if (ChunkExist == false){
GameObject newChunkObject = Instantiate(chunkPrefab, new Vector3(x, y, z), Quaternion.Euler(Vector3.zero)) as GameObject;
Chunk newChunk = newChunkObject.GetComponent<Chunk>();
newChunk.pos = worldPos;
newChunk.world = this;
chunks.Add(worldPos, newChunk);
}
}
public void DestroyChunk(int x, int y, int z){
Chunk chunk = GetChunk(x, y, z);
if (chunk != null){
Object.Destroy(chunk.gameObject);
chunks.Remove(new WorldPos(x, y, z));
}
}
}
and the Chunk Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshCollider))]
public class Chunk : MonoBehaviour
{
MeshFilter filter;
MeshCollider coll;
public int octaves = 4;
public int seed = 350;
//Size of the Chunk.
public const int chunkSize = 16;
public float scale = 7.2f;
public float persistance = 0.5f;
public float lacunairty = 2f;
public Vector3 offset;
public bool update = true;
public World world;
public WorldPos pos;
private Block[ , , ] blocks = new Block[chunkSize, chunkSize, chunkSize];
private float[ , , ] chunkDensity = new float[chunkSize, chunkSize, chunkSize];
void Start(){
filter = gameObject.GetComponent<MeshFilter>();
coll = gameObject.GetComponent<MeshCollider>();
offset.x = pos.x;
offset.y = pos.y;
offset.z = pos.z;
octaves = 4;
seed = 350;
scale = 7.2f;
persistance = 0.5f;
lacunairty = 2f;
chunkDensity = Simple3dNoise.GenerateWorld(chunkSize, octaves, seed, scale, persistance, lacunairty, offset);
for (int x = 0; x < chunkSize; x++){
for (int y = 0; y < chunkSize; y++){
for (int z = 0; z < chunkSize; z++){
blocks[x, y, z] = new BlockAir();
if (chunkDensity[x, y, z] > 0.38){
blocks[x, y, z] = new Block();
}
}
}
}
}
void Update(){
if (Input.GetKeyDown(KeyCode.P)){
UpdateChunk();
}
if (update){
update = false;
UpdateChunk();
}
}
public static bool InRange(int index){
if (index < 0 || index >= chunkSize){
return false;
}
return true;
}
public Block GetBlock(int x, int y, int z){
if (InRange(x) && InRange(y) && InRange(z)){
return blocks[x, y, z];
}
else{
return world.GetBlock(pos.x + x, pos.y + y, pos.z + z);
}
}
public void SetBlock(int x, int y, int z, Block block){
if (InRange(x) && InRange(y) && InRange(z)){
blocks[x, y, z] = block;
}
else{
world.SetBlock(pos.x, x, pos.y, y, pos.z, z, block);
}
}
public void UpdateChunk(){
MeshData meshData = new MeshData();
for (int x = 0; x < chunkSize; x++){
for (int y = 0; y < chunkSize; y++){
for (int z = 0; z < chunkSize; z++){
meshData = blocks[x, y, z].BlockData(this, x, y, z, meshData);
}
}
}
RenderChunk(meshData);
}
public void RenderChunk(MeshData meshData){
filter.mesh.Clear();
filter.mesh.vertices = meshData.vertices.ToArray();
filter.mesh.triangles = meshData.triangles.ToArray();
filter.mesh.uv = meshData.UVs.ToArray();
filter.mesh.RecalculateNormals();
}
}
If anything else is needed to figure it out I'll add it.
Answer by Bunny83 · Dec 14, 2019 at 11:14 PM
Well, it would be interesting how WorldPos looks like. However the actual reason is your World.GetChunk method. You do some strange things in there. First of all the 3 if statements all check if x is negative. Probably a copy&paste error. However regardless of that I don't quite get the point of those if statements. You create a new empty "pos". Then only when the x coordinate is negative you actually set the x / y / z component to the position passed. That means if x is positive then you will not set any of the components at all so you most likely always get the chunk (0,0,0). Since your two GetBlock method (one in World, one in Chunk) calls each other when the coordinate does not fall within the same chunk you get an infinite recursion since each time you try to get a chunk to the right but you always return the same.
I would also recommend to actually store the chunk position and not the lowest block position in block coordinates. So a chunk coordinate of (2,0) would start at (2*chunksize, 0). Also you should probably centralize the chunk coordinate alignment and rethink your logic because at the moment it makes no sense at all.
Your answer
Follow this Question
Related Questions
Unity Player crashes on a scene with Video Player. 1 Answer
Photon crash 1 Answer
unity crashes when i run a empty foreach loop 0 Answers
Unity Crashes When Adding Script To GameObject 0 Answers
the name 'chunk' does not exist in the current context 0 Answers