summaryrefslogtreecommitdiffstats
path: root/src/world
diff options
context:
space:
mode:
Diffstat (limited to 'src/world')
-rw-r--r--src/world/Block.cpp10
-rw-r--r--src/world/Block.hpp15
-rw-r--r--src/world/Section.cpp129
-rw-r--r--src/world/Section.hpp41
-rw-r--r--src/world/World.cpp117
-rw-r--r--src/world/World.hpp32
6 files changed, 344 insertions, 0 deletions
diff --git a/src/world/Block.cpp b/src/world/Block.cpp
new file mode 100644
index 0000000..64e5330
--- /dev/null
+++ b/src/world/Block.cpp
@@ -0,0 +1,10 @@
+#include "Block.hpp"
+
+Block::~Block() {}
+
+Block::Block(unsigned short idAndState, unsigned char light) : id(idAndState >> 4), state(idAndState & 0x0F),
+ light(light) {}
+
+Block::Block(unsigned short id, unsigned char state, unsigned char light) : id(id), state(state), light(light) {}
+
+Block::Block() : id(0), state(0), light(0) {}
diff --git a/src/world/Block.hpp b/src/world/Block.hpp
new file mode 100644
index 0000000..7c780c1
--- /dev/null
+++ b/src/world/Block.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+struct Block {
+ Block(unsigned short idAndState, unsigned char light);
+
+ Block(unsigned short id, unsigned char state, unsigned char light);
+
+ Block();
+
+ ~Block();
+
+ unsigned short id:13;
+ unsigned char state:4;
+ unsigned char light:4;
+}; \ No newline at end of file
diff --git a/src/world/Section.cpp b/src/world/Section.cpp
new file mode 100644
index 0000000..f53c987
--- /dev/null
+++ b/src/world/Section.cpp
@@ -0,0 +1,129 @@
+#include <iostream>
+#include "Section.hpp"
+
+Section::Section(byte *dataBlocks, size_t dataBlocksLength, byte *dataLight, byte *dataSky, byte bitsPerBlock,
+ std::vector<unsigned short> palette) {
+ m_dataBlocksLen = dataBlocksLength;
+ m_dataBlocks = new byte[m_dataBlocksLen];
+ std::copy(dataBlocks, dataBlocks + m_dataBlocksLen, m_dataBlocks);
+
+ m_dataLight = new byte[2048];
+ std::copy(dataLight, dataLight + 2048, m_dataLight);
+
+ if (dataSky) {
+ m_dataSkyLight = new byte[2048];
+ std::copy(dataSky, dataSky + 2048, m_dataSkyLight);
+ }
+
+ m_palette = palette;
+ m_bitsPerBlock = bitsPerBlock;
+}
+
+Section::~Section() {
+ delete[] m_dataBlocks;
+ m_dataBlocksLen = 0;
+ m_dataBlocks = nullptr;
+ delete[] m_dataLight;
+ m_dataLight = nullptr;
+ delete[] m_dataSkyLight;
+ m_dataSkyLight = nullptr;
+}
+
+Block &Section::GetBlock(Vector pos) {
+ if (m_dataBlocks != nullptr) {
+ std::mutex parseMutex;
+ std::unique_lock<std::mutex> parseLocker(parseMutex);
+ parseWaiter.wait(parseLocker);
+ while (m_dataBlocks != nullptr) {
+ parseWaiter.wait(parseLocker);
+ }
+ }
+ return m_blocks[pos.GetY() * 256 + pos.GetZ() * 16 + pos.GetX()];
+}
+
+void Section::Parse() {
+ if (m_dataBlocks == nullptr)
+ return;
+
+ long long *longArray = reinterpret_cast<long long *>(m_dataBlocks);
+ for (int i = 0; i < m_dataBlocksLen / 8; i++)
+ endswap(&longArray[i]);
+ std::vector<unsigned short> blocks;
+ blocks.reserve(4096);
+ int bitPos = 0;
+ unsigned short t = 0;
+ for (int i = 0; i < m_dataBlocksLen; i++) {
+ for (int j = 0; j < 8; j++) {
+ t |= (m_dataBlocks[i] & 0x01) ? 0x80 : 0x00;
+ t >>= 1;
+ m_dataBlocks[i] >>= 1;
+ bitPos++;
+ if (bitPos >= m_bitsPerBlock) {
+ bitPos = 0;
+ t >>= m_bitsPerBlock - 1;
+ blocks.push_back(t);
+ t = 0;
+ }
+ }
+ }
+
+ std::vector<byte> light;
+ light.reserve(4096);
+ for (int i = 0; i < 2048; i++) {
+ byte t = m_dataLight[i];
+ byte first = t & 0b11110000;
+ byte second = t >> 4;
+ light.push_back(first);
+ light.push_back(second);
+ }
+ for (int i = 0; i < 4096; i++) {
+ unsigned short blockId = m_palette.size() > 0 ? m_palette[blocks[i]] : blocks[i];
+ Block block(blockId, light[i]);
+ m_blocks.push_back(block);
+ }
+ if ((light.size() + blocks.size()) / 2 != 4096) {
+ throw 118;
+ }
+ delete[] m_dataBlocks;
+ m_dataBlocksLen = 0;
+ m_dataBlocks = nullptr;
+ delete[] m_dataLight;
+ m_dataLight = nullptr;
+ delete[] m_dataSkyLight;
+ m_dataSkyLight = nullptr;
+ parseWaiter.notify_all();
+}
+
+Section &Section::operator=(Section other) {
+ other.swap(*this);
+ return *this;
+}
+
+void Section::swap(Section &other) {
+ std::swap(other.m_dataBlocksLen, m_dataBlocksLen);
+ std::swap(other.m_dataBlocks, m_dataBlocks);
+ std::swap(other.m_dataLight, m_dataLight);
+ std::swap(other.m_dataSkyLight, m_dataSkyLight);
+ std::swap(other.m_blocks, m_blocks);
+ std::swap(other.m_palette, m_palette);
+ std::swap(other.m_bitsPerBlock, m_bitsPerBlock);
+}
+
+Section::Section(const Section &other) {
+ m_dataBlocksLen = other.m_dataBlocksLen;
+ m_dataBlocks = new byte[m_dataBlocksLen];
+ std::copy(other.m_dataBlocks, other.m_dataBlocks + m_dataBlocksLen, m_dataBlocks);
+
+ m_dataLight = new byte[2048];
+ std::copy(other.m_dataLight, other.m_dataLight + 2048, m_dataLight);
+
+ if (other.m_dataSkyLight) {
+ m_dataSkyLight = new byte[2048];
+ std::copy(other.m_dataSkyLight, other.m_dataSkyLight + 2048, m_dataSkyLight);
+ }
+
+ m_palette = other.m_palette;
+ m_bitsPerBlock = other.m_bitsPerBlock;
+}
+
+
diff --git a/src/world/Section.hpp b/src/world/Section.hpp
new file mode 100644
index 0000000..3065cbd
--- /dev/null
+++ b/src/world/Section.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <vector>
+#include <map>
+#include <condition_variable>
+#include "Block.hpp"
+#include "../packet/Field.hpp"
+
+const int SECTION_WIDTH = 16;
+const int SECTION_LENGTH = 16;
+const int SECTION_HEIGHT = 16;
+
+class Section {
+ std::vector<unsigned short> m_palette;
+ byte *m_dataBlocks = nullptr;
+ size_t m_dataBlocksLen;
+ byte *m_dataLight = nullptr;
+ byte *m_dataSkyLight = nullptr;
+ byte m_bitsPerBlock = 0;
+ std::vector<Block> m_blocks;
+ std::condition_variable parseWaiter;
+
+ Section();
+
+public:
+ void Parse();
+
+ Section(byte *dataBlocks, size_t dataBlocksLength, byte *dataLight, byte *dataSky, byte bitsPerBlock,
+ std::vector<unsigned short> palette);
+
+ ~Section();
+
+ Block &GetBlock(Vector pos);
+
+ Section &operator=(Section other);
+
+ void swap(Section &other);
+
+ Section(const Section &other);
+
+}; \ No newline at end of file
diff --git a/src/world/World.cpp b/src/world/World.cpp
new file mode 100644
index 0000000..adbb3e1
--- /dev/null
+++ b/src/world/World.cpp
@@ -0,0 +1,117 @@
+#include <iostream>
+#include <bitset>
+#include "World.hpp"
+
+void World::ParseChunkData(Packet packet) {
+ int chunkX = packet.GetField(0).GetInt();
+ int chunkZ = packet.GetField(1).GetInt();
+ bool isGroundContinuous = packet.GetField(2).GetBool();
+ std::bitset<16> bitmask(packet.GetField(3).GetVarInt());
+ int entities = packet.GetField(5).GetVarInt();
+
+ size_t dataLen = packet.GetField(5).GetLength();
+ byte *content = new byte[dataLen];
+ byte *contentOrigPtr = content;
+ packet.GetField(5).CopyToBuff(content);
+
+ if (isGroundContinuous)
+ dataLen -= 256;
+
+ byte *biomes = content + packet.GetField(5).GetLength() - 256;
+ for (int i = 0; i < 16; i++) {
+ if (bitmask[i]) {
+ size_t len = 0;
+ Vector chunkPosition = Vector(chunkX, i, chunkZ);
+ if (!m_sections.insert(std::make_pair(chunkPosition,ParseSection(content,len))).second)
+ std::cout<<"Chunk not created: "<<chunkPosition<<std::endl;
+ auto sectionIter = m_sections.find(chunkPosition);
+ if (sectionIter==m_sections.end())
+ std::cout<<"Created chunk not found: "<<chunkPosition<<std::endl;
+ else
+ sectionIter->second.Parse();
+ /*m_sections[chunkPosition] = ParseSection(content, len);
+ m_sections[chunkPosition].Parse();*/
+ /*m_sectionToParse.push(m_sections.find(Vector(chunkX, i, chunkZ)));
+ m_parseSectionWaiter.notify_one();*/
+ content += len;
+ }
+ }
+ delete[] contentOrigPtr;
+ //std::cout<<m_sections.size()<<std::endl;
+}
+
+Section World::ParseSection(byte *data, size_t &dataLen) {
+ dataLen = 0;
+
+ Field fBitsPerBlock = FieldParser::Parse(UnsignedByte, data);
+ byte bitsPerBlock = fBitsPerBlock.GetUByte();
+ data += fBitsPerBlock.GetLength();
+ dataLen += fBitsPerBlock.GetLength();
+
+ Field fPaletteLength = FieldParser::Parse(VarInt, data);
+ int paletteLength = fPaletteLength.GetVarInt();
+ data += fPaletteLength.GetLength();
+ dataLen += fPaletteLength.GetLength();
+
+ std::vector<unsigned short> palette;
+ if (paletteLength > 0) {
+ for (unsigned char i = 0; i < paletteLength; i++) {
+ endswap(&i);
+ Field f = FieldParser::Parse(VarInt, data);
+ data += f.GetLength();
+ dataLen += f.GetLength();
+ palette.push_back(f.GetVarInt());
+ endswap(&i);
+ }
+ }
+
+ Field fDataLength = FieldParser::Parse(VarInt, data);
+ data += fDataLength.GetLength();
+ dataLen += fDataLength.GetLength();
+
+ int dataLength = fDataLength.GetVarInt();
+ size_t dataSize = dataLength * 8;
+ dataLen += dataSize;
+ byte *dataBlocks = data;
+
+ data += 2048;
+ dataLen += 2048;
+ byte *dataLight = data;
+
+ byte *dataSky = nullptr;
+ if (m_dimension == 0) {
+ data += 2048;
+ dataLen += 2048;
+ dataSky = data;
+ }
+
+ return Section(dataBlocks, dataSize, dataLight, dataSky, bitsPerBlock, palette);
+}
+
+World::~World() {
+ isContinue = false;
+ m_parseSectionWaiter.notify_all();
+ m_sectionParseThread.join();
+}
+
+void World::SectionParsingThread() {
+ while (isContinue) {
+ std::unique_lock<std::mutex> sectionParseLocker(m_parseSectionMutex);
+ m_parseSectionWaiter.wait(sectionParseLocker);
+ while (m_sectionToParse.size() == 0 && isContinue) {
+ m_parseSectionWaiter.wait(sectionParseLocker);
+ }
+ while (m_sectionToParse.size() > 0) {
+ auto it = m_sectionToParse.front();
+ m_sectionToParse.pop();
+ it->second.Parse();
+ /*std::cout << "Parsed chunk" << it->first.GetX() << "x" << it->first.GetY() << "x" << it->first.GetZ()
+ << std::endl;*/
+ }
+ }
+}
+
+World::World() {
+ m_sectionParseThread = std::thread(&World::SectionParsingThread, this);
+}
+
diff --git a/src/world/World.hpp b/src/world/World.hpp
new file mode 100644
index 0000000..7b7ea60
--- /dev/null
+++ b/src/world/World.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <map>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <queue>
+#include "Block.hpp"
+#include "../packet/Packet.hpp"
+#include "Section.hpp"
+
+class World {
+ //utility vars
+ World(const World& other);
+ World&operator=(const World &other);
+ bool isContinue=true;
+ std::mutex m_parseSectionMutex;
+ std::condition_variable m_parseSectionWaiter;
+ std::thread m_sectionParseThread;
+ std::queue<std::map<Vector,Section>::iterator> m_sectionToParse;
+ //utility methods
+ void SectionParsingThread();
+ //game vars
+ int m_dimension = 0;
+ //game methods
+ Section ParseSection(byte *data, size_t &dataLen);
+public:
+ World();
+ ~World();
+ void ParseChunkData(Packet packet);
+ std::map<Vector, Section> m_sections;
+}; \ No newline at end of file