summaryrefslogtreecommitdiffstats
path: root/src/ChunkSender.h
blob: 9c391a6fc49b23591a38e903660bf4df710649fd (plain) (blame)
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
129
130
131
132
133
134
135
136
137

// ChunkSender.h

// Interfaces to the cChunkSender class representing the thread that waits for chunks becoming ready (loaded / generated) and sends them to clients

/*
The whole thing is a thread that runs in a loop, waiting for either:
	"finished chunks" (ChunkReady()), or
	"chunks to send" (QueueSendChunkTo())
to come to a queue.
And once they do, it requests the chunk data and sends it all away, either
	broadcasting (ChunkReady), or
	sends to a specific client (QueueSendChunkTo)
Chunk data is queried using the cChunkDataCallback interface.
It is cached inside the ChunkSender object during the query and then processed after the query ends.
Note that the data needs to be compressed only after the query finishes,
because the query callbacks run with ChunkMap's CS locked.

A client may remove itself from all direct requests(QueueSendChunkTo()) by calling RemoveClient();
this ensures that the client's Send() won't be called anymore by ChunkSender.
Note that it may be called by world's BroadcastToChunk() if the client is still in the chunk.
*/



#pragma once

#include "OSSupport/IsThread.h"
#include "ChunkDef.h"
#include "ChunkDataCallback.h"
#include "ChunkStay.h"





class cWorld;
class cClientHandle;





// fwd:
class cChunkSender;





class cChunkSender:
	public cIsThread
{
	typedef cIsThread super;
public:
	cChunkSender(cWorld & a_World);
	~cChunkSender();

	enum eChunkPriority
	{
		E_CHUNK_PRIORITY_HIGH = 0,
		E_CHUNK_PRIORITY_MIDHIGH,
		E_CHUNK_PRIORITY_MEDIUM,
		E_CHUNK_PRIORITY_LOW,

	};

	bool Start();

	void Stop(void);

	/** Queues a chunk to be sent to a specific client
	A chunkstay ensures that the chunk is valid before sending */
	void QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, eChunkPriority a_Priority, const std::weak_ptr<cClientHandle> & a_Client);
	void QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, eChunkPriority a_Priority, const std::vector<std::weak_ptr<cClientHandle>> & a_Clients);

protected:

	class cChunkQueue :
		public cChunkStay,
		public cChunkDataSeparateCollector
	{
	public:

		cChunkQueue(eChunkPriority a_Priority, cChunkCoords a_ChunkCoordinate, const std::weak_ptr<cClientHandle> & a_Client, cChunkSender & a_ChunkSender) :
			m_Priority(a_Priority),
			m_Chunk(a_ChunkCoordinate),
			m_Clients{ a_Client },
			m_ChunkSender(a_ChunkSender)
		{
			Add(a_ChunkCoordinate.m_ChunkX, a_ChunkCoordinate.m_ChunkZ);
		}

		eChunkPriority m_Priority;
		cChunkCoords m_Chunk;
		std::vector<std::weak_ptr<cClientHandle>> m_Clients;

		// Data about the chunk that is being sent:
		// NOTE that m_BlockData[] is inherited from the cChunkDataCollector
		unsigned char m_BiomeMap[cChunkDef::Width * cChunkDef::Width];

	private:
		cChunkSender & m_ChunkSender;

		// cChunkDataCollector overrides:
		// (Note that they are called while the ChunkMap's CS is locked - don't do heavy calculations here!)
		virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override;

		// cChunkStay overrides
		virtual void OnChunkAvailable(int a_ChunkX, int a_ChunkZ) override
		{
			UNUSED(a_ChunkX);
			UNUSED(a_ChunkZ);
		}
		virtual bool OnAllChunksAvailable(void) override;
		virtual void OnDisabled(void) override
		{
			delete this;
		}
	};

	cWorld & m_World;

	cCriticalSection  m_CS;
	std::vector<cChunkQueue *> m_LoadQueue;
	std::vector<cChunkQueue *> m_SendChunks;
	cEvent m_evtQueue;  // Set when anything is added to m_ChunksReady

	// cIsThread override:
	virtual void Execute(void) override;

	/** Sends the specified chunk to all the specified clients */
	void SendChunk(const cChunkQueue & a_Item);
} ;