mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01:00 
			
		
		
		
	Merge branch 'upstream/master'
This commit is contained in:
		@@ -9,7 +9,7 @@ project(minetest-delta)
 | 
			
		||||
 | 
			
		||||
set(VERSION_MAJOR 0)
 | 
			
		||||
set(VERSION_MINOR 2)
 | 
			
		||||
set(VERSION_PATCH 20110720_0)
 | 
			
		||||
set(VERSION_PATCH 20110730_rc1)
 | 
			
		||||
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
 | 
			
		||||
 | 
			
		||||
# Configuration options
 | 
			
		||||
 
 | 
			
		||||
@@ -415,8 +415,9 @@ void Client::step(float dtime)
 | 
			
		||||
			// [0] u16 TOSERVER_INIT
 | 
			
		||||
			// [2] u8 SER_FMT_VER_HIGHEST
 | 
			
		||||
			// [3] u8[20] player_name
 | 
			
		||||
			// [23] u8[28] password
 | 
			
		||||
			SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE);
 | 
			
		||||
			// [23] u8[28] password (new in some version)
 | 
			
		||||
			// [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);
 | 
			
		||||
			writeU8(&data[2], SER_FMT_VER_HIGHEST);
 | 
			
		||||
 | 
			
		||||
@@ -428,6 +429,9 @@ void Client::step(float dtime)
 | 
			
		||||
 | 
			
		||||
			memset((char*)&data[23], 0, PASSWORD_SIZE);
 | 
			
		||||
			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(0, data, false);
 | 
			
		||||
 
 | 
			
		||||
@@ -171,7 +171,8 @@ enum ToServerCommand
 | 
			
		||||
		[0] u16 TOSERVER_INIT
 | 
			
		||||
		[2] u8 SER_FMT_VER_HIGHEST
 | 
			
		||||
		[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,
 | 
			
		||||
 
 | 
			
		||||
@@ -187,7 +187,8 @@ public:
 | 
			
		||||
	core::aabbox3d<f32>* getSelectionBox()
 | 
			
		||||
		{return &m_selection_box;}
 | 
			
		||||
	v3f getPosition()
 | 
			
		||||
		{return m_position;}
 | 
			
		||||
		{return pos_translator.vect_show;}
 | 
			
		||||
		//{return m_position;}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	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";
 | 
			
		||||
	else if(subname == "rat")
 | 
			
		||||
		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")
 | 
			
		||||
		return "firefly.png";
 | 
			
		||||
	else
 | 
			
		||||
@@ -98,7 +102,7 @@ s16 item_craft_get_drop_count(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 false;
 | 
			
		||||
@@ -110,7 +114,26 @@ InventoryItem* item_craft_create_cook_result(const std::string &subname)
 | 
			
		||||
		return new CraftItem("steel_ingot", 1);
 | 
			
		||||
	else if(subname == "lump_of_clay")
 | 
			
		||||
		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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
bool                item_craft_is_cookable(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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -277,6 +277,20 @@ bool FurnaceNodeMetadata::step(float dtime)
 | 
			
		||||
			fuel_list->decrementMaterials(1);
 | 
			
		||||
			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))
 | 
			
		||||
		{
 | 
			
		||||
			m_fuel_totaltime = 30/4;
 | 
			
		||||
@@ -284,6 +298,41 @@ bool FurnaceNodeMetadata::step(float dtime)
 | 
			
		||||
			fuel_list->decrementMaterials(1);
 | 
			
		||||
			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))
 | 
			
		||||
		{
 | 
			
		||||
			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
 | 
			
		||||
@@ -232,7 +244,7 @@ RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos):
 | 
			
		||||
 | 
			
		||||
	m_oldpos = 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_counter2 = 0;
 | 
			
		||||
	m_age = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,7 @@ public:
 | 
			
		||||
	std::string getStaticData();
 | 
			
		||||
	InventoryItem* createInventoryItem();
 | 
			
		||||
	InventoryItem* createPickedUpItem(){return createInventoryItem();}
 | 
			
		||||
	void rightClick(Player *player);
 | 
			
		||||
private:
 | 
			
		||||
	std::string m_inventorystring;
 | 
			
		||||
	v3f m_speed_f;
 | 
			
		||||
 
 | 
			
		||||
