Add framework for reporting player

This commit is contained in:
Benau 2019-05-09 14:36:47 +08:00
parent fce5827c7d
commit 65e53f19e5
8 changed files with 109 additions and 90 deletions

View File

@ -147,17 +147,23 @@ The current server configuration xml looks like this:
<!-- Set how many states the server will send per second, the higher this value, the more bandwidth requires, also each client will trigger more rewind, which clients with slow device may have problem playing this server, use the default value is recommended. --> <!-- Set how many states the server will send per second, the higher this value, the more bandwidth requires, also each client will trigger more rewind, which clients with slow device may have problem playing this server, use the default value is recommended. -->
<state-frequency value="10" /> <state-frequency value="10" />
<!-- Use sql to manage server stats and banlist, STK needs to be compiled with sqlite3 supported. --> <!-- Use sql database for handling server stats and maintenance, STK needs to be compiled with sqlite3 supported. -->
<sql-management value="false" /> <sql-management value="false" />
<!-- Database filename for sqlite to use, it can be shared for servers creating in this machine, and stk will create specific table for each server. You need to create the database yourself first, see NETWORKING.md for details --> <!-- Database filename for sqlite to use, it can be shared for servers creating in this machine, and stk will create specific table for each server. You need to create the database yourself first, see NETWORKING.md for details -->
<database-file value="stkservers.db" /> <database-file value="stkservers.db" />
<!-- Ip ban list table name, you need to create the table first, see NETWORKING.md for details. --> <!-- Ip ban list table name, you need to create the table first, see NETWORKING.md for details, empty to disable. -->
<ip-ban-table value="ipban" /> <ip-ban-table value="ip_ban" />
<!-- Online ID ban list table name, you need to create the table first, see NETWORKING.md for details. --> <!-- Online ID ban list table name, you need to create the table first, see NETWORKING.md for details, empty to disable. -->
<online-id-ban-table value="onlineidban" /> <online-id-ban-table value="online_id_ban" />
<!-- Player reports table name, which will be written when a player reports player in the network user dialog, you need to create the table first, see NETWORKING.md for details, empty to disable. -->
<player-reports-table value="player_reports" />
<!-- Days to keep player reports, older than that will be auto cleared, 0 to keep them forever. -->
<player-reports-expired-days value="3" />
</server-config> </server-config>
@ -242,9 +248,9 @@ Current players in server with ip in human readable format and time played of ea
`*_player_stats` `*_player_stats`
All players with online id and username with their time played stats in this server since creation of this database. All players with online id and username with their time played stats in this server since creation of this database.
For IP or online ID ban list, you need to create one yourself: For IP, online ID ban list or player reports, you need to create one yourself:
```sql ```sql
CREATE TABLE ipban CREATE TABLE ip_ban
( (
ip_start INTEGER UNSIGNED NOT NULL UNIQUE, -- Starting of ip decimal for banning (inclusive) ip_start INTEGER UNSIGNED NOT NULL UNIQUE, -- Starting of ip decimal for banning (inclusive)
ip_end INTEGER UNSIGNED NOT NULL UNIQUE, -- Ending of ip decimal for banning (inclusive) ip_end INTEGER UNSIGNED NOT NULL UNIQUE, -- Ending of ip decimal for banning (inclusive)
@ -256,7 +262,7 @@ CREATE TABLE ipban
last_trigger TIMESTAMP NULL DEFAULT NULL -- Latest time this banning entry was triggered last_trigger TIMESTAMP NULL DEFAULT NULL -- Latest time this banning entry was triggered
); );
CREATE TABLE onlineidban CREATE TABLE online_id_ban
( (
online_id INTEGER UNSIGNED NOT NULL UNIQUE, -- Online id from STK addons database for banning online_id INTEGER UNSIGNED NOT NULL UNIQUE, -- Online id from STK addons database for banning
starting_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Starting time of this banning entry to be effective starting_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Starting time of this banning entry to be effective
@ -266,4 +272,14 @@ CREATE TABLE onlineidban
trigger_count INTEGER UNSIGNED NOT NULL DEFAULT 0, -- Number of banning triggered by this ban entry trigger_count INTEGER UNSIGNED NOT NULL DEFAULT 0, -- Number of banning triggered by this ban entry
last_trigger TIMESTAMP NULL DEFAULT NULL -- Latest time this banning entry was triggered last_trigger TIMESTAMP NULL DEFAULT NULL -- Latest time this banning entry was triggered
); );
CREATE TABLE player_reports
(
reported_online_id INTEGER UNSIGNED NOT NULL, -- Online id of player who reports, 0 for offline player
reported_username TEXT NOT NULL, -- Player name who reports
reported_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Time of reporting
info TEXT NOT NULL, -- Report info by reporter
reporting_online_id INTEGER UNSIGNED NOT NULL, -- Online id of player being reported, 0 for offline player
reporting_username TEXT NOT NULL -- Player name being reported
);
``` ```

