diff options
Diffstat (limited to 'src/world')
-rw-r--r-- | src/world/Block.cpp | 10 | ||||
-rw-r--r-- | src/world/Block.hpp | 15 | ||||
-rw-r--r-- | src/world/Section.cpp | 129 | ||||
-rw-r--r-- | src/world/Section.hpp | 41 | ||||
-rw-r--r-- | src/world/World.cpp | 117 | ||||
-rw-r--r-- | src/world/World.hpp | 32 |
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 |