Node definition names

This commit is contained in:
Perttu Ahola 2011-11-16 13:03:28 +02:00
parent 50d63e4b0a
commit c0f6395cf0
18 changed files with 972 additions and 549 deletions

View File

@ -94,6 +94,7 @@ configure_file(
)
set(common_SRCS
nameidmapping.cpp
tooldef.cpp
nodedef.cpp
luaentity_common.cpp

View File

@ -848,7 +848,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
//TimeTaker t1("TOCLIENT_ADDNODE");
MapNode n;
n.deSerialize(&data[8], ser_version, m_nodedef);
n.deSerialize(&data[8], ser_version);
addNode(p, n);
}
@ -2331,4 +2331,11 @@ ITextureSource* Client::getTextureSource()
{
return m_tsrc;
}
u16 Client::allocateUnknownNodeId(const std::string &name)
{
errorstream<<"Client::allocateUnknownNodeId(): "
<<"Client cannot allocate node IDs"<<std::endl;
assert(0);
return CONTENT_IGNORE;
}

View File

@ -324,10 +324,10 @@ public:
float getRTT(void);
// IGameDef interface
// Under envlock
virtual IToolDefManager* getToolDefManager();
virtual INodeDefManager* getNodeDefManager();
virtual ITextureSource* getTextureSource();
virtual u16 allocateUnknownNodeId(const std::string &name);
private:

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,10 @@ extern content_t trans_table_19[21][2];
MapNode mapnode_translate_from_internal(MapNode n_from, u8 version);
MapNode mapnode_translate_to_internal(MapNode n_from, u8 version);
// Get legacy node name mapping
class NameIdMapping;
void content_mapnode_get_name_id_mapping(NameIdMapping *nimap);
/*
Node content type IDs
Ranges:

View File

@ -20,6 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef GAMEDEF_HEADER
#define GAMEDEF_HEADER
#include <string>
class IToolDefManager;
class INodeDefManager;
//class IItemDefManager; //TODO
@ -43,6 +45,9 @@ public:
// This is always thread-safe, but referencing the irrlicht texture
// pointers in other threads than main thread will make things explode.
virtual ITextureSource* getTextureSource()=0;
// Used for keeping track of names/ids of unknown nodes
virtual u16 allocateUnknownNodeId(const std::string &name)=0;
// Shorthands
IToolDefManager* tdef(){return getToolDefManager();}

View File

@ -3367,10 +3367,10 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
Save blocks loaded in old format in new format
*/
if(version < SER_FMT_VER_HIGHEST || save_after_load)
{
//if(version < SER_FMT_VER_HIGHEST || save_after_load)
// Only save if asked to; no need to update version
if(save_after_load)
saveBlock(block);
}
// We just loaded it from, so it's up-to-date.
block->resetModified();

View File