View File

@ -99,6 +99,7 @@ ClientLobby::ClientLobby(const TransportAddress& a, std::shared_ptr<Server> s)
m_server_send_live_load_world = false; m_server_send_live_load_world = false;
m_server_enabled_chat = true; m_server_enabled_chat = true;
m_server_enabled_track_voting = true; m_server_enabled_track_voting = true;
m_server_enabled_report_player = false;
} // ClientLobby } // ClientLobby
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -622,6 +623,9 @@ void ClientLobby::connectionAccepted(Event* event)
if (auto_start_timer != std::numeric_limits<float>::max()) if (auto_start_timer != std::numeric_limits<float>::max())
NetworkingLobby::getInstance()->setStartingTimerTo(auto_start_timer); NetworkingLobby::getInstance()->setStartingTimerTo(auto_start_timer);
m_server_enabled_chat = data.getUInt8() == 1; m_server_enabled_chat = data.getUInt8() == 1;
if (NetworkConfig::get()->getServerCapabilities().find("report_player") !=
NetworkConfig::get()->getServerCapabilities().end())
m_server_enabled_report_player = data.getUInt8() == 1;
} // connectionAccepted } // connectionAccepted
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -107,6 +107,8 @@ private:
bool m_server_enabled_track_voting; bool m_server_enabled_track_voting;
bool m_server_enabled_report_player;
uint64_t m_auto_back_to_lobby_time; uint64_t m_auto_back_to_lobby_time;
uint64_t m_start_live_game_time; uint64_t m_start_live_game_time;
@ -173,6 +175,8 @@ public:
bool serverEnabledChat() const { return m_server_enabled_chat; } bool serverEnabledChat() const { return m_server_enabled_chat; }
bool serverEnabledTrackVoting() const bool serverEnabledTrackVoting() const
{ return m_server_enabled_track_voting; } { return m_server_enabled_track_voting; }
bool serverEnabledReportPlayer() const
{ return m_server_enabled_report_player; }
}; };
#endif // CLIENT_LOBBY_HPP #endif // CLIENT_LOBBY_HPP

View File

