summaryrefslogblamecommitdiffstats
path: root/src/World.cpp
blob: f9edbe138033211ace2722c1a93cc9969007bdc5 (plain) (tree)
1
2
3
4
5
6
7
8
9
                    
                    

                                                                     
                                                                         



                                                                                         

                                                                                              





                                                                                                        
                                
                                                                                

                                                                                                  
         


         
                                                                       
                                                       





                          






                                                                  
                                                    

                                            
                                                     
                                                                                             

                                                                                                 
 
                 



                                             
                                                                                                                                      







                                                                     


                



                                                                              

                                                                                                                                             
                                                          






                                                                                
          
                                            
                                                      
                                                               
                                             
         














                                                      
                                                      


                                                              
                                                                                        

                                                                            


                                                                                   








                                                                                 

                                              



                                                                                                


                            

                                                          


                                                     

                                                                   


                              




                                                                                                        


                                      

                         


                                         
                           
 


                                                
                         

                                      
                                   


                      
                           





                                                  
                         



                                   
                           




                                    
                         






                                                                              















                                               
 

                                                                       
                                                                                      

                                                                                                                                           
 








                                                                            
                                                                                






                                                                                                           











                                                                                          
 
#include "World.hpp"
#include "Event.hpp"

void World::ParseChunkData(std::shared_ptr<PacketChunkData> packet) {
	StreamBuffer chunkData(packet->Data.data(), packet->Data.size());
	std::bitset<16> bitmask(packet->PrimaryBitMask);
	for (int i = 0; i < 16; i++) {
		if (bitmask[i]) {
			Vector chunkPosition = Vector(packet->ChunkX, i, packet->ChunkZ);
			PackedSection packedSection = ParseSection(&chunkData, chunkPosition);
            Section section(packedSection);
            
            if (packet->GroundUpContinuous) {
                if (!cachedSections.insert(std::make_pair(chunkPosition, section)).second) {
                    LOG(ERROR) << "New chunk not created " << chunkPosition << " potential memory leak";
                }
            } else {
                using std::swap;
                swap(cachedSections.at(chunkPosition), section);                
            }
            EventAgregator::PushEvent(EventType::ChunkChanged, ChunkChangedData{ chunkPosition });
        }
	}
}

PackedSection World::ParseSection(StreamInput *data, Vector position) {
	unsigned char bitsPerBlock = data->ReadUByte();
    if (bitsPerBlock < 4)
        bitsPerBlock = 4;

    if (bitsPerBlock > 8)
        bitsPerBlock = 13;

	int paletteLength = data->ReadVarInt();
	std::vector<unsigned short> palette;
	for (int i = 0; i < paletteLength; i++) {
		palette.push_back(data->ReadVarInt());
	}
	int dataArrayLength = data->ReadVarInt();
	auto dataArray = data->ReadByteArray(dataArrayLength * 8);
	auto blockLight = data->ReadByteArray(2048);
	std::vector<unsigned char> skyLight;
	if (dimension == 0)
		skyLight = data->ReadByteArray(2048);
	return PackedSection(position, dataArray.data(), dataArray.size(), blockLight.data(),
	               (skyLight.size() > 0 ? skyLight.data() : nullptr), bitsPerBlock, palette);
}

World::~World() {
}

Block & World::GetBlock(Vector worldPosition)
{
    Vector sectionPos(std::floor(worldPosition.x / 16.0), std::floor(worldPosition.y / 16.0), std::floor(worldPosition.z / 16.0));    
    auto it = cachedSections.find(sectionPos);
    if (it == cachedSections.end()) {
        static Block fallbackBlock;
        return fallbackBlock;
    }
    Section& section = it->second;
    Block& block = section.GetBlock(worldPosition - sectionPos * 16);
    return block;
}

World::World() {
}

bool World::isPlayerCollides(double X, double Y, double Z) {
	Vector PlayerChunk(floor(X / 16.0), floor(Y / 16.0), floor(Z / 16.0));
    if (cachedSections.find(PlayerChunk) == cachedSections.end() || cachedSections.find(PlayerChunk - Vector(0,1,0)) == cachedSections.end())
        return true;
	std::vector<Vector> closestSectionsCoordinates = {
			Vector(PlayerChunk.x, PlayerChunk.y, PlayerChunk.z),
			Vector(PlayerChunk.x + 1, PlayerChunk.y, PlayerChunk.z),
			Vector(PlayerChunk.x - 1, PlayerChunk.y, PlayerChunk.z),
			Vector(PlayerChunk.x, PlayerChunk.y + 1, PlayerChunk.z),
			Vector(PlayerChunk.x, PlayerChunk.y - 1, PlayerChunk.z),
			Vector(PlayerChunk.x, PlayerChunk.y, PlayerChunk.z + 1),
			Vector(PlayerChunk.x, PlayerChunk.y, PlayerChunk.z - 1),
	};
	std::vector<Vector> closestSections;
	for (auto &coord:closestSectionsCoordinates) {
        if (cachedSections.find(coord) != cachedSections.end())
            closestSections.push_back(coord);
	}

	for (auto &it:closestSections) {

		const double PlayerWidth = 0.6;
		const double PlayerHeight = 1.82;
		const double PlayerLength = 0.6;

		AABB playerColl;
		playerColl.x = X - PlayerWidth / 2.0;
		playerColl.w = PlayerWidth;
		playerColl.y = Y;
		playerColl.h = PlayerHeight;
		playerColl.z = Z - PlayerLength / 2.0;
		playerColl.l = PlayerLength;

        const Section &section = this->GetSection(it);
		for (int x = 0; x < 16; x++) {
			for (int y = 0; y < 16; y++) {
				for (int z = 0; z < 16; z++) {
					Block block = section.GetBlock(Vector(x, y, z));
					if (block.id == 0 || block.id == 31)
						continue;
					AABB blockColl{(x + it.x * 16.0),
					               (y + it.y * 16.0),
					               (z + it.z * 16.0), 1, 1, 1};
					if (TestCollision(playerColl, blockColl))
						return true;
				}
			}
		}
	}
	return false;
}

