X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmapnode.h;h=389fa1c9c7f73da1587d2e6aa34709c9d4ace4af;hb=98fa00db12b4658f6bce61f0a2c03c69b963f8f2;hp=69a5a08cd58b6fdd0bc73e3b711c117b588a58a8;hpb=d3a6a12baea7317f6765ae7541cbc453f83d7928;p=dragonfireclient.git diff --git a/src/mapnode.h b/src/mapnode.h index 69a5a08cd..389fa1c9c 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -1,6 +1,6 @@ /* Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola +Copyright (C) 2010-2011 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,8 +27,34 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "exceptions.h" #include "serialization.h" #include "tile.h" +#include "materials.h" -#define MATERIALS_COUNT 256 +/* + Naming scheme: + - Material = irrlicht's Material class + - Content = (content_t) content of a node + - Tile = TileSpec at some side of a node of some content type + + Content ranges: + 0x000...0x07f: param2 is fully usable + 0x800...0xfff: param2 lower 4 bytes are free +*/ +typedef u16 content_t; +#define MAX_CONTENT 0xfff + +/* + Initializes all kind of stuff in here. + Many things depend on this. + + This accesses g_texturesource; if it is non-NULL, textures are set. + + Client first calls this with g_texturesource=NULL to run some + unit tests and stuff, then it runs this again with g_texturesource + defined to get the textures. + + Server only calls this once with g_texturesource=NULL. +*/ +void init_mapnode(); /* Ignored node. @@ -39,163 +65,252 @@ with this program; if not, write to the Free Software Foundation, Inc., Doesn't create faces with anything and is considered being out-of-map in the game map. */ -#define CONTENT_IGNORE 255 +//#define CONTENT_IGNORE 255 +#define CONTENT_IGNORE 127 #define CONTENT_IGNORE_DEFAULT_PARAM 0 /* The common material through which the player can walk and which is transparent to light */ -#define CONTENT_AIR 254 +//#define CONTENT_AIR 254 +#define CONTENT_AIR 126 /* - Suggested materials: - - Gravel - - Sand - - New naming scheme: - - Material = irrlicht's Material class - - Content = (u8) content of a node - - Tile = (u16) Material ID at some side of a node + Content feature list */ -#define CONTENT_STONE 0 -#define CONTENT_GRASS 1 -#define CONTENT_WATER 2 -#define CONTENT_TORCH 3 -#define CONTENT_TREE 4 -#define CONTENT_LEAVES 5 -#define CONTENT_GRASS_FOOTSTEPS 6 -#define CONTENT_MESE 7 -#define CONTENT_MUD 8 -#define CONTENT_WATERSOURCE 9 -#define CONTENT_CLOUD 10 -#define CONTENT_COALSTONE 11 -#define CONTENT_WOOD 12 +enum ContentParamType +{ + CPT_NONE, + CPT_LIGHT, + CPT_MINERAL, + // Direction for chests and furnaces and such + CPT_FACEDIR_SIMPLE +}; + +enum LiquidType +{ + LIQUID_NONE, + LIQUID_FLOWING, + LIQUID_SOURCE +}; + +struct MapNode; +class NodeMetadata; + +struct ContentFeatures +{ + // Type of MapNode::param1 + ContentParamType param_type; + + /* + 0: up + 1: down + 2: right + 3: left + 4: back + 5: front + */ + TileSpec tiles[6]; + + video::ITexture *inventory_texture; + + // True for all ground-like things like stone and mud, false for eg. trees + bool is_ground_content; + bool light_propagates; + bool sunlight_propagates; + u8 solidness; // Used when choosing which face is drawn + // This is used for collision detection. + // Also for general solidness queries. + bool walkable; + // Player can point to these + bool pointable; + // Player can dig these + bool diggable; + // Player can climb these + bool climbable; + // Player can build on these + bool buildable_to; + // Whether the node has no liquid, source liquid or flowing liquid + enum LiquidType liquid_type; + // If true, param2 is set to direction when placed. Used for torches. + // NOTE: the direction format is quite inefficient and should be changed + bool wall_mounted; + // If true, node is equivalent to air. Torches are, air is. Water is not. + // Is used for example to check whether a mud block can have grass on. + bool air_equivalent; + + // Inventory item string as which the node appears in inventory when dug. + // Mineral overrides this. + std::string dug_item; + + // Initial metadata is cloned from this + NodeMetadata *initial_metadata; + + // If the content is liquid, this is the flowing version of the liquid. + // If content is liquid, this is the same content. + content_t liquid_alternative_flowing; + // If the content is liquid, this is the source version of the liquid. + content_t liquid_alternative_source; + + // Amount of light the node emits + u8 light_source; + + // Digging properties for different tools + DiggingPropertiesList digging_properties; + + // NOTE: Move relevant properties to here from elsewhere + + void reset() + { + param_type = CPT_NONE; + inventory_texture = NULL; + is_ground_content = false; + light_propagates = false; + sunlight_propagates = false; + solidness = 2; + walkable = true; + pointable = true; + diggable = true; + climbable = false; + buildable_to = false; + liquid_type = LIQUID_NONE; + wall_mounted = false; + air_equivalent = false; + dug_item = ""; + initial_metadata = NULL; + liquid_alternative_flowing = CONTENT_IGNORE; + light_source = 0; + digging_properties.clear(); + } + + ContentFeatures() + { + reset(); + } + + ~ContentFeatures(); + + /* + Quickhands for simple materials + */ + + void setTexture(u16 i, std::string name, u8 alpha=255); + + void setAllTextures(std::string name, u8 alpha=255) + { + for(u16 i=0; i<6; i++) + { + setTexture(i, name, alpha); + } + // Force inventory texture too + setInventoryTexture(name); + } + + void setTile(u16 i, const TileSpec &tile) + { + tiles[i] = tile; + } + void setAllTiles(const TileSpec &tile) + { + for(u16 i=0; i<6; i++) + { + setTile(i, tile); + } + } + + void setInventoryTexture(std::string imgname); -#define USEFUL_CONTENT_COUNT 13 + void setInventoryTextureCube(std::string top, + std::string left, std::string right); +}; + +/* + Call this to access the ContentFeature list +*/ +ContentFeatures & content_features(content_t i); +ContentFeatures & content_features(MapNode &n); -extern u16 g_content_tiles[USEFUL_CONTENT_COUNT][6]; -extern const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT]; -// Initializes g_content_inventory_texture_paths -void init_content_inventory_texture_paths(); +/* + Here is a bunch of DEPRECATED functions. +*/ /* If true, the material allows light propagation and brightness is stored in param. + NOTE: Don't use, use "content_features(m).whatever" instead */ -inline bool light_propagates_content(u8 m) +inline bool light_propagates_content(content_t m) { - return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE); + return content_features(m).light_propagates; } - /* If true, the material allows lossless sunlight propagation. NOTE: It doesn't seem to go through torches regardlessly of this + NOTE: Don't use, use "content_features(m).whatever" instead */ -inline bool sunlight_propagates_content(u8 m) +inline bool sunlight_propagates_content(content_t m) { - return (m == CONTENT_AIR || m == CONTENT_TORCH); + return content_features(m).sunlight_propagates; } - /* On a node-node surface, the material of the node with higher solidness is used for drawing. 0: Invisible 1: Transparent 2: Opaque + NOTE: Don't use, use "content_features(m).whatever" instead */ -inline u8 content_solidness(u8 m) +inline u8 content_solidness(content_t m) { - // As of now, every pseudo node like torches are added to this - if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER) - return 0; - if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE) - return 1; - return 2; + return content_features(m).solidness; } - // Objects collide with walkable contents -inline bool content_walkable(u8 m) +// NOTE: Don't use, use "content_features(m).whatever" instead +inline bool content_walkable(content_t m) { - return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH); + return content_features(m).walkable; } - -inline bool content_liquid(u8 m) +// NOTE: Don't use, use "content_features(m).whatever" instead +inline bool content_liquid(content_t m) { - return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE); + return content_features(m).liquid_type != LIQUID_NONE; } - -inline bool content_flowing_liquid(u8 m) +// NOTE: Don't use, use "content_features(m).whatever" instead +inline bool content_flowing_liquid(content_t m) { - return (m == CONTENT_WATER); + return content_features(m).liquid_type == LIQUID_FLOWING; } - -inline bool content_liquid_source(u8 m) +// NOTE: Don't use, use "content_features(m).whatever" instead +inline bool content_liquid_source(content_t m) { - return (m == CONTENT_WATERSOURCE); + return content_features(m).liquid_type == LIQUID_SOURCE; } - // CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER // CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA -inline u8 make_liquid_flowing(u8 m) +// NOTE: Don't use, use "content_features(m).whatever" instead +inline content_t make_liquid_flowing(content_t m) { - if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE) - return CONTENT_WATER; - assert(0); + u8 c = content_features(m).liquid_alternative_flowing; + assert(c != CONTENT_IGNORE); + return c; } - // Pointable contents can be pointed to in the map -inline bool content_pointable(u8 m) +// NOTE: Don't use, use "content_features(m).whatever" instead +inline bool content_pointable(content_t m) { - return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE); + return content_features(m).pointable; } - -inline bool content_diggable(u8 m) +// NOTE: Don't use, use "content_features(m).whatever" instead +inline bool content_diggable(content_t m) { - return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE); + return content_features(m).diggable; } - -inline bool content_buildable_to(u8 m) +// NOTE: Don't use, use "content_features(m).whatever" instead +inline bool content_buildable_to(content_t m) { - return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE); -} - -/* - Returns true for contents that form the base ground that - follows the main heightmap -*/ -inline bool is_ground_content(u8 m) -{ - return ( - m != CONTENT_IGNORE - && m != CONTENT_AIR - && m != CONTENT_WATER - && m != CONTENT_TORCH - && m != CONTENT_TREE - && m != CONTENT_LEAVES - && m != CONTENT_WATERSOURCE - && m != CONTENT_CLOUD - ); -} - -inline bool is_mineral(u8 c) -{ - return(c == CONTENT_MESE - || c == CONTENT_COALSTONE); -} - -inline bool liquid_replaces_content(u8 c) -{ - return (c == CONTENT_AIR || c == CONTENT_TORCH); -} - -/* - When placing a node, drection info is added to it if this is true -*/ -inline bool content_directional(u8 c) -{ - return (c == CONTENT_TORCH); + return content_features(m).buildable_to; } /* @@ -205,7 +320,7 @@ inline bool content_directional(u8 c) 1: Face uses m1's content 2: Face uses m2's content */ -inline u8 face_contents(u8 m1, u8 m2) +inline u8 face_contents(content_t m1, content_t m2) { if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE) return 0; @@ -275,33 +390,15 @@ inline v3s16 unpackDir(u8 b) return d; } -inline u16 content_tile(u8 c, v3s16 dir) -{ - if(c == CONTENT_IGNORE || c == CONTENT_AIR - || c >= USEFUL_CONTENT_COUNT) - return TILE_NONE; - - s32 dir_i = -1; - - 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) - return TILE_NONE;*/ - assert(dir_i != -1); +/* + facedir: CPT_FACEDIR_SIMPLE param1 value + dir: The face for which stuff is wanted + return value: The face from which the stuff is actually found - return g_content_tiles[c][dir_i]; -} + NOTE: Currently this uses 2 bits for Z-,X-,Z+,X+, should there be Y+ + and Y- too? +*/ +v3s16 facedir_rotate(u8 facedir, v3s16 dir); enum LightBank { @@ -309,77 +406,54 @@ enum LightBank LIGHTBANK_NIGHT }; -#if 0 -#define DIR_PX 1 //X+ -#define DIR_NX 2 //X- -#define DIR_PZ 4 //Z+ -#define DIR_NZ 8 //Z- -#define DIR_PY 16 //Y+ -#define DIR_NY 32 //Y- +/* + Masks for MapNode.param2 of flowing liquids + */ +#define LIQUID_LEVEL_MASK 0x07 +#define LIQUID_FLOW_DOWN_MASK 0x08 -inline void decode_dirs(u8 b, core::list &dirs) -{ - if(b & DIR_PX) - dirs.push_back(v3s16(1,0,0)); - if(b & DIR_NX) - dirs.push_back(v3s16(-1,0,0)); - if(b & DIR_PZ) - dirs.push_back(v3s16(0,0,1)); - if(b & DIR_NZ) - dirs.push_back(v3s16(0,0,-1)); - if(b & DIR_PY) - dirs.push_back(v3s16(0,1,0)); - if(b & DIR_NY) - dirs.push_back(v3s16(0,-1,0)); -} +/* + This is the stuff what the whole world consists of. +*/ -inline u8 encode_dirs(core::list &dirs) -{ - u8 b = 0; - for(core::list::Iterator - i = dirs.begin(); - i != dirs.end(); i++) - { - if(*i == v3s16(1,0,0)) - b += DIR_PX; - else if(*i == v3s16(-1,0,0)) - b += DIR_NX; - else if(*i == v3s16(0,0,1)) - b += DIR_PZ; - else if(*i == v3s16(0,0,-1)) - b += DIR_NZ; - else if(*i == v3s16(0,1,0)) - b += DIR_PY; - else if(*i == v3s16(0,-1,0)) - b += DIR_NY; - } - return b; -} -#endif struct MapNode { - // Content - u8 d; + /* + Main content + 0x00-0x7f: Short content type + 0x80-0xff: Long content type (param2>>4 makes up low bytes) + */ + union + { + u8 param0; + //u8 d; + }; /* Misc parameter. Initialized to 0. - For light_propagates() blocks, this is light intensity, stored logarithmically from 0 to LIGHT_MAX. Sunlight is LIGHT_SUN, which is LIGHT_MAX+1. - - Contains 2 values, day- and night lighting. Each takes 4 bits. + - Contains 2 values, day- and night lighting. Each takes 4 bits. + - Mineral content (should be removed from here) + - Uhh... well, most blocks have light or nothing in here. */ - s8 param; + union + { + u8 param1; + //s8 param; + }; + /* + The second parameter. Initialized to 0. + E.g. direction for torches and flowing water. + If param0 >= 0x80, bits 0xf0 of this is extended content type data + */ union { u8 param2; - - /* - Direction for torches and other stuff. - Format is freeform. e.g. packDir or encode_dirs can be used. - */ - u8 dir; + //u8 dir; }; MapNode(const MapNode & n) @@ -387,44 +461,64 @@ struct MapNode *this = n; } - MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_param2=0) + MapNode(content_t content=CONTENT_AIR, u8 a_param1=0, u8 a_param2=0) { - d = data; - param = a_param; + //param0 = a_param0; + param1 = a_param1; param2 = a_param2; + // Set after other params because this needs to override part of param2 + setContent(content); } bool operator==(const MapNode &other) { - return (d == other.d - && param == other.param + return (param0 == other.param0 + && param1 == other.param1 && param2 == other.param2); } - - bool light_propagates() + + // To be used everywhere + content_t getContent() + { + if(param0 < 0x80) + return param0; + else + return (param0<<4) + (param2>>4); + } + void setContent(content_t c) { - return light_propagates_content(d); + if(c < 0x80) + { + if(param0 >= 0x80) + param2 &= ~(0xf0); + param0 = c; + } + else + { + param0 = c>>4; + param2 &= ~(0xf0); + param2 |= (c&0x0f)<<4; + } } + /* + These four are DEPRECATED I guess. -c55 + */ + bool light_propagates() + { + return light_propagates_content(getContent()); + } bool sunlight_propagates() { - return sunlight_propagates_content(d); + return sunlight_propagates_content(getContent()); } - u8 solidness() { - return content_solidness(d); + return content_solidness(getContent()); } - u8 light_source() { - /* - Note that a block that isn't light_propagates() can be a light source. - */ - if(d == CONTENT_TORCH) - return LIGHT_MAX; - - return 0; + return content_features(*this).light_source; } u8 getLightBanksWithSource() @@ -432,10 +526,10 @@ struct MapNode // Select the brightest of [light source, propagated light] u8 lightday = 0; u8 lightnight = 0; - if(light_propagates()) + if(content_features(*this).param_type == CPT_LIGHT) { - lightday = param & 0x0f; - lightnight = (param>>4)&0x0f; + lightday = param1 & 0x0f; + lightnight = (param1>>4)&0x0f; } if(light_source() > lightday) lightday = light_source(); @@ -444,21 +538,16 @@ struct MapNode return (lightday&0x0f) | ((lightnight<<4)&0xf0); } - void setLightBanks(u8 a_light) - { - param = a_light; - } - u8 getLight(enum LightBank bank) { // Select the brightest of [light source, propagated light] u8 light = 0; - if(light_propagates()) + if(content_features(*this).param_type == CPT_LIGHT) { if(bank == LIGHTBANK_DAY) - light = param & 0x0f; + light = param1 & 0x0f; else if(bank == LIGHTBANK_NIGHT) - light = (param>>4)&0x0f; + light = (param1>>4)&0x0f; else assert(0); } @@ -495,122 +584,66 @@ struct MapNode void setLight(enum LightBank bank, u8 a_light) { - // If not transparent, can't set light - if(light_propagates() == false) + // If node doesn't contain light data, ignore this + if(content_features(*this).param_type != CPT_LIGHT) return; if(bank == LIGHTBANK_DAY) { - param &= 0xf0; - param |= a_light & 0x0f; + param1 &= 0xf0; + param1 |= a_light & 0x0f; } else if(bank == LIGHTBANK_NIGHT) { - param &= 0x0f; - param |= (a_light & 0x0f)<<4; + param1 &= 0x0f; + param1 |= (a_light & 0x0f)<<4; } else assert(0); } - - u16 getTile(v3s16 dir) - { - return content_tile(d, dir); - } - + + // In mapnode.cpp + /* + Get tile of a face of the node. + dir: direction of face + Returns: TileSpec. Can contain miscellaneous texture coordinates, + which must be obeyed so that the texture atlas can be used. + */ + TileSpec getTile(v3s16 dir); + + /* + Gets mineral content of node, if there is any. + MINERAL_NONE if doesn't contain or isn't able to contain mineral. + */ + u8 getMineral(); + /* - These serialization functions are used when informing client - of a single node add + Serialization functions */ - static u32 serializedLength(u8 version) - { - if(!ser_ver_supported(version)) - throw VersionMismatchException("ERROR: MapNode format not supported"); - - if(version == 0) - return 1; - else if(version <= 9) - return 2; - else - return 3; - } - void serialize(u8 *dest, u8 version) - { - if(!ser_ver_supported(version)) - throw VersionMismatchException("ERROR: MapNode format not supported"); - - if(version == 0) - { - dest[0] = d; - } - else if(version <= 9) - { - dest[0] = d; - dest[1] = param; - } - else - { - dest[0] = d; - dest[1] = param; - dest[2] = param2; - } - } - void deSerialize(u8 *source, u8 version) - { - if(!ser_ver_supported(version)) - throw VersionMismatchException("ERROR: MapNode format not supported"); - - if(version == 0) - { - d = source[0]; - } - else if(version == 1) - { - d = source[0]; - // This version doesn't support saved lighting - if(light_propagates() || light_source() > 0) - param = 0; - else - param = source[1]; - } - else if(version <= 9) - { - d = source[0]; - param = source[1]; - } - else - { - d = source[0]; - param = source[1]; - param2 = source[2]; - } - } + static u32 serializedLength(u8 version); + void serialize(u8 *dest, u8 version); + void deSerialize(u8 *source, u8 version); + }; /* - Returns integer position of the node in given - floating point position. -*/ -inline v3s16 floatToInt(v3f p) -{ - v3s16 p2( - (p.X + (p.X>0 ? BS/2 : -BS/2))/BS, - (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS, - (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS); - return p2; -} - -inline v3f intToFloat(v3s16 p) -{ - v3f p2( - p.X * BS, - p.Y * BS, - p.Z * BS - ); - return p2; -} - + Gets lighting value at face of node + + Parameters must consist of air and !air. + Order doesn't matter. + If either of the nodes doesn't exist, light is 0. + + parameters: + daynight_ratio: 0...1000 + n: getNodeParent(p) + n2: getNodeParent(p + face_dir) + face_dir: axis oriented unit vector from p to p2 + + returns encoded light value. +*/ +u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, + v3s16 face_dir); #endif