Init
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using UnityEngine;
|
||||
|
||||
public class Chunk
|
||||
{
|
||||
//basic
|
||||
private ChunkCoord chunkPosition;
|
||||
private World world;
|
||||
|
||||
//rendering
|
||||
public GameObject gameObject;
|
||||
|
||||
//data
|
||||
public byte[,,] blocks = new byte[Data.chunkWidth, Data.chunkHeight, Data.chunkWidth];
|
||||
|
||||
public Chunk(ChunkCoord chunkPosition, World world)
|
||||
{
|
||||
this.chunkPosition = chunkPosition;
|
||||
this.world = world;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
|
||||
//initializes the chunks components
|
||||
private void Initialize()
|
||||
{
|
||||
gameObject = new GameObject(chunkPosition.x + ", " + chunkPosition.z);
|
||||
gameObject.transform.position =
|
||||
new Vector3(chunkPosition.x * Data.chunkWidth, 0, chunkPosition.z * Data.chunkWidth);
|
||||
}
|
||||
|
||||
//writes the block data
|
||||
public void PopulateBlocks()
|
||||
{
|
||||
for (int y = 0; y < Data.chunkHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < Data.chunkWidth; x++)
|
||||
{
|
||||
for (int z = 0; z < Data.chunkWidth; z++)
|
||||
{
|
||||
blocks[x, y, z] = world.GetBlockID(new Vector3(x + chunkPosition.x * Data.chunkWidth,
|
||||
y, z + chunkPosition.z * Data.chunkWidth));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(byte x, byte y, byte z, byte blockID)
|
||||
{
|
||||
blocks[x, y, z] = blockID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5d27935c6d501a41a2d972b8ff6cc7c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[Serializable]
|
||||
public class ChunkCoord
|
||||
{
|
||||
public ChunkCoord(int x, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public int x;
|
||||
public int z;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b0ff680cf7becd4a905cd0f219efa91
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class Data
|
||||
{
|
||||
public static int chunkWidth = 15, chunkHeight = 250;
|
||||
public static int textureAtlasSize = 16;
|
||||
|
||||
public static readonly Vector3[] vertices =
|
||||
{
|
||||
new Vector3(0, 0, 0),
|
||||
new Vector3(1, 0, 0),
|
||||
new Vector3(1, 1, 0),
|
||||
new Vector3(0, 1, 0),
|
||||
new Vector3(1, 0, 1),
|
||||
new Vector3(0, 0, 1),
|
||||
new Vector3(0, 1, 1),
|
||||
new Vector3(1, 1, 1)
|
||||
};
|
||||
|
||||
public static readonly int[,] triangles =
|
||||
{
|
||||
//front
|
||||
{0, 3, 1, 1, 3, 2},
|
||||
//back
|
||||
{4, 7, 5, 5, 7, 6},
|
||||
//top
|
||||
{3, 6, 2, 2, 6, 7},
|
||||
//bottom
|
||||
{5, 0, 4, 4, 0, 1},
|
||||
//left
|
||||
{5, 6, 0, 0, 6, 3},
|
||||
//right
|
||||
{1, 2, 4, 4, 2, 7},
|
||||
};
|
||||
|
||||
public static readonly Vector3[] faceChecks =
|
||||
{
|
||||
//front
|
||||
new Vector3(0, 0, -1),
|
||||
//back
|
||||
new Vector3(0, 0, 1),
|
||||
//top
|
||||
new Vector3(0, 1, 0),
|
||||
//bottom
|
||||
new Vector3(0, -1, 0),
|
||||
//left
|
||||
new Vector3(-1, 0, 0),
|
||||
//right
|
||||
new Vector3(1, 0, 0),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 643914e5a873de34baea75d649800005
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,213 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
public class Server
|
||||
{
|
||||
//game
|
||||
private World world;
|
||||
|
||||
//network
|
||||
private UdpClient client;
|
||||
private int transferDelay;
|
||||
private List<IPEndPoint> players = new List<IPEndPoint>();
|
||||
private List<string> playerNames = new List<string>();
|
||||
private List<bool> nextTransfer = new List<bool>();
|
||||
private Thread receiveThread;
|
||||
private List<Thread> transferThreads = new List<Thread>();
|
||||
|
||||
public Server(World world, int transferDelay)
|
||||
{
|
||||
this.transferDelay = transferDelay;
|
||||
this.world = world;
|
||||
|
||||
//setup client
|
||||
client = new UdpClient(8051);
|
||||
client.DontFragment = false;
|
||||
|
||||
//start listening
|
||||
receiveThread = new Thread(Receive); //info:
|
||||
receiveThread.Start();
|
||||
//0: init message
|
||||
}
|
||||
|
||||
//info:
|
||||
//[0] = 0: init message
|
||||
//[0] = 1: world transfer [1] = 1: finished
|
||||
//[0] = 2: world size
|
||||
//[0] = 3: edit block
|
||||
//[0] = 4: disconnect player
|
||||
//[0] = 5: next transfer
|
||||
|
||||
private void Receive()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
byte[] data = client.Receive(ref endPoint);
|
||||
|
||||
if (data[0] == 5)
|
||||
{
|
||||
int id = GetPlayerID(endPoint);
|
||||
nextTransfer[id] = true;
|
||||
}
|
||||
|
||||
if (data[0] == 4)
|
||||
{
|
||||
IPEndPoint tempEndPoint = null;
|
||||
int i = 0;
|
||||
foreach (IPEndPoint e in players)
|
||||
{
|
||||
if (e.Address.GetHashCode() == endPoint.Address.GetHashCode())
|
||||
{
|
||||
Send(new byte[] { 4 }, e);
|
||||
tempEndPoint = e;
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (tempEndPoint != null)
|
||||
{
|
||||
players.Remove(tempEndPoint);
|
||||
Console.WriteLine(playerNames[i] + " left the game");
|
||||
playerNames.RemoveAt(i);
|
||||
nextTransfer.RemoveAt(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (data[0] == 0)
|
||||
{
|
||||
Thread t = new Thread(TransferWorld);
|
||||
transferThreads.Add(t);
|
||||
t.Start(endPoint);
|
||||
}
|
||||
|
||||
if (data[0] == 2)
|
||||
{
|
||||
Send(new byte[] { 2, (byte)world.worldSize }, endPoint);
|
||||
|
||||
List<byte> asciiName = new List<byte>();
|
||||
for (int i = 1; i < data.Length; i++)
|
||||
{
|
||||
asciiName.Add(data[i]);
|
||||
}
|
||||
|
||||
string name = Encoding.ASCII.GetString(asciiName.ToArray());
|
||||
//add player
|
||||
players.Add(endPoint);
|
||||
playerNames.Add(name);
|
||||
nextTransfer.Add(false);
|
||||
Console.WriteLine(name + " joined the game");
|
||||
}
|
||||
|
||||
if (data[0] == 3)
|
||||
{
|
||||
ChunkCoord chunk = new ChunkCoord(data[1], data[2]);
|
||||
Vector3 positionInChunk = new Vector3(data[3], data[4], data[5]);
|
||||
byte blockID = data[6];
|
||||
|
||||
world.EditBlock(chunk, positionInChunk, blockID);
|
||||
|
||||
foreach (IPEndPoint e in players)
|
||||
{
|
||||
Send(new byte[]
|
||||
{
|
||||
3, (byte)chunk.x, (byte)chunk.z,
|
||||
(byte)positionInChunk.x, (byte)positionInChunk.y, (byte)positionInChunk.z, blockID
|
||||
}, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private int GetPlayerID(IPEndPoint endPoint)
|
||||
{
|
||||
int i = 0;
|
||||
foreach (IPEndPoint e in players)
|
||||
{
|
||||
if (e.Address.GetHashCode() == endPoint.Address.GetHashCode())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void TransferWorld(object o)
|
||||
{
|
||||
IPEndPoint endPoint = (IPEndPoint)o;
|
||||
int id = GetPlayerID(endPoint);
|
||||
|
||||
Console.WriteLine("begin world transfer for " + playerNames[id]);
|
||||
for (int xChunk = 0; xChunk < world.worldSize; xChunk++)
|
||||
{
|
||||
for (int zChunk = 0; zChunk < world.worldSize; zChunk++)
|
||||
{
|
||||
nextTransfer[id] = false;
|
||||
|
||||
byte[] send = new byte[Data.chunkWidth * Data.chunkWidth * Data.chunkHeight + 2];
|
||||
send[0] = 1;
|
||||
send[1] = 0;
|
||||
int i = 2;
|
||||
|
||||
for (int y = 0; y < Data.chunkHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < Data.chunkWidth; x++)
|
||||
{
|
||||
for (int z = 0; z < Data.chunkWidth; z++)
|
||||
{
|
||||
send[i] = world.chunks[xChunk, zChunk].blocks[x, y, z];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Send(send, endPoint);
|
||||
|
||||
while (!nextTransfer[id])
|
||||
{
|
||||
}
|
||||
|
||||
nextTransfer[id] = false;
|
||||
}
|
||||
}
|
||||
|
||||
Send(new byte[] { 1, 1 }, endPoint);
|
||||
Console.WriteLine("world transfer finished for " + playerNames[id]);
|
||||
}
|
||||
|
||||
private void Send(byte[] data, IPEndPoint endPoint)
|
||||
{
|
||||
client.Send(data, data.Length, endPoint);
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
receiveThread.Abort();
|
||||
for (int i = 0; i < transferThreads.Count; i++)
|
||||
{
|
||||
if (transferThreads[i] != null)
|
||||
{
|
||||
transferThreads[i].Abort();
|
||||
}
|
||||
}
|
||||
client.Close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40d9d5a5030b4944ea8c79b350ed5a0c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class World : MonoBehaviour
|
||||
{
|
||||
//basic
|
||||
[SerializeField] public int worldSize;
|
||||
|
||||
//chunks
|
||||
public Chunk[,] chunks;
|
||||
|
||||
//network
|
||||
private Server server;
|
||||
[SerializeField] private int transferDelay;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
CreateChunks();
|
||||
server = new Server(this, transferDelay);
|
||||
}
|
||||
|
||||
//creates an array of chunks
|
||||
private void CreateChunks()
|
||||
{
|
||||
chunks = new Chunk[worldSize, worldSize];
|
||||
for (int x = 0; x < worldSize; x++)
|
||||
{
|
||||
for (int z = 0; z < worldSize; z++)
|
||||
{
|
||||
chunks[x, z] = new Chunk(new ChunkCoord(x, z), this);
|
||||
chunks[x, z].gameObject.transform.SetParent(gameObject.transform);
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < worldSize; x++)
|
||||
{
|
||||
for (int z = 0; z < worldSize; z++)
|
||||
{
|
||||
chunks[x, z].PopulateBlocks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//return the ID of a block
|
||||
public byte GetBlockID(Vector3 positionInWorld)
|
||||
{
|
||||
byte height = GetHeight((int)positionInWorld.x, (int)positionInWorld.z);
|
||||
|
||||
//world pass
|
||||
if (positionInWorld.x < 0 || positionInWorld.y < 0 || positionInWorld.z < 0 ||
|
||||
positionInWorld.x >= worldSize * Data.chunkWidth || positionInWorld.y > height ||
|
||||
positionInWorld.z >= worldSize * Data.chunkWidth)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//chunk pass
|
||||
if ((int)positionInWorld.y == height)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
if ((int)positionInWorld.y == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((int)positionInWorld.y > height - 3)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
if ((int)positionInWorld.y < height)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//returns if a block is on the position
|
||||
public bool CheckBlock(Vector3 positionInWorld)
|
||||
{
|
||||
if (positionInWorld.x < -1 || positionInWorld.z < -1 ||
|
||||
positionInWorld.x > worldSize * Data.chunkWidth ||
|
||||
positionInWorld.z > worldSize * Data.chunkWidth)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (positionInWorld.x < 0 || positionInWorld.y < 0 || positionInWorld.z < 0 ||
|
||||
positionInWorld.x >= worldSize * Data.chunkWidth || positionInWorld.y >= Data.chunkHeight ||
|
||||
positionInWorld.z >= worldSize * Data.chunkWidth)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ChunkCoord chunk = new ChunkCoord((int)(positionInWorld.x / Data.chunkWidth),
|
||||
(int)(positionInWorld.z / Data.chunkWidth));
|
||||
|
||||
int xInChunk = (int)(positionInWorld.x - chunk.x * Data.chunkWidth);
|
||||
int yInChunk = (int)positionInWorld.y;
|
||||
int zInChunk = (int)(positionInWorld.z - chunk.z * Data.chunkWidth);
|
||||
|
||||
if (chunks[chunk.x, chunk.z] != null)
|
||||
{
|
||||
if (chunks[chunk.x, chunk.z].blocks[xInChunk, yInChunk, zInChunk] == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private byte GetHeight(int x, int z)
|
||||
{
|
||||
float scale = 0.025f;
|
||||
byte perlinHeight = 10;
|
||||
byte groundHeight = 10;
|
||||
|
||||
byte height = (byte)(Mathf.PerlinNoise((x) * scale + 0.1f, (z) * scale + 0.1f) * perlinHeight + groundHeight);
|
||||
return height;
|
||||
}
|
||||
|
||||
public void EditBlock(ChunkCoord chunk, Vector3 positionInChunk, byte blockID)
|
||||
{
|
||||
byte xInChunk = (byte)(positionInChunk.x);
|
||||
byte yInChunk = (byte)positionInChunk.y;
|
||||
byte zInChunk = (byte)(positionInChunk.z);
|
||||
|
||||
//edit block in chunk
|
||||
if(chunks[chunk.x, chunk.z].blocks[xInChunk, yInChunk, zInChunk] != 1)
|
||||
{
|
||||
chunks[chunk.x, chunk.z].Update(xInChunk, yInChunk, zInChunk, blockID);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnApplicationQuit()
|
||||
{
|
||||
server.Disconnect();
|
||||
}
|
||||
|
||||
|
||||
private void SaveWorld()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5457f26f725053d46bffb9885acfd7d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user