@@ -77,9 +77,10 @@ void set_default_settings()
 | 
			
		||||
	g_settings.setDefault("screenshot_path", ".");
 | 
			
		||||
 | 
			
		||||
	// Server stuff
 | 
			
		||||
	g_settings.setDefault("motd", "<Message of the day (motd) not set>");
 | 
			
		||||
	g_settings.setDefault("enable_experimental", "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("default_password", "");
 | 
			
		||||
	g_settings.setDefault("default_privs", "build, shout");
 | 
			
		||||
 
 | 
			
		||||
@@ -816,7 +816,7 @@ void ServerEnvironment::step(float dtime)
 | 
			
		||||
	if(m_active_blocks_test_interval.step(dtime, 10.0))
 | 
			
		||||
	{
 | 
			
		||||
		//float dtime = 10.0;
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		for(core::map<v3s16, bool>::Iterator
 | 
			
		||||
				i = m_active_blocks.m_list.getIterator();
 | 
			
		||||
				i.atEnd()==false; i++)
 | 
			
		||||
@@ -846,6 +846,21 @@ void ServerEnvironment::step(float dtime)
 | 
			
		||||
				searching loop to keep things fast.
 | 
			
		||||
			*/
 | 
			
		||||
			// 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;
 | 
			
		||||
			for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
 | 
			
		||||
@@ -875,18 +890,39 @@ void ServerEnvironment::step(float dtime)
 | 
			
		||||
				/*
 | 
			
		||||
					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)
 | 
			
		||||
					{
 | 
			
		||||
						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);
 | 
			
		||||
							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 address,
 | 
			
		||||
	u16 port,
 | 
			
		||||
	std::wstring &error_message
 | 
			
		||||
	std::wstring &error_message,
 | 
			
		||||
    std::string configpath
 | 
			
		||||
)
 | 
			
		||||
{
 | 
			
		||||
	video::IVideoDriver* driver = device->getVideoDriver();
 | 
			
		||||
@@ -755,7 +756,7 @@ void the_game(
 | 
			
		||||
	if(address == ""){
 | 
			
		||||
		draw_load_screen(L"Creating server...", driver, font);
 | 
			
		||||
		std::cout<<DTIME<<"Creating server"<<std::endl;
 | 
			
		||||
		server = new Server(map_dir);
 | 
			
		||||
		server = new Server(map_dir, configpath);
 | 
			
		||||
		server->start(port);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
@@ -1656,6 +1657,8 @@ void the_game(
 | 
			
		||||
			else if(input->getRightClicked())
 | 
			
		||||
			{
 | 
			
		||||
				std::cout<<DTIME<<"Right-clicked object"<<std::endl;
 | 
			
		||||
				client.clickActiveObject(1,
 | 
			
		||||
						selected_active_object->getId(), g_selected_item);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else // selected_object == NULL
 | 
			
		||||
@@ -2021,7 +2024,7 @@ void the_game(
 | 
			
		||||
			endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;
 | 
			
		||||
			
 | 
			
		||||
			char temptext[300];
 | 
			
		||||
			snprintf(temptext, 300, "Minetest-delta %s ("
 | 
			
		||||
			snprintf(temptext, 300, "Minetest-c55 %s ("
 | 
			
		||||
					"R: range_all=%i"
 | 
			
		||||
					")"
 | 
			
		||||
					" drawtime=%.0f, beginscenetime=%.0f"
 | 
			
		||||
 
 | 
			
		||||
@@ -70,7 +70,8 @@ void the_game(
 | 
			
		||||
	std::string password,
 | 
			
		||||
	std::string address,
 | 
			
		||||
	u16 port,
 | 
			
		||||
	std::wstring &error_message
 | 
			
		||||
	std::wstring &error_message,
 | 
			
		||||
	std::string configpath
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 Minetest-delta
 | 
			
		||||
 Minetest-c55
 | 
			
		||||
 Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
 | 
			
		||||
 Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
 | 
			
		||||
 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) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
 | 
			
		||||
 Copyright (C) 2011 teddydestodes <derkomtur@schattengang.net>
 | 
			
		||||
 
 | 
			
		||||
@@ -135,10 +135,10 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize)
 | 
			
		||||
		core::rect<s32> rect(0, 0, 180, 240);
 | 
			
		||||
		rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2);
 | 
			
		||||
		Environment->addStaticText(chartowchar_t(gettext(
 | 
			
		||||
		"Keys:\n"
 | 
			
		||||
		"Default Controls:\n"
 | 
			
		||||
		"- WASD: Walk\n"
 | 
			
		||||
		"- Mouse left: dig blocks\n"
 | 
			
		||||
		"- Mouse right: place blocks\n"
 | 
			
		||||
		"- Mouse left: dig/hit\n"
 | 
			
		||||
		"- Mouse right: place/use\n"
 | 
			
		||||
		"- Mouse wheel: select item\n"
 | 
			
		||||
		"- 0...9: select item\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_inventory.h"
 | 
			
		||||
#include "content_sao.h"
 | 
			
		||||
#include "player.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	InventoryItem
 | 
			
		||||
@@ -168,6 +169,20 @@ InventoryItem *CraftItem::createCookResult()
 | 
			
		||||
	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
 | 
			
		||||
	TODO: Remove
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
 | 
			
		||||
class ServerActiveObject;
 | 
			
		||||
class ServerEnvironment;
 | 
			
		||||
class Player;
 | 
			
		||||
 | 
			
		||||
class InventoryItem
 | 
			
		||||
{
 | 
			
		||||
@@ -99,12 +100,19 @@ public:
 | 
			
		||||
	/*
 | 
			
		||||
		Other properties
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	// Whether it can be cooked
 | 
			
		||||
	virtual bool isCookable(){return false;}
 | 
			
		||||
	// Time of cooking
 | 
			
		||||
	virtual float getCookTime(){return 3.0;}
 | 
			
		||||
	// Result of cooking
 | 
			
		||||
	// Result of cooking (can randomize)
 | 
			
		||||
	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:
 | 
			
		||||
	u16 m_count;
 | 
			
		||||
@@ -298,11 +306,16 @@ public:
 | 
			
		||||
			return 0;
 | 
			
		||||
		return QUANTITY_ITEM_MAX_COUNT - m_count;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		Other properties
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	bool isCookable();
 | 
			
		||||
	InventoryItem *createCookResult();
 | 
			
		||||
 | 
			
		||||
	bool use(ServerEnvironment *env, Player *player);
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
		Special methods
 | 
			
		||||
	*/
 | 
			
		||||
 
 | 
			
		||||
@@ -1298,7 +1298,7 @@ int main(int argc, char *argv[])
 | 
			
		||||
		g_timegetter = new SimpleTimeGetter();
 | 
			
		||||
		
 | 
			
		||||
		// Create server
 | 
			
		||||
		Server server(map_dir.c_str());
 | 
			
		||||
		Server server(map_dir.c_str(), configpath);
 | 
			
		||||
		server.start(port);
 | 
			
		||||
		
 | 
			
		||||
		// Run server
 | 
			
		||||
@@ -1637,7 +1637,8 @@ int main(int argc, char *argv[])
 | 
			
		||||
				password,
 | 
			
		||||
				address,
 | 
			
		||||
				port,
 | 
			
		||||
				error_message
 | 
			
		||||
				error_message,
 | 
			
		||||
				configpath
 | 
			
		||||
			);
 | 
			
		||||
 | 
			
		||||
		} //try
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										161
									
								
								src/server.cpp
									
									
									
									
									
								
							
							
						
						
									
										161
									
								
								src/server.cpp
									
									
									
									
									
								
							@@ -1058,7 +1058,8 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
