aboutsummaryrefslogtreecommitdiff
path: root/builtin/common/chatcommands.lua
blob: 52edda659baab0a89ede36a09b6c45faf6877641 (plain)
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
-- Minetest: builtin/common/chatcommands.lua

core.registered_chatcommands = {}

function core.register_chatcommand(cmd, def)
	def = def or {}
	def.params = def.params or ""
	def.description = def.description or ""
	def.privs = def.privs or {}
	def.mod_origin = core.get_current_modname() or "??"
	core.registered_chatcommands[cmd] = def
end

function core.unregister_chatcommand(name)
	if core.registered_chatcommands[name] then
		core.registered_chatcommands[name] = nil
	else
		core.log("warning", "Not unregistering chatcommand " ..name..
			" because it doesn't exist.")
	end
end

function core.override_chatcommand(name, redefinition)
	local chatcommand = core.registered_chatcommands[name]
	assert(chatcommand, "Attempt to override non-existent chatcommand "..name)
	for k, v in pairs(redefinition) do
		rawset(chatcommand, k, v)
	end
	core.registered_chatcommands[name] = chatcommand
end

local cmd_marker = "/"

local function gettext(...)
	return ...
end

local function gettext_replace(text, replace)
	return text:gsub("$1", replace)
end


if INIT == "client" then
	cmd_marker = "."
	gettext = core.gettext
	gettext_replace = fgettext_ne
end