@ -144,6 +144,7 @@ ServerLobby::ServerLobby() : LobbyProtocol(NULL)
m_difficulty.store(ServerConfig::m_server_difficulty); m_difficulty.store(ServerConfig::m_server_difficulty);
m_game_mode.store(ServerConfig::m_server_mode); m_game_mode.store(ServerConfig::m_server_mode);
m_default_vote = new PeerVote(); m_default_vote = new PeerVote();
m_player_reports_table_exists = false;
initDatabase(); initDatabase();
} // ServerLobby } // ServerLobby
@ -171,7 +172,6 @@ void ServerLobby::initDatabase()
#ifdef ENABLE_SQLITE3 #ifdef ENABLE_SQLITE3
m_last_cleanup_db_time = StkTime::getMonoTimeMs(); m_last_cleanup_db_time = StkTime::getMonoTimeMs();
m_db = NULL; m_db = NULL;
sqlite3_stmt* stmt = NULL;;
m_ip_ban_table_exists = false; m_ip_ban_table_exists = false;
m_online_id_ban_table_exists = false; m_online_id_ban_table_exists = false;
if (!ServerConfig::m_sql_management) if (!ServerConfig::m_sql_management)
@ -186,80 +186,11 @@ void ServerLobby::initDatabase()
return; return;
} }
const std::string ip_ban_table = ServerConfig::m_ip_ban_table; checkTableExists(ServerConfig::m_ip_ban_table, m_ip_ban_table_exists);
if (!ip_ban_table.empty()) checkTableExists(ServerConfig::m_online_id_ban_table,
{ m_online_id_ban_table_exists);
std::string query = StringUtils::insertValues( checkTableExists(ServerConfig::m_player_reports_table,
"SELECT count(type) FROM sqlite_master " m_player_reports_table_exists);
"WHERE type='table' AND name='%s';", ip_ban_table.c_str());
ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0);
if (ret == SQLITE_OK)
{
ret = sqlite3_step(stmt);
if (ret == SQLITE_ROW)
{
int number = sqlite3_column_int(stmt, 0);
if (number == 1)
{
Log::info("ServerLobby", "%s ip ban table will used.",
ip_ban_table.c_str());
m_ip_ban_table_exists = true;
}
}
ret = sqlite3_finalize(stmt);
if (ret != SQLITE_OK)
{
Log::error("ServerLobby",
"Error finalize database for query %s: %s", query.c_str(),
sqlite3_errmsg(m_db));
}
}
}
if (!m_ip_ban_table_exists && !ip_ban_table.empty())
{
Log::warn("ServerLobby", "%s ip ban table not found in database.",
ip_ban_table.c_str());
}
const std::string online_id_ban_table =
ServerConfig::m_online_id_ban_table;
if (!online_id_ban_table.empty())
{
std::string query = StringUtils::insertValues(
"SELECT count(type) FROM sqlite_master "
"WHERE type='table' AND name='%s';", online_id_ban_table.c_str());
int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0);
if (ret == SQLITE_OK)
{
ret = sqlite3_step(stmt);
if (ret == SQLITE_ROW)
{
int number = sqlite3_column_int(stmt, 0);
if (number == 1)
{
Log::info("ServerLobby",
"%s online id ban table will used.",
online_id_ban_table.c_str());
m_online_id_ban_table_exists = true;
}
}
ret = sqlite3_finalize(stmt);
if (ret != SQLITE_OK)
{
Log::error("ServerLobby",
"Error finalize database for query %s: %s",
query.c_str(), sqlite3_errmsg(m_db));
}
}
}
if (!m_online_id_ban_table_exists && !online_id_ban_table.empty())
{
Log::warn("ServerLobby",
"%s online id ban table not found in database.",
online_id_ban_table.c_str());
}
#endif #endif
} // initDatabase } // initDatabase
@ -790,6 +721,49 @@ void ServerLobby::easySQLQuery(const std::string& query) const
query.c_str(), sqlite3_errmsg(m_db)); query.c_str(), sqlite3_errmsg(m_db));
} }
} // easySQLQuery } // easySQLQuery
//-----------------------------------------------------------------------------
/* Write true to result if table name exists in database. */
void ServerLobby::checkTableExists(const std::string& table, bool& result)
{
if (!m_db)
return;
sqlite3_stmt* stmt = NULL;
if (!table.empty())
{
std::string query = StringUtils::insertValues(
"SELECT count(type) FROM sqlite_master "
"WHERE type='table' AND name='%s';", table.c_str());
int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0);
if (ret == SQLITE_OK)
{
ret = sqlite3_step(stmt);
if (ret == SQLITE_ROW)
{
int number = sqlite3_column_int(stmt, 0);
if (number == 1)
{
Log::info("ServerLobby", "Table named %s will used.",
table.c_str());
result = true;
}
}
ret = sqlite3_finalize(stmt);
if (ret != SQLITE_OK)
{
Log::error("ServerLobby",
"Error finalize database for query %s: %s",
query.c_str(), sqlite3_errmsg(m_db));
}
}
}
if (!result && !table.empty())
{
Log::warn("ServerLobby", "Table named %s not found in database.",
table.c_str());
}
} // checkTableExists
#endif #endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2767,7 +2741,8 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr<STKPeer> peer,
message_ack->addFloat(auto_start_timer) message_ack->addFloat(auto_start_timer)
.addUInt32(ServerConfig::m_state_frequency) .addUInt32(ServerConfig::m_state_frequency)
.addUInt8(ServerConfig::m_chat ? 1 : 0); .addUInt8(ServerConfig::m_chat ? 1 : 0)
.addUInt8(m_player_reports_table_exists ? 1 : 0);
peer->setSpectator(false); peer->setSpectator(false);
if (game_started) if (game_started)

View File

@ -70,6 +70,8 @@ private:
irr::core::stringw m_name; irr::core::stringw m_name;
bool m_tried = false; bool m_tried = false;
}; };
bool m_player_reports_table_exists;
#ifdef ENABLE_SQLITE3 #ifdef ENABLE_SQLITE3
sqlite3* m_db; sqlite3* m_db;
@ -84,6 +86,8 @@ private:
void cleanupDatabase(); void cleanupDatabase();
void easySQLQuery(const std::string& query) const; void easySQLQuery(const std::string& query) const;
void checkTableExists(const std::string& table, bool& result);
#endif #endif
void initDatabase(); void initDatabase();

View File

@ -311,6 +311,8 @@ void loadServerLobbyFromConfig()
} }
NetworkConfig::get()->setStateFrequency(m_state_frequency); NetworkConfig::get()->setStateFrequency(m_state_frequency);
if (m_player_reports_expired_days < 0.0f)
m_player_reports_expired_days.revertToDefaults();
if (m_server_difficulty > RaceManager::DIFFICULTY_LAST) if (m_server_difficulty > RaceManager::DIFFICULTY_LAST)
m_server_difficulty = RaceManager::DIFFICULTY_LAST; m_server_difficulty = RaceManager::DIFFICULTY_LAST;
if (m_server_mode > 8) if (m_server_mode > 8)

