1
0
mirror of https://github.com/luanti-org/luanti.git synced 2026-01-14 05:15:21 +01:00
Files
luanti/src/servermap.h
lhofhansl 8883c4cb23 Process (a chunk local) liquid queue early when blocks are generated (#16771)
When generating a new chunk, the chunk's liquid queue is processed immediately, instead of adding entries to the global liquid queue. Since the generated have not been sent to the client, this avoids sending duplicate blocks (that interfere with map sending) later when the global liquid queue is processed.
2025-12-24 10:02:26 +01:00

210 lines
5.6 KiB
C++

// Luanti
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (C) 2010-2024 celeron55, Perttu Ahola <celeron55@gmail.com>
#pragma once
#include <vector>
#include <memory>
#include "map.h"
#include "util/container.h" // UniqueQueue
#include "util/metricsbackend.h" // ptr typedefs
#include "map_settings_manager.h"
class Settings;
class MapDatabase;
class EmergeManager;
class ServerEnvironment;
struct BlockMakeData;
class MetricsBackend;
// TODO: this could wrap all calls to MapDatabase, including locking
struct MapDatabaseAccessor {
/// Lock, to be taken for any operation
std::mutex mutex;
/// Main database
MapDatabase *dbase = nullptr;
/// Fallback database for read operations
MapDatabase *dbase_ro = nullptr;
/// Load a block, taking dbase_ro into account.
/// @note call locked
void loadBlock(v3s16 blockpos, std::string &ret);
};
/*
ServerMap
This is the only map class that is able to generate map.
*/
class ServerMap : public Map
{
public:
/*
savedir: directory to which map data should be saved
*/
ServerMap(const std::string &savedir, IGameDef *gamedef, EmergeManager *emerge, MetricsBackend *mb);
~ServerMap();
/*
Get a sector from somewhere.
- Check memory
- Check disk (doesn't load blocks)
- Create blank one
*/
MapSector *createSector(v2s16 p);
/*
Blocks are generated by using these and makeBlock().
*/
bool blockpos_over_mapgen_limit(v3s16 p);
/// @brief copy data from map to prepare for mapgen
/// @return true if mapgen should actually happen
bool initBlockMake(v3s16 blockpos, BlockMakeData *data);
/// @brief write data back to map after mapgen
/// @param now current game time
void finishBlockMake(BlockMakeData *data,
std::map<v3s16, MapBlock*> *changed_blocks, ServerEnvironment *env);
void cancelBlockMake(BlockMakeData *data);
/*
Get a block from somewhere.
- Memory
- Create blank
*/
MapBlock *createBlock(v3s16 p);
/*
Forcefully get a block from somewhere (blocking!).
- Memory
- Load from disk
- Create blank filled with CONTENT_IGNORE
*/
MapBlock *emergeBlock(v3s16 p, bool create_blank=true) override;
/*
Try to get a block.
If it does not exist in memory, add it to the emerge queue.
- Memory
- Emerge Queue (deferred disk or generate)
*/
MapBlock *getBlockOrEmerge(v3s16 p3d, bool generate);
bool isBlockInQueue(v3s16 pos);
void addNodeAndUpdate(v3s16 p, MapNode n,
std::map<v3s16, MapBlock*> &modified_blocks,
bool remove_metadata) override;
/*
Database functions
*/
static std::vector<std::string> getDatabaseBackends();
static MapDatabase *createDatabase(const std::string &name, const std::string &savedir, Settings &conf);
// Call these before and after saving of blocks
void beginSave() override;
void endSave() override;
void save(ModifiedState save_level) override;
void listAllLoadableBlocks(std::vector<v3s16> &dst);
void listAllLoadedBlocks(std::vector<v3s16> &dst);
MapgenParams *getMapgenParams();
bool saveBlock(MapBlock *block) override;
static bool saveBlock(MapBlock *block, MapDatabase *db, int compression_level = -1);
// Load block in a synchronous fashion
MapBlock *loadBlock(v3s16 p);
/// Load a block that was already read from disk. Used by EmergeManager.
/// @return non-null block (but can be blank)
MapBlock *loadBlock(const std::string &blob, v3s16 p, bool save_after_load=false);
// Helper for deserializing blocks from disk
// @throws SerializationError
static void deSerializeBlock(MapBlock *block, std::istream &is);
// Blocks are removed from the map but not deleted from memory until
// deleteDetachedBlocks() is called, since pointers to them may still exist
// when deleteBlock() is called.
bool deleteBlock(v3s16 blockpos) override;
void deleteDetachedBlocks();
void step();
void updateVManip(v3s16 pos);
// For debug printing
void PrintInfo(std::ostream &out) override;
bool isSavingEnabled(){ return m_map_saving_enabled; }
u64 getSeed();
/*!
* Fixes lighting in one map block.
* May modify other blocks as well, as light can spread
* out of the specified block.
* Returns false if the block is not generated (so nothing
* changed), true otherwise.
*/
bool repairBlockLight(v3s16 blockpos,
std::map<v3s16, MapBlock *> *modified_blocks);
void transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks,
ServerEnvironment *env);
void transformLiquidsLocal(std::map<v3s16, MapBlock*> &modified_blocks, UniqueQueue<v3s16> &liquid_queue,
ServerEnvironment *env, u32 liquid_loop_max);
void transforming_liquid_add(v3s16 p);
MapSettingsManager settings_mgr;
protected:
void reportMetrics(u64 save_time_us, u32 saved_blocks, u32 all_blocks) override;
private:
friend class ModApiMapgen; // for m_transforming_liquid
// extra border area during mapgen (in blocks)
constexpr static v3s16 EMERGE_EXTRA_BORDER{1, 1, 1};
// Emerge manager
EmergeManager *m_emerge;
std::string m_savedir;
bool m_map_saving_enabled;
int m_map_compression_level;
std::set<v3s16> m_chunks_in_progress;
// used by deleteBlock() and deleteDetachedBlocks()
std::vector<std::unique_ptr<MapBlock>> m_detached_blocks;
// Queued transforming water nodes
UniqueQueue<v3s16> m_transforming_liquid;
f32 m_transforming_liquid_loop_count_multiplier = 1.0f;
u32 m_unprocessed_count = 0;
u64 m_inc_trending_up_start_time = 0; // milliseconds
bool m_queue_size_timer_started = false;
/*
Metadata is re-written on disk only if this is true.
This is reset to false when written on disk.
*/
bool m_map_metadata_changed = true;
MapDatabaseAccessor m_db;
// Map metrics
MetricGaugePtr m_loaded_blocks_gauge;
MetricCounterPtr m_save_time_counter;
MetricCounterPtr m_save_count_counter;
};