local function do_help_cmd(name, param)
	local function format_help_line(cmd, def)
		local msg = core.colorize("#00ffff", cmd_marker .. cmd)
		if def.params and def.params ~= "" then
			msg = msg .. " " .. def.params
		end
		if def.description and def.description ~= "" then
			msg = msg .. ": " .. def.description
		end
		return msg
	end
	if param == "" then
		local cmds = {}
		for cmd, def in pairs(core.registered_chatcommands) do
			if INIT == "client" or core.check_player_privs(name, def.privs) then
				cmds[#cmds + 1] = cmd
			end
		end
		table.sort(cmds)
		return true, gettext("Available commands: ") .. table.concat(cmds, " ") .. "\n"
				.. gettext_replace("Use '$1help <cmd>' to get more information,"
				.. " or '$1help all' to list everything.", cmd_marker)
	elseif param == "all" then
		local cmds = {}
		for cmd, def in pairs(core.registered_chatcommands) do
			if INIT == "client" or core.check_player_privs(name, def.privs) then
				cmds[#cmds + 1] = format_help_line(cmd, def)
			end
		end
		table.sort(cmds)
		return true, gettext("Available commands:").."\n"..table.concat(cmds, "\n")
	elseif INIT == "game" and param == "privs" then
		local privs = {}
		for priv, def in pairs(core.registered_privileges) do
			privs[#privs + 1] = priv .. ": " .. def.description
		end
		table.sort(privs)
		return true, "Available privileges:\n"..table.concat(privs, "\n")
	else
		local cmd = param
		local def = core.registered_chatcommands[cmd]
		if not def then
			return false, gettext("Command not available: ")..cmd
		else
			return true, format_help_line(cmd, def)
		end
	end
end

if INIT == "client" then
	core.register_chatcommand("help", {
		params = gettext("[all | <cmd>]"),
		description = gettext("Get help for commands"),
		func = function(param)
			return do_help_cmd(nil, param)
		end,
	})
else
	core.register_chatcommand("help", {
		params = "[all | privs | <cmd>]",
		description = "Get help for commands or list privileges",
		func = do_help_cmd,
	})
end
// Returned pointer must be deleted // Returns NULL if queue is empty QueuedMeshUpdate * pop(); u32 size() { JMutexAutoLock lock(m_mutex); return m_queue.size(); } private: std::vector<QueuedMeshUpdate*> m_queue; std::set<v3s16> m_urgents; JMutex m_mutex; }; struct MeshUpdateResult { v3s16 p; MapBlockMesh *mesh; bool ack_block_to_server; MeshUpdateResult(): p(-1338,-1338,-1338), mesh(NULL), ack_block_to_server(false) { } }; class MeshUpdateThread : public SimpleThread { public: MeshUpdateThread(IGameDef *gamedef): m_gamedef(gamedef) { } void * Thread(); MeshUpdateQueue m_queue_in; MutexedQueue<MeshUpdateResult> m_queue_out; IGameDef *m_gamedef; }; enum ClientEventType { CE_NONE, CE_PLAYER_DAMAGE, CE_PLAYER_FORCE_MOVE, CE_DEATHSCREEN, CE_TEXTURES_UPDATED }; struct ClientEvent { ClientEventType type; union{ struct{ } none; struct{ u8 amount; } player_damage; struct{ f32 pitch; f32 yaw; } player_force_move; struct{ bool set_camera_point_target; f32 camera_point_target_x; f32 camera_point_target_y; f32 camera_point_target_z; } deathscreen; struct{ } textures_updated; }; }; class Client : public con::PeerHandler, public InventoryManager, public IGameDef { public: /* NOTE: Nothing is thread-safe here. */ Client( IrrlichtDevice *device, const char *playername, std::string password, MapDrawControl &control, IWritableTextureSource *tsrc, IWritableShaderSource *shsrc, IWritableItemDefManager *itemdef, IWritableNodeDefManager *nodedef, ISoundManager *sound, MtEventManager *event ); ~Client(); /* The name of the local player should already be set when calling this, as it is sent in the initialization. */ void connect(Address address); /* returns true when m_con.Connected() == true AND m_server_ser_ver != SER_FMT_VER_INVALID throws con::PeerNotFoundException if connection has been deleted, eg. timed out. */ bool connectedAndInitialized(); /* Stuff that references the environment is valid only as long as this is not called. (eg. Players) If this throws a PeerNotFoundException, the connection has timed out. */ void step(float dtime); void ProcessData(u8 *data, u32 datasize, u16 sender_peer_id); // Returns true if something was received bool AsyncProcessPacket(); bool AsyncProcessData(); void Send(u16 channelnum, SharedBuffer<u8> data, bool reliable); void interact(u8 action, const PointedThing& pointed); void sendNodemetaFields(v3s16 p, const std::string &formname, const std::map<std::string, std::string> &fields); void sendInventoryFields(const std::string &formname, const std::map<std::string, std::string> &fields); void sendInventoryAction(InventoryAction *a); void sendChatMessage(const std::wstring &message); void sendChangePassword(const std::wstring oldpassword, const std::wstring newpassword); void sendDamage(u8 damage); void sendRespawn(); ClientEnvironment& getEnv() { return m_env; } // Causes urgent mesh updates (unlike Map::add/removeNodeWithEvent) void removeNode(v3s16 p); void addNode(v3s16 p, MapNode n); void setPlayerControl(PlayerControl &control); void selectPlayerItem(u16 item); u16 getPlayerItem() const { return m_playeritem; } // Returns true if the inventory of the local player has been // updated from the server. If it is true, it is set to false. bool getLocalInventoryUpdated(); // Copies the inventory of the local player to parameter void getLocalInventory(Inventory &dst); /* InventoryManager interface */ Inventory* getInventory(const InventoryLocation &loc); void inventoryAction(InventoryAction *a); // Gets closest object pointed by the shootline // Returns NULL if not found ClientActiveObject * getSelectedActiveObject( f32 max_d, v3f from_pos_f_on_map, core::line3d<f32> shootline_on_map ); // Prints a line or two of info void printDebugInfo(std::ostream &os); core::list<std::wstring> getConnectedPlayerNames(); float getAnimationTime(); int getCrackLevel(); void setCrack(int level, v3s16 pos); u16 getHP(); bool checkPrivilege(const std::string &priv) { return (m_privileges.count(priv) != 0); } bool getChatMessage(std::wstring &message); void typeChatMessage(const std::wstring& message); u64 getMapSeed(){ return m_map_seed; } void addUpdateMeshTask(v3s16 blockpos, bool ack_to_server=false, bool urgent=false); // Including blocks at appropriate edges void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false, bool urgent=false); void addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server=false, bool urgent=false); // Get event from queue. CE_NONE is returned if queue is empty. ClientEvent getClientEvent(); bool accessDenied() { return m_access_denied; } std::wstring accessDeniedReason() { return m_access_denied_reason; } float mediaReceiveProgress() { return m_media_receive_progress; } bool texturesReceived() { return m_media_received; } bool itemdefReceived() { return m_itemdef_received; } bool nodedefReceived() { return m_nodedef_received; } void afterContentReceived(); float getRTT(void); // IGameDef interface virtual IItemDefManager* getItemDefManager(); virtual INodeDefManager* getNodeDefManager(); virtual ICraftDefManager* getCraftDefManager(); virtual ITextureSource* getTextureSource(); virtual IShaderSource* getShaderSource(); virtual u16 allocateUnknownNodeId(const std::string &name); virtual ISoundManager* getSoundManager(); virtual MtEventManager* getEventManager(); virtual bool checkLocalPrivilege(const std::string &priv) { return checkPrivilege(priv); } private: // Insert a media file appropriately into the appropriate manager bool loadMedia(const std::string &data, const std::string &filename); // Virtual methods from con::PeerHandler void peerAdded(con::Peer *peer); void deletingPeer(con::Peer *peer, bool timeout); void ReceiveAll(); void Receive(); void sendPlayerPos(); // This sends the player's current name etc to the server void sendPlayerInfo(); // Send the item number 'item' as player item to the server void sendPlayerItem(u16 item); float m_packetcounter_timer; float m_connection_reinit_timer; float m_avg_rtt_timer; float m_playerpos_send_timer; float m_ignore_damage_timer; // Used after server moves player IntervalLimiter m_map_timer_and_unload_interval; IWritableTextureSource *m_tsrc; IWritableShaderSource *m_shsrc; IWritableItemDefManager *m_itemdef; IWritableNodeDefManager *m_nodedef; ISoundManager *m_sound; MtEventManager *m_event; MeshUpdateThread m_mesh_update_thread; ClientEnvironment m_env; con::Connection m_con; IrrlichtDevice *m_device; // Server serialization version u8 m_server_ser_ver; u16 m_playeritem; bool m_inventory_updated; Inventory *m_inventory_from_server; float m_inventory_from_server_age; core::map<v3s16, bool> m_active_blocks; PacketCounter m_packetcounter; // Block mesh animation parameters float m_animation_time; int m_crack_level; v3s16 m_crack_pos; // 0 <= m_daynight_i < DAYNIGHT_CACHE_COUNT //s32 m_daynight_i; //u32 m_daynight_ratio; Queue<std::wstring> m_chat_queue; // The seed returned by the server in TOCLIENT_INIT is stored here u64 m_map_seed; std::string m_password; bool m_access_denied; std::wstring m_access_denied_reason; Queue<ClientEvent> m_client_event_queue; FileCache m_media_cache; // Mapping from media file name to SHA1 checksum core::map<std::string, std::string> m_media_name_sha1_map; float m_media_receive_progress; bool m_media_received; bool m_itemdef_received; bool m_nodedef_received; friend class FarMesh; // time_of_day speed approximation for old protocol bool m_time_of_day_set; float m_last_time_of_day_f; float m_time_of_day_update_timer; // An interval for generally sending object positions and stuff float m_recommended_send_interval; // Sounds float m_removed_sounds_check_timer; // Mapping from server sound ids to our sound ids std::map<s32, int> m_sounds_server_to_client; // And the other way! std::map<int, s32> m_sounds_client_to_server; // And relations to objects std::map<int, u16> m_sounds_to_objects; // Privileges std::set<std::string> m_privileges; // Detached inventories // key = name std::map<std::string, Inventory*> m_detached_inventories; }; #endif // !CLIENT_HEADER