void ItemDefinition::deSerialize(std::istream &is) { // Reset everything reset(); // Deserialize int version = readU8(is); if (version < 5) throw SerializationError("unsupported ItemDefinition version"); type = (enum ItemType)readU8(is); name = deSerializeString(is); description = deSerializeString(is); inventory_image = deSerializeString(is); wield_image = deSerializeString(is); wield_scale = readV3F1000(is); stack_max = readS16(is); usable = readU8(is); liquids_pointable = readU8(is); std::string tool_capabilities_s = deSerializeString(is); if(!tool_capabilities_s.empty()) { std::istringstream tmp_is(tool_capabilities_s, std::ios::binary); tool_capabilities = new ToolCapabilities; tool_capabilities->deSerialize(tmp_is); } groups.clear(); u32 groups_size = readU16(is); for(u32 i=0; i<groups_size; i++){ std::string name = deSerializeString(is); int value = readS16(is); groups[name] = value; } node_placement_prediction = deSerializeString(is); //deserializeSimpleSoundSpec(sound_place, is); sound_place.name = deSerializeString(is); sound_place.gain = readF1000(is); range = readF1000(is); sound_place_failed.name = deSerializeString(is); sound_place_failed.gain = readF1000(is); palette_image = deSerializeString(is); color = readARGB8(is); sound_place.pitch = readF1000(is); sound_place_failed.pitch = readF1000(is); inventory_overlay = deSerializeString(is); wield_overlay = deSerializeString(is); // If you add anything here, insert it primarily inside the try-catch // block to not need to increase the version. //try { //} catch(SerializationError &e) {}; }
void TestSerialization::testStreamRead() { std::string datastr( (const char *)test_serialized_data, sizeof(test_serialized_data)); std::istringstream is(datastr, std::ios_base::binary); UASSERT(readU8(is) == 0x11); UASSERT(readU16(is) == 0x2233); UASSERT(readU32(is) == 0x44556677); UASSERT(readU64(is) == 0x8899AABBCCDDEEFF); UASSERT(readS8(is) == -128); UASSERT(readS16(is) == 30000); UASSERT(readS32(is) == -6); UASSERT(readS64(is) == -43); UASSERT(readF1000(is) == 53.534f); UASSERT(readF1000(is) == -300000.32f); UASSERT(readF1000(is) == F1000_MIN); UASSERT(readF1000(is) == F1000_MAX); UASSERT(deSerializeString(is) == "foobar!"); UASSERT(readV2S16(is) == v2s16(500, 500)); UASSERT(readV3S16(is) == v3s16(4207, 604, -30)); UASSERT(readV2S32(is) == v2s32(1920, 1080)); UASSERT(readV3S32(is) == v3s32(-400, 6400054, 290549855)); UASSERT(readV2F1000(is) == v2f(500.656f, 350.345f)); UASSERT(deSerializeWideString(is) == L"\x02~woof~\x5455"); UASSERT(readV3F1000(is) == v3f(500, 10024.2f, -192.54f)); UASSERT(readARGB8(is) == video::SColor(255, 128, 50, 128)); UASSERT(deSerializeLongString(is) == "some longer string here"); UASSERT(is.rdbuf()->in_avail() == 2); UASSERT(readU16(is) == 0xF00D); UASSERT(is.rdbuf()->in_avail() == 0); }
void ObjectProperties::deSerialize(std::istream &is) { int version = readU8(is); if(version == 1) { try{ hp_max = readS16(is); physical = readU8(is); weight = readF1000(is); collisionbox.MinEdge = readV3F1000(is); collisionbox.MaxEdge = readV3F1000(is); visual = deSerializeString(is); visual_size = readV2F1000(is); textures.clear(); u32 texture_count = readU16(is); for(u32 i=0; i<texture_count; i++){ textures.push_back(deSerializeString(is)); } spritediv = readV2S16(is); initial_sprite_basepos = readV2S16(is); is_visible = readU8(is); makes_footstep_sound = readU8(is); automatic_rotate = readF1000(is); mesh = deSerializeString(is); u32 color_count = readU16(is); for(u32 i=0; i<color_count; i++){ colors.push_back(readARGB8(is)); } collideWithObjects = readU8(is); stepheight = readF1000(is); automatic_face_movement_dir = readU8(is); automatic_face_movement_dir_offset = readF1000(is); }catch(SerializationError &e){} } else { throw SerializationError("unsupported ObjectProperties version"); } }
// set_sky(self, bgcolor, type, list) int ObjectRef::l_set_sky(lua_State *L) { ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) return 0; video::SColor bgcolor(255,255,255,255); if (!lua_isnil(L, 2)) bgcolor = readARGB8(L, 2); std::string type = luaL_checkstring(L, 3); std::vector<std::string> params; if (lua_istable(L, 4)) { int table = lua_gettop(L); lua_pushnil(L); while (lua_next(L, table) != 0) { // key at index -2 and value at index -1 if (lua_isstring(L, -1)) params.push_back(lua_tostring(L, -1)); else params.push_back(""); // removes value, keeps key for next iteration lua_pop(L, 1); } } if (type == "skybox" && params.size() != 6) throw LuaError("skybox expects 6 textures"); if (!getServer(L)->setSky(player, bgcolor, type, params)) return 0; lua_pushboolean(L, true); return 1; }
ContentFeatures read_content_features(lua_State *L, int index) { if(index < 0) index = lua_gettop(L) + 1 + index; ContentFeatures f; /* Cache existence of some callbacks */ lua_getfield(L, index, "on_construct"); if(!lua_isnil(L, -1)) f.has_on_construct = true; lua_pop(L, 1); lua_getfield(L, index, "on_destruct"); if(!lua_isnil(L, -1)) f.has_on_destruct = true; lua_pop(L, 1); lua_getfield(L, index, "after_destruct"); if(!lua_isnil(L, -1)) f.has_after_destruct = true; lua_pop(L, 1); lua_getfield(L, index, "on_activate"); if(!lua_isnil(L, -1)) { f.has_on_activate = true; f.is_circuit_element = true; } lua_pop(L, 1); lua_getfield(L, index, "on_deactivate"); if(!lua_isnil(L, -1)) { f.has_on_deactivate = true; f.is_circuit_element = true; } lua_pop(L, 1); lua_getfield(L, index, "on_rightclick"); f.rightclickable = lua_isfunction(L, -1); lua_pop(L, 1); /* Name */ getstringfield(L, index, "name", f.name); /* Groups */ lua_getfield(L, index, "groups"); read_groups(L, -1, f.groups); lua_pop(L, 1); /* Visual definition */ f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", ScriptApiNode::es_DrawType,NDT_NORMAL); getfloatfield(L, index, "visual_scale", f.visual_scale); /* Meshnode model filename */ getstringfield(L, index, "mesh", f.mesh); // tiles = {} lua_getfield(L, index, "tiles"); // If nil, try the deprecated name "tile_images" instead if(lua_isnil(L, -1)){ lua_pop(L, 1); warn_if_field_exists(L, index, "tile_images", "Deprecated; new name is \"tiles\"."); lua_getfield(L, index, "tile_images"); } if(lua_istable(L, -1)){ int table = lua_gettop(L); lua_pushnil(L); int i = 0; while(lua_next(L, table) != 0){ // Read tiledef from value f.tiledef[i] = read_tiledef(L, -1); // removes value, keeps key for next iteration lua_pop(L, 1); i++; if(i==6){ lua_pop(L, 1); break; } } // Copy last value to all remaining textures if(i >= 1){ TileDef lasttile = f.tiledef[i-1]; while(i < 6){ f.tiledef[i] = lasttile; i++; } } } lua_pop(L, 1); /* Circuit options */ lua_getfield(L, index, "is_wire"); if(!lua_isnil(L, -1)) { f.is_wire = true; } lua_pop(L, 1); lua_getfield(L, index, "is_wire_connector"); if(!lua_isnil(L, -1)) { f.is_wire_connector = true; } lua_pop(L, 1); lua_getfield(L, index, "wire_connections"); if(!lua_isnil(L, -1) && lua_istable(L, -1)) { // Both can't be set to true f.is_wire |= !f.is_wire_connector; int table = lua_gettop(L); lua_pushnil(L); int i; unsigned char current_shift = 1; for(i = 0; (i < 6) && (lua_next(L, table) != 0); ++i) { f.wire_connections[i] = lua_tonumber(L, -1); f.wire_connections[i] |= current_shift; current_shift <<= 1; lua_pop(L, 1); } if(i < 6) { luaL_error(L, "Wire connectins array must have exactly 6 integer numbers."); } // Convert to two-way wire (one-way may cause undefined behavior) for(i = 0; i < 6; ++i) { for(int j = 0; j < 6; ++j) { f.wire_connections[i] |= f.wire_connections[j] & (1 << i); f.wire_connections[j] |= f.wire_connections[i] & (1 << j); } } } else if(f.is_wire || f.is_wire_connector) { // Assuming that it's a standart wire or wire connector for(int i = 0; i < 6; ++i) { f.wire_connections[i] = 0x3F; } } lua_pop(L, 1); lua_getfield(L, index, "circuit_states"); if(!lua_isnil(L, -1) && lua_istable(L, -1)) { f.is_circuit_element = true; int table = lua_gettop(L); lua_pushnil(L); int i; for(i = 0; (i < 64) && (lua_next(L, table) != 0); ++i) { f.circuit_element_func[i] = lua_tonumber(L, -1); lua_pop(L, 1); } if(i < 64) { luaL_error(L, "Circuit element states table must have exactly 64 integer numbers."); } } lua_pop(L, 1); f.circuit_element_delay = getintfield_default(L, index, "circuit_element_delay", f.circuit_element_delay + 1) - 1; if(f.circuit_element_delay > 100) { luaL_error(L, "\"circuit_element_delay\" must be a positive integer number less than 101"); } // special_tiles = {} lua_getfield(L, index, "special_tiles"); // If nil, try the deprecated name "special_materials" instead if(lua_isnil(L, -1)){ lua_pop(L, 1); warn_if_field_exists(L, index, "special_materials", "Deprecated; new name is \"special_tiles\"."); lua_getfield(L, index, "special_materials"); } if(lua_istable(L, -1)){ int table = lua_gettop(L); lua_pushnil(L); int i = 0; while(lua_next(L, table) != 0){ // Read tiledef from value f.tiledef_special[i] = read_tiledef(L, -1); // removes value, keeps key for next iteration lua_pop(L, 1); i++; if(i==CF_SPECIAL_COUNT){ lua_pop(L, 1); break; } } } lua_pop(L, 1); f.alpha = getintfield_default(L, index, "alpha", 255); bool usealpha = getboolfield_default(L, index, "use_texture_alpha", false); if (usealpha) f.alpha = 0; /* Other stuff */ lua_getfield(L, index, "post_effect_color"); if(!lua_isnil(L, -1)) f.post_effect_color = readARGB8(L, -1); lua_pop(L, 1); f.param_type = (ContentParamType)getenumfield(L, index, "paramtype", ScriptApiNode::es_ContentParamType, CPT_NONE); f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2", ScriptApiNode::es_ContentParamType2, CPT2_NONE); // Warn about some deprecated fields warn_if_field_exists(L, index, "wall_mounted", "deprecated: use paramtype2 = 'wallmounted'"); warn_if_field_exists(L, index, "light_propagates", "deprecated: determined from paramtype"); warn_if_field_exists(L, index, "dug_item", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item_rarity", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "metadata_name", "deprecated: use on_add and metadata callbacks"); // True for all ground-like things like stone and mud, false for eg. trees getboolfield(L, index, "is_ground_content", f.is_ground_content); f.light_propagates = (f.param_type == CPT_LIGHT); getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates); // This is used for collision detection. // Also for general solidness queries. getboolfield(L, index, "walkable", f.walkable); // Player can point to these getboolfield(L, index, "pointable", f.pointable); // Player can dig these getboolfield(L, index, "diggable", f.diggable); // Player can climb these getboolfield(L, index, "climbable", f.climbable); // Player can build on these getboolfield(L, index, "buildable_to", f.buildable_to); // Whether the node is non-liquid, source liquid or flowing liquid f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype", ScriptApiNode::es_LiquidType, LIQUID_NONE); // If the content is liquid, this is the flowing version of the liquid. getstringfield(L, index, "liquid_alternative_flowing", f.liquid_alternative_flowing); // If the content is liquid, this is the source version of the liquid. getstringfield(L, index, "liquid_alternative_source", f.liquid_alternative_source); // Viscosity for fluid flow, ranging from 1 to 7, with // 1 giving almost instantaneous propagation and 7 being // the slowest possible f.liquid_viscosity = getintfield_default(L, index, "liquid_viscosity", f.liquid_viscosity); f.leveled = getintfield_default(L, index, "leveled", f.leveled); getboolfield(L, index, "liquid_renewable", f.liquid_renewable); getstringfield(L, index, "freeze", f.freeze); getstringfield(L, index, "melt", f.melt); f.drowning = getintfield_default(L, index, "drowning", f.drowning); // Amount of light the node emits f.light_source = getintfield_default(L, index, "light_source", f.light_source); f.damage_per_second = getintfield_default(L, index, "damage_per_second", f.damage_per_second); lua_getfield(L, index, "node_box"); if(lua_istable(L, -1)) f.node_box = read_nodebox(L, -1); lua_pop(L, 1); lua_getfield(L, index, "selection_box"); if(lua_istable(L, -1)) f.selection_box = read_nodebox(L, -1); lua_pop(L, 1); lua_getfield(L, index, "collision_box"); if(lua_istable(L, -1)) f.collision_box = read_nodebox(L, -1); lua_pop(L, 1); f.waving = getintfield_default(L, index, "waving", f.waving); // Set to true if paramtype used to be 'facedir_simple' getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple); // Set to true if wall_mounted used to be set to true getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted); // Sound table lua_getfield(L, index, "sounds"); if(lua_istable(L, -1)){ lua_getfield(L, -1, "footstep"); read_soundspec(L, -1, f.sound_footstep); lua_pop(L, 1); lua_getfield(L, -1, "dig"); read_soundspec(L, -1, f.sound_dig); lua_pop(L, 1); lua_getfield(L, -1, "dug"); read_soundspec(L, -1, f.sound_dug); lua_pop(L, 1); } lua_pop(L, 1); return f; }
void read_object_properties(lua_State *L, int index, ObjectProperties *prop) { if(index < 0) index = lua_gettop(L) + 1 + index; if(!lua_istable(L, index)) return; prop->hp_max = getintfield_default(L, -1, "hp_max", 10); getboolfield(L, -1, "physical", prop->physical); getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects); getfloatfield(L, -1, "weight", prop->weight); lua_getfield(L, -1, "collisionbox"); if(lua_istable(L, -1)) prop->collisionbox = read_aabb3f(L, -1, 1.0); lua_pop(L, 1); getstringfield(L, -1, "visual", prop->visual); getstringfield(L, -1, "mesh", prop->mesh); lua_getfield(L, -1, "visual_size"); if(lua_istable(L, -1)) prop->visual_size = read_v2f(L, -1); lua_pop(L, 1); lua_getfield(L, -1, "textures"); if(lua_istable(L, -1)){ prop->textures.clear(); int table = lua_gettop(L); lua_pushnil(L); while(lua_next(L, table) != 0){ // key at index -2 and value at index -1 if(lua_isstring(L, -1)) prop->textures.push_back(lua_tostring(L, -1)); else prop->textures.push_back(""); // removes value, keeps key for next iteration lua_pop(L, 1); } } lua_pop(L, 1); lua_getfield(L, -1, "colors"); if(lua_istable(L, -1)){ prop->colors.clear(); int table = lua_gettop(L); lua_pushnil(L); while(lua_next(L, table) != 0){ // key at index -2 and value at index -1 if(lua_isstring(L, -1)) prop->colors.push_back(readARGB8(L, -1)); else prop->colors.push_back(video::SColor(255, 255, 255, 255)); // removes value, keeps key for next iteration lua_pop(L, 1); } } lua_pop(L, 1); lua_getfield(L, -1, "spritediv"); if(lua_istable(L, -1)) prop->spritediv = read_v2s16(L, -1); lua_pop(L, 1); lua_getfield(L, -1, "initial_sprite_basepos"); if(lua_istable(L, -1)) prop->initial_sprite_basepos = read_v2s16(L, -1); lua_pop(L, 1); getboolfield(L, -1, "is_visible", prop->is_visible); getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound); getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate); if (getfloatfield(L, -1, "stepheight", prop->stepheight)) prop->stepheight *= BS; lua_getfield(L, -1, "automatic_face_movement_dir"); if (lua_isnumber(L, -1)) { prop->automatic_face_movement_dir = true; prop->automatic_face_movement_dir_offset = luaL_checknumber(L, -1); } else if (lua_isboolean(L, -1)) { prop->automatic_face_movement_dir = lua_toboolean(L, -1); prop->automatic_face_movement_dir_offset = 0.0; } lua_pop(L, 1); }
ContentFeatures read_content_features(lua_State *L, int index) { if(index < 0) index = lua_gettop(L) + 1 + index; ContentFeatures f; /* Cache existence of some callbacks */ lua_getfield(L, index, "on_construct"); if(!lua_isnil(L, -1)) f.has_on_construct = true; lua_pop(L, 1); lua_getfield(L, index, "on_destruct"); if(!lua_isnil(L, -1)) f.has_on_destruct = true; lua_pop(L, 1); lua_getfield(L, index, "after_destruct"); if(!lua_isnil(L, -1)) f.has_after_destruct = true; lua_pop(L, 1); lua_getfield(L, index, "on_rightclick"); f.rightclickable = lua_isfunction(L, -1); lua_pop(L, 1); /* Name */ getstringfield(L, index, "name", f.name); /* Groups */ lua_getfield(L, index, "groups"); read_groups(L, -1, f.groups); lua_pop(L, 1); /* Visual definition */ f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", ScriptApiNode::es_DrawType,NDT_NORMAL); getfloatfield(L, index, "visual_scale", f.visual_scale); // tiles = {} lua_getfield(L, index, "tiles"); // If nil, try the deprecated name "tile_images" instead if(lua_isnil(L, -1)){ lua_pop(L, 1); warn_if_field_exists(L, index, "tile_images", "Deprecated; new name is \"tiles\"."); lua_getfield(L, index, "tile_images"); } if(lua_istable(L, -1)){ int table = lua_gettop(L); lua_pushnil(L); int i = 0; while(lua_next(L, table) != 0){ // Read tiledef from value f.tiledef[i] = read_tiledef(L, -1); // removes value, keeps key for next iteration lua_pop(L, 1); i++; if(i==6){ lua_pop(L, 1); break; } } // Copy last value to all remaining textures if(i >= 1){ TileDef lasttile = f.tiledef[i-1]; while(i < 6){ f.tiledef[i] = lasttile; i++; } } } lua_pop(L, 1); // special_tiles = {} lua_getfield(L, index, "special_tiles"); // If nil, try the deprecated name "special_materials" instead if(lua_isnil(L, -1)){ lua_pop(L, 1); warn_if_field_exists(L, index, "special_materials", "Deprecated; new name is \"special_tiles\"."); lua_getfield(L, index, "special_materials"); } if(lua_istable(L, -1)){ int table = lua_gettop(L); lua_pushnil(L); int i = 0; while(lua_next(L, table) != 0){ // Read tiledef from value f.tiledef_special[i] = read_tiledef(L, -1); // removes value, keeps key for next iteration lua_pop(L, 1); i++; if(i==6){ lua_pop(L, 1); break; } } } lua_pop(L, 1); f.alpha = getintfield_default(L, index, "alpha", 255); bool usealpha = getboolfield_default(L, index, "use_texture_alpha", false); if (usealpha) f.alpha = 0; /* Other stuff */ lua_getfield(L, index, "post_effect_color"); if(!lua_isnil(L, -1)) f.post_effect_color = readARGB8(L, -1); lua_pop(L, 1); f.param_type = (ContentParamType)getenumfield(L, index, "paramtype", ScriptApiNode::es_ContentParamType, CPT_NONE); f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2", ScriptApiNode::es_ContentParamType2, CPT2_NONE); // Warn about some deprecated fields warn_if_field_exists(L, index, "wall_mounted", "deprecated: use paramtype2 = 'wallmounted'"); warn_if_field_exists(L, index, "light_propagates", "deprecated: determined from paramtype"); warn_if_field_exists(L, index, "dug_item", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item_rarity", "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "metadata_name", "deprecated: use on_add and metadata callbacks"); // True for all ground-like things like stone and mud, false for eg. trees getboolfield(L, index, "is_ground_content", f.is_ground_content); f.light_propagates = (f.param_type == CPT_LIGHT); getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates); // This is used for collision detection. // Also for general solidness queries. getboolfield(L, index, "walkable", f.walkable); // Player can point to these getboolfield(L, index, "pointable", f.pointable); // Player can dig these getboolfield(L, index, "diggable", f.diggable); // Player can climb these getboolfield(L, index, "climbable", f.climbable); // Player can build on these getboolfield(L, index, "buildable_to", f.buildable_to); // Whether the node is non-liquid, source liquid or flowing liquid f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype", ScriptApiNode::es_LiquidType, LIQUID_NONE); // If the content is liquid, this is the flowing version of the liquid. getstringfield(L, index, "liquid_alternative_flowing", f.liquid_alternative_flowing); // If the content is liquid, this is the source version of the liquid. getstringfield(L, index, "liquid_alternative_source", f.liquid_alternative_source); // Viscosity for fluid flow, ranging from 1 to 7, with // 1 giving almost instantaneous propagation and 7 being // the slowest possible f.liquid_viscosity = getintfield_default(L, index, "liquid_viscosity", f.liquid_viscosity); f.liquid_range = getintfield_default(L, index, "liquid_range", f.liquid_range); f.leveled = getintfield_default(L, index, "leveled", f.leveled); getboolfield(L, index, "liquid_renewable", f.liquid_renewable); getstringfield(L, index, "freezemelt", f.freezemelt); f.drowning = getintfield_default(L, index, "drowning", f.drowning); // Amount of light the node emits f.light_source = getintfield_default(L, index, "light_source", f.light_source); f.damage_per_second = getintfield_default(L, index, "damage_per_second", f.damage_per_second); lua_getfield(L, index, "node_box"); if(lua_istable(L, -1)) f.node_box = read_nodebox(L, -1); lua_pop(L, 1); lua_getfield(L, index, "selection_box"); if(lua_istable(L, -1)) f.selection_box = read_nodebox(L, -1); lua_pop(L, 1); // Set to true if paramtype used to be 'facedir_simple' getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple); // Set to true if wall_mounted used to be set to true getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted); // Sound table lua_getfield(L, index, "sounds"); if(lua_istable(L, -1)){ lua_getfield(L, -1, "footstep"); read_soundspec(L, -1, f.sound_footstep); lua_pop(L, 1); lua_getfield(L, -1, "dig"); read_soundspec(L, -1, f.sound_dig); lua_pop(L, 1); lua_getfield(L, -1, "dug"); read_soundspec(L, -1, f.sound_dug); lua_pop(L, 1); } lua_pop(L, 1); return f; }
void ContentFeatures::deSerialize(std::istream &is) { // version detection const u8 version = readU8(is); if (version < CONTENTFEATURES_VERSION) throw SerializationError("unsupported ContentFeatures version"); // general name = deSerializeString(is); groups.clear(); u32 groups_size = readU16(is); for (u32 i = 0; i < groups_size; i++) { std::string name = deSerializeString(is); int value = readS16(is); groups[name] = value; } param_type = (enum ContentParamType) readU8(is); param_type_2 = (enum ContentParamType2) readU8(is); // visual drawtype = (enum NodeDrawType) readU8(is); mesh = deSerializeString(is); visual_scale = readF32(is); if (readU8(is) != 6) throw SerializationError("unsupported tile count"); for (TileDef &td : tiledef) td.deSerialize(is, version, drawtype); for (TileDef &td : tiledef_overlay) td.deSerialize(is, version, drawtype); if (readU8(is) != CF_SPECIAL_COUNT) throw SerializationError("unsupported CF_SPECIAL_COUNT"); for (TileDef &td : tiledef_special) td.deSerialize(is, version, drawtype); alpha = readU8(is); color.setRed(readU8(is)); color.setGreen(readU8(is)); color.setBlue(readU8(is)); palette_name = deSerializeString(is); waving = readU8(is); connect_sides = readU8(is); u16 connects_to_size = readU16(is); connects_to_ids.clear(); for (u16 i = 0; i < connects_to_size; i++) connects_to_ids.push_back(readU16(is)); post_effect_color = readARGB8(is); leveled = readU8(is); // lighting-related light_propagates = readU8(is); sunlight_propagates = readU8(is); light_source = readU8(is); light_source = MYMIN(light_source, LIGHT_MAX); // map generation is_ground_content = readU8(is); // interaction walkable = readU8(is); pointable = readU8(is); diggable = readU8(is); climbable = readU8(is); buildable_to = readU8(is); rightclickable = readU8(is); damage_per_second = readU32(is); // liquid liquid_type = (enum LiquidType) readU8(is); liquid_alternative_flowing = deSerializeString(is); liquid_alternative_source = deSerializeString(is); liquid_viscosity = readU8(is); liquid_renewable = readU8(is); liquid_range = readU8(is); drowning = readU8(is); floodable = readU8(is); // node boxes node_box.deSerialize(is); selection_box.deSerialize(is); collision_box.deSerialize(is); // sounds sound_footstep.deSerialize(is, version); sound_dig.deSerialize(is, version); sound_dug.deSerialize(is, version); // read legacy properties legacy_facedir_simple = readU8(is); legacy_wallmounted = readU8(is); try { node_dig_prediction = deSerializeString(is); } catch(SerializationError &e) {}; }