Exemplo n.º 1
0
// Calculate lighting at the XYZ- corner of p
u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio)
{
	u16 ambient_occlusion = 0;
	u16 light = 0;
	u16 light_count = 0;
	for(u32 i=0; i<8; i++)
	{
		MapNode n = vmanip.getNodeNoEx(p - dirs8[i]);
		if(content_features(n.d).param_type == CPT_LIGHT
				// Fast-style leaves look better this way
				&& content_features(n.d).solidness != 2)
		{
			light += decode_light(n.getLightBlend(daynight_ratio));
			light_count++;
		}
		else
		{
			if(n.d != CONTENT_IGNORE)
				ambient_occlusion++;
		}
	}

	if(light_count == 0)
		return 255;
	
	light /= light_count;

	if(ambient_occlusion > 4)
	{
		ambient_occlusion -= 4;
		light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
	}

	return light;
}
TileSpec MapNode::getTile(v3s16 dir)
{
	if(content_features(*this).param_type == CPT_FACEDIR_SIMPLE)
		dir = facedir_rotate(param1, dir);

	TileSpec spec;

	s32 dir_i = -1;

	if(dir == v3s16(0,0,0))
		dir_i = -1;
	else if(dir == v3s16(0,1,0))
		dir_i = 0;
	else if(dir == v3s16(0,-1,0))
		dir_i = 1;
	else if(dir == v3s16(1,0,0))
		dir_i = 2;
	else if(dir == v3s16(-1,0,0))
		dir_i = 3;
	else if(dir == v3s16(0,0,1))
		dir_i = 4;
	else if(dir == v3s16(0,0,-1))
		dir_i = 5;

	if(dir_i == -1)
		// Non-directional
		spec = content_features(*this).tiles[0];
	else
		spec = content_features(*this).tiles[dir_i];

	/*
		If it contains some mineral, change texture id
	*/
	if(content_features(*this).param_type == CPT_MINERAL && g_texturesource)
	{
		u8 mineral = getMineral();
		std::string mineral_texture_name = mineral_block_texture(mineral);
		if(mineral_texture_name != "")
		{
			u32 orig_id = spec.texture.id;
			std::string texture_name = g_texturesource->getTextureName(orig_id);
			//texture_name += "^blit:";
			texture_name += "^";
			texture_name += mineral_texture_name;
			u32 new_id = g_texturesource->getTextureId(texture_name);
			spec.texture = g_texturesource->getTexture(new_id);
		}
	}

	return spec;
}
Exemplo n.º 3
0
void Camera::wield(const InventoryItem* item)
{
	if (item != NULL) {
		bool haveWield = false;
		m_wieldnode_baserotation = v3f(-100, 110, -100);
		m_wieldnode_baseposition = v3f(45, -35, 65);

		// Try to make a MaterialItem cube.
		if (std::string(item->getName()) == "MaterialItem") {
			// A block-type material
			MaterialItem* mat_item = (MaterialItem*) item;
			content_t content = mat_item->getMaterial();
			if (content_features(content).solidness || content_features(content).visual_solidness) {
				m_wieldnode->setCube(content_features(content).tiles);
				m_wieldnode->setScale(v3f(30));
				haveWield = true;
			}else if (
				(
					content_features(content).draw_type == CDT_NODEBOX
					|| content_features(content).draw_type == CDT_NODEBOX_META
					|| content_features(content).draw_type == CDT_FENCELIKE
					|| content_features(content).draw_type == CDT_WALLLIKE
					|| content_features(content).draw_type == CDT_STAIRLIKE
					|| content_features(content).draw_type == CDT_SLABLIKE
				)
				&& content_features(content).wield_nodebox == true
			) {
				m_wieldnode->setNodeBox(content);
				m_wieldnode->setScale(v3f(30));
				m_wieldnode_baserotation = v3f(-10, 10, -10);
				haveWield = true;
			}
		}

		// If that failed, make an extruded sprite.
		if (!haveWield) {
			m_wieldnode->setSprite(item->getImageRaw());
			m_wieldnode->setScale(v3f(40));
		}

		m_wieldnode->setVisible(true);
	}else{
		// Bare hands
		m_wieldnode->setArm(m_client->getLocalPlayer()->getTexture());
		m_wieldnode_baserotation = v3f(-30, 130, 20);
		m_wieldnode_baseposition = v3f(45, -43, 60);
		m_wieldnode->setScale(v3f(40));
		m_wieldnode->setVisible(true);
	}
}
Exemplo n.º 4
0
void content_nodedef_knob(content_t nodeid, content_t source_node, ContentMaterialType material_type, const char* texture, const std::wstring desc)
{
	ContentFeatures *features = &content_features(nodeid);
	features->description = std::wstring(desc);
	features->setAllTextures(texture);
	features->param_type = CPT_LIGHT;
	features->param2_type = CPT_FACEDIR_WALLMOUNT;
	features->draw_type = CDT_NODEBOX;
	features->is_ground_content = false;
	features->solidness = 0;
	features->light_propagates = true;
	features->dug_item = std::string("MaterialItem2 ")+itos(nodeid)+" 1";
	features->type = CMT_STONE;
	features->hardness = 0.8;
	features->climbable = true;
	features->suffocation_per_second = 0;
	if (material_type == CMT_WOOD) {
		content_t recipe[9] = {
			CONTENT_IGNORE, CONTENT_IGNORE, CONTENT_IGNORE,
			source_node   , source_node   , CONTENT_IGNORE,
			CONTENT_IGNORE, CONTENT_IGNORE, CONTENT_IGNORE
		};

		crafting::setRecipe(recipe, nodeid, 2);
	}else{
		crafting::set1To4Recipe(source_node,nodeid);
	}
	content_nodebox_knob(features);
	features->setInventoryTextureNodeBox(nodeid,texture,texture,texture);
	lists::add("craftguide",nodeid);
	lists::add("creative",nodeid);
}
Exemplo n.º 5
0
void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
{
	// Get time difference
	u32 dtime_s = 0;
	u32 stamp = block->getTimestamp();
	if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
		dtime_s = m_game_time - block->getTimestamp();
	dtime_s += additional_dtime;

	// Set current time as timestamp (and let it set ChangedFlag)
	block->setTimestamp(m_game_time);

	//dstream<<"Block is "<<dtime_s<<" seconds old."<<std::endl;
	
	// Activate stored objects
	activateObjects(block);

	// Run node metadata
	bool changed = block->m_node_metadata.step((float)dtime_s);
	if(changed)
	{
		MapEditEvent event;
		event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
		event.p = block->getPos();
		m_map->dispatchEvent(&event);

		block->setChangedFlag();
	}

	// TODO: Do something
	// TODO: Implement usage of ActiveBlockModifier
	
	// Here's a quick demonstration
	v3s16 p0;
	for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
	for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
	for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
	{
		v3s16 p = p0 + block->getPosRelative();
		MapNode n = block->getNodeNoEx(p0);
#if 1
		// Test something:
		// Convert all mud under proper day lighting to grass
		if(n.getContent() == CONTENT_MUD)
		{
			if(dtime_s > 300)
			{
				MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
				if(content_features(n_top).air_equivalent &&
						n_top.getLight(LIGHTBANK_DAY) >= 13)
				{
					n.setContent(CONTENT_GRASS);
					m_map->addNodeWithEvent(p, n);
				}
			}
		}
#endif
	}
}
Exemplo n.º 6
0
// This is probably very useless
void spawnRandomObjects(MapBlock *block)
{
	for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
	for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
	{
		bool last_node_walkable = false;
		for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
		{
			v3s16 p(x0,y0,z0);
			MapNode n = block->getNodeNoEx(p);
			if(n.getContent() == CONTENT_IGNORE)
				continue;
			if(content_features(n).liquid_type != LIQUID_NONE)
				continue;
			if(content_features(n).walkable)
			{
				last_node_walkable = true;
				continue;
			}
			if(last_node_walkable)
			{
				// If block contains light information
				if(content_features(n).param_type == CPT_LIGHT)
				{
					if(n.getLight(LIGHTBANK_DAY) <= 5)
					{
						if(myrand() % 1000 == 0)
						{
							v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
							pos_f.Y -= BS*0.4;
							ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
							std::string data = obj->getStaticData();
							StaticObject s_obj(obj->getType(),
									obj->getBasePosition(), data);
							// Add one
							block->m_static_objects.insert(0, s_obj);
							delete obj;
							block->setChangedFlag();
						}
					}
				}
			}
			last_node_walkable = false;
		}
	}
}
u8 MapNode::getMineral()
{
	if(content_features(*this).param_type == CPT_MINERAL)
	{
		return param1 & 0x0f;
	}

	return MINERAL_NONE;
}
/*
	Nodes make a face if contents differ and solidness differs.
	Return value:
		0: No face
		1: Face uses m1's content
		2: Face uses m2's content
	equivalent: Whether the blocks share the same face (eg. water and glass)
*/
u8 face_contents(content_t m1, content_t m2, bool *equivalent)
{
	*equivalent = false;

	if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
		return 0;

	bool contents_differ = (m1 != m2);

	// Contents don't differ for different forms of same liquid
	if(content_liquid(m1) && content_liquid(m2)
			&& make_liquid_flowing(m1) == make_liquid_flowing(m2))
		contents_differ = false;

	u8 c1 = content_solidness(m1);
	u8 c2 = content_solidness(m2);

	bool solidness_differs = (c1 != c2);
	bool makes_face = contents_differ && solidness_differs;

	if(makes_face == false)
		return 0;

	if(c1 == 0)
		c1 = content_features(m1).visual_solidness;
	if(c2 == 0)
		c2 = content_features(m2).visual_solidness;

	if(c1 == c2){
		*equivalent = true;
		// If same solidness, liquid takes precense
		if(content_features(m1).liquid_type != LIQUID_NONE)
			return 1;
		if(content_features(m2).liquid_type != LIQUID_NONE)
			return 2;
	}

	if(c1 > c2)
		return 1;
	else
		return 2;
}
s16 WeatherParticles::traceGroundLevel(v3s16 p) {
	//@TODO needs cachepurging
	if (m_heightmap.find(v2s16(p.X, p.Z)) > 0) {
		return m_heightmap.find(v2s16(p.X, p.Z))->getValue();
	}
	s16 y = p.Y + 100;
	if (y > 100)
		y = 100;
	bool isair = true;
	do {
		y--;
		try {
			isair
					= content_features(m_client->getNode(v3s16(p.X, y, p.Z)).d).air_equivalent;
		} catch (InvalidPositionException &e) {
		}
		if (y < p.Y - 100)
			break;
	} while (isair);

	m_heightmap.insert(v2s16(p.X, p.Z), y);
	//dstream << y << std::endl;
	return y;
}
Exemplo n.º 10
0
void ServerEnvironment::step(float dtime)
{
	DSTACK(__FUNCTION_NAME);
	
	//TimeTaker timer("ServerEnv step");

	// Get some settings
	bool footprints = g_settings.getBool("footprints");

	/*
		Increment game time
	*/
	{
		m_game_time_fraction_counter += dtime;
		u32 inc_i = (u32)m_game_time_fraction_counter;
		m_game_time += inc_i;
		m_game_time_fraction_counter -= (float)inc_i;
	}
	
	/*
		Handle players
	*/
	for(core::list<Player*>::Iterator i = m_players.begin();
			i != m_players.end(); i++)
	{
		Player *player = *i;
		
		// Ignore disconnected players
		if(player->peer_id == 0)
			continue;

		v3f playerpos = player->getPosition();
		
		// Move
		player->move(dtime, *m_map, 100*BS);
		
		/*
			Add footsteps to grass
		*/
		if(footprints)
		{
			// Get node that is at BS/4 under player
			v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
			try{
				MapNode n = m_map->getNode(bottompos);
				if(n.getContent() == CONTENT_GRASS)
				{
					n.setContent(CONTENT_GRASS_FOOTSTEPS);
					m_map->setNode(bottompos, n);
				}
			}
			catch(InvalidPositionException &e)
			{
			}
		}
	}

	/*
		Manage active block list
	*/
	if(m_active_blocks_management_interval.step(dtime, 2.0))
	{
		/*
			Get player block positions
		*/
		core::list<v3s16> players_blockpos;
		for(core::list<Player*>::Iterator
				i = m_players.begin();
				i != m_players.end(); i++)
		{
			Player *player = *i;
			// Ignore disconnected players
			if(player->peer_id == 0)
				continue;
			v3s16 blockpos = getNodeBlockPos(
					floatToInt(player->getPosition(), BS));
			players_blockpos.push_back(blockpos);
		}
		
		/*
			Update list of active blocks, collecting changes
		*/
		const s16 active_block_range = 5;
		core::map<v3s16, bool> blocks_removed;
		core::map<v3s16, bool> blocks_added;
		m_active_blocks.update(players_blockpos, active_block_range,
				blocks_removed, blocks_added);

		/*
			Handle removed blocks
		*/

		// Convert active objects that are no more in active blocks to static
		deactivateFarObjects(false);
		
		for(core::map<v3s16, bool>::Iterator
				i = blocks_removed.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();

			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") became inactive"<<std::endl;*/
			
			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;
			
			// Set current time as timestamp (and let it set ChangedFlag)
			block->setTimestamp(m_game_time);
		}

		/*
			Handle added blocks
		*/

		for(core::map<v3s16, bool>::Iterator
				i = blocks_added.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();
			
			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") became active"<<std::endl;*/

			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;

			activateBlock(block);
		}
	}

	/*
		Mess around in active blocks
	*/
	if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
	{
		float dtime = 1.0;

		for(core::map<v3s16, bool>::Iterator
				i = m_active_blocks.m_list.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();
			
			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") being handled"<<std::endl;*/

			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;

			// Reset block usage timer
			block->resetUsageTimer();
			
			// Set current time as timestamp
			block->setTimestampNoChangedFlag(m_game_time);

			// Run node metadata
			bool changed = block->m_node_metadata.step(dtime);
			if(changed)
			{
				MapEditEvent event;
				event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
				event.p = p;
				m_map->dispatchEvent(&event);

				block->setChangedFlag();
			}
		}
	}
	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++)
		{
			v3s16 p = i.getNode()->getKey();
			
			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") being handled"<<std::endl;*/

			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;
			
			// Set current time as timestamp
			block->setTimestampNoChangedFlag(m_game_time);

			/*
				Do stuff!

				Note that map modifications should be done using the event-
				making map methods so that the server gets information
				about them.

				Reading can be done quickly directly from the block.

				Everything should bind to inside this single content
				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++)
			for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
			for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
			{
				v3s16 p = p0 + block->getPosRelative();
				MapNode n = block->getNodeNoEx(p0);

				/*
					Test something:
					Convert mud under proper lighting to grass
				*/
				if(n.getContent() == CONTENT_MUD)
				{
					if(myrand()%20 == 0)
					{
						MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
						if(content_features(n_top).air_equivalent &&
								n_top.getLightBlend(getDayNightRatio()) >= 13)
						{
							n.setContent(CONTENT_GRASS);
							m_map->addNodeWithEvent(p, n);
						}
					}
				}
				/*
					Convert grass into mud if under something else than air
				*/
				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)
						{
							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);
						}
					}
			 }
			}
		}
	}
	
	/*
		Step active objects
	*/
	{
		//TimeTaker timer("Step active objects");
		
		// This helps the objects to send data at the same time
		bool send_recommended = false;
		m_send_recommended_timer += dtime;
		if(m_send_recommended_timer > 0.15)
		{
			m_send_recommended_timer = 0;
			send_recommended = true;
		}

		for(core::map<u16, ServerActiveObject*>::Iterator
				i = m_active_objects.getIterator();
				i.atEnd()==false; i++)
		{
			ServerActiveObject* obj = i.getNode()->getValue();
			// Don't step if is to be removed or stored statically
			if(obj->m_removed || obj->m_pending_deactivation)
				continue;
			// Step object
			obj->step(dtime, send_recommended);
			// Read messages from object
			while(obj->m_messages_out.size() > 0)
			{
				m_active_object_messages.push_back(
						obj->m_messages_out.pop_front());
			}
		}
	}
	
	/*
		Manage active objects
	*/
	if(m_object_management_interval.step(dtime, 0.5))
	{
		/*
			Remove objects that satisfy (m_removed && m_known_by_count==0)
		*/
		removeRemovedObjects();
	}

	if(g_settings.getBool("enable_experimental"))
	{

	/*
		TEST CODE
	*/
#if 1
	m_random_spawn_timer -= dtime;
	if(m_random_spawn_timer < 0)
	{
		//m_random_spawn_timer += myrand_range(2.0, 20.0);
		//m_random_spawn_timer += 2.0;
		m_random_spawn_timer += 200.0;

		/*
			Find some position
		*/

		/*v2s16 p2d(myrand_range(-5,5), myrand_range(-5,5));
		s16 y = 1 + getServerMap().findGroundLevel(p2d);
		v3f pos(p2d.X*BS,y*BS,p2d.Y*BS);*/
		
		Player *player = getRandomConnectedPlayer();
		v3f pos(0,0,0);
		if(player)
			pos = player->getPosition();
		pos += v3f(
			myrand_range(-3,3)*BS,
			0,
			myrand_range(-3,3)*BS
		);

		/*
			Create a ServerActiveObject
		*/

		//TestSAO *obj = new TestSAO(this, 0, pos);
		//ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
		//ServerActiveObject *obj = new RatSAO(this, 0, pos);
		//ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
		ServerActiveObject *obj = new FireflySAO(this, 0, pos);
		addActiveObject(obj);
	}
#endif

	} // enable_experimental
}
DiggingPropertiesList * getDiggingPropertiesList(u16 content)
{
	return &content_features(content).digging_properties;
}
Exemplo n.º 12
0
DiggingProperties getDiggingProperties(content_t content, u8 mineral, content_t tool, u16 data)
{
	ToolItemFeatures t_features = content_toolitem_features(tool);
	ContentFeatures &c_features = content_features(content);
	f32 time = t_features.dig_time*c_features.hardness;
	f32 wear = 0;
	if (t_features.hardness && c_features.hardness)
		wear = 65535/t_features.hardness*c_features.hardness;
	bool diggable = true;
	bool type_match = false;
	if (
		(tool&CONTENT_CLOTHESITEM_MASK) == CONTENT_CLOTHESITEM_MASK
		|| (c_features.type == CMT_STONE && t_features.type != TT_PICK)
		|| (c_features.type == CMT_TREE && t_features.type == TT_NONE)
	) {
		diggable = false;
	}else{
		switch (t_features.type) {
		case TT_SPECIAL:
			diggable = false;
			break;
		case TT_AXE:
			if (c_features.type == CMT_PLANT) {
				time *= 2.;
				type_match = true;
			}else if (c_features.type != CMT_WOOD && c_features.type != CMT_TREE && c_features.type != CMT_GLASS) {
				time *= 10.;
			}else{
				type_match = true;
			}
			break;
		case TT_PICK:
			if (c_features.type != CMT_STONE || t_features.level < mineral_features(mineral).min_level) {
				time *= 2.;
			}else{
				type_match = true;
			}
			break;
		case TT_SHOVEL:
			if (c_features.type != CMT_DIRT) {
				time *= 10.;
			}else{
				type_match = true;
			}
			break;
		case TT_SWORD:
			if (c_features.type != CMT_PLANT)
				time = 10.;
			break;
		case TT_SHEAR:
			if (c_features.type != CMT_PLANT) {
				time *= 10.;
			}else{
				type_match = true;
			}
			break;
		case TT_BUCKET:
			if (c_features.type != CMT_LIQUID) {
				time = 10.;
			}else{
				type_match = true;
			}
			break;
		case TT_SPEAR:
			if (c_features.type != CMT_DIRT)
				time = 10.;
			break;
		case TT_NONE:
			if (c_features.type == CMT_DIRT)
				time *= 0.75;
			break;
		default:
			break;
		}
	}

	if (data != 0 && diggable) {
		f32 tp = time/4.0;
		f32 wp = wear/4.0;
		EnchantmentInfo info;
		while (enchantment_get(&data,&info)) {
			switch (info.type) {
			case ENCHANTMENT_FAST:
				if (type_match) {
					time -= tp*(info.level+1);
				}else if (info.level > 1) {
					time -= tp;
				}
				break;
			case ENCHANTMENT_LONGLASTING:
				wear -= wp*(info.level+1);
				break;
			case ENCHANTMENT_FLAME:
				wear *= 2.5;
				break;
			default:;
			}
		}
		if (time < 0.0)
			time = 0.01;
		if (wear < 0.0)
			wear = 0.01;
	}

	return DiggingProperties(diggable,time,wear);
}
Exemplo n.º 13
0
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
		core::list<CollisionInfo> *collision_info)
{
	v3f position = getPosition();
	v3f oldpos = position;
	v3s16 oldpos_i = floatToInt(oldpos, BS);

	v3f old_speed = m_speed;

	/*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
			<<oldpos_i.Z<<")"<<std::endl;*/

	/*
		Calculate new position
	*/
	position += m_speed * dtime;
	
	// Skip collision detection if a special movement mode is used
	bool free_move = g_settings->getBool("free_move");
	if(free_move)
	{
		setPosition(position);
		return;
	}

	/*
		Collision detection
	*/
	
	// Player position in nodes
	v3s16 pos_i = floatToInt(position, BS);
	
	/*
		Check if player is in water (the oscillating value)
	*/
	try{
		// If in water, the threshold of coming out is at higher y
		if(in_water)
		{
			v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
			in_water = content_liquid(map.getNode(pp).getContent());
		}
		// If not in water, the threshold of going in is at lower y
		else
		{
			v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
			in_water = content_liquid(map.getNode(pp).getContent());
		}
	}
	catch(InvalidPositionException &e)
	{
		in_water = false;
	}

	/*
		Check if player is in water (the stable value)
	*/
	try{
		v3s16 pp = floatToInt(position + v3f(0,0,0), BS);
		in_water_stable = content_liquid(map.getNode(pp).getContent());
	}
	catch(InvalidPositionException &e)
	{
		in_water_stable = false;
	}

	/*
	        Check if player is climbing
	*/

	try {
	        v3s16 pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
		v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
		is_climbing = ((content_features(map.getNode(pp).getContent()).climbable ||
				content_features(map.getNode(pp2).getContent()).climbable) && !free_move);
	}
	catch(InvalidPositionException &e)
	{
	        is_climbing = false;
	}

	/*
		Collision uncertainty radius
		Make it a bit larger than the maximum distance of movement
	*/
	//f32 d = pos_max_d * 1.1;
	// A fairly large value in here makes moving smoother
	f32 d = 0.15*BS;

	// This should always apply, otherwise there are glitches
	assert(d > pos_max_d);

	float player_radius = BS*0.35;
	float player_height = BS*1.7;
	
	// Maximum distance over border for sneaking
	f32 sneak_max = BS*0.4;

	/*
		If sneaking, player has larger collision radius to keep from
		falling
	*/
	/*if(control.sneak)
		player_radius = sneak_max + d*1.1;*/
	
	/*
		If sneaking, keep in range from the last walked node and don't
		fall off from it
	*/
	if(control.sneak && m_sneak_node_exists)
	{
		f32 maxd = 0.5*BS + sneak_max;
		v3f lwn_f = intToFloat(m_sneak_node, BS);
		position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
		position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
		
		f32 min_y = lwn_f.Y + 0.5*BS;
		if(position.Y < min_y)
		{
			position.Y = min_y;

			//v3f old_speed = m_speed;

			if(m_speed.Y < 0)
				m_speed.Y = 0;

			/*if(collision_info)
			{
				// Report fall collision
				if(old_speed.Y < m_speed.Y - 0.1)
				{
					CollisionInfo info;
					info.t = COLLISION_FALL;
					info.speed = m_speed.Y - old_speed.Y;
					collision_info->push_back(info);
				}
			}*/
		}
	}

	/*
		Calculate player collision box (new and old)
	*/
	core::aabbox3d<f32> playerbox(
		position.X - player_radius,
		position.Y - 0.0,
		position.Z - player_radius,
		position.X + player_radius,
		position.Y + player_height,
		position.Z + player_radius
	);
	core::aabbox3d<f32> playerbox_old(
		oldpos.X - player_radius,
		oldpos.Y - 0.0,
		oldpos.Z - player_radius,
		oldpos.X + player_radius,
		oldpos.Y + player_height,
		oldpos.Z + player_radius
	);

	/*
		If the player's feet touch the topside of any node, this is
		set to true.

		Player is allowed to jump when this is true.
	*/
	touching_ground = false;

	/*std::cout<<"Checking collisions for ("
			<<oldpos_i.X<<","<<oldpos_i.Y<<","<<oldpos_i.Z
			<<") -> ("
			<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z
			<<"):"<<std::endl;*/
	
	bool standing_on_unloaded = false;
	
	/*
		Go through every node around the player
	*/
	for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
	for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
	for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
	{
		bool is_unloaded = false;
		try{
			// Player collides into walkable nodes
			if(content_walkable(map.getNode(v3s16(x,y,z)).getContent()) == false)
				continue;
		}
		catch(InvalidPositionException &e)
		{
			is_unloaded = true;
			// Doing nothing here will block the player from
			// walking over map borders
		}

		core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
		
		/*
			See if the player is touching ground.

			Player touches ground if player's minimum Y is near node's
			maximum Y and player's X-Z-area overlaps with the node's
			X-Z-area.

			Use 0.15*BS so that it is easier to get on a node.
		*/
		if(
				//fabs(nodebox.MaxEdge.Y-playerbox.MinEdge.Y) < d
				fabs(nodebox.MaxEdge.Y-playerbox.MinEdge.Y) < 0.15*BS
				&& nodebox.MaxEdge.X-d > playerbox.MinEdge.X
				&& nodebox.MinEdge.X+d < playerbox.MaxEdge.X
				&& nodebox.MaxEdge.Z-d > playerbox.MinEdge.Z
				&& nodebox.MinEdge.Z+d < playerbox.MaxEdge.Z
		){
			touching_ground = true;
			if(is_unloaded)
				standing_on_unloaded = true;
		}
		
		// If player doesn't intersect with node, ignore node.
		if(playerbox.intersectsWithBox(nodebox) == false)
			continue;
		
		/*
			Go through every axis
		*/
		v3f dirs[3] = {
			v3f(0,0,1), // back-front
			v3f(0,1,0), // top-bottom
			v3f(1,0,0), // right-left
		};
		for(u16 i=0; i<3; i++)
		{
			/*
				Calculate values along the axis
			*/
			f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
			f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
			f32 playermax = playerbox.MaxEdge.dotProduct(dirs[i]);
			f32 playermin = playerbox.MinEdge.dotProduct(dirs[i]);
			f32 playermax_old = playerbox_old.MaxEdge.dotProduct(dirs[i]);
			f32 playermin_old = playerbox_old.MinEdge.dotProduct(dirs[i]);
			
			/*
				Check collision for the axis.
				Collision happens when player is going through a surface.
			*/
			/*f32 neg_d = d;
			f32 pos_d = d;
			// Make it easier to get on top of a node
			if(i == 1)
				neg_d = 0.15*BS;
			bool negative_axis_collides =
				(nodemax > playermin && nodemax <= playermin_old + neg_d
					&& m_speed.dotProduct(dirs[i]) < 0);
			bool positive_axis_collides =
				(nodemin < playermax && nodemin >= playermax_old - pos_d
					&& m_speed.dotProduct(dirs[i]) > 0);*/
			bool negative_axis_collides =
				(nodemax > playermin && nodemax <= playermin_old + d
					&& m_speed.dotProduct(dirs[i]) < 0);
			bool positive_axis_collides =
				(nodemin < playermax && nodemin >= playermax_old - d
					&& m_speed.dotProduct(dirs[i]) > 0);
			bool main_axis_collides =
					negative_axis_collides || positive_axis_collides;
			
			/*
				Check overlap of player and node in other axes
			*/
			bool other_axes_overlap = true;
			for(u16 j=0; j<3; j++)
			{
				if(j == i)
					continue;
				f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
				f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
				f32 playermax = playerbox.MaxEdge.dotProduct(dirs[j]);
				f32 playermin = playerbox.MinEdge.dotProduct(dirs[j]);
				if(!(nodemax - d > playermin && nodemin + d < playermax))
				{
					other_axes_overlap = false;
					break;
				}
			}
			
			/*
				If this is a collision, revert the position in the main
				direction.
			*/
			if(other_axes_overlap && main_axis_collides)
			{
				//v3f old_speed = m_speed;

				m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
				position -= position.dotProduct(dirs[i]) * dirs[i];
				position += oldpos.dotProduct(dirs[i]) * dirs[i];
				
				/*if(collision_info)
				{
					// Report fall collision
					if(old_speed.Y < m_speed.Y - 0.1)
					{
						CollisionInfo info;
						info.t = COLLISION_FALL;
						info.speed = m_speed.Y - old_speed.Y;
						collision_info->push_back(info);
					}
				}*/
			}
		
		}
	} // xyz

	/*
		Check the nodes under the player to see from which node the
		player is sneaking from, if any.
	*/
	{
		v3s16 pos_i_bottom = floatToInt(position - v3f(0,BS/2,0), BS);
		v2f player_p2df(position.X, position.Z);
		f32 min_distance_f = 100000.0*BS;
		// If already seeking from some node, compare to it.
		/*if(m_sneak_node_exists)
		{
			v3f sneaknode_pf = intToFloat(m_sneak_node, BS);
			v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z);
			f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df);
			f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y);
			// Ignore if player is not on the same level (likely dropped)
			if(d_vert_f < 0.15*BS)
				min_distance_f = d_horiz_f;
		}*/
		v3s16 new_sneak_node = m_sneak_node;
		for(s16 x=-1; x<=1; x++)
		for(s16 z=-1; z<=1; z++)
		{
			v3s16 p = pos_i_bottom + v3s16(x,0,z);
			v3f pf = intToFloat(p, BS);
			v2f node_p2df(pf.X, pf.Z);
			f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
			f32 max_axis_distance_f = MYMAX(
					fabs(player_p2df.X-node_p2df.X),
					fabs(player_p2df.Y-node_p2df.Y));
					
			if(distance_f > min_distance_f ||
					max_axis_distance_f > 0.5*BS + sneak_max + 0.1*BS)
				continue;

			try{
				// The node to be sneaked on has to be walkable
				if(content_walkable(map.getNode(p).getContent()) == false)
					continue;
				// And the node above it has to be nonwalkable
				if(content_walkable(map.getNode(p+v3s16(0,1,0)).getContent()) == true)
					continue;
			}
			catch(InvalidPositionException &e)
			{
				continue;
			}

			min_distance_f = distance_f;
			new_sneak_node = p;
		}
		
		bool sneak_node_found = (min_distance_f < 100000.0*BS*0.9);
		
		if(control.sneak && m_sneak_node_exists)
		{
			if(sneak_node_found)
				m_sneak_node = new_sneak_node;
		}
		else
		{
			m_sneak_node = new_sneak_node;
			m_sneak_node_exists = sneak_node_found;
		}

		/*
			If sneaking, the player's collision box can be in air, so
			this has to be set explicitly
		*/
		if(sneak_node_found && control.sneak)
			touching_ground = true;
	}
	
	/*
		Set new position
	*/
	setPosition(position);
	
	/*
		Report collisions
	*/
	if(collision_info)
	{
		// Report fall collision
		if(old_speed.Y < m_speed.Y - 0.1 && !standing_on_unloaded)
		{
			CollisionInfo info;
			info.t = COLLISION_FALL;
			info.speed = m_speed.Y - old_speed.Y;
			collision_info->push_back(info);
		}
	}
}
Exemplo n.º 14
0
void content_mapnode_plants(bool repeat)
{
	bool new_style_leaves = g_settings->getBool("new_style_leaves");
	content_t i;
	ContentFeatures *f = NULL;


	i = CONTENT_TREE;
	f = &content_features(i);
	f->description = wgettext("Tree");
	f->setAllTextures("tree.png");
	f->setTexture(0, "tree_top.png");
	f->setTexture(1, "tree_top.png");
	f->setInventoryTextureCube("tree_top.png", "tree.png", "tree.png");
	f->draw_type = CDT_TRUNKLIKE;
	f->is_ground_content = true;
	f->flammable = 2; // can be set on fire
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->cook_result = std::string("CraftItem lump_of_charcoal 1");
	f->fuel_time = 30;
	f->type = CMT_TREE;
	f->hardness = 1.0;
	f->ondig_special_drop = CONTENT_WOOD;
	f->ondig_special_drop_count = 6;
	f->ondig_special_tool = TT_AXE;
	lists::add("creative",i);
	lists::add("cooking",i);

	i = CONTENT_APPLE_TREE;
	f = &content_features(i);
	f->description = wgettext("Apple Tree");
	f->setAllTextures("apple_tree.png");
	f->setTexture(0, "apple_tree_top.png");
	f->setTexture(1, "apple_tree_top.png");
	f->setInventoryTextureCube("apple_tree_top.png", "apple_tree.png", "apple_tree.png");
	f->draw_type = CDT_TRUNKLIKE;
	f->is_ground_content = true;
	f->flammable = 2; // can be set on fire
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->cook_result = std::string("CraftItem lump_of_charcoal 1");
	f->fuel_time = 30;
	f->type = CMT_TREE;
	f->hardness = 1.0;
	f->ondig_special_drop = CONTENT_WOOD;
	f->ondig_special_drop_count = 6;
	f->ondig_special_tool = TT_AXE;
	lists::add("creative",i);
	lists::add("cooking",i);

	i = CONTENT_JUNGLETREE;
	f = &content_features(i);
	f->description = wgettext("Jungle Tree");
	f->setAllTextures("jungletree.png");
	f->setTexture(0, "jungletree_top.png");
	f->setTexture(1, "jungletree_top.png");
	f->setInventoryTextureCube("jungletree_top.png", "jungletree.png", "jungletree.png");
	f->draw_type = CDT_TRUNKLIKE;
	//f->is_ground_content = true;
	f->flammable = 2; // can be set on fire
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->cook_result = std::string("CraftItem lump_of_charcoal 1");
	f->fuel_time = 30;
	f->type = CMT_TREE;
	f->hardness = 1.0;
	f->ondig_special_drop = CONTENT_JUNGLEWOOD;
	f->ondig_special_drop_count = 6;
	f->ondig_special_tool = TT_AXE;
	lists::add("creative",i);

	i = CONTENT_CONIFER_TREE;
	f = &content_features(i);
	f->description = wgettext("Conifer Tree");
	f->setAllTextures("conifer_tree.png");
	f->setTexture(0, "conifer_tree_top.png");
	f->setTexture(1, "conifer_tree_top.png");
	f->setInventoryTextureCube("conifer_tree_top.png", "conifer_tree.png", "conifer_tree.png");
	f->draw_type = CDT_TRUNKLIKE;
	f->is_ground_content = true;
	f->flammable = 2; // can be set on fire
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->cook_result = std::string("CraftItem lump_of_charcoal 1");
	f->fuel_time = 25;
	f->type = CMT_TREE;
	f->hardness = 0.8;
	f->ondig_special_drop = CONTENT_WOOD_PINE;
	f->ondig_special_drop_count = 6;
	f->ondig_special_tool = TT_AXE;
	lists::add("creative",i);
	lists::add("cooking",i);

	i = CONTENT_YOUNG_TREE;
	f = &content_features(i);
	f->description = wgettext("Young Tree");
	f->setAllTextures("tree.png");
	f->setTexture(0, "tree_top.png");
	f->setTexture(1, "tree_top.png");
	f->draw_type = CDT_NODEBOX;
	f->solidness = 0; // drawn separately, makes no faces
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	content_nodebox_youngtree(f);
	f->setInventoryTextureNodeBox(i,"tree_top.png", "tree.png", "tree.png");
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->special_alternate_node = CONTENT_LEAVES;
	f->fuel_time = 20;
	f->type = CMT_TREE;
	f->hardness = 1.0;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_YOUNG_JUNGLETREE;
	f = &content_features(i);
	f->description = wgettext("Young Jungle Tree");
	f->setAllTextures("jungletree.png");
	f->setTexture(0, "jungletree_top.png");
	f->setTexture(1, "jungletree_top.png");
	f->draw_type = CDT_NODEBOX;
	f->solidness = 0; // drawn separately, makes no faces
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	content_nodebox_youngtree(f);
	f->setInventoryTextureNodeBox(i,"jungletree_top.png", "jungletree.png", "jungletree.png");
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->special_alternate_node = CONTENT_JUNGLELEAVES;
	f->fuel_time = 20;
	f->type = CMT_TREE;
	f->hardness = 1.0;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_YOUNG_APPLE_TREE;
	f = &content_features(i);
	f->description = wgettext("Young Apple Tree");
	f->setAllTextures("apple_tree.png");
	f->setTexture(0, "apple_tree_top.png");
	f->setTexture(1, "apple_tree_top.png");
	f->draw_type = CDT_NODEBOX;
	f->solidness = 0; // drawn separately, makes no faces
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	content_nodebox_youngtree(f);
	f->setInventoryTextureNodeBox(i,"apple_tree_top.png", "apple_tree.png", "apple_tree.png");
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->special_alternate_node = CONTENT_APPLE_LEAVES;
	f->fuel_time = 20;
	f->type = CMT_TREE;
	f->hardness = 1.0;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_YOUNG_CONIFER_TREE;
	f = &content_features(i);
	f->description = wgettext("Young Conifer Tree");
	f->setAllTextures("conifer_tree.png");
	f->setTexture(0, "conifer_tree_top.png");
	f->setTexture(1, "conifer_tree_top.png");
	f->draw_type = CDT_NODEBOX;
	f->solidness = 0; // drawn separately, makes no faces
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	content_nodebox_youngtree(f);
	f->setInventoryTextureNodeBox(i,"conifer_tree_top.png", "conifer_tree.png", "conifer_tree.png");
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->special_alternate_node = CONTENT_CONIFER_LEAVES;
	f->fuel_time = 20;
	f->type = CMT_TREE;
	f->hardness = 1.0;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_JUNGLEGRASS;
	f = &content_features(i);
	f->description = wgettext("Jungle Grass");
	f->setInventoryTexture("junglegrass.png");
	f->setAllTextures("junglegrass.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE_LGE;
	//f->is_ground_content = true;
	f->air_equivalent = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->type = CMT_PLANT;
	f->hardness = 0.20;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_LEAVES;
	f = &content_features(i);
	f->description = wgettext("Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	//f->is_ground_content = true;
	if (new_style_leaves) {
		f->draw_type = CDT_LEAFLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->setAllTextures("leaves.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
		f->setAllTextureFlags(0);
#endif
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:leaves.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem lump_of_resin 1");
	f->extra_dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAPLING)+" 1";
	f->extra_dug_item_rarity = 20;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->ondig_special_drop = CONTENT_TRIMMED_LEAVES;
	f->ondig_special_drop_count = 1;
	f->ondig_special_tool = TT_SHEAR;
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("decrafting",i);
	lists::add("cooking",i);

	i = CONTENT_LEAVES_AUTUMN;
	f = &content_features(i);
	f->description = wgettext("Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	//f->is_ground_content = true;
	if (new_style_leaves) {
		f->draw_type = CDT_LEAFLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->setAllTextures("leaves_autumn.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
		f->setAllTextureFlags(0);
#endif
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:leaves_autumn.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem lump_of_resin 1");
	f->extra_dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAPLING)+" 1";
	f->extra_dug_item_rarity = 20;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->ondig_special_drop = CONTENT_TRIMMED_LEAVES_AUTUMN;
	f->ondig_special_drop_count = 1;
	f->ondig_special_tool = TT_SHEAR;
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("decrafting",i);
	lists::add("cooking",i);

	i = CONTENT_LEAVES_WINTER;
	f = &content_features(i);
	f->description = wgettext("Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	//f->is_ground_content = true;
	if (new_style_leaves) {
		f->draw_type = CDT_LEAFLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->setAllTextures("leaves_winter.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
		f->setAllTextureFlags(0);
#endif
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:leaves_winter.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem2 ")+itos(CONTENT_CRAFTITEM_ASH)+" 1";
	f->extra_dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAPLING)+" 1";
	f->extra_dug_item_rarity = 20;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->ondig_special_drop = CONTENT_TRIMMED_LEAVES_WINTER;
	f->ondig_special_drop_count = 1;
	f->ondig_special_tool = TT_SHEAR;
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("decrafting",i);
	lists::add("cooking",i);

	i = CONTENT_LEAVES_SNOWY;
	f = &content_features(i);
	f->description = wgettext("Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	//f->is_ground_content = true;
	if (new_style_leaves) {
		f->draw_type = CDT_LEAFLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->setAllTextures("leaves_snowy.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
		f->setAllTextureFlags(0);
#endif
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:leaves_snowy.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem2 ")+itos(CONTENT_CRAFTITEM_ASH)+" 1";
	f->extra_dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAPLING)+" 1";
	f->extra_dug_item_rarity = 20;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_LEAVES_WINTER)+" 1";
	f->ondig_special_drop = CONTENT_TRIMMED_LEAVES_WINTER;
	f->ondig_special_drop_count = 1;
	f->ondig_special_tool = TT_SHEAR;
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("decrafting",i);
	lists::add("cooking",i);

	i = CONTENT_APPLE_LEAVES;
	f = &content_features(i);
	f->description = wgettext("Apple Tree Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	f->special_alternate_node = CONTENT_APPLE_BLOSSOM;
	if (new_style_leaves) {
		f->draw_type = CDT_LEAFLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->setAllTextures("apple_leaves.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
		f->setAllTextureFlags(0);
#endif
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:apple_leaves.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem lump_of_resin 1");
	f->extra_dug_item = std::string("MaterialItem2 ")+itos(CONTENT_APPLE_SAPLING)+" 1";
	f->extra_dug_item_rarity = 20;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->ondig_special_drop = CONTENT_TRIMMED_APPLE_LEAVES;
	f->ondig_special_drop_count = 1;
	f->ondig_special_tool = TT_SHEAR;
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("decrafting",i);
	lists::add("cooking",i);

	i = CONTENT_JUNGLELEAVES;
	f = &content_features(i);
	f->description = wgettext("Jungle Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	//f->is_ground_content = true;
	if (new_style_leaves) {
		f->draw_type = CDT_LEAFLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->setAllTextures("jungleleaves.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
		f->setAllTextureFlags(0);
#endif
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:jungleleaves.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem lump_of_resin 1");
	f->extra_dug_item = std::string("MaterialItem2 ")+itos(CONTENT_JUNGLESAPLING)+" 1";
	f->extra_dug_item_rarity = 20;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->ondig_special_drop = CONTENT_TRIMMED_JUNGLE_LEAVES;
	f->ondig_special_drop_count = 1;
	f->ondig_special_tool = TT_SHEAR;
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("decrafting",i);
	lists::add("cooking",i);

	i = CONTENT_CONIFER_LEAVES;
	f = &content_features(i);
	f->description = wgettext("Conifer Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	//f->is_ground_content = true;
	if (new_style_leaves) {
		f->draw_type = CDT_LEAFLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->setAllTextures("conifer_leaves.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
		f->setAllTextureFlags(0);
#endif
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:conifer_leaves.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem lump_of_resin 1");
	f->extra_dug_item = std::string("MaterialItem2 ")+itos(CONTENT_CONIFER_SAPLING)+" 1";
	f->extra_dug_item_rarity = 20;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->ondig_special_drop = CONTENT_TRIMMED_CONIFER_LEAVES;
	f->ondig_special_drop_count = 1;
	f->ondig_special_tool = TT_SHEAR;
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("decrafting",i);
	lists::add("cooking",i);

	i = CONTENT_TRIMMED_LEAVES;
	f = &content_features(i);
	f->description = wgettext("Trimmed Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	if (new_style_leaves) {
		f->draw_type = CDT_GLASSLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->visual_solidness = 1;
		f->setAllTextures("leaves.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
#endif
		f->setInventoryTextureCube("leaves.png", "leaves.png", "leaves.png");
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:leaves.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem lump_of_resin 1");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);
	lists::add("cooking",i);

	i = CONTENT_TRIMMED_LEAVES_AUTUMN;
	f = &content_features(i);
	f->description = wgettext("Trimmed Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	if (new_style_leaves) {
		f->draw_type = CDT_GLASSLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->visual_solidness = 1;
		f->setAllTextures("leaves_autumn.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
#endif
		f->setInventoryTextureCube("leaves_autumn.png", "leaves_autumn.png", "leaves_autumn.png");
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:leaves_autumn.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem lump_of_resin 1");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);
	lists::add("cooking",i);

	i = CONTENT_TRIMMED_LEAVES_WINTER;
	f = &content_features(i);
	f->description = wgettext("Trimmed Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	if (new_style_leaves) {
		f->draw_type = CDT_GLASSLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->visual_solidness = 1;
		f->setAllTextures("leaves_winter.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
#endif
		f->setInventoryTextureCube("leaves_winter.png", "leaves_winter.png", "leaves_winter.png");
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:leaves_winter.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem2 ")+itos(CONTENT_CRAFTITEM_ASH)+" 1";
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);
	lists::add("cooking",i);

	i = CONTENT_TRIMMED_APPLE_LEAVES;
	f = &content_features(i);
	f->description = wgettext("Trimmed Apple Tree Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	if (new_style_leaves) {
		f->draw_type = CDT_GLASSLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->visual_solidness = 1;
		f->setAllTextures("apple_leaves.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
#endif
		f->setInventoryTextureCube("apple_leaves.png", "apple_leaves.png", "apple_leaves.png");
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:apple_leaves.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem lump_of_resin 1");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);
	lists::add("cooking",i);

	i = CONTENT_TRIMMED_JUNGLE_LEAVES;
	f = &content_features(i);
	f->description = wgettext("Trimmed Jungle Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	if (new_style_leaves) {
		f->draw_type = CDT_GLASSLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->visual_solidness = 1;
		f->setAllTextures("jungleleaves.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
#endif
		f->setInventoryTextureCube("jungleleaves.png", "jungleleaves.png", "jungleleaves.png");
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:jungleleaves.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem lump_of_resin 1");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);
	lists::add("cooking",i);

	i = CONTENT_TRIMMED_CONIFER_LEAVES;
	f = &content_features(i);
	f->description = wgettext("Trimmed Conifer Leaves");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	if (new_style_leaves) {
		f->draw_type = CDT_GLASSLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->visual_solidness = 1;
		f->setAllTextures("conifer_leaves.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
#endif
		f->setInventoryTextureCube("conifer_leaves.png", "conifer_leaves.png", "conifer_leaves.png");
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:conifer_leaves.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/16;
	f->cook_result = std::string("CraftItem lump_of_resin 1");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);
	lists::add("cooking",i);

	i = CONTENT_APPLE_BLOSSOM;
	f = &content_features(i);
	f->description = wgettext("Apple Tree Blossom");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	f->special_alternate_node = CONTENT_APPLE_LEAVES;
	if (new_style_leaves) {
		f->draw_type = CDT_LEAFLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->visual_solidness = 1;
		f->setAllTextures("apple_leaves.png^apple_blossom.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
		f->setAllTextureFlags(0);
#endif
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:apple_leaves.png^apple_blossom.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->extra_dug_item = std::string("CraftItem apple_blossom 1");
	f->extra_dug_item_rarity = 1;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_APPLE_LEAVES)+" 1";
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("decrafting",i);

	i = CONTENT_TRIMMED_APPLE_BLOSSOM;
	f = &content_features(i);
	f->description = wgettext("Trimmed Apple Tree Blossom");
	f->light_propagates = true;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	f->param_type = CPT_LIGHT;
	if (new_style_leaves) {
		f->draw_type = CDT_GLASSLIKE;
		f->solidness = 0; // drawn separately, makes no faces
		f->visual_solidness = 1;
		f->setAllTextures("apple_leaves.png^apple_blossom.png");
#ifndef SERVER
		f->setAllTextureTypes(MATERIAL_ALPHA_SIMPLE);
#endif
		f->setInventoryTextureCube("apple_leaves.png^apple_blossom.png", "apple_leaves.png^apple_blossom.png", "apple_leaves.png^apple_blossom.png");
	}else{
		f->draw_type = CDT_CUBELIKE;
		f->setAllTextures("[noalpha:apple_leaves.png^apple_blossom.png");
	}
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_CACTUS_BLOSSOM;
	f = &content_features(i);
	f->description = wgettext("Cactus Blossom");
	f->setInventoryTexture("cactus_blossom.png");
	f->setAllTextures("cactus_blossom.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->air_equivalent = false; // grass grows underneath
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->type = CMT_PLANT;
	f->hardness = 0.20;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_CACTUS_FLOWER;
	f = &content_features(i);
	f->description = wgettext("Cactus Flower");
	f->setInventoryTexture("cactus_flower.png");
	f->setAllTextures("cactus_flower.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->air_equivalent = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_CACTUS_BLOSSOM)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->type = CMT_PLANT;
	f->hardness = 0.20;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);
	lists::add("decrafting",i);

	i = CONTENT_CACTUS_FRUIT;
	f = &content_features(i);
	f->description = wgettext("Cactus Berry");
	f->setInventoryTexture("cactus_fruit.png");
	f->setAllTextures("cactus_fruit.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->air_equivalent = true;
	f->dug_item = std::string("CraftItem cactus_fruit 1");
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->type = CMT_PLANT;
	f->hardness = 0.20;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_CACTUS;
	f = &content_features(i);
	f->description = wgettext("Cactus");
	f->setAllTextures("cactus_side.png");
	f->setTexture(0, "cactus_top.png");
	f->setTexture(1, "cactus_top.png");
	f->draw_type = CDT_NODEBOX;
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->damage_per_second = 2;
	f->solidness = 0; // drawn separately, makes no faces
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/4;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->extra_dug_item = std::string("CraftItem2 ") + itos (CONTENT_CRAFTITEM_MUSH) + " 1";
	f->extra_dug_item_rarity = 10;
	f->setNodeBox(core::aabbox3d<f32>(
		-0.4375*BS,
		-0.5*BS,
		-0.4375*BS,
		0.4375*BS,
		0.5*BS,
		0.4375*BS
	));
	f->addNodeBox(core::aabbox3d<f32>(
		-0.5*BS,
		0.3125*BS,
		-0.5*BS,
		-0.4375*BS,
		0.375*BS,
		-0.4375*BS
	));
	f->addNodeBox(core::aabbox3d<f32>(
		0.4375*BS,
		0.125*BS,
		0.4375*BS,
		0.5*BS,
		0.1875*BS,
		0.5*BS
	));
	f->addNodeBox(core::aabbox3d<f32>(
		0.4375*BS,
		-0.1875*BS,
		-0.5*BS,
		0.5*BS,
		-0.125*BS,
		-0.4375*BS
	));
	f->addNodeBox(core::aabbox3d<f32>(
		-0.5*BS,
		-0.375*BS,
		0.4375*BS,
		-0.4375*BS,
		-0.3125*BS,
		0.5*BS
	));
	f->setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png");
	f->type = CMT_WOOD;
	f->hardness = 0.75;
	f->pressure_type = CST_CRUSHABLE;
	lists::add("creative",i);

	i = CONTENT_PAPYRUS;
	f = &content_features(i);
	f->description = wgettext("Papyrus");
	f->setInventoryTexture("papyrus.png");
	f->setAllTextures("papyrus.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->param2_type = CPT_PLANTGROWTH;
	f->draw_type = CDT_PLANTLIKE;
	f->plantgrowth_large_dug_node = CONTENT_PAPYRUS;
	f->plantgrowth_large_count = 1;
	f->plantgrowth_max_height = 5;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->type = CMT_PLANT;
	f->hardness = 0.25;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_SAPLING;
	f = &content_features(i);
	f->description = wgettext("Sapling");
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->setAllTextures("sapling.png");
	f->setInventoryTexture("sapling.png");
	f->setAllTextureFlags(0);
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->light_propagates = true;
	f->air_equivalent = false;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 1;
	f->type = CMT_WOOD;
	f->hardness = 0.1;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	f->fertilizer_affects = true;
	lists::add("creative",i);

	i = CONTENT_APPLE_SAPLING;
	f = &content_features(i);
	f->description = wgettext("Apple Tree Sapling");
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->setAllTextures("apple_sapling.png");
	f->setInventoryTexture("apple_sapling.png");
	f->setAllTextureFlags(0);
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->light_propagates = true;
	f->air_equivalent = false;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 1;
	f->type = CMT_WOOD;
	f->hardness = 0.1;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	f->fertilizer_affects = true;
	lists::add("creative",i);

	i = CONTENT_JUNGLESAPLING;
	f = &content_features(i);
	f->description = wgettext("Jungle Sapling");
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->setAllTextures("junglesapling.png");
	f->setInventoryTexture("junglesapling.png");
	f->setAllTextureFlags(0);
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->light_propagates = true;
	f->air_equivalent = false;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 1;
	f->type = CMT_WOOD;
	f->hardness = 0.1;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	f->fertilizer_affects = true;
	lists::add("creative",i);

	i = CONTENT_CONIFER_SAPLING;
	f = &content_features(i);
	f->description = wgettext("Conifer Sapling");
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->setAllTextures("conifer_sapling.png");
	f->setInventoryTexture("conifer_sapling.png");
	f->setAllTextureFlags(0);
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->light_propagates = true;
	f->air_equivalent = false;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 1;
	f->type = CMT_WOOD;
	f->hardness = 0.1;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	f->fertilizer_affects = true;
	lists::add("creative",i);

	i = CONTENT_APPLE;
	f = &content_features(i);
	f->description = wgettext("Apple");
	f->setInventoryTexture("apple.png");
	f->setAllTextures("apple.png");
	f->setAllTextureFlags(0);
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE_SML;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->air_equivalent = true;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 1;
	f->dug_item = std::string("CraftItem apple 1");
	f->ondig_replace_node = CONTENT_APPLE_LEAVES;
	f->ondig_replace_node_requires = CONTENT_APPLE_TREE;
	f->type = CMT_WOOD;
	f->hardness = 0.0;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	// plants
	i = CONTENT_WILDGRASS_SHORT;
	f = &content_features(i);
	f->description = wgettext("Wild Grass");
	f->setInventoryTexture("wildgrass_short.png");
	f->setAllTextures("wildgrass_short.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->air_equivalent = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->material_pointable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	//f->pointable = false;
	f->buildable_to = true;
	f->type = CMT_PLANT;
	f->hardness = 0.10;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;

	i = CONTENT_WILDGRASS_LONG;
	f = &content_features(i);
	f->description = wgettext("Wild Grass");
	f->setInventoryTexture("wildgrass_long.png");
	f->setAllTextures("wildgrass_long.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->air_equivalent = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_WILDGRASS_SHORT)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->material_pointable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->buildable_to = true;
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;

	i = CONTENT_DEADGRASS;
	f = &content_features(i);
	f->description = wgettext("Dead Grass");
	f->setInventoryTexture("deadgrass.png");
	f->setAllTextures("deadgrass.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->air_equivalent = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->material_pointable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->buildable_to = true;
	f->type = CMT_PLANT;
	f->hardness = 0.10;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;

	i = CONTENT_FLOWER_STEM;
	f = &content_features(i);
	f->description = wgettext("Flower Stem");
	f->setInventoryTexture("flower_stem.png");
	f->setAllTextures("flower_stem.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->air_equivalent = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->material_pointable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->buildable_to = true;
	f->type = CMT_PLANT;
	f->hardness = 0.10;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;

	i = CONTENT_FLOWER_ROSE;
	f = &content_features(i);
	f->description = wgettext("Rose");
	f->setInventoryTexture("flower_rose.png");
	f->setAllTextures("flower_rose.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->air_equivalent = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->material_pointable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->buildable_to = true;
	f->type = CMT_PLANT;
	f->hardness = 0.10;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_FLOWER_DAFFODIL;
	f = &content_features(i);
	f->description = wgettext("Daffodil");
	f->setInventoryTexture("flower_daffodil.png");
	f->setAllTextures("flower_daffodil.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->air_equivalent = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->material_pointable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->buildable_to = true;
	f->type = CMT_PLANT;
	f->hardness = 0.10;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_FLOWER_TULIP;
	f = &content_features(i);
	f->description = wgettext("Tulip");
	f->setInventoryTexture("flower_tulip.png");
	f->setAllTextures("flower_tulip.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->air_equivalent = true;
	f->param_type = CPT_LIGHT;
	f->draw_type = CDT_PLANTLIKE;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->material_pointable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->buildable_to = true;
	f->type = CMT_PLANT;
	f->hardness = 0.10;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_SEEDS_TEA;
	f = &content_features(i);
	f->description = wgettext("Tea Seeds");
	f->setAllTextures("farm_seeds_tea.png");
	f->draw_type = CDT_PLANTLIKE;
	f->param_type = CPT_LIGHT;
	f->setAllTextureFlags(0);
	f->walkable = false;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->air_equivalent = true;
	f->special_alternate_node = CONTENT_TEA;
	f->solidness = 0; // drawn separately, makes no faces
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->type = CMT_PLANT;
	f->hardness = 0.4;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_TEA;
	f = &content_features(i);
	f->description = wgettext("Tea Plant");
	f->setInventoryTexture("plant_tea.png");
	f->setAllTextures("plant_tea.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->param2_type = CPT_PLANTGROWTH;
	f->draw_type = CDT_PLANTLIKE;
	f->plantgrowth_small_dug_node = CONTENT_SEEDS_TEA;
	f->plantgrowth_large_dug_node = CONTENT_CRAFTITEM_TEA_LEAVES;
	f->plantgrowth_large_gives_small = true;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->buildable_to = true;
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_BEANS_COFFEE;
	f = &content_features(i);
	f->description = wgettext("Coffee Beans");
	f->setAllTextures("farm_seeds_coffee.png");
	f->draw_type = CDT_PLANTLIKE;
	f->param_type = CPT_LIGHT;
	f->setAllTextureFlags(0);
	f->walkable = false;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->air_equivalent = true;
	f->special_alternate_node = CONTENT_COFFEE;
	f->solidness = 0; // drawn separately, makes no faces
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->cook_result = std::string("CraftItem2 ")+itos(CONTENT_CRAFTITEM_COFFEE_BEANS)+" 1";
	f->type = CMT_PLANT;
	f->hardness = 0.4;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);

	i = CONTENT_COFFEE;
	f = &content_features(i);
	f->description = wgettext("Coffee Plant");
	f->setInventoryTexture("plant_coffe.png");
	f->setAllTextures("plant_coffee.png");
	f->setAllTextureFlags(0);
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->param2_type = CPT_PLANTGROWTH;
	f->draw_type = CDT_PLANTLIKE;
	f->plantgrowth_small_dug_node = CONTENT_BEANS_COFFEE;
	f->plantgrowth_large_dug_node = CONTENT_BEANS_COFFEE;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->flammable = 1; // can be replaced by fire if the node under it is set on fire
	f->fuel_time = 30/32;
	f->buildable_to = true;
	f->type = CMT_PLANT;
	f->hardness = 0.15;
	f->pressure_type = CST_CRUSHABLE;
	f->suffocation_per_second = 0;
	lists::add("creative",i);
}
Exemplo n.º 15
0
void mapblock_mesh_generate_special(MeshMakeData *data,
		MeshCollector &collector)
{
	// 0ms
	//TimeTaker timer("mapblock_mesh_generate_special()");

	/*
		Some settings
	*/
	bool new_style_water = g_settings.getBool("new_style_water");
	bool new_style_leaves = g_settings.getBool("new_style_leaves");
	//bool smooth_lighting = g_settings.getBool("smooth_lighting");
	bool invisible_stone = g_settings.getBool("invisible_stone");
	
	float node_water_level = 1.0;
	if(new_style_water)
		node_water_level = 0.85;
	
	v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;

	// Flowing water material
	video::SMaterial material_water1;
	material_water1.setFlag(video::EMF_LIGHTING, false);
	material_water1.setFlag(video::EMF_BACK_FACE_CULLING, false);
	material_water1.setFlag(video::EMF_BILINEAR_FILTER, false);
	material_water1.setFlag(video::EMF_FOG_ENABLE, true);
	material_water1.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
	AtlasPointer pa_water1 = g_texturesource->getTexture(
			g_texturesource->getTextureId("water.png"));
	material_water1.setTexture(0, pa_water1.atlas);

	// New-style leaves material
	video::SMaterial material_leaves1;
	material_leaves1.setFlag(video::EMF_LIGHTING, false);
	//material_leaves1.setFlag(video::EMF_BACK_FACE_CULLING, false);
	material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
	material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
	material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
	AtlasPointer pa_leaves1 = g_texturesource->getTexture(
			g_texturesource->getTextureId("leaves.png"));
	material_leaves1.setTexture(0, pa_leaves1.atlas);

	// Glass material
	video::SMaterial material_glass;
	material_glass.setFlag(video::EMF_LIGHTING, false);
	material_glass.setFlag(video::EMF_BILINEAR_FILTER, false);
	material_glass.setFlag(video::EMF_FOG_ENABLE, true);
	material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
	AtlasPointer pa_glass = g_texturesource->getTexture(
			g_texturesource->getTextureId("glass.png"));
	material_glass.setTexture(0, pa_glass.atlas);

	// Wood material
	video::SMaterial material_wood;
	material_wood.setFlag(video::EMF_LIGHTING, false);
	material_wood.setFlag(video::EMF_BILINEAR_FILTER, false);
	material_wood.setFlag(video::EMF_FOG_ENABLE, true);
	material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
	AtlasPointer pa_wood = g_texturesource->getTexture(
			g_texturesource->getTextureId("wood.png"));
	material_wood.setTexture(0, pa_wood.atlas);

	// General ground material for special output
	// Texture is modified just before usage
	video::SMaterial material_general;
	material_general.setFlag(video::EMF_LIGHTING, false);
	material_general.setFlag(video::EMF_BILINEAR_FILTER, false);
	material_general.setFlag(video::EMF_FOG_ENABLE, true);
	material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;


	// Papyrus material
	video::SMaterial material_papyrus;
	material_papyrus.setFlag(video::EMF_LIGHTING, false);
	material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false);
	material_papyrus.setFlag(video::EMF_FOG_ENABLE, true);
	material_papyrus.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
	AtlasPointer pa_papyrus = g_texturesource->getTexture(
			g_texturesource->getTextureId("papyrus.png"));
	material_papyrus.setTexture(0, pa_papyrus.atlas);
	for(s16 z=0; z<MAP_BLOCKSIZE; z++)
	for(s16 y=0; y<MAP_BLOCKSIZE; y++)
	for(s16 x=0; x<MAP_BLOCKSIZE; x++)
	{
		v3s16 p(x,y,z);

		MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
		
		/*
			Add torches to mesh
		*/
		if(n.d == CONTENT_TORCH)
		{
			video::SColor c(255,255,255,255);

			// Wall at X+ of node
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
				video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
				video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
				video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
			};

			v3s16 dir = unpackDir(n.dir);

			for(s32 i=0; i<4; i++)
			{
				if(dir == v3s16(1,0,0))
					vertices[i].Pos.rotateXZBy(0);
				if(dir == v3s16(-1,0,0))
					vertices[i].Pos.rotateXZBy(180);
				if(dir == v3s16(0,0,1))
					vertices[i].Pos.rotateXZBy(90);
				if(dir == v3s16(0,0,-1))
					vertices[i].Pos.rotateXZBy(-90);
				if(dir == v3s16(0,-1,0))
					vertices[i].Pos.rotateXZBy(45);
				if(dir == v3s16(0,1,0))
					vertices[i].Pos.rotateXZBy(-45);

				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			// Set material
			video::SMaterial material;
			material.setFlag(video::EMF_LIGHTING, false);
			material.setFlag(video::EMF_BACK_FACE_CULLING, false);
			material.setFlag(video::EMF_BILINEAR_FILTER, false);
			//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
			material.MaterialType
					= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;

			if(dir == v3s16(0,-1,0))
				material.setTexture(0,
						g_texturesource->getTextureRaw("torch_on_floor.png"));
			else if(dir == v3s16(0,1,0))
				material.setTexture(0,
						g_texturesource->getTextureRaw("torch_on_ceiling.png"));
			// For backwards compatibility
			else if(dir == v3s16(0,0,0))
				material.setTexture(0,
						g_texturesource->getTextureRaw("torch_on_floor.png"));
			else
				material.setTexture(0, 
						g_texturesource->getTextureRaw("torch.png"));

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(material, vertices, 4, indices, 6);
		}
		/*
			Signs on walls
		*/
		else if(n.d == CONTENT_SIGN_WALL)
		{
			u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
			video::SColor c(255,l,l,l);
				
			float d = (float)BS/16;
			// Wall at X+ of node
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
				video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
				video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
				video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
			};

			v3s16 dir = unpackDir(n.dir);

			for(s32 i=0; i<4; i++)
			{
				if(dir == v3s16(1,0,0))
					vertices[i].Pos.rotateXZBy(0);
				if(dir == v3s16(-1,0,0))
					vertices[i].Pos.rotateXZBy(180);
				if(dir == v3s16(0,0,1))
					vertices[i].Pos.rotateXZBy(90);
				if(dir == v3s16(0,0,-1))
					vertices[i].Pos.rotateXZBy(-90);
				if(dir == v3s16(0,-1,0))
					vertices[i].Pos.rotateXYBy(-90);
				if(dir == v3s16(0,1,0))
					vertices[i].Pos.rotateXYBy(90);

				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			// Set material
			video::SMaterial material;
			material.setFlag(video::EMF_LIGHTING, false);
			material.setFlag(video::EMF_BACK_FACE_CULLING, false);
			material.setFlag(video::EMF_BILINEAR_FILTER, false);
			material.setFlag(video::EMF_FOG_ENABLE, true);
			//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
			material.MaterialType
					= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;

			material.setTexture(0, 
					g_texturesource->getTextureRaw("sign_wall.png"));

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(material, vertices, 4, indices, 6);
		}
		/*
			Add flowing water to mesh
		*/
		else if(n.d == CONTENT_WATER)
		{
			bool top_is_water = false;
			MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
			if(ntop.d == CONTENT_WATER || ntop.d == CONTENT_WATERSOURCE)
				top_is_water = true;
			
			u8 l = 0;
			// Use the light of the node on top if possible
			if(content_features(ntop.d).param_type == CPT_LIGHT)
				l = decode_light(ntop.getLightBlend(data->m_daynight_ratio));
			// Otherwise use the light of this node (the water)
			else
				l = decode_light(n.getLightBlend(data->m_daynight_ratio));
			video::SColor c(WATER_ALPHA,l,l,l);
			
			// Neighbor water levels (key = relative position)
			// Includes current node
			core::map<v3s16, f32> neighbor_levels;
			core::map<v3s16, u8> neighbor_contents;
			core::map<v3s16, u8> neighbor_flags;
			const u8 neighborflag_top_is_water = 0x01;
			v3s16 neighbor_dirs[9] = {
				v3s16(0,0,0),
				v3s16(0,0,1),
				v3s16(0,0,-1),
				v3s16(1,0,0),
				v3s16(-1,0,0),
				v3s16(1,0,1),
				v3s16(-1,0,-1),
				v3s16(1,0,-1),
				v3s16(-1,0,1),
			};
			for(u32 i=0; i<9; i++)
			{
				u8 content = CONTENT_AIR;
				float level = -0.5 * BS;
				u8 flags = 0;
				// Check neighbor
				v3s16 p2 = p + neighbor_dirs[i];
				MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
				if(n2.d != CONTENT_IGNORE)
				{
					content = n2.d;

					if(n2.d == CONTENT_WATERSOURCE)
						level = (-0.5+node_water_level) * BS;
					else if(n2.d == CONTENT_WATER)
						level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0
								* node_water_level) * BS;

					// Check node above neighbor.
					// NOTE: This doesn't get executed if neighbor
					//       doesn't exist
					p2.Y += 1;
					n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
					if(n2.d == CONTENT_WATERSOURCE || n2.d == CONTENT_WATER)
						flags |= neighborflag_top_is_water;
				}
				
				neighbor_levels.insert(neighbor_dirs[i], level);
				neighbor_contents.insert(neighbor_dirs[i], content);
				neighbor_flags.insert(neighbor_dirs[i], flags);
			}

			//float water_level = (-0.5 + ((float)n.param2 + 0.5) / 8.0) * BS;
			//float water_level = neighbor_levels[v3s16(0,0,0)];

			// Corner heights (average between four waters)
			f32 corner_levels[4];
			
			v3s16 halfdirs[4] = {
				v3s16(0,0,0),
				v3s16(1,0,0),
				v3s16(1,0,1),
				v3s16(0,0,1),
			};
			for(u32 i=0; i<4; i++)
			{
				v3s16 cornerdir = halfdirs[i];
				float cornerlevel = 0;
				u32 valid_count = 0;
				for(u32 j=0; j<4; j++)
				{
					v3s16 neighbordir = cornerdir - halfdirs[j];
					u8 content = neighbor_contents[neighbordir];
					// Special case for source nodes
					if(content == CONTENT_WATERSOURCE)
					{
						cornerlevel = (-0.5+node_water_level)*BS;
						valid_count = 1;
						break;
					}
					else if(content == CONTENT_WATER)
					{
						cornerlevel += neighbor_levels[neighbordir];
						valid_count++;
					}
					else if(content == CONTENT_AIR)
					{
						cornerlevel += -0.5*BS;
						valid_count++;
					}
				}
				if(valid_count > 0)
					cornerlevel /= valid_count;
				corner_levels[i] = cornerlevel;
			}

			/*
				Generate sides
			*/

			v3s16 side_dirs[4] = {
				v3s16(1,0,0),
				v3s16(-1,0,0),
				v3s16(0,0,1),
				v3s16(0,0,-1),
			};
			s16 side_corners[4][2] = {
				{1, 2},
				{3, 0},
				{2, 3},
				{0, 1},
			};
			for(u32 i=0; i<4; i++)
			{
				v3s16 dir = side_dirs[i];

				/*
					If our topside is water and neighbor's topside
					is water, don't draw side face
				*/
				if(top_is_water &&
						neighbor_flags[dir] & neighborflag_top_is_water)
					continue;

				u8 neighbor_content = neighbor_contents[dir];
				
				// Don't draw face if neighbor is not air or water
				if(neighbor_content != CONTENT_AIR
						&& neighbor_content != CONTENT_WATER)
					continue;
				
				bool neighbor_is_water = (neighbor_content == CONTENT_WATER);
				
				// Don't draw any faces if neighbor is water and top is water
				if(neighbor_is_water == true && top_is_water == false)
					continue;
				
				video::S3DVertex vertices[4] =
				{
					/*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_water1.x0(), pa_water1.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_water1.x1(), pa_water1.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_water1.x1(), pa_water1.y0()),
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_water1.x0(), pa_water1.y0()),
				};
				
				/*
					If our topside is water, set upper border of face
					at upper border of node
				*/
				if(top_is_water)
				{
					vertices[2].Pos.Y = 0.5*BS;
					vertices[3].Pos.Y = 0.5*BS;
				}
				/*
					Otherwise upper position of face is corner levels
				*/
				else
				{
					vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
					vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
				}
				
				/*
					If neighbor is water, lower border of face is corner
					water levels
				*/
				if(neighbor_is_water)
				{
					vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
					vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
				}
				/*
					If neighbor is not water, lower border of face is
					lower border of node
				*/
				else
				{
					vertices[0].Pos.Y = -0.5*BS;
					vertices[1].Pos.Y = -0.5*BS;
				}
				
				for(s32 j=0; j<4; j++)
				{
					if(dir == v3s16(0,0,1))
						vertices[j].Pos.rotateXZBy(0);
					if(dir == v3s16(0,0,-1))
						vertices[j].Pos.rotateXZBy(180);
					if(dir == v3s16(-1,0,0))
						vertices[j].Pos.rotateXZBy(90);
					if(dir == v3s16(1,0,-0))
						vertices[j].Pos.rotateXZBy(-90);

					vertices[j].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_water1, vertices, 4, indices, 6);
			}
			
			/*
				Generate top side, if appropriate
			*/
			
			if(top_is_water == false)
			{
				video::S3DVertex vertices[4] =
				{
					/*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
					video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_water1.x0(), pa_water1.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_water1.x1(), pa_water1.y1()),
					video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
							pa_water1.x1(), pa_water1.y0()),
					video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
							pa_water1.x0(), pa_water1.y0()),
				};
				
				// This fixes a strange bug
				s32 corner_resolve[4] = {3,2,1,0};

				for(s32 i=0; i<4; i++)
				{
					//vertices[i].Pos.Y += water_level;
					//vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
					s32 j = corner_resolve[i];
					vertices[i].Pos.Y += corner_levels[j];
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_water1, vertices, 4, indices, 6);
			}
		}
		/*
			Add water sources to mesh if using new style
		*/
		else if(n.d == CONTENT_WATERSOURCE && new_style_water)
		{
			//bool top_is_water = false;
			bool top_is_air = false;
			MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
			/*if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
				top_is_water = true;*/
			if(n.d == CONTENT_AIR)
				top_is_air = true;
			
			/*if(top_is_water == true)
				continue;*/
			if(top_is_air == false)
				continue;

			u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
			video::SColor c(WATER_ALPHA,l,l,l);
			
			video::S3DVertex vertices[4] =
			{
				/*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
				video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
				video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
				video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
				video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
						pa_water1.x0(), pa_water1.y1()),
				video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
						pa_water1.x1(), pa_water1.y1()),
				video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
						pa_water1.x1(), pa_water1.y0()),
				video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
						pa_water1.x0(), pa_water1.y0()),
			};

			for(s32 i=0; i<4; i++)
			{
				vertices[i].Pos.Y += (-0.5+node_water_level)*BS;
				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(material_water1, vertices, 4, indices, 6);
		}
		/*
			Add leaves if using new style
		*/
		else if(n.d == CONTENT_LEAVES && new_style_leaves)
		{
			/*u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));*/
			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
			video::SColor c(255,l,l,l);

			for(u32 j=0; j<6; j++)
			{
				video::S3DVertex vertices[4] =
				{
					/*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
					video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x0(), pa_leaves1.y1()),
					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x1(), pa_leaves1.y1()),
					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x1(), pa_leaves1.y0()),
					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x0(), pa_leaves1.y0()),
				};

				if(j == 0)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(0);
				}
				else if(j == 1)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(180);
				}
				else if(j == 2)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-90);
				}
				else if(j == 3)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(90);
				}
				else if(j == 4)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(-90);
				}
				else if(j == 5)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(90);
				}

				for(u16 i=0; i<4; i++)
				{
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_leaves1, vertices, 4, indices, 6);
			}
		}
		/*
			Add glass
		*/
		else if(n.d == CONTENT_GLASS)
		{
			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
			video::SColor c(255,l,l,l);

			for(u32 j=0; j<6; j++)
			{
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_glass.x0(), pa_glass.y1()),
					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_glass.x1(), pa_glass.y1()),
					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
						pa_glass.x1(), pa_glass.y0()),
					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
						pa_glass.x0(), pa_glass.y0()),
				};

				if(j == 0)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(0);
				}
				else if(j == 1)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(180);
				}
				else if(j == 2)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-90);
				}
				else if(j == 3)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(90);
				}
				else if(j == 4)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(-90);
				}
				else if(j == 5)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(90);
				}

				for(u16 i=0; i<4; i++)
				{
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_glass, vertices, 4, indices, 6);
			}
		}
		/*
			Add fence
		*/
		else if(n.d == CONTENT_FENCE)
		{
			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
			video::SColor c(255,l,l,l);

			const f32 post_rad=(f32)BS/10;
			const f32 bar_rad=(f32)BS/20;
			const f32 bar_len=(f32)(BS/2)-post_rad;

			// The post - always present
			v3f pos = intToFloat(p+blockpos_nodes, BS);
			f32 postuv[24]={
					0.4,0.4,0.6,0.6,
					0.35,0,0.65,1,
					0.35,0,0.65,1,
					0.35,0,0.65,1,
					0.35,0,0.65,1,
					0.4,0.4,0.6,0.6};
			makeCuboid(material_wood, &collector,
				&pa_wood, c, pos,
				post_rad,BS/2,post_rad, postuv);

			// Now a section of fence, +X, if there's a post there
			v3s16 p2 = p;
			p2.X++;
			MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
			if(n2.d == CONTENT_FENCE)
			{
				pos = intToFloat(p+blockpos_nodes, BS);
				pos.X += BS/2;
				pos.Y += BS/4;
				f32 xrailuv[24]={
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6};
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_len,bar_rad,bar_rad, xrailuv);

				pos.Y -= BS/2;
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_len,bar_rad,bar_rad, xrailuv);
			}

			// Now a section of fence, +Z, if there's a post there
			p2 = p;
			p2.Z++;
			n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
			if(n2.d == CONTENT_FENCE)
			{
				pos = intToFloat(p+blockpos_nodes, BS);
				pos.Z += BS/2;
				pos.Y += BS/4;
				f32 zrailuv[24]={
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6};
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_rad,bar_rad,bar_len, zrailuv);
				pos.Y -= BS/2;
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_rad,bar_rad,bar_len, zrailuv);

			}

		}
#if 1
		/*
			Add stones with minerals if stone is invisible
		*/
		else if(n.d == CONTENT_STONE && invisible_stone && n.getMineral() != MINERAL_NONE)
		{
			for(u32 j=0; j<6; j++)
			{
				// NOTE: Hopefully g_6dirs[j] is the right direction...
				v3s16 dir = g_6dirs[j];
				/*u8 l = 0;
				MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + dir);
				if(content_features(n2.d).param_type == CPT_LIGHT)
					l = decode_light(n2.getLightBlend(data->m_daynight_ratio));
				else
					l = 255;*/
				u8 l = 255;
				video::SColor c(255,l,l,l);
				
				// Get the right texture
				TileSpec ts = n.getTile(dir);
				AtlasPointer ap = ts.texture;
				material_general.setTexture(0, ap.atlas);
				video::S3DVertex vertices[4] =
 				{
					/*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
					video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
						ap.x0(), ap.y1()),
					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
						ap.x1(), ap.y1()),
					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
						ap.x1(), ap.y0()),
					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
						ap.x0(), ap.y0()),
				};

				if(j == 0)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(0);
				}
				else if(j == 1)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(180);
				}
				else if(j == 2)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-90);
				}
				else if(j == 3)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(90);
				}
				else if(j == 4)

				for(u16 i=0; i<4; i++)
				{
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_general, vertices, 4, indices, 6);
			}
		}
#endif
		else if(n.d == CONTENT_PAPYRUS)
		{
			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
			video::SColor c(255,l,l,l);

			for(u32 j=0; j<4; j++)
			{
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
						pa_papyrus.x0(), pa_papyrus.y1()),
					video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
						pa_papyrus.x1(), pa_papyrus.y1()),
					video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
						pa_papyrus.x1(), pa_papyrus.y0()),
					video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
						pa_papyrus.x0(), pa_papyrus.y0()),
				};

				if(j == 0)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(45);
				}
				else if(j == 1)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-45);
				}
				else if(j == 2)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(135);
				}
				else if(j == 3)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-135);
				}

				for(u16 i=0; i<4; i++)
				{
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_papyrus, vertices, 4, indices, 6);
			}
		}
		else if(n.d == CONTENT_RAIL)
		{
			u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
			video::SColor c(255,l,l,l);

			bool is_rail_x [] = { false, false };  /* x-1, x+1 */
			bool is_rail_z [] = { false, false };  /* z-1, z+1 */

			MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z));
			MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z));
			MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1));
			MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1));

			if(n_minus_x.d == CONTENT_RAIL)
				is_rail_x[0] = true;
			if(n_plus_x.d == CONTENT_RAIL)
				is_rail_x[1] = true;
			if(n_minus_z.d == CONTENT_RAIL)
				is_rail_z[0] = true;
			if(n_plus_z.d == CONTENT_RAIL)
				is_rail_z[1] = true;

			float d = (float)BS/16;
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
					0, 1),
				video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
					1, 1),
				video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c,
					1, 0),
				video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c,
					0, 0),
			};

			video::SMaterial material_rail;
			material_rail.setFlag(video::EMF_LIGHTING, false);
			material_rail.setFlag(video::EMF_BACK_FACE_CULLING, false);
			material_rail.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_rail.setFlag(video::EMF_FOG_ENABLE, true);
			material_rail.MaterialType
					= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;

			int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1];

			// Assign textures
			if(adjacencies < 2)
				material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png"));
			else if(adjacencies == 2)
			{
				if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1]))
					material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png"));
				else
					material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_curved.png"));
			}
			else if(adjacencies == 3)
				material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_t_junction.png"));
			else if(adjacencies == 4)
				material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_crossing.png"));

			// Rotate textures
			int angle = 0;

			if(adjacencies == 1)
			{
				if(is_rail_x[0] || is_rail_x[1])
					angle = 90;
			}
			else if(adjacencies == 2)
			{
				if(is_rail_x[0] && is_rail_x[1])
					angle = 90;
				else if(is_rail_x[0] && is_rail_z[0])
					angle = 270;
				else if(is_rail_x[0] && is_rail_z[1])
					angle = 180;
				else if(is_rail_x[1] && is_rail_z[1])
					angle = 90;
			}
			else if(adjacencies == 3)
			{
				if(!is_rail_x[0])
					angle=0;
				if(!is_rail_x[1])
					angle=180;
				if(!is_rail_z[0])
					angle=90;
				if(!is_rail_z[1])
					angle=270;
			}

			if(angle != 0) {
				for(u16 i=0; i<4; i++)
					vertices[i].Pos.rotateXZBy(angle);
			}

			for(s32 i=0; i<4; i++)
			{
				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			collector.append(material_rail, vertices, 4, indices, 6);
		}
	}
}
ContentFeatures & content_features(MapNode &n)
{
	return content_features(n.getContent());
}
Exemplo n.º 17
0
void MovingObject::move(float dtime, v3f acceleration)
{
	DSTACKF("%s: typeid=%i, pos=(%f,%f,%f), speed=(%f,%f,%f)"
			", dtime=%f, acc=(%f,%f,%f)",
			__FUNCTION_NAME,
			getTypeId(),
			m_pos.X, m_pos.Y, m_pos.Z,
			m_speed.X, m_speed.Y, m_speed.Z,
			dtime,
			acceleration.X, acceleration.Y, acceleration.Z
			);
	
	v3s16 oldpos_i = floatToInt(m_pos, BS);
	
	if(m_block->isValidPosition(oldpos_i) == false)
	{
		// Should have wrapped, cancelling further movement.
		return;
	}

	// No collisions if there is no collision box
	if(m_collision_box == NULL)
	{
		m_speed += dtime * acceleration;
		m_pos += m_speed * dtime;
		return;
	}
	
	// Set insane speed to zero
	// Otherwise there will be divides by zero and other silly stuff
	if(m_speed.getLength() > 1000.0*BS)
		m_speed = v3f(0,0,0);
		
	// Limit speed to a reasonable value
	float speed_limit = 20.0*BS;
	if(m_speed.getLength() > speed_limit)
		m_speed = m_speed * (speed_limit / m_speed.getLength());

	v3f position = m_pos;
	v3f oldpos = position;

	/*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
			<<oldpos_i.Z<<")"<<std::endl;*/

	// Maximum time increment (for collision detection etc)
	// Allow 0.1 blocks per increment
	// time = distance / speed
	// NOTE: In the loop below collisions are detected at 0.15*BS radius
	float speedlength = m_speed.getLength();
	f32 dtime_max_increment;
	if(fabs(speedlength) > 0.001)
		dtime_max_increment = 0.05*BS / speedlength;
	else
		dtime_max_increment = 0.5;
	
	m_touching_ground = false;
		
	u32 loopcount = 0;
	do
	{
		loopcount++;

		f32 dtime_part;
		if(dtime > dtime_max_increment)
			dtime_part = dtime_max_increment;
		else
			dtime_part = dtime;
		dtime -= dtime_part;

		// Begin of dtime limited code
		
		m_speed += acceleration * dtime_part;
		position += m_speed * dtime_part;

		/*
			Collision detection
		*/
		
		v3s16 pos_i = floatToInt(position, BS);
		
		// The loop length is limited to the object moving a distance
		f32 d = (float)BS * 0.15;

		core::aabbox3d<f32> objectbox(
				m_collision_box->MinEdge + position,
				m_collision_box->MaxEdge + position
		);
		
		core::aabbox3d<f32> objectbox_old(
				m_collision_box->MinEdge + oldpos,
				m_collision_box->MaxEdge + oldpos
		);
		
		//TODO: Get these ranges from somewhere
		for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
		for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
		for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
		{
			try{
				MapNode n = m_block->getNodeParent(v3s16(x,y,z));
				if(content_features(n).walkable == false)
					continue;
			}
			catch(InvalidPositionException &e)
			{
				// Doing nothing here will block the object from
				// walking over map borders
			}

			core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
			
			// See if the object is touching ground
			if(
					fabs(nodebox.MaxEdge.Y-objectbox.MinEdge.Y) < d
					&& nodebox.MaxEdge.X-d > objectbox.MinEdge.X
					&& nodebox.MinEdge.X+d < objectbox.MaxEdge.X
					&& nodebox.MaxEdge.Z-d > objectbox.MinEdge.Z
					&& nodebox.MinEdge.Z+d < objectbox.MaxEdge.Z
			){
				m_touching_ground = true;
			}
			
			if(objectbox.intersectsWithBox(nodebox))
			{
					
		v3f dirs[3] = {
			v3f(0,0,1), // back
			v3f(0,1,0), // top
			v3f(1,0,0), // right
		};
		for(u16 i=0; i<3; i++)
		{
			f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
			f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
			f32 playermax = objectbox.MaxEdge.dotProduct(dirs[i]);
			f32 playermin = objectbox.MinEdge.dotProduct(dirs[i]);
			f32 playermax_old = objectbox_old.MaxEdge.dotProduct(dirs[i]);
			f32 playermin_old = objectbox_old.MinEdge.dotProduct(dirs[i]);

			bool main_edge_collides = 
				((nodemax > playermin && nodemax <= playermin_old + d
					&& m_speed.dotProduct(dirs[i]) < 0)
				||
				(nodemin < playermax && nodemin >= playermax_old - d
					&& m_speed.dotProduct(dirs[i]) > 0));

			bool other_edges_collide = true;
			for(u16 j=0; j<3; j++)
			{
				if(j == i)
					continue;
				f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
				f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
				f32 playermax = objectbox.MaxEdge.dotProduct(dirs[j]);
				f32 playermin = objectbox.MinEdge.dotProduct(dirs[j]);
				if(!(nodemax - d > playermin && nodemin + d < playermax))
				{
					other_edges_collide = false;
					break;
				}
			}
			
			if(main_edge_collides && other_edges_collide)
			{
				m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
				position -= position.dotProduct(dirs[i]) * dirs[i];
				position += oldpos.dotProduct(dirs[i]) * dirs[i];
			}
		
		}
		
			} // if(objectbox.intersectsWithBox(nodebox))
		} // for y

	} // End of dtime limited loop
	while(dtime > 0.001);

	m_pos = position;
}
Exemplo n.º 18
0
void content_mapnode_init()
{
	// Read some settings
	bool new_style_water = g_settings.getBool("new_style_water");
	bool new_style_leaves = g_settings.getBool("new_style_leaves");
	bool invisible_stone = g_settings.getBool("invisible_stone");

	content_t i;
	ContentFeatures *f = NULL;

	i = CONTENT_STONE;
	f = &content_features(i);
	f->setAllTextures("stone.png");
	f->setInventoryTextureCube("stone.png", "stone.png", "stone.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 1.0);
	if(invisible_stone)
		f->solidness = 0; // For debugging, hides regular stone
	
	i = CONTENT_GRASS;
	f = &content_features(i);
	f->setAllTextures("mud.png^grass_side.png");
	f->setTexture(0, "grass.png");
	f->setTexture(1, "mud.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_MUD)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_GRASS_FOOTSTEPS;
	f = &content_features(i);
	f->setAllTextures("mud.png^grass_side.png");
	f->setTexture(0, "grass_footsteps.png");
	f->setTexture(1, "mud.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_MUD)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_MUD;
	f = &content_features(i);
	f->setAllTextures("mud.png");
	f->setInventoryTextureCube("mud.png", "mud.png", "mud.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_SAND;
	f = &content_features(i);
	f->setAllTextures("sand.png");
	f->setInventoryTextureCube("sand.png", "sand.png", "sand.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_GRAVEL;
	f = &content_features(i);
	f->setAllTextures("gravel.png");
	f->setInventoryTextureCube("gravel.png", "gravel.png", "gravel.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.75);
	
	i = CONTENT_SANDSTONE;
	f = &content_features(i);
	f->setAllTextures("sandstone.png");
	f->setInventoryTextureCube("sandstone.png", "sandstone.png", "sandstone.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAND)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);

	i = CONTENT_CLAY;
	f = &content_features(i);
	f->setAllTextures("clay.png");
	f->setInventoryTextureCube("clay.png", "clay.png", "clay.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("CraftItem lump_of_clay 4");
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);

	i = CONTENT_BRICK;
	f = &content_features(i);
	f->setAllTextures("brick.png");
	f->setInventoryTextureCube("brick.png", "brick.png", "brick.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("CraftItem clay_brick 4");
	setStoneLikeDiggingProperties(f->digging_properties, 1.0);

	i = CONTENT_TREE;
	f = &content_features(i);
	f->setAllTextures("tree.png");
	f->setTexture(0, "tree_top.png");
	f->setTexture(1, "tree_top.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setWoodLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_JUNGLETREE;
	f = &content_features(i);
	f->setAllTextures("jungletree.png");
	f->setTexture(0, "jungletree_top.png");
	f->setTexture(1, "jungletree_top.png");
	f->param_type = CPT_MINERAL;
	//f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setWoodLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_JUNGLEGRASS;
	f = &content_features(i);
	f->setInventoryTexture("junglegrass.png");
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	//f->is_ground_content = true;
	f->air_equivalent = false; // grass grows underneath
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	setWoodLikeDiggingProperties(f->digging_properties, 0.10);

	i = CONTENT_LEAVES;
	f = &content_features(i);
	f->light_propagates = true;
	//f->param_type = CPT_MINERAL;
	f->param_type = CPT_LIGHT;
	//f->is_ground_content = true;
	if(new_style_leaves)
	{
		f->solidness = 0; // drawn separately, makes no faces
		f->setInventoryTextureCube("leaves.png", "leaves.png", "leaves.png");
	}
	else
	{
		f->setAllTextures("[noalpha:leaves.png");
	}
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setWoodLikeDiggingProperties(f->digging_properties, 0.15);

	i = CONTENT_CACTUS;
	f = &content_features(i);
	f->setAllTextures("cactus_side.png");
	f->setTexture(0, "cactus_top.png");
	f->setTexture(1, "cactus_top.png");
	f->setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setWoodLikeDiggingProperties(f->digging_properties, 0.75);

	i = CONTENT_PAPYRUS;
	f = &content_features(i);
	f->setInventoryTexture("papyrus.png");
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	setWoodLikeDiggingProperties(f->digging_properties, 0.25);

	i = CONTENT_BOOKSHELF;
	f = &content_features(i);
	f->setAllTextures("bookshelf.png");
	f->setTexture(0, "wood.png");
	f->setTexture(1, "wood.png");
	// FIXME: setInventoryTextureCube() only cares for the first texture
	f->setInventoryTextureCube("bookshelf.png", "bookshelf.png", "bookshelf.png");
	//f->setInventoryTextureCube("wood.png", "bookshelf.png", "bookshelf.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	setWoodLikeDiggingProperties(f->digging_properties, 0.75);

	i = CONTENT_GLASS;
	f = &content_features(i);
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->param_type = CPT_LIGHT;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->setInventoryTextureCube("glass.png", "glass.png", "glass.png");
	setWoodLikeDiggingProperties(f->digging_properties, 0.15);

	i = CONTENT_FENCE;
	f = &content_features(i);
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->air_equivalent = true; // grass grows underneath
	f->setInventoryTexture("item_fence.png");
	setWoodLikeDiggingProperties(f->digging_properties, 0.75);

	i = CONTENT_RAIL;
	f = &content_features(i);
	f->setInventoryTexture("rail.png");
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->air_equivalent = true; // grass grows underneath
	f->walkable = false;
	setDirtLikeDiggingProperties(f->digging_properties, 0.75);

	i = CONTENT_LADDER;
	f = &content_features(i);
	f->setInventoryTexture("ladder.png");
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
	f->wall_mounted = true;
	f->solidness = 0;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	setWoodLikeDiggingProperties(f->digging_properties, 0.5);

	// Deprecated
	i = CONTENT_COALSTONE;
	f = &content_features(i);
	f->setAllTextures("stone.png^mineral_coal.png");
	f->is_ground_content = true;
	setStoneLikeDiggingProperties(f->digging_properties, 1.5);
	
	i = CONTENT_WOOD;
	f = &content_features(i);
	f->setAllTextures("wood.png");
	f->setInventoryTextureCube("wood.png", "wood.png", "wood.png");
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setWoodLikeDiggingProperties(f->digging_properties, 0.75);
	
	i = CONTENT_MESE;
	f = &content_features(i);
	f->setAllTextures("mese.png");
	f->setInventoryTextureCube("mese.png", "mese.png", "mese.png");
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 0.5);
	
	i = CONTENT_CLOUD;
	f = &content_features(i);
	f->setAllTextures("cloud.png");
	f->setInventoryTextureCube("cloud.png", "cloud.png", "cloud.png");
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	
	i = CONTENT_AIR;
	f = &content_features(i);
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->solidness = 0;
	f->walkable = false;
	f->pointable = false;
	f->diggable = false;
	f->buildable_to = true;
	f->air_equivalent = true;
	
	i = CONTENT_WATER;
	f = &content_features(i);
	f->setInventoryTextureCube("water.png", "water.png", "water.png");
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->solidness = 0; // Drawn separately, makes no faces
	f->walkable = false;
	f->pointable = false;
	f->diggable = false;
	f->buildable_to = true;
	f->liquid_type = LIQUID_FLOWING;
	f->liquid_alternative_flowing = CONTENT_WATER;
	f->liquid_alternative_source = CONTENT_WATERSOURCE;
	
	i = CONTENT_WATERSOURCE;
	f = &content_features(i);
	//f->setInventoryTexture("water.png");
	f->setInventoryTextureCube("water.png", "water.png", "water.png");
	if(new_style_water)
	{
		f->solidness = 0; // drawn separately, makes no faces
	}
	else // old style
	{
		f->solidness = 1;

		TileSpec t;
		if(g_texturesource)
			t.texture = g_texturesource->getTexture("water.png");
		
		t.alpha = WATER_ALPHA;
		t.material_type = MATERIAL_ALPHA_VERTEX;
		t.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
		f->setAllTiles(t);
	}
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->walkable = false;
	f->pointable = false;
	f->diggable = false;
	f->buildable_to = true;
	f->liquid_type = LIQUID_SOURCE;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->liquid_alternative_flowing = CONTENT_WATER;
	f->liquid_alternative_source = CONTENT_WATERSOURCE;
	
	i = CONTENT_TORCH;
	f = &content_features(i);
	f->setInventoryTexture("torch_on_floor.png");
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->wall_mounted = true;
	f->air_equivalent = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->light_source = LIGHT_MAX-1;
	f->digging_properties.set("", DiggingProperties(true, 0.0, 0));
	
	i = CONTENT_SIGN_WALL;
	f = &content_features(i);
	f->setInventoryTexture("sign_wall.png");
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->wall_mounted = true;
	f->air_equivalent = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	if(f->initial_metadata == NULL)
		f->initial_metadata = new SignNodeMetadata("Some sign");
	f->digging_properties.set("", DiggingProperties(true, 0.5, 0));
	
	i = CONTENT_CHEST;
	f = &content_features(i);
	f->param_type = CPT_FACEDIR_SIMPLE;
	f->setAllTextures("chest_side.png");
	f->setTexture(0, "chest_top.png");
	f->setTexture(1, "chest_top.png");
	f->setTexture(5, "chest_front.png"); // Z-
	f->setInventoryTexture("chest_top.png");
	//f->setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	if(f->initial_metadata == NULL)
		f->initial_metadata = new ChestNodeMetadata();
	setWoodLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_FURNACE;
	f = &content_features(i);
	f->param_type = CPT_FACEDIR_SIMPLE;
	f->setAllTextures("furnace_side.png");
	f->setTexture(5, "furnace_front.png"); // Z-
	f->setInventoryTexture("furnace_front.png");
	//f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 6";
	if(f->initial_metadata == NULL)
		f->initial_metadata = new FurnaceNodeMetadata();
	setStoneLikeDiggingProperties(f->digging_properties, 3.0);
	
	i = CONTENT_COBBLE;
	f = &content_features(i);
	f->setAllTextures("cobble.png");
	f->setInventoryTextureCube("cobble.png", "cobble.png", "cobble.png");
	f->param_type = CPT_NONE;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 0.9);

	i = CONTENT_MOSSYCOBBLE;
	f = &content_features(i);
	f->setAllTextures("mossycobble.png");
	f->setInventoryTextureCube("mossycobble.png", "mossycobble.png", "mossycobble.png");
	f->param_type = CPT_NONE;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 0.8);
	
	i = CONTENT_STEEL;
	f = &content_features(i);
	f->setAllTextures("steel_block.png");
	f->setInventoryTextureCube("steel_block.png", "steel_block.png",
			"steel_block.png");
	f->param_type = CPT_NONE;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 5.0);
	
	i = CONTENT_NC;
	f = &content_features(i);
	f->param_type = CPT_FACEDIR_SIMPLE;
	f->setAllTextures("nc_side.png");
	f->setTexture(5, "nc_front.png"); // Z-
	f->setTexture(4, "nc_back.png"); // Z+
	f->setInventoryTexture("nc_front.png");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 3.0);
	
	i = CONTENT_NC_RB;
	f = &content_features(i);
	f->setAllTextures("nc_rb.png");
	f->setInventoryTexture("nc_rb.png");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 3.0);
	
	// NOTE: Remember to add frequently used stuff to the texture atlas in tile.cpp
	

	/*
		Add MesePick to everything
	*/
	for(u16 i=0; i<=MAX_CONTENT; i++)
	{
		content_features(i).digging_properties.set("MesePick",
				DiggingProperties(true, 0.0, 65535./1337));
	}

}
/*
	See mapnode.h for description.
*/
void init_mapnode()
{
	if(g_texturesource == NULL)
	{
		dstream<<"INFO: Initial run of init_mapnode with "
				"g_texturesource=NULL. If this segfaults, "
				"there is a bug with something not checking for "
				"the NULL value."<<std::endl;
	}
	else
	{
		dstream<<"INFO: Full run of init_mapnode with "
				"g_texturesource!=NULL"<<std::endl;
	}

	/*// Read some settings
	bool new_style_water = g_settings.getBool("new_style_water");
	bool new_style_leaves = g_settings.getBool("new_style_leaves");*/

	/*
		Initialize content feature table
	*/

#ifndef SERVER
	/*
		Set initial material type to same in all tiles, so that the
		same material can be used in more stuff.
		This is set according to the leaves because they are the only
		differing material to which all materials can be changed to
		get this optimization.
	*/
	u8 initial_material_type = MATERIAL_ALPHA_SIMPLE;
	/*if(new_style_leaves)
		initial_material_type = MATERIAL_ALPHA_SIMPLE;
	else
		initial_material_type = MATERIAL_ALPHA_NONE;*/
	for(u16 i=0; i<MAX_CONTENT+1; i++)
	{
		ContentFeatures *f = &g_content_features[i];
		// Re-initialize
		f->reset();

		for(u16 j=0; j<6; j++)
			f->tiles[j].material_type = initial_material_type;
	}
#endif

	/*
		Initially set every block to be shown as an unknown block.
		Don't touch CONTENT_IGNORE or CONTENT_AIR.
	*/
	for(u16 i=0; i<MAX_CONTENT+1; i++)
	{
		if(i == CONTENT_IGNORE || i == CONTENT_AIR)
			continue;
		ContentFeatures *f = &g_content_features[i];
		f->setAllTextures("unknown_block.png");
		f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	}

	// Make CONTENT_IGNORE to not block the view when occlusion culling
	content_features(CONTENT_IGNORE).solidness = 0;

	/*
		Initialize mapnode content
	*/
	content_mapnode_init();

}
Exemplo n.º 20
0
void content_mapnode_init()
{
	// Read some settings
	bool new_style_water = g_settings->getBool("new_style_water");
	bool new_style_leaves = g_settings->getBool("new_style_leaves");
	bool invisible_stone = g_settings->getBool("invisible_stone");
	bool opaque_water = g_settings->getBool("opaque_water");

	content_t i;
	ContentFeatures *f = NULL;

	i = CONTENT_STONE;
	f = &content_features(i);
	f->setAllTextures("stone.png");
	f->setInventoryTextureCube("stone.png", "stone.png", "stone.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->often_contains_mineral = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 1.0);
	if(invisible_stone)
		f->solidness = 0; // For debugging, hides regular stone
	
	i = CONTENT_GRASS;
	f = &content_features(i);
	f->setAllTextures("mud.png^grass_side.png");
	f->setTexture(0, "grass.png");
	f->setTexture(1, "mud.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_MUD)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_GRASS_FOOTSTEPS;
	f = &content_features(i);
	f->setAllTextures("mud.png^grass_side.png");
	f->setTexture(0, "grass_footsteps.png");
	f->setTexture(1, "mud.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_MUD)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_MUD;
	f = &content_features(i);
	f->setAllTextures("mud.png");
	f->setInventoryTextureCube("mud.png", "mud.png", "mud.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_SAND;
	f = &content_features(i);
	f->setAllTextures("sand.png");
	f->setInventoryTextureCube("sand.png", "sand.png", "sand.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_GRAVEL;
	f = &content_features(i);
	f->setAllTextures("gravel.png");
	f->setInventoryTextureCube("gravel.png", "gravel.png", "gravel.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.75);
	
	i = CONTENT_SANDSTONE;
	f = &content_features(i);
	f->setAllTextures("sandstone.png");
	f->setInventoryTextureCube("sandstone.png", "sandstone.png", "sandstone.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAND)+" 1";
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);

	i = CONTENT_CLAY;
	f = &content_features(i);
	f->setAllTextures("clay.png");
	f->setInventoryTextureCube("clay.png", "clay.png", "clay.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("CraftItem lump_of_clay 4");
	setDirtLikeDiggingProperties(f->digging_properties, 1.0);

	i = CONTENT_BRICK;
	f = &content_features(i);
	f->setAllTextures("brick.png");
	f->setInventoryTextureCube("brick.png", "brick.png", "brick.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("CraftItem clay_brick 4");
	setStoneLikeDiggingProperties(f->digging_properties, 1.0);

	i = CONTENT_TREE;
	f = &content_features(i);
	f->setAllTextures("tree.png");
	f->setTexture(0, "tree_top.png");
	f->setTexture(1, "tree_top.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setWoodLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_JUNGLETREE;
	f = &content_features(i);
	f->setAllTextures("jungletree.png");
	f->setTexture(0, "jungletree_top.png");
	f->setTexture(1, "jungletree_top.png");
	f->param_type = CPT_MINERAL;
	//f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setWoodLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_JUNGLEGRASS;
	f = &content_features(i);
	f->setInventoryTexture("junglegrass.png");
	f->used_texturenames["junglegrass.png"] = true;
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	//f->is_ground_content = true;
	f->air_equivalent = false; // grass grows underneath
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	setWoodLikeDiggingProperties(f->digging_properties, 0.10);

	i = CONTENT_LEAVES;
	f = &content_features(i);
	f->light_propagates = true;
	//f->param_type = CPT_MINERAL;
	f->param_type = CPT_LIGHT;
	//f->is_ground_content = true;
	if(new_style_leaves)
	{
		f->solidness = 0; // drawn separately, makes no faces
		f->visual_solidness = 1;
		f->setAllTextures("leaves.png");
		f->setInventoryTextureCube("leaves.png", "leaves.png", "leaves.png");
	}
	else
	{
		f->setAllTextures("[noalpha:leaves.png");
	}
	f->extra_dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAPLING)+" 1";
	f->extra_dug_item_rarity = 20;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setWoodLikeDiggingProperties(f->digging_properties, 0.15);

	i = CONTENT_CACTUS;
	f = &content_features(i);
	f->setAllTextures("cactus_side.png");
	f->setTexture(0, "cactus_top.png");
	f->setTexture(1, "cactus_top.png");
	f->setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setWoodLikeDiggingProperties(f->digging_properties, 0.75);

	i = CONTENT_PAPYRUS;
	f = &content_features(i);
	f->setInventoryTexture("papyrus.png");
	f->used_texturenames["papyrus.png"] = true;
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	setWoodLikeDiggingProperties(f->digging_properties, 0.25);

	i = CONTENT_BOOKSHELF;
	f = &content_features(i);
	f->setAllTextures("bookshelf.png");
	f->setTexture(0, "wood.png");
	f->setTexture(1, "wood.png");
	// FIXME: setInventoryTextureCube() only cares for the first texture
	f->setInventoryTextureCube("bookshelf.png", "bookshelf.png", "bookshelf.png");
	//f->setInventoryTextureCube("wood.png", "bookshelf.png", "bookshelf.png");
	f->param_type = CPT_MINERAL;
	f->is_ground_content = true;
	setWoodLikeDiggingProperties(f->digging_properties, 0.75);

	i = CONTENT_GLASS;
	f = &content_features(i);
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->param_type = CPT_LIGHT;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->visual_solidness = 1;
	f->setAllTextures("glass.png");
	f->setInventoryTextureCube("glass.png", "glass.png", "glass.png");
	setWoodLikeDiggingProperties(f->digging_properties, 0.15);

	i = CONTENT_FENCE;
	f = &content_features(i);
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->air_equivalent = true; // grass grows underneath
	f->setInventoryTexture("fence.png");
	f->used_texturenames["fence.png"] = true;
	setWoodLikeDiggingProperties(f->digging_properties, 0.75);

	i = CONTENT_RAIL;
	f = &content_features(i);
	f->setInventoryTexture("rail.png");
	f->used_texturenames["rail.png"] = true;
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->solidness = 0; // drawn separately, makes no faces
	f->air_equivalent = true; // grass grows underneath
	f->walkable = false;
	setDirtLikeDiggingProperties(f->digging_properties, 0.75);

	i = CONTENT_LADDER;
	f = &content_features(i);
	f->setInventoryTexture("ladder.png");
	f->used_texturenames["ladder.png"] = true;
	f->light_propagates = true;
	f->param_type = CPT_LIGHT;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
	f->wall_mounted = true;
	f->solidness = 0;
	f->air_equivalent = true;
	f->walkable = false;
	f->climbable = true;
	setWoodLikeDiggingProperties(f->digging_properties, 0.5);

	// Deprecated
	i = CONTENT_COALSTONE;
	f = &content_features(i);
	f->setAllTextures("stone.png^mineral_coal.png");
	f->is_ground_content = true;
	setStoneLikeDiggingProperties(f->digging_properties, 1.5);
	
	i = CONTENT_WOOD;
	f = &content_features(i);
	f->setAllTextures("wood.png");
	f->setInventoryTextureCube("wood.png", "wood.png", "wood.png");
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setWoodLikeDiggingProperties(f->digging_properties, 0.75);
	
	i = CONTENT_MESE;
	f = &content_features(i);
	f->setAllTextures("mese.png");
	f->setInventoryTextureCube("mese.png", "mese.png", "mese.png");
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 0.5);
	
	i = CONTENT_CLOUD;
	f = &content_features(i);
	f->setAllTextures("cloud.png");
	f->setInventoryTextureCube("cloud.png", "cloud.png", "cloud.png");
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	
	i = CONTENT_AIR;
	f = &content_features(i);
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->solidness = 0;
	f->walkable = false;
	f->pointable = false;
	f->diggable = false;
	f->buildable_to = true;
	f->air_equivalent = true;
	
	i = CONTENT_WATER;
	f = &content_features(i);
	f->setInventoryTextureCube("water.png", "water.png", "water.png");
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->solidness = 0; // Drawn separately, makes no faces
	f->visual_solidness = 1;
	f->walkable = false;
	f->pointable = false;
	f->diggable = false;
	f->buildable_to = true;
	f->liquid_type = LIQUID_FLOWING;
	f->liquid_alternative_flowing = CONTENT_WATER;
	f->liquid_alternative_source = CONTENT_WATERSOURCE;
	f->liquid_viscosity = WATER_VISC;
#ifndef SERVER
	if(!opaque_water)
		f->vertex_alpha = WATER_ALPHA;
	f->post_effect_color = video::SColor(64, 100, 100, 200);
	if(f->special_material == NULL && g_texturesource)
	{
		// Flowing water material
		f->special_material = new video::SMaterial;
		f->special_material->setFlag(video::EMF_LIGHTING, false);
		f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false);
		f->special_material->setFlag(video::EMF_BILINEAR_FILTER, false);
		f->special_material->setFlag(video::EMF_FOG_ENABLE, true);
		if(!opaque_water)
			f->special_material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
		AtlasPointer *pa_water1 = new AtlasPointer(g_texturesource->getTexture(
				g_texturesource->getTextureId("water.png")));
		f->special_material->setTexture(0, pa_water1->atlas);
		f->special_atlas = pa_water1;
	}
#endif
	
	i = CONTENT_WATERSOURCE;
	f = &content_features(i);
	//f->setInventoryTexture("water.png");
	f->setInventoryTextureCube("water.png", "water.png", "water.png");
	if(new_style_water)
	{
		f->solidness = 0; // drawn separately, makes no faces
	}
	else // old style
	{
		f->solidness = 1;
#ifndef SERVER
		TileSpec t;
		if(g_texturesource)
			t.texture = g_texturesource->getTexture("water.png");
		
		if(!opaque_water){
			t.alpha = WATER_ALPHA;
			t.material_type = MATERIAL_ALPHA_VERTEX;
		}
		t.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
		f->setAllTiles(t);
#endif
	}
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->walkable = false;
	f->pointable = false;
	f->diggable = false;
	f->buildable_to = true;
	f->liquid_type = LIQUID_SOURCE;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->liquid_alternative_flowing = CONTENT_WATER;
	f->liquid_alternative_source = CONTENT_WATERSOURCE;
	f->liquid_viscosity = WATER_VISC;
#ifndef SERVER
	if(!opaque_water)
		f->vertex_alpha = WATER_ALPHA;
	f->post_effect_color = video::SColor(64, 100, 100, 200);
	if(f->special_material == NULL && g_texturesource)
	{
		// Flowing water material
		f->special_material = new video::SMaterial;
		f->special_material->setFlag(video::EMF_LIGHTING, false);
		f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false);
		f->special_material->setFlag(video::EMF_BILINEAR_FILTER, false);
		f->special_material->setFlag(video::EMF_FOG_ENABLE, true);
		f->special_material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
		AtlasPointer *pa_water1 = new AtlasPointer(g_texturesource->getTexture(
				g_texturesource->getTextureId("water.png")));
		f->special_material->setTexture(0, pa_water1->atlas);
		f->special_atlas = pa_water1;
	}
#endif
	
	i = CONTENT_LAVA;
	f = &content_features(i);
	f->setInventoryTextureCube("lava.png", "lava.png", "lava.png");
	f->used_texturenames["lava.png"] = true;
	f->param_type = CPT_LIGHT;
	f->light_propagates = false;
	f->light_source = LIGHT_MAX-1;
	f->solidness = 0; // Drawn separately, makes no faces
	f->visual_solidness = 2;
	f->walkable = false;
	f->pointable = false;
	f->diggable = false;
	f->buildable_to = true;
	f->liquid_type = LIQUID_FLOWING;
	f->liquid_alternative_flowing = CONTENT_LAVA;
	f->liquid_alternative_source = CONTENT_LAVASOURCE;
	f->liquid_viscosity = LAVA_VISC;
	f->damage_per_second = 4*2;
#ifndef SERVER
	f->post_effect_color = video::SColor(192, 255, 64, 0);
	if(f->special_material == NULL && g_texturesource)
	{
		// Flowing lava material
		f->special_material = new video::SMaterial;
		f->special_material->setFlag(video::EMF_LIGHTING, false);
		f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false);
		f->special_material->setFlag(video::EMF_BILINEAR_FILTER, false);
		f->special_material->setFlag(video::EMF_FOG_ENABLE, true);
		f->special_material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
		AtlasPointer *pa_lava1 = new AtlasPointer(
			g_texturesource->getTexture(
				g_texturesource->getTextureId("lava.png")));
		f->special_material->setTexture(0, pa_lava1->atlas);
		f->special_atlas = pa_lava1;
	}
#endif
	
	i = CONTENT_LAVASOURCE;
	f = &content_features(i);
	f->setInventoryTextureCube("lava.png", "lava.png", "lava.png");
	f->used_texturenames["ladder.png"] = true;
	if(new_style_water)
	{
		f->solidness = 0; // drawn separately, makes no faces
	}
	else // old style
	{
		f->solidness = 2;
#ifndef SERVER
		TileSpec t;
		if(g_texturesource)
			t.texture = g_texturesource->getTexture("lava.png");
		
		//t.alpha = 255;
		//t.material_type = MATERIAL_ALPHA_VERTEX;
		//t.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
		f->setAllTiles(t);
#endif
	}
	f->param_type = CPT_LIGHT;
	f->light_propagates = false;
	f->light_source = LIGHT_MAX-1;
	f->walkable = false;
	f->pointable = false;
	f->diggable = false;
	f->buildable_to = true;
	f->liquid_type = LIQUID_SOURCE;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->liquid_alternative_flowing = CONTENT_LAVA;
	f->liquid_alternative_source = CONTENT_LAVASOURCE;
	f->liquid_viscosity = LAVA_VISC;
	f->damage_per_second = 4*2;
#ifndef SERVER
	f->post_effect_color = video::SColor(192, 255, 64, 0);
	if(f->special_material == NULL && g_texturesource)
	{
		// Flowing lava material
		f->special_material = new video::SMaterial;
		f->special_material->setFlag(video::EMF_LIGHTING, false);
		f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false);
		f->special_material->setFlag(video::EMF_BILINEAR_FILTER, false);
		f->special_material->setFlag(video::EMF_FOG_ENABLE, true);
		f->special_material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
		AtlasPointer *pa_lava1 = new AtlasPointer(
			g_texturesource->getTexture(
				g_texturesource->getTextureId("lava.png")));
		f->special_material->setTexture(0, pa_lava1->atlas);
		f->special_atlas = pa_lava1;
	}
#endif
	
	i = CONTENT_TORCH;
	f = &content_features(i);
	f->setInventoryTexture("torch_on_floor.png");
	f->used_texturenames["torch_on_floor.png"] = true;
	f->used_texturenames["torch_on_ceiling.png"] = true;
	f->used_texturenames["torch_on_floor.png"] = true;
	f->used_texturenames["torch.png"] = true;
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->wall_mounted = true;
	f->air_equivalent = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->light_source = LIGHT_MAX-1;
	f->digging_properties.set("", DiggingProperties(true, 0.0, 0));
	
	i = CONTENT_SIGN_WALL;
	f = &content_features(i);
	f->setInventoryTexture("sign_wall.png");
	f->used_texturenames["sign_wall.png"] = true;
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->wall_mounted = true;
	f->air_equivalent = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	if(f->initial_metadata == NULL)
		f->initial_metadata = new SignNodeMetadata("Some sign");
	f->digging_properties.set("", DiggingProperties(true, 0.5, 0));
	
	i = CONTENT_CHEST;
	f = &content_features(i);
	f->param_type = CPT_FACEDIR_SIMPLE;
	f->setAllTextures("chest_side.png");
	f->setTexture(0, "chest_top.png");
	f->setTexture(1, "chest_top.png");
	f->setTexture(5, "chest_front.png"); // Z-
	f->setInventoryTexture("chest_top.png");
	//f->setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	if(f->initial_metadata == NULL)
		f->initial_metadata = new ChestNodeMetadata();
	setWoodLikeDiggingProperties(f->digging_properties, 1.0);
	
	i = CONTENT_LOCKABLE_CHEST;
	f = &content_features(i);
	f->param_type = CPT_FACEDIR_SIMPLE;
	f->setAllTextures("chest_side.png");
	f->setTexture(0, "chest_top.png");
	f->setTexture(1, "chest_top.png");
	f->setTexture(5, "chest_lock.png"); // Z-
	f->setInventoryTexture("chest_lock.png");
	//f->setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	if(f->initial_metadata == NULL)
		f->initial_metadata = new LockingChestNodeMetadata();
	setWoodLikeDiggingProperties(f->digging_properties, 1.0);

	i = CONTENT_FURNACE;
	f = &content_features(i);
	f->param_type = CPT_FACEDIR_SIMPLE;
	f->setAllTextures("furnace_side.png");
	f->setTexture(5, "furnace_front.png"); // Z-
	f->setInventoryTexture("furnace_front.png");
	//f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 6";
	if(f->initial_metadata == NULL)
		f->initial_metadata = new FurnaceNodeMetadata();
	setStoneLikeDiggingProperties(f->digging_properties, 3.0);
	
	i = CONTENT_COBBLE;
	f = &content_features(i);
	f->setAllTextures("cobble.png");
	f->setInventoryTextureCube("cobble.png", "cobble.png", "cobble.png");
	f->param_type = CPT_NONE;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 0.9);

	i = CONTENT_MOSSYCOBBLE;
	f = &content_features(i);
	f->setAllTextures("mossycobble.png");
	f->setInventoryTextureCube("mossycobble.png", "mossycobble.png", "mossycobble.png");
	f->param_type = CPT_NONE;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 0.8);
	
	i = CONTENT_STEEL;
	f = &content_features(i);
	f->setAllTextures("steel_block.png");
	f->setInventoryTextureCube("steel_block.png", "steel_block.png",
			"steel_block.png");
	f->param_type = CPT_NONE;
	f->is_ground_content = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 5.0);
	
	i = CONTENT_NC;
	f = &content_features(i);
	f->param_type = CPT_FACEDIR_SIMPLE;
	f->setAllTextures("nc_side.png");
	f->setTexture(5, "nc_front.png"); // Z-
	f->setTexture(4, "nc_back.png"); // Z+
	f->setInventoryTexture("nc_front.png");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 3.0);
	
	i = CONTENT_NC_RB;
	f = &content_features(i);
	f->setAllTextures("nc_rb.png");
	f->setInventoryTexture("nc_rb.png");
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	setStoneLikeDiggingProperties(f->digging_properties, 3.0);

	i = CONTENT_SAPLING;
	f = &content_features(i);
	f->param_type = CPT_LIGHT;
	f->setAllTextures("sapling.png");
	f->setInventoryTexture("sapling.png");
	f->used_texturenames["sapling.png"] = true;
	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
	f->light_propagates = true;
	f->air_equivalent = false;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->digging_properties.set("", DiggingProperties(true, 0.0, 0));
	
	i = CONTENT_APPLE;
	f = &content_features(i);
	f->setInventoryTexture("apple.png");
	f->used_texturenames["apple.png"] = true;
	f->param_type = CPT_LIGHT;
	f->light_propagates = true;
	f->sunlight_propagates = true;
	f->solidness = 0; // drawn separately, makes no faces
	f->walkable = false;
	f->air_equivalent = true;
	f->dug_item = std::string("CraftItem apple 1");
	f->digging_properties.set("", DiggingProperties(true, 0.0, 0));
	
	// NOTE: Remember to add frequently used stuff to the texture atlas in tile.cpp
	

	/*
		Add MesePick to everything
	*/
	for(u16 i=0; i<=MAX_CONTENT; i++)
	{
		content_features(i).digging_properties.set("MesePick",
				DiggingProperties(true, 0.0, 65535./1337));
	}

}
Exemplo n.º 21
0
void TextureSource::buildMainAtlas() 
{
	infostream<<"TextureSource::buildMainAtlas()"<<std::endl;

	//return; // Disable (for testing)
	
	video::IVideoDriver* driver = m_device->getVideoDriver();
	assert(driver);

	JMutexAutoLock lock(m_atlaspointer_cache_mutex);

	// Create an image of the right size
	core::dimension2d<u32> atlas_dim(1024,1024);
	video::IImage *atlas_img =
			driver->createImage(video::ECF_A8R8G8B8, atlas_dim);
	//assert(atlas_img);
	if(atlas_img == NULL)
	{
		errorstream<<"TextureSource::buildMainAtlas(): Failed to create atlas "
				"image; not building texture atlas."<<std::endl;
		return;
	}

	/*
		Grab list of stuff to include in the texture atlas from the
		main content features
	*/

	core::map<std::string, bool> sourcelist;

	for(u16 j=0; j<MAX_CONTENT+1; j++)
	{
		if(j == CONTENT_IGNORE || j == CONTENT_AIR)
			continue;
		ContentFeatures *f = &content_features(j);
		for(core::map<std::string, bool>::Iterator
				i = f->used_texturenames.getIterator();
				i.atEnd() == false; i++)
		{
			std::string name = i.getNode()->getKey();
			sourcelist[name] = true;

			if(f->often_contains_mineral){
				for(int k=1; k<MINERAL_COUNT; k++){
					std::string mineraltexture = mineral_block_texture(k);
					std::string fulltexture = name + "^" + mineraltexture;
					sourcelist[fulltexture] = true;
				}
			}
		}
	}
	
	infostream<<"Creating texture atlas out of textures: ";
	for(core::map<std::string, bool>::Iterator
			i = sourcelist.getIterator();
			i.atEnd() == false; i++)
	{
		std::string name = i.getNode()->getKey();
		infostream<<"\""<<name<<"\" ";
	}
	infostream<<std::endl;

	// Padding to disallow texture bleeding
	s32 padding = 16;

	s32 column_width = 256;
	s32 column_padding = 16;

	/*
		First pass: generate almost everything
	*/
	core::position2d<s32> pos_in_atlas(0,0);
	
	pos_in_atlas.Y = padding;

	for(core::map<std::string, bool>::Iterator
			i = sourcelist.getIterator();
			i.atEnd() == false; i++)
	{
		std::string name = i.getNode()->getKey();

		/*video::IImage *img = driver->createImageFromFile(
				getTexturePath(name.c_str()).c_str());
		if(img == NULL)
			continue;
		
		core::dimension2d<u32> dim = img->getDimension();
		// Make a copy with the right color format
		video::IImage *img2 =
				driver->createImage(video::ECF_A8R8G8B8, dim);
		img->copyTo(img2);
		img->drop();*/
		
		// Generate image by name
		video::IImage *img2 = generate_image_from_scratch(name, m_device);
		if(img2 == NULL)
		{
			infostream<<"TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
			continue;
		}

		core::dimension2d<u32> dim = img2->getDimension();

		// Don't add to atlas if image is large
		core::dimension2d<u32> max_size_in_atlas(32,32);
		if(dim.Width > max_size_in_atlas.Width
		|| dim.Height > max_size_in_atlas.Height)
		{
			infostream<<"TextureSource::buildMainAtlas(): Not adding "
					<<"\""<<name<<"\" because image is large"<<std::endl;
			continue;
		}

		// Wrap columns and stop making atlas if atlas is full
		if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
		{
			if(pos_in_atlas.X > (s32)atlas_dim.Width - 256 - padding){
				errorstream<<"TextureSource::buildMainAtlas(): "
						<<"Atlas is full, not adding more textures."
						<<std::endl;
				break;
			}
			pos_in_atlas.Y = padding;
			pos_in_atlas.X += column_width + column_padding;
		}
		
        infostream<<"TextureSource::buildMainAtlas(): Adding \""<<name
                <<"\" to texture atlas"<<std::endl;

		// Tile it a few times in the X direction
		u16 xwise_tiling = column_width / dim.Width;
		if(xwise_tiling > 16) // Limit to 16 (more gives no benefit)
			xwise_tiling = 16;
		for(u32 j=0; j<xwise_tiling; j++)
		{
			// Copy the copy to the atlas
			img2->copyToWithAlpha(atlas_img,
					pos_in_atlas + v2s32(j*dim.Width,0),
					core::rect<s32>(v2s32(0,0), dim),
					video::SColor(255,255,255,255),
					NULL);
		}

		// Copy the borders a few times to disallow texture bleeding
		for(u32 side=0; side<2; side++) // top and bottom
		for(s32 y0=0; y0<padding; y0++)
		for(s32 x0=0; x0<(s32)xwise_tiling*(s32)dim.Width; x0++)
		{
			s32 dst_y;
			s32 src_y;
			if(side==0)
			{
				dst_y = y0 + pos_in_atlas.Y + dim.Height;
				src_y = pos_in_atlas.Y + dim.Height - 1;
			}
			else
			{
				dst_y = -y0 + pos_in_atlas.Y-1;
				src_y = pos_in_atlas.Y;
			}
			s32 x = x0 + pos_in_atlas.X;
			video::SColor c = atlas_img->getPixel(x, src_y);
			atlas_img->setPixel(x,dst_y,c);
		}

		img2->drop();

		/*
			Add texture to caches
		*/
		
		// Get next id
		u32 id = m_atlaspointer_cache.size();

		// Create AtlasPointer
		AtlasPointer ap(id);
		ap.atlas = NULL; // Set on the second pass
		ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
				(float)pos_in_atlas.Y/(float)atlas_dim.Height);
		ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
				(float)dim.Width/(float)atlas_dim.Height);
		ap.tiled = xwise_tiling;

		// Create SourceAtlasPointer and add to containers
		SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
		m_atlaspointer_cache.push_back(nap);
		m_name_to_id.insert(name, id);
			
		// Increment position
		pos_in_atlas.Y += dim.Height + padding * 2;
	}

	/*
		Make texture
	*/
	video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
	assert(t);

	/*
		Second pass: set texture pointer in generated AtlasPointers
	*/
	for(core::map<std::string, bool>::Iterator
			i = sourcelist.getIterator();
			i.atEnd() == false; i++)
	{
		std::string name = i.getNode()->getKey();
		if(m_name_to_id.find(name) == NULL)
			continue;
		u32 id = m_name_to_id[name];
		//infostream<<"id of name "<<name<<" is "<<id<<std::endl;
		m_atlaspointer_cache[id].a.atlas = t;
	}

	/*
		Write image to file so that it can be inspected
	*/
	/*std::string atlaspath = porting::path_userdata
			+ DIR_DELIM + "generated_texture_atlas.png";
	infostream<<"Removing and writing texture atlas for inspection to "
			<<atlaspath<<std::endl;
	fs::RecursiveDelete(atlaspath);
	driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
}