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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#include "server/pch.hh"
#include "server/worldgen.hh"
#include "shared/chunk.hh"
#include "shared/dimension.hh"
#include "shared/protocol.hh"
#include "shared/threading.hh"
#include "server/sessions.hh"
static emhash8::HashMap<Dimension *, emhash8::HashMap<chunk_pos, std::unordered_set<Session *>>> active_tasks;
class WorldgenTask final : public Task {
public:
explicit WorldgenTask(Dimension *dimension, const chunk_pos &cpos);
virtual ~WorldgenTask(void) = default;
virtual void process(void) override;
virtual void finalize(void) override;
private:
Dimension *m_dimension;
VoxelStorage m_voxels;
chunk_pos m_cpos;
};
WorldgenTask::WorldgenTask(Dimension *dimension, const chunk_pos &cpos)
{
m_dimension = dimension;
m_voxels.fill(rand()); // trolling
m_cpos = cpos;
}
void WorldgenTask::process(void)
{
if(!m_dimension->generate(m_cpos, m_voxels)) {
set_status(task_status::CANCELLED);
}
}
void WorldgenTask::finalize(void)
{
auto dim_tasks = active_tasks.find(m_dimension);
if(dim_tasks == active_tasks.cend()) {
// Normally this should never happen but
// one can never be sure about anything
// when that anything is threaded out
return;
}
auto it = dim_tasks->second.find(m_cpos);
if(it == dim_tasks->second.cend()) {
// Normally this should never happen but
// one can never be sure about anything
// when that anything is threaded out
return;
}
auto chunk = m_dimension->create_chunk(m_cpos);
chunk->set_voxels(m_voxels);
protocol::ChunkVoxels response;
response.voxels = m_voxels;
response.chunk = m_cpos;
auto packet = protocol::encode(response);
for(auto session : it->second) {
if(session->peer) {
// Respond with the voxels to every session
// that has requested this specific chunk for this dimension
enet_peer_send(session->peer, protocol::CHANNEL, packet);
}
}
dim_tasks->second.erase(it);
if(dim_tasks->second.empty()) {
// There are no more requests
// to generate a chunk for that
// dimension, at least for now
active_tasks.erase(dim_tasks);
}
}
bool worldgen::is_generating(Dimension *dimension, const chunk_pos &cpos)
{
auto dim_tasks = active_tasks.find(dimension);
if(dim_tasks == active_tasks.cend()) {
// No tasks for this dimension
return false;
}
auto it = dim_tasks->second.find(cpos);
if(it == dim_tasks->second.cend()) {
// Not generating this chunk
return false;
}
return true;
}
void worldgen::request_chunk(Session *session, const chunk_pos &cpos)
{
if(session->dimension) {
auto dim_tasks = active_tasks.find(session->dimension);
if(dim_tasks == active_tasks.cend()) {
dim_tasks = active_tasks.emplace(session->dimension, emhash8::HashMap<chunk_pos, std::unordered_set<Session *>>()).first;
}
auto it = dim_tasks->second.find(cpos);
if(it == dim_tasks->second.cend()) {
auto &sessions = dim_tasks->second.insert_or_assign(cpos, std::unordered_set<Session *>()).first->second;
sessions.insert(session);
threading::submit<WorldgenTask>(session->dimension, cpos);
return;
}
it->second.insert(session);
}
}
|