forked from Mirrorlandia_minetest/minetest
Merge branch 'upstream/master'
This commit is contained in:
commit
96bee29e35
@ -9,7 +9,7 @@ project(minetest-delta)
|
|||||||
|
|
||||||
set(VERSION_MAJOR 0)
|
set(VERSION_MAJOR 0)
|
||||||
set(VERSION_MINOR 2)
|
set(VERSION_MINOR 2)
|
||||||
set(VERSION_PATCH 20110720_0)
|
set(VERSION_PATCH 20110730_rc1)
|
||||||
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||||
|
|
||||||
# Configuration options
|
# Configuration options
|
||||||
|
@ -415,8 +415,9 @@ void Client::step(float dtime)
|
|||||||
// [0] u16 TOSERVER_INIT
|
// [0] u16 TOSERVER_INIT
|
||||||
// [2] u8 SER_FMT_VER_HIGHEST
|
// [2] u8 SER_FMT_VER_HIGHEST
|
||||||
// [3] u8[20] player_name
|
// [3] u8[20] player_name
|
||||||
// [23] u8[28] password
|
// [23] u8[28] password (new in some version)
|
||||||
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE);
|
// [51] u16 client network protocol version (new in some version)
|
||||||
|
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2);
|
||||||
writeU16(&data[0], TOSERVER_INIT);
|
writeU16(&data[0], TOSERVER_INIT);
|
||||||
writeU8(&data[2], SER_FMT_VER_HIGHEST);
|
writeU8(&data[2], SER_FMT_VER_HIGHEST);
|
||||||
|
|
||||||
@ -429,6 +430,9 @@ void Client::step(float dtime)
|
|||||||
memset((char*)&data[23], 0, PASSWORD_SIZE);
|
memset((char*)&data[23], 0, PASSWORD_SIZE);
|
||||||
snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
|
snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
|
||||||
|
|
||||||
|
// This should be incremented in each version
|
||||||
|
writeU16(&data[51], 1);
|
||||||
|
|
||||||
// Send as unreliable
|
// Send as unreliable
|
||||||
Send(0, data, false);
|
Send(0, data, false);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,8 @@ enum ToServerCommand
|
|||||||
[0] u16 TOSERVER_INIT
|
[0] u16 TOSERVER_INIT
|
||||||
[2] u8 SER_FMT_VER_HIGHEST
|
[2] u8 SER_FMT_VER_HIGHEST
|
||||||
[3] u8[20] player_name
|
[3] u8[20] player_name
|
||||||
[23] u8[28] password
|
[23] u8[28] password (new in some version)
|
||||||
|
[51] u16 client network protocol version (new in some version)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TOSERVER_INIT2 = 0x11,
|
TOSERVER_INIT2 = 0x11,
|
||||||
|
@ -187,7 +187,8 @@ public:
|
|||||||
core::aabbox3d<f32>* getSelectionBox()
|
core::aabbox3d<f32>* getSelectionBox()
|
||||||
{return &m_selection_box;}
|
{return &m_selection_box;}
|
||||||
v3f getPosition()
|
v3f getPosition()
|
||||||
{return m_position;}
|
{return pos_translator.vect_show;}
|
||||||
|
//{return m_position;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::aabbox3d<f32> m_selection_box;
|
core::aabbox3d<f32> m_selection_box;
|
||||||
|
@ -65,6 +65,10 @@ std::string item_craft_get_image_name(const std::string &subname)
|
|||||||
return "clay_brick.png";
|
return "clay_brick.png";
|
||||||
else if(subname == "rat")
|
else if(subname == "rat")
|
||||||
return "rat.png";
|
return "rat.png";
|
||||||
|
else if(subname == "cooked_rat")
|
||||||
|
return "cooked_rat.png";
|
||||||
|
else if(subname == "scorched_stuff")
|
||||||
|
return "scorched_stuff.png";
|
||||||
else if(subname == "firefly")
|
else if(subname == "firefly")
|
||||||
return "firefly.png";
|
return "firefly.png";
|
||||||
else
|
else
|
||||||
@ -98,7 +102,7 @@ s16 item_craft_get_drop_count(const std::string &subname)
|
|||||||
|
|
||||||
bool item_craft_is_cookable(const std::string &subname)
|
bool item_craft_is_cookable(const std::string &subname)
|
||||||
{
|
{
|
||||||
if(subname == "lump_of_iron" || subname == "lump_of_clay")
|
if(subname == "lump_of_iron" || subname == "lump_of_clay" || subname == "rat" || subname == "cooked_rat")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -110,7 +114,26 @@ InventoryItem* item_craft_create_cook_result(const std::string &subname)
|
|||||||
return new CraftItem("steel_ingot", 1);
|
return new CraftItem("steel_ingot", 1);
|
||||||
else if(subname == "lump_of_clay")
|
else if(subname == "lump_of_clay")
|
||||||
return new CraftItem("clay_brick", 1);
|
return new CraftItem("clay_brick", 1);
|
||||||
|
else if(subname == "rat")
|
||||||
|
return new CraftItem("cooked_rat", 1);
|
||||||
|
else if(subname == "cooked_rat")
|
||||||
|
return new CraftItem("scorched_stuff", 1);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool item_craft_is_eatable(const std::string &subname)
|
||||||
|
{
|
||||||
|
if(subname == "cooked_rat")
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 item_craft_eat_hp_change(const std::string &subname)
|
||||||
|
{
|
||||||
|
if(subname == "cooked_rat")
|
||||||
|
return 6; // 3 hearts
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@ ServerActiveObject* item_craft_create_object(const std::string &subname,
|
|||||||
s16 item_craft_get_drop_count(const std::string &subname);
|
s16 item_craft_get_drop_count(const std::string &subname);
|
||||||
bool item_craft_is_cookable(const std::string &subname);
|
bool item_craft_is_cookable(const std::string &subname);
|
||||||
InventoryItem* item_craft_create_cook_result(const std::string &subname);
|
InventoryItem* item_craft_create_cook_result(const std::string &subname);
|
||||||
|
bool item_craft_is_eatable(const std::string &subname);
|
||||||
|
s16 item_craft_eat_hp_change(const std::string &subname);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -277,6 +277,20 @@ bool FurnaceNodeMetadata::step(float dtime)
|
|||||||
fuel_list->decrementMaterials(1);
|
fuel_list->decrementMaterials(1);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
else if(ItemSpec(ITEM_MATERIAL, CONTENT_JUNGLETREE).checkItem(fuel_item))
|
||||||
|
{
|
||||||
|
m_fuel_totaltime = 30;
|
||||||
|
m_fuel_time = 0;
|
||||||
|
fuel_list->decrementMaterials(1);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else if(ItemSpec(ITEM_MATERIAL, CONTENT_FENCE).checkItem(fuel_item))
|
||||||
|
{
|
||||||
|
m_fuel_totaltime = 30/2;
|
||||||
|
m_fuel_time = 0;
|
||||||
|
fuel_list->decrementMaterials(1);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
else if(ItemSpec(ITEM_MATERIAL, CONTENT_WOOD).checkItem(fuel_item))
|
else if(ItemSpec(ITEM_MATERIAL, CONTENT_WOOD).checkItem(fuel_item))
|
||||||
{
|
{
|
||||||
m_fuel_totaltime = 30/4;
|
m_fuel_totaltime = 30/4;
|
||||||
@ -284,6 +298,41 @@ bool FurnaceNodeMetadata::step(float dtime)
|
|||||||
fuel_list->decrementMaterials(1);
|
fuel_list->decrementMaterials(1);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
else if(ItemSpec(ITEM_MATERIAL, CONTENT_BOOKSHELF).checkItem(fuel_item))
|
||||||
|
{
|
||||||
|
m_fuel_totaltime = 30/4;
|
||||||
|
m_fuel_time = 0;
|
||||||
|
fuel_list->decrementMaterials(1);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else if(ItemSpec(ITEM_MATERIAL, CONTENT_LEAVES).checkItem(fuel_item))
|
||||||
|
{
|
||||||
|
m_fuel_totaltime = 30/16;
|
||||||
|
m_fuel_time = 0;
|
||||||
|
fuel_list->decrementMaterials(1);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else if(ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS).checkItem(fuel_item))
|
||||||
|
{
|
||||||
|
m_fuel_totaltime = 30/32;
|
||||||
|
m_fuel_time = 0;
|
||||||
|
fuel_list->decrementMaterials(1);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else if(ItemSpec(ITEM_MATERIAL, CONTENT_JUNGLEGRASS).checkItem(fuel_item))
|
||||||
|
{
|
||||||
|
m_fuel_totaltime = 30/32;
|
||||||
|
m_fuel_time = 0;
|
||||||
|
fuel_list->decrementMaterials(1);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else if(ItemSpec(ITEM_MATERIAL, CONTENT_CACTUS).checkItem(fuel_item))
|
||||||
|
{
|
||||||
|
m_fuel_totaltime = 30/4;
|
||||||
|
m_fuel_time = 0;
|
||||||
|
fuel_list->decrementMaterials(1);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
else if(ItemSpec(ITEM_CRAFT, "Stick").checkItem(fuel_item))
|
else if(ItemSpec(ITEM_CRAFT, "Stick").checkItem(fuel_item))
|
||||||
{
|
{
|
||||||
m_fuel_totaltime = 30/4/4;
|
m_fuel_totaltime = 30/4/4;
|
||||||
|
@ -215,6 +215,18 @@ InventoryItem * ItemSAO::createInventoryItem()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemSAO::rightClick(Player *player)
|
||||||
|
{
|
||||||
|
dstream<<__FUNCTION_NAME<<std::endl;
|
||||||
|
InventoryItem *item = createInventoryItem();
|
||||||
|
if(item == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool to_be_deleted = item->use(m_env, player);
|
||||||
|
|
||||||
|
if(to_be_deleted)
|
||||||
|
m_removed = true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
RatSAO
|
RatSAO
|
||||||
@ -232,7 +244,7 @@ RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos):
|
|||||||
|
|
||||||
m_oldpos = v3f(0,0,0);
|
m_oldpos = v3f(0,0,0);
|
||||||
m_last_sent_position = v3f(0,0,0);
|
m_last_sent_position = v3f(0,0,0);
|
||||||
m_yaw = 0;
|
m_yaw = myrand_range(0,PI*2);
|
||||||
m_counter1 = 0;
|
m_counter1 = 0;
|
||||||
m_counter2 = 0;
|
m_counter2 = 0;
|
||||||
m_age = 0;
|
m_age = 0;
|
||||||
|
@ -51,6 +51,7 @@ public:
|
|||||||
std::string getStaticData();
|
std::string getStaticData();
|
||||||
InventoryItem* createInventoryItem();
|
InventoryItem* createInventoryItem();
|
||||||
InventoryItem* createPickedUpItem(){return createInventoryItem();}
|
InventoryItem* createPickedUpItem(){return createInventoryItem();}
|
||||||
|
void rightClick(Player *player);
|
||||||
private:
|
private:
|
||||||
std::string m_inventorystring;
|
std::string m_inventorystring;
|
||||||
v3f m_speed_f;
|
v3f m_speed_f;
|
||||||
|
@ -77,9 +77,10 @@ void set_default_settings()
|
|||||||
g_settings.setDefault("screenshot_path", ".");
|
g_settings.setDefault("screenshot_path", ".");
|
||||||
|
|
||||||
// Server stuff
|
// Server stuff
|
||||||
|
g_settings.setDefault("motd", "<Message of the day (motd) not set>");
|
||||||
g_settings.setDefault("enable_experimental", "false");
|
g_settings.setDefault("enable_experimental", "false");
|
||||||
g_settings.setDefault("creative_mode", "false");
|
g_settings.setDefault("creative_mode", "false");
|
||||||
g_settings.setDefault("enable_damage", "false"); //TODO: Set to true when healing is possible
|
g_settings.setDefault("enable_damage", "true");
|
||||||
g_settings.setDefault("give_initial_stuff", "false");
|
g_settings.setDefault("give_initial_stuff", "false");
|
||||||
g_settings.setDefault("default_password", "");
|
g_settings.setDefault("default_password", "");
|
||||||
g_settings.setDefault("default_privs", "build, shout");
|
g_settings.setDefault("default_privs", "build, shout");
|
||||||
|
@ -847,6 +847,21 @@ void ServerEnvironment::step(float dtime)
|
|||||||
*/
|
*/
|
||||||
// TODO: Implement usage of ActiveBlockModifier
|
// TODO: Implement usage of ActiveBlockModifier
|
||||||
|
|
||||||
|
// Find out how many objects the block contains
|
||||||
|
u32 active_object_count = block->m_static_objects.m_active.size();
|
||||||
|
// Find out how many objects this and all the neighbors contain
|
||||||
|
u32 active_object_count_wider = 0;
|
||||||
|
for(s16 x=-1; x<=1; x++)
|
||||||
|
for(s16 y=-1; y<=1; y++)
|
||||||
|
for(s16 z=-1; z<=1; z++)
|
||||||
|
{
|
||||||
|
MapBlock *block = m_map->getBlockNoCreateNoEx(p+v3s16(x,y,z));
|
||||||
|
if(block==NULL)
|
||||||
|
continue;
|
||||||
|
active_object_count_wider +=
|
||||||
|
block->m_static_objects.m_active.size();
|
||||||
|
}
|
||||||
|
|
||||||
v3s16 p0;
|
v3s16 p0;
|
||||||
for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
|
for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
|
||||||
for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
|
for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
|
||||||
@ -875,18 +890,39 @@ void ServerEnvironment::step(float dtime)
|
|||||||
/*
|
/*
|
||||||
Convert grass into mud if under something else than air
|
Convert grass into mud if under something else than air
|
||||||
*/
|
*/
|
||||||
else if(n.getContent() == CONTENT_GRASS)
|
if(n.getContent() == CONTENT_GRASS)
|
||||||
{
|
{
|
||||||
//if(myrand()%20 == 0)
|
//if(myrand()%20 == 0)
|
||||||
{
|
{
|
||||||
MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
|
MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
|
||||||
if(content_features(n_top).air_equivalent == false)
|
if(content_features(n_top).air_equivalent == false)
|
||||||
{
|
{
|
||||||
n.setContent(CONTENT_MUD);
|
n.setContent(CONTENT_MUD);
|
||||||
m_map->addNodeWithEvent(p, n);
|
m_map->addNodeWithEvent(p, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
Rats spawn around regular trees
|
||||||
|
*/
|
||||||
|
if(n.getContent() == CONTENT_TREE ||
|
||||||
|
n.getContent() == CONTENT_JUNGLETREE)
|
||||||
|
{
|
||||||
|
if(myrand()%200 == 0 && active_object_count_wider == 0)
|
||||||
|
{
|
||||||
|
v3s16 p1 = p + v3s16(myrand_range(-2, 2),
|
||||||
|
0, myrand_range(-2, 2));
|
||||||
|
MapNode n1 = m_map->getNodeNoEx(p1);
|
||||||
|
MapNode n1b = m_map->getNodeNoEx(p1+v3s16(0,-1,0));
|
||||||
|
if(n1b.getContent() == CONTENT_GRASS &&
|
||||||
|
n1.getContent() == CONTENT_AIR)
|
||||||
|
{
|
||||||
|
v3f pos = intToFloat(p1, BS);
|
||||||
|
ServerActiveObject *obj = new RatSAO(this, 0, pos);
|
||||||
|
addActiveObject(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -715,7 +715,8 @@ void the_game(
|
|||||||
std::string password,
|
std::string password,
|
||||||
std::string address,
|
std::string address,
|
||||||
u16 port,
|
u16 port,
|
||||||
std::wstring &error_message
|
std::wstring &error_message,
|
||||||
|
std::string configpath
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
video::IVideoDriver* driver = device->getVideoDriver();
|
video::IVideoDriver* driver = device->getVideoDriver();
|
||||||
@ -755,7 +756,7 @@ void the_game(
|
|||||||
if(address == ""){
|
if(address == ""){
|
||||||
draw_load_screen(L"Creating server...", driver, font);
|
draw_load_screen(L"Creating server...", driver, font);
|
||||||
std::cout<<DTIME<<"Creating server"<<std::endl;
|
std::cout<<DTIME<<"Creating server"<<std::endl;
|
||||||
server = new Server(map_dir);
|
server = new Server(map_dir, configpath);
|
||||||
server->start(port);
|
server->start(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1656,6 +1657,8 @@ void the_game(
|
|||||||
else if(input->getRightClicked())
|
else if(input->getRightClicked())
|
||||||
{
|
{
|
||||||
std::cout<<DTIME<<"Right-clicked object"<<std::endl;
|
std::cout<<DTIME<<"Right-clicked object"<<std::endl;
|
||||||
|
client.clickActiveObject(1,
|
||||||
|
selected_active_object->getId(), g_selected_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // selected_object == NULL
|
else // selected_object == NULL
|
||||||
@ -2021,7 +2024,7 @@ void the_game(
|
|||||||
endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;
|
endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;
|
||||||
|
|
||||||
char temptext[300];
|
char temptext[300];
|
||||||
snprintf(temptext, 300, "Minetest-delta %s ("
|
snprintf(temptext, 300, "Minetest-c55 %s ("
|
||||||
"R: range_all=%i"
|
"R: range_all=%i"
|
||||||
")"
|
")"
|
||||||
" drawtime=%.0f, beginscenetime=%.0f"
|
" drawtime=%.0f, beginscenetime=%.0f"
|
||||||
|
@ -70,7 +70,8 @@ void the_game(
|
|||||||
std::string password,
|
std::string password,
|
||||||
std::string address,
|
std::string address,
|
||||||
u16 port,
|
u16 port,
|
||||||
std::wstring &error_message
|
std::wstring &error_message,
|
||||||
|
std::string configpath
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Minetest-delta
|
Minetest-c55
|
||||||
Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
|
Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
|
||||||
Copyright (C) 2011 teddydestodes <derkomtur@schattengang.net>
|
Copyright (C) 2011 teddydestodes <derkomtur@schattengang.net>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Minetest-delta
|
Minetest-c55
|
||||||
Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
|
Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
|
||||||
Copyright (C) 2011 teddydestodes <derkomtur@schattengang.net>
|
Copyright (C) 2011 teddydestodes <derkomtur@schattengang.net>
|
||||||
|
@ -135,10 +135,10 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize)
|
|||||||
core::rect<s32> rect(0, 0, 180, 240);
|
core::rect<s32> rect(0, 0, 180, 240);
|
||||||
rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2);
|
rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2);
|
||||||
Environment->addStaticText(chartowchar_t(gettext(
|
Environment->addStaticText(chartowchar_t(gettext(
|
||||||
"Keys:\n"
|
"Default Controls:\n"
|
||||||
"- WASD: Walk\n"
|
"- WASD: Walk\n"
|
||||||
"- Mouse left: dig blocks\n"
|
"- Mouse left: dig/hit\n"
|
||||||
"- Mouse right: place blocks\n"
|
"- Mouse right: place/use\n"
|
||||||
"- Mouse wheel: select item\n"
|
"- Mouse wheel: select item\n"
|
||||||
"- 0...9: select item\n"
|
"- 0...9: select item\n"
|
||||||
"- Shift: sneak\n"
|
"- Shift: sneak\n"
|
||||||
|
@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "content_mapnode.h"
|
#include "content_mapnode.h"
|
||||||
#include "content_inventory.h"
|
#include "content_inventory.h"
|
||||||
#include "content_sao.h"
|
#include "content_sao.h"
|
||||||
|
#include "player.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
InventoryItem
|
InventoryItem
|
||||||
@ -168,6 +169,20 @@ InventoryItem *CraftItem::createCookResult()
|
|||||||
return item_craft_create_cook_result(m_subname);
|
return item_craft_create_cook_result(m_subname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CraftItem::use(ServerEnvironment *env, Player *player)
|
||||||
|
{
|
||||||
|
if(item_craft_is_eatable(m_subname))
|
||||||
|
{
|
||||||
|
s16 hp_change = item_craft_eat_hp_change(m_subname);
|
||||||
|
if(player->hp + hp_change > 20)
|
||||||
|
player->hp = 20;
|
||||||
|
else
|
||||||
|
player->hp += hp_change;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MapBlockObjectItem DEPRECATED
|
MapBlockObjectItem DEPRECATED
|
||||||
TODO: Remove
|
TODO: Remove
|
||||||
|
@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
class ServerActiveObject;
|
class ServerActiveObject;
|
||||||
class ServerEnvironment;
|
class ServerEnvironment;
|
||||||
|
class Player;
|
||||||
|
|
||||||
class InventoryItem
|
class InventoryItem
|
||||||
{
|
{
|
||||||
@ -99,13 +100,20 @@ public:
|
|||||||
/*
|
/*
|
||||||
Other properties
|
Other properties
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Whether it can be cooked
|
// Whether it can be cooked
|
||||||
virtual bool isCookable(){return false;}
|
virtual bool isCookable(){return false;}
|
||||||
// Time of cooking
|
// Time of cooking
|
||||||
virtual float getCookTime(){return 3.0;}
|
virtual float getCookTime(){return 3.0;}
|
||||||
// Result of cooking
|
// Result of cooking (can randomize)
|
||||||
virtual InventoryItem *createCookResult(){return NULL;}
|
virtual InventoryItem *createCookResult(){return NULL;}
|
||||||
|
|
||||||
|
// Eat, press, activate, whatever.
|
||||||
|
// Called when item is right-clicked when lying on ground.
|
||||||
|
// If returns true, item shall be deleted.
|
||||||
|
virtual bool use(ServerEnvironment *env,
|
||||||
|
Player *player){return false;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
u16 m_count;
|
u16 m_count;
|
||||||
};
|
};
|
||||||
@ -298,11 +306,16 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
return QUANTITY_ITEM_MAX_COUNT - m_count;
|
return QUANTITY_ITEM_MAX_COUNT - m_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Other properties
|
Other properties
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool isCookable();
|
bool isCookable();
|
||||||
InventoryItem *createCookResult();
|
InventoryItem *createCookResult();
|
||||||
|
|
||||||
|
bool use(ServerEnvironment *env, Player *player);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Special methods
|
Special methods
|
||||||
*/
|
*/
|
||||||
|
@ -1298,7 +1298,7 @@ int main(int argc, char *argv[])
|
|||||||
g_timegetter = new SimpleTimeGetter();
|
g_timegetter = new SimpleTimeGetter();
|
||||||
|
|
||||||
// Create server
|
// Create server
|
||||||
Server server(map_dir.c_str());
|
Server server(map_dir.c_str(), configpath);
|
||||||
server.start(port);
|
server.start(port);
|
||||||
|
|
||||||
// Run server
|
// Run server
|
||||||
@ -1637,7 +1637,8 @@ int main(int argc, char *argv[])
|
|||||||
password,
|
password,
|
||||||
address,
|
address,
|
||||||
port,
|
port,
|
||||||
error_message
|
error_message,
|
||||||
|
configpath
|
||||||
);
|
);
|
||||||
|
|
||||||
} //try
|
} //try
|
||||||
|
161
src/server.cpp
161
src/server.cpp
@ -1058,7 +1058,8 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Server::Server(
|
Server::Server(
|
||||||
std::string mapsavedir
|
std::string mapsavedir,
|
||||||
|
std::string configpath
|
||||||
):
|
):
|
||||||
m_env(new ServerMap(mapsavedir), this),
|
m_env(new ServerMap(mapsavedir), this),
|
||||||
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
||||||
@ -1069,6 +1070,7 @@ Server::Server(
|
|||||||
m_time_of_day_send_timer(0),
|
m_time_of_day_send_timer(0),
|
||||||
m_uptime(0),
|
m_uptime(0),
|
||||||
m_mapsavedir(mapsavedir),
|
m_mapsavedir(mapsavedir),
|
||||||
|
m_configpath(configpath),
|
||||||
m_shutdown_requested(false),
|
m_shutdown_requested(false),
|
||||||
m_ignore_map_edit_events(false),
|
m_ignore_map_edit_events(false),
|
||||||
m_ignore_map_edit_events_peer_id(0)
|
m_ignore_map_edit_events_peer_id(0)
|
||||||
@ -1964,9 +1966,27 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
derr_server<<DTIME<<"Server: Cannot negotiate "
|
derr_server<<DTIME<<"Server: Cannot negotiate "
|
||||||
"serialization version with peer "
|
"serialization version with peer "
|
||||||
<<peer_id<<std::endl;
|
<<peer_id<<std::endl;
|
||||||
|
SendAccessDenied(m_con, peer_id,
|
||||||
|
L"Your client is too old (map format)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check network protocol version
|
||||||
|
*/
|
||||||
|
u16 net_proto_version = 0;
|
||||||
|
if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
|
||||||
|
{
|
||||||
|
net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
|
||||||
|
}
|
||||||
|
getClient(peer->id)->net_proto_version = net_proto_version;
|
||||||
|
/*if(net_proto_version == 0)
|
||||||
|
{
|
||||||
|
SendAccessDenied(m_con, peer_id,
|
||||||
|
L"Your client is too old (network protocol)");
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set up player
|
Set up player
|
||||||
*/
|
*/
|
||||||
@ -1997,7 +2017,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
|
|
||||||
// Get password
|
// Get password
|
||||||
char password[PASSWORD_SIZE];
|
char password[PASSWORD_SIZE];
|
||||||
if(datasize == 2+1+PLAYERNAME_SIZE)
|
if(datasize >= 2+1+PLAYERNAME_SIZE)
|
||||||
{
|
{
|
||||||
// old version - assume blank password
|
// old version - assume blank password
|
||||||
password[0] = 0;
|
password[0] = 0;
|
||||||
@ -2162,6 +2182,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
BroadcastChatMessage(message);
|
BroadcastChatMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(getClient(peer->id)->net_proto_version == 0)
|
||||||
|
{
|
||||||
|
SendChatMessage(peer_id, L"# Server: NOTE: YOUR CLIENT IS OLD AND DOES NOT WORK PROPERLY WITH THIS SERVER");
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2368,75 +2393,92 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip if object has been removed
|
||||||
|
if(obj->m_removed)
|
||||||
|
return;
|
||||||
|
|
||||||
//TODO: Check that object is reasonably close
|
//TODO: Check that object is reasonably close
|
||||||
|
|
||||||
// Left click, pick object up (usually)
|
// Left click, pick object up (usually)
|
||||||
if(button == 0)
|
if(button == 0)
|
||||||
{
|
{
|
||||||
InventoryList *ilist = player->inventory.getList("main");
|
/*
|
||||||
if(g_settings.getBool("creative_mode") == false && ilist != NULL)
|
Try creating inventory item
|
||||||
|
*/
|
||||||
|
InventoryItem *item = obj->createPickedUpItem();
|
||||||
|
|
||||||
|
if(item)
|
||||||
{
|
{
|
||||||
|
InventoryList *ilist = player->inventory.getList("main");
|
||||||
// Skip if inventory has no free space
|
if(ilist != NULL)
|
||||||
if(ilist->getUsedSlots() == ilist->getSize())
|
|
||||||
{
|
{
|
||||||
dout_server<<"Player inventory has no free space"<<std::endl;
|
if(g_settings.getBool("creative_mode") == false)
|
||||||
return;
|
{
|
||||||
}
|
// Skip if inventory has no free space
|
||||||
|
if(ilist->getUsedSlots() == ilist->getSize())
|
||||||
|
{
|
||||||
|
dout_server<<"Player inventory has no free space"<<std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip if object has been removed
|
// Add to inventory and send inventory
|
||||||
if(obj->m_removed)
|
ilist->addItem(item);
|
||||||
return;
|
UpdateCrafting(player->peer_id);
|
||||||
|
SendInventory(player->peer_id);
|
||||||
/*
|
}
|
||||||
Create the inventory item
|
|
||||||
*/
|
|
||||||
InventoryItem *item = obj->createPickedUpItem();
|
|
||||||
|
|
||||||
if(item)
|
|
||||||
{
|
|
||||||
// Add to inventory and send inventory
|
|
||||||
ilist->addItem(item);
|
|
||||||
UpdateCrafting(player->peer_id);
|
|
||||||
SendInventory(player->peer_id);
|
|
||||||
|
|
||||||
// Remove object from environment
|
// Remove object from environment
|
||||||
obj->m_removed = true;
|
obj->m_removed = true;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Item cannot be picked up. Punch it instead.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ToolItem *titem = NULL;
|
||||||
|
std::string toolname = "";
|
||||||
|
|
||||||
|
InventoryList *mlist = player->inventory.getList("main");
|
||||||
|
if(mlist != NULL)
|
||||||
{
|
{
|
||||||
/*
|
InventoryItem *item = mlist->getItem(item_i);
|
||||||
Item cannot be picked up. Punch it instead.
|
if(item && (std::string)item->getName() == "ToolItem")
|
||||||
*/
|
|
||||||
|
|
||||||
ToolItem *titem = NULL;
|
|
||||||
std::string toolname = "";
|
|
||||||
|
|
||||||
InventoryList *mlist = player->inventory.getList("main");
|
|
||||||
if(mlist != NULL)
|
|
||||||
{
|
{
|
||||||
InventoryItem *item = mlist->getItem(item_i);
|
titem = (ToolItem*)item;
|
||||||
if(item && (std::string)item->getName() == "ToolItem")
|
toolname = titem->getToolName();
|
||||||
{
|
|
||||||
titem = (ToolItem*)item;
|
|
||||||
toolname = titem->getToolName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
v3f playerpos = player->getPosition();
|
|
||||||
v3f objpos = obj->getBasePosition();
|
|
||||||
v3f dir = (objpos - playerpos).normalize();
|
|
||||||
|
|
||||||
u16 wear = obj->punch(toolname, dir);
|
|
||||||
|
|
||||||
if(titem)
|
|
||||||
{
|
|
||||||
bool weared_out = titem->addWear(wear);
|
|
||||||
if(weared_out)
|
|
||||||
mlist->deleteItem(item_i);
|
|
||||||
SendInventory(player->peer_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v3f playerpos = player->getPosition();
|
||||||
|
v3f objpos = obj->getBasePosition();
|
||||||
|
v3f dir = (objpos - playerpos).normalize();
|
||||||
|
|
||||||
|
u16 wear = obj->punch(toolname, dir);
|
||||||
|
|
||||||
|
if(titem)
|
||||||
|
{
|
||||||
|
bool weared_out = titem->addWear(wear);
|
||||||
|
if(weared_out)
|
||||||
|
mlist->deleteItem(item_i);
|
||||||
|
SendInventory(player->peer_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Right click, do something with object
|
||||||
|
if(button == 1)
|
||||||
|
{
|
||||||
|
// Track hp changes super-crappily
|
||||||
|
u16 oldhp = player->hp;
|
||||||
|
|
||||||
|
// Do stuff
|
||||||
|
obj->rightClick(player);
|
||||||
|
|
||||||
|
// Send back stuff
|
||||||
|
if(player->hp != oldhp)
|
||||||
|
{
|
||||||
|
SendPlayerHP(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3180,8 +3222,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
|
|
||||||
message = message.substr(commandprefix.size());
|
message = message.substr(commandprefix.size());
|
||||||
|
|
||||||
|
WStrfnd f1(message);
|
||||||
|
f1.next(L" "); // Skip over /#whatever
|
||||||
|
std::wstring paramstring = f1.next(L"");
|
||||||
|
|
||||||
ServerCommandContext *ctx = new ServerCommandContext(
|
ServerCommandContext *ctx = new ServerCommandContext(
|
||||||
str_split(message, L' '),
|
str_split(message, L' '),
|
||||||
|
paramstring,
|
||||||
this,
|
this,
|
||||||
&m_env,
|
&m_env,
|
||||||
player,
|
player,
|
||||||
@ -4001,7 +4048,9 @@ std::wstring Server::getStatusString()
|
|||||||
}
|
}
|
||||||
os<<L"}";
|
os<<L"}";
|
||||||
if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
|
if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
|
||||||
os<<" WARNING: Map saving is disabled."<<std::endl;
|
os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
|
||||||
|
if(g_settings.get("motd") != "")
|
||||||
|
os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings.get("motd"));
|
||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
src/server.h
16
src/server.h
@ -235,6 +235,8 @@ public:
|
|||||||
u16 peer_id;
|
u16 peer_id;
|
||||||
// The serialization version to use with the client
|
// The serialization version to use with the client
|
||||||
u8 serialization_version;
|
u8 serialization_version;
|
||||||
|
//
|
||||||
|
u16 net_proto_version;
|
||||||
// Version is stored in here after INIT before INIT2
|
// Version is stored in here after INIT before INIT2
|
||||||
u8 pending_serialization_version;
|
u8 pending_serialization_version;
|
||||||
|
|
||||||
@ -244,6 +246,7 @@ public:
|
|||||||
{
|
{
|
||||||
peer_id = 0;
|
peer_id = 0;
|
||||||
serialization_version = SER_FMT_VER_INVALID;
|
serialization_version = SER_FMT_VER_INVALID;
|
||||||
|
net_proto_version = 0;
|
||||||
pending_serialization_version = SER_FMT_VER_INVALID;
|
pending_serialization_version = SER_FMT_VER_INVALID;
|
||||||
m_nearest_unsent_d = 0;
|
m_nearest_unsent_d = 0;
|
||||||
m_nearest_unsent_reset_timer = 0.0;
|
m_nearest_unsent_reset_timer = 0.0;
|
||||||
@ -364,7 +367,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Server(
|
Server(
|
||||||
std::string mapsavedir
|
std::string mapsavedir,
|
||||||
|
std::string configpath
|
||||||
);
|
);
|
||||||
~Server();
|
~Server();
|
||||||
void start(unsigned short port);
|
void start(unsigned short port);
|
||||||
@ -444,6 +448,13 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Saves g_settings to configpath given at initialization
|
||||||
|
void saveConfig()
|
||||||
|
{
|
||||||
|
if(m_configpath != "")
|
||||||
|
g_settings.updateConfigFile(m_configpath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// con::PeerHandler implementation.
|
// con::PeerHandler implementation.
|
||||||
@ -606,6 +617,9 @@ private:
|
|||||||
// Map directory
|
// Map directory
|
||||||
std::string m_mapsavedir;
|
std::string m_mapsavedir;
|
||||||
|
|
||||||
|
// Configuration path ("" = no configuration file)
|
||||||
|
std::string m_configpath;
|
||||||
|
|
||||||
bool m_shutdown_requested;
|
bool m_shutdown_requested;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -142,9 +142,16 @@ void cmd_setting(std::wostringstream &os,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string confline = wide_to_narrow(ctx->parms[1] + L" = " + ctx->parms[2]);
|
/*std::string confline = wide_to_narrow(
|
||||||
|
ctx->parms[1] + L" = " + ctx->params[2]);*/
|
||||||
|
|
||||||
|
std::string confline = wide_to_narrow(ctx->paramstring);
|
||||||
|
|
||||||
g_settings.parseConfigLine(confline);
|
g_settings.parseConfigLine(confline);
|
||||||
os<< L"-!- Setting changed.";
|
|
||||||
|
ctx->server->saveConfig();
|
||||||
|
|
||||||
|
os<< L"-!- Setting changed and configuration saved.";
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_teleport(std::wostringstream &os,
|
void cmd_teleport(std::wostringstream &os,
|
||||||
|
@ -29,6 +29,7 @@ struct ServerCommandContext
|
|||||||
{
|
{
|
||||||
|
|
||||||
std::vector<std::wstring> parms;
|
std::vector<std::wstring> parms;
|
||||||
|
std::wstring paramstring;
|
||||||
Server* server;
|
Server* server;
|
||||||
ServerEnvironment *env;
|
ServerEnvironment *env;
|
||||||
Player* player;
|
Player* player;
|
||||||
@ -39,11 +40,13 @@ struct ServerCommandContext
|
|||||||
|
|
||||||
ServerCommandContext(
|
ServerCommandContext(
|
||||||
std::vector<std::wstring> parms,
|
std::vector<std::wstring> parms,
|
||||||
|
std::wstring paramstring,
|
||||||
Server* server,
|
Server* server,
|
||||||
ServerEnvironment *env,
|
ServerEnvironment *env,
|
||||||
Player* player,
|
Player* player,
|
||||||
u64 privs)
|
u64 privs)
|
||||||
: parms(parms), server(server), env(env), player(player), privs(privs)
|
: parms(parms), paramstring(paramstring),
|
||||||
|
server(server), env(env), player(player), privs(privs)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +323,7 @@ int main(int argc, char *argv[])
|
|||||||
map_dir = g_settings.get("map-dir");
|
map_dir = g_settings.get("map-dir");
|
||||||
|
|
||||||
// Create server
|
// Create server
|
||||||
Server server(map_dir.c_str());
|
Server server(map_dir.c_str(), configpath);
|
||||||
server.start(port);
|
server.start(port);
|
||||||
|
|
||||||
// Run server
|
// Run server
|
||||||
|
@ -42,6 +42,7 @@ Some planning
|
|||||||
|
|
||||||
class ServerEnvironment;
|
class ServerEnvironment;
|
||||||
class InventoryItem;
|
class InventoryItem;
|
||||||
|
class Player;
|
||||||
|
|
||||||
class ServerActiveObject : public ActiveObject
|
class ServerActiveObject : public ActiveObject
|
||||||
{
|
{
|
||||||
@ -106,6 +107,10 @@ public:
|
|||||||
virtual u16 punch(const std::string &toolname, v3f dir)
|
virtual u16 punch(const std::string &toolname, v3f dir)
|
||||||
{return 0;}
|
{return 0;}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
virtual void rightClick(Player *player){}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Number of players which know about this object. Object won't be
|
Number of players which know about this object. Object won't be
|
||||||
deleted until this is 0 to keep the id preserved for the right
|
deleted until this is 0 to keep the id preserved for the right
|
||||||
|
50
src/strfnd.h
50
src/strfnd.h
@ -74,6 +74,56 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WStrfnd{
|
||||||
|
std::wstring tek;
|
||||||
|
unsigned int p;
|
||||||
|
public:
|
||||||
|
void start(std::wstring niinq){
|
||||||
|
tek = niinq;
|
||||||
|
p=0;
|
||||||
|
}
|
||||||
|
unsigned int where(){
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
void to(unsigned int i){
|
||||||
|
p = i;
|
||||||
|
}
|
||||||
|
std::wstring what(){
|
||||||
|
return tek;
|
||||||
|
}
|
||||||
|
std::wstring next(std::wstring plop){
|
||||||
|
//std::cout<<"tek=\""<<tek<<"\" plop=\""<<plop<<"\""<<std::endl;
|
||||||
|
size_t n;
|
||||||
|
std::wstring palautus;
|
||||||
|
if (p < tek.size())
|
||||||
|
{
|
||||||
|
//std::cout<<"\tp<tek.size()"<<std::endl;
|
||||||
|
if ((n = tek.find(plop, p)) == std::wstring::npos || plop == L"")
|
||||||
|
{
|
||||||
|
//std::cout<<"\t\tn == string::npos || plop == \"\""<<std::endl;
|
||||||
|
n = tek.size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//std::cout<<"\t\tn != string::npos"<<std::endl;
|
||||||
|
}
|
||||||
|
palautus = tek.substr(p, n-p);
|
||||||
|
p = n + plop.length();
|
||||||
|
}
|
||||||
|
//else
|
||||||
|
//std::cout<<"\tp>=tek.size()"<<std::endl;
|
||||||
|
//std::cout<<"palautus=\""<<palautus<<"\""<<std::endl;
|
||||||
|
return palautus;
|
||||||
|
}
|
||||||
|
bool atend(){
|
||||||
|
if(p>=tek.size()) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WStrfnd(std::wstring s){
|
||||||
|
start(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
inline std::string trim(const std::string &s)
|
inline std::string trim(const std::string &s)
|
||||||
{
|
{
|
||||||
std::string str = s;
|
std::string str = s;
|
||||||
|
Loading…
Reference in New Issue
Block a user