View File

@ -322,8 +322,8 @@ namespace ServerConfig
SERVER_CFG_PREFIX BoolServerConfigParam m_sql_management SERVER_CFG_PREFIX BoolServerConfigParam m_sql_management
SERVER_CFG_DEFAULT(BoolServerConfigParam(false, SERVER_CFG_DEFAULT(BoolServerConfigParam(false,
"sql-management", "sql-management",
"Use sql to manage server stats and banlist, STK needs to be compiled " "Use sql database for handling server stats and maintenance, STK "
"with sqlite3 supported.")); "needs to be compiled with sqlite3 supported."));
SERVER_CFG_PREFIX StringServerConfigParam m_database_file SERVER_CFG_PREFIX StringServerConfigParam m_database_file
SERVER_CFG_DEFAULT(StringServerConfigParam("stkservers.db", SERVER_CFG_DEFAULT(StringServerConfigParam("stkservers.db",
@ -334,17 +334,29 @@ namespace ServerConfig
"NETWORKING.md for details")); "NETWORKING.md for details"));
SERVER_CFG_PREFIX StringServerConfigParam m_ip_ban_table SERVER_CFG_PREFIX StringServerConfigParam m_ip_ban_table
SERVER_CFG_DEFAULT(StringServerConfigParam("ipban", SERVER_CFG_DEFAULT(StringServerConfigParam("ip_ban",
"ip-ban-table", "ip-ban-table",
"Ip ban list table name, you need to create the table first, see " "Ip ban list table name, you need to create the table first, see "
"NETWORKING.md for details, empty to disable.")); "NETWORKING.md for details, empty to disable."));
SERVER_CFG_PREFIX StringServerConfigParam m_online_id_ban_table SERVER_CFG_PREFIX StringServerConfigParam m_online_id_ban_table
SERVER_CFG_DEFAULT(StringServerConfigParam("onlineidban", SERVER_CFG_DEFAULT(StringServerConfigParam("online_id_ban",
"online-id-ban-table", "online-id-ban-table",
"Online ID ban list table name, you need to create the table first, " "Online ID ban list table name, you need to create the table first, "
"see NETWORKING.md for details, empty to disable.")); "see NETWORKING.md for details, empty to disable."));
SERVER_CFG_PREFIX StringServerConfigParam m_player_reports_table
SERVER_CFG_DEFAULT(StringServerConfigParam("player_reports",
"player-reports-table",
"Player reports table name, which will be written when a player "
"reports player in the network user dialog, you need to create the "
"table first, see NETWORKING.md for details, empty to disable."));
SERVER_CFG_PREFIX FloatServerConfigParam m_player_reports_expired_days
SERVER_CFG_DEFAULT(FloatServerConfigParam(3.0f,
"player-reports-expired-days", "Days to keep player reports, "
"older than that will be auto cleared, 0 to keep them forever."));
// ======================================================================== // ========================================================================
/** Server version, will be advanced if there are protocol changes. */ /** Server version, will be advanced if there are protocol changes. */
static const uint32_t m_server_version = 6; static const uint32_t m_server_version = 6;

View File

@ -26,7 +26,7 @@
#include "guiengine/widgets/ribbon_widget.hpp" #include "guiengine/widgets/ribbon_widget.hpp"
#include "guiengine/widgets/text_box_widget.hpp" #include "guiengine/widgets/text_box_widget.hpp"
#include "online/online_profile.hpp" #include "online/online_profile.hpp"
#include "network/protocols/lobby_protocol.hpp" #include "network/protocols/client_lobby.hpp"
#include "network/stk_host.hpp" #include "network/stk_host.hpp"
#include "states_screens/dialogs/general_text_field_dialog.hpp" #include "states_screens/dialogs/general_text_field_dialog.hpp"
#include "states_screens/state_manager.hpp" #include "states_screens/state_manager.hpp"
@ -129,7 +129,9 @@ void NetworkUserDialog::beforeAddingWidgets()
getWidget<IconButtonWidget>("remove")->setVisible(false); getWidget<IconButtonWidget>("remove")->setVisible(false);
m_report_widget = getWidget<IconButtonWidget>("enter"); m_report_widget = getWidget<IconButtonWidget>("enter");
assert(m_report_widget != NULL); assert(m_report_widget != NULL);
if (m_host_id != STKHost::get()->getMyHostId()) auto cl = LobbyProtocol::get<ClientLobby>();
if (cl->serverEnabledReportPlayer() &&
m_host_id != STKHost::get()->getMyHostId())
{ {
// I18N: In the network user dialog, // I18N: In the network user dialog,
// report player about for example abusive behaviour in game // report player about for example abusive behaviour in game