@ -18,14 +18,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "mapblock.h"
#include <sstream>
#include "map.h"
// For g_settings
#include "main.h"
#include "light.h"
#include <sstream>
#include "nodedef.h"
#include "nodemetadata.h"
#include "gamedef.h"
#include "log.h"
#include "nameidmapping.h"
#include "content_mapnode.h" // For legacy name-id mapping
/*
MapBlock
@ -188,13 +192,13 @@ void MapBlock::replaceMesh(scene::SMesh *mesh_new)
IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
}*/
/*dstream<<"mesh_old->getReferenceCount()="
/*infostream<<"mesh_old->getReferenceCount()="
<<mesh_old->getReferenceCount()<<std::endl;
u32 c = mesh_old->getMeshBufferCount();
for(u32 i=0; i<c; i++)
{
scene::IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
dstream<<"buf->getReferenceCount()="
infostream<<"buf->getReferenceCount()="
<<buf->getReferenceCount()<<std::endl;
}*/
@ -519,6 +523,86 @@ s16 MapBlock::getGroundLevel(v2s16 p2d)
Serialization
*/
// List relevant id-name pairs for ids in the block using nodedef
static void getBlockNodeIdMapping(NameIdMapping *nimap, MapBlock *block,
INodeDefManager *nodedef)
{
std::set<content_t> unknown_contents;
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
{
v3s16 p(x0,y0,z0);
MapNode n = block->getNode(p);
content_t id = n.getContent();
const ContentFeatures &f = nodedef->get(id);
const std::string &name = f.name;
if(name == "")
unknown_contents.insert(id);
else
nimap->set(id, name);
}
for(std::set<content_t>::const_iterator
i = unknown_contents.begin();
i != unknown_contents.end(); i++){
errorstream<<"getBlockNodeIdMapping(): IGNORING ERROR: "
<<"Name for node id "<<(*i)<<" not known"<<std::endl;
}
}
// Correct ids in the block to match nodedef based on names.
// Unknown ones are added to nodedef.
// Will not update itself to match id-name pairs in nodedef.
void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block,
IGameDef *gamedef)
{
INodeDefManager *nodedef = gamedef->ndef();
// This means the block contains incorrect ids, and we contain
// the information to convert those to names.
// nodedef contains information to convert our names to globally
// correct ids.
std::set<content_t> unnamed_contents;
std::set<std::string> unallocatable_contents;
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
{
v3s16 p(x0,y0,z0);
MapNode n = block->getNode(p);
content_t local_id = n.getContent();
std::string name;
bool found = nimap->getName(local_id, name);
if(!found){
unnamed_contents.insert(local_id);
continue;
}
content_t global_id;
found = nodedef->getId(name, global_id);
if(!found){
global_id = gamedef->allocateUnknownNodeId(name);
if(global_id == CONTENT_IGNORE){
unallocatable_contents.insert(name);
continue;
}
}
n.setContent(global_id);
block->setNode(p, n);
}
for(std::set<content_t>::const_iterator
i = unnamed_contents.begin();
i != unnamed_contents.end(); i++){
errorstream<<"correctBlockNodeIds(): IGNORING ERROR: "
<<"Block contains id "<<(*i)
<<" with no name mapping"<<std::endl;
}
for(std::set<std::string>::const_iterator
i = unallocatable_contents.begin();
i != unallocatable_contents.end(); i++){
errorstream<<"correctBlockNodeIds(): IGNORING ERROR: "
<<"Could not allocate global id for node name \""
<<(*i)<<"\""<<std::endl;
}
}
void MapBlock::serialize(std::ostream &os, u8 version)
{
if(!ser_ver_supported(version))
@ -602,7 +686,7 @@ void MapBlock::serialize(std::ostream &os, u8 version)
flags |= 0x08;
}
os.write((char*)&flags, 1);
u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
/*
@ -663,8 +747,6 @@ void MapBlock::serialize(std::ostream &os, u8 version)
void MapBlock::deSerialize(std::istream &is, u8 version)
{
INodeDefManager *nodemgr = m_gamedef->ndef();
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapBlock format not supported");
@ -698,7 +780,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
if(is.gcount() != len)
throw SerializationError
("MapBlock::deSerialize: no enough input data");
data[i].deSerialize(*d, version, nodemgr);
data[i].deSerialize(*d, version);
}
}
else if(version <= 10)
@ -780,7 +862,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
buf[0] = s[i];
buf[1] = s[i+nodecount];
buf[2] = s[i+nodecount*2];
data[i].deSerialize(buf, version, m_gamedef->getNodeDefManager());
data[i].deSerialize(buf, version);
}
/*
@ -807,7 +889,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
}
catch(SerializationError &e)
{
dstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
<<" while deserializing node metadata"<<std::endl;
}
}
@ -834,6 +916,13 @@ void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
{
writeU32(os, getTimestamp());
}
// Scan and write node definition id mapping
if(version >= 21){
NameIdMapping nimap;
getBlockNodeIdMapping(&nimap, this, m_gamedef->ndef());
nimap.serialize(os);
}
}
void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
@ -841,12 +930,11 @@ void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
/*
Versions up from 9 have block objects. (DEPRECATED)
*/
if(version >= 9)
{
if(version >= 9){
u16 count = readU16(is);
// Not supported and length not known if count is not 0
if(count != 0){
dstream<<"WARNING: MapBlock::deSerializeDiskExtra(): "
errorstream<<"WARNING: MapBlock::deSerializeDiskExtra(): "
<<"Ignoring stuff coming at and after MBOs"<<std::endl;
return;
}
@ -856,19 +944,24 @@ void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
Versions up from 15 have static objects.
*/
if(version >= 15)
{
m_static_objects.deSerialize(is);
}
// Timestamp
if(version >= 17)
{
setTimestamp(readU32(is));
}
else
{
setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
// Dynamically re-set ids based on node names
NameIdMapping nimap;
// If supported, read node definition id mapping
if(version >= 21){
nimap.deSerialize(is);
// Else set the legacy mapping
} else {
content_mapnode_get_name_id_mapping(&nimap);
}
correctBlockNodeIds(&nimap, this, m_gamedef);
}
/*
@ -877,9 +970,7 @@ void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
std::string analyze_block(MapBlock *block)
{
if(block == NULL)
{
return "NULL";
}
std::ostringstream desc;

View File

@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map;
class NodeMetadataList;
class IGameDef;
class IWritableNodeDefManager;
#define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
@ -540,8 +541,11 @@ public:
// These don't write or read version by itself
void serialize(std::ostream &os, u8 version);
void deSerialize(std::istream &is, u8 version);
// Used after the basic ones when writing on disk (serverside)
void serializeDiskExtra(std::ostream &os, u8 version);
// In addition to doing other things, will add unknown blocks from
// id-name mapping to wndef
void deSerializeDiskExtra(std::istream &is, u8 version);
private:

View File

@ -268,7 +268,7 @@ void MapNode::serialize(u8 *dest, u8 version)
dest[2] = n_foreign.param2;
}
}
void MapNode::deSerialize(u8 *source, u8 version, INodeDefManager *nodemgr)
void MapNode::deSerialize(u8 *source, u8 version)
{
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapNode format not supported");
@ -280,11 +280,6 @@ void MapNode::deSerialize(u8 *source, u8 version, INodeDefManager *nodemgr)
else if(version == 1)
{
param0 = source[0];
// This version doesn't support saved lighting
if(nodemgr->get(*this).light_propagates || nodemgr->get(*this).light_source > 0)
param1 = 0;
else
param1 = source[1];
}
else if(version <= 9)
{

View File

@ -221,7 +221,7 @@ struct MapNode
static u32 serializedLength(u8 version);
void serialize(u8 *dest, u8 version);
void deSerialize(u8 *source, u8 version, INodeDefManager *nodemgr);
void deSerialize(u8 *source, u8 version);
};

50
src/nameidmapping.cpp Normal file
View File

@ -0,0 +1,50 @@
/*
Minetest-c55
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "nameidmapping.h"
#include "utility.h"
void NameIdMapping::serialize(std::ostream &os) const
{
writeU8(os, 0); // version
writeU16(os, m_id_to_name.size());
for(std::map<u16, std::string>::const_iterator
i = m_id_to_name.begin();
i != m_id_to_name.end(); i++){
writeU16(os, i->first);
os<<serializeString(i->second);
}
}
void NameIdMapping::deSerialize(std::istream &is)
{
int version = readU8(is);
if(version != 0)
throw SerializationError("unsupported NameIdMapping version");
u32 count = readU16(is);
m_id_to_name.clear();
m_name_to_id.clear();
for(u32 i=0; i<count; i++){
u16 id = readU16(is);
std::string name = deSerializeString(is);
m_id_to_name[id] = name;
m_name_to_id[name] = id;
}
}

79
src/nameidmapping.h Normal file
View File

@ -0,0 +1,79 @@
/*
Minetest-c55
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef NAMEIDMAPPING_HEADER
#define NAMEIDMAPPING_HEADER
#include <string>
#include <iostream>
#include <set>
#include <map>
#include "irrlichttypes.h"
class NameIdMapping
{
public:
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
void clear(){
m_id_to_name.clear();
m_name_to_id.clear();
}
void set(u16 id, const std::string &name){
m_id_to_name[id] = name;
m_name_to_id[name] = id;
}
void removeId(u16 id){
std::string name;
bool found = getName(id, name);
if(!found) return;
m_id_to_name.erase(id);
m_name_to_id.erase(name);
}
void eraseName(const std::string &name){
u16 id;
bool found = getId(name, id);
if(!found) return;
m_id_to_name.erase(id);
m_name_to_id.erase(name);
}
bool getName(u16 id, std::string &result) const{
std::map<u16, std::string>::const_iterator i;
i = m_id_to_name.find(id);
if(i == m_id_to_name.end())
return false;
result = i->second;
return true;
}
bool getId(const std::string &name, u16 &result) const{
std::map<std::string, u16>::const_iterator i;
i = m_name_to_id.find(name);
if(i == m_name_to_id.end())
return false;
result = i->second;
return true;
}
private:
std::map<u16, std::string> m_id_to_name;
std::map<std::string, u16> m_name_to_id;
};
#endif

View File

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
#include "log.h"
#include "settings.h"
#include "nameidmapping.h"
/*
NodeBox
@ -318,20 +319,63 @@ class CNodeDefManager: public IWritableNodeDefManager
public:
void clear()
{
m_name_id_mapping.clear();
for(u16 i=0; i<=MAX_CONTENT; i++)
{
ContentFeatures *f = &m_content_features[i];
f->reset(); // Reset to defaults
if(i == CONTENT_IGNORE || i == CONTENT_AIR){
f->drawtype = NDT_AIRLIKE;
continue;
}
f->setAllTextures("unknown_block.png");
ContentFeatures &f = m_content_features[i];
f.reset(); // Reset to defaults
f.setAllTextures("unknown_block.png");
}
#ifndef SERVER
// Make CONTENT_IGNORE to not block the view when occlusion culling
m_content_features[CONTENT_IGNORE].solidness = 0;
#endif
// Set CONTENT_AIR
{
ContentFeatures f;
f.name = "air";
f.drawtype = NDT_AIRLIKE;
f.param_type = CPT_LIGHT;
f.light_propagates = true;
f.sunlight_propagates = true;
f.walkable = false;
f.pointable = false;
f.diggable = false;
f.buildable_to = true;
f.air_equivalent = true;
set(CONTENT_AIR, f);
}
// Set CONTENT_IGNORE
{
ContentFeatures f;
f.name = "ignore";
f.drawtype = NDT_AIRLIKE;
f.param_type = CPT_LIGHT;
f.light_propagates = true;
f.sunlight_propagates = true;
f.walkable = false;
f.pointable = false;
f.diggable = false;
f.buildable_to = true;
f.air_equivalent = true;
set(CONTENT_AIR, f);
}
}
// CONTENT_IGNORE = not found
content_t getFreeId(bool require_full_param2)
{
// If allowed, first search in the large 4-byte-param2 pool
if(!require_full_param2){
for(u16 i=0x800; i<=0xfff; i++){
const ContentFeatures &f = m_content_features[i];
if(f.name == "")
return i;
}
}
// Then search from the small 8-byte-param2 pool
for(u16 i=0; i<=125; i++){
const ContentFeatures &f = m_content_features[i];
if(f.name == "")
return i;
}
return CONTENT_IGNORE;
}
CNodeDefManager()
{
@ -358,18 +402,54 @@ public:
{
return get(n.getContent());
}
// Writable
virtual bool getId(const std::string &name, content_t &result) const
{
return m_name_id_mapping.getId(name, result);
}
// IWritableNodeDefManager
virtual void set(content_t c, const ContentFeatures &def)
{
infostream<<"registerNode: registering content id \""<<c
<<"\": name=\""<<def.name<<"\""<<std::endl;
assert(c <= MAX_CONTENT);
m_content_features[c] = def;
if(def.name != "")
m_name_id_mapping.set(c, def.name);
}
virtual ContentFeatures* getModifiable(content_t c)
virtual content_t set(const std::string &name,
const ContentFeatures &def)
{
assert(c <= MAX_CONTENT);
return &m_content_features[c];
assert(name == def.name);
u16 id = CONTENT_IGNORE;
bool found = m_name_id_mapping.getId(name, id);
if(!found){
// Determine if full param2 is required
bool require_full_param2 = (
def.liquid_type == LIQUID_FLOWING
||
def.drawtype == NDT_FLOWINGLIQUID
||
def.drawtype == NDT_TORCHLIKE
||
def.drawtype == NDT_SIGNLIKE
);
// Get some id
id = getFreeId(require_full_param2);
if(id == CONTENT_IGNORE)
return CONTENT_IGNORE;
if(name != "")
m_name_id_mapping.set(id, name);
}
set(id, def);
return id;
}
virtual content_t allocateDummy(const std::string &name)
{
assert(name != "");
ContentFeatures f;
f.name = name;
f.setAllTextures("unknown_block.png");
return set(name, f);
}
virtual void updateTextures(ITextureSource *tsrc)
{
@ -499,6 +579,8 @@ public:
std::ostringstream tmp_os(std::ios::binary);
for(u16 i=0; i<=MAX_CONTENT; i++)
{
if(i == CONTENT_IGNORE || i == CONTENT_AIR)
continue;
ContentFeatures *f = &m_content_features[i];
if(f->name == "")
continue;
@ -523,10 +605,13 @@ public:
}
ContentFeatures *f = &m_content_features[i];
f->deSerialize(tmp_is, gamedef);
if(f->name != "")
m_name_id_mapping.set(i, f->name);
}
}
private:
ContentFeatures m_content_features[MAX_CONTENT+1];
NameIdMapping m_name_id_mapping;
};
IWritableNodeDefManager* createNodeDefManager()

View File

@ -253,6 +253,7 @@ public:
// Get node definition
virtual const ContentFeatures& get(content_t c) const=0;
virtual const ContentFeatures& get(const MapNode &n) const=0;
virtual bool getId(const std::string &name, content_t &result) const=0;
virtual void serialize(std::ostream &os)=0;
};
@ -266,10 +267,16 @@ public:
// Get node definition
virtual const ContentFeatures& get(content_t c) const=0;
virtual const ContentFeatures& get(const MapNode &n) const=0;
virtual bool getId(const std::string &name, content_t &result) const=0;
// Register node definition
virtual void set(content_t c, const ContentFeatures &def)=0;
virtual ContentFeatures* getModifiable(content_t c)=0;
// Register node definition by name (allocate an id)
// If returns CONTENT_IGNORE, could not allocate id
virtual content_t set(const std::string &name,
const ContentFeatures &def)=0;
// If returns CONTENT_IGNORE, could not allocate id
virtual content_t allocateDummy(const std::string &name)=0;
/*
Update tile textures to latest return values of TextueSource.

View File

@ -56,11 +56,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
18: new generator (not really necessary, but it's there)
19: new content type handling
20: many existing content types translated to extended ones
21: dynamic content type allocation
*/
// This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255
// Highest supported serialization version
#define SER_FMT_VER_HIGHEST 20
#define SER_FMT_VER_HIGHEST 21
// Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0

View File

@ -4428,6 +4428,10 @@ ITextureSource* Server::getTextureSource()
{
return NULL;
}
u16 Server::allocateUnknownNodeId(const std::string &name)
{
return m_nodemgr->allocateDummy(name);
}
IWritableToolDefManager* Server::getWritableToolDefManager()
{

View File

@ -491,6 +491,7 @@ public:
virtual IToolDefManager* getToolDefManager();
virtual INodeDefManager* getNodeDefManager();
virtual ITextureSource* getTextureSource();
virtual u16 allocateUnknownNodeId(const std::string &name);
IWritableToolDefManager* getWritableToolDefManager();
IWritableNodeDefManager* getWritableNodeDefManager();