Permalink
Browse files

Experimental-ish rollback functionality

  • Loading branch information...
1 parent 0c91a0d commit 0190f9b077dcb2b8cb41c622dd91ffc1e04dacac @celeron55 committed Jul 26, 2012
View
@@ -496,3 +496,75 @@ minetest.register_chatcommand("pulverize", {
end,
})
+-- Key = player name
+minetest.rollback_punch_callbacks = {}
+
+minetest.register_on_punchnode(function(pos, node, puncher)
+ local name = puncher:get_player_name()
+ if minetest.rollback_punch_callbacks[name] then
+ minetest.rollback_punch_callbacks[name](pos, node, puncher)
+ minetest.rollback_punch_callbacks[name] = nil
+ end
+end)
+
+minetest.register_chatcommand("rollback_check", {
+ params = "[<range>] [<seconds>]",
+ description = "check who has last touched a node or near it, "..
+ "max. <seconds> ago (default range=0, seconds=86400=24h)",
+ privs = {rollback=true},
+ func = function(name, param)
+ local range, seconds = string.match(param, "(%d+) *(%d*)")
+ range = tonumber(range) or 0
+ seconds = tonumber(seconds) or 86400
+ minetest.chat_send_player(name, "Punch a node (limits set: range="..
+ dump(range).." seconds="..dump(seconds).."s)")
+ minetest.rollback_punch_callbacks[name] = function(pos, node, puncher)
+ local name = puncher:get_player_name()
+ local actor, act_p, act_seconds =
+ minetest.rollback_get_last_node_actor(pos, range, seconds)
+ if actor == "" then
+ minetest.chat_send_player(name, "Nobody has touched the "..
+ "specified location in "..dump(seconds).." seconds")
+ return
+ end
+ local nodedesc = "this node"
+ if act_p.x ~= pos.x or act_p.y ~= pos.y or act_p.z ~= pos.z then
+ nodedesc = minetest.pos_to_string(act_p)
+ end
+ minetest.chat_send_player(name, "Last actor on "..nodedesc.." was "..
+ actor..", "..dump(act_seconds).."s ago")
+ end
+ end,
+})
+
+minetest.register_chatcommand("rollback", {
+ params = "<player name> [<seconds>] | :liquid [<seconds>]",
+ description = "revert actions of a player; default for <seconds> is 60",
+ privs = {rollback=true},
+ func = function(name, param)
+ local target_name, seconds = string.match(param, ":([^ ]+) *(%d*)")
+ if not target_name then
+ local player_name = nil;
+ player_name, seconds = string.match(param, "([^ ]+) *(%d*)")
+ if not player_name then
+ minetest.chat_send_player(name, "Invalid parameters. See /help rollback and /help rollback_check")
+ return
+ end
+ target_name = "player:"..player_name
+ end
+ seconds = tonumber(seconds) or 60
+ minetest.chat_send_player(name, "Reverting actions of "..
+ dump(target_name).." since "..dump(seconds).." seconds.")
+ local success, log = minetest.rollback_revert_actions_by(
+ target_name, seconds)
+ for _,line in ipairs(log) do
+ minetest.chat_send_player(name, line)
+ end
+ if success then
+ minetest.chat_send_player(name, "Reverting actions succeeded.")
+ else
+ minetest.chat_send_player(name, "Reverting actions FAILED.")
+ end
+ end,
+})
+
View
@@ -44,5 +44,5 @@ minetest.register_privilege("fast", {
description = "Can walk fast using the fast_move mode",
give_to_singleplayer = false,
})
-
+minetest.register_privilege("rollback", "Can use the rollback functionality")
View
@@ -889,6 +889,14 @@ minetest.get_craft_recipe(output) -> input
stack 5, stack 6, stack 7, stack 8, stack 9 }
^ input.items = nil if no recipe found
+Rollbacks:
+minetest.rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
+^ Find who has done something to a node, or near a node
+^ actor: "player:<name>", also "liquid".
+minetest.rollback_revert_actions_by(actor, seconds) -> bool, log messages
+^ Revert latest actions of someone
+^ actor: "player:<name>", also "liquid".
+
Defaults for the on_* item definition functions:
(These return the leftover itemstack)
minetest.item_place_node(itemstack, placer, pointed_thing)
View
@@ -153,6 +153,8 @@ configure_file(
)
set(common_SRCS
+ rollback_interface.cpp
+ rollback.cpp
genericobject.cpp
voxelalgorithms.cpp
sound.cpp
View
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "mapblock.h" // For getNodeBlockPos
#include "mapgen.h" // For mapgen::make_tree
+#include "map.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
View
@@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h" // For IntervalLimiter
#include "util/serialize.h"
#include "util/mathconstants.h"
+#include "map.h"
class Settings;
struct ToolCapabilities;
View
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "environment.h"
#include "gamedef.h"
#include "log.h"
+#include "map.h"
static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
float txs, float tys, int col, int row)
View
@@ -349,6 +349,17 @@ ServerEnvironment::~ServerEnvironment()
}
}
+Map & ServerEnvironment::getMap()
+{
+ return *m_map;
+}
+
+ServerMap & ServerEnvironment::getServerMap()
+{
+ return *m_map;
+}
+
+
void ServerEnvironment::serializePlayers(const std::string &savedir)
{
std::string players_path = savedir + "/players";
View
@@ -33,11 +33,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <set>
#include "irrlichttypes_extrabloated.h"
#include "player.h"
-#include "map.h"
#include <ostream>
#include "activeobject.h"
#include "util/container.h"
#include "util/numeric.h"
+#include "mapnode.h"
+#include "mapblock.h"
class Server;
class ServerEnvironment;
@@ -46,6 +47,8 @@ class ServerActiveObject;
typedef struct lua_State lua_State;
class ITextureSource;
class IGameDef;
+class Map;
+class ServerMap;
class ClientMap;
class Environment
@@ -191,11 +194,9 @@ class ServerEnvironment : public Environment
IBackgroundBlockEmerger *emerger);
~ServerEnvironment();
- Map & getMap()
- { return *m_map; }
+ Map & getMap();
- ServerMap & getServerMap()
- { return *m_map; }
+ ServerMap & getServerMap();
lua_State* getLua()
{ return m_lua; }
View
@@ -29,6 +29,7 @@ class ICraftDefManager;
class ITextureSource;
class ISoundManager;
class MtEventManager;
+class IRollbackReportSink;
/*
An interface for fetching game-global definitions like tool and
@@ -54,6 +55,10 @@ class IGameDef
// Only usable on the client
virtual ISoundManager* getSoundManager()=0;
virtual MtEventManager* getEventManager()=0;
+
+ // Only usable on the server, and NOT thread-safe. It is usable from the
+ // environment thread.
+ virtual IRollbackReportSink* getRollbackReportSink(){return NULL;}
// Used on the client
virtual bool checkLocalPrivilege(const std::string &priv)
@@ -66,6 +71,7 @@ class IGameDef
ITextureSource* tsrc(){return getTextureSource();}
ISoundManager* sound(){return getSoundManager();}
MtEventManager* event(){return getEventManager();}
+ IRollbackReportSink* rollback(){return getRollbackReportSink();}
};
#endif
View
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // for g_settings
#include "settings.h"
#include "craftdef.h"
+#include "rollback_interface.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@@ -200,6 +201,14 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
}
/*
+ Do not handle rollback if both inventories are that of the same player
+ */
+ bool ignore_rollback = (
+ from_inv.type == InventoryLocation::PLAYER &&
+ to_inv.type == InventoryLocation::PLAYER &&
+ from_inv.name == to_inv.name);
+
+ /*
Collect information of endpoints
*/
@@ -344,6 +353,41 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
<<std::endl;
/*
+ Record rollback information
+ */
+ if(!ignore_rollback)
+ {
+ IRollbackReportSink *rollback = gamedef->rollback();
+
+ // If source is not infinite, record item take
+ if(!src_can_take_count != -1){
+ RollbackAction action;
+ std::string loc;
+ {
+ std::ostringstream os(std::ios::binary);
+ from_inv.serialize(os);
+ loc = os.str();
+ }
+ action.setModifyInventoryStack(loc, from_list, from_i, false,
+ src_item.getItemString());
+ rollback->reportAction(action);
+ }
+ // If destination is not infinite, record item put
+ if(!dst_can_put_count != -1){
+ RollbackAction action;
+ std::string loc;
+ {
+ std::ostringstream os(std::ios::binary);
+ to_inv.serialize(os);
+ loc = os.str();
+ }
+ action.setModifyInventoryStack(loc, to_list, to_i, true,
+ src_item.getItemString());
+ rollback->reportAction(action);
+ }
+ }
+
+ /*
Report move to endpoints
*/
@@ -405,7 +449,7 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
L, from_inv.p, from_list, from_i, src_item, player);
}
}
-
+
mgr->setInventoryModified(from_inv);
if(inv_from != inv_to)
mgr->setInventoryModified(to_inv);
@@ -489,6 +533,11 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
}
/*
+ Do not handle rollback if inventory is player's
+ */
+ bool ignore_src_rollback = (from_inv.type == InventoryLocation::PLAYER);
+
+ /*
Collect information of endpoints
*/
@@ -575,6 +624,28 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
scriptapi_nodemeta_inventory_on_take(
L, from_inv.p, from_list, from_i, src_item, player);
}
+
+ /*
+ Record rollback information
+ */
+ if(!ignore_src_rollback)
+ {
+ IRollbackReportSink *rollback = gamedef->rollback();
+
+ // If source is not infinite, record item take
+ if(!src_can_take_count != -1){
+ RollbackAction action;
+ std::string loc;
+ {
+ std::ostringstream os(std::ios::binary);
+ from_inv.serialize(os);
+ loc = os.str();
+ }
+ action.setModifyInventoryStack(loc, from_list, from_i,
+ false, src_item.getItemString());
+ rollback->reportAction(action);
+ }
+ }
}
void IDropAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
Oops, something went wrong.

0 comments on commit 0190f9b

Please sign in to comment.