Server::Server(
 | 
			
		||||
		std::string mapsavedir
 | 
			
		||||
		std::string mapsavedir,
 | 
			
		||||
		std::string configpath
 | 
			
		||||
	):
 | 
			
		||||
	m_env(new ServerMap(mapsavedir), this),
 | 
			
		||||
	m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
 | 
			
		||||
@@ -1069,6 +1070,7 @@ Server::Server(
 | 
			
		||||
	m_time_of_day_send_timer(0),
 | 
			
		||||
	m_uptime(0),
 | 
			
		||||
	m_mapsavedir(mapsavedir),
 | 
			
		||||
	m_configpath(configpath),
 | 
			
		||||
	m_shutdown_requested(false),
 | 
			
		||||
	m_ignore_map_edit_events(false),
 | 
			
		||||
	m_ignore_map_edit_events_peer_id(0)
 | 
			
		||||
@@ -1964,8 +1966,26 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 | 
			
		||||
			derr_server<<DTIME<<"Server: Cannot negotiate "
 | 
			
		||||
					"serialization version with peer "
 | 
			
		||||
					<<peer_id<<std::endl;
 | 
			
		||||
			SendAccessDenied(m_con, peer_id,
 | 
			
		||||
					L"Your client is too old (map format)");
 | 
			
		||||
			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
 | 
			
		||||
@@ -1997,7 +2017,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 | 
			
		||||
 | 
			
		||||
		// Get password
 | 
			
		||||
		char password[PASSWORD_SIZE];
 | 
			
		||||
		if(datasize == 2+1+PLAYERNAME_SIZE)
 | 
			
		||||
		if(datasize >= 2+1+PLAYERNAME_SIZE)
 | 
			
		||||
		{
 | 
			
		||||
			// old version - assume blank password
 | 
			
		||||
			password[0] = 0;
 | 
			
		||||
@@ -2162,6 +2182,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 | 
			
		||||
			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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -2368,75 +2393,92 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Skip if object has been removed
 | 
			
		||||
		if(obj->m_removed)
 | 
			
		||||
			return;
 | 
			
		||||
		
 | 
			
		||||
		//TODO: Check that object is reasonably close
 | 
			
		||||
		
 | 
			
		||||
		// Left click, pick object up (usually)
 | 
			
		||||
		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();
 | 
			
		||||
			
 | 
			
		||||
				// Skip if inventory has no free space
 | 
			
		||||
				if(ilist->getUsedSlots() == ilist->getSize())
 | 
			
		||||
			if(item)
 | 
			
		||||
			{
 | 
			
		||||
				InventoryList *ilist = player->inventory.getList("main");
 | 
			
		||||
				if(ilist != NULL)
 | 
			
		||||
				{
 | 
			
		||||
					dout_server<<"Player inventory has no free space"<<std::endl;
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
					if(g_settings.getBool("creative_mode") == false)
 | 
			
		||||
					{
 | 
			
		||||
						// 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
 | 
			
		||||
				if(obj->m_removed)
 | 
			
		||||
					return;
 | 
			
		||||
				
 | 
			
		||||
				/*
 | 
			
		||||
					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);
 | 
			
		||||
						// Add to inventory and send inventory
 | 
			
		||||
						ilist->addItem(item);
 | 
			
		||||
						UpdateCrafting(player->peer_id);
 | 
			
		||||
						SendInventory(player->peer_id);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// Remove object from environment
 | 
			
		||||
					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)
 | 
			
		||||
				{
 | 
			
		||||
					/*
 | 
			
		||||
						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);
 | 
			
		||||
					if(item && (std::string)item->getName() == "ToolItem")
 | 
			
		||||
					{
 | 
			
		||||
						InventoryItem *item = mlist->getItem(item_i);
 | 
			
		||||
						if(item && (std::string)item->getName() == "ToolItem")
 | 
			
		||||
						{
 | 
			
		||||
							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);
 | 
			
		||||
						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);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// 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);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -3179,9 +3221,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 | 
			
		||||
			line += L"Server: ";
 | 
			
		||||
 | 
			
		||||
			message = message.substr(commandprefix.size());
 | 
			
		||||
			
 | 
			
		||||
			WStrfnd f1(message);
 | 
			
		||||
			f1.next(L" "); // Skip over /#whatever
 | 
			
		||||
			std::wstring paramstring = f1.next(L"");
 | 
			
		||||
 | 
			
		||||
			ServerCommandContext *ctx = new ServerCommandContext(
 | 
			
		||||
				str_split(message, L' '),
 | 
			
		||||
				paramstring,
 | 
			
		||||
				this,
 | 
			
		||||
				&m_env,
 | 
			
		||||
				player,
 | 
			
		||||
@@ -4001,7 +4048,9 @@ std::wstring Server::getStatusString()
 | 
			
		||||
	}
 | 
			
		||||
	os<<L"}";
 | 
			
		||||
	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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								src/server.h
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/server.h
									
									
									
									
									
								
							@@ -235,6 +235,8 @@ public:
 | 
			
		||||
	u16 peer_id;
 | 
			
		||||
	// The serialization version to use with the client
 | 
			
		||||
	u8 serialization_version;
 | 
			
		||||
	//
 | 
			
		||||
	u16 net_proto_version;
 | 
			
		||||
	// Version is stored in here after INIT before INIT2
 | 
			
		||||
	u8 pending_serialization_version;
 | 
			
		||||
 | 
			
		||||
@@ -244,6 +246,7 @@ public:
 | 
			
		||||
	{
 | 
			
		||||
		peer_id = 0;
 | 
			
		||||
		serialization_version = SER_FMT_VER_INVALID;
 | 
			
		||||
		net_proto_version = 0;
 | 
			
		||||
		pending_serialization_version = SER_FMT_VER_INVALID;
 | 
			
		||||
		m_nearest_unsent_d = 0;
 | 
			
		||||
		m_nearest_unsent_reset_timer = 0.0;
 | 
			
		||||
@@ -364,7 +367,8 @@ public:
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	Server(
 | 
			
		||||
		std::string mapsavedir
 | 
			
		||||
		std::string mapsavedir,
 | 
			
		||||
		std::string configpath
 | 
			
		||||
	);
 | 
			
		||||
	~Server();
 | 
			
		||||
	void start(unsigned short port);
 | 
			
		||||
@@ -443,6 +447,13 @@ public:
 | 
			
		||||
			dstream<<"WARNING: Auth not found for "<<name<<std::endl;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Saves g_settings to configpath given at initialization
 | 
			
		||||
	void saveConfig()
 | 
			
		||||
	{
 | 
			
		||||
		if(m_configpath != "")
 | 
			
		||||
			g_settings.updateConfigFile(m_configpath.c_str());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
@@ -606,6 +617,9 @@ private:
 | 
			
		||||
	// Map directory
 | 
			
		||||
	std::string m_mapsavedir;
 | 
			
		||||
 | 
			
		||||
	// Configuration path ("" = no configuration file)
 | 
			
		||||
	std::string m_configpath;
 | 
			
		||||
 | 
			
		||||
	bool m_shutdown_requested;
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
 
 | 
			
		||||
@@ -142,9 +142,16 @@ void cmd_setting(std::wostringstream &os,
 | 
			
		||||
		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);
 | 
			
		||||
	os<< L"-!- Setting changed.";
 | 
			
		||||
	
 | 
			
		||||
	ctx->server->saveConfig();
 | 
			
		||||
 | 
			
		||||
	os<< L"-!- Setting changed and configuration saved.";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cmd_teleport(std::wostringstream &os,
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ struct ServerCommandContext
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	std::vector<std::wstring> parms;
 | 
			
		||||
	std::wstring paramstring;
 | 
			
		||||
	Server* server;
 | 
			
		||||
	ServerEnvironment *env;
 | 
			
		||||
	Player* player;
 | 
			
		||||
@@ -39,11 +40,13 @@ struct ServerCommandContext
 | 
			
		||||
 | 
			
		||||
	ServerCommandContext(
 | 
			
		||||
		std::vector<std::wstring> parms,
 | 
			
		||||
		std::wstring paramstring,
 | 
			
		||||
		Server* server,
 | 
			
		||||
		ServerEnvironment *env,
 | 
			
		||||
		Player* player,
 | 
			
		||||
		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");
 | 
			
		||||
	
 | 
			
		||||
	// Create server
 | 
			
		||||
	Server server(map_dir.c_str());
 | 
			
		||||
	Server server(map_dir.c_str(), configpath);
 | 
			
		||||
	server.start(port);
 | 
			
		||||
 | 
			
		||||
	// Run server
 | 
			
		||||
 
 | 
			
		||||
@@ -42,6 +42,7 @@ Some planning
 | 
			
		||||
 | 
			
		||||
class ServerEnvironment;
 | 
			
		||||
class InventoryItem;
 | 
			
		||||
class Player;
 | 
			
		||||
 | 
			
		||||
class ServerActiveObject : public ActiveObject
 | 
			
		||||
{
 | 
			
		||||
@@ -105,6 +106,10 @@ public:
 | 
			
		||||
	*/
 | 
			
		||||
	virtual u16 punch(const std::string &toolname, v3f dir)
 | 
			
		||||
	{return 0;}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	*/
 | 
			
		||||
	virtual void rightClick(Player *player){}
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
		Number of players which know about this object. Object won't be
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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)
 | 
			
		||||
{
 | 
			
		||||
	std::string str = s;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user