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",
* 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`
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)
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();
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());
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();
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;
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();
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) {
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;
}
}
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);
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);
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();
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
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;
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: ";
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.
- 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.
// 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
}
// 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;
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)
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);
// remove_node(pos)
// pos = {x=num, y=num, z=num}
static int l_remove_node(lua_State *L);
-
+
// swap_node(pos, node)
// pos = {x=num, y=num, z=num}
static int l_swap_node(lua_State *L);
// 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);
// get_perlin_map(noiseparams, size)
// returns world-specific PerlinNoiseMap
static int l_get_perlin_map(lua_State *L);
-
+
// get_voxel_manip()
// returns world-specific voxel manipulator
static int l_get_voxel_manip(lua_State *L);
-
+
// clear_objects()
// clear all objects in the environment
static int l_clear_objects(lua_State *L);
// forceload_block(blockpos)
// forceloads a block
static int l_forceload_block(lua_State *L);
-
+
// forceload_free_block(blockpos)
// stops forceloading a position
static int l_forceload_free_block(lua_State *L);
-
+
// get us precision time
static int l_get_us_time(lua_State *L);