// 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; }
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); } }
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); }
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 } }
// 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; }
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; }
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); }
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); } } }
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); }
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()); }
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; }
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(); }
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)); } }
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());*/ }