Improved server commands and added player permissions.
--HG-- extra : rebase_source : 178fe08f10b7de3ebaba088bd24faad795114216experimental
parent
dadac0e79f
commit
248d7c8469
|
@ -69,6 +69,7 @@ set(common_SRCS
|
|||
connection.cpp
|
||||
environment.cpp
|
||||
server.cpp
|
||||
servercommand.cpp
|
||||
socket.cpp
|
||||
mapblock.cpp
|
||||
mapsector.cpp
|
||||
|
|
|
@ -34,7 +34,8 @@ Player::Player():
|
|||
m_pitch(0),
|
||||
m_yaw(0),
|
||||
m_speed(0,0,0),
|
||||
m_position(0,0,0)
|
||||
m_position(0,0,0),
|
||||
privs(PRIV_DEFAULT)
|
||||
{
|
||||
updateName("<not set>");
|
||||
resetInventory();
|
||||
|
@ -100,6 +101,7 @@ void Player::serialize(std::ostream &os)
|
|||
args.setV3F("position", m_position);
|
||||
args.setBool("craftresult_is_preview", craftresult_is_preview);
|
||||
args.setS32("hp", hp);
|
||||
args.setU64("privs", privs);
|
||||
|
||||
args.writeLines(os);
|
||||
|
||||
|
@ -141,6 +143,11 @@ void Player::deSerialize(std::istream &is)
|
|||
}catch(SettingNotFoundException &e){
|
||||
hp = 20;
|
||||
}
|
||||
try{
|
||||
privs = args.getU64("privs");
|
||||
}catch(SettingNotFoundException &e){
|
||||
privs = PRIV_DEFAULT;
|
||||
}
|
||||
|
||||
inventory.deSerialize(is);
|
||||
}
|
||||
|
|
72
src/player.h
72
src/player.h
|
@ -28,11 +28,29 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,"
|
||||
|
||||
// Player privileges. These form a bitmask stored in the privs field
|
||||
// of the player, and define things they're allowed to do. See also
|
||||
// the static methods Player::privsToString and stringToPrivs that
|
||||
// convert these to human-readable form.
|
||||
const u64 PRIV_BUILD = 1; // Can build - i.e. modify the world
|
||||
// (not enforced yet)
|
||||
const u64 PRIV_TELEPORT = 2; // Can teleport
|
||||
const u64 PRIV_SETTIME = 4; // Can set the time
|
||||
const u64 PRIV_PRIVS = 8; // Can grant and revoke privileges
|
||||
const u64 PRIV_SERVER = 16; // Can manage the server (e.g. shutodwn ,settings)
|
||||
|
||||
const u64 PRIV_DEFAULT = PRIV_BUILD;
|
||||
const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL;
|
||||
const u64 PRIV_INVALID = 0x8000000000000000ULL;
|
||||
|
||||
|
||||
class Map;
|
||||
|
||||
class Player
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
Player();
|
||||
virtual ~Player();
|
||||
|
||||
|
@ -123,6 +141,9 @@ public:
|
|||
|
||||
u16 hp;
|
||||
|
||||
// Player's privileges - a bitmaps of PRIV_xxxx.
|
||||
u64 privs;
|
||||
|
||||
u16 peer_id;
|
||||
|
||||
protected:
|
||||
|
@ -131,6 +152,57 @@ protected:
|
|||
f32 m_yaw;
|
||||
v3f m_speed;
|
||||
v3f m_position;
|
||||
|
||||
public:
|
||||
|
||||
// Converst a prvileges value into a human-readable string,
|
||||
// with each component separated by a comma.
|
||||
static std::wstring privsToString(u64 privs)
|
||||
{
|
||||
std::wostringstream os(std::ios_base::binary);
|
||||
if(privs & PRIV_BUILD)
|
||||
os<<L"build,";
|
||||
if(privs & PRIV_TELEPORT)
|
||||
os<<L"teleport,";
|
||||
if(privs & PRIV_SETTIME)
|
||||
os<<L"settime,";
|
||||
if(privs & PRIV_PRIVS)
|
||||
os<<L"privs,";
|
||||
if(os.tellp())
|
||||
{
|
||||
// Drop the trailing comma. (Why on earth can't
|
||||
// you truncate a C++ stream anyway???)
|
||||
std::wstring tmp = os.str();
|
||||
return tmp.substr(0, tmp.length() -1);
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
// Converts a comma-seperated list of privilege values into a
|
||||
// privileges value. The reverse of privsToString(). Returns
|
||||
// PRIV_INVALID if there is anything wrong with the input.
|
||||
static u64 stringToPrivs(std::wstring str)
|
||||
{
|
||||
u64 privs=0;
|
||||
std::vector<std::wstring> pr;
|
||||
pr=str_split(str, ',');
|
||||
for(std::vector<std::wstring>::iterator i = pr.begin();
|
||||
i != pr.end(); ++i)
|
||||
{
|
||||
if(*i == L"build")
|
||||
privs |= PRIV_BUILD;
|
||||
else if(*i == L"teleport")
|
||||
privs |= PRIV_TELEPORT;
|
||||
else if(*i == L"settime")
|
||||
privs |= PRIV_SETTIME;
|
||||
else if(*i == L"privs")
|
||||
privs |= PRIV_PRIVS;
|
||||
else
|
||||
return PRIV_INVALID;
|
||||
}
|
||||
return privs;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "materials.h"
|
||||
#include "mineral.h"
|
||||
#include "config.h"
|
||||
#include "servercommand.h"
|
||||
|
||||
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
|
||||
|
||||
|
@ -1994,6 +1995,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
if(datasize < 13)
|
||||
return;
|
||||
|
||||
if((player->privs & PRIV_BUILD) == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
[0] u16 command
|
||||
[2] u8 button (0=left, 1=right)
|
||||
|
@ -2075,6 +2079,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
if(datasize < 7)
|
||||
return;
|
||||
|
||||
if((player->privs & PRIV_BUILD) == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
length: 7
|
||||
[0] u16 command
|
||||
|
@ -2167,6 +2174,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
{
|
||||
if(datasize < 17)
|
||||
return;
|
||||
if((player->privs & PRIV_BUILD) == 0)
|
||||
return;
|
||||
/*
|
||||
length: 17
|
||||
[0] u16 command
|
||||
|
@ -2615,6 +2624,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
#endif
|
||||
else if(command == TOSERVER_SIGNTEXT)
|
||||
{
|
||||
if((player->privs & PRIV_BUILD) == 0)
|
||||
return;
|
||||
/*
|
||||
u16 command
|
||||
v3s16 blockpos
|
||||
|
@ -2672,6 +2683,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
}
|
||||
else if(command == TOSERVER_SIGNNODETEXT)
|
||||
{
|
||||
if((player->privs & PRIV_BUILD) == 0)
|
||||
return;
|
||||
/*
|
||||
u16 command
|
||||
v3s16 p
|
||||
|
@ -2853,71 +2866,19 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
line += L"Server: ";
|
||||
|
||||
message = message.substr(commandprefix.size());
|
||||
// Get player name as narrow string
|
||||
std::string name_s = player->getName();
|
||||
// Convert message to narrow string
|
||||
std::string message_s = wide_to_narrow(message);
|
||||
// Operator is the single name defined in config.
|
||||
std::string operator_name = g_settings.get("name");
|
||||
bool is_operator = (operator_name != "" &&
|
||||
wide_to_narrow(name) == operator_name);
|
||||
bool valid_command = false;
|
||||
if(message_s == "help")
|
||||
{
|
||||
line += L"-!- Available commands: ";
|
||||
line += L"status ";
|
||||
if(is_operator)
|
||||
{
|
||||
line += L"shutdown setting time ";
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
send_to_sender = true;
|
||||
valid_command = true;
|
||||
}
|
||||
else if(message_s == "status")
|
||||
{
|
||||
line = getStatusString();
|
||||
send_to_sender = true;
|
||||
valid_command = true;
|
||||
}
|
||||
else if(is_operator)
|
||||
{
|
||||
if(message_s == "shutdown")
|
||||
{
|
||||
dstream<<DTIME<<" Server: Operator requested shutdown."
|
||||
<<std::endl;
|
||||
m_shutdown_requested.set(true);
|
||||
|
||||
line += L"*** Server shutting down (operator request)";
|
||||
send_to_sender = true;
|
||||
valid_command = true;
|
||||
}
|
||||
else if(message_s.substr(0,8) == "setting ")
|
||||
{
|
||||
std::string confline = message_s.substr(8);
|
||||
g_settings.parseConfigLine(confline);
|
||||
line += L"-!- Setting changed.";
|
||||
send_to_sender = true;
|
||||
valid_command = true;
|
||||
}
|
||||
else if(message_s.substr(0,5) == "time ")
|
||||
{
|
||||
u32 time = stoi(message_s.substr(5));
|
||||
m_time_of_day.set(time);
|
||||
m_time_of_day_send_timer = 0;
|
||||
line += L"-!- time_of_day changed.";
|
||||
send_to_sender = true;
|
||||
valid_command = true;
|
||||
}
|
||||
}
|
||||
ServerCommandContext *ctx = new ServerCommandContext(
|
||||
str_split(message, L' '),
|
||||
this,
|
||||
&m_env,
|
||||
player
|
||||
);
|
||||
|
||||
line += ServerCommand::processCommand(ctx);
|
||||
send_to_sender = ctx->flags & 1;
|
||||
send_to_others = ctx->flags & 2;
|
||||
delete ctx;
|
||||
|
||||
if(valid_command == false)
|
||||
{
|
||||
line += L"-!- Invalid command: " + message;
|
||||
send_to_sender = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
23
src/server.h
23
src/server.h
|
@ -387,6 +387,12 @@ public:
|
|||
return time_to_daynight_ratio(m_time_of_day.get());
|
||||
}
|
||||
|
||||
void setTimeOfDay(u32 time)
|
||||
{
|
||||
m_time_of_day.set(time);
|
||||
m_time_of_day_send_timer = 0;
|
||||
}
|
||||
|
||||
bool getShutdownRequested()
|
||||
{
|
||||
return m_shutdown_requested.get();
|
||||
|
@ -405,6 +411,19 @@ public:
|
|||
Inventory* getInventory(InventoryContext *c, std::string id);
|
||||
void inventoryModified(InventoryContext *c, std::string id);
|
||||
|
||||
// Connection must be locked when called
|
||||
std::wstring getStatusString();
|
||||
|
||||
void requestShutdown(void)
|
||||
{
|
||||
m_shutdown_requested.set(true);
|
||||
}
|
||||
|
||||
|
||||
// Envlock and conlock should be locked when calling this
|
||||
void SendMovePlayer(Player *player);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Virtual methods from con::PeerHandler.
|
||||
|
@ -429,7 +448,6 @@ private:
|
|||
void SendChatMessage(u16 peer_id, const std::wstring &message);
|
||||
void BroadcastChatMessage(const std::wstring &message);
|
||||
void SendPlayerHP(Player *player);
|
||||
void SendMovePlayer(Player *player);
|
||||
/*
|
||||
Send a node removal/addition event to all clients except ignore_id.
|
||||
Additionally, if far_players!=NULL, players further away than
|
||||
|
@ -455,9 +473,6 @@ private:
|
|||
// When called, connection mutex should be locked
|
||||
RemoteClient* getClient(u16 peer_id);
|
||||
|
||||
// Connection must be locked when called
|
||||
std::wstring getStatusString();
|
||||
|
||||
/*
|
||||
Get a player from memory or creates one.
|
||||
If player is already connected, return NULL
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU 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 "servercommand.h"
|
||||
#include "utility.h"
|
||||
|
||||
// Process a command sent from a client. The environment and connection
|
||||
// should be locked when this is called.
|
||||
// Returns a response message, to be dealt with according to the flags set
|
||||
// in the context.
|
||||
std::wstring ServerCommand::processCommand(ServerCommandContext *ctx)
|
||||
{
|
||||
|
||||
std::wostringstream os(std::ios_base::binary);
|
||||
ctx->flags = 1; // Default, unless we change it.
|
||||
|
||||
u64 privs = ctx->player->privs;
|
||||
|
||||
if(ctx->parms.size() == 0 || ctx->parms[0] == L"help")
|
||||
{
|
||||
os<<L"-!- Available commands: ";
|
||||
os<<L"status privs ";
|
||||
if(privs & PRIV_SERVER)
|
||||
os<<L"shutdown setting ";
|
||||
if(privs & PRIV_SETTIME)
|
||||
os<<L" time";
|
||||
if(privs & PRIV_TELEPORT)
|
||||
os<<L" teleport";
|
||||
if(privs & PRIV_PRIVS)
|
||||
os<<L" grant revoke";
|
||||
}
|
||||
else if(ctx->parms[0] == L"status")
|
||||
{
|
||||
cmd_status(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"privs")
|
||||
{
|
||||
cmd_privs(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"grant" || ctx->parms[0] == L"revoke")
|
||||
{
|
||||
cmd_grantrevoke(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"time")
|
||||
{
|
||||
cmd_time(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"shutdown")
|
||||
{
|
||||
cmd_shutdown(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"setting")
|
||||
{
|
||||
cmd_setting(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"teleport")
|
||||
{
|
||||
cmd_teleport(os, ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
os<<L"-!- Invalid command: " + ctx->parms[0];
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
void ServerCommand::cmd_status(std::wostringstream &os,
|
||||
ServerCommandContext *ctx)
|
||||
{
|
||||
os<<ctx->server->getStatusString();
|
||||
}
|
||||
|
||||
void ServerCommand::cmd_privs(std::wostringstream &os,
|
||||
ServerCommandContext *ctx)
|
||||
{
|
||||
if(ctx->parms.size() == 1)
|
||||
{
|
||||
os<<L"-!- " + Player::privsToString(ctx->player->privs);
|
||||
return;
|
||||
}
|
||||
|
||||
if((ctx->player->privs & PRIV_PRIVS) == 0)
|
||||
{
|
||||
os<<L"-!- You don't have permission to do that";
|
||||
return;
|
||||
}
|
||||
|
||||
Player *tp = ctx->env->getPlayer(wide_to_narrow(ctx->parms[1]).c_str());
|
||||
if(tp == NULL)
|
||||
{
|
||||
os<<L"-!- No such player";
|
||||
return;
|
||||
}
|
||||
|
||||
os<<L"-!- " + Player::privsToString(tp->privs);
|
||||
}
|
||||
|
||||
void ServerCommand::cmd_grantrevoke(std::wostringstream &os,
|
||||
ServerCommandContext *ctx)
|
||||
{
|
||||
if(ctx->parms.size() != 3)
|
||||
{
|
||||
os<<L"-!- Missing parameter";
|
||||
return;
|
||||
}
|
||||
|
||||
if((ctx->player->privs & PRIV_PRIVS) == 0)
|
||||
{
|
||||
os<<L"-!- You don't have permission to do that";
|
||||
return;
|
||||
}
|
||||
|
||||
u64 newprivs = Player::stringToPrivs(ctx->parms[2]);
|
||||
if(newprivs == PRIV_INVALID)
|
||||
{
|
||||
os<<L"-!- Invalid privileges specified";
|
||||
return;
|
||||
}
|
||||
|
||||
Player *tp = ctx->env->getPlayer(wide_to_narrow(ctx->parms[1]).c_str());
|
||||
if(tp == NULL)
|
||||
{
|
||||
os<<L"-!- No such player";
|
||||
return;
|
||||
}
|
||||
|
||||
if(ctx->parms[0] == L"grant")
|
||||
tp->privs |= newprivs;
|
||||
else
|
||||
tp->privs &= ~newprivs;
|
||||
|
||||
os<<L"-!- Privileges change to ";
|
||||
os<<Player::privsToString(tp->privs);
|
||||
}
|
||||
|
||||
void ServerCommand::cmd_time(std::wostringstream &os,
|
||||
ServerCommandContext *ctx)
|
||||
{
|
||||
if(ctx->parms.size() != 2)
|
||||
{
|
||||
os<<L"-!- Missing parameter";
|
||||
return;
|
||||
}
|
||||
|
||||
if((ctx->player->privs & PRIV_SETTIME) ==0)
|
||||
{
|
||||
os<<L"-!- You don't have permission to do that";
|
||||
return;
|
||||
}
|
||||
|
||||
u32 time = stoi(wide_to_narrow(ctx->parms[1]));
|
||||
ctx->server->setTimeOfDay(time);
|
||||
os<<L"-!- time_of_day changed.";
|
||||
}
|
||||
|
||||
void ServerCommand::cmd_shutdown(std::wostringstream &os,
|
||||
ServerCommandContext *ctx)
|
||||
{
|
||||
if((ctx->player->privs & PRIV_SERVER) ==0)
|
||||
{
|
||||
os<<L"-!- You don't have permission to do that";
|
||||
return;
|
||||
}
|
||||
|
||||
dstream<<DTIME<<" Server: Operator requested shutdown."
|
||||
<<std::endl;
|
||||
ctx->server->requestShutdown();
|
||||
|
||||
os<<L"*** Server shutting down (operator request)";
|
||||
ctx->flags |= 2;
|
||||
}
|
||||
|
||||
void ServerCommand::cmd_setting(std::wostringstream &os,
|
||||
ServerCommandContext *ctx)
|
||||
{
|
||||
if((ctx->player->privs & PRIV_SERVER) ==0)
|
||||
{
|
||||
os<<L"-!- You don't have permission to do that";
|
||||
return;
|
||||
}
|
||||
|
||||
std::string confline = wide_to_narrow(ctx->parms[1] + L" = " + ctx->parms[2]);
|
||||
g_settings.parseConfigLine(confline);
|
||||
os<< L"-!- Setting changed.";
|
||||
}
|
||||
|
||||
void ServerCommand::cmd_teleport(std::wostringstream &os,
|
||||
ServerCommandContext *ctx)
|
||||
{
|
||||
if((ctx->player->privs & PRIV_TELEPORT) ==0)
|
||||
{
|
||||
os<<L"-!- You don't have permission to do that";
|
||||
return;
|
||||
}
|
||||
|
||||
if(ctx->parms.size() != 2)
|
||||
{
|
||||
os<<L"-!- Missing parameter";
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::wstring> coords = str_split(ctx->parms[1], L',');
|
||||
if(coords.size() != 3)
|
||||
{
|
||||
os<<L"-!- You can only specify coordinates currently";
|
||||
return;
|
||||
}
|
||||
|
||||
v3f dest(stoi(coords[0])*10, stoi(coords[1])*10, stoi(coords[2])*10);
|
||||
ctx->player->setPosition(dest);
|
||||
ctx->server->SendMovePlayer(ctx->player);
|
||||
|
||||
os<< L"-!- Teleported.";
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU 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.
|
||||
*/
|
||||
|
||||
#ifndef SERVERCOMMAND_HEADER
|
||||
#define SERVERCOMMAND_HEADER
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include "common_irrlicht.h"
|
||||
#include "player.h"
|
||||
#include "server.h"
|
||||
|
||||
struct ServerCommandContext
|
||||
{
|
||||
|
||||
std::vector<std::wstring> parms;
|
||||
Server* server;
|
||||
ServerEnvironment *env;
|
||||
Player* player;
|
||||
u32 flags;
|
||||
|
||||
ServerCommandContext(
|
||||
std::vector<std::wstring> parms,
|
||||
Server* server,
|
||||
ServerEnvironment *env,
|
||||
Player* player)
|
||||
: parms(parms), server(server), env(env), player(player)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class ServerCommand
|
||||
{
|
||||
public:
|
||||
|
||||
static std::wstring processCommand(ServerCommandContext *ctx);
|
||||
|
||||
private:
|
||||
|
||||
static void cmd_status(std::wostringstream &os,
|
||||
ServerCommandContext *ctx);
|
||||
static void cmd_privs(std::wostringstream &os,
|
||||
ServerCommandContext *ctx);
|
||||
static void cmd_grantrevoke(std::wostringstream &os,
|
||||
ServerCommandContext *ctx);
|
||||
static void cmd_time(std::wostringstream &os,
|
||||
ServerCommandContext *ctx);
|
||||
static void cmd_shutdown(std::wostringstream &os,
|
||||
ServerCommandContext *ctx);
|
||||
static void cmd_setting(std::wostringstream &os,
|
||||
ServerCommandContext *ctx);
|
||||
static void cmd_teleport(std::wostringstream &os,
|
||||
ServerCommandContext *ctx);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <jthread.h>
|
||||
#include <jmutex.h>
|
||||
#include <jmutexautolock.h>
|
||||
|
@ -731,6 +732,19 @@ inline std::string wide_to_narrow(const std::wstring& wcs)
|
|||
return *mbs;
|
||||
}
|
||||
|
||||
// Split a string using the given delimiter. Returns a vector containing
|
||||
// the component parts.
|
||||
inline std::vector<std::wstring> str_split(const std::wstring &str, wchar_t delimiter)
|
||||
{
|
||||
std::vector<std::wstring> parts;
|
||||
std::wstringstream sstr(str);
|
||||
std::wstring part;
|
||||
while(std::getline(sstr, part, delimiter))
|
||||
parts.push_back(part);
|
||||
return parts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
See test.cpp for example cases.
|
||||
wraps degrees to the range of -360...360
|
||||
|
@ -791,6 +805,11 @@ inline s32 stoi(std::string s)
|
|||
return atoi(s.c_str());
|
||||
}
|
||||
|
||||
inline s32 stoi(std::wstring s)
|
||||
{
|
||||
return atoi(wide_to_narrow(s).c_str());
|
||||
}
|
||||
|
||||
inline float stof(std::string s)
|
||||
{
|
||||
float f;
|
||||
|
|
Loading…
Reference in New Issue