forked from Mirrorlandia_minetest/minetest
Implement mod communication channels (#6351)
Implement network communication for channels * Implement ModChannel manager server side to route incoming messages from clients to other clients * Add signal handler switch on client & ModChannelMgr on client to handle channels * Add Lua API bindings + client packet sending + unittests * Implement server message sending * Add callback from received message handler to Lua API using registration method
This commit is contained in:
parent
6df312a608
commit
6f1c907204
@ -71,3 +71,5 @@ core.registered_on_dignode, core.register_on_dignode = make_registration()
|
|||||||
core.registered_on_punchnode, core.register_on_punchnode = make_registration()
|
core.registered_on_punchnode, core.register_on_punchnode = make_registration()
|
||||||
core.registered_on_placenode, core.register_on_placenode = make_registration()
|
core.registered_on_placenode, core.register_on_placenode = make_registration()
|
||||||
core.registered_on_item_use, core.register_on_item_use = make_registration()
|
core.registered_on_item_use, core.register_on_item_use = make_registration()
|
||||||
|
core.registered_on_modchannel_message, core.register_on_modchannel_message = make_registration()
|
||||||
|
core.registered_on_modchannel_signal, core.register_on_modchannel_signal = make_registration()
|
||||||
|
@ -583,6 +583,7 @@ core.registered_on_punchplayers, core.register_on_punchplayer = make_registratio
|
|||||||
core.registered_on_priv_grant, core.register_on_priv_grant = make_registration()
|
core.registered_on_priv_grant, core.register_on_priv_grant = make_registration()
|
||||||
core.registered_on_priv_revoke, core.register_on_priv_revoke = make_registration()
|
core.registered_on_priv_revoke, core.register_on_priv_revoke = make_registration()
|
||||||
core.registered_can_bypass_userlimit, core.register_can_bypass_userlimit = make_registration()
|
core.registered_can_bypass_userlimit, core.register_can_bypass_userlimit = make_registration()
|
||||||
|
core.registered_on_modchannel_message, core.register_on_modchannel_message = make_registration()
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Compatibility for on_mapgen_init()
|
-- Compatibility for on_mapgen_init()
|
||||||
|
@ -928,6 +928,9 @@ player_transfer_distance (Player transfer distance) int 0
|
|||||||
# Whether to allow players to damage and kill each other.
|
# Whether to allow players to damage and kill each other.
|
||||||
enable_pvp (Player versus Player) bool true
|
enable_pvp (Player versus Player) bool true
|
||||||
|
|
||||||
|
# Enable mod channels support.
|
||||||
|
enable_mod_channels (Mod channels) bool false
|
||||||
|
|
||||||
# If this is set, players will always (re)spawn at the given position.
|
# If this is set, players will always (re)spawn at the given position.
|
||||||
static_spawnpoint (Static spawnpoint) string
|
static_spawnpoint (Static spawnpoint) string
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
local modname = core.get_current_modname() or "??"
|
local modname = core.get_current_modname() or "??"
|
||||||
local modstorage = core.get_mod_storage()
|
local modstorage = core.get_mod_storage()
|
||||||
|
local mod_channel
|
||||||
|
|
||||||
dofile("preview:example.lua")
|
dofile("preview:example.lua")
|
||||||
-- This is an example function to ensure it's working properly, should be removed before merge
|
-- This is an example function to ensure it's working properly, should be removed before merge
|
||||||
@ -14,6 +15,21 @@ core.register_on_connect(function()
|
|||||||
print("Server ip: " .. server_info.ip)
|
print("Server ip: " .. server_info.ip)
|
||||||
print("Server address: " .. server_info.address)
|
print("Server address: " .. server_info.address)
|
||||||
print("Server port: " .. server_info.port)
|
print("Server port: " .. server_info.port)
|
||||||
|
|
||||||
|
mod_channel = core.mod_channel_join("experimental_preview")
|
||||||
|
end)
|
||||||
|
|
||||||
|
core.register_on_modchannel_message(function(channel, sender, message)
|
||||||
|
print("[PREVIEW][modchannels] Received message `" .. message .. "` on channel `"
|
||||||
|
.. channel .. "` from sender `" .. sender .. "`")
|
||||||
|
core.after(1, function()
|
||||||
|
mod_channel:send_all("CSM preview received " .. message)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
core.register_on_modchannel_signal(function(channel, signal)
|
||||||
|
print("[PREVIEW][modchannels] Received signal id `" .. signal .. "` on channel `"
|
||||||
|
.. channel)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
core.register_on_placenode(function(pointed_thing, node)
|
core.register_on_placenode(function(pointed_thing, node)
|
||||||
@ -100,6 +116,12 @@ core.after(2, function()
|
|||||||
preview_minimap()
|
preview_minimap()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
core.after(4, function()
|
||||||
|
if mod_channel:is_writeable() then
|
||||||
|
mod_channel:send_all("preview talk to experimental")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
core.after(5, function()
|
core.after(5, function()
|
||||||
if core.ui.minimap then
|
if core.ui.minimap then
|
||||||
core.ui.minimap:show()
|
core.ui.minimap:show()
|
||||||
|
@ -683,6 +683,12 @@ Call these functions only at load time!
|
|||||||
* Called when the local player uses an item.
|
* Called when the local player uses an item.
|
||||||
* Newest functions are called first.
|
* Newest functions are called first.
|
||||||
* If any function returns true, the item use is not sent to server.
|
* If any function returns true, the item use is not sent to server.
|
||||||
|
* `minetest.register_on_modchannel_message(func(channel_name, sender, message))`
|
||||||
|
* Called when an incoming mod channel message is received
|
||||||
|
* You must have joined some channels before, and server must acknowledge the
|
||||||
|
join request.
|
||||||
|
* If message comes from a server mod, `sender` field is an empty string.
|
||||||
|
|
||||||
### Sounds
|
### Sounds
|
||||||
* `minetest.sound_play(spec, parameters)`: returns a handle
|
* `minetest.sound_play(spec, parameters)`: returns a handle
|
||||||
* `spec` is a `SimpleSoundSpec`
|
* `spec` is a `SimpleSoundSpec`
|
||||||
@ -754,6 +760,16 @@ Call these functions only at load time!
|
|||||||
* returns reference to mod private `StorageRef`
|
* returns reference to mod private `StorageRef`
|
||||||
* must be called during mod load time
|
* must be called during mod load time
|
||||||
|
|
||||||
|
### Mod channels
|
||||||
|
![Mod channels communication scheme](docs/mod channels.png)
|
||||||
|
|
||||||
|
* `minetest.mod_channel_join(channel_name)`
|
||||||
|
* Client joins channel `channel_name`, and creates it, if necessary. You
|
||||||
|
should listen from incoming messages with `minetest.register_on_modchannel_message`
|
||||||
|
call to receive incoming messages. Warning, this function is asynchronous.
|
||||||
|
* You should use a minetest.register_on_connect(function() ... end) to perform
|
||||||
|
a successful channel join on client startup.
|
||||||
|
|
||||||
### Misc.
|
### Misc.
|
||||||
* `minetest.parse_json(string[, nullvalue])`: returns something
|
* `minetest.parse_json(string[, nullvalue])`: returns something
|
||||||
* Convert a string containing JSON data into the Lua equivalent
|
* Convert a string containing JSON data into the Lua equivalent
|
||||||
@ -827,9 +843,25 @@ Call these functions only at load time!
|
|||||||
Class reference
|
Class reference
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
### ModChannel
|
||||||
|
|
||||||
|
An interface to use mod channels on client and server
|
||||||
|
|
||||||
|
#### Methods
|
||||||
|
* `leave()`: leave the mod channel.
|
||||||
|
* Client leaves channel `channel_name`.
|
||||||
|
* No more incoming or outgoing messages can be sent to this channel from client mods.
|
||||||
|
* This invalidate all future object usage
|
||||||
|
* Ensure your set mod_channel to nil after that to free Lua resources
|
||||||
|
* `is_writeable()`: returns true if channel is writeable and mod can send over it.
|
||||||
|
* `send_all(message)`: Send `message` though the mod channel.
|
||||||
|
* If mod channel is not writeable or invalid, message will be dropped.
|
||||||
|
* Message size is limited to 65535 characters by protocol.
|
||||||
|
|
||||||
### Minimap
|
### Minimap
|
||||||
An interface to manipulate minimap on client UI
|
An interface to manipulate minimap on client UI
|
||||||
|
|
||||||
|
#### Methods
|
||||||
* `show()`: shows the minimap (if not disabled by server)
|
* `show()`: shows the minimap (if not disabled by server)
|
||||||
* `hide()`: hides the minimap
|
* `hide()`: hides the minimap
|
||||||
* `set_pos(pos)`: sets the minimap position on screen
|
* `set_pos(pos)`: sets the minimap position on screen
|
||||||
|
@ -2496,6 +2496,20 @@ Call these functions only at load time!
|
|||||||
* `minetest.register_can_bypass_userlimit(function(name, ip))`
|
* `minetest.register_can_bypass_userlimit(function(name, ip))`
|
||||||
* Called when `name` user connects with `ip`.
|
* Called when `name` user connects with `ip`.
|
||||||
* Return `true` to by pass the player limit
|
* Return `true` to by pass the player limit
|
||||||
|
* `minetest.register_on_modchannel_message(func(channel_name, sender, message))`
|
||||||
|
* Called when an incoming mod channel message is received
|
||||||
|
* You should have joined some channels to receive events.
|
||||||
|
* If message comes from a server mod, `sender` field is an empty string.
|
||||||
|
* `minetest.register_on_modchannel_signal(func(channel_name, signal))`
|
||||||
|
* Called when a valid incoming mod channel signal is received
|
||||||
|
* Signal id permit to react to server mod channel events
|
||||||
|
* Possible values are:
|
||||||
|
0: join_ok
|
||||||
|
1: join_failed
|
||||||
|
2: leave_ok
|
||||||
|
3: leave_failed
|
||||||
|
4: event_on_not_joined_channel
|
||||||
|
5: state_changed
|
||||||
|
|
||||||
### Other registration functions
|
### Other registration functions
|
||||||
* `minetest.register_chatcommand(cmd, chatcommand definition)`
|
* `minetest.register_chatcommand(cmd, chatcommand definition)`
|
||||||
@ -2773,6 +2787,14 @@ and `minetest.auth_reload` call the authetification handler.
|
|||||||
* spread these updates to neighbours and can cause a cascade
|
* spread these updates to neighbours and can cause a cascade
|
||||||
of nodes to fall.
|
of nodes to fall.
|
||||||
|
|
||||||
|
### Mod channels
|
||||||
|
You can find mod channels communication scheme in `docs/mod_channels.png`.
|
||||||
|
|
||||||
|
* `minetest.mod_channel_join(channel_name)`
|
||||||
|
* Server joins channel `channel_name`, and creates it if necessary. You
|
||||||
|
should listen from incoming messages with `minetest.register_on_modchannel_message`
|
||||||
|
call to receive incoming messages
|
||||||
|
|
||||||
### Inventory
|
### Inventory
|
||||||
`minetest.get_inventory(location)`: returns an `InvRef`
|
`minetest.get_inventory(location)`: returns an `InvRef`
|
||||||
|
|
||||||
@ -3256,6 +3278,21 @@ These functions return the leftover itemstack.
|
|||||||
Class reference
|
Class reference
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
### ModChannel
|
||||||
|
|
||||||
|
An interface to use mod channels on client and server
|
||||||
|
|
||||||
|
#### Methods
|
||||||
|
* `leave()`: leave the mod channel.
|
||||||
|
* Server leaves channel `channel_name`.
|
||||||
|
* No more incoming or outgoing messages can be sent to this channel from server mods.
|
||||||
|
* This invalidate all future object usage
|
||||||
|
* Ensure your set mod_channel to nil after that to free Lua resources
|
||||||
|
* `is_writeable()`: returns true if channel is writeable and mod can send over it.
|
||||||
|
* `send_all(message)`: Send `message` though the mod channel.
|
||||||
|
* If mod channel is not writeable or invalid, message will be dropped.
|
||||||
|
* Message size is limited to 65535 characters by protocol.
|
||||||
|
|
||||||
### `MetaDataRef`
|
### `MetaDataRef`
|
||||||
See `StorageRef`, `NodeMetaRef` and `ItemStackMetaRef`.
|
See `StorageRef`, `NodeMetaRef` and `ItemStackMetaRef`.
|
||||||
|
|
||||||
|
BIN
doc/mod_channels.png
Normal file
BIN
doc/mod_channels.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 341 KiB |
@ -2,6 +2,8 @@
|
|||||||
-- Experimental things
|
-- Experimental things
|
||||||
--
|
--
|
||||||
|
|
||||||
|
dofile(minetest.get_modpath("experimental").."/modchannels.lua")
|
||||||
|
|
||||||
-- For testing random stuff
|
-- For testing random stuff
|
||||||
|
|
||||||
experimental = {}
|
experimental = {}
|
||||||
|
16
games/minimal/mods/experimental/modchannels.lua
Normal file
16
games/minimal/mods/experimental/modchannels.lua
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
--
|
||||||
|
-- Mod channels experimental handlers
|
||||||
|
--
|
||||||
|
local mod_channel = core.mod_channel_join("experimental_preview")
|
||||||
|
|
||||||
|
core.register_on_modchannel_message(function(channel, sender, message)
|
||||||
|
print("[minimal][modchannels] Server received message `" .. message
|
||||||
|
.. "` on channel `" .. channel .. "` from sender `" .. sender .. "`")
|
||||||
|
|
||||||
|
if mod_channel:is_writeable() then
|
||||||
|
mod_channel:send_all("experimental answers to preview")
|
||||||
|
mod_channel:leave()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
print("[minimal][modchannels] Code loaded!")
|
@ -1126,6 +1126,10 @@
|
|||||||
# type: bool
|
# type: bool
|
||||||
# enable_pvp = true
|
# enable_pvp = true
|
||||||
|
|
||||||
|
# Enable mod channels.
|
||||||
|
# type: bool
|
||||||
|
# enable_mod_channels = false
|
||||||
|
|
||||||
# If this is set, players will always (re)spawn at the given position.
|
# If this is set, players will always (re)spawn at the given position.
|
||||||
# type: string
|
# type: string
|
||||||
# static_spawnpoint =
|
# static_spawnpoint =
|
||||||
|
@ -420,6 +420,7 @@ set(common_SRCS
|
|||||||
mg_decoration.cpp
|
mg_decoration.cpp
|
||||||
mg_ore.cpp
|
mg_ore.cpp
|
||||||
mg_schematic.cpp
|
mg_schematic.cpp
|
||||||
|
modchannels.cpp
|
||||||
mods.cpp
|
mods.cpp
|
||||||
nameidmapping.cpp
|
nameidmapping.cpp
|
||||||
nodedef.cpp
|
nodedef.cpp
|
||||||
|
@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "mapblock_mesh.h"
|
#include "mapblock_mesh.h"
|
||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
#include "minimap.h"
|
#include "minimap.h"
|
||||||
|
#include "modchannels.h"
|
||||||
#include "mods.h"
|
#include "mods.h"
|
||||||
#include "profiler.h"
|
#include "profiler.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
@ -94,7 +95,8 @@ Client::Client(
|
|||||||
m_chosen_auth_mech(AUTH_MECHANISM_NONE),
|
m_chosen_auth_mech(AUTH_MECHANISM_NONE),
|
||||||
m_media_downloader(new ClientMediaDownloader()),
|
m_media_downloader(new ClientMediaDownloader()),
|
||||||
m_state(LC_Created),
|
m_state(LC_Created),
|
||||||
m_game_ui_flags(game_ui_flags)
|
m_game_ui_flags(game_ui_flags),
|
||||||
|
m_modchannel_mgr(new ModChannelMgr())
|
||||||
{
|
{
|
||||||
// Add local player
|
// Add local player
|
||||||
m_env.setLocalPlayer(new LocalPlayer(this, playername));
|
m_env.setLocalPlayer(new LocalPlayer(this, playername));
|
||||||
@ -1919,3 +1921,57 @@ std::string Client::getModStoragePath() const
|
|||||||
{
|
{
|
||||||
return porting::path_user + DIR_DELIM + "client" + DIR_DELIM + "mod_storage";
|
return porting::path_user + DIR_DELIM + "client" + DIR_DELIM + "mod_storage";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mod channels
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool Client::joinModChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
if (m_modchannel_mgr->channelRegistered(channel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
NetworkPacket pkt(TOSERVER_MODCHANNEL_JOIN, 2 + channel.size());
|
||||||
|
pkt << channel;
|
||||||
|
Send(&pkt);
|
||||||
|
|
||||||
|
m_modchannel_mgr->joinChannel(channel, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Client::leaveModChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
if (!m_modchannel_mgr->channelRegistered(channel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
NetworkPacket pkt(TOSERVER_MODCHANNEL_LEAVE, 2 + channel.size());
|
||||||
|
pkt << channel;
|
||||||
|
Send(&pkt);
|
||||||
|
|
||||||
|
m_modchannel_mgr->leaveChannel(channel, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Client::sendModChannelMessage(const std::string &channel, const std::string &message)
|
||||||
|
{
|
||||||
|
if (!m_modchannel_mgr->canWriteOnChannel(channel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (message.size() > STRING_MAX_LEN) {
|
||||||
|
warningstream << "ModChannel message too long, dropping before sending "
|
||||||
|
<< " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
|
||||||
|
<< channel << ")" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO: do some client rate limiting
|
||||||
|
NetworkPacket pkt(TOSERVER_MODCHANNEL_MSG, 2 + channel.size() + 2 + message.size());
|
||||||
|
pkt << channel << message;
|
||||||
|
Send(&pkt);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModChannel* Client::getModChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
return m_modchannel_mgr->getModChannel(channel);
|
||||||
|
}
|
||||||
|
10
src/client.h
10
src/client.h
@ -52,6 +52,7 @@ class IWritableNodeDefManager;
|
|||||||
//class IWritableCraftDefManager;
|
//class IWritableCraftDefManager;
|
||||||
class ClientMediaDownloader;
|
class ClientMediaDownloader;
|
||||||
struct MapDrawControl;
|
struct MapDrawControl;
|
||||||
|
class ModChannelMgr;
|
||||||
class MtEventManager;
|
class MtEventManager;
|
||||||
struct PointedThing;
|
struct PointedThing;
|
||||||
class MapDatabase;
|
class MapDatabase;
|
||||||
@ -224,6 +225,8 @@ public:
|
|||||||
void handleCommand_LocalPlayerAnimations(NetworkPacket* pkt);
|
void handleCommand_LocalPlayerAnimations(NetworkPacket* pkt);
|
||||||
void handleCommand_EyeOffset(NetworkPacket* pkt);
|
void handleCommand_EyeOffset(NetworkPacket* pkt);
|
||||||
void handleCommand_UpdatePlayerList(NetworkPacket* pkt);
|
void handleCommand_UpdatePlayerList(NetworkPacket* pkt);
|
||||||
|
void handleCommand_ModChannelMsg(NetworkPacket *pkt);
|
||||||
|
void handleCommand_ModChannelSignal(NetworkPacket *pkt);
|
||||||
void handleCommand_SrpBytesSandB(NetworkPacket* pkt);
|
void handleCommand_SrpBytesSandB(NetworkPacket* pkt);
|
||||||
void handleCommand_CSMFlavourLimits(NetworkPacket *pkt);
|
void handleCommand_CSMFlavourLimits(NetworkPacket *pkt);
|
||||||
|
|
||||||
@ -424,6 +427,11 @@ public:
|
|||||||
return m_csm_noderange_limit;
|
return m_csm_noderange_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool joinModChannel(const std::string &channel);
|
||||||
|
bool leaveModChannel(const std::string &channel);
|
||||||
|
bool sendModChannelMessage(const std::string &channel, const std::string &message);
|
||||||
|
ModChannel *getModChannel(const std::string &channel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Virtual methods from con::PeerHandler
|
// Virtual methods from con::PeerHandler
|
||||||
@ -580,4 +588,6 @@ private:
|
|||||||
// CSM flavour limits byteflag
|
// CSM flavour limits byteflag
|
||||||
u64 m_csm_flavour_limits = CSMFlavourLimit::CSM_FL_NONE;
|
u64 m_csm_flavour_limits = CSMFlavourLimit::CSM_FL_NONE;
|
||||||
u32 m_csm_noderange_limit = 8;
|
u32 m_csm_noderange_limit = 8;
|
||||||
|
|
||||||
|
std::unique_ptr<ModChannelMgr> m_modchannel_mgr;
|
||||||
};
|
};
|
||||||
|
@ -300,6 +300,7 @@ void set_default_settings(Settings *settings)
|
|||||||
settings->setDefault("default_password", "");
|
settings->setDefault("default_password", "");
|
||||||
settings->setDefault("default_privs", "interact, shout");
|
settings->setDefault("default_privs", "interact, shout");
|
||||||
settings->setDefault("enable_pvp", "true");
|
settings->setDefault("enable_pvp", "true");
|
||||||
|
settings->setDefault("enable_mod_channels", "false");
|
||||||
settings->setDefault("disallow_empty_password", "false");
|
settings->setDefault("disallow_empty_password", "false");
|
||||||
settings->setDefault("disable_anticheat", "false");
|
settings->setDefault("disable_anticheat", "false");
|
||||||
settings->setDefault("enable_rollback_recording", "false");
|
settings->setDefault("enable_rollback_recording", "false");
|
||||||
|
@ -33,6 +33,7 @@ class MtEventManager;
|
|||||||
class IRollbackManager;
|
class IRollbackManager;
|
||||||
class EmergeManager;
|
class EmergeManager;
|
||||||
class Camera;
|
class Camera;
|
||||||
|
class ModChannel;
|
||||||
class ModMetadata;
|
class ModMetadata;
|
||||||
|
|
||||||
namespace irr { namespace scene {
|
namespace irr { namespace scene {
|
||||||
@ -78,4 +79,10 @@ public:
|
|||||||
virtual std::string getModStoragePath() const = 0;
|
virtual std::string getModStoragePath() const = 0;
|
||||||
virtual bool registerModStorage(ModMetadata *storage) = 0;
|
virtual bool registerModStorage(ModMetadata *storage) = 0;
|
||||||
virtual void unregisterModStorage(const std::string &name) = 0;
|
virtual void unregisterModStorage(const std::string &name) = 0;
|
||||||
|
|
||||||
|
virtual bool joinModChannel(const std::string &channel) = 0;
|
||||||
|
virtual bool leaveModChannel(const std::string &channel) = 0;
|
||||||
|
virtual bool sendModChannelMessage(const std::string &channel,
|
||||||
|
const std::string &message) = 0;
|
||||||
|
virtual ModChannel *getModChannel(const std::string &channel) = 0;
|
||||||
};
|
};
|
||||||
|
152
src/modchannels.cpp
Normal file
152
src/modchannels.cpp
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "modchannels.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include "util/basic_macros.h"
|
||||||
|
|
||||||
|
bool ModChannel::registerConsumer(u16 peer_id)
|
||||||
|
{
|
||||||
|
|
||||||
|
// ignore if peer_id already joined
|
||||||
|
if (CONTAINS(m_client_consumers, peer_id))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_client_consumers.push_back(peer_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModChannel::removeConsumer(u16 peer_id)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
auto peer_removal_fct = [peer_id, &found](u16 p) {
|
||||||
|
if (p == peer_id)
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
return p == peer_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
m_client_consumers.erase(
|
||||||
|
std::remove_if(m_client_consumers.begin(),
|
||||||
|
m_client_consumers.end(), peer_removal_fct),
|
||||||
|
m_client_consumers.end());
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModChannel::canWrite() const
|
||||||
|
{
|
||||||
|
return m_state == MODCHANNEL_STATE_READ_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModChannel::setState(ModChannelState state)
|
||||||
|
{
|
||||||
|
assert(state != MODCHANNEL_STATE_INIT);
|
||||||
|
|
||||||
|
m_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModChannelMgr::channelRegistered(const std::string &channel) const
|
||||||
|
{
|
||||||
|
return m_registered_channels.find(channel) != m_registered_channels.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModChannel *ModChannelMgr::getModChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
if (!channelRegistered(channel))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return m_registered_channels[channel].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModChannelMgr::canWriteOnChannel(const std::string &channel) const
|
||||||
|
{
|
||||||
|
const auto channel_it = m_registered_channels.find(channel);
|
||||||
|
if (channel_it == m_registered_channels.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel_it->second->canWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModChannelMgr::registerChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
m_registered_channels[channel] =
|
||||||
|
std::unique_ptr<ModChannel>(new ModChannel(channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModChannelMgr::setChannelState(const std::string &channel, ModChannelState state)
|
||||||
|
{
|
||||||
|
if (!channelRegistered(channel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto channel_it = m_registered_channels.find(channel);
|
||||||
|
channel_it->second->setState(state);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModChannelMgr::removeChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
if (!channelRegistered(channel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_registered_channels.erase(channel);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModChannelMgr::joinChannel(const std::string &channel, u16 peer_id)
|
||||||
|
{
|
||||||
|
if (!channelRegistered(channel))
|
||||||
|
registerChannel(channel);
|
||||||
|
|
||||||
|
return m_registered_channels[channel]->registerConsumer(peer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModChannelMgr::leaveChannel(const std::string &channel, u16 peer_id)
|
||||||
|
{
|
||||||
|
if (!channelRegistered(channel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Remove consumer from channel
|
||||||
|
bool consumerRemoved = m_registered_channels[channel]->removeConsumer(peer_id);
|
||||||
|
|
||||||
|
// If channel is empty, remove it
|
||||||
|
if (m_registered_channels[channel]->getChannelPeers().empty()) {
|
||||||
|
removeChannel(channel);
|
||||||
|
}
|
||||||
|
return consumerRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModChannelMgr::leaveAllChannels(u16 peer_id)
|
||||||
|
{
|
||||||
|
for (auto &channel_it : m_registered_channels)
|
||||||
|
channel_it.second->removeConsumer(peer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<u16> empty_channel_list;
|
||||||
|
const std::vector<u16> &ModChannelMgr::getChannelPeers(const std::string &channel) const
|
||||||
|
{
|
||||||
|
const auto &channel_it = m_registered_channels.find(channel);
|
||||||
|
if (channel_it == m_registered_channels.end())
|
||||||
|
return empty_channel_list;
|
||||||
|
|
||||||
|
return channel_it->second->getChannelPeers();
|
||||||
|
}
|
92
src/modchannels.h
Normal file
92
src/modchannels.h
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include "irrlichttypes.h"
|
||||||
|
|
||||||
|
enum ModChannelState : u8
|
||||||
|
{
|
||||||
|
MODCHANNEL_STATE_INIT,
|
||||||
|
MODCHANNEL_STATE_READ_WRITE,
|
||||||
|
MODCHANNEL_STATE_READ_ONLY,
|
||||||
|
MODCHANNEL_STATE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModChannel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModChannel(const std::string &name) : m_name(name) {}
|
||||||
|
~ModChannel() = default;
|
||||||
|
|
||||||
|
const std::string &getName() const { return m_name; }
|
||||||
|
bool registerConsumer(u16 peer_id);
|
||||||
|
bool removeConsumer(u16 peer_id);
|
||||||
|
const std::vector<u16> &getChannelPeers() const { return m_client_consumers; }
|
||||||
|
bool canWrite() const;
|
||||||
|
void setState(ModChannelState state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
ModChannelState m_state = MODCHANNEL_STATE_INIT;
|
||||||
|
std::vector<u16> m_client_consumers;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ModChannelSignal : u8
|
||||||
|
{
|
||||||
|
MODCHANNEL_SIGNAL_JOIN_OK,
|
||||||
|
MODCHANNEL_SIGNAL_JOIN_FAILURE,
|
||||||
|
MODCHANNEL_SIGNAL_LEAVE_OK,
|
||||||
|
MODCHANNEL_SIGNAL_LEAVE_FAILURE,
|
||||||
|
MODCHANNEL_SIGNAL_CHANNEL_NOT_REGISTERED,
|
||||||
|
MODCHANNEL_SIGNAL_SET_STATE,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModChannelMgr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModChannelMgr() = default;
|
||||||
|
~ModChannelMgr() = default;
|
||||||
|
|
||||||
|
void registerChannel(const std::string &channel);
|
||||||
|
bool setChannelState(const std::string &channel, ModChannelState state);
|
||||||
|
bool joinChannel(const std::string &channel, u16 peer_id);
|
||||||
|
bool leaveChannel(const std::string &channel, u16 peer_id);
|
||||||
|
bool channelRegistered(const std::string &channel) const;
|
||||||
|
ModChannel *getModChannel(const std::string &channel);
|
||||||
|
/**
|
||||||
|
* This function check if a local mod can write on the channel
|
||||||
|
*
|
||||||
|
* @param channel
|
||||||
|
* @return true if write is allowed
|
||||||
|
*/
|
||||||
|
bool canWriteOnChannel(const std::string &channel) const;
|
||||||
|
void leaveAllChannels(u16 peer_id);
|
||||||
|
const std::vector<u16> &getChannelPeers(const std::string &channel) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool removeChannel(const std::string &channel);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<ModChannel>>
|
||||||
|
m_registered_channels;
|
||||||
|
};
|
@ -111,8 +111,8 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
|
|||||||
{ "TOCLIENT_CLOUD_PARAMS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CloudParams }, // 0x54
|
{ "TOCLIENT_CLOUD_PARAMS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CloudParams }, // 0x54
|
||||||
{ "TOCLIENT_FADE_SOUND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FadeSound }, // 0x55
|
{ "TOCLIENT_FADE_SOUND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FadeSound }, // 0x55
|
||||||
{ "TOCLIENT_UPDATE_PLAYER_LIST", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_UpdatePlayerList }, // 0x56
|
{ "TOCLIENT_UPDATE_PLAYER_LIST", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_UpdatePlayerList }, // 0x56
|
||||||
null_command_handler,
|
{ "TOCLIENT_MODCHANNEL_MSG", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_ModChannelMsg }, // 0x57
|
||||||
null_command_handler,
|
{ "TOCLIENT_MODCHANNEL_SIGNAL", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_ModChannelSignal }, // 0x58
|
||||||
null_command_handler,
|
null_command_handler,
|
||||||
null_command_handler,
|
null_command_handler,
|
||||||
null_command_handler,
|
null_command_handler,
|
||||||
@ -150,9 +150,9 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] =
|
|||||||
null_command_factory, // 0x14
|
null_command_factory, // 0x14
|
||||||
null_command_factory, // 0x15
|
null_command_factory, // 0x15
|
||||||
null_command_factory, // 0x16
|
null_command_factory, // 0x16
|
||||||
null_command_factory, // 0x17
|
{ "TOSERVER_MODCHANNEL_JOIN", 0, true }, // 0x17
|
||||||
null_command_factory, // 0x18
|
{ "TOSERVER_MODCHANNEL_LEAVE", 0, true }, // 0x18
|
||||||
null_command_factory, // 0x19
|
{ "TOSERVER_MODCHANNEL_MSG", 0, true }, // 0x19
|
||||||
null_command_factory, // 0x1a
|
null_command_factory, // 0x1a
|
||||||
null_command_factory, // 0x1b
|
null_command_factory, // 0x1b
|
||||||
null_command_factory, // 0x1c
|
null_command_factory, // 0x1c
|
||||||
|
@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "mapsector.h"
|
#include "mapsector.h"
|
||||||
#include "minimap.h"
|
#include "minimap.h"
|
||||||
|
#include "modchannels.h"
|
||||||
#include "nodedef.h"
|
#include "nodedef.h"
|
||||||
#include "serialization.h"
|
#include "serialization.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
@ -1330,3 +1331,95 @@ void Client::handleCommand_CSMFlavourLimits(NetworkPacket *pkt)
|
|||||||
{
|
{
|
||||||
*pkt >> m_csm_flavour_limits >> m_csm_noderange_limit;
|
*pkt >> m_csm_flavour_limits >> m_csm_noderange_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mod channels
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Client::handleCommand_ModChannelMsg(NetworkPacket *pkt)
|
||||||
|
{
|
||||||
|
std::string channel_name, sender, channel_msg;
|
||||||
|
*pkt >> channel_name >> sender >> channel_msg;
|
||||||
|
|
||||||
|
verbosestream << "Mod channel message received from server " << pkt->getPeerId()
|
||||||
|
<< " on channel " << channel_name << ". sender: `" << sender << "`, message: "
|
||||||
|
<< channel_msg << std::endl;
|
||||||
|
|
||||||
|
if (!m_modchannel_mgr->channelRegistered(channel_name)) {
|
||||||
|
verbosestream << "Server sent us messages on unregistered channel "
|
||||||
|
<< channel_name << ", ignoring." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_script->on_modchannel_message(channel_name, sender, channel_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::handleCommand_ModChannelSignal(NetworkPacket *pkt)
|
||||||
|
{
|
||||||
|
u8 signal_tmp;
|
||||||
|
ModChannelSignal signal;
|
||||||
|
std::string channel;
|
||||||
|
|
||||||
|
*pkt >> signal_tmp >> channel;
|
||||||
|
|
||||||
|
signal = (ModChannelSignal)signal_tmp;
|
||||||
|
|
||||||
|
bool valid_signal = true;
|
||||||
|
// @TODO: send Signal to Lua API
|
||||||
|
switch (signal) {
|
||||||
|
case MODCHANNEL_SIGNAL_JOIN_OK:
|
||||||
|
m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
|
||||||
|
infostream << "Server ack our mod channel join on channel `" << channel
|
||||||
|
<< "`, joining." << std::endl;
|
||||||
|
break;
|
||||||
|
case MODCHANNEL_SIGNAL_JOIN_FAILURE:
|
||||||
|
// Unable to join, remove channel
|
||||||
|
m_modchannel_mgr->leaveChannel(channel, 0);
|
||||||
|
infostream << "Server refused our mod channel join on channel `" << channel
|
||||||
|
<< "`" << std::endl;
|
||||||
|
break;
|
||||||
|
case MODCHANNEL_SIGNAL_LEAVE_OK:
|
||||||
|
#ifndef NDEBUG
|
||||||
|
infostream << "Server ack our mod channel leave on channel " << channel
|
||||||
|
<< "`, leaving." << std::endl;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case MODCHANNEL_SIGNAL_LEAVE_FAILURE:
|
||||||
|
infostream << "Server refused our mod channel leave on channel `" << channel
|
||||||
|
<< "`" << std::endl;
|
||||||
|
break;
|
||||||
|
case MODCHANNEL_SIGNAL_CHANNEL_NOT_REGISTERED:
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Generally unused, but ensure we don't do an implementation error
|
||||||
|
infostream << "Server tells us we sent a message on channel `" << channel
|
||||||
|
<< "` but we are not registered. Message was dropped." << std::endl;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case MODCHANNEL_SIGNAL_SET_STATE: {
|
||||||
|
u8 state;
|
||||||
|
*pkt >> state;
|
||||||
|
|
||||||
|
if (state == MODCHANNEL_STATE_INIT || state >= MODCHANNEL_STATE_MAX) {
|
||||||
|
infostream << "Received wrong channel state " << state
|
||||||
|
<< ", ignoring." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_modchannel_mgr->setChannelState(channel, (ModChannelState) state);
|
||||||
|
infostream << "Server sets mod channel `" << channel
|
||||||
|
<< "` in read-only mode." << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
#ifndef NDEBUG
|
||||||
|
warningstream << "Received unhandled mod channel signal ID "
|
||||||
|
<< signal << ", ignoring." << std::endl;
|
||||||
|
#endif
|
||||||
|
valid_signal = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If signal is valid, forward it to client side mods
|
||||||
|
if (valid_signal)
|
||||||
|
m_script->on_modchannel_signal(channel, signal);
|
||||||
|
}
|
||||||
|
@ -180,6 +180,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
Backwards compatibility drop
|
Backwards compatibility drop
|
||||||
Add 'can_zoom' to player object properties
|
Add 'can_zoom' to player object properties
|
||||||
Add glow to object properties
|
Add glow to object properties
|
||||||
|
Mod channels
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LATEST_PROTOCOL_VERSION 36
|
#define LATEST_PROTOCOL_VERSION 36
|
||||||
@ -611,6 +612,22 @@ enum ToClientCommand
|
|||||||
u8[len] player name
|
u8[len] player name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
TOCLIENT_MODCHANNEL_MSG = 0x57,
|
||||||
|
/*
|
||||||
|
u16 channel name length
|
||||||
|
std::string channel name
|
||||||
|
u16 channel name sender
|
||||||
|
std::string channel name
|
||||||
|
u16 message length
|
||||||
|
std::string message
|
||||||
|
*/
|
||||||
|
TOCLIENT_MODCHANNEL_SIGNAL = 0x58,
|
||||||
|
/*
|
||||||
|
u8 signal id
|
||||||
|
u16 channel name length
|
||||||
|
std::string channel name
|
||||||
|
*/
|
||||||
|
|
||||||
TOCLIENT_SRP_BYTES_S_B = 0x60,
|
TOCLIENT_SRP_BYTES_S_B = 0x60,
|
||||||
/*
|
/*
|
||||||
Belonging to AUTH_MECHANISM_SRP.
|
Belonging to AUTH_MECHANISM_SRP.
|
||||||
@ -645,6 +662,26 @@ enum ToServerCommand
|
|||||||
[0] u16 TOSERVER_INIT2
|
[0] u16 TOSERVER_INIT2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
TOSERVER_MODCHANNEL_JOIN = 0x17,
|
||||||
|
/*
|
||||||
|
u16 channel name length
|
||||||
|
std::string channel name
|
||||||
|
*/
|
||||||
|
|
||||||
|
TOSERVER_MODCHANNEL_LEAVE = 0x18,
|
||||||
|
/*
|
||||||
|
u16 channel name length
|
||||||
|
std::string channel name
|
||||||
|
*/
|
||||||
|
|
||||||
|
TOSERVER_MODCHANNEL_MSG = 0x19,
|
||||||
|
/*
|
||||||
|
u16 channel name length
|
||||||
|
std::string channel name
|
||||||
|
u16 message length
|
||||||
|
std::string message
|
||||||
|
*/
|
||||||
|
|
||||||
TOSERVER_GETBLOCK = 0x20, // Obsolete
|
TOSERVER_GETBLOCK = 0x20, // Obsolete
|
||||||
TOSERVER_ADDNODE = 0x21, // Obsolete
|
TOSERVER_ADDNODE = 0x21, // Obsolete
|
||||||
TOSERVER_REMOVENODE = 0x22, // Obsolete
|
TOSERVER_REMOVENODE = 0x22, // Obsolete
|
||||||
|
@ -47,9 +47,9 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] =
|
|||||||
null_command_handler, // 0x14
|
null_command_handler, // 0x14
|
||||||
null_command_handler, // 0x15
|
null_command_handler, // 0x15
|
||||||
null_command_handler, // 0x16
|
null_command_handler, // 0x16
|
||||||
null_command_handler, // 0x17
|
{ "TOSERVER_MODCHANNEL_JOIN", TOSERVER_STATE_INGAME, &Server::handleCommand_ModChannelJoin }, // 0x17
|
||||||
null_command_handler, // 0x18
|
{ "TOSERVER_MODCHANNEL_LEAVE", TOSERVER_STATE_INGAME, &Server::handleCommand_ModChannelLeave }, // 0x18
|
||||||
null_command_handler, // 0x19
|
{ "TOSERVER_MODCHANNEL_MSG", TOSERVER_STATE_INGAME, &Server::handleCommand_ModChannelMsg }, // 0x19
|
||||||
null_command_handler, // 0x1a
|
null_command_handler, // 0x1a
|
||||||
null_command_handler, // 0x1b
|
null_command_handler, // 0x1b
|
||||||
null_command_handler, // 0x1c
|
null_command_handler, // 0x1c
|
||||||
@ -200,8 +200,8 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
|
|||||||
{ "TOCLIENT_CLOUD_PARAMS", 0, true }, // 0x54
|
{ "TOCLIENT_CLOUD_PARAMS", 0, true }, // 0x54
|
||||||
{ "TOCLIENT_FADE_SOUND", 0, true }, // 0x55
|
{ "TOCLIENT_FADE_SOUND", 0, true }, // 0x55
|
||||||
{ "TOCLIENT_UPDATE_PLAYER_LIST", 0, true }, // 0x56
|
{ "TOCLIENT_UPDATE_PLAYER_LIST", 0, true }, // 0x56
|
||||||
null_command_factory,
|
{ "TOCLIENT_MODCHANNEL_MSG", 0, true}, // 0x57
|
||||||
null_command_factory,
|
{ "TOCLIENT_MODCHANNEL_SIGNAL", 0, true}, // 0x58
|
||||||
null_command_factory,
|
null_command_factory,
|
||||||
null_command_factory,
|
null_command_factory,
|
||||||
null_command_factory,
|
null_command_factory,
|
||||||
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "content_sao.h"
|
#include "content_sao.h"
|
||||||
#include "emerge.h"
|
#include "emerge.h"
|
||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
|
#include "modchannels.h"
|
||||||
#include "nodedef.h"
|
#include "nodedef.h"
|
||||||
#include "remoteplayer.h"
|
#include "remoteplayer.h"
|
||||||
#include "rollback_interface.h"
|
#include "rollback_interface.h"
|
||||||
@ -363,7 +364,7 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt)
|
|||||||
actionstream
|
actionstream
|
||||||
<< "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
|
<< "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
|
||||||
<< peer_id << std::endl;
|
<< peer_id << std::endl;
|
||||||
m_con->DisconnectPeer(peer_id);
|
DisconnectPeer(peer_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,7 +373,7 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt)
|
|||||||
errorstream
|
errorstream
|
||||||
<< "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
|
<< "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
|
||||||
<< peer_id << std::endl;
|
<< peer_id << std::endl;
|
||||||
m_con->DisconnectPeer(peer_id);
|
DisconnectPeer(peer_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,7 +504,7 @@ void Server::handleCommand_PlayerPos(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player for peer_id=" << pkt->getPeerId()
|
"No player for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,7 +513,7 @@ void Server::handleCommand_PlayerPos(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player object for peer_id=" << pkt->getPeerId()
|
"No player object for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,7 +565,7 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player for peer_id=" << pkt->getPeerId()
|
"No player for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,7 +574,7 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player object for peer_id=" << pkt->getPeerId()
|
"No player object for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,7 +746,7 @@ void Server::handleCommand_ChatMessage(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player for peer_id=" << pkt->getPeerId()
|
"No player for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -773,7 +774,7 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player for peer_id=" << pkt->getPeerId()
|
"No player for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -782,7 +783,7 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player object for peer_id=" << pkt->getPeerId()
|
"No player object for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,7 +840,7 @@ void Server::handleCommand_Password(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player for peer_id=" << pkt->getPeerId()
|
"No player for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -892,7 +893,7 @@ void Server::handleCommand_PlayerItem(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player for peer_id=" << pkt->getPeerId()
|
"No player for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -901,7 +902,7 @@ void Server::handleCommand_PlayerItem(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player object for peer_id=" << pkt->getPeerId()
|
"No player object for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -919,7 +920,7 @@ void Server::handleCommand_Respawn(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player for peer_id=" << pkt->getPeerId()
|
"No player for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,7 +973,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player for peer_id=" << pkt->getPeerId()
|
"No player for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -981,7 +982,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player object for peer_id=" << pkt->getPeerId()
|
"No player object for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1411,7 +1412,7 @@ void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player for peer_id=" << pkt->getPeerId()
|
"No player for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1420,7 +1421,7 @@ void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player object for peer_id=" << pkt->getPeerId()
|
"No player object for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1462,7 +1463,7 @@ void Server::handleCommand_InventoryFields(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player for peer_id=" << pkt->getPeerId()
|
"No player for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1471,7 +1472,7 @@ void Server::handleCommand_InventoryFields(NetworkPacket* pkt)
|
|||||||
errorstream << "Server::ProcessData(): Canceling: "
|
errorstream << "Server::ProcessData(): Canceling: "
|
||||||
"No player object for peer_id=" << pkt->getPeerId()
|
"No player object for peer_id=" << pkt->getPeerId()
|
||||||
<< " disconnecting peer!" << std::endl;
|
<< " disconnecting peer!" << std::endl;
|
||||||
m_con->DisconnectPeer(pkt->getPeerId());
|
DisconnectPeer(pkt->getPeerId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1733,3 +1734,81 @@ void Server::handleCommand_SrpBytesM(NetworkPacket* pkt)
|
|||||||
|
|
||||||
acceptAuth(pkt->getPeerId(), wantSudo);
|
acceptAuth(pkt->getPeerId(), wantSudo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mod channels
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Server::handleCommand_ModChannelJoin(NetworkPacket *pkt)
|
||||||
|
{
|
||||||
|
std::string channel_name;
|
||||||
|
*pkt >> channel_name;
|
||||||
|
|
||||||
|
NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_SIGNAL, 1 + 2 + channel_name.size(),
|
||||||
|
pkt->getPeerId());
|
||||||
|
|
||||||
|
// Send signal to client to notify join succeed or not
|
||||||
|
if (g_settings->getBool("enable_mod_channels") &&
|
||||||
|
m_modchannel_mgr->joinChannel(channel_name, pkt->getPeerId())) {
|
||||||
|
resp_pkt << (u8) MODCHANNEL_SIGNAL_JOIN_OK;
|
||||||
|
infostream << "Peer " << pkt->getPeerId() << " joined channel " << channel_name
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resp_pkt << (u8)MODCHANNEL_SIGNAL_JOIN_FAILURE;
|
||||||
|
infostream << "Peer " << pkt->getPeerId() << " tried to join channel "
|
||||||
|
<< channel_name << ", but was already registered." << std::endl;
|
||||||
|
}
|
||||||
|
resp_pkt << channel_name;
|
||||||
|
Send(&resp_pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::handleCommand_ModChannelLeave(NetworkPacket *pkt)
|
||||||
|
{
|
||||||
|
std::string channel_name;
|
||||||
|
*pkt >> channel_name;
|
||||||
|
|
||||||
|
NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_SIGNAL, 1 + 2 + channel_name.size(),
|
||||||
|
pkt->getPeerId());
|
||||||
|
|
||||||
|
// Send signal to client to notify join succeed or not
|
||||||
|
if (g_settings->getBool("enable_mod_channels") &&
|
||||||
|
m_modchannel_mgr->leaveChannel(channel_name, pkt->getPeerId())) {
|
||||||
|
resp_pkt << (u8)MODCHANNEL_SIGNAL_LEAVE_OK;
|
||||||
|
infostream << "Peer " << pkt->getPeerId() << " left channel " << channel_name
|
||||||
|
<< std::endl;
|
||||||
|
} else {
|
||||||
|
resp_pkt << (u8) MODCHANNEL_SIGNAL_LEAVE_FAILURE;
|
||||||
|
infostream << "Peer " << pkt->getPeerId() << " left channel " << channel_name
|
||||||
|
<< ", but was not registered." << std::endl;
|
||||||
|
}
|
||||||
|
resp_pkt << channel_name;
|
||||||
|
Send(&resp_pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::handleCommand_ModChannelMsg(NetworkPacket *pkt)
|
||||||
|
{
|
||||||
|
std::string channel_name, channel_msg;
|
||||||
|
*pkt >> channel_name >> channel_msg;
|
||||||
|
|
||||||
|
verbosestream << "Mod channel message received from peer " << pkt->getPeerId()
|
||||||
|
<< " on channel " << channel_name << " message: " << channel_msg << std::endl;
|
||||||
|
|
||||||
|
// If mod channels are not enabled, discard message
|
||||||
|
if (!g_settings->getBool("enable_mod_channels")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If channel not registered, signal it and ignore message
|
||||||
|
if (!m_modchannel_mgr->channelRegistered(channel_name)) {
|
||||||
|
NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_SIGNAL, 1 + 2 + channel_name.size(),
|
||||||
|
pkt->getPeerId());
|
||||||
|
resp_pkt << (u8)MODCHANNEL_SIGNAL_CHANNEL_NOT_REGISTERED << channel_name;
|
||||||
|
Send(&resp_pkt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO: filter, rate limit
|
||||||
|
|
||||||
|
broadcastModChannelMessage(channel_name, channel_msg, pkt->getPeerId());
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ set(common_SCRIPT_CPP_API_SRCS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_env.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_env.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_inventory.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_inventory.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_item.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_item.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/s_modchannels.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_node.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_node.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_nodemeta.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_nodemeta.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/s_player.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/s_player.cpp
|
||||||
|
50
src/script/cpp_api/s_modchannels.cpp
Normal file
50
src/script/cpp_api/s_modchannels.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "s_modchannels.h"
|
||||||
|
#include "s_internal.h"
|
||||||
|
|
||||||
|
void ScriptApiModChannels::on_modchannel_message(const std::string &channel,
|
||||||
|
const std::string &sender, const std::string &message)
|
||||||
|
{
|
||||||
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
|
// Get core.registered_on_generateds
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
lua_getfield(L, -1, "registered_on_modchannel_message");
|
||||||
|
// Call callbacks
|
||||||
|
lua_pushstring(L, channel.c_str());
|
||||||
|
lua_pushstring(L, sender.c_str());
|
||||||
|
lua_pushstring(L, message.c_str());
|
||||||
|
runCallbacks(3, RUN_CALLBACKS_MODE_AND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptApiModChannels::on_modchannel_signal(
|
||||||
|
const std::string &channel, ModChannelSignal signal)
|
||||||
|
{
|
||||||
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
|
// Get core.registered_on_generateds
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
lua_getfield(L, -1, "registered_on_modchannel_signal");
|
||||||
|
// Call callbacks
|
||||||
|
lua_pushstring(L, channel.c_str());
|
||||||
|
lua_pushinteger(L, (int)signal);
|
||||||
|
runCallbacks(2, RUN_CALLBACKS_MODE_AND);
|
||||||
|
}
|
31
src/script/cpp_api/s_modchannels.h
Normal file
31
src/script/cpp_api/s_modchannels.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cpp_api/s_base.h"
|
||||||
|
#include "modchannels.h"
|
||||||
|
|
||||||
|
class ScriptApiModChannels : virtual public ScriptApiBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void on_modchannel_message(const std::string &channel, const std::string &sender,
|
||||||
|
const std::string &message);
|
||||||
|
void on_modchannel_signal(const std::string &channel, ModChannelSignal signal);
|
||||||
|
};
|
@ -8,6 +8,7 @@ set(common_SCRIPT_LUA_API_SRCS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/l_itemstackmeta.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/l_itemstackmeta.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/l_mapgen.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/l_mapgen.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/l_metadata.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/l_metadata.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/l_modchannels.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/l_nodemeta.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/l_nodemeta.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/l_nodetimer.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/l_nodetimer.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/l_noise.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/l_noise.cpp
|
||||||
|
161
src/script/lua_api/l_modchannels.cpp
Normal file
161
src/script/lua_api/l_modchannels.cpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <log.h>
|
||||||
|
#include "lua_api/l_modchannels.h"
|
||||||
|
#include "l_internal.h"
|
||||||
|
#include "modchannels.h"
|
||||||
|
|
||||||
|
int ModApiChannels::l_mod_channel_join(lua_State *L)
|
||||||
|
{
|
||||||
|
if (!lua_isstring(L, 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
std::string channel = luaL_checkstring(L, 1);
|
||||||
|
if (channel.empty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
getGameDef(L)->joinModChannel(channel);
|
||||||
|
ModChannel *channelObj = getGameDef(L)->getModChannel(channel);
|
||||||
|
assert(channelObj);
|
||||||
|
ModChannelRef::create(L, channelObj);
|
||||||
|
|
||||||
|
int object = lua_gettop(L);
|
||||||
|
lua_pushvalue(L, object);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModApiChannels::Initialize(lua_State *L, int top)
|
||||||
|
{
|
||||||
|
API_FCT(mod_channel_join);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ModChannelRef
|
||||||
|
*/
|
||||||
|
|
||||||
|
ModChannelRef::ModChannelRef(ModChannel *modchannel) : m_modchannel(modchannel)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModChannelRef::l_leave(lua_State *L)
|
||||||
|
{
|
||||||
|
ModChannelRef *ref = checkobject(L, 1);
|
||||||
|
ModChannel *channel = getobject(ref);
|
||||||
|
if (!channel)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
getGameDef(L)->leaveModChannel(channel->getName());
|
||||||
|
// Channel left, invalidate the channel object ptr
|
||||||
|
// This permits to invalidate every object action from Lua because core removed
|
||||||
|
// channel consuming link
|
||||||
|
ref->m_modchannel = nullptr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModChannelRef::l_send_all(lua_State *L)
|
||||||
|
{
|
||||||
|
ModChannelRef *ref = checkobject(L, 1);
|
||||||
|
ModChannel *channel = getobject(ref);
|
||||||
|
if (!channel || !channel->canWrite())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// @TODO serialize message
|
||||||
|
std::string message = luaL_checkstring(L, 2);
|
||||||
|
|
||||||
|
getGameDef(L)->sendModChannelMessage(channel->getName(), message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModChannelRef::l_is_writeable(lua_State *L)
|
||||||
|
{
|
||||||
|
ModChannelRef *ref = checkobject(L, 1);
|
||||||
|
ModChannel *channel = getobject(ref);
|
||||||
|
if (!channel)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
lua_pushboolean(L, channel->canWrite());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void ModChannelRef::Register(lua_State *L)
|
||||||
|
{
|
||||||
|
lua_newtable(L);
|
||||||
|
int methodtable = lua_gettop(L);
|
||||||
|
luaL_newmetatable(L, className);
|
||||||
|
int metatable = lua_gettop(L);
|
||||||
|
|
||||||
|
lua_pushliteral(L, "__metatable");
|
||||||
|
lua_pushvalue(L, methodtable);
|
||||||
|
lua_settable(L, metatable); // hide metatable from lua getmetatable()
|
||||||
|
|
||||||
|
lua_pushliteral(L, "__index");
|
||||||
|
lua_pushvalue(L, methodtable);
|
||||||
|
lua_settable(L, metatable);
|
||||||
|
|
||||||
|
lua_pushliteral(L, "__gc");
|
||||||
|
lua_pushcfunction(L, gc_object);
|
||||||
|
lua_settable(L, metatable);
|
||||||
|
|
||||||
|
lua_pop(L, 1); // Drop metatable
|
||||||
|
|
||||||
|
luaL_openlib(L, 0, methods, 0); // fill methodtable
|
||||||
|
lua_pop(L, 1); // Drop methodtable
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModChannelRef::create(lua_State *L, ModChannel *channel)
|
||||||
|
{
|
||||||
|
ModChannelRef *o = new ModChannelRef(channel);
|
||||||
|
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
|
||||||
|
luaL_getmetatable(L, className);
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModChannelRef::gc_object(lua_State *L)
|
||||||
|
{
|
||||||
|
ModChannelRef *o = *(ModChannelRef **)(lua_touserdata(L, 1));
|
||||||
|
delete o;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModChannelRef *ModChannelRef::checkobject(lua_State *L, int narg)
|
||||||
|
{
|
||||||
|
luaL_checktype(L, narg, LUA_TUSERDATA);
|
||||||
|
|
||||||
|
void *ud = luaL_checkudata(L, narg, className);
|
||||||
|
if (!ud)
|
||||||
|
luaL_typerror(L, narg, className);
|
||||||
|
|
||||||
|
return *(ModChannelRef **)ud; // unbox pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
ModChannel *ModChannelRef::getobject(ModChannelRef *ref)
|
||||||
|
{
|
||||||
|
return ref->m_modchannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
const char ModChannelRef::className[] = "ModChannelRef";
|
||||||
|
const luaL_Reg ModChannelRef::methods[] = {
|
||||||
|
luamethod(ModChannelRef, leave),
|
||||||
|
luamethod(ModChannelRef, is_writeable),
|
||||||
|
luamethod(ModChannelRef, send_all),
|
||||||
|
{0, 0},
|
||||||
|
};
|
||||||
|
// clang-format on
|
66
src/script/lua_api/l_modchannels.h
Normal file
66
src/script/lua_api/l_modchannels.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lua_api/l_base.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
class ModChannel;
|
||||||
|
|
||||||
|
class ModApiChannels : public ModApiBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// mod_channel_join(name)
|
||||||
|
static int l_mod_channel_join(lua_State *L);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void Initialize(lua_State *L, int top);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModChannelRef : public ModApiBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModChannelRef(ModChannel *modchannel);
|
||||||
|
~ModChannelRef() = default;
|
||||||
|
|
||||||
|
static void Register(lua_State *L);
|
||||||
|
static void create(lua_State *L, ModChannel *channel);
|
||||||
|
|
||||||
|
// leave()
|
||||||
|
static int l_leave(lua_State *L);
|
||||||
|
|
||||||
|
// send(message)
|
||||||
|
static int l_send_all(lua_State *L);
|
||||||
|
|
||||||
|
// is_writeable()
|
||||||
|
static int l_is_writeable(lua_State *L);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// garbage collector
|
||||||
|
static int gc_object(lua_State *L);
|
||||||
|
|
||||||
|
static ModChannelRef *checkobject(lua_State *L, int narg);
|
||||||
|
static ModChannel *getobject(ModChannelRef *ref);
|
||||||
|
|
||||||
|
ModChannel *m_modchannel = nullptr;
|
||||||
|
|
||||||
|
static const char className[];
|
||||||
|
static const luaL_Reg methods[];
|
||||||
|
};
|
@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "lua_api/l_client.h"
|
#include "lua_api/l_client.h"
|
||||||
#include "lua_api/l_env.h"
|
#include "lua_api/l_env.h"
|
||||||
#include "lua_api/l_minimap.h"
|
#include "lua_api/l_minimap.h"
|
||||||
|
#include "lua_api/l_modchannels.h"
|
||||||
#include "lua_api/l_storage.h"
|
#include "lua_api/l_storage.h"
|
||||||
#include "lua_api/l_sound.h"
|
#include "lua_api/l_sound.h"
|
||||||
#include "lua_api/l_util.h"
|
#include "lua_api/l_util.h"
|
||||||
@ -72,11 +73,13 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
|
|||||||
NodeMetaRef::RegisterClient(L);
|
NodeMetaRef::RegisterClient(L);
|
||||||
LuaLocalPlayer::Register(L);
|
LuaLocalPlayer::Register(L);
|
||||||
LuaCamera::Register(L);
|
LuaCamera::Register(L);
|
||||||
|
ModChannelRef::Register(L);
|
||||||
|
|
||||||
ModApiUtil::InitializeClient(L, top);
|
ModApiUtil::InitializeClient(L, top);
|
||||||
ModApiClient::Initialize(L, top);
|
ModApiClient::Initialize(L, top);
|
||||||
ModApiStorage::Initialize(L, top);
|
ModApiStorage::Initialize(L, top);
|
||||||
ModApiEnvMod::InitializeClient(L, top);
|
ModApiEnvMod::InitializeClient(L, top);
|
||||||
|
ModApiChannels::Initialize(L, top);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientScripting::on_client_ready(LocalPlayer *localplayer)
|
void ClientScripting::on_client_ready(LocalPlayer *localplayer)
|
||||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "cpp_api/s_base.h"
|
#include "cpp_api/s_base.h"
|
||||||
#include "cpp_api/s_client.h"
|
#include "cpp_api/s_client.h"
|
||||||
|
#include "cpp_api/s_modchannels.h"
|
||||||
#include "cpp_api/s_security.h"
|
#include "cpp_api/s_security.h"
|
||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
@ -30,7 +31,8 @@ class Camera;
|
|||||||
class ClientScripting:
|
class ClientScripting:
|
||||||
virtual public ScriptApiBase,
|
virtual public ScriptApiBase,
|
||||||
public ScriptApiSecurity,
|
public ScriptApiSecurity,
|
||||||
public ScriptApiClient
|
public ScriptApiClient,
|
||||||
|
public ScriptApiModChannels
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClientScripting(Client *client);
|
ClientScripting(Client *client);
|
||||||
|
@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "lua_api/l_item.h"
|
#include "lua_api/l_item.h"
|
||||||
#include "lua_api/l_itemstackmeta.h"
|
#include "lua_api/l_itemstackmeta.h"
|
||||||
#include "lua_api/l_mapgen.h"
|
#include "lua_api/l_mapgen.h"
|
||||||
|
#include "lua_api/l_modchannels.h"
|
||||||
#include "lua_api/l_nodemeta.h"
|
#include "lua_api/l_nodemeta.h"
|
||||||
#include "lua_api/l_nodetimer.h"
|
#include "lua_api/l_nodetimer.h"
|
||||||
#include "lua_api/l_noise.h"
|
#include "lua_api/l_noise.h"
|
||||||
@ -100,6 +101,7 @@ void ServerScripting::InitializeModApi(lua_State *L, int top)
|
|||||||
ObjectRef::Register(L);
|
ObjectRef::Register(L);
|
||||||
LuaSettings::Register(L);
|
LuaSettings::Register(L);
|
||||||
StorageRef::Register(L);
|
StorageRef::Register(L);
|
||||||
|
ModChannelRef::Register(L);
|
||||||
|
|
||||||
// Initialize mod api modules
|
// Initialize mod api modules
|
||||||
ModApiCraft::Initialize(L, top);
|
ModApiCraft::Initialize(L, top);
|
||||||
@ -113,6 +115,7 @@ void ServerScripting::InitializeModApi(lua_State *L, int top)
|
|||||||
ModApiUtil::Initialize(L, top);
|
ModApiUtil::Initialize(L, top);
|
||||||
ModApiHttp::Initialize(L, top);
|
ModApiHttp::Initialize(L, top);
|
||||||
ModApiStorage::Initialize(L, top);
|
ModApiStorage::Initialize(L, top);
|
||||||
|
ModApiChannels::Initialize(L, top);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_deprecated(const std::string &message)
|
void log_deprecated(const std::string &message)
|
||||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "cpp_api/s_entity.h"
|
#include "cpp_api/s_entity.h"
|
||||||
#include "cpp_api/s_env.h"
|
#include "cpp_api/s_env.h"
|
||||||
#include "cpp_api/s_inventory.h"
|
#include "cpp_api/s_inventory.h"
|
||||||
|
#include "cpp_api/s_modchannels.h"
|
||||||
#include "cpp_api/s_node.h"
|
#include "cpp_api/s_node.h"
|
||||||
#include "cpp_api/s_player.h"
|
#include "cpp_api/s_player.h"
|
||||||
#include "cpp_api/s_server.h"
|
#include "cpp_api/s_server.h"
|
||||||
@ -36,6 +37,7 @@ class ServerScripting:
|
|||||||
public ScriptApiDetached,
|
public ScriptApiDetached,
|
||||||
public ScriptApiEntity,
|
public ScriptApiEntity,
|
||||||
public ScriptApiEnv,
|
public ScriptApiEnv,
|
||||||
|
public ScriptApiModChannels,
|
||||||
public ScriptApiNode,
|
public ScriptApiNode,
|
||||||
public ScriptApiPlayer,
|
public ScriptApiPlayer,
|
||||||
public ScriptApiServer,
|
public ScriptApiServer,
|
||||||
|
@ -51,6 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "content_sao.h"
|
#include "content_sao.h"
|
||||||
#include "mods.h"
|
#include "mods.h"
|
||||||
#include "event_manager.h"
|
#include "event_manager.h"
|
||||||
|
#include "modchannels.h"
|
||||||
#include "serverlist.h"
|
#include "serverlist.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "rollback.h"
|
#include "rollback.h"
|
||||||
@ -168,7 +169,8 @@ Server::Server(
|
|||||||
m_event(new EventManager()),
|
m_event(new EventManager()),
|
||||||
m_uptime(0),
|
m_uptime(0),
|
||||||
m_clients(m_con),
|
m_clients(m_con),
|
||||||
m_admin_chat(iface)
|
m_admin_chat(iface),
|
||||||
|
m_modchannel_mgr(new ModChannelMgr())
|
||||||
{
|
{
|
||||||
m_lag = g_settings->getFloat("dedicated_server_step");
|
m_lag = g_settings->getFloat("dedicated_server_step");
|
||||||
|
|
||||||
@ -1376,7 +1378,12 @@ void Server::printToConsoleOnly(const std::string &text)
|
|||||||
|
|
||||||
void Server::Send(NetworkPacket *pkt)
|
void Server::Send(NetworkPacket *pkt)
|
||||||
{
|
{
|
||||||
m_clients.send(pkt->getPeerId(),
|
Send(pkt->getPeerId(), pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::Send(u16 peer_id, NetworkPacket *pkt)
|
||||||
|
{
|
||||||
|
m_clients.send(peer_id,
|
||||||
clientCommandFactoryTable[pkt->getCommand()].channel,
|
clientCommandFactoryTable[pkt->getCommand()].channel,
|
||||||
pkt,
|
pkt,
|
||||||
clientCommandFactoryTable[pkt->getCommand()].reliable);
|
clientCommandFactoryTable[pkt->getCommand()].reliable);
|
||||||
@ -2567,7 +2574,7 @@ void Server::DenyAccessVerCompliant(u16 peer_id, u16 proto_ver, AccessDeniedCode
|
|||||||
SendAccessDenied(peer_id, reason, str_reason, reconnect);
|
SendAccessDenied(peer_id, reason, str_reason, reconnect);
|
||||||
|
|
||||||
m_clients.event(peer_id, CSE_SetDenied);
|
m_clients.event(peer_id, CSE_SetDenied);
|
||||||
m_con->DisconnectPeer(peer_id);
|
DisconnectPeer(peer_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2575,7 +2582,7 @@ void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string
|
|||||||
{
|
{
|
||||||
SendAccessDenied(peer_id, reason, custom_reason);
|
SendAccessDenied(peer_id, reason, custom_reason);
|
||||||
m_clients.event(peer_id, CSE_SetDenied);
|
m_clients.event(peer_id, CSE_SetDenied);
|
||||||
m_con->DisconnectPeer(peer_id);
|
DisconnectPeer(peer_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 13/03/15: remove this function when protocol version 25 will become
|
// 13/03/15: remove this function when protocol version 25 will become
|
||||||
@ -2584,6 +2591,12 @@ void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
|
|||||||
{
|
{
|
||||||
SendAccessDenied_Legacy(peer_id, reason);
|
SendAccessDenied_Legacy(peer_id, reason);
|
||||||
m_clients.event(peer_id, CSE_SetDenied);
|
m_clients.event(peer_id, CSE_SetDenied);
|
||||||
|
DisconnectPeer(peer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::DisconnectPeer(u16 peer_id)
|
||||||
|
{
|
||||||
|
m_modchannel_mgr->leaveAllChannels(peer_id);
|
||||||
m_con->DisconnectPeer(peer_id);
|
m_con->DisconnectPeer(peer_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3570,3 +3583,68 @@ void dedicated_server_loop(Server &server, bool &kill)
|
|||||||
server.m_bind_addr.getPort());
|
server.m_bind_addr.getPort());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mod channels
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
bool Server::joinModChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
|
||||||
|
m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Server::leaveModChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
|
||||||
|
{
|
||||||
|
if (!m_modchannel_mgr->canWriteOnChannel(channel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModChannel* Server::getModChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
return m_modchannel_mgr->getModChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::broadcastModChannelMessage(const std::string &channel,
|
||||||
|
const std::string &message, u16 from_peer)
|
||||||
|
{
|
||||||
|
const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
|
||||||
|
if (peers.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (message.size() > STRING_MAX_LEN) {
|
||||||
|
warningstream << "ModChannel message too long, dropping before sending "
|
||||||
|
<< " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
|
||||||
|
<< channel << ")" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sender;
|
||||||
|
if (from_peer != PEER_ID_SERVER) {
|
||||||
|
sender = getPlayerName(from_peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
|
||||||
|
2 + channel.size() + 2 + sender.size() + 2 + message.size());
|
||||||
|
resp_pkt << channel << sender << message;
|
||||||
|
for (u16 peer_id : peers) {
|
||||||
|
// Ignore sender
|
||||||
|
if (peer_id == from_peer)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Send(peer_id, &resp_pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from_peer != PEER_ID_SERVER) {
|
||||||
|
m_script->on_modchannel_message(channel, sender, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
16
src/server.h
16
src/server.h
@ -50,6 +50,7 @@ class IWritableCraftDefManager;
|
|||||||
class BanManager;
|
class BanManager;
|
||||||
class EventManager;
|
class EventManager;
|
||||||
class Inventory;
|
class Inventory;
|
||||||
|
class ModChannelMgr;
|
||||||
class RemotePlayer;
|
class RemotePlayer;
|
||||||
class PlayerSAO;
|
class PlayerSAO;
|
||||||
class IRollbackManager;
|
class IRollbackManager;
|
||||||
@ -144,6 +145,9 @@ public:
|
|||||||
void handleCommand_Deprecated(NetworkPacket* pkt);
|
void handleCommand_Deprecated(NetworkPacket* pkt);
|
||||||
void handleCommand_Init(NetworkPacket* pkt);
|
void handleCommand_Init(NetworkPacket* pkt);
|
||||||
void handleCommand_Init2(NetworkPacket* pkt);
|
void handleCommand_Init2(NetworkPacket* pkt);
|
||||||
|
void handleCommand_ModChannelJoin(NetworkPacket *pkt);
|
||||||
|
void handleCommand_ModChannelLeave(NetworkPacket *pkt);
|
||||||
|
void handleCommand_ModChannelMsg(NetworkPacket *pkt);
|
||||||
void handleCommand_RequestMedia(NetworkPacket* pkt);
|
void handleCommand_RequestMedia(NetworkPacket* pkt);
|
||||||
void handleCommand_ClientReady(NetworkPacket* pkt);
|
void handleCommand_ClientReady(NetworkPacket* pkt);
|
||||||
void handleCommand_GotBlocks(NetworkPacket* pkt);
|
void handleCommand_GotBlocks(NetworkPacket* pkt);
|
||||||
@ -166,6 +170,7 @@ public:
|
|||||||
void ProcessData(NetworkPacket *pkt);
|
void ProcessData(NetworkPacket *pkt);
|
||||||
|
|
||||||
void Send(NetworkPacket *pkt);
|
void Send(NetworkPacket *pkt);
|
||||||
|
void Send(u16 peer_id, NetworkPacket *pkt);
|
||||||
|
|
||||||
// Helper for handleCommand_PlayerPos and handleCommand_Interact
|
// Helper for handleCommand_PlayerPos and handleCommand_Interact
|
||||||
void process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
|
void process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
|
||||||
@ -319,6 +324,7 @@ public:
|
|||||||
void DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason="");
|
void DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason="");
|
||||||
void acceptAuth(u16 peer_id, bool forSudoMode);
|
void acceptAuth(u16 peer_id, bool forSudoMode);
|
||||||
void DenyAccess_Legacy(u16 peer_id, const std::wstring &reason);
|
void DenyAccess_Legacy(u16 peer_id, const std::wstring &reason);
|
||||||
|
void DisconnectPeer(u16 peer_id);
|
||||||
bool getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval);
|
bool getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval);
|
||||||
bool getClientInfo(u16 peer_id,ClientState* state, u32* uptime,
|
bool getClientInfo(u16 peer_id,ClientState* state, u32* uptime,
|
||||||
u8* ser_vers, u16* prot_vers, u8* major, u8* minor, u8* patch,
|
u8* ser_vers, u16* prot_vers, u8* major, u8* minor, u8* patch,
|
||||||
@ -334,6 +340,11 @@ public:
|
|||||||
virtual bool registerModStorage(ModMetadata *storage);
|
virtual bool registerModStorage(ModMetadata *storage);
|
||||||
virtual void unregisterModStorage(const std::string &name);
|
virtual void unregisterModStorage(const std::string &name);
|
||||||
|
|
||||||
|
bool joinModChannel(const std::string &channel);
|
||||||
|
bool leaveModChannel(const std::string &channel);
|
||||||
|
bool sendModChannelMessage(const std::string &channel, const std::string &message);
|
||||||
|
ModChannel *getModChannel(const std::string &channel);
|
||||||
|
|
||||||
// Bind address
|
// Bind address
|
||||||
Address m_bind_addr;
|
Address m_bind_addr;
|
||||||
|
|
||||||
@ -383,6 +394,8 @@ private:
|
|||||||
float thickness,
|
float thickness,
|
||||||
const v2f &speed);
|
const v2f &speed);
|
||||||
void SendOverrideDayNightRatio(u16 peer_id, bool do_override, float ratio);
|
void SendOverrideDayNightRatio(u16 peer_id, bool do_override, float ratio);
|
||||||
|
void broadcastModChannelMessage(const std::string &channel,
|
||||||
|
const std::string &message, u16 from_peer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Send a node removal/addition event to all clients except ignore_id.
|
Send a node removal/addition event to all clients except ignore_id.
|
||||||
@ -640,6 +653,9 @@ private:
|
|||||||
// CSM flavour limits byteflag
|
// CSM flavour limits byteflag
|
||||||
u64 m_csm_flavour_limits = CSMFlavourLimit::CSM_FL_NONE;
|
u64 m_csm_flavour_limits = CSMFlavourLimit::CSM_FL_NONE;
|
||||||
u32 m_csm_noderange_limit = 8;
|
u32 m_csm_noderange_limit = 8;
|
||||||
|
|
||||||
|
// ModChannel manager
|
||||||
|
std::unique_ptr<ModChannelMgr> m_modchannel_mgr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,6 +8,7 @@ set (UNITTEST_SRCS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_inventory.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_inventory.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_map_settings_manager.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_map_settings_manager.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_mapnode.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_mapnode.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test_modchannels.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_nodedef.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_nodedef.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_noderesolver.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_noderesolver.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test_noise.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test_noise.cpp
|
||||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "nodedef.h"
|
#include "nodedef.h"
|
||||||
#include "itemdef.h"
|
#include "itemdef.h"
|
||||||
#include "gamedef.h"
|
#include "gamedef.h"
|
||||||
|
#include "modchannels.h"
|
||||||
#include "mods.h"
|
#include "mods.h"
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
|
|
||||||
@ -69,6 +70,13 @@ public:
|
|||||||
virtual std::string getModStoragePath() const { return "."; }
|
virtual std::string getModStoragePath() const { return "."; }
|
||||||
virtual bool registerModStorage(ModMetadata *meta) { return true; }
|
virtual bool registerModStorage(ModMetadata *meta) { return true; }
|
||||||
virtual void unregisterModStorage(const std::string &name) {}
|
virtual void unregisterModStorage(const std::string &name) {}
|
||||||
|
bool joinModChannel(const std::string &channel);
|
||||||
|
bool leaveModChannel(const std::string &channel);
|
||||||
|
bool sendModChannelMessage(const std::string &channel, const std::string &message);
|
||||||
|
ModChannel *getModChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
return m_modchannel_mgr->getModChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IItemDefManager *m_itemdef = nullptr;
|
IItemDefManager *m_itemdef = nullptr;
|
||||||
@ -81,10 +89,12 @@ private:
|
|||||||
scene::ISceneManager *m_scenemgr = nullptr;
|
scene::ISceneManager *m_scenemgr = nullptr;
|
||||||
IRollbackManager *m_rollbackmgr = nullptr;
|
IRollbackManager *m_rollbackmgr = nullptr;
|
||||||
EmergeManager *m_emergemgr = nullptr;
|
EmergeManager *m_emergemgr = nullptr;
|
||||||
|
std::unique_ptr<ModChannelMgr> m_modchannel_mgr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TestGameDef::TestGameDef()
|
TestGameDef::TestGameDef() :
|
||||||
|
m_modchannel_mgr(new ModChannelMgr())
|
||||||
{
|
{
|
||||||
m_itemdef = createItemDefManager();
|
m_itemdef = createItemDefManager();
|
||||||
m_nodedef = createNodeDefManager();
|
m_nodedef = createNodeDefManager();
|
||||||
@ -222,6 +232,25 @@ void TestGameDef::defineSomeNodes()
|
|||||||
t_CONTENT_BRICK = ndef->set(f.name, f);
|
t_CONTENT_BRICK = ndef->set(f.name, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TestGameDef::joinModChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestGameDef::leaveModChannel(const std::string &channel)
|
||||||
|
{
|
||||||
|
return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestGameDef::sendModChannelMessage(const std::string &channel,
|
||||||
|
const std::string &message)
|
||||||
|
{
|
||||||
|
if (!m_modchannel_mgr->channelRegistered(channel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
//// run_tests
|
//// run_tests
|
||||||
////
|
////
|
||||||
|
76
src/unittest/test_modchannels.cpp
Normal file
76
src/unittest/test_modchannels.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#include "gamedef.h"
|
||||||
|
#include "modchannels.h"
|
||||||
|
|
||||||
|
class TestModChannels : public TestBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestModChannels() { TestManager::registerTestModule(this); }
|
||||||
|
const char *getName() { return "TestModChannels"; }
|
||||||
|
|
||||||
|
void runTests(IGameDef *gamedef);
|
||||||
|
|
||||||
|
void testJoinChannel(IGameDef *gamedef);
|
||||||
|
void testLeaveChannel(IGameDef *gamedef);
|
||||||
|
void testSendMessageToChannel(IGameDef *gamedef);
|
||||||
|
};
|
||||||
|
|
||||||
|
static TestModChannels g_test_instance;
|
||||||
|
|
||||||
|
void TestModChannels::runTests(IGameDef *gamedef)
|
||||||
|
{
|
||||||
|
TEST(testJoinChannel, gamedef);
|
||||||
|
TEST(testLeaveChannel, gamedef);
|
||||||
|
TEST(testSendMessageToChannel, gamedef);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestModChannels::testJoinChannel(IGameDef *gamedef)
|
||||||
|
{
|
||||||
|
// Test join
|
||||||
|
UASSERT(gamedef->joinModChannel("test_join_channel"));
|
||||||
|
// Test join (fail, already join)
|
||||||
|
UASSERT(!gamedef->joinModChannel("test_join_channel"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestModChannels::testLeaveChannel(IGameDef *gamedef)
|
||||||
|
{
|
||||||
|
// Test leave (not joined)
|
||||||
|
UASSERT(!gamedef->leaveModChannel("test_leave_channel"));
|
||||||
|
|
||||||
|
UASSERT(gamedef->joinModChannel("test_leave_channel"));
|
||||||
|
|
||||||
|
// Test leave (joined)
|
||||||
|
UASSERT(gamedef->leaveModChannel("test_leave_channel"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestModChannels::testSendMessageToChannel(IGameDef *gamedef)
|
||||||
|
{
|
||||||
|
// Test sendmsg (not joined)
|
||||||
|
UASSERT(!gamedef->sendModChannelMessage(
|
||||||
|
"test_sendmsg_channel", "testmsgchannel"));
|
||||||
|
|
||||||
|
UASSERT(gamedef->joinModChannel("test_sendmsg_channel"));
|
||||||
|
|
||||||
|
// Test sendmsg (joined)
|
||||||
|
UASSERT(gamedef->sendModChannelMessage("test_sendmsg_channel", "testmsgchannel"));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user