forked from Mirrorlandia_minetest/minetest
Add ability to delete MapBlocks from map
Also add a Lua API and chatcommand for this
This commit is contained in:
parent
0330cec7ec
commit
9736548720
@ -403,6 +403,46 @@ core.register_chatcommand("set", {
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_chatcommand("deleteblocks", {
|
||||
params = "[here] [<pos1> <pos2>]",
|
||||
description = "delete map blocks contained in area pos1 to pos2",
|
||||
privs = {server=true},
|
||||
func = function(name, param)
|
||||
local p1 = {}
|
||||
local p2 = {}
|
||||
if param == "here" then
|
||||
local player = core.get_player_by_name(name)
|
||||
if player == nil then
|
||||
core.log("error", "player is nil")
|
||||
return false, "Unable to get current position; player is nil"
|
||||
end
|
||||
p1 = player:getpos()
|
||||
p2 = p1
|
||||
else
|
||||
p1.x, p1.y, p1.z, p2.x, p2.y, p2.z = string.match(param,
|
||||
"^%(([%d.-]+), *([%d.-]+), *([%d.-]+)%) *%(([%d.-]+), *([%d.-]+), *([%d.-]+)%)$")
|
||||
p1.x = tonumber(p1.x)
|
||||
p1.y = tonumber(p1.y)
|
||||
p1.z = tonumber(p1.z)
|
||||
p2.x = tonumber(p2.x)
|
||||
p2.y = tonumber(p2.y)
|
||||
p2.z = tonumber(p2.z)
|
||||
|
||||
if p1.x == nil or p1.y == nil or p1.z == nil or
|
||||
p2.x == nil or p2.y == nil or p2.z == nil then
|
||||
return false, "Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)"
|
||||
end
|
||||
end
|
||||
|
||||
if core.delete_area(p1, p2) then
|
||||
return true, "Successfully cleared area ranging from " ..
|
||||
core.pos_to_string(p1) .. " to " .. core.pos_to_string(p2)
|
||||
else
|
||||
return false, "Failed to clear one or more blocks in area"
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_chatcommand("mods", {
|
||||
params = "",
|
||||
description = "List mods installed on the server",
|
||||
|
@ -1880,6 +1880,8 @@ and `minetest.auth_reload` call the authetification handler.
|
||||
* Generate all registered decorations within the VoxelManip specified by `vm`.
|
||||
* `minetest.clear_objects()`
|
||||
* clear all objects in the environments
|
||||
* `minetest.delete_area(pos1, pos2)`
|
||||
* delete all mapblocks in the area from pos1 to pos2, inclusive
|
||||
* `minetest.line_of_sight(pos1, pos2, stepsize)`: returns `boolean, pos`
|
||||
* Check if there is a direct line of sight between `pos1` and `pos2`
|
||||
* Returns the position of the blocking node when `false`
|
||||
|
@ -59,6 +59,11 @@ std::string Database_Dummy::loadBlock(v3s16 blockpos)
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Database_Dummy::deleteBlock(v3s16 blockpos)
|
||||
{
|
||||
m_database.erase(getBlockAsInteger(blockpos));
|
||||
}
|
||||
|
||||
void Database_Dummy::listAllLoadableBlocks(std::list<v3s16> &dst)
|
||||
{
|
||||
for(std::map<u64, std::string>::iterator x = m_database.begin(); x != m_database.end(); ++x)
|
||||
|
@ -35,6 +35,7 @@ public:
|
||||
virtual void endSave();
|
||||
virtual bool saveBlock(v3s16 blockpos, std::string &data);
|
||||
virtual std::string loadBlock(v3s16 blockpos);
|
||||
virtual bool deleteBlock(v3s16 blockpos);
|
||||
virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
|
||||
virtual int Initialized(void);
|
||||
~Database_Dummy();
|
||||
|
@ -80,6 +80,19 @@ std::string Database_LevelDB::loadBlock(v3s16 blockpos)
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Database_LevelDB::deleteBlock(v3s16 blockpos)
|
||||
{
|
||||
leveldb::Status status = m_database->Delete(leveldb::WriteOptions(),
|
||||
i64tos(getBlockAsInteger(blockpos)));
|
||||
if (!status.ok()) {
|
||||
errorstream << "WARNING: deleteBlock: LevelDB error deleting block "
|
||||
<< PP(blockpos) << ": " << status.ToString() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Database_LevelDB::listAllLoadableBlocks(std::list<v3s16> &dst)
|
||||
{
|
||||
leveldb::Iterator* it = m_database->NewIterator(leveldb::ReadOptions());
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
virtual void endSave();
|
||||
virtual bool saveBlock(v3s16 blockpos, std::string &data);
|
||||
virtual std::string loadBlock(v3s16 blockpos);
|
||||
virtual bool deleteBlock(v3s16 blockpos);
|
||||
virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
|
||||
virtual int Initialized(void);
|
||||
~Database_LevelDB();
|
||||
|
@ -123,6 +123,30 @@ std::string Database_Redis::loadBlock(v3s16 blockpos)
|
||||
return str;
|
||||
}
|
||||
|
||||
bool Database_Redis::deleteBlock(v3s16 blockpos)
|
||||
{
|
||||
std::string tmp = i64tos(getBlockAsInteger(blockpos));
|
||||
|
||||
redisReply *reply = (redisReply *)redisCommand(ctx, "HDEL %s %s",
|
||||
hash.c_str(), tmp.c_str());
|
||||
if (!reply) {
|
||||
errorstream << "WARNING: deleteBlock: redis command 'HDEL' failed on "
|
||||
"block " << PP(blockpos) << ": " << ctx->errstr << std::endl;
|
||||
freeReplyObject(reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reply->type == REDIS_REPLY_ERROR) {
|
||||
errorstream << "WARNING: deleteBlock: deleting block " << PP(blockpos)
|
||||
<< "failed" << std::endl;
|
||||
freeReplyObject(reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
freeReplyObject(reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Database_Redis::listAllLoadableBlocks(std::list<v3s16> &dst)
|
||||
{
|
||||
redisReply *reply;
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
virtual void endSave();
|
||||
virtual bool saveBlock(v3s16 blockpos, std::string &data);
|
||||
virtual std::string loadBlock(v3s16 blockpos);
|
||||
virtual bool deleteBlock(v3s16 blockpos);
|
||||
virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
|
||||
virtual int Initialized(void);
|
||||
~Database_Redis();
|
||||
|
@ -131,13 +131,11 @@ void Database_SQLite3::verifyDatabase() {
|
||||
throw FileNotGoodException("Cannot prepare write statement");
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
d = sqlite3_prepare(m_database, "DELETE FROM `blocks` WHERE `pos`=?;", -1, &m_database_delete, NULL);
|
||||
if(d != SQLITE_OK) {
|
||||
infostream<<"WARNING: SQLite3 database delete statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
|
||||
throw FileNotGoodException("Cannot prepare delete statement");
|
||||
}
|
||||
#endif
|
||||
|
||||
d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
|
||||
if(d != SQLITE_OK) {
|
||||
@ -148,22 +146,48 @@ void Database_SQLite3::verifyDatabase() {
|
||||
infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
|
||||
}
|
||||
|
||||
bool Database_SQLite3::deleteBlock(v3s16 blockpos)
|
||||
{
|
||||
verifyDatabase();
|
||||
|
||||
if (sqlite3_bind_int64(m_database_delete, 1,
|
||||
getBlockAsInteger(blockpos)) != SQLITE_OK) {
|
||||
errorstream << "WARNING: Could not bind block position for delete: "
|
||||
<< sqlite3_errmsg(m_database) << std::endl;
|
||||
}
|
||||
|
||||
if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
|
||||
errorstream << "WARNING: deleteBlock: Block failed to delete "
|
||||
<< PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
|
||||
sqlite3_reset(m_database_delete);
|
||||
return false;
|
||||
}
|
||||
|
||||
sqlite3_reset(m_database_delete);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
|
||||
{
|
||||
verifyDatabase();
|
||||
|
||||
s64 bkey = getBlockAsInteger(blockpos);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
/**
|
||||
* Note: For some unknown reason sqlite3 fails to REPLACE blocks on android,
|
||||
* deleting them and inserting first works.
|
||||
*/
|
||||
if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
|
||||
if (sqlite3_bind_int64(m_database_read, 1, bkey) != SQLITE_OK) {
|
||||
infostream << "WARNING: Could not bind block position for load: "
|
||||
<< sqlite3_errmsg(m_database)<<std::endl;
|
||||
}
|
||||
|
||||
if (sqlite3_step(m_database_read) == SQLITE_ROW) {
|
||||
if (sqlite3_bind_int64(m_database_delete, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
|
||||
int step_result = sqlite3_step(m_database_read);
|
||||
sqlite3_reset(m_database_read);
|
||||
|
||||
if (step_result == SQLITE_ROW) {
|
||||
if (sqlite3_bind_int64(m_database_delete, 1, bkey) != SQLITE_OK) {
|
||||
infostream << "WARNING: Could not bind block position for delete: "
|
||||
<< sqlite3_errmsg(m_database)<<std::endl;
|
||||
}
|
||||
@ -175,17 +199,17 @@ bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
|
||||
}
|
||||
sqlite3_reset(m_database_delete);
|
||||
}
|
||||
sqlite3_reset(m_database_read);
|
||||
#endif
|
||||
|
||||
if (sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
|
||||
if (sqlite3_bind_int64(m_database_write, 1, bkey) != SQLITE_OK) {
|
||||
errorstream << "WARNING: saveBlock: Block position failed to bind: "
|
||||
<< PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
|
||||
sqlite3_reset(m_database_write);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sqlite3_bind_blob(m_database_write, 2, (void *) data.c_str(), data.size(), NULL) != SQLITE_OK) {
|
||||
if (sqlite3_bind_blob(m_database_write, 2, (void *)data.c_str(),
|
||||
data.size(), NULL) != SQLITE_OK) {
|
||||
errorstream << "WARNING: saveBlock: Block data failed to bind: "
|
||||
<< PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
|
||||
sqlite3_reset(m_database_write);
|
||||
@ -277,6 +301,7 @@ Database_SQLite3::~Database_SQLite3()
|
||||
FINALIZE_STATEMENT(m_database_read)
|
||||
FINALIZE_STATEMENT(m_database_write)
|
||||
FINALIZE_STATEMENT(m_database_list)
|
||||
FINALIZE_STATEMENT(m_database_delete)
|
||||
|
||||
if(m_database)
|
||||
rc = sqlite3_close(m_database);
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
|
||||
virtual bool saveBlock(v3s16 blockpos, std::string &data);
|
||||
virtual std::string loadBlock(v3s16 blockpos);
|
||||
virtual bool deleteBlock(v3s16 blockpos);
|
||||
virtual void listAllLoadableBlocks(std::list<v3s16> &dst);
|
||||
virtual int Initialized(void);
|
||||
~Database_SQLite3();
|
||||
@ -47,9 +48,7 @@ private:
|
||||
sqlite3 *m_database;
|
||||
sqlite3_stmt *m_database_read;
|
||||
sqlite3_stmt *m_database_write;
|
||||
#ifdef __ANDROID__
|
||||
sqlite3_stmt *m_database_delete;
|
||||
#endif
|
||||
sqlite3_stmt *m_database_list;
|
||||
|
||||
// Create the database structure
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
|
||||
virtual bool saveBlock(v3s16 blockpos, std::string &data) = 0;
|
||||
virtual std::string loadBlock(v3s16 blockpos) = 0;
|
||||
virtual bool deleteBlock(v3s16 blockpos) = 0;
|
||||
s64 getBlockAsInteger(const v3s16 pos) const;
|
||||
v3s16 getIntegerAsBlock(s64 i) const;
|
||||
virtual void listAllLoadableBlocks(std::list<v3s16> &dst) = 0;
|
||||
|
17
src/map.cpp
17
src/map.cpp
@ -3588,6 +3588,23 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
|
||||
return getBlockNoCreateNoEx(blockpos);
|
||||
}
|
||||
|
||||
bool ServerMap::deleteBlock(v3s16 blockpos)
|
||||
{
|
||||
if (!dbase->deleteBlock(blockpos))
|
||||
return false;
|
||||
|
||||
MapBlock *block = getBlockNoCreateNoEx(blockpos);
|
||||
if (block) {
|
||||
v2s16 p2d(blockpos.X, blockpos.Z);
|
||||
MapSector *sector = getSectorNoGenerateNoEx(p2d);
|
||||
if (!sector)
|
||||
return false;
|
||||
sector->deleteBlock(block);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServerMap::PrintInfo(std::ostream &out)
|
||||
{
|
||||
out<<"ServerMap: ";
|
||||
|
@ -267,9 +267,10 @@ public:
|
||||
|
||||
virtual void save(ModifiedState save_level){assert(0);};
|
||||
|
||||
// Server implements this.
|
||||
// Client leaves it as no-op.
|
||||
// Server implements these.
|
||||
// Client leaves them as no-op.
|
||||
virtual bool saveBlock(MapBlock *block) { return false; };
|
||||
virtual bool deleteBlock(v3s16 blockpos) { return false; };
|
||||
|
||||
/*
|
||||
Updates usage timers and unloads unused blocks and sectors.
|
||||
@ -423,7 +424,7 @@ public:
|
||||
- Create blank filled with CONTENT_IGNORE
|
||||
|
||||
*/
|
||||
MapBlock * emergeBlock(v3s16 p, bool create_blank=true);
|
||||
MapBlock *emergeBlock(v3s16 p, bool create_blank=true);
|
||||
|
||||
/*
|
||||
Try to get a block.
|
||||
@ -498,6 +499,8 @@ public:
|
||||
// Database version
|
||||
void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false);
|
||||
|
||||
bool deleteBlock(v3s16 blockpos);
|
||||
|
||||
void updateVManip(v3s16 pos);
|
||||
|
||||
// For debug printing
|
||||
|
@ -657,7 +657,8 @@ int ModApiEnvMod::l_clear_objects(lua_State *L)
|
||||
}
|
||||
|
||||
// line_of_sight(pos1, pos2, stepsize) -> true/false, pos
|
||||
int ModApiEnvMod::l_line_of_sight(lua_State *L) {
|
||||
int ModApiEnvMod::l_line_of_sight(lua_State *L)
|
||||
{
|
||||
float stepsize = 1.0;
|
||||
|
||||
GET_ENV_PTR;
|
||||
@ -681,6 +682,37 @@ int ModApiEnvMod::l_line_of_sight(lua_State *L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// delete_area(p1, p2)
|
||||
// delete mapblocks in area p1..p2
|
||||
int ModApiEnvMod::l_delete_area(lua_State *L)
|
||||
{
|
||||
GET_ENV_PTR;
|
||||
|
||||
v3s16 bpmin = getNodeBlockPos(read_v3s16(L, 1));
|
||||
v3s16 bpmax = getNodeBlockPos(read_v3s16(L, 2));
|
||||
sortBoxVerticies(bpmin, bpmax);
|
||||
|
||||
ServerMap &map = env->getServerMap();
|
||||
|
||||
MapEditEvent event;
|
||||
event.type = MEET_OTHER;
|
||||
|
||||
bool success = true;
|
||||
for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
|
||||
for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
|
||||
for (s16 x = bpmin.X; x <= bpmax.X; x++) {
|
||||
v3s16 bp(x, y, z);
|
||||
if (map.deleteBlock(bp))
|
||||
event.modified_blocks.insert(bp);
|
||||
else
|
||||
success = false;
|
||||
}
|
||||
|
||||
map.dispatchEvent(&event);
|
||||
lua_pushboolean(L, success);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// find_path(pos1, pos2, searchdistance,
|
||||
// max_jump, max_drop, algorithm) -> table containing path
|
||||
int ModApiEnvMod::l_find_path(lua_State *L)
|
||||
@ -849,6 +881,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
|
||||
API_FCT(get_gametime);
|
||||
API_FCT(find_node_near);
|
||||
API_FCT(find_nodes_in_area);
|
||||
API_FCT(delete_area);
|
||||
API_FCT(get_perlin);
|
||||
API_FCT(get_perlin_map);
|
||||
API_FCT(get_voxel_manip);
|
||||
|
@ -119,6 +119,9 @@ private:
|
||||
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
|
||||
static int l_find_nodes_in_area(lua_State *L);
|
||||
|
||||
// delete_area(p1, p2) -> true/false
|
||||
static int l_delete_area(lua_State *L);
|
||||
|
||||
// get_perlin(seeddiff, octaves, persistence, scale)
|
||||
// returns world-specific PerlinNoise
|
||||
static int l_get_perlin(lua_State *L);
|
||||
|
Loading…
Reference in New Issue
Block a user