Compare commits
8 Commits
master
...
feature/ch
Author | SHA1 | Date |
---|---|---|
Jonas Weinz | 43c31d59f0 | |
Jonas Weinz | 4b93ca2c4d | |
Jonas Weinz | 03f5fbcb6a | |
Jonas Weinz | fb6b622ed7 | |
Jonas Weinz | 3fa38762d5 | |
Jonas Weinz | 4f8bd555d9 | |
Jonas Weinz | 5614574261 | |
Jonas Weinz | 3b031e825e |
|
@ -153,15 +153,15 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: a5f06ccd15360461ea85cd374d1c8a29, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
min_range: {x: 6, y: 3, z: 6}
|
||||
max_range: {x: 16, y: 16, z: 16}
|
||||
min_range: {x: 5, y: 3, z: 5}
|
||||
max_range: {x: 9, y: 16, z: 9}
|
||||
cache_range: {x: 48, y: 48, z: 48}
|
||||
server_host: 127.0.0.1
|
||||
server_port: 5050
|
||||
chunkPrefab: {fileID: 114418011670574046, guid: ef7e3e7be15a440f4ab23c93edf6b0fd,
|
||||
type: 2}
|
||||
max_geometry_updates_per_frame: 15
|
||||
n_chunk_build_threads: 3
|
||||
max_geometry_updates_per_frame: 10
|
||||
n_chunk_build_threads: 4
|
||||
position_reference: {fileID: 1846517683}
|
||||
--- !u!1 &1237971281
|
||||
GameObject:
|
||||
|
@ -301,7 +301,7 @@ Transform:
|
|||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 1846517680}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalPosition: {x: 256, y: 1, z: 256}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
|
|
|
@ -4,7 +4,7 @@ using UnityEngine;
|
|||
|
||||
public class Chunk : MonoBehaviour {
|
||||
|
||||
public enum Direction {x_neg, y_neg, z_neg, x_pos, y_pos, z_pos};
|
||||
|
||||
|
||||
// rawData:
|
||||
public const int N_CHUNK_SIDELENGTH = 16; // FIXME: bad naming
|
||||
|
@ -12,28 +12,45 @@ public class Chunk : MonoBehaviour {
|
|||
public const int N_CHUNK_SIDELENGTH_SQRD = 256; //16 * 16
|
||||
public const int N_CHUNK_BLOCKS=4096; //16*16*16
|
||||
|
||||
private int[] data = new int[N_CHUNK_BLOCKS];
|
||||
public ChunkData chunk_data = null;
|
||||
|
||||
protected MeshFilter meshFilter;
|
||||
protected MeshFilter meshFilter;
|
||||
|
||||
protected List<Vector3> all_vertices;
|
||||
protected List<int> all_tris;
|
||||
protected List<Vector3> all_normals;
|
||||
protected List<Color> all_colors;
|
||||
|
||||
protected List<Vector3> vertices;
|
||||
protected List<int> tris;
|
||||
protected List<Vector3> normals;
|
||||
protected List<Color> colors;
|
||||
protected List<Vector3> inner_vertices;
|
||||
protected List<int> inner_tris;
|
||||
protected List<Vector3> inner_normals;
|
||||
protected List<Color> inner_colors;
|
||||
|
||||
// data for the border area:
|
||||
protected List<Vector3>[] border_vertices;
|
||||
protected List<int>[] border_tris;
|
||||
protected List<Vector3>[] border_normals;
|
||||
protected List<Color>[] border_colors;
|
||||
|
||||
protected object border_handle = new object();
|
||||
|
||||
public object borderHandle
|
||||
{
|
||||
get{
|
||||
return border_handle;
|
||||
}
|
||||
}
|
||||
|
||||
protected int[] chunk_position = new int[3] {0,0,0};
|
||||
protected Vector3Int chunk_position_vec;
|
||||
|
||||
public int[] ChunkPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return chunk_position;
|
||||
return chunk_data.ChunkPosition;
|
||||
}
|
||||
set
|
||||
{
|
||||
chunk_position = value;
|
||||
chunk_position_vec = new Vector3Int(value[0], value[1], value[2]);
|
||||
chunk_data.ChunkPosition = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,22 +58,11 @@ public class Chunk : MonoBehaviour {
|
|||
{
|
||||
get
|
||||
{
|
||||
return chunk_position_vec;
|
||||
return chunk_data.ChunkPositionVec;
|
||||
}
|
||||
set
|
||||
{
|
||||
chunk_position_vec = value;
|
||||
chunk_position = new int[3] {value.x, value.y, value.z};
|
||||
}
|
||||
}
|
||||
|
||||
protected Chunk[] neighbor_chunks = new Chunk[6];
|
||||
|
||||
public Chunk[] NeighborChunks
|
||||
{
|
||||
get
|
||||
{
|
||||
return neighbor_chunks;
|
||||
chunk_data.ChunkPositionVec = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,20 +70,22 @@ public class Chunk : MonoBehaviour {
|
|||
{
|
||||
get
|
||||
{
|
||||
return data;
|
||||
return chunk_data.Data;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
data = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void ConnectChunk(Chunk chunk, Direction direction)
|
||||
public void DeleteBorderVertices(ChunkData.Direction dir)
|
||||
{
|
||||
neighbor_chunks[(int) direction] = chunk;
|
||||
chunk.neighbor_chunks[((int) direction + 3) % 6] = this;
|
||||
int d = (int)dir;
|
||||
|
||||
lock(border_handle)
|
||||
{
|
||||
border_vertices[d] = null;
|
||||
border_tris[d] = null;
|
||||
border_normals[d] = null;
|
||||
border_colors[d] = null;
|
||||
}
|
||||
}
|
||||
|
||||
void Awake()
|
||||
|
@ -86,10 +94,28 @@ public class Chunk : MonoBehaviour {
|
|||
|
||||
meshFilter.mesh.MarkDynamic();
|
||||
|
||||
vertices = new List<Vector3>();
|
||||
tris = new List<int>();
|
||||
normals = new List<Vector3>();
|
||||
colors = new List<Color>();
|
||||
all_vertices = new List<Vector3>();
|
||||
all_tris = new List<int>();
|
||||
all_normals = new List<Vector3>();
|
||||
all_colors = new List<Color>();
|
||||
|
||||
inner_vertices = new List<Vector3>();
|
||||
inner_tris = new List<int>();
|
||||
inner_normals = new List<Vector3>();
|
||||
inner_colors = new List<Color>();
|
||||
|
||||
border_vertices = new List<Vector3>[6];
|
||||
border_tris = new List<int>[6];
|
||||
border_normals = new List<Vector3>[6];
|
||||
border_colors = new List<Color>[6];
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
border_vertices[i] = null;
|
||||
border_tris[i] = null;
|
||||
border_normals[i] = null;
|
||||
border_colors[i] = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -98,21 +124,6 @@ public class Chunk : MonoBehaviour {
|
|||
|
||||
}
|
||||
|
||||
public void SetDataFromMessageObject(MessageObject mo)
|
||||
{
|
||||
if (mo.data == null)
|
||||
{
|
||||
throw new System.Exception("received empty data block");
|
||||
}
|
||||
|
||||
if (mo.data.Length != 4096)
|
||||
{
|
||||
throw new System.Exception("bad data received");
|
||||
}
|
||||
|
||||
Data = mo.data;
|
||||
}
|
||||
|
||||
|
||||
public void Index2Coords(int i, int[] coords)
|
||||
{
|
||||
|
@ -128,10 +139,16 @@ public class Chunk : MonoBehaviour {
|
|||
|
||||
protected Color CalculateColor(int[] coords)
|
||||
{
|
||||
return Color.blue + (((float)coords[1] + chunk_position[1] * N_CHUNK_SIDELENGTH) / (float)WorldManager.Instance.WorldHeight) * (Color.green - Color.blue);
|
||||
return Color.blue + (((float)coords[1] + chunk_data.ChunkPosition[1] * N_CHUNK_SIDELENGTH) / (float)WorldManager.Instance.WorldHeight) * (Color.green - Color.blue);
|
||||
}
|
||||
|
||||
protected void AddPlane(Vector3 normal, Vector3 pos, Color color)
|
||||
protected void AddPlane(Vector3 normal,
|
||||
Vector3 pos,
|
||||
Color color,
|
||||
List<Vector3> verts,
|
||||
List<int> tris,
|
||||
List<Vector3> normals,
|
||||
List<Color> colors)
|
||||
{
|
||||
|
||||
/*
|
||||
|
@ -185,12 +202,12 @@ normal a |
|
|||
c += pos;
|
||||
d += pos;
|
||||
|
||||
int n = vertices.Count;
|
||||
int n = verts.Count;
|
||||
|
||||
vertices.Add(a);
|
||||
vertices.Add(half_normal > 0 ? d : b); // forcing clockwise built triangles
|
||||
vertices.Add(c);
|
||||
vertices.Add(half_normal > 0 ? b : d);
|
||||
verts.Add(a);
|
||||
verts.Add(half_normal > 0 ? d : b); // forcing clockwise built triangles
|
||||
verts.Add(c);
|
||||
verts.Add(half_normal > 0 ? b : d);
|
||||
|
||||
tris.Add(n + 0);
|
||||
tris.Add(n + 1);
|
||||
|
@ -212,13 +229,13 @@ normal a |
|
|||
}
|
||||
|
||||
// Build the chunk mesh from ground up
|
||||
public void BuildMesh()
|
||||
public void BuildInnerMesh()
|
||||
{
|
||||
|
||||
vertices.Clear();
|
||||
tris.Clear();
|
||||
normals.Clear();
|
||||
colors.Clear();
|
||||
inner_vertices.Clear();
|
||||
inner_tris.Clear();
|
||||
inner_normals.Clear();
|
||||
inner_colors.Clear();
|
||||
|
||||
int i = 0;
|
||||
int[] pos = new int[3];
|
||||
|
@ -247,23 +264,17 @@ normal a |
|
|||
k = Coords2Index(pos_buffer);
|
||||
if (Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.right, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
AddPlane(Vector3.right,
|
||||
new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]),
|
||||
CalculateColor(pos_buffer),
|
||||
inner_vertices,
|
||||
inner_tris,
|
||||
inner_normals,
|
||||
inner_colors);
|
||||
}
|
||||
pos_buffer[0] += 1;
|
||||
|
||||
}
|
||||
else if (neighbor_chunks[(int)Direction.x_neg])
|
||||
{
|
||||
//wraparound
|
||||
pos_buffer[0] = N_CHUNK_SIDELENGTH - 1;
|
||||
k = Coords2Index(pos_buffer);
|
||||
pos_buffer[0] = -1;
|
||||
if (neighbor_chunks[(int) Direction.x_neg].Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.right, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
}
|
||||
pos_buffer[0] = 0;
|
||||
}
|
||||
|
||||
if (pos[0] + 1 < N_CHUNK_SIDELENGTH)
|
||||
{
|
||||
|
@ -271,23 +282,16 @@ normal a |
|
|||
k = Coords2Index(pos_buffer);
|
||||
if (Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.left, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
AddPlane(Vector3.left,
|
||||
new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]),
|
||||
CalculateColor(pos_buffer),
|
||||
inner_vertices,
|
||||
inner_tris,
|
||||
inner_normals,
|
||||
inner_colors);
|
||||
}
|
||||
pos_buffer[0] -= 1;
|
||||
}
|
||||
else if (neighbor_chunks[(int)Direction.x_pos])
|
||||
{
|
||||
//wraparound
|
||||
pos_buffer[0] = 0;
|
||||
k = Coords2Index(pos_buffer);
|
||||
pos_buffer[0] = N_CHUNK_SIDELENGTH;
|
||||
if (neighbor_chunks[(int) Direction.x_pos].Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.left, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
|
||||
}
|
||||
pos_buffer[0] = N_CHUNK_SIDELENGTH - 1;
|
||||
}
|
||||
|
||||
// y axis
|
||||
if (pos[1] > 0)
|
||||
|
@ -296,23 +300,16 @@ normal a |
|
|||
k = Coords2Index(pos_buffer);
|
||||
if (Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.up, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
AddPlane(Vector3.up,
|
||||
new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]),
|
||||
CalculateColor(pos_buffer),
|
||||
inner_vertices,
|
||||
inner_tris,
|
||||
inner_normals,
|
||||
inner_colors);
|
||||
}
|
||||
pos_buffer[1] += 1;
|
||||
|
||||
}
|
||||
else if (neighbor_chunks[(int)Direction.y_neg])
|
||||
{
|
||||
//wraparound
|
||||
pos_buffer[1] = N_CHUNK_SIDELENGTH - 1;
|
||||
k = Coords2Index(pos_buffer);
|
||||
pos_buffer[1] = -1;
|
||||
if (neighbor_chunks[(int) Direction.y_neg].Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.up, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
}
|
||||
pos_buffer[1] = 0;
|
||||
|
||||
}
|
||||
|
||||
if (pos[1] + 1 < N_CHUNK_SIDELENGTH)
|
||||
|
@ -321,22 +318,16 @@ normal a |
|
|||
k = Coords2Index(pos_buffer);
|
||||
if (Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.down, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
AddPlane(Vector3.down,
|
||||
new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]),
|
||||
CalculateColor(pos_buffer),
|
||||
inner_vertices,
|
||||
inner_tris,
|
||||
inner_normals,
|
||||
inner_colors);
|
||||
}
|
||||
pos_buffer[1] -= 1;
|
||||
}
|
||||
else if (neighbor_chunks[(int)Direction.y_pos])
|
||||
{
|
||||
//wraparound
|
||||
pos_buffer[1] = 0;
|
||||
k = Coords2Index(pos_buffer);
|
||||
pos_buffer[1] = N_CHUNK_SIDELENGTH;
|
||||
if (neighbor_chunks[(int) Direction.y_pos].Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.down, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
}
|
||||
pos_buffer[1] = N_CHUNK_SIDELENGTH - 1;
|
||||
}
|
||||
|
||||
// z axis
|
||||
if (pos[2] > 0)
|
||||
|
@ -345,23 +336,17 @@ normal a |
|
|||
k = Coords2Index(pos_buffer);
|
||||
if (Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.forward, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
AddPlane(Vector3.forward,
|
||||
new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]),
|
||||
CalculateColor(pos_buffer),
|
||||
inner_vertices,
|
||||
inner_tris,
|
||||
inner_normals,
|
||||
inner_colors);
|
||||
}
|
||||
pos_buffer[2] += 1;
|
||||
|
||||
}
|
||||
else if (neighbor_chunks[(int)Direction.z_neg])
|
||||
{
|
||||
//wraparound
|
||||
pos_buffer[2] = N_CHUNK_SIDELENGTH - 1;
|
||||
k = Coords2Index(pos_buffer);
|
||||
pos_buffer[2] = -1;
|
||||
if (neighbor_chunks[(int) Direction.z_neg].Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.forward, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
}
|
||||
pos_buffer[2] = 0;
|
||||
}
|
||||
|
||||
if (pos[2] + 1 < N_CHUNK_SIDELENGTH)
|
||||
{
|
||||
|
@ -369,22 +354,16 @@ normal a |
|
|||
k = Coords2Index(pos_buffer);
|
||||
if (Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.back, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
AddPlane(Vector3.back,
|
||||
new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]),
|
||||
CalculateColor(pos_buffer),
|
||||
inner_vertices,
|
||||
inner_tris,
|
||||
inner_normals,
|
||||
inner_colors);
|
||||
}
|
||||
pos_buffer[2] -= 1;
|
||||
}
|
||||
else if (neighbor_chunks[(int)Direction.z_pos])
|
||||
{
|
||||
//wraparound
|
||||
pos_buffer[2] = 0;
|
||||
k = Coords2Index(pos_buffer);
|
||||
pos_buffer[2] = N_CHUNK_SIDELENGTH;
|
||||
if (neighbor_chunks[(int) Direction.z_pos].Data[k] != 0)
|
||||
{
|
||||
AddPlane(Vector3.back, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
|
||||
}
|
||||
pos_buffer[2] = N_CHUNK_SIDELENGTH - 1;
|
||||
}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
|
@ -394,16 +373,278 @@ normal a |
|
|||
}
|
||||
}
|
||||
|
||||
public void BuildBorderGeometry(ChunkData.Direction dir)
|
||||
{
|
||||
if (chunk_data.Neighbors[(int)dir] == null)
|
||||
{
|
||||
Debug.LogWarning("tried to build geometry from non existing chunk: " + (chunk_data.ChunkPositionVec + ChunkData.DirectionNormalsInt[(int)dir]).ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// depending on direction iterate throug different dimensions
|
||||
|
||||
int d = (int) dir;
|
||||
int op_d = (d + 3) % 6;
|
||||
|
||||
int[] pos = new int[3];
|
||||
|
||||
int neighbor_index;
|
||||
int index;
|
||||
|
||||
lock(border_handle)
|
||||
{
|
||||
|
||||
border_vertices[d] = new List<Vector3>();
|
||||
border_tris[d] = new List<int>();
|
||||
border_normals[d] = new List<Vector3>();
|
||||
border_colors[d] = new List<Color>();
|
||||
|
||||
// X
|
||||
|
||||
if (dir == ChunkData.Direction.x_neg)
|
||||
{
|
||||
for (int y = 0; y < N_CHUNK_SIDELENGTH; y++)
|
||||
{
|
||||
for (int z = 0; z < N_CHUNK_SIDELENGTH; z++)
|
||||
{
|
||||
pos[0] = N_CHUNK_SIDELENGTH - 1;
|
||||
pos[1] = y;
|
||||
pos[2] = z;
|
||||
|
||||
neighbor_index = Coords2Index(pos);
|
||||
pos[0] = 0;
|
||||
index = Coords2Index(pos);
|
||||
pos[0] = -1;
|
||||
|
||||
if (chunk_data.Neighbors[d].Data[neighbor_index] != 0 && Data[index] == 0)
|
||||
{
|
||||
AddPlane(ChunkData.DirectionNormals[op_d],
|
||||
new Vector3(pos[0], pos[1], pos[2]),
|
||||
CalculateColor(pos),
|
||||
border_vertices[d],
|
||||
border_tris[d],
|
||||
border_normals[d],
|
||||
border_colors[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (dir == ChunkData.Direction.x_pos)
|
||||
{
|
||||
for (int y = 0; y < N_CHUNK_SIDELENGTH; y++)
|
||||
{
|
||||
for (int z = 0; z < N_CHUNK_SIDELENGTH; z++)
|
||||
{
|
||||
pos[0] = 0;
|
||||
pos[1] = y;
|
||||
pos[2] = z;
|
||||
|
||||
neighbor_index = Coords2Index(pos);
|
||||
pos[0] = N_CHUNK_SIDELENGTH - 1;
|
||||
index = Coords2Index(pos);
|
||||
pos[0] = N_CHUNK_SIDELENGTH;
|
||||
|
||||
if (chunk_data.Neighbors[d].Data[neighbor_index] != 0 && Data[index] == 0)
|
||||
{
|
||||
AddPlane(ChunkData.DirectionNormals[op_d],
|
||||
new Vector3(pos[0], pos[1], pos[2]),
|
||||
CalculateColor(pos),
|
||||
border_vertices[d],
|
||||
border_tris[d],
|
||||
border_normals[d],
|
||||
border_colors[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Y
|
||||
|
||||
else if (dir == ChunkData.Direction.y_neg)
|
||||
{
|
||||
for (int x = 0; x < N_CHUNK_SIDELENGTH; x++)
|
||||
{
|
||||
for (int z = 0; z < N_CHUNK_SIDELENGTH; z++)
|
||||
{
|
||||
pos[0] = x;
|
||||
pos[1] = N_CHUNK_SIDELENGTH - 1;
|
||||
pos[2] = z;
|
||||
|
||||
neighbor_index = Coords2Index(pos);
|
||||
pos[1] = 0;
|
||||
index = Coords2Index(pos);
|
||||
pos[1] = -1;
|
||||
|
||||
if (chunk_data.Neighbors[d].Data[neighbor_index] != 0 && Data[index] == 0)
|
||||
{
|
||||
AddPlane(ChunkData.DirectionNormals[op_d],
|
||||
new Vector3(pos[0], pos[1], pos[2]),
|
||||
CalculateColor(pos),
|
||||
border_vertices[d],
|
||||
border_tris[d],
|
||||
border_normals[d],
|
||||
border_colors[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (dir == ChunkData.Direction.y_pos)
|
||||
{
|
||||
for (int x = 0; x < N_CHUNK_SIDELENGTH; x++)
|
||||
{
|
||||
for (int z = 0; z < N_CHUNK_SIDELENGTH; z++)
|
||||
{
|
||||
pos[0] = x;
|
||||
pos[1] = 0;
|
||||
pos[2] = z;
|
||||
|
||||
neighbor_index = Coords2Index(pos);
|
||||
pos[1] = N_CHUNK_SIDELENGTH - 1;
|
||||
index = Coords2Index(pos);
|
||||
pos[1] = N_CHUNK_SIDELENGTH;
|
||||
|
||||
if (chunk_data.Neighbors[d].Data[neighbor_index] != 0 && Data[index] == 0)
|
||||
{
|
||||
AddPlane(ChunkData.DirectionNormals[op_d],
|
||||
new Vector3(pos[0], pos[1], pos[2]),
|
||||
CalculateColor(pos),
|
||||
border_vertices[d],
|
||||
border_tris[d],
|
||||
border_normals[d],
|
||||
border_colors[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Z
|
||||
|
||||
else if (dir == ChunkData.Direction.z_neg)
|
||||
{
|
||||
for (int x = 0; x < N_CHUNK_SIDELENGTH; x++)
|
||||
{
|
||||
for (int y = 0; y < N_CHUNK_SIDELENGTH; y++)
|
||||
{
|
||||
pos[0] = x;
|
||||
pos[1] = y;
|
||||
pos[2] = N_CHUNK_SIDELENGTH - 1;
|
||||
|
||||
neighbor_index = Coords2Index(pos);
|
||||
pos[2] = 0;
|
||||
index = Coords2Index(pos);
|
||||
pos[2] = -1;
|
||||
|
||||
if (chunk_data.Neighbors[d].Data[neighbor_index] != 0 && Data[index] == 0)
|
||||
{
|
||||
AddPlane(ChunkData.DirectionNormals[op_d],
|
||||
new Vector3(pos[0], pos[1], pos[2]),
|
||||
CalculateColor(pos),
|
||||
border_vertices[d],
|
||||
border_tris[d],
|
||||
border_normals[d],
|
||||
border_colors[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (dir == ChunkData.Direction.z_pos)
|
||||
{
|
||||
for (int x = 0; x < N_CHUNK_SIDELENGTH; x++)
|
||||
{
|
||||
for (int y = 0; y < N_CHUNK_SIDELENGTH; y++)
|
||||
{
|
||||
pos[0] = x;
|
||||
pos[1] = y;
|
||||
pos[2] = 0;
|
||||
|
||||
neighbor_index = Coords2Index(pos);
|
||||
pos[2] = N_CHUNK_SIDELENGTH - 1;
|
||||
index = Coords2Index(pos);
|
||||
pos[2] = N_CHUNK_SIDELENGTH;
|
||||
|
||||
if (chunk_data.Neighbors[d].Data[neighbor_index] != 0 && Data[index] == 0)
|
||||
{
|
||||
AddPlane(ChunkData.DirectionNormals[op_d],
|
||||
new Vector3(pos[0], pos[1], pos[2]),
|
||||
CalculateColor(pos),
|
||||
border_vertices[d],
|
||||
border_tris[d],
|
||||
border_normals[d],
|
||||
border_colors[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void ConcatenateGeometry()
|
||||
{
|
||||
|
||||
int n_inner = inner_vertices.Count;
|
||||
|
||||
all_vertices = new List<Vector3>(inner_vertices);
|
||||
all_tris = new List<int>(inner_tris);
|
||||
all_normals = new List<Vector3>(inner_normals);
|
||||
all_colors = new List<Color>(inner_colors);
|
||||
|
||||
int c_verts = n_inner;
|
||||
int c_tris = inner_tris.Count;
|
||||
|
||||
lock (border_handle)
|
||||
{
|
||||
//get vertices count of border areas:
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (border_vertices[i] != null)
|
||||
{
|
||||
all_vertices.AddRange(border_vertices[i]);
|
||||
all_tris.AddRange(border_tris[i]);
|
||||
all_normals.AddRange(border_normals[i]);
|
||||
all_colors.AddRange(border_colors[i]);
|
||||
|
||||
// correct triangle indices
|
||||
for (int tri_i = c_tris; tri_i < c_tris + border_tris[i].Count; tri_i++)
|
||||
{
|
||||
all_tris[tri_i] += c_verts;
|
||||
}
|
||||
|
||||
c_tris += border_tris[i].Count;
|
||||
c_verts += border_vertices[i].Count;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void AssignMesh()
|
||||
{
|
||||
meshFilter.mesh.Clear();
|
||||
meshFilter.mesh.vertices = vertices.ToArray();
|
||||
meshFilter.mesh.triangles = tris.ToArray();
|
||||
meshFilter.mesh.normals = normals.ToArray();
|
||||
meshFilter.mesh.colors = colors.ToArray();
|
||||
meshFilter.mesh.vertices = all_vertices.ToArray();
|
||||
meshFilter.mesh.triangles = all_tris.ToArray();
|
||||
meshFilter.mesh.normals = all_normals.ToArray();
|
||||
meshFilter.mesh.colors = all_colors.ToArray();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// Disconnect from all neighbors
|
||||
chunk_data.DisconnectChunkData(ChunkData.Direction.x_neg);
|
||||
chunk_data.DisconnectChunkData(ChunkData.Direction.y_neg);
|
||||
chunk_data.DisconnectChunkData(ChunkData.Direction.z_neg);
|
||||
chunk_data.DisconnectChunkData(ChunkData.Direction.x_pos);
|
||||
chunk_data.DisconnectChunkData(ChunkData.Direction.y_pos);
|
||||
chunk_data.DisconnectChunkData(ChunkData.Direction.z_pos);
|
||||
|
||||
}
|
||||
// Update is called once per frame
|
||||
void Update () {
|
||||
//Pulse();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,440 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ChunkData {
|
||||
|
||||
public enum ChunkGeometryType
|
||||
{
|
||||
Unknown,
|
||||
Mixed,
|
||||
Full,
|
||||
Empty
|
||||
};
|
||||
|
||||
public enum Direction {x_neg, y_neg, z_neg, x_pos, y_pos, z_pos};
|
||||
|
||||
protected static Vector3Int[] direction_normals_int = new Vector3Int[] {Vector3Int.left,
|
||||
Vector3Int.down,
|
||||
new Vector3Int(0,0,-1),
|
||||
Vector3Int.right,
|
||||
Vector3Int.up,
|
||||
new Vector3Int(0,0,1)};
|
||||
|
||||
protected static Vector3[] direction_normals = new Vector3[] {Vector3.left,
|
||||
Vector3.down,
|
||||
new Vector3(0,0,-1),
|
||||
Vector3.right,
|
||||
Vector3.up,
|
||||
new Vector3(0,0,1)};
|
||||
|
||||
public static Vector3Int[] DirectionNormalsInt
|
||||
{
|
||||
get
|
||||
{
|
||||
return direction_normals_int;
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3[] DirectionNormals
|
||||
{
|
||||
get
|
||||
{
|
||||
return direction_normals;
|
||||
}
|
||||
}
|
||||
|
||||
public const int N_CHUNK_SIDELENGTH = 16; // FIXME: bad naming
|
||||
|
||||
public const int N_CHUNK_SIDELENGTH_SQRD = 256; //16 * 16
|
||||
public const int N_CHUNK_BLOCKS=4096; //16*16*16
|
||||
|
||||
private int[] data = new int[N_CHUNK_BLOCKS];
|
||||
|
||||
private ChunkGeometryType m_chunk_geometry_type = ChunkGeometryType.Unknown;
|
||||
|
||||
private ChunkGeometryType[] m_chunk_geometry_type_borders = new ChunkGeometryType[] {ChunkGeometryType.Unknown,
|
||||
ChunkGeometryType.Unknown,
|
||||
ChunkGeometryType.Unknown,
|
||||
ChunkGeometryType.Unknown,
|
||||
ChunkGeometryType.Unknown,
|
||||
ChunkGeometryType.Unknown};
|
||||
|
||||
private bool m_is_built_necessary = false;
|
||||
|
||||
|
||||
private Chunk m_chunk = null;
|
||||
|
||||
private object neighbor_lock = new object();
|
||||
|
||||
private ChunkData[] m_neighbors = new ChunkData[] {null, null, null, null, null, null};
|
||||
|
||||
protected int[] chunk_position = new int[3] {0,0,0};
|
||||
protected Vector3Int chunk_position_vec;
|
||||
|
||||
protected int m_connected_neighbors = 0;
|
||||
protected bool m_is_fully_connected = false;
|
||||
|
||||
public int[] ChunkPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return chunk_position;
|
||||
}
|
||||
set
|
||||
{
|
||||
chunk_position = value;
|
||||
chunk_position_vec = new Vector3Int(value[0], value[1], value[2]);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3Int ChunkPositionVec
|
||||
{
|
||||
get
|
||||
{
|
||||
return chunk_position_vec;
|
||||
}
|
||||
set
|
||||
{
|
||||
chunk_position_vec = value;
|
||||
chunk_position = new int[3] {value.x, value.y, value.z};
|
||||
}
|
||||
}
|
||||
|
||||
public int ConnectedNeighbors
|
||||
{
|
||||
get
|
||||
{
|
||||
int val;
|
||||
lock(neighbor_lock)
|
||||
{
|
||||
val = m_connected_neighbors;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFullyConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
bool val;
|
||||
lock(neighbor_lock)
|
||||
{
|
||||
val = m_is_fully_connected;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
public bool isBuiltNecessary
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_is_built_necessary;
|
||||
}
|
||||
}
|
||||
|
||||
public int[] Data
|
||||
{
|
||||
get{
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public Chunk ParentChunk
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_chunk;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_chunk = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkGeometryType GeometryType
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_chunk_geometry_type;
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkGeometryType[] GeometryTypeBorders
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_chunk_geometry_type_borders;
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkData[] Neighbors
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_neighbors;
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Index2Coords(int i, int[] coords)
|
||||
{
|
||||
coords[0] = i % N_CHUNK_SIDELENGTH;
|
||||
coords[1] = (i / N_CHUNK_SIDELENGTH) % N_CHUNK_SIDELENGTH;
|
||||
coords[2] = i / (N_CHUNK_SIDELENGTH * N_CHUNK_SIDELENGTH);
|
||||
}
|
||||
|
||||
public int Coords2Index(int[] coords)
|
||||
{
|
||||
return coords[0] + coords[1] * N_CHUNK_SIDELENGTH + coords[2] * N_CHUNK_SIDELENGTH_SQRD;
|
||||
}
|
||||
|
||||
public ChunkData(MessageObject mo)
|
||||
{
|
||||
SetDataFromMessageObject(mo);
|
||||
}
|
||||
|
||||
public void analyseData ()
|
||||
{
|
||||
int i = 0;
|
||||
if (data[i] == 0)
|
||||
{
|
||||
m_chunk_geometry_type = ChunkGeometryType.Empty;
|
||||
// first block is air
|
||||
while(i < data.Length)
|
||||
{
|
||||
if (data[i] != 0)
|
||||
{
|
||||
m_chunk_geometry_type = ChunkGeometryType.Mixed;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
m_chunk_geometry_type = ChunkGeometryType.Full;
|
||||
// first block is something
|
||||
while (i < data.Length)
|
||||
{
|
||||
if (data[i] == 0)
|
||||
{
|
||||
m_chunk_geometry_type = ChunkGeometryType.Mixed;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// check borders:
|
||||
|
||||
int[] p = {0,0,0};
|
||||
|
||||
m_chunk_geometry_type_borders[(int)Direction.z_neg] = data[Coords2Index(p)] == 0 ? ChunkGeometryType.Empty : ChunkGeometryType.Full;
|
||||
m_chunk_geometry_type_borders[(int)Direction.x_neg] = m_chunk_geometry_type_borders[(int)Direction.y_neg] = m_chunk_geometry_type_borders[(int)Direction.z_neg];
|
||||
|
||||
p[0] = N_CHUNK_SIDELENGTH - 1;
|
||||
p[1] = N_CHUNK_SIDELENGTH - 1;
|
||||
p[2] = N_CHUNK_SIDELENGTH - 1;
|
||||
|
||||
m_chunk_geometry_type_borders[(int)Direction.z_pos] = data[Coords2Index(p)] == 0 ? ChunkGeometryType.Empty : ChunkGeometryType.Full;
|
||||
m_chunk_geometry_type_borders[(int)Direction.x_pos] = m_chunk_geometry_type_borders[(int)Direction.y_pos] = m_chunk_geometry_type_borders[(int)Direction.z_pos];
|
||||
|
||||
p[0] = 0;
|
||||
p[1] = 0;
|
||||
p[2] = 0;
|
||||
bool empty = data[Coords2Index(p)] == 0;
|
||||
|
||||
for(p[0] = 0; p[0] < N_CHUNK_SIDELENGTH; p[0]++)
|
||||
{
|
||||
for(p[1] = 0; p[1] < N_CHUNK_SIDELENGTH; p[1]++)
|
||||
{
|
||||
if (data[Coords2Index(p)] != 0 && empty || data[Coords2Index(p)] == 0 && !empty)
|
||||
{
|
||||
m_chunk_geometry_type_borders[(int)Direction.z_neg] = ChunkGeometryType.Mixed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_chunk_geometry_type_borders[(int)Direction.z_neg] == ChunkGeometryType.Mixed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p[0] = 0;
|
||||
p[1] = 0;
|
||||
empty = data[Coords2Index(p)] == 0;
|
||||
for(p[0] = 0; p[0] < N_CHUNK_SIDELENGTH; p[0]++)
|
||||
{
|
||||
for(p[2] = 0; p[2] < N_CHUNK_SIDELENGTH; p[2]++)
|
||||
{
|
||||
if (data[Coords2Index(p)] != 0 && empty || data[Coords2Index(p)] == 0 && !empty)
|
||||
{
|
||||
m_chunk_geometry_type_borders[(int)Direction.y_neg] = ChunkGeometryType.Mixed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_chunk_geometry_type_borders[(int)Direction.y_neg] == ChunkGeometryType.Mixed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p[0] = 0;
|
||||
p[2] = 0;
|
||||
empty = data[Coords2Index(p)] == 0;
|
||||
for(p[1] = 0; p[1] < N_CHUNK_SIDELENGTH; p[1]++)
|
||||
{
|
||||
for(p[2] = 0; p[2] < N_CHUNK_SIDELENGTH; p[2]++)
|
||||
{
|
||||
if (data[Coords2Index(p)] != 0 && empty || data[Coords2Index(p)] == 0 && !empty)
|
||||
{
|
||||
m_chunk_geometry_type_borders[(int)Direction.x_neg] = ChunkGeometryType.Mixed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_chunk_geometry_type_borders[(int)Direction.x_neg] == ChunkGeometryType.Mixed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p[1] = 0;
|
||||
p[2] = N_CHUNK_SIDELENGTH - 1;
|
||||
empty = data[Coords2Index(p)] == 0;
|
||||
for(p[0] = 0; p[0] < N_CHUNK_SIDELENGTH; p[0]++)
|
||||
{
|
||||
for(p[1] = 0; p[1] < N_CHUNK_SIDELENGTH; p[1]++)
|
||||
{
|
||||
if (data[Coords2Index(p)] != 0 && empty || data[Coords2Index(p)] == 0 && !empty)
|
||||
{
|
||||
m_chunk_geometry_type_borders[(int)Direction.z_pos] = ChunkGeometryType.Mixed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_chunk_geometry_type_borders[(int)Direction.z_pos] == ChunkGeometryType.Mixed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p[0] = 0;
|
||||
p[1] = N_CHUNK_SIDELENGTH - 1;
|
||||
empty = data[Coords2Index(p)] == 0;
|
||||
for(p[0] = 0; p[0] < N_CHUNK_SIDELENGTH; p[0]++)
|
||||
{
|
||||
for(p[2] = 0; p[2] < N_CHUNK_SIDELENGTH; p[2]++)
|
||||
{
|
||||
if (data[Coords2Index(p)] != 0 && empty || data[Coords2Index(p)] == 0 && !empty)
|
||||
{
|
||||
m_chunk_geometry_type_borders[(int)Direction.y_pos] = ChunkGeometryType.Mixed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_chunk_geometry_type_borders[(int)Direction.y_pos] == ChunkGeometryType.Mixed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p[0] = N_CHUNK_SIDELENGTH - 1;
|
||||
p[2] = 0;
|
||||
empty = data[Coords2Index(p)] == 0;
|
||||
for(p[1] = 0; p[1] < N_CHUNK_SIDELENGTH; p[1]++)
|
||||
{
|
||||
for(p[2] = 0; p[2] < N_CHUNK_SIDELENGTH; p[2]++)
|
||||
{
|
||||
if (data[Coords2Index(p)] != 0 && empty || data[Coords2Index(p)] == 0 && !empty)
|
||||
{
|
||||
m_chunk_geometry_type_borders[(int)Direction.x_pos] = ChunkGeometryType.Mixed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_chunk_geometry_type_borders[(int)Direction.x_pos] == ChunkGeometryType.Mixed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_is_built_necessary = m_chunk_geometry_type == ChunkGeometryType.Mixed;
|
||||
|
||||
}
|
||||
|
||||
public void SetDataFromMessageObject(MessageObject mo)
|
||||
{
|
||||
if (mo.data == null || mo.position == null)
|
||||
{
|
||||
throw new System.Exception("received empty data block");
|
||||
}
|
||||
|
||||
if (mo.data.Length != 4096)
|
||||
{
|
||||
throw new System.Exception("bad data received");
|
||||
}
|
||||
|
||||
data = mo.data;
|
||||
ChunkPositionVec = new Vector3Int(mo.position[2], mo.position[1], mo.position[0]);
|
||||
}
|
||||
|
||||
public void ConnectChunkData(ChunkData cd, Direction dir)
|
||||
{
|
||||
int d = (int)dir;
|
||||
int op_d = (d+3)%6;
|
||||
lock(neighbor_lock)
|
||||
{
|
||||
if (m_neighbors[d] == null)
|
||||
{
|
||||
m_connected_neighbors++;
|
||||
m_is_fully_connected = (m_connected_neighbors == 6);
|
||||
}
|
||||
|
||||
m_neighbors[d] = cd;
|
||||
}
|
||||
|
||||
ChunkGeometryType borderType = cd.m_chunk_geometry_type_borders[op_d];
|
||||
|
||||
if (borderType != ChunkGeometryType.Empty && m_chunk_geometry_type == ChunkGeometryType.Empty)
|
||||
{
|
||||
m_is_built_necessary = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void DisconnectChunkData(Direction dir)
|
||||
{
|
||||
int d = (int)dir;
|
||||
int op_d = (d+3)%6;
|
||||
|
||||
lock (neighbor_lock)
|
||||
{
|
||||
if (m_neighbors[d] == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_chunk != null)
|
||||
{
|
||||
m_chunk.DeleteBorderVertices(dir);
|
||||
}
|
||||
if (m_neighbors[d].m_chunk != null)
|
||||
{
|
||||
m_neighbors[d].m_chunk.DeleteBorderVertices((Direction) op_d);
|
||||
}
|
||||
|
||||
m_neighbors[d].m_neighbors[op_d] = null;
|
||||
m_neighbors[d] = null;
|
||||
|
||||
m_connected_neighbors--;
|
||||
m_is_fully_connected = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -5,12 +5,6 @@ using System.Net.Sockets;
|
|||
|
||||
public class ChunkManager
|
||||
{
|
||||
private enum ChunkGeometryType
|
||||
{
|
||||
Mixed,
|
||||
Full,
|
||||
Empty
|
||||
};
|
||||
// chunks inside this radius will be actively loaded and visible
|
||||
private Vector3Int m_min_view_radius;
|
||||
|
||||
|
@ -29,8 +23,31 @@ public class ChunkManager
|
|||
private Vector3Int m_srqd_max_view_radius;
|
||||
private Vector3Int m_srqd_cached_chunk_radius;
|
||||
|
||||
private WorldManager m_world_manager;
|
||||
|
||||
private NetworkThread m_network_thread;
|
||||
|
||||
private bool m_end_builder_threads = false;
|
||||
|
||||
private Queue<MessageObject> m_received_message_queue;
|
||||
|
||||
private Queue<ChunkData> m_create_chunk_data_queue;
|
||||
|
||||
private Queue<Chunk> m_chunk_mesh_update_queue;
|
||||
|
||||
// queue of chunk which are waiting for geometry to be applied
|
||||
private Queue<Chunk> m_chunk_geometry_build_queue;
|
||||
private Queue<ChunkData> m_chunk_data_to_cache_queue;
|
||||
|
||||
private object m_handle = new object();
|
||||
|
||||
private System.Threading.Thread[] m_threads = null;
|
||||
|
||||
|
||||
// chunks that are in our memory (either as active or inactive object in Unity)
|
||||
private Dictionary<Vector3Int, Chunk> m_dict_loaded_chunks;
|
||||
private Dictionary<Vector3Int, ChunkData> m_dict_cached_chunk_data;
|
||||
|
||||
private Dictionary<Vector3Int, Chunk> m_dict_cached_chunks;
|
||||
|
||||
// active (visible chunks)
|
||||
private Dictionary<Vector3Int, Chunk> m_dict_active_chunks;
|
||||
|
@ -39,29 +56,91 @@ public class ChunkManager
|
|||
private Dictionary<Vector3Int, bool> m_dict_chunk_requested;
|
||||
|
||||
// blocked chunks. (e.g. geometry is build in another thread) They will not be removed
|
||||
private Dictionary<Vector3Int, bool> m_dict_chunk_blocked;
|
||||
private Dictionary<Vector3Int, bool> m_dict_chunk_blocked;
|
||||
|
||||
// dict of chunks that are empty. For them no geometry is build
|
||||
private Dictionary<Vector3Int, bool> m_dict_empty_chunk;
|
||||
private Dictionary<Vector3Int, bool> _m_dict_is_chunk_data_cached;
|
||||
|
||||
// dict of chunks that are full of geometry. Since they probably stay invisible, they will also not drawed
|
||||
// TODO: special case: empty blocks are directly located next to that chunk
|
||||
private Dictionary<Vector3Int, bool> m_dict_full_chunk;
|
||||
private Dictionary<Vector3Int, bool> _m_dict_is_chunk_cached;
|
||||
|
||||
private WorldManager m_world_manager;
|
||||
private bool isChunkDataCached(Vector3Int p)
|
||||
{
|
||||
bool b;
|
||||
lock(_m_dict_is_chunk_data_cached)
|
||||
{
|
||||
b = _m_dict_is_chunk_data_cached.ContainsKey(p);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
private NetworkThread m_network_thread;
|
||||
private void setChunkDataCached(Vector3Int p, bool b)
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
lock(_m_dict_is_chunk_data_cached)
|
||||
{
|
||||
_m_dict_is_chunk_data_cached[p] = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
lock(_m_dict_is_chunk_data_cached)
|
||||
{
|
||||
_m_dict_is_chunk_data_cached.Remove(p);
|
||||
}
|
||||
}
|
||||
|
||||
private bool m_end_builder_threads = false;
|
||||
private void cacheChunkData(ChunkData cd)
|
||||
{
|
||||
m_dict_cached_chunk_data[cd.ChunkPositionVec] = cd;
|
||||
|
||||
private Queue<Chunk> m_empty_chunks_queue;
|
||||
private Queue<MessageObject> m_message_queue;
|
||||
setChunkDataCached(cd.ChunkPositionVec, true);
|
||||
}
|
||||
|
||||
// queue of chunk which are waiting for geometry to be applied
|
||||
private Queue<Chunk> m_chunk_mesh_queue;
|
||||
private void uncacheChunkData(Vector3Int chunk_pos)
|
||||
{
|
||||
m_dict_cached_chunk_data.Remove(chunk_pos);
|
||||
|
||||
private object m_handle = new object();
|
||||
private System.Threading.Thread[] m_threads = null;
|
||||
setChunkDataCached(chunk_pos, false);
|
||||
}
|
||||
|
||||
private bool isChunkCached(Vector3Int p)
|
||||
{
|
||||
bool b;
|
||||
lock(_m_dict_is_chunk_cached)
|
||||
{
|
||||
b = _m_dict_is_chunk_cached.ContainsKey(p);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
private void setChunkCached(Vector3Int p, bool b)
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
lock(_m_dict_is_chunk_cached)
|
||||
{
|
||||
_m_dict_is_chunk_cached[p] = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
lock(_m_dict_is_chunk_cached)
|
||||
{
|
||||
_m_dict_is_chunk_cached.Remove(p);
|
||||
}
|
||||
}
|
||||
|
||||
private void cacheChunk(Chunk c)
|
||||
{
|
||||
m_dict_cached_chunks[c.ChunkPositionVec] = c;
|
||||
|
||||
setChunkCached(c.ChunkPositionVec, true);
|
||||
}
|
||||
|
||||
private void uncacheChunk(Vector3Int chunk_pos)
|
||||
{
|
||||
m_dict_cached_chunks.Remove(chunk_pos);
|
||||
|
||||
setChunkCached(chunk_pos, false);
|
||||
}
|
||||
|
||||
public bool end_builder_threads
|
||||
{
|
||||
|
@ -104,15 +183,19 @@ public class ChunkManager
|
|||
m_reference_transform = reference_transform;
|
||||
|
||||
m_dict_active_chunks = new Dictionary<Vector3Int, Chunk>();
|
||||
m_dict_loaded_chunks = new Dictionary<Vector3Int, Chunk>();
|
||||
m_dict_cached_chunks = new Dictionary<Vector3Int, Chunk>();
|
||||
m_dict_cached_chunk_data = new Dictionary<Vector3Int, ChunkData>();
|
||||
m_dict_chunk_requested = new Dictionary<Vector3Int, bool>();
|
||||
m_dict_chunk_blocked = new Dictionary<Vector3Int, bool>();
|
||||
m_dict_empty_chunk = new Dictionary<Vector3Int, bool>();
|
||||
m_dict_full_chunk = new Dictionary<Vector3Int, bool>();
|
||||
_m_dict_is_chunk_data_cached = new Dictionary<Vector3Int, bool>();
|
||||
_m_dict_is_chunk_cached = new Dictionary<Vector3Int, bool>();
|
||||
|
||||
m_empty_chunks_queue = new Queue<Chunk>();
|
||||
m_message_queue = new Queue<MessageObject>();
|
||||
m_chunk_mesh_queue = new Queue<Chunk>();
|
||||
|
||||
m_received_message_queue = new Queue<MessageObject>();
|
||||
m_chunk_mesh_update_queue = new Queue<Chunk>();
|
||||
m_chunk_geometry_build_queue = new Queue<Chunk>();
|
||||
m_create_chunk_data_queue = new Queue<ChunkData>();
|
||||
m_chunk_data_to_cache_queue = new Queue<ChunkData>();
|
||||
|
||||
m_threads = new System.Threading.Thread[n_threads];
|
||||
|
||||
|
@ -125,38 +208,6 @@ public class ChunkManager
|
|||
|
||||
}
|
||||
|
||||
|
||||
private ChunkGeometryType analyseData (int[] data)
|
||||
{
|
||||
int i = 0;
|
||||
if (data[i] == 0)
|
||||
{
|
||||
// first block is air
|
||||
while(i < data.Length)
|
||||
{
|
||||
if (data[i] != 0)
|
||||
{
|
||||
return ChunkGeometryType.Mixed;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return ChunkGeometryType.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
// first block is something
|
||||
while (i < data.Length)
|
||||
{
|
||||
if (data[i] == 0)
|
||||
{
|
||||
return ChunkGeometryType.Mixed;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return ChunkGeometryType.Full;
|
||||
}
|
||||
}
|
||||
|
||||
public void processServerMessage(MessageObject mo)
|
||||
{
|
||||
//TODO: check datatype
|
||||
|
@ -165,86 +216,142 @@ public class ChunkManager
|
|||
if (m_dict_chunk_requested.ContainsKey(chunk_pos))
|
||||
{
|
||||
|
||||
ChunkGeometryType cg_type = analyseData(mo.data);
|
||||
|
||||
m_dict_chunk_requested.Remove(chunk_pos);
|
||||
|
||||
if (cg_type == ChunkGeometryType.Empty)
|
||||
{
|
||||
m_dict_empty_chunk[chunk_pos] = true;
|
||||
return;
|
||||
}
|
||||
if (cg_type == ChunkGeometryType.Full)
|
||||
{
|
||||
m_dict_full_chunk[chunk_pos] = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3Int tmp = chunk_pos - m_reference_chunk_position;
|
||||
tmp = Vector3Int.Scale(tmp,tmp);
|
||||
|
||||
if (!InRange(tmp, m_srqd_max_view_radius))
|
||||
{
|
||||
Debug.LogWarning("Lost Chunk: " + chunk_pos.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
m_dict_chunk_blocked[chunk_pos] = true;
|
||||
|
||||
|
||||
Chunk c = m_world_manager.InstantiateNewChunk(chunk_pos);
|
||||
|
||||
lock(m_handle)
|
||||
ChunkData cd = new ChunkData(mo);
|
||||
lock(m_create_chunk_data_queue)
|
||||
{
|
||||
m_empty_chunks_queue.Enqueue(c);
|
||||
m_message_queue.Enqueue(mo);
|
||||
m_create_chunk_data_queue.Enqueue(cd);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Received chunk we not asked for");
|
||||
Debug.LogWarning("Received chunk we not asked for: " + mo.position.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendNewChunkToBuild(ChunkData cd)
|
||||
{
|
||||
Debug.Assert(cd.IsFullyConnected);
|
||||
|
||||
Chunk c = m_world_manager.InstantiateNewChunk(cd);
|
||||
|
||||
m_dict_chunk_blocked[cd.ChunkPositionVec] = true;
|
||||
|
||||
lock(m_handle)
|
||||
{
|
||||
m_chunk_geometry_build_queue.Enqueue(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void RunChunkBuilderThread()
|
||||
{
|
||||
int count;
|
||||
Chunk c;
|
||||
MessageObject mo;
|
||||
int count_data;
|
||||
int count_geometry;
|
||||
Chunk c = null;;
|
||||
ChunkData cd = null;
|
||||
bool success;
|
||||
|
||||
while (!end_builder_threads)
|
||||
{
|
||||
success = false;
|
||||
|
||||
lock(m_handle)
|
||||
{
|
||||
count = m_message_queue.Count;
|
||||
count_geometry = m_chunk_geometry_build_queue.Count;
|
||||
}
|
||||
if (count > 0)
|
||||
lock (m_create_chunk_data_queue)
|
||||
{
|
||||
lock(m_handle)
|
||||
count_data = m_create_chunk_data_queue.Count;
|
||||
}
|
||||
|
||||
if(count_geometry == 0 && count_data == 0)
|
||||
{
|
||||
System.Threading.Thread.Sleep(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count_data > count_geometry)
|
||||
{
|
||||
lock (m_create_chunk_data_queue)
|
||||
{
|
||||
c = m_empty_chunks_queue.Dequeue();
|
||||
mo = m_message_queue.Dequeue();
|
||||
if (m_create_chunk_data_queue.Count > 0)
|
||||
{
|
||||
cd = m_create_chunk_data_queue.Dequeue();
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
c.SetDataFromMessageObject(mo);
|
||||
c.BuildMesh();
|
||||
|
||||
// TODO: connect neighbors
|
||||
|
||||
lock(m_handle)
|
||||
if (!success)
|
||||
{
|
||||
m_chunk_mesh_queue.Enqueue(c);
|
||||
// another thread was faster
|
||||
continue;
|
||||
}
|
||||
|
||||
cd.analyseData();
|
||||
|
||||
|
||||
lock(m_chunk_data_to_cache_queue)
|
||||
{
|
||||
m_chunk_data_to_cache_queue.Enqueue(cd);
|
||||
}
|
||||
}
|
||||
System.Threading.Thread.Sleep(50);
|
||||
else
|
||||
{
|
||||
// looking for new chunk geometry to build
|
||||
|
||||
|
||||
lock(m_handle)
|
||||
{
|
||||
if (m_chunk_geometry_build_queue.Count > 0)
|
||||
{
|
||||
c = m_chunk_geometry_build_queue.Dequeue();
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
//another thread was faster
|
||||
continue;
|
||||
}
|
||||
|
||||
c.BuildInnerMesh();
|
||||
|
||||
Vector3Int chunk_pos = c.ChunkPositionVec;
|
||||
|
||||
// TODO: connect neighbors and build border regions
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
c.BuildBorderGeometry((ChunkData.Direction)i);
|
||||
}
|
||||
|
||||
c.ConcatenateGeometry();
|
||||
|
||||
|
||||
lock(m_handle)
|
||||
{
|
||||
m_chunk_mesh_update_queue.Enqueue(c);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Debug.Log("Closing Chunk Builder Thread");
|
||||
}
|
||||
|
||||
|
||||
private bool isChunkCached(Vector3Int chunk_pos)
|
||||
{
|
||||
return m_dict_loaded_chunks.ContainsKey(chunk_pos);
|
||||
}
|
||||
|
||||
private bool isChunkActive(Vector3Int chunk_pos)
|
||||
{
|
||||
return m_dict_active_chunks.ContainsKey(chunk_pos);
|
||||
|
@ -252,7 +359,8 @@ public class ChunkManager
|
|||
|
||||
public void requestChunkFromServer(Vector3Int chunk_pos)
|
||||
{
|
||||
if (!m_dict_chunk_requested.ContainsKey(chunk_pos) && !m_dict_loaded_chunks.ContainsKey(chunk_pos))
|
||||
|
||||
if (!m_dict_chunk_requested.ContainsKey(chunk_pos) && !isChunkDataCached(chunk_pos))
|
||||
{
|
||||
m_dict_chunk_requested[chunk_pos] = true;
|
||||
//request chunk
|
||||
|
@ -273,13 +381,13 @@ public class ChunkManager
|
|||
Chunk c;
|
||||
lock(m_handle)
|
||||
{
|
||||
n = m_chunk_mesh_queue.Count;
|
||||
n = m_chunk_mesh_update_queue.Count;
|
||||
}
|
||||
while(n > 0 && i > 0)
|
||||
{
|
||||
lock(m_handle)
|
||||
{
|
||||
c = m_chunk_mesh_queue.Dequeue();
|
||||
c = m_chunk_mesh_update_queue.Dequeue();
|
||||
}
|
||||
|
||||
c.AssignMesh();
|
||||
|
@ -289,7 +397,8 @@ public class ChunkManager
|
|||
|
||||
m_dict_chunk_blocked.Remove(c.ChunkPositionVec);
|
||||
|
||||
m_dict_loaded_chunks[c.ChunkPositionVec] = c;
|
||||
cacheChunk(c);
|
||||
|
||||
m_dict_active_chunks[c.ChunkPositionVec] = c;
|
||||
|
||||
}
|
||||
|
@ -307,18 +416,51 @@ public class ChunkManager
|
|||
|
||||
public void UpdateViewRange()
|
||||
{
|
||||
//getting new Chunk Data:
|
||||
int cache_count;
|
||||
lock(m_chunk_data_to_cache_queue)
|
||||
{
|
||||
cache_count = m_chunk_data_to_cache_queue.Count;
|
||||
|
||||
}
|
||||
|
||||
while (cache_count > 0)
|
||||
{
|
||||
ChunkData cd;
|
||||
lock (m_chunk_data_to_cache_queue)
|
||||
{
|
||||
cd = m_chunk_data_to_cache_queue.Dequeue();
|
||||
|
||||
}
|
||||
|
||||
// check for neighbors TODO: make this in builder thread!
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
Vector3Int neighbor_pos = cd.ChunkPositionVec + ChunkData.DirectionNormalsInt[i];
|
||||
if (isChunkDataCached(neighbor_pos))
|
||||
{
|
||||
ChunkData neighbor = m_dict_cached_chunk_data[neighbor_pos];
|
||||
cd.ConnectChunkData(neighbor, (ChunkData.Direction)i);
|
||||
neighbor.ConnectChunkData(cd, (ChunkData.Direction) ((i+3)%6));
|
||||
|
||||
}
|
||||
}
|
||||
cacheChunkData(cd);
|
||||
m_dict_chunk_requested.Remove(cd.ChunkPositionVec);
|
||||
cache_count --;
|
||||
}
|
||||
|
||||
Vector3Int current_chunk_position = Vector3Int.RoundToInt(m_reference_transform.position);
|
||||
current_chunk_position.x /= Chunk.N_CHUNK_SIDELENGTH;
|
||||
current_chunk_position.y /= Chunk.N_CHUNK_SIDELENGTH;
|
||||
current_chunk_position.z /= Chunk.N_CHUNK_SIDELENGTH;
|
||||
current_chunk_position.x /= ChunkData.N_CHUNK_SIDELENGTH;
|
||||
current_chunk_position.y /= ChunkData.N_CHUNK_SIDELENGTH;
|
||||
current_chunk_position.z /= ChunkData.N_CHUNK_SIDELENGTH;
|
||||
|
||||
m_reference_chunk_position = current_chunk_position;
|
||||
|
||||
Stack<Vector3Int> to_remove = new Stack<Vector3Int>();
|
||||
|
||||
// check for chunks to remove:
|
||||
|
||||
foreach(KeyValuePair<Vector3Int, Chunk> entry in m_dict_loaded_chunks)
|
||||
foreach(KeyValuePair<Vector3Int, ChunkData> entry in m_dict_cached_chunk_data)
|
||||
{
|
||||
// do something with entry.Value or entry.Key
|
||||
Vector3Int tmp = entry.Key - m_reference_chunk_position;
|
||||
|
@ -329,17 +471,19 @@ public class ChunkManager
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!InRange(tmp, m_srqd_max_view_radius))
|
||||
if (m_dict_active_chunks.ContainsKey(entry.Key) && !InRange(tmp, m_srqd_max_view_radius))
|
||||
{
|
||||
entry.Value.gameObject.SetActive(false);
|
||||
Debug.Assert(entry.Value.ParentChunk != null);
|
||||
if (entry.Value.ParentChunk != null)
|
||||
entry.Value.ParentChunk.gameObject.SetActive(false);
|
||||
else
|
||||
Debug.LogError("corrupted chunk: " + entry.Key.ToString());
|
||||
m_dict_active_chunks.Remove(entry.Key);
|
||||
//m_dict_loaded_chunks.Remove(entry.Key);
|
||||
}
|
||||
|
||||
|
||||
if (!InRange(tmp, m_srqd_cached_chunk_radius))
|
||||
{
|
||||
//m_dict_active_chunks.Remove(entry.Key);
|
||||
to_remove.Push(entry.Key);
|
||||
}
|
||||
|
||||
|
@ -348,10 +492,14 @@ public class ChunkManager
|
|||
while (to_remove.Count > 0)
|
||||
{
|
||||
Vector3Int k = to_remove.Pop();
|
||||
Chunk c = m_dict_loaded_chunks[k];
|
||||
m_dict_loaded_chunks.Remove(k);
|
||||
uncacheChunkData(k);
|
||||
|
||||
UnityEngine.Object.Destroy(c);
|
||||
if (m_dict_cached_chunks.ContainsKey(k))
|
||||
{
|
||||
Chunk c = m_dict_cached_chunks[k];
|
||||
uncacheChunk(k);
|
||||
UnityEngine.Object.Destroy(c);
|
||||
}
|
||||
}
|
||||
|
||||
// reload view range:
|
||||
|
@ -364,19 +512,41 @@ public class ChunkManager
|
|||
Vector3Int p = new Vector3Int(x, y, z) + m_reference_chunk_position;
|
||||
if (m_dict_active_chunks.ContainsKey(p)
|
||||
|| m_dict_chunk_requested.ContainsKey(p)
|
||||
|| m_dict_chunk_blocked.ContainsKey(p)
|
||||
|| m_dict_empty_chunk.ContainsKey(p)
|
||||
|| m_dict_full_chunk.ContainsKey(p))
|
||||
|| m_dict_chunk_blocked.ContainsKey(p))
|
||||
{
|
||||
// TODO: the if above is a hell of a mess!
|
||||
continue;
|
||||
}
|
||||
if (m_dict_loaded_chunks.ContainsKey(p))
|
||||
|
||||
|
||||
|
||||
if (isChunkDataCached(p))
|
||||
{
|
||||
Chunk c = m_dict_loaded_chunks[p];
|
||||
c.gameObject.SetActive(true);
|
||||
m_dict_active_chunks[p] = c;
|
||||
if (!isChunkCached(p))
|
||||
{
|
||||
|
||||
ChunkData cd = m_dict_cached_chunk_data[p];
|
||||
|
||||
if (cd.IsFullyConnected )
|
||||
{
|
||||
if (cd.isBuiltNecessary)
|
||||
{
|
||||
AppendNewChunkToBuild(cd);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Chunk c;
|
||||
|
||||
c = m_dict_cached_chunks[p];
|
||||
|
||||
c.gameObject.SetActive(true);
|
||||
m_dict_active_chunks[p] = c;
|
||||
}
|
||||
}
|
||||
|
||||
else if (!m_dict_chunk_requested.ContainsKey(p))
|
||||
{
|
||||
requestChunkFromServer(p);
|
||||
|
|
|
@ -86,12 +86,18 @@ public class WorldManager : MonoBehaviour {
|
|||
chunk_manager.UpdateViewRange();
|
||||
}
|
||||
|
||||
public Chunk InstantiateNewChunk(Vector3Int chunk_position)
|
||||
public Chunk InstantiateNewChunk(ChunkData cd)
|
||||
{
|
||||
|
||||
Chunk c = (Chunk)Instantiate(chunkPrefab, transform);
|
||||
|
||||
Vector3Int chunk_position = cd.ChunkPositionVec;
|
||||
|
||||
c.transform.localPosition = new Vector3(chunk_position.x * Chunk.N_CHUNK_SIDELENGTH,chunk_position.y * Chunk.N_CHUNK_SIDELENGTH,chunk_position.z * Chunk.N_CHUNK_SIDELENGTH);
|
||||
c.gameObject.name = "Chunk_" +chunk_position.ToString() ;
|
||||
|
||||
c.chunk_data = cd;
|
||||
cd.ParentChunk = c;
|
||||
|
||||
c.ChunkPosition = new int[] {chunk_position.x, chunk_position.y, chunk_position.z};
|
||||
|
||||
|
|
Loading…
Reference in New Issue