summaryrefslogtreecommitdiffstats
path: root/src/game/server/world/unloader.cc
blob: 4a3f4e1f415b04fc1bc54d32461cc4507b3be912 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include "server/pch.hh"

#include "server/world/unloader.hh"

#include "core/config/number.hh"

#include "shared/entity/player.hh"
#include "shared/entity/transform.hh"

#include "shared/world/chunk.hh"
#include "shared/world/chunk_aabb.hh"
#include "shared/world/dimension.hh"

#include "server/world/inhabited.hh"
#include "server/world/universe.hh"

#include "server/game.hh"
#include "server/globals.hh"

static void on_chunk_update(const world::ChunkUpdateEvent& event)
{
    event.dimension->chunks.emplace_or_replace<world::Inhabited>(event.chunk->get_entity());
}

static void on_voxel_set(const world::VoxelSetEvent& event)
{
    event.dimension->chunks.emplace_or_replace<world::Inhabited>(event.chunk->get_entity());
}

void world::unloader::init(void)
{
    globals::dispatcher.sink<world::ChunkUpdateEvent>().connect<&on_chunk_update>();
    globals::dispatcher.sink<world::VoxelSetEvent>().connect<&on_voxel_set>();
}

void world::unloader::init_late(void)
{
}

void world::unloader::fixed_update_late(Dimension* dimension)
{
    auto group = dimension->entities.group(entt::get<entity::Player, entity::Transform>);
    auto boxes = std::vector<ChunkAABB>();

    for(const auto [entity, transform] : group.each()) {
        ChunkAABB aabb;
        aabb.min = transform.chunk - static_cast<chunk_pos::value_type>(server_game::view_distance.get_value());
        aabb.max = transform.chunk + static_cast<chunk_pos::value_type>(server_game::view_distance.get_value());
        boxes.push_back(aabb);
    }

    auto view = dimension->chunks.view<ChunkComponent>();
    auto chunk_in_view = false;

    for(const auto [entity, chunk] : view.each()) {
        chunk_in_view = false;

        for(const auto& aabb : boxes) {
            if(aabb.contains(chunk.cpos)) {
                chunk_in_view = true;
                break;
            }
        }

        if(chunk_in_view) {
            // The chunk is within view box of at least
            // a single player; we shouldn't unload it now
            continue;
        }

        if(dimension->chunks.any_of<Inhabited>(entity)) {
            // Only store inhabited chunks on disk
            world::universe::save_chunk(dimension, chunk.cpos);
        }

        dimension->remove_chunk(entity);
    }
}