std::vector<Vector> World::GetSectionsList() {
	std::vector<Vector> sectionsList;
    for (auto& it : cachedSections) {
        if (std::find(sectionsList.begin(), sectionsList.end(), it.first) == sectionsList.end())
            sectionsList.push_back(it.first);
    }
	return sectionsList;
}

static Section fallbackSection = Section(PackedSection());

const Section &World::GetSection(Vector sectionPos) {
    auto result = cachedSections.find(sectionPos);
    if (result == cachedSections.end()) {
        LOG(ERROR) << "Accessed not loaded section " << sectionPos;
        return fallbackSection;
    } else {
        return result->second;
    }
}

glm::vec3 World::Raycast(glm::vec3 position, glm::vec3 direction, float maxLength, float minPrecision) {
    return glm::vec3(position * direction / maxLength * minPrecision);
}

void World::UpdatePhysics(float delta)
{
    //delta /= 5;
    entitiesMutex.lock();
    for (auto& it : entities) {
        it.pos = it.pos + it.vel * delta;
    }
    entitiesMutex.unlock();
}

Entity & World::GetEntity(unsigned int EntityId)
{
    entitiesMutex.lock();
    for (auto& it : entities) {
        if (it.entityId == EntityId) {
            entitiesMutex.unlock();
            return it;
        }
    }
    entitiesMutex.unlock();
    static Entity fallback;
    return fallback;
}

std::vector<unsigned int> World::GetEntitiesList()
{
    entitiesMutex.lock();
    std::vector<unsigned int> ret;
    for (auto& it : entities) {
        ret.push_back(it.entityId);
    }
    entitiesMutex.unlock();
    return ret;
}

void World::AddEntity(Entity entity)
{
    entitiesMutex.lock();
    for (auto& it : entities) {
        if (it.entityId == entity.entityId) {
            LOG(ERROR) << "Adding already existing entity" << entity.entityId;
            return;
        }
    }
    entities.push_back(entity);
    entitiesMutex.unlock();
}

void World::DeleteEntity(unsigned int EntityId)
{
    entitiesMutex.lock();
    auto it = entities.begin();
    for (; it != entities.end(); ++it) {
        if (it->entityId == EntityId) {
            break;
        }
    }
    if (it != entities.end())
        entities.erase(it);
    entitiesMutex.unlock();
}

void World::ParseChunkData(std::shared_ptr<PacketBlockChange> packet) {
    Block& block = this->GetBlock(packet->Position);
    block = Block(packet->BlockId >> 4, packet->BlockId & 15, block.light, block.sky);
    Vector sectionPos(std::floor(packet->Position.x / 16.0), std::floor(packet->Position.y / 16.0), std::floor(packet->Position.z / 16.0));
    EventAgregator::PushEvent(EventType::ChunkChanged, ChunkChangedData{ sectionPos });
}

void World::ParseChunkData(std::shared_ptr<PacketMultiBlockChange> packet) {
    std::vector<Vector> changedSections;
    for (auto& it : packet->Records) {
        int x = (it.HorizontalPosition >> 4 & 15) + (packet->ChunkX * 16);
        int y = it.YCoordinate;
        int z = (it.HorizontalPosition & 15) + (packet->ChunkZ * 16);
        Vector worldPos(x, y, z);
        Block& block = GetBlock(worldPos);
        block = Block(it.BlockId >> 4, it.BlockId & 15, block.light, block.sky);

        Vector sectionPos(packet->ChunkX, std::floor(it.YCoordinate / 16.0), packet->ChunkZ);
        if (std::find(changedSections.begin(), changedSections.end(), sectionPos) == changedSections.end())
            changedSections.push_back(sectionPos);
    }
    for (auto& sectionPos: changedSections)
        EventAgregator::PushEvent(EventType::ChunkChanged, ChunkChangedData{ sectionPos });
}

void World::ParseChunkData(std::shared_ptr<PacketUnloadChunk> packet) {
    std::vector<std::map<Vector,Section>::iterator> toRemove;
    for (auto it = cachedSections.begin(); it != cachedSections.end(); ++it) {
        if (it->first.x == packet->ChunkX && it->first.z == packet->ChunkZ)
            toRemove.push_back(it);
    }
    for (auto& it : toRemove) {
        EventAgregator::PushEvent(EventType::ChunkDeleted, ChunkDeletedData{ it->first });
        cachedSections.erase(it);        
    }
}