summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKahrl <kahrl@gmx.net>2012-01-12 06:10:39 +0100
committerKahrl <kahrl@gmx.net>2012-01-12 06:10:39 +0100
commit6a76c226e10e92c3e3339096f07f8ab065e2098b (patch)
tree396d9083f5f76ebb5ba96df113ba68046c2487df /src
parent569156b01302ea4ba45d11ff5524b62dbc6a9aa0 (diff)
downloadminetest-6a76c226e10e92c3e3339096f07f8ab065e2098b.tar.gz
minetest-6a76c226e10e92c3e3339096f07f8ab065e2098b.tar.bz2
minetest-6a76c226e10e92c3e3339096f07f8ab065e2098b.zip
The huge item definition and item namespace unification patch (itemdef), see http://c55.me/minetest/wiki/doku.php?id=changes:itemdef
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/camera.cpp211
-rw-r--r--src/camera.h54
-rw-r--r--src/client.cpp261
-rw-r--r--src/client.h29
-rw-r--r--src/clientserver.h15
-rw-r--r--src/connection.cpp6
-rw-r--r--src/content_cao.cpp107
-rw-r--r--src/content_mapblock.cpp284
-rw-r--r--src/content_mapnode.cpp831
-rw-r--r--src/content_mapnode.h6
-rw-r--r--src/content_nodemeta.cpp287
-rw-r--r--src/content_sao.cpp154
-rw-r--r--src/content_sao.h8
-rw-r--r--src/craftdef.cpp844
-rw-r--r--src/craftdef.h349
-rw-r--r--src/craftitemdef.cpp214
-rw-r--r--src/craftitemdef.h79
-rw-r--r--src/environment.h1
-rw-r--r--src/game.cpp134
-rw-r--r--src/gamedef.h10
-rw-r--r--src/guiInventoryMenu.cpp149
-rw-r--r--src/guiInventoryMenu.h37
-rw-r--r--src/inventory.cpp967
-rw-r--r--src/inventory.h517
-rw-r--r--src/inventorymanager.cpp452
-rw-r--r--src/inventorymanager.h121
-rw-r--r--src/irrlichttypes.h2
-rw-r--r--src/itemdef.cpp502
-rw-r--r--src/itemdef.h147
-rw-r--r--src/mapblock.cpp3
-rw-r--r--src/mapblock.h3
-rw-r--r--src/mapblock_mesh.cpp76
-rw-r--r--src/mapblock_mesh.h8
-rw-r--r--src/materials.cpp51
-rw-r--r--src/materials.h24
-rw-r--r--src/mesh.cpp117
-rw-r--r--src/mesh.h22
-rw-r--r--src/mineral.cpp11
-rw-r--r--src/mineral.h13
-rw-r--r--src/nodedef.cpp199
-rw-r--r--src/nodedef.h49
-rw-r--r--src/player.cpp10
-rw-r--r--src/player.h14
-rw-r--r--src/scriptapi.cpp2639
-rw-r--r--src/scriptapi.h21
-rw-r--r--src/server.cpp976
-rw-r--r--src/server.h28
-rw-r--r--src/serverobject.cpp29
-rw-r--r--src/serverobject.h27
-rw-r--r--src/serverremoteplayer.cpp155
-rw-r--r--src/serverremoteplayer.h20
-rw-r--r--src/test.cpp198
-rw-r--r--src/tile.cpp190
-rw-r--r--src/tile.h4
-rw-r--r--src/tooldef.cpp238
-rw-r--r--src/tooldef.h103
-rw-r--r--src/utility.cpp95
-rw-r--r--src/utility.h6
59 files changed, 5778 insertions, 6332 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3b3b326c4..e82e26dc7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -100,9 +100,8 @@ set(common_SRCS
content_abm.cpp
craftdef.cpp
nameidmapping.cpp
- tooldef.cpp
+ itemdef.cpp
nodedef.cpp
- craftitemdef.cpp
luaentity_common.cpp
scriptapi.cpp
script.cpp
diff --git a/src/camera.cpp b/src/camera.cpp
index c0e171468..066208569 100644
--- a/src/camera.cpp
+++ b/src/camera.cpp
@@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tile.h"
#include <cmath>
#include "settings.h"
-#include "nodedef.h" // For wield visualization
+#include "itemdef.h" // For wield visualization
Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
m_smgr(smgr),
@@ -37,6 +37,7 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
m_wieldmgr(NULL),
m_wieldnode(NULL),
+ m_wieldlight(0),
m_draw_control(draw_control),
m_viewing_range_min(5.0),
@@ -77,15 +78,15 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
// all other 3D scene nodes and before the GUI.
m_wieldmgr = smgr->createNewSceneManager();
m_wieldmgr->addCameraSceneNode();
- m_wieldnode = new ExtrudedSpriteSceneNode(m_wieldmgr->getRootSceneNode(), m_wieldmgr);
+ m_wieldnode = m_wieldmgr->addMeshSceneNode(createCubeMesh(v3f(1,1,1)), NULL); // need a dummy mesh
updateSettings();
}
Camera::~Camera()
{
+ m_wieldnode->setMesh(NULL);
m_wieldmgr->drop();
- m_wieldnode->drop();
}
bool Camera::successfullyCreated(std::wstring& error_message)
@@ -292,7 +293,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
}
m_wieldnode->setPosition(wield_position);
m_wieldnode->setRotation(wield_rotation);
- m_wieldnode->updateLight(player->light);
+ m_wieldlight = player->light;
// Render distance feedback loop
updateViewingRange(frametime);
@@ -449,62 +450,38 @@ void Camera::updateSettings()
m_wanted_frametime = 1.0 / wanted_fps;
}
-void Camera::wield(const InventoryItem* item, IGameDef *gamedef)
+void Camera::setDigging(s32 button)
{
- //ITextureSource *tsrc = gamedef->tsrc();
- INodeDefManager *ndef = gamedef->ndef();
+ if (m_digging_button == -1)
+ m_digging_button = button;
+}
- if (item != NULL)
+void Camera::wield(const ItemStack &item, IGameDef *gamedef)
+{
+ IItemDefManager *idef = gamedef->idef();
+ scene::IMesh *wield_mesh = item.getDefinition(idef).wield_mesh;
+ if(wield_mesh)
{
- bool isCube = false;
-
- // 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();
- switch(ndef->get(content).drawtype){
- case NDT_NORMAL:
- case NDT_LIQUID:
- case NDT_FLOWINGLIQUID:
- case NDT_GLASSLIKE:
- case NDT_ALLFACES:
- case NDT_ALLFACES_OPTIONAL:
- m_wieldnode->setCube(ndef->get(content).tiles);
- isCube = true;
- break;
- default:
- break;
- }
- }
-
- // If that failed, make an extruded sprite.
- if (!isCube)
- {
- m_wieldnode->setSprite(item->getImageRaw());
- }
-
+ m_wieldnode->setMesh(wield_mesh);
m_wieldnode->setVisible(true);
}
else
{
- // Bare hands
- m_wieldnode->setSprite(gamedef->tsrc()->getTextureRaw("wieldhand.png"));
- m_wieldnode->setVisible(true);
+ m_wieldnode->setVisible(false);
}
}
-void Camera::setDigging(s32 button)
-{
- if (m_digging_button == -1)
- m_digging_button = button;
-}
-
void Camera::drawWieldedTool()
{
+ // Set vertex colors of wield mesh according to light level
+ u8 li = decode_light(m_wieldlight);
+ video::SColor color(255,li,li,li);
+ setMeshColor(m_wieldnode->getMesh(), color);
+
+ // Clear Z buffer
m_wieldmgr->getVideoDriver()->clearZBuffer();
+ // Draw the wielded node (in a separate scene manager)
scene::ICameraSceneNode* cam = m_wieldmgr->getActiveCamera();
cam->setAspectRatio(m_cameranode->getAspectRatio());
cam->setFOV(m_cameranode->getFOV());
@@ -512,145 +489,3 @@ void Camera::drawWieldedTool()
cam->setFarValue(100);
m_wieldmgr->drawAll();
}
-
-
-ExtrudedSpriteSceneNode::ExtrudedSpriteSceneNode(
- scene::ISceneNode* parent,
- scene::ISceneManager* mgr,
- s32 id,
- const v3f& position,
- const v3f& rotation,
- const v3f& scale
-):
- ISceneNode(parent, mgr, id, position, rotation, scale)
-{
- m_meshnode = mgr->addMeshSceneNode(NULL, this, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true);
- m_cubemesh = NULL;
- m_is_cube = false;
- m_light = LIGHT_MAX;
-}
-
-ExtrudedSpriteSceneNode::~ExtrudedSpriteSceneNode()
-{
- removeChild(m_meshnode);
- if (m_cubemesh)
- m_cubemesh->drop();
-}
-
-void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture)
-{
- const v3f sprite_scale(40.0, 40.0, 4.0); // width, height, thickness
-
- if (texture == NULL)
- {
- m_meshnode->setVisible(false);
- return;
- }
-
- io::path name = getExtrudedName(texture);
- scene::IMeshCache* cache = SceneManager->getMeshCache();
- scene::IAnimatedMesh* mesh = cache->getMeshByName(name);
- if (mesh != NULL)
- {
- // Extruded texture has been found in cache.
- m_meshnode->setMesh(mesh);
- }
- else
- {
- // Texture was not yet extruded, do it now and save in cache
- mesh = createExtrudedMesh(texture,
- SceneManager->getVideoDriver(),
- sprite_scale);
- if (mesh == NULL)
- {
- dstream << "Warning: failed to extrude sprite" << std::endl;
- m_meshnode->setVisible(false);
- return;
- }
- cache->addMesh(name, mesh);
- m_meshnode->setMesh(mesh);
- mesh->drop();
- }
-
- m_meshnode->getMaterial(0).setTexture(0, texture);
- m_meshnode->getMaterial(0).setFlag(video::EMF_LIGHTING, false);
- m_meshnode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, false);
- m_meshnode->getMaterial(0).MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
- m_meshnode->setVisible(true);
- m_is_cube = false;
- updateLight(m_light);
-}
-
-void ExtrudedSpriteSceneNode::setCube(const TileSpec tiles[6])
-{
- const v3f cube_scale(30.0, 30.0, 30.0);
-
- if (m_cubemesh == NULL)
- {
- m_cubemesh = createCubeMesh(cube_scale);
- }
-
- m_meshnode->setMesh(m_cubemesh);
- for (int i = 0; i < 6; ++i)
- {
- // Get the tile texture and atlas transformation
- video::ITexture* atlas = tiles[i].texture.atlas;
- v2f pos = tiles[i].texture.pos;
- v2f size = tiles[i].texture.size;
-
- // Set material flags and texture
- video::SMaterial& material = m_meshnode->getMaterial(i);
- material.setFlag(video::EMF_LIGHTING, false);
- material.setFlag(video::EMF_BILINEAR_FILTER, false);
- tiles[i].applyMaterialOptions(material);
- material.setTexture(0, atlas);
- material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
- material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
- }
- m_meshnode->setVisible(true);
- m_is_cube = true;
- updateLight(m_light);
-}
-
-void ExtrudedSpriteSceneNode::updateLight(u8 light)
-{
- m_light = light;
-
- u8 li = decode_light(light);
- // Set brightness one lower than incoming light
- diminish_light(li);
- video::SColor color(255,li,li,li);
- setMeshColor(m_meshnode->getMesh(), color);
-}
-
-void ExtrudedSpriteSceneNode::removeSpriteFromCache(video::ITexture* texture)
-{
- scene::IMeshCache* cache = SceneManager->getMeshCache();
- scene::IAnimatedMesh* mesh = cache->getMeshByName(getExtrudedName(texture));
- if (mesh != NULL)
- cache->removeMesh(mesh);
-}
-
-const core::aabbox3d<f32>& ExtrudedSpriteSceneNode::getBoundingBox() const
-{
- return m_meshnode->getBoundingBox();
-}
-
-void ExtrudedSpriteSceneNode::OnRegisterSceneNode()
-{
- if (IsVisible)
- SceneManager->registerNodeForRendering(this);
- ISceneNode::OnRegisterSceneNode();
-}
-
-void ExtrudedSpriteSceneNode::render()
-{
- // do nothing
-}
-
-io::path ExtrudedSpriteSceneNode::getExtrudedName(video::ITexture* texture)
-{
- io::path path = texture->getName();
- path.append("/[extruded]");
- return path;
-}
diff --git a/src/camera.h b/src/camera.h
index d5789d807..56c99d101 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -26,12 +26,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tile.h"
#include "utility.h"
#include <ICameraSceneNode.h>
-#include <IMeshCache.h>
-#include <IAnimatedMesh.h>
class LocalPlayer;
struct MapDrawControl;
-class ExtrudedSpriteSceneNode;
class IGameDef;
/*
@@ -116,13 +113,13 @@ public:
// Update settings from g_settings
void updateSettings();
- // Replace the wielded item mesh
- void wield(const InventoryItem* item, IGameDef *gamedef);
-
// Start digging animation
// Pass 0 for left click, 1 for right click
void setDigging(s32 button);
+ // Replace the wielded item mesh
+ void wield(const ItemStack &item, IGameDef *gamedef);
+
// Draw the wielded tool.
// This has to happen *after* the main scene is drawn.
// Warning: This clears the Z buffer.
@@ -136,7 +133,8 @@ private:
scene::ICameraSceneNode* m_cameranode;
scene::ISceneManager* m_wieldmgr;
- ExtrudedSpriteSceneNode* m_wieldnode;
+ scene::IMeshSceneNode* m_wieldnode;
+ u8 m_wieldlight;
// draw control
MapDrawControl& m_draw_control;
@@ -182,46 +180,4 @@ private:
s32 m_digging_button;
};
-
-/*
- A scene node that displays a 2D mesh extruded into the third dimension,
- to add an illusion of depth.
-
- Since this class was created to display the wielded tool of the local
- player, and only tools and items are rendered like this (but not solid
- content like stone and mud, which are shown as cubes), the option to
- draw a textured cube instead is provided.
- */
-class ExtrudedSpriteSceneNode: public scene::ISceneNode
-{
-public:
- ExtrudedSpriteSceneNode(
- scene::ISceneNode* parent,
- scene::ISceneManager* mgr,
- s32 id = -1,
- const v3f& position = v3f(0,0,0),
- const v3f& rotation = v3f(0,0,0),
- const v3f& scale = v3f(1,1,1));
- ~ExtrudedSpriteSceneNode();
-
- void setSprite(video::ITexture* texture);
- void setCube(const TileSpec tiles[6]);
-
- void updateLight(u8 light);
-
- void removeSpriteFromCache(video::ITexture* texture);
-
- virtual const core::aabbox3d<f32>& getBoundingBox() const;
- virtual void OnRegisterSceneNode();
- virtual void render();
-
-private:
- scene::IMeshSceneNode* m_meshnode;
- scene::IMesh* m_cubemesh;
- bool m_is_cube;
- u8 m_light;
-
- io::path getExtrudedName(video::ITexture* texture);
-};
-
#endif
diff --git a/src/client.cpp b/src/client.cpp
index 38ed14978..feb8a3a1e 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -33,8 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "nodemetadata.h"
#include "nodedef.h"
-#include "tooldef.h"
-#include "craftitemdef.h"
+#include "itemdef.h"
#include <IFileSystem.h>
#include "sha1.h"
#include "base64.h"
@@ -207,14 +206,12 @@ Client::Client(
std::string password,
MapDrawControl &control,
IWritableTextureSource *tsrc,
- IWritableToolDefManager *tooldef,
- IWritableNodeDefManager *nodedef,
- IWritableCraftItemDefManager *craftitemdef
+ IWritableItemDefManager *itemdef,
+ IWritableNodeDefManager *nodedef
):
m_tsrc(tsrc),
- m_tooldef(tooldef),
+ m_itemdef(itemdef),
m_nodedef(nodedef),
- m_craftitemdef(craftitemdef),
m_mesh_update_thread(this),
m_env(
new ClientMap(this, this, control,
@@ -234,9 +231,8 @@ Client::Client(
m_access_denied(false),
m_texture_receive_progress(0),
m_textures_received(false),
- m_tooldef_received(false),
- m_nodedef_received(false),
- m_craftitemdef_received(false)
+ m_itemdef_received(false),
+ m_nodedef_received(false)
{
m_packetcounter_timer = 0.0;
//m_delete_unused_sectors_timer = 0.0;
@@ -251,12 +247,6 @@ Client::Client(
else
infostream<<"Not building texture atlas."<<std::endl;
- // Update node textures
- m_nodedef->updateTextures(m_tsrc);
-
- // Start threads after setting up content definitions
- m_mesh_update_thread.Start();
-
/*
Add local player
*/
@@ -266,9 +256,6 @@ Client::Client(
player->updateName(playername);
m_env.addPlayer(player);
-
- // Initialize player in the inventory context
- m_inventory_context.current_player = player;
}
}
@@ -983,7 +970,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
//t4.stop();
//TimeTaker t1("inventory.deSerialize()", m_device);
- player->inventory.deSerialize(is, this);
+ player->inventory.deSerialize(is);
//t1.stop();
m_inventory_updated = true;
@@ -1216,18 +1203,18 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
} else {
InventoryList *inv = player->inventory.getList("main");
std::string itemstring(deSerializeString(is));
- if (itemstring.empty()) {
- inv->deleteItem(0);
- infostream
- <<"Client: empty player item for peer "
- << peer_id << std::endl;
- } else {
- std::istringstream iss(itemstring);
- delete inv->changeItem(0,
- InventoryItem::deSerialize(iss, this));
- infostream<<"Client: player item for peer " << peer_id << ": ";
- player->getWieldItem()->serialize(infostream);
- infostream<<std::endl;
+ ItemStack item;
+ item.deSerialize(itemstring, m_itemdef);
+ inv->changeItem(0, item);
+ if(itemstring.empty())
+ {
+ infostream<<"Client: empty player item for peer "
+ <<peer_id<<std::endl;
+ }
+ else
+ {
+ infostream<<"Client: player item for peer "
+ <<peer_id<<": "<<itemstring<<std::endl;
}
}
}
@@ -1256,14 +1243,9 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
-
- // Stop threads while updating content definitions
- m_mesh_update_thread.setRun(false);
- // Process the remaining TextureSource queue to let MeshUpdateThread
- // get it's remaining textures and thus let it stop
- while(m_mesh_update_thread.IsRunning()){
- m_tsrc->processQueue();
- }
+ // Mesh update thread must be stopped while
+ // updating content definitions
+ assert(!m_mesh_update_thread.IsRunning());
int num_textures = readU16(is);
@@ -1362,9 +1344,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
}
- // Resume threads
- m_mesh_update_thread.setRun(true);
- m_mesh_update_thread.Start();
ClientEvent event;
event.type = CE_TEXTURES_UPDATED;
@@ -1412,14 +1391,10 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
- // Stop threads while updating content definitions
- m_mesh_update_thread.setRun(false);
- // Process the remaining TextureSource queue to let MeshUpdateThread
- // get it's remaining textures and thus let it stop
- while(m_mesh_update_thread.IsRunning()){
- m_tsrc->processQueue();
- }
-
+ // Mesh update thread must be stopped while
+ // updating content definitions
+ assert(!m_mesh_update_thread.IsRunning());
+
/*
u16 command
u16 total number of texture bunches
@@ -1484,22 +1459,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
img->drop();
rfile->drop();
}
-
- if(m_nodedef_received && m_textures_received){
- // Rebuild inherited images and recreate textures
- m_tsrc->rebuildImagesAndTextures();
-
- // Update texture atlas
- if(g_settings->getBool("enable_texture_atlas"))
- m_tsrc->buildMainAtlas(this);
-
- // Update node textures
- m_nodedef->updateTextures(m_tsrc);
- }
-
- // Resume threads
- m_mesh_update_thread.setRun(true);
- m_mesh_update_thread.Start();
ClientEvent event;
event.type = CE_TEXTURES_UPDATED;
@@ -1507,82 +1466,53 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
else if(command == TOCLIENT_TOOLDEF)
{
- infostream<<"Client: Received tool definitions: packet size: "
- <<datasize<<std::endl;
-
- std::string datastring((char*)&data[2], datasize-2);
- std::istringstream is(datastring, std::ios_base::binary);
-
- m_tooldef_received = true;
-
- // Stop threads while updating content definitions
- m_mesh_update_thread.setRun(false);
- // Process the remaining TextureSource queue to let MeshUpdateThread
- // get it's remaining textures and thus let it stop
- while(m_mesh_update_thread.IsRunning()){
- m_tsrc->processQueue();
- }
-
- std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
- m_tooldef->deSerialize(tmp_is);
-
- // Resume threads
- m_mesh_update_thread.setRun(true);
- m_mesh_update_thread.Start();
+ infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
}
else if(command == TOCLIENT_NODEDEF)
{
infostream<<"Client: Received node definitions: packet size: "
<<datasize<<std::endl;
+ // Mesh update thread must be stopped while
+ // updating content definitions
+ assert(!m_mesh_update_thread.IsRunning());
+
+ // Decompress node definitions
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
-
- m_nodedef_received = true;
-
- // Stop threads while updating content definitions
- m_mesh_update_thread.stop();
-
std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
- m_nodedef->deSerialize(tmp_is, this);
-
- if(m_textures_received){
- // Update texture atlas
- if(g_settings->getBool("enable_texture_atlas"))
- m_tsrc->buildMainAtlas(this);
-
- // Update node textures
- m_nodedef->updateTextures(m_tsrc);
- }
+ std::ostringstream tmp_os;
+ decompressZlib(tmp_is, tmp_os);
- // Resume threads
- m_mesh_update_thread.setRun(true);
- m_mesh_update_thread.Start();
+ // Deserialize node definitions
+ std::istringstream tmp_is2(tmp_os.str());
+ m_nodedef->deSerialize(tmp_is2);
+ m_nodedef_received = true;
}
else if(command == TOCLIENT_CRAFTITEMDEF)
{
- infostream<<"Client: Received CraftItem definitions: packet size: "
+ infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
+ }
+ else if(command == TOCLIENT_ITEMDEF)
+ {
+ infostream<<"Client: Received item definitions: packet size: "
<<datasize<<std::endl;
+ // Mesh update thread must be stopped while
+ // updating content definitions
+ assert(!m_mesh_update_thread.IsRunning());
+
+ // Decompress item definitions
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
-
- m_craftitemdef_received = true;
-
- // Stop threads while updating content definitions
- m_mesh_update_thread.setRun(false);
- // Process the remaining TextureSource queue to let MeshUpdateThread
- // get it's remaining textures and thus let it stop
- while(m_mesh_update_thread.IsRunning()){
- m_tsrc->processQueue();
- }
-
std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
- m_craftitemdef->deSerialize(tmp_is);
-
- // Resume threads
- m_mesh_update_thread.setRun(true);
- m_mesh_update_thread.Start();
+ std::ostringstream tmp_os;
+ decompressZlib(tmp_is, tmp_os);
+
+ // Deserialize node definitions
+ std::istringstream tmp_is2(tmp_os.str());
+ m_itemdef->deSerialize(tmp_is2);
+ m_itemdef_received = true;
}
else
{
@@ -1943,11 +1873,6 @@ void Client::selectPlayerItem(u16 item)
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
m_playeritem = item;
m_inventory_updated = true;
-
- LocalPlayer *player = m_env.getLocalPlayer();
- assert(player != NULL);
- player->wieldItem(item);
-
sendPlayerItem(item);
}
@@ -1971,17 +1896,19 @@ void Client::getLocalInventory(Inventory &dst)
dst = player->inventory;
}
-InventoryContext *Client::getInventoryContext()
-{
- return &m_inventory_context;
-}
-
Inventory* Client::getInventory(const InventoryLocation &loc)
{
switch(loc.type){
case InventoryLocation::UNDEFINED:
{}
break;
+ case InventoryLocation::CURRENT_PLAYER:
+ {
+ Player *player = m_env.getLocalPlayer();
+ assert(player != NULL);
+ return &player->inventory;
+ }
+ break;
case InventoryLocation::PLAYER:
{
Player *player = m_env.getPlayer(loc.name.c_str());
@@ -2003,36 +1930,6 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
}
return NULL;
}
-#if 0
-Inventory* Client::getInventory(InventoryContext *c, std::string id)
-{
- if(id == "current_player")
- {
- assert(c->current_player);
- return &(c->current_player->inventory);
- }
-
- Strfnd fn(id);
- std::string id0 = fn.next(":");
-
- if(id0 == "nodemeta")
- {
- v3s16 p;
- p.X = stoi(fn.next(","));
- p.Y = stoi(fn.next(","));
- p.Z = stoi(fn.next(","));
- NodeMetadata* meta = getNodeMetadata(p);
- if(meta)
- return meta->getInventory();
- infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
- <<"no metadata found"<<std::endl;
- return NULL;
- }
-
- infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
- return NULL;
-}
-#endif
void Client::inventoryAction(InventoryAction *a)
{
sendInventoryAction(a);
@@ -2234,6 +2131,32 @@ ClientEvent Client::getClientEvent()
return m_client_event_queue.pop_front();
}
+void Client::afterContentReceived()
+{
+ assert(m_itemdef_received);
+ assert(m_nodedef_received);
+ assert(m_textures_received);
+
+ // Rebuild inherited images and recreate textures
+ m_tsrc->rebuildImagesAndTextures();
+
+ // Update texture atlas
+ if(g_settings->getBool("enable_texture_atlas"))
+ m_tsrc->buildMainAtlas(this);
+
+ // Update node aliases
+ m_nodedef->updateAliases(m_itemdef);
+
+ // Update node textures
+ m_nodedef->updateTextures(m_tsrc);
+
+ // Update item textures and meshes
+ m_itemdef->updateTexturesAndMeshes(this);
+
+ // Start mesh update thread after setting up content definitions
+ m_mesh_update_thread.Start();
+}
+
float Client::getRTT(void)
{
try{
@@ -2245,9 +2168,9 @@ float Client::getRTT(void)
// IGameDef interface
// Under envlock
-IToolDefManager* Client::getToolDefManager()
+IItemDefManager* Client::getItemDefManager()
{
- return m_tooldef;
+ return m_itemdef;
}
INodeDefManager* Client::getNodeDefManager()
{
@@ -2258,10 +2181,6 @@ ICraftDefManager* Client::getCraftDefManager()
return NULL;
//return m_craftdef;
}
-ICraftItemDefManager* Client::getCraftItemDefManager()
-{
- return m_craftitemdef;
-}
ITextureSource* Client::getTextureSource()
{
return m_tsrc;
diff --git a/src/client.h b/src/client.h
index 49794acf5..6d5e5c525 100644
--- a/src/client.h
+++ b/src/client.h
@@ -36,10 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct MeshMakeData;
class IGameDef;
class IWritableTextureSource;
-class IWritableToolDefManager;
+class IWritableItemDefManager;
class IWritableNodeDefManager;
//class IWritableCraftDefManager;
-class IWritableCraftItemDefManager;
class ClientNotReadyException : public BaseException
{
@@ -167,9 +166,8 @@ public:
std::string password,
MapDrawControl &control,
IWritableTextureSource *tsrc,
- IWritableToolDefManager *tooldef,
- IWritableNodeDefManager *nodedef,
- IWritableCraftItemDefManager *craftitemdef
+ IWritableItemDefManager *itemdef,
+ IWritableNodeDefManager *nodedef
);
~Client();
@@ -245,11 +243,8 @@ public:
// Copies the inventory of the local player to parameter
void getLocalInventory(Inventory &dst);
- InventoryContext *getInventoryContext();
-
/* InventoryManager interface */
Inventory* getInventory(const InventoryLocation &loc);
- //Inventory* getInventory(InventoryContext *c, std::string id);
void inventoryAction(InventoryAction *a);
// Gets closest object pointed by the shootline
@@ -323,20 +318,19 @@ public:
bool texturesReceived()
{ return m_textures_received; }
- bool tooldefReceived()
- { return m_tooldef_received; }
+ bool itemdefReceived()
+ { return m_itemdef_received; }
bool nodedefReceived()
{ return m_nodedef_received; }
- bool craftitemdefReceived()
- { return m_craftitemdef_received; }
+ void afterContentReceived();
+
float getRTT(void);
// IGameDef interface
- virtual IToolDefManager* getToolDefManager();
+ virtual IItemDefManager* getItemDefManager();
virtual INodeDefManager* getNodeDefManager();
virtual ICraftDefManager* getCraftDefManager();
- virtual ICraftItemDefManager* getCraftItemDefManager();
virtual ITextureSource* getTextureSource();
virtual u16 allocateUnknownNodeId(const std::string &name);
@@ -363,9 +357,8 @@ private:
IntervalLimiter m_map_timer_and_unload_interval;
IWritableTextureSource *m_tsrc;
- IWritableToolDefManager *m_tooldef;
+ IWritableItemDefManager *m_itemdef;
IWritableNodeDefManager *m_nodedef;
- IWritableCraftItemDefManager *m_craftitemdef;
MeshUpdateThread m_mesh_update_thread;
ClientEnvironment m_env;
con::Connection m_con;
@@ -387,13 +380,11 @@ private:
std::string m_password;
bool m_access_denied;
std::wstring m_access_denied_reason;
- InventoryContext m_inventory_context;
Queue<ClientEvent> m_client_event_queue;
float m_texture_receive_progress;
bool m_textures_received;
- bool m_tooldef_received;
+ bool m_itemdef_received;
bool m_nodedef_received;
- bool m_craftitemdef_received;
friend class FarMesh;
};
diff --git a/src/clientserver.h b/src/clientserver.h
index 43de689e4..acb4f8530 100644
--- a/src/clientserver.h
+++ b/src/clientserver.h
@@ -39,9 +39,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Make players to be handled mostly as ActiveObjects
PROTOCOL_VERSION 6:
Only non-cached textures are sent
+ PROTOCOL_VERSION 7:
+ Add TOCLIENT_ITEMDEF
+ Obsolete TOCLIENT_TOOLDEF
+ Obsolete TOCLIENT_CRAFTITEMDEF
+ Compress the contents of TOCLIENT_ITEMDEF and TOCLIENT_NODEDEF
*/
-#define PROTOCOL_VERSION 6
+#define PROTOCOL_VERSION 7
#define PROTOCOL_ID 0x4f457403
@@ -252,6 +257,14 @@ enum ToClientCommand
string sha1_digest
}
*/
+
+ TOCLIENT_ITEMDEF = 0x3d,
+ /*
+ u16 command
+ u32 length of next item
+ serialized ItemDefManager
+ */
+
};
enum ToServerCommand
diff --git a/src/connection.cpp b/src/connection.cpp
index b9c5d2ac8..8f308c99f 100644
--- a/src/connection.cpp
+++ b/src/connection.cpp
@@ -666,7 +666,7 @@ void Connection::send(float dtime)
// Receive packets from the network and buffers and create ConnectionEvents
void Connection::receive()
{
- u32 datasize = 100000;
+ u32 datasize = m_max_packet_size * 2; // Double it just to be safe
// TODO: We can not know how many layers of header there are.
// For now, just assume there are no other than the base headers.
u32 packet_maxsize = datasize + BASE_HEADER_SIZE;
@@ -854,10 +854,6 @@ void Connection::receive()
dout_con<<"ProcessPacket returned data of size "
<<resultdata.getSize()<<std::endl;
- if(datasize < resultdata.getSize())
- throw InvalidIncomingDataException
- ("Buffer too small for received data");
-
ConnectionEvent e;
e.dataReceived(peer_id, resultdata);
putEvent(e);
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index d581b35dc..a2708674b 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_cao.h"
#include "tile.h"
#include "environment.h"
+#include "collision.h"
#include "settings.h"
#include <ICameraSceneNode.h>
#include <ITextSceneNode.h>
@@ -172,6 +173,8 @@ public:
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
+ void updateInfoText();
+ void updateTexture();
void step(float dtime, ClientEnvironment *env);
@@ -191,7 +194,7 @@ private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
- std::string m_inventorystring;
+ std::string m_itemstring;
std::string m_infotext;
};
@@ -595,39 +598,13 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
buf->drop();
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
- // Set it to use the materials of the meshbuffers directly.
- // This is needed for changing the texture in the future
- m_node->setReadOnlyMaterials(true);
updateNodePos();
/*
Update image of node
*/
- // Create an inventory item to see what is its image
- std::istringstream is(m_inventorystring, std::ios_base::binary);
- video::ITexture *texture = NULL;
- try{
- InventoryItem *item = NULL;
- item = InventoryItem::deSerialize(is, m_gamedef);
- infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
- <<m_inventorystring<<"\" -> item="<<item
- <<std::endl;
- if(item)
- {
- texture = item->getImage();
- delete item;
- }
- }
- catch(SerializationError &e)
- {
- infostream<<"WARNING: "<<__FUNCTION_NAME
- <<": error deSerializing inventorystring \""
- <<m_inventorystring<<"\""<<std::endl;
- }
-
- // Set meshbuffer texture
- buf->getMaterial().setTexture(0, texture);
+ updateTexture();
}
void ItemCAO::removeFromScene()
@@ -662,6 +639,51 @@ void ItemCAO::updateNodePos()
m_node->setPosition(m_position);
}
+void ItemCAO::updateInfoText()
+{
+ try{
+ IItemDefManager *idef = m_gamedef->idef();
+ ItemStack item;
+ item.deSerialize(m_itemstring, idef);
+ if(item.isKnown(idef))
+ m_infotext = item.getDefinition(idef).description;
+ else
+ m_infotext = "Unknown item: '" + m_itemstring + "'";
+ if(item.count >= 2)
+ m_infotext += " (" + itos(item.count) + ")";
+ }
+ catch(SerializationError &e)
+ {
+ m_infotext = "Unknown item: '" + m_itemstring + "'";
+ }
+}
+
+void ItemCAO::updateTexture()
+{
+ if(m_node == NULL)
+ return;
+
+ // Create an inventory item to see what is its image
+ std::istringstream is(m_itemstring, std::ios_base::binary);
+ video::ITexture *texture = NULL;
+ try{
+ IItemDefManager *idef = m_gamedef->idef();
+ ItemStack item;
+ item.deSerialize(is, idef);
+ texture = item.getDefinition(idef).inventory_texture;
+ }
+ catch(SerializationError &e)
+ {
+ infostream<<"WARNING: "<<__FUNCTION_NAME
+ <<": error deSerializing itemstring \""
+ <<m_itemstring<<std::endl;
+ }
+
+ // Set meshbuffer texture
+ m_node->getMaterial(0).setTexture(0, texture);
+}
+
+
void ItemCAO::step(float dtime, ClientEnvironment *env)
{
if(m_node)
@@ -689,6 +711,13 @@ void ItemCAO::processMessage(const std::string &data)
m_position = readV3F1000(is);
updateNodePos();
}
+ if(cmd == 1)
+ {
+ // itemstring
+ m_itemstring = deSerializeString(is);
+ updateInfoText();
+ updateTexture();
+ }
}
void ItemCAO::initialize(const std::string &data)
@@ -704,28 +733,12 @@ void ItemCAO::initialize(const std::string &data)
return;
// pos
m_position = readV3F1000(is);
- // inventorystring
- m_inventorystring = deSerializeString(is);
+ // itemstring
+ m_itemstring = deSerializeString(is);
}
updateNodePos();
-
- /*
- Set infotext to item name if item cannot be deserialized
- */
- try{
- InventoryItem *item = NULL;
- item = InventoryItem::deSerialize(m_inventorystring, m_gamedef);
- if(item){
- if(!item->isKnown())
- m_infotext = "Unknown item: '" + m_inventorystring + "'";
- }
- delete item;
- }
- catch(SerializationError &e)
- {
- m_infotext = "Unknown item: '" + m_inventorystring + "'";
- }
+ updateInfoText();
}
/*
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index e8e4fd231..79f49cbf8 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -20,112 +20,105 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapblock.h"
#include "main.h" // For g_settings
-#include "mineral.h"
-#include "mapblock_mesh.h" // For MapBlock_LightColor()
+#include "mapblock_mesh.h" // For MapBlock_LightColor() and MeshCollector
#include "settings.h"
#include "nodedef.h"
+#include "tile.h"
#include "gamedef.h"
-#ifndef SERVER
// Create a cuboid.
-// material - the material to use (for all 6 faces)
// collector - the MeshCollector for the resulting polygons
-// pa - texture atlas pointer for the material
+// box - the position and size of the box
+// materials - the materials to use (for all 6 faces)
+// pa - texture atlas pointers for the materials
+// matcount - number of entries in "materials" and "pa", 1<=matcount<=6
// c - vertex colour - used for all
-// pos - the position of the centre of the cuboid
-// rz,ry,rz - the radius of the cuboid in each dimension
// txc - texture coordinates - this is a list of texture coordinates
// for the opposite corners of each face - therefore, there
// should be (2+2)*6=24 values in the list. Alternatively, pass
// NULL to use the entire texture for each face. The order of
-// the faces in the list is top-backi-right-front-left-bottom
-// If you specified 0,0,1,1 for each face, that would be the
-// same as passing NULL.
-void makeCuboid(video::SMaterial &material, MeshCollector *collector,
- AtlasPointer* pa, video::SColor &c,
- v3f &pos, f32 rx, f32 ry, f32 rz, f32* txc)
+// the faces in the list is up-down-right-left-back-front
+// (compatible with ContentFeatures). If you specified 0,0,1,1
+// for each face, that would be the same as passing NULL.
+void makeCuboid(MeshCollector *collector, const aabb3f &box,
+ const video::SMaterial *materials, const AtlasPointer *pa, int matcount,
+ video::SColor &c, const f32* txc)
{
- f32 tu0=pa->x0();
- f32 tu1=pa->x1();
- f32 tv0=pa->y0();
- f32 tv1=pa->y1();
- f32 txus=tu1-tu0;
- f32 txvs=tv1-tv0;
-
- video::S3DVertex v[4] =
+ assert(matcount >= 1);
+
+ v3f min = box.MinEdge;
+ v3f max = box.MaxEdge;
+
+ if(txc == NULL)
{
- video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv1),
- video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv1),
- video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv0),
- video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv0)
- };
+ static const f32 txc_default[24] = {
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1
+ };
+ txc = txc_default;
+ }
- for(int i=0;i<6;i++)
+ video::S3DVertex vertices[24] =
{
- switch(i)
- {
- case 0: // top
- v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
- v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
- v[2].Pos.X= rx; v[2].Pos.Y= ry; v[2].Pos.Z= rz;
- v[3].Pos.X= rx; v[3].Pos.Y= ry, v[3].Pos.Z=-rz;
- break;
- case 1: // back
- v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
- v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
- v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
- v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
- break;
- case 2: //right
- v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
- v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
- v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
- v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
- break;
- case 3: // front
- v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
- v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
- v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
- v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
- break;
- case 4: // left
- v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
- v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
- v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
- v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
- break;
- case 5: // bottom
- v[0].Pos.X= rx; v[0].Pos.Y=-ry; v[0].Pos.Z= rz;
- v[1].Pos.X=-rx; v[1].Pos.Y=-ry; v[1].Pos.Z= rz;
- v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
- v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
- break;
- }
+ // up
+ video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c, txc[0],txc[1]),
+ video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c, txc[2],txc[1]),
+ video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c, txc[2],txc[3]),
+ video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c, txc[0],txc[3]),
+ // down
+ video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c, txc[4],txc[5]),
+ video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c, txc[6],txc[5]),
+ video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c, txc[6],txc[7]),
+ video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c, txc[4],txc[7]),
+ // right
+ video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c, txc[ 8],txc[9]),
+ video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c, txc[10],txc[9]),
+ video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c, txc[10],txc[11]),
+ video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c, txc[ 8],txc[11]),
+ // left
+ video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c, txc[12],txc[13]),
+ video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c, txc[14],txc[13]),
+ video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]),
+ video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]),
+ // back
+ video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[16],txc[17]),
+ video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[18],txc[17]),
+ video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[18],txc[19]),
+ video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[16],txc[19]),
+ // front
+ video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[20],txc[21]),
+ video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[22],txc[21]),
+ video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[22],txc[23]),
+ video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[20],txc[23]),
+ };
- if(txc!=NULL)
- {
- v[0].TCoords.X=tu0+txus*txc[0]; v[0].TCoords.Y=tv0+txvs*txc[3];
- v[1].TCoords.X=tu0+txus*txc[2]; v[1].TCoords.Y=tv0+txvs*txc[3];
- v[2].TCoords.X=tu0+txus*txc[2]; v[2].TCoords.Y=tv0+txvs*txc[1];
- v[3].TCoords.X=tu0+txus*txc[0]; v[3].TCoords.Y=tv0+txvs*txc[1];
- txc+=4;
- }
+ for(s32 j=0; j<24; j++)
+ {
+ int matindex = MYMIN(j/4, matcount-1);
+ vertices[j].TCoords *= pa[matindex].size;
+ vertices[j].TCoords += pa[matindex].pos;
+ }
- for(u16 i=0; i<4; i++)
- v[i].Pos += pos;
- u16 indices[] = {0,1,2,2,3,0};
- collector->append(material, v, 4, indices, 6);
+ u16 indices[] = {0,1,2,2,3,0};
+ // Add to mesh collector
+ for(s32 j=0; j<24; j+=4)
+ {
+ int matindex = MYMIN(j/4, matcount-1);
+ collector->append(materials[matindex],
+ vertices+j, 4, indices, 6);
}
-
}
-#endif
-#ifndef SERVER
void mapblock_mesh_generate_special(MeshMakeData *data,
MeshCollector &collector, IGameDef *gamedef)
{
INodeDefManager *nodedef = gamedef->ndef();
+ ITextureSource *tsrc = gamedef->getTextureSource();
// 0ms
//TimeTaker timer("mapblock_mesh_generate_special()");
@@ -521,7 +514,9 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
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 = f.tiles[0].texture;
+ TileSpec tile_glass = getNodeTile(n, p, v3s16(0,0,0),
+ &data->m_temp_mods, tsrc, nodedef);
+ AtlasPointer pa_glass = tile_glass.texture;
material_glass.setTexture(0, pa_glass.atlas);
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
@@ -585,54 +580,21 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
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 = f.tiles[0].texture;
+ TileSpec tile_leaves1 = getNodeTile(n, p, v3s16(0,0,0),
+ &data->m_temp_mods, tsrc, nodedef);
+ AtlasPointer pa_leaves1 = tile_leaves1.texture;
material_leaves1.setTexture(0, pa_leaves1.atlas);
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
video::SColor c = MapBlock_LightColor(255, 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_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()),
- };
-
- // Rotations in the g_6dirs format
- if(j == 0) // Z+
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateXZBy(0);
- else if(j == 1) // Y+
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateYZBy(-90);
- else if(j == 2) // X+
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateXZBy(-90);
- else if(j == 3) // Z-
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateXZBy(180);
- else if(j == 4) // Y-
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateYZBy(90);
- else if(j == 5) // X-
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateXZBy(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);
- }
+ v3f pos = intToFloat(p+blockpos_nodes, BS);
+ aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
+ box.MinEdge += pos;
+ box.MaxEdge += pos;
+ makeCuboid(&collector, box,
+ &material_leaves1, &pa_leaves1, 1,
+ c, NULL);
break;}
case NDT_ALLFACES_OPTIONAL:
// This is always pre-converted to something else
@@ -824,9 +786,22 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
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 = f.tiles[0].texture;
+ TileSpec tile_wood = getNodeTile(n, p, v3s16(0,0,0),
+ &data->m_temp_mods, tsrc, nodedef);
+ AtlasPointer pa_wood = tile_wood.texture;
material_wood.setTexture(0, pa_wood.atlas);
+ video::SMaterial material_wood_nomod;
+ material_wood_nomod.setFlag(video::EMF_LIGHTING, false);
+ material_wood_nomod.setFlag(video::EMF_BILINEAR_FILTER, false);
+ material_wood_nomod.setFlag(video::EMF_FOG_ENABLE, true);
+ material_wood_nomod.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+
+ TileSpec tile_wood_nomod = getNodeTile(n, p, v3s16(0,0,0),
+ NULL, tsrc, nodedef);
+ AtlasPointer pa_wood_nomod = tile_wood_nomod.texture;
+ material_wood_nomod.setTexture(0, pa_wood_nomod.atlas);
+
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
video::SColor c = MapBlock_LightColor(255, l);
@@ -834,18 +809,21 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
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);
+
+ // The post - always present
+ aabb3f post(-post_rad,-BS/2,-post_rad,post_rad,BS/2,post_rad);
+ post.MinEdge += pos;
+ post.MaxEdge += pos;
f32 postuv[24]={
0.4,0.4,0.6,0.6,
+ 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);
+ 0.35,0,0.65,1};
+ makeCuboid(&collector, post, &material_wood,
+ &pa_wood, 1, c, postuv);
// Now a section of fence, +X, if there's a post there
v3s16 p2 = p;
@@ -854,9 +832,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
const ContentFeatures *f2 = &nodedef->get(n2);
if(f2->drawtype == NDT_FENCELIKE)
{
- pos = intToFloat(p+blockpos_nodes, BS);
- pos.X += BS/2;
- pos.Y += BS/4;
+ aabb3f bar(-bar_len+BS/2,-bar_rad+BS/4,-bar_rad,
+ bar_len+BS/2,bar_rad+BS/4,bar_rad);
+ bar.MinEdge += pos;
+ bar.MaxEdge += pos;
f32 xrailuv[24]={
0,0.4,1,0.6,
0,0.4,1,0.6,
@@ -864,14 +843,12 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
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);
+ makeCuboid(&collector, bar, &material_wood_nomod,
+ &pa_wood_nomod, 1, c, xrailuv);
+ bar.MinEdge.Y -= BS/2;
+ bar.MaxEdge.Y -= BS/2;
+ makeCuboid(&collector, bar, &material_wood_nomod,
+ &pa_wood_nomod, 1, c, xrailuv);
}
// Now a section of fence, +Z, if there's a post there
@@ -881,9 +858,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
f2 = &nodedef->get(n2);
if(f2->drawtype == NDT_FENCELIKE)
{
- pos = intToFloat(p+blockpos_nodes, BS);
- pos.Z += BS/2;
- pos.Y += BS/4;
+ aabb3f bar(-bar_rad,-bar_rad+BS/4,-bar_len+BS/2,
+ bar_rad,bar_rad+BS/4,bar_len+BS/2);
+ bar.MinEdge += pos;
+ bar.MaxEdge += pos;
f32 zrailuv[24]={
0,0.4,1,0.6,
0,0.4,1,0.6,
@@ -891,14 +869,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
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);
+ makeCuboid(&collector, bar, &material_wood_nomod,
+ &pa_wood_nomod, 1, c, zrailuv);
+ bar.MinEdge.Y -= BS/2;
+ bar.MaxEdge.Y -= BS/2;
+ makeCuboid(&collector, bar, &material_wood_nomod,
+ &pa_wood_nomod, 1, c, zrailuv);
}
break;}
case NDT_RAILLIKE:
@@ -1011,5 +988,4 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
}
}
}
-#endif
diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp
index a74760ba3..4701736cf 100644
--- a/src/content_mapnode.cpp
+++ b/src/content_mapnode.cpp
@@ -27,75 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <map>
/*
- Legacy node definitions
-*/
-
-#define WATER_ALPHA 160
-
-#define WATER_VISC 1
-#define LAVA_VISC 7
-
-void setConstantMaterialProperties(MaterialProperties &mprop, float time)
-{
- mprop.diggability = DIGGABLE_CONSTANT;
- mprop.constant_time = time;
-}
-
-void setStoneLikeMaterialProperties(MaterialProperties &mprop, float toughness)
-{
- mprop.diggability = DIGGABLE_NORMAL;
- mprop.weight = 5.0 * toughness;
- mprop.crackiness = 1.0;
- mprop.crumbliness = -0.1;
- mprop.cuttability = -0.2;
-}
-
-void setDirtLikeMaterialProperties(MaterialProperties &mprop, float toughness)
-{
- mprop.diggability = DIGGABLE_NORMAL;
- mprop.weight = toughness * 1.2;
- mprop.crackiness = 0;
- mprop.crumbliness = 1.2;
- mprop.cuttability = -0.4;
-}
-
-void setGravelLikeMaterialProperties(MaterialProperties &mprop, float toughness)
-{
- mprop.diggability = DIGGABLE_NORMAL;
- mprop.weight = toughness * 2.0;
- mprop.crackiness = 0.2;
- mprop.crumbliness = 1.5;
- mprop.cuttability = -1.0;
-}
-
-void setWoodLikeMaterialProperties(MaterialProperties &mprop, float toughness)
-{
- mprop.diggability = DIGGABLE_NORMAL;
- mprop.weight = toughness * 1.0;
- mprop.crackiness = 0.75;
- mprop.crumbliness = -1.0;
- mprop.cuttability = 1.5;
-}
-
-void setLeavesLikeMaterialProperties(MaterialProperties &mprop, float toughness)
-{
- mprop.diggability = DIGGABLE_NORMAL;
- mprop.weight = -0.5 * toughness;
- mprop.crackiness = 0;
- mprop.crumbliness = 0;
- mprop.cuttability = 2.0;
-}
-
-void setGlassLikeMaterialProperties(MaterialProperties &mprop, float toughness)
-{
- mprop.diggability = DIGGABLE_NORMAL;
- mprop.weight = 0.1 * toughness;
- mprop.crackiness = 2.0;
- mprop.crumbliness = -1.0;
- mprop.cuttability = -1.0;
-}
-
-/*
Legacy node content type IDs
Ranges:
0x000...0x07f (0...127): param2 is fully usable
@@ -209,46 +140,46 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version)
void content_mapnode_get_name_id_mapping(NameIdMapping *nimap)
{
- nimap->set(0, "stone");
- nimap->set(2, "water_flowing");
- nimap->set(3, "torch");
- nimap->set(9, "water_source");
- nimap->set(14, "sign_wall");
- nimap->set(15, "chest");
- nimap->set(16, "furnace");
- nimap->set(17, "locked_chest");
- nimap->set(21, "wooden_fence");
- nimap->set(30, "rail");
- nimap->set(31, "ladder");
- nimap->set(32, "lava_flowing");
- nimap->set(33, "lava_source");
- nimap->set(0x800, "dirt_with_grass");
- nimap->set(0x801, "tree");
- nimap->set(0x802, "leaves");
- nimap->set(0x803, "dirt_with_grass_footsteps");
- nimap->set(0x804, "mese");
- nimap->set(0x805, "dirt");
- nimap->set(0x806, "cloud");
- nimap->set(0x807, "coalstone");
- nimap->set(0x808, "wood");
- nimap->set(0x809, "sand");
- nimap->set(0x80a, "cobble");
- nimap->set(0x80b, "steel");
- nimap->set(0x80c, "glass");
- nimap->set(0x80d, "mossycobble");
- nimap->set(0x80e, "gravel");
- nimap->set(0x80f, "sandstone");
- nimap->set(0x810, "cactus");
- nimap->set(0x811, "brick");
- nimap->set(0x812, "clay");
- nimap->set(0x813, "papyrus");
- nimap->set(0x814, "bookshelf");
- nimap->set(0x815, "jungletree");
- nimap->set(0x816, "junglegrass");
- nimap->set(0x817, "nyancat");
- nimap->set(0x818, "nyancat_rainbow");
- nimap->set(0x819, "apple");
- nimap->set(0x820, "sapling");
+ nimap->set(0, "default:stone");
+ nimap->set(2, "default:water_flowing");
+ nimap->set(3, "default:torch");
+ nimap->set(9, "default:water_source");
+ nimap->set(14, "default:sign_wall");
+ nimap->set(15, "default:chest");
+ nimap->set(16, "default:furnace");
+ nimap->set(17, "default:chest_locked");
+ nimap->set(21, "default:fence_wood");
+ nimap->set(30, "default:rail");
+ nimap->set(31, "default:ladder");
+ nimap->set(32, "default:lava_flowing");
+ nimap->set(33, "default:lava_source");
+ nimap->set(0x800, "default:dirt_with_grass");
+ nimap->set(0x801, "default:tree");
+ nimap->set(0x802, "default:leaves");
+ nimap->set(0x803, "default:dirt_with_grass_footsteps");
+ nimap->set(0x804, "default:mese");
+ nimap->set(0x805, "default:dirt");
+ nimap->set(0x806, "default:cloud");
+ nimap->set(0x807, "default:coalstone");
+ nimap->set(0x808, "default:wood");
+ nimap->set(0x809, "default:sand");
+ nimap->set(0x80a, "default:cobble");
+ nimap->set(0x80b, "default:steelblock");
+ nimap->set(0x80c, "default:glass");
+ nimap->set(0x80d, "default:mossycobble");
+ nimap->set(0x80e, "default:gravel");
+ nimap->set(0x80f, "default:sandstone");
+ nimap->set(0x810, "default:cactus");
+ nimap->set(0x811, "default:brick");
+ nimap->set(0x812, "default:clay");
+ nimap->set(0x813, "default:papyrus");
+ nimap->set(0x814, "default:bookshelf");
+ nimap->set(0x815, "default:jungletree");
+ nimap->set(0x816, "default:junglegrass");
+ nimap->set(0x817, "default:nyancat");
+ nimap->set(0x818, "default:nyancat_rainbow");
+ nimap->set(0x819, "default:apple");
+ nimap->set(0x820, "default:sapling");
// Static types
nimap->set(CONTENT_IGNORE, "ignore");
nimap->set(CONTENT_AIR, "air");
@@ -259,46 +190,46 @@ class NewNameGetter
public:
NewNameGetter()
{
- old_to_new["CONTENT_STONE"] = "stone";
- old_to_new["CONTENT_WATER"] = "water_flowing";
- old_to_new["CONTENT_TORCH"] = "torch";
- old_to_new["CONTENT_WATERSOURCE"] = "water_source";
- old_to_new["CONTENT_SIGN_WALL"] = "sign_wall";
- old_to_new["CONTENT_CHEST"] = "chest";
- old_to_new["CONTENT_FURNACE"] = "furnace";
- old_to_new["CONTENT_LOCKABLE_CHEST"] = "locked_chest";
- old_to_new["CONTENT_FENCE"] = "wooden_fence";
- old_to_new["CONTENT_RAIL"] = "rail";
- old_to_new["CONTENT_LADDER"] = "ladder";
- old_to_new["CONTENT_LAVA"] = "lava_flowing";
- old_to_new["CONTENT_LAVASOURCE"] = "lava_source";
- old_to_new["CONTENT_GRASS"] = "dirt_with_grass";
- old_to_new["CONTENT_TREE"] = "tree";
- old_to_new["CONTENT_LEAVES"] = "leaves";
- old_to_new["CONTENT_GRASS_FOOTSTEPS"] = "dirt_with_grass_footsteps";
- old_to_new["CONTENT_MESE"] = "mese";
- old_to_new["CONTENT_MUD"] = "dirt";
- old_to_new["CONTENT_CLOUD"] = "cloud";
- old_to_new["CONTENT_COALSTONE"] = "coalstone";
- old_to_new["CONTENT_WOOD"] = "wood";
- old_to_new["CONTENT_SAND"] = "sand";
- old_to_new["CONTENT_COBBLE"] = "cobble";
- old_to_new["CONTENT_STEEL"] = "steel";
- old_to_new["CONTENT_GLASS"] = "glass";
- old_to_new["CONTENT_MOSSYCOBBLE"] = "mossycobble";
- old_to_new["CONTENT_GRAVEL"] = "gravel";
- old_to_new["CONTENT_SANDSTONE"] = "sandstone";
- old_to_new["CONTENT_CACTUS"] = "cactus";
- old_to_new["CONTENT_BRICK"] = "brick";
- old_to_new["CONTENT_CLAY"] = "clay";
- old_to_new["CONTENT_PAPYRUS"] = "papyrus";
- old_to_new["CONTENT_BOOKSHELF"] = "bookshelf";
- old_to_new["CONTENT_JUNGLETREE"] = "jungletree";
- old_to_new["CONTENT_JUNGLEGRASS"] = "junglegrass";
- old_to_new["CONTENT_NC"] = "nyancat";
- old_to_new["CONTENT_NC_RB"] = "nyancat_rainbow";
- old_to_new["CONTENT_APPLE"] = "apple";
- old_to_new["CONTENT_SAPLING"] = "sapling";
+ old_to_new["CONTENT_STONE"] = "default:stone";
+ old_to_new["CONTENT_WATER"] = "default:water_flowing";
+ old_to_new["CONTENT_TORCH"] = "default:torch";
+ old_to_new["CONTENT_WATERSOURCE"] = "default:water_source";
+ old_to_new["CONTENT_SIGN_WALL"] = "default:sign_wall";
+ old_to_new["CONTENT_CHEST"] = "default:chest";
+ old_to_new["CONTENT_FURNACE"] = "default:furnace";
+ old_to_new["CONTENT_LOCKABLE_CHEST"] = "default:locked_chest";
+ old_to_new["CONTENT_FENCE"] = "default:wooden_fence";
+ old_to_new["CONTENT_RAIL"] = "default:rail";
+ old_to_new["CONTENT_LADDER"] = "default:ladder";
+ old_to_new["CONTENT_LAVA"] = "default:lava_flowing";
+ old_to_new["CONTENT_LAVASOURCE"] = "default:lava_source";
+ old_to_new["CONTENT_GRASS"] = "default:dirt_with_grass";
+ old_to_new["CONTENT_TREE"] = "default:tree";
+ old_to_new["CONTENT_LEAVES"] = "default:leaves";
+ old_to_new["CONTENT_GRASS_FOOTSTEPS"] = "default:dirt_with_grass_footsteps";
+ old_to_new["CONTENT_MESE"] = "default:mese";
+ old_to_new["CONTENT_MUD"] = "default:dirt";
+ old_to_new["CONTENT_CLOUD"] = "default:cloud";
+ old_to_new["CONTENT_COALSTONE"] = "default:coalstone";
+ old_to_new["CONTENT_WOOD"] = "default:wood";
+ old_to_new["CONTENT_SAND"] = "default:sand";
+ old_to_new["CONTENT_COBBLE"] = "default:cobble";
+ old_to_new["CONTENT_STEEL"] = "default:steel";
+ old_to_new["CONTENT_GLASS"] = "default:glass";
+ old_to_new["CONTENT_MOSSYCOBBLE"] = "default:mossycobble";
+ old_to_new["CONTENT_GRAVEL"] = "default:gravel";
+ old_to_new["CONTENT_SANDSTONE"] = "default:sandstone";
+ old_to_new["CONTENT_CACTUS"] = "default:cactus";
+ old_to_new["CONTENT_BRICK"] = "default:brick";
+ old_to_new["CONTENT_CLAY"] = "default:clay";
+ old_to_new["CONTENT_PAPYRUS"] = "default:papyrus";
+ old_to_new["CONTENT_BOOKSHELF"] = "default:bookshelf";
+ old_to_new["CONTENT_JUNGLETREE"] = "default:jungletree";
+ old_to_new["CONTENT_JUNGLEGRASS"] = "default:junglegrass";
+ old_to_new["CONTENT_NC"] = "default:nyancat";
+ old_to_new["CONTENT_NC_RB"] = "default:nyancat_rainbow";
+ old_to_new["CONTENT_APPLE"] = "default:apple";
+ old_to_new["CONTENT_SAPLING"] = "default:sapling";
// Just in case
old_to_new["CONTENT_IGNORE"] = "ignore";
old_to_new["CONTENT_AIR"] = "air";
@@ -334,605 +265,3 @@ content_t legacy_get_id(const std::string &oldname, INodeDefManager *ndef)
return id;
}
-// Initialize default (legacy) node definitions
-void content_mapnode_init(IWritableNodeDefManager *nodemgr)
-{
- content_t i;
- ContentFeatures f;
-
- i = CONTENT_STONE;
- f = ContentFeatures();
- f.name = "stone";
- 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";
- setStoneLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_GRASS;
- f = ContentFeatures();
- f.name = "dirt_with_grass";
- 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";
- setDirtLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_GRASS_FOOTSTEPS;
- f = ContentFeatures();
- f.name = "dirt_with_grass_footsteps";
- 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";
- setDirtLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_MUD;
- f = ContentFeatures();
- f.name = "dirt";
- 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";
- setDirtLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_SAND;
- f = ContentFeatures();
- f.name = "sand";
- 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";
- f.cookresult_item = std::string("MaterialItem2 ")+itos(CONTENT_GLASS)+" 1";
- setDirtLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_GRAVEL;
- f = ContentFeatures();
- f.name = "gravel";
- 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";
- setGravelLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_SANDSTONE;
- f = ContentFeatures();
- f.name = "sandstone";
- 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";
- setDirtLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_CLAY;
- f = ContentFeatures();
- f.name = "clay";
- 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");
- setDirtLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_BRICK;
- f = ContentFeatures();
- f.name = "brick";
- 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");
- setStoneLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_TREE;
- f = ContentFeatures();
- f.name = "tree";
- 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";
- f.cookresult_item = "CraftItem lump_of_coal 1";
- f.furnace_burntime = 30;
- setWoodLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_JUNGLETREE;
- f = ContentFeatures();
- f.name = "jungletree";
- f.setAllTextures("jungletree.png");
- f.setTexture(0, "jungletree_top.png");
- f.setTexture(1, "jungletree_top.png");
- f.param_type = CPT_MINERAL;
- f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
- f.furnace_burntime = 30;
- setWoodLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_JUNGLEGRASS;
- f = ContentFeatures();
- f.name = "junglegrass";
- f.drawtype = NDT_PLANTLIKE;
- f.visual_scale = 1.3;
- f.setAllTextures("junglegrass.png");
- f.setInventoryTexture("junglegrass.png");
- f.light_propagates = true;
- f.param_type = CPT_LIGHT;
- f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
- f.walkable = false;
- setLeavesLikeMaterialProperties(f.material, 1.0);
- f.furnace_burntime = 2;
- nodemgr->set(i, f);
-
- i = CONTENT_LEAVES;
- f = ContentFeatures();
- f.name = "leaves";
- f.drawtype = NDT_ALLFACES_OPTIONAL;
- f.setAllTextures("leaves.png");
- //f.setAllTextures("[noalpha:leaves.png");
- f.light_propagates = true;
- f.param_type = CPT_LIGHT;
- 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";
- setLeavesLikeMaterialProperties(f.material, 1.0);
- f.furnace_burntime = 1.0;
- nodemgr->set(i, f);
-
- i = CONTENT_CACTUS;
- f = ContentFeatures();
- f.name = "cactus";
- 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";
- setWoodLikeMaterialProperties(f.material, 0.75);
- f.furnace_burntime = 15;
- nodemgr->set(i, f);
-
- i = CONTENT_PAPYRUS;
- f = ContentFeatures();
- f.name = "papyrus";
- f.drawtype = NDT_PLANTLIKE;
- f.setAllTextures("papyrus.png");
- 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.walkable = false;
- setLeavesLikeMaterialProperties(f.material, 0.5);
- f.furnace_burntime = 1;
- nodemgr->set(i, f);
-
- i = CONTENT_BOOKSHELF;
- f = ContentFeatures();
- f.name = "bookshelf";
- 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;
- setWoodLikeMaterialProperties(f.material, 0.75);
- f.furnace_burntime = 30;
- nodemgr->set(i, f);
-
- i = CONTENT_GLASS;
- f = ContentFeatures();
- f.name = "glass";
- f.drawtype = NDT_GLASSLIKE;
- f.setAllTextures("glass.png");
- 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.setInventoryTextureCube("glass.png", "glass.png", "glass.png");
- setGlassLikeMaterialProperties(f.material, 1.0);
- nodemgr->set(i, f);
-
- i = CONTENT_FENCE;
- f = ContentFeatures();
- f.name = "wooden_fence";
- f.drawtype = NDT_FENCELIKE;
- f.setInventoryTexture("fence.png");
- f.setTexture(0, "wood.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.selection_box.type = NODEBOX_FIXED;
- f.selection_box.fixed = core::aabbox3d<f32>(
- -BS/7, -BS/2, -BS/7, BS/7, BS/2, BS/7);
- f.furnace_burntime = 30/2;
- setWoodLikeMaterialProperties(f.material, 0.75);
- nodemgr->set(i, f);
-
- i = CONTENT_RAIL;
- f = ContentFeatures();
- f.name = "rail";
- f.drawtype = NDT_RAILLIKE;
- f.setInventoryTexture("rail.png");
- f.setTexture(0, "rail.png");
- f.setTexture(1, "rail_curved.png");
- f.setTexture(2, "rail_t_junction.png");
- f.setTexture(3, "rail_crossing.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.walkable = false;
- f.selection_box.type = NODEBOX_FIXED;
- f.furnace_burntime = 5;
- setDirtLikeMaterialProperties(f.material, 0.75);
- nodemgr->set(i, f);
-
- i = CONTENT_LADDER;
- f = ContentFeatures();
- f.name = "ladder";
- f.drawtype = NDT_SIGNLIKE;
- f.setAllTextures("ladder.png");
- 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.walkable = false;
- f.climbable = true;
- f.selection_box.type = NODEBOX_WALLMOUNTED;
- f.furnace_burntime = 5;
- setWoodLikeMaterialProperties(f.material, 0.5);
-
- nodemgr->set(i, f);
-
- i = CONTENT_COALSTONE;
- f = ContentFeatures();
- f.name = "coalstone";
- f.setAllTextures("stone.png^mineral_coal.png");
- f.is_ground_content = true;
- setStoneLikeMaterialProperties(f.material, 1.5);
- nodemgr->set(i, f);
-
- i = CONTENT_WOOD;
- f = ContentFeatures();
- f.name = "wood";
- 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";
- f.furnace_burntime = 30/4;
- setWoodLikeMaterialProperties(f.material, 0.75);
- nodemgr->set(i, f);
-
- i = CONTENT_MESE;
- f = ContentFeatures();
- f.name = "mese";
- 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";
- f.furnace_burntime = 30;
- setStoneLikeMaterialProperties(f.material, 0.5);
- nodemgr->set(i, f);
-
- i = CONTENT_CLOUD;
- f = ContentFeatures();
- f.name = "cloud";
- 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";
- nodemgr->set(i, f);
-
- i = CONTENT_AIR;
- f = ContentFeatures();
- f.name = "air";
- 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;
- nodemgr->set(i, f);
-
- i = CONTENT_WATER;
- f = ContentFeatures();
- f.name = "water_flowing";
- f.drawtype = NDT_FLOWINGLIQUID;
- f.setAllTextures("water.png");
- f.alpha = WATER_ALPHA;
- f.setInventoryTextureCube("water.png", "water.png", "water.png");
- 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_FLOWING;
- f.liquid_alternative_flowing = "water_flowing";
- f.liquid_alternative_source = "water_source";
- f.liquid_viscosity = WATER_VISC;
- f.post_effect_color = video::SColor(64, 100, 100, 200);
- f.setSpecialMaterial(0, MaterialSpec("water.png", false));
- f.setSpecialMaterial(1, MaterialSpec("water.png", true));
- nodemgr->set(i, f);
-
- i = CONTENT_WATERSOURCE;
- f = ContentFeatures();
- f.name = "water_source";
- f.drawtype = NDT_LIQUID;
- f.setAllTextures("water.png");
- f.alpha = WATER_ALPHA;
- f.setInventoryTextureCube("water.png", "water.png", "water.png");
- 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 = "water_flowing";
- f.liquid_alternative_source = "water_source";
- f.liquid_viscosity = WATER_VISC;
- f.post_effect_color = video::SColor(64, 100, 100, 200);
- // New-style water source material (mostly unused)
- f.setSpecialMaterial(0, MaterialSpec("water.png", false));
- nodemgr->set(i, f);
-
- i = CONTENT_LAVA;
- f = ContentFeatures();
- f.name = "lava_flowing";
- f.drawtype = NDT_FLOWINGLIQUID;
- f.setAllTextures("lava.png");
- f.setInventoryTextureCube("lava.png", "lava.png", "lava.png");
- 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_FLOWING;
- f.liquid_alternative_flowing = "lava_flowing";
- f.liquid_alternative_source = "lava_source";
- f.liquid_viscosity = LAVA_VISC;
- f.damage_per_second = 4*2;
- f.post_effect_color = video::SColor(192, 255, 64, 0);
- f.setSpecialMaterial(0, MaterialSpec("lava.png", false));
- f.setSpecialMaterial(1, MaterialSpec("lava.png", true));
- nodemgr->set(i, f);
-
- i = CONTENT_LAVASOURCE;
- f = ContentFeatures();
- f.name = "lava_source";
- f.drawtype = NDT_LIQUID;
- f.setAllTextures("lava.png");
- f.setInventoryTextureCube("lava.png", "lava.png", "lava.png");
- 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 = "lava_flowing";
- f.liquid_alternative_source = "lava_source";
- f.liquid_viscosity = LAVA_VISC;
- f.damage_per_second = 4*2;
- f.post_effect_color = video::SColor(192, 255, 64, 0);
- // New-style lava source material (mostly unused)
- f.setSpecialMaterial(0, MaterialSpec("lava.png", false));
- f.furnace_burntime = 60;
- nodemgr->set(i, f);
-
- i = CONTENT_TORCH;
- f = ContentFeatures();
- f.name = "torch";
- f.drawtype = NDT_TORCHLIKE;
- f.setTexture(0, "torch_on_floor.png");
- f.setTexture(1, "torch_on_ceiling.png");
- f.setTexture(2, "torch.png");
- f.setInventoryTexture("torch_on_floor.png");
- f.param_type = CPT_LIGHT;
- f.light_propagates = true;
- f.sunlight_propagates = true;
- f.walkable = false;
- f.wall_mounted = true;
- f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
- f.light_source = LIGHT_MAX-1;
- f.selection_box.type = NODEBOX_WALLMOUNTED;
- f.selection_box.wall_top = core::aabbox3d<f32>(
- -BS/10, BS/2-BS/3.333*2, -BS/10, BS/10, BS/2, BS/10);
- f.selection_box.wall_bottom = core::aabbox3d<f32>(
- -BS/10, -BS/2, -BS/10, BS/10, -BS/2+BS/3.333*2, BS/10);
- f.selection_box.wall_side = core::aabbox3d<f32>(
- -BS/2, -BS/3.333, -BS/10, -BS/2+BS/3.333, BS/3.333, BS/10);
- setConstantMaterialProperties(f.material, 0.0);
- f.furnace_burntime = 4;
- nodemgr->set(i, f);
-
- i = CONTENT_SIGN_WALL;
- f = ContentFeatures();
- f.name = "sign_wall";
- f.drawtype = NDT_SIGNLIKE;
- f.setAllTextures("sign_wall.png");
- f.setInventoryTexture("sign_wall.png");
- f.param_type = CPT_LIGHT;
- f.light_propagates = true;
- f.sunlight_propagates = true;
- f.walkable = false;
- f.wall_mounted = true;
- f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
- f.metadata_name = "sign";
- setConstantMaterialProperties(f.material, 0.5);
- f.selection_box.type = NODEBOX_WALLMOUNTED;
- f.furnace_burntime = 10;
- nodemgr->set(i, f);
-
- i = CONTENT_CHEST;
- f = ContentFeatures();
- f.name = "chest";
- 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";
- f.metadata_name = "chest";
- setWoodLikeMaterialProperties(f.material, 1.0);
- f.furnace_burntime = 30;
- nodemgr->set(i, f);
-
- i = CONTENT_LOCKABLE_CHEST;
- f = ContentFeatures();
- f.name = "locked_chest";
- 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";
- f.metadata_name = "locked_chest";
- setWoodLikeMaterialProperties(f.material, 1.0);
- f.furnace_burntime = 30;
- nodemgr->set(i, f);
-
- i = CONTENT_FURNACE;
- f = ContentFeatures();
- f.name = "furnace";
- 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";
- f.metadata_name = "furnace";
- setStoneLikeMaterialProperties(f.material, 3.0);
- nodemgr->set(i, f);
-
- i = CONTENT_COBBLE;
- f = ContentFeatures();
- f.name = "cobble";
- 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";
- f.cookresult_item = std::string("MaterialItem2 ")+itos(CONTENT_STONE)+" 1";
- setStoneLikeMaterialProperties(f.material, 0.9);
- nodemgr->set(i, f);
-
- i = CONTENT_MOSSYCOBBLE;
- f = ContentFeatures();
- f.name = "mossycobble";
- 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";
- setStoneLikeMaterialProperties(f.material, 0.8);
- nodemgr->set(i, f);
-
- i = CONTENT_STEEL;
- f = ContentFeatures();
- f.name = "steelblock";
- 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";
- setStoneLikeMaterialProperties(f.material, 5.0);
- nodemgr->set(i, f);
-
- i = CONTENT_NC;
- f = ContentFeatures();
- f.name = "nyancat";
- 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";
- setStoneLikeMaterialProperties(f.material, 3.0);
- f.furnace_burntime = 1;
- nodemgr->set(i, f);
-
- i = CONTENT_NC_RB;
- f = ContentFeatures();
- f.name = "nyancat_rainbow";
- f.setAllTextures("nc_rb.png");
- f.setInventoryTexture("nc_rb.png");
- f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
- setStoneLikeMaterialProperties(f.material, 3.0);
- f.furnace_burntime = 1;
- nodemgr->set(i, f);
-
- i = CONTENT_SAPLING;
- f = ContentFeatures();
- f.name = "sapling";
- f.drawtype = NDT_PLANTLIKE;
- f.visual_scale = 1.0;
- f.setAllTextures("sapling.png");
- f.setInventoryTexture("sapling.png");
- f.param_type = CPT_LIGHT;
- f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
- f.light_propagates = true;
- f.walkable = false;
- setConstantMaterialProperties(f.material, 0.0);
- f.furnace_burntime = 10;
- nodemgr->set(i, f);
-
- i = CONTENT_APPLE;
- f = ContentFeatures();
- f.name = "apple";
- f.drawtype = NDT_PLANTLIKE;
- f.visual_scale = 1.0;
- f.setAllTextures("apple.png");
- f.setInventoryTexture("apple.png");
- f.param_type = CPT_LIGHT;
- f.light_propagates = true;
- f.sunlight_propagates = true;
- f.walkable = false;
- f.dug_item = std::string("CraftItem apple 1");
- setConstantMaterialProperties(f.material, 0.0);
- f.furnace_burntime = 3;
- nodemgr->set(i, f);
-}
-
-
diff --git a/src/content_mapnode.h b/src/content_mapnode.h
index b928e4407..003b7edd7 100644
--- a/src/content_mapnode.h
+++ b/src/content_mapnode.h
@@ -26,12 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Legacy node definitions
*/
-class IWritableNodeDefManager;
-
-// Initialize legacy node definitions
-// Not used used anywhere else than in test.cpp (and SHALL NOT BE)
-void content_mapnode_init(IWritableNodeDefManager *nodemgr);
-
// Backwards compatibility for non-extended content types in v19
extern content_t trans_table_19[21][2];
MapNode mapnode_translate_from_internal(MapNode n_from, u8 version);
diff --git a/src/content_nodemeta.cpp b/src/content_nodemeta.cpp
index 8666051a4..9fb5450cf 100644
--- a/src/content_nodemeta.cpp
+++ b/src/content_nodemeta.cpp
@@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventory.h"
#include "log.h"
#include "utility.h"
+#include "craftdef.h"
+#include "gamedef.h"
class Inventory;
@@ -125,9 +127,14 @@ public:
virtual bool step(float dtime);
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
+
+protected:
+ bool getCookResult(bool remove, std::string &cookresult, float &cooktime);
+ bool getBurnResult(bool remove, float &burntime);
private:
Inventory *m_inventory;
+ std::string m_infotext;
float m_step_accumulator;
float m_fuel_totaltime;
float m_fuel_time;
@@ -185,9 +192,7 @@ ChestNodeMetadata::ChestNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef)
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
-
- m_inventory = new Inventory();
- m_inventory->addList("0", 8*4);
+ m_inventory = NULL;
}
ChestNodeMetadata::~ChestNodeMetadata()
{
@@ -200,18 +205,21 @@ u16 ChestNodeMetadata::typeId() const
NodeMetadata* ChestNodeMetadata::create(std::istream &is, IGameDef *gamedef)
{
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
- d->m_inventory->deSerialize(is, gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
+ d->m_inventory->deSerialize(is);
return d;
}
NodeMetadata* ChestNodeMetadata::create(IGameDef *gamedef)
{
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
+ d->m_inventory->addList("0", 8*4);
return d;
}
NodeMetadata* ChestNodeMetadata::clone(IGameDef *gamedef)
{
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
- *d->m_inventory = *m_inventory;
+ d->m_inventory = new Inventory(*m_inventory);
return d;
}
void ChestNodeMetadata::serializeBody(std::ostream &os)
@@ -253,9 +261,7 @@ LockingChestNodeMetadata::LockingChestNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef)
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
-
- m_inventory = new Inventory();
- m_inventory->addList("0", 8*4);
+ m_inventory = NULL;
}
LockingChestNodeMetadata::~LockingChestNodeMetadata()
{
@@ -269,18 +275,21 @@ NodeMetadata* LockingChestNodeMetadata::create(std::istream &is, IGameDef *gamed
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
d->setOwner(deSerializeString(is));
- d->m_inventory->deSerialize(is, gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
+ d->m_inventory->deSerialize(is);
return d;
}
NodeMetadata* LockingChestNodeMetadata::create(IGameDef *gamedef)
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
+ d->m_inventory->addList("0", 8*4);
return d;
}
NodeMetadata* LockingChestNodeMetadata::clone(IGameDef *gamedef)
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
- *d->m_inventory = *m_inventory;
+ d->m_inventory = new Inventory(*m_inventory);
return d;
}
void LockingChestNodeMetadata::serializeBody(std::ostream &os)
@@ -324,10 +333,9 @@ FurnaceNodeMetadata::FurnaceNodeMetadata(IGameDef *gamedef):
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
- m_inventory = new Inventory();
- m_inventory->addList("fuel", 1);
- m_inventory->addList("src", 1);
- m_inventory->addList("dst", 4);
+ m_inventory = NULL;
+
+ m_infotext = "Furnace is inactive";
m_step_accumulator = 0;
m_fuel_totaltime = 0;
@@ -346,26 +354,52 @@ u16 FurnaceNodeMetadata::typeId() const
NodeMetadata* FurnaceNodeMetadata::clone(IGameDef *gamedef)
{
FurnaceNodeMetadata *d = new FurnaceNodeMetadata(m_gamedef);
- *d->m_inventory = *m_inventory;
+ d->m_inventory = new Inventory(*m_inventory);
return d;
}
NodeMetadata* FurnaceNodeMetadata::create(std::istream &is, IGameDef *gamedef)
{
FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef);
- d->m_inventory->deSerialize(is, gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
+ d->m_inventory->deSerialize(is);
- int temp;
+ int temp = 0;
is>>temp;
d->m_fuel_totaltime = (float)temp/10;
+ temp = 0;
is>>temp;
d->m_fuel_time = (float)temp/10;
+ temp = 0;
+ is>>temp;
+ d->m_src_totaltime = (float)temp/10;
+ temp = 0;
+ is>>temp;
+ d->m_src_time = (float)temp/10;
+
+ if(is.eof())
+ {
+ // Old furnaces didn't serialize src_totaltime and src_time
+ d->m_src_totaltime = 0;
+ d->m_src_time = 0;
+ d->m_infotext = "";
+ }
+ else
+ {
+ // New furnaces also serialize the infotext (so that the
+ // client doesn't need to have the list of cooking recipes).
+ d->m_infotext = deSerializeJsonString(is);
+ }
return d;
}
NodeMetadata* FurnaceNodeMetadata::create(IGameDef *gamedef)
{
FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
+ d->m_inventory->addList("fuel", 1);
+ d->m_inventory->addList("src", 1);
+ d->m_inventory->addList("dst", 4);
return d;
}
void FurnaceNodeMetadata::serializeBody(std::ostream &os)
@@ -373,36 +407,13 @@ void FurnaceNodeMetadata::serializeBody(std::ostream &os)
m_inventory->serialize(os);
os<<itos(m_fuel_totaltime*10)<<" ";
os<<itos(m_fuel_time*10)<<" ";
+ os<<itos(m_src_totaltime*10)<<" ";
+ os<<itos(m_src_time*10)<<" ";
+ os<<serializeJsonString(m_infotext);
}
std::string FurnaceNodeMetadata::infoText()
{
- //return "Furnace";
- if(m_fuel_time >= m_fuel_totaltime)
- {
- const InventoryList *src_list = m_inventory->getList("src");
- assert(src_list);
- const InventoryItem *src_item = src_list->getItem(0);
-
- if(src_item && src_item->isCookable()) {
- InventoryList *dst_list = m_inventory->getList("dst");
- if(!dst_list->roomForCookedItem(src_item))
- return "Furnace is overloaded";
- return "Furnace is out of fuel";
- }
- else
- return "Furnace is inactive";
- }
- else
- {
- std::string s = "Furnace is active";
- // Do this so it doesn't always show (0%) for weak fuel
- if(m_fuel_totaltime > 3) {
- s += " (";
- s += itos(m_fuel_time/m_fuel_totaltime*100);
- s += "%)";
- }
- return s;
- }
+ return m_infotext;
}
bool FurnaceNodeMetadata::nodeRemovalDisabled()
{
@@ -440,86 +451,107 @@ bool FurnaceNodeMetadata::step(float dtime)
dtime = interval;
//infostream<<"Furnace step dtime="<<dtime<<std::endl;
-
+
InventoryList *dst_list = m_inventory->getList("dst");
assert(dst_list);
- InventoryList *src_list = m_inventory->getList("src");
- assert(src_list);
- InventoryItem *src_item = src_list->getItem(0);
-
+ // Check
+ // 1. if the source item is cookable
+ // 2. if there is room for the cooked item
+ std::string cookresult;
+ float cooktime;
+ bool cookable = getCookResult(false, cookresult, cooktime);
+ ItemStack cookresult_item;
bool room_available = false;
-
- if(src_item && src_item->isCookable())
- room_available = dst_list->roomForCookedItem(src_item);
-
- // Start only if there are free slots in dst, so that it can
- // accomodate any result item
- if(room_available)
+ if(cookable)
{
- m_src_totaltime = src_item->getCookTime();
+ cookresult_item.deSerialize(cookresult, m_gamedef->idef());
+ room_available = dst_list->roomForItem(cookresult_item);
}
- else
+
+ // Step fuel time
+ bool burning = (m_fuel_time < m_fuel_totaltime);
+ if(burning)
{
- m_src_time = 0;
- m_src_totaltime = 0;
+ changed = true;
+ m_fuel_time += dtime;
}
-
- /*
- If fuel is burning, increment the burn counters.
- If item finishes cooking, move it to result.
- */
- if(m_fuel_time < m_fuel_totaltime)
+
+ std::string infotext;
+ if(room_available)
{
- //infostream<<"Furnace is active"<<std::endl;
- m_fuel_time += dtime;
- m_src_time += dtime;
- if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
- && src_item)
+ float burntime;
+ if(burning)
+ {
+ changed = true;
+ m_src_time += dtime;
+ m_src_totaltime = cooktime;
+ infotext = "Furnace is cooking";
+ }
+ else if(getBurnResult(true, burntime))
+ {
+ // Fuel inserted
+ changed = true;
+ m_fuel_time = 0;
+ m_fuel_totaltime = burntime;
+ //m_src_time += dtime;
+ //m_src_totaltime = cooktime;
+ infotext = "Furnace is cooking";
+ }
+ else
{
- InventoryItem *cookresult = src_item->createCookResult();
- dst_list->addItem(cookresult);
- src_list->decrementMaterials(1);
m_src_time = 0;
m_src_totaltime = 0;
+ infotext = "Furnace is out of fuel";
+ }
+ if(m_src_totaltime > 0.001 && m_src_time >= m_src_totaltime)
+ {
+ // One item fully cooked
+ changed = true;
+ dst_list->addItem(cookresult_item);
+ getCookResult(true, cookresult, cooktime); // decrement source
+ m_src_totaltime = 0;
+ m_src_time = 0;
}
- changed = true;
-
- // If the fuel was not used up this step, just keep burning it
- if(m_fuel_time < m_fuel_totaltime)
- continue;
}
-
- /*
- Get the source again in case it has all burned
- */
- src_item = src_list->getItem(0);
-
- /*
- If there is no source item, or the source item is not cookable,
- or the furnace is still cooking, or the furnace became overloaded, stop loop.
- */
- if(src_item == NULL || !room_available || m_fuel_time < m_fuel_totaltime ||
- dst_list->roomForCookedItem(src_item) == false)
+ else
{
- m_step_accumulator = 0;
- break;
+ // Not cookable or no room available
+ m_src_totaltime = 0;
+ m_src_time = 0;
+ if(cookable)
+ infotext = "Furnace is overloaded";
+ else if(burning)
+ infotext = "Furnace is active";
+ else
+ {
+ infotext = "Furnace is inactive";
+ m_fuel_totaltime = 0;
+ m_fuel_time = 0;
+ }
+ }
+
+ // Do this so it doesn't always show (0%) for weak fuel
+ if(m_fuel_totaltime > 3) {
+ infotext += " (";
+ infotext += itos(m_fuel_time/m_fuel_totaltime*100);
+ infotext += "%)";
}
-
- //infostream<<"Furnace is out of fuel"<<std::endl;
- InventoryList *fuel_list = m_inventory->getList("fuel");
- assert(fuel_list);
- const InventoryItem *fuel_item = fuel_list->getItem(0);
+ if(infotext != m_infotext)
+ {
+ m_infotext = infotext;
+ changed = true;
+ }
- if(fuel_item && fuel_item->getBurnTime() >= 0){
- m_fuel_totaltime = fuel_item->getBurnTime();
+ if(burning && m_fuel_time >= m_fuel_totaltime)
+ {
m_fuel_time = 0;
- fuel_list->decrementMaterials(1);
- changed = true;
- } else {
- //infostream<<"No fuel found"<<std::endl;
- // No fuel, stop loop.
+ m_fuel_totaltime = 0;
+ }
+
+ if(!changed)
+ {
m_step_accumulator = 0;
break;
}
@@ -535,6 +567,43 @@ std::string FurnaceNodeMetadata::getInventoryDrawSpecString()
"list[current_name;dst;5,1;2,2;]"
"list[current_player;main;0,5;8,4;]";
}
+bool FurnaceNodeMetadata::getCookResult(bool remove,
+ std::string &cookresult, float &cooktime)
+{
+ std::vector<ItemStack> items;
+ InventoryList *src_list = m_inventory->getList("src");
+ assert(src_list);
+ items.push_back(src_list->getItem(0));
+
+ CraftInput ci(CRAFT_METHOD_COOKING, 1, items);
+ CraftOutput co;
+ bool found = m_gamedef->getCraftDefManager()->getCraftResult(
+ ci, co, remove, m_gamedef);
+ if(remove)
+ src_list->changeItem(0, ci.items[0]);
+
+ cookresult = co.item;
+ cooktime = co.time;
+ return found;
+}
+bool FurnaceNodeMetadata::getBurnResult(bool remove, float &burntime)
+{
+ std::vector<ItemStack> items;
+ InventoryList *fuel_list = m_inventory->getList("fuel");
+ assert(fuel_list);
+ items.push_back(fuel_list->getItem(0));
+
+ CraftInput ci(CRAFT_METHOD_FUEL, 1, items);
+ CraftOutput co;
+ bool found = m_gamedef->getCraftDefManager()->getCraftResult(
+ ci, co, remove, m_gamedef);
+ if(remove)
+ fuel_list->changeItem(0, ci.items[0]);
+
+ burntime = co.time;
+ return found;
+}
+
/*
GenericNodeMetadata
@@ -571,7 +640,7 @@ public:
GenericNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef),
- m_inventory(new Inventory()),
+ m_inventory(NULL),
m_text(""),
m_owner(""),
@@ -594,7 +663,7 @@ public:
{
GenericNodeMetadata *d = new GenericNodeMetadata(m_gamedef);
- *d->m_inventory = *m_inventory;
+ d->m_inventory = new Inventory(*m_inventory);
d->m_text = m_text;
d->m_owner = m_owner;
@@ -610,13 +679,15 @@ public:
static NodeMetadata* create(IGameDef *gamedef)
{
GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
return d;
}
static NodeMetadata* create(std::istream &is, IGameDef *gamedef)
{
GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
- d->m_inventory->deSerialize(is, gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
+ d->m_inventory->deSerialize(is);
d->m_text = deSerializeLongString(is);
d->m_owner = deSerializeString(is);
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index f195b16bd..02be64c64 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -24,8 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // For g_profiler
#include "profiler.h"
#include "serialization.h" // For compressZlib
-#include "materials.h" // For MaterialProperties
-#include "tooldef.h" // ToolDiggingProperties
+#include "materials.h" // For MaterialProperties and ToolDiggingProperties
+#include "gamedef.h"
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
@@ -114,9 +114,10 @@ void TestSAO::step(float dtime, bool send_recommended)
ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");
ItemSAO::ItemSAO(ServerEnvironment *env, v3f pos,
- const std::string inventorystring):
+ const std::string itemstring):
ServerActiveObject(env, pos),
- m_inventorystring(inventorystring),
+ m_itemstring(itemstring),
+ m_itemstring_changed(false),
m_speed_f(0,0,0),
m_last_sent_position(0,0,0)
{
@@ -134,10 +135,10 @@ ServerActiveObject* ItemSAO::create(ServerEnvironment *env, v3f pos,
// check if version is supported
if(version != 0)
return NULL;
- std::string inventorystring = deSerializeString(is);
+ std::string itemstring = deSerializeString(is);
infostream<<"ItemSAO::create(): Creating item \""
- <<inventorystring<<"\""<<std::endl;
- return new ItemSAO(env, pos, inventorystring);
+ <<itemstring<<"\""<<std::endl;
+ return new ItemSAO(env, pos, itemstring);
}
void ItemSAO::step(float dtime, bool send_recommended)
@@ -175,17 +176,23 @@ void ItemSAO::step(float dtime, bool send_recommended)
m_last_sent_position = pos_f;
std::ostringstream os(std::ios::binary);
- char buf[6];
// command (0 = update position)
- buf[0] = 0;
- os.write(buf, 1);
+ writeU8(os, 0);
// pos
- writeS32((u8*)buf, m_base_position.X*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Y*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Z*1000);
- os.write(buf, 4);
+ writeV3F1000(os, m_base_position);
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ m_messages_out.push_back(aom);
+ }
+ if(m_itemstring_changed)
+ {
+ m_itemstring_changed = false;
+
+ std::ostringstream os(std::ios::binary);
+ // command (1 = update itemstring)
+ writeU8(os, 1);
+ // itemstring
+ os<<serializeString(m_itemstring);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
@@ -195,19 +202,12 @@ void ItemSAO::step(float dtime, bool send_recommended)
std::string ItemSAO::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
- char buf[6];
// version
- buf[0] = 0;
- os.write(buf, 1);
+ writeU8(os, 0);
// pos
- writeS32((u8*)buf, m_base_position.X*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Y*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Z*1000);
- os.write(buf, 4);
- // inventorystring
- os<<serializeString(m_inventorystring);
+ writeV3F1000(os, m_base_position);
+ // itemstring
+ os<<serializeString(m_itemstring);
return os.str();
}
@@ -215,42 +215,58 @@ std::string ItemSAO::getStaticData()
{
infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
- char buf[1];
// version
- buf[0] = 0;
- os.write(buf, 1);
- // inventorystring
- os<<serializeString(m_inventorystring);
+ writeU8(os, 0);
+ // itemstring
+ os<<serializeString(m_itemstring);
return os.str();
}
-InventoryItem * ItemSAO::createInventoryItem()
+ItemStack ItemSAO::createItemStack()
{
try{
- std::istringstream is(m_inventorystring, std::ios_base::binary);
- IGameDef *gamedef = m_env->getGameDef();
- InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
- infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
- <<m_inventorystring<<"\" -> item="<<item
+ IItemDefManager *idef = m_env->getGameDef()->idef();
+ ItemStack item;
+ item.deSerialize(m_itemstring, idef);
+ infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring
+ <<"\" -> item=\""<<item.getItemString()<<"\""
<<std::endl;
return item;
}
catch(SerializationError &e)
{
infostream<<__FUNCTION_NAME<<": serialization error: "
- <<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
- return NULL;
+ <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
+ return ItemStack();
}
}
void ItemSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
- InventoryItem *item = createInventoryItem();
- bool fits = puncher->addToInventory(item);
- if(fits)
+ // Allow removing items in creative mode
+ if(g_settings->getBool("creative_mode") == true)
+ {
m_removed = true;
- else
- delete item;
+ return;
+ }
+
+ ItemStack item = createItemStack();
+ Inventory *inv = puncher->getInventory();
+ if(inv != NULL)
+ {
+ std::string wieldlist = puncher->getWieldList();
+ ItemStack leftover = inv->addItem(wieldlist, item);
+ puncher->setInventoryModified();
+ if(leftover.empty())
+ {
+ m_removed = true;
+ }
+ else
+ {
+ m_itemstring = leftover.getItemString();
+ m_itemstring_changed = true;
+ }
+ }
}
/*
@@ -436,14 +452,24 @@ std::string RatSAO::getStaticData()
void RatSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
- std::istringstream is("CraftItem rat 1", std::ios_base::binary);
- IGameDef *gamedef = m_env->getGameDef();
- InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
- bool fits = puncher->addToInventory(item);
- if(fits)
+ // Allow removing rats in creative mode
+ if(g_settings->getBool("creative_mode") == true)
+ {
m_removed = true;
- else
- delete item;
+ return;
+ }
+
+ IItemDefManager *idef = m_env->getGameDef()->idef();
+ ItemStack item("rat", 1, 0, "", idef);
+ Inventory *inv = puncher->getInventory();
+ if(inv != NULL)
+ {
+ std::string wieldlist = puncher->getWieldList();
+ ItemStack leftover = inv->addItem(wieldlist, item);
+ puncher->setInventoryModified();
+ if(leftover.empty())
+ m_removed = true;
+ }
}
/*
@@ -703,14 +729,20 @@ void Oerkki1SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
mp.crackiness = -1.0;
mp.cuttability = 1.0;
- ToolDiggingProperties tp;
- puncher->getWieldDiggingProperties(&tp);
+ IItemDefManager *idef = m_env->getGameDef()->idef();
+ ItemStack punchitem = puncher->getWieldedItem();
+ ToolDiggingProperties tp =
+ punchitem.getToolDiggingProperties(idef);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
doDamage(hitprop.hp);
- puncher->damageWieldedItem(hitprop.wear);
+ if(g_settings->getBool("creative_mode") == false)
+ {
+ punchitem.addWear(hitprop.wear, idef);
+ puncher->setWieldedItem(punchitem);
+ }
}
void Oerkki1SAO::doDamage(u16 d)
@@ -1393,14 +1425,20 @@ void MobV2SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
mp.crackiness = -1.0;
mp.cuttability = 1.0;
- ToolDiggingProperties tp;
- puncher->getWieldDiggingProperties(&tp);
+ IItemDefManager *idef = m_env->getGameDef()->idef();
+ ItemStack punchitem = puncher->getWieldedItem();
+ ToolDiggingProperties tp =
+ punchitem.getToolDiggingProperties(idef);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
doDamage(hitprop.hp);
- puncher->damageWieldedItem(hitprop.wear);
+ if(g_settings->getBool("creative_mode") == false)
+ {
+ punchitem.addWear(hitprop.wear, idef);
+ puncher->setWieldedItem(punchitem);
+ }
}
bool MobV2SAO::isPeaceful()
diff --git a/src/content_sao.h b/src/content_sao.h
index c2bb9c3f5..f0c9cea90 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -40,8 +40,7 @@ private:
class ItemSAO : public ServerActiveObject
{
public:
- ItemSAO(ServerEnvironment *env, v3f pos,
- const std::string inventorystring);
+ ItemSAO(ServerEnvironment *env, v3f pos, const std::string itemstring);
u8 getType() const
{return ACTIVEOBJECT_TYPE_ITEM;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
@@ -49,11 +48,12 @@ public:
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
- InventoryItem* createInventoryItem();
+ ItemStack createItemStack();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
float getMinimumSavedMovement(){ return 0.1*BS; }
private:
- std::string m_inventorystring;
+ std::string m_itemstring;
+ bool m_itemstring_changed;
v3f m_speed_f;
v3f m_last_sent_position;
IntervalLimiter m_move_interval;
diff --git a/src/craftdef.cpp b/src/craftdef.cpp
index 0cbb74ea0..5bcbf6f94 100644
--- a/src/craftdef.cpp
+++ b/src/craftdef.cpp
@@ -22,88 +22,738 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h"
#include "log.h"
#include <sstream>
+#include <set>
#include "utility.h"
#include "gamedef.h"
#include "inventory.h"
-#include "inventorymanager.h" // checkItemCombination
-CraftPointerInput::~CraftPointerInput()
+
+// Deserialize an itemstring then return the name of the item
+static std::string craftGetItemName(const std::string &itemstring, IGameDef *gamedef)
+{
+ ItemStack item;
+ item.deSerialize(itemstring, gamedef->idef());
+ return item.name;
+}
+
+// (mapcar craftGetItemName itemstrings)
+static std::vector<std::string> craftGetItemNames(
+ const std::vector<std::string> &itemstrings, IGameDef *gamedef)
+{
+ std::vector<std::string> result;
+ for(std::vector<std::string>::const_iterator
+ i = itemstrings.begin();
+ i != itemstrings.end(); i++)
+ {
+ result.push_back(craftGetItemName(*i, gamedef));
+ }
+ return result;
+}
+
+// Get name of each item, and return them as a new list.
+static std::vector<std::string> craftGetItemNames(
+ const std::vector<ItemStack> &items, IGameDef *gamedef)
{
- for(u32 i=0; i<items.size(); i++)
- delete items[i];
+ std::vector<std::string> result;
+ for(std::vector<ItemStack>::const_iterator
+ i = items.begin();
+ i != items.end(); i++)
+ {
+ result.push_back(i->name);
+ }
+ return result;
}
-CraftPointerInput createPointerInput(const CraftInput &ci, IGameDef *gamedef)
+// Compute bounding rectangle given a matrix of items
+// Returns false if every item is ""
+static bool craftGetBounds(const std::vector<std::string> &items, unsigned int width,
+ unsigned int &min_x, unsigned int &max_x,
+ unsigned int &min_y, unsigned int &max_y)
{
- std::vector<InventoryItem*> items;
- for(u32 i=0; i<ci.items.size(); i++){
- InventoryItem *item = NULL;
- if(ci.items[i] != ""){
- std::istringstream iss(ci.items[i], std::ios::binary);
- item = InventoryItem::deSerialize(iss, gamedef);
+ bool success = false;
+ unsigned int x = 0;
+ unsigned int y = 0;
+ for(std::vector<std::string>::const_iterator
+ i = items.begin();
+ i != items.end(); i++)
+ {
+ if(*i != "") // Is this an actual item?
+ {
+ if(!success)
+ {
+ // This is the first nonempty item
+ min_x = max_x = x;
+ min_y = max_y = y;
+ success = true;
+ }
+ else
+ {
+ if(x < min_x) min_x = x;
+ if(x > max_x) max_x = x;
+ if(y < min_y) min_y = y;
+ if(y > max_y) max_y = y;
+ }
}
- items.push_back(item);
+
+ // Step coordinate
+ x++;
+ if(x == width)
+ {
+ x = 0;
+ y++;
+ }
+ }
+ return success;
+}
+
+// Convert a list of item names to a multiset
+static std::multiset<std::string> craftMakeMultiset(const std::vector<std::string> &names)
+{
+ std::multiset<std::string> set;
+ for(std::vector<std::string>::const_iterator
+ i = names.begin();
+ i != names.end(); i++)
+ {
+ if(*i != "")
+ set.insert(*i);
}
- return CraftPointerInput(ci.width, items);
+ return set;
}
-CraftInput createInput(const CraftPointerInput &cpi)
+// Removes 1 from each item stack
+static void craftDecrementInput(CraftInput &input, IGameDef *gamedef)
{
- std::vector<std::string> items;
- for(u32 i=0; i<cpi.items.size(); i++){
- if(cpi.items[i] == NULL)
- items.push_back("");
- else{
- std::ostringstream oss(std::ios::binary);
- cpi.items[i]->serialize(oss);
- items.push_back(oss.str());
+ for(std::vector<ItemStack>::iterator
+ i = input.items.begin();
+ i != input.items.end(); i++)
+ {
+ if(i->count != 0)
+ i->remove(1);
+ }
+}
+
+// Removes 1 from each item stack with replacement support
+// Example: if replacements contains the pair ("bucket:bucket_water", "bucket:bucket_empty"),
+// a water bucket will not be removed but replaced by an empty bucket.
+static void craftDecrementOrReplaceInput(CraftInput &input,
+ const CraftReplacements &replacements,
+ IGameDef *gamedef)
+{
+ if(replacements.pairs.empty())
+ {
+ craftDecrementInput(input, gamedef);
+ return;
+ }
+
+ // Make a copy of the replacements pair list
+ std::vector<std::pair<std::string, std::string> > pairs = replacements.pairs;
+
+ for(std::vector<ItemStack>::iterator
+ i = input.items.begin();
+ i != input.items.end(); i++)
+ {
+ if(i->count == 1)
+ {
+ // Find an appropriate replacement
+ bool found_replacement = false;
+ for(std::vector<std::pair<std::string, std::string> >::iterator
+ j = pairs.begin();
+ j != pairs.end(); j++)
+ {
+ ItemStack from_item;
+ from_item.deSerialize(j->first, gamedef->idef());
+ if(i->name == from_item.name)
+ {
+ i->deSerialize(j->second, gamedef->idef());
+ found_replacement = true;
+ pairs.erase(j);
+ break;
+ }
+ }
+ // No replacement was found, simply decrement count to zero
+ if(!found_replacement)
+ i->remove(1);
+ }
+ else if(i->count >= 2)
+ {
+ // Ignore replacements for items with count >= 2
+ i->remove(1);
+ }
+ }
+}
+
+// Dump an itemstring matrix
+static std::string craftDumpMatrix(const std::vector<std::string> &items,
+ unsigned int width)
+{
+ std::ostringstream os(std::ios::binary);
+ os<<"{ ";
+ unsigned int x = 0;
+ for(std::vector<std::string>::const_iterator
+ i = items.begin();
+ i != items.end(); i++, x++)
+ {
+ if(x == width)
+ {
+ os<<"; ";
+ x = 0;
+ }
+ else if(x != 0)
+ {
+ os<<",";
+ }
+ os<<"\""<<(*i)<<"\"";
+ }
+ os<<" }";
+ return os.str();
+}
+
+// Dump an item matrix
+std::string craftDumpMatrix(const std::vector<ItemStack> &items,
+ unsigned int width)
+{
+ std::ostringstream os(std::ios::binary);
+ os<<"{ ";
+ unsigned int x = 0;
+ for(std::vector<ItemStack>::const_iterator
+ i = items.begin();
+ i != items.end(); i++, x++)
+ {
+ if(x == width)
+ {
+ os<<"; ";
+ x = 0;
+ }
+ else if(x != 0)
+ {
+ os<<",";
}
+ os<<"\""<<(i->getItemString())<<"\"";
}
- return CraftInput(cpi.width, items);
+ os<<" }";
+ return os.str();
}
+
+/*
+ CraftInput
+*/
+
std::string CraftInput::dump() const
{
std::ostringstream os(std::ios::binary);
- os<<"(width="<<width<<"){";
- for(u32 i=0; i<items.size(); i++)
- os<<"\""<<items[i]<<"\",";
- os<<"}";
+ os<<"(method="<<((int)method)<<", items="<<craftDumpMatrix(items, width)<<")";
return os.str();
}
-std::string CraftDefinition::dump() const
+/*
+ CraftOutput
+*/
+
+std::string CraftOutput::dump() const
{
std::ostringstream os(std::ios::binary);
- os<<"{output=\""<<output<<"\", input={";
- for(u32 i=0; i<input.items.size(); i++)
- os<<"\""<<input.items[i]<<"\",";
- os<<"}, (input.width="<<input.width<<")}";
+ os<<"(item=\""<<item<<"\", time="<<time<<")";
return os.str();
}
+/*
+ CraftReplacements
+*/
+std::string CraftReplacements::dump() const
+{
+ std::ostringstream os(std::ios::binary);
+ os<<"{";
+ const char *sep = "";
+ for(std::vector<std::pair<std::string, std::string> >::const_iterator
+ i = pairs.begin();
+ i != pairs.end(); i++)
+ {
+ os<<sep<<"\""<<(i->first)<<"\"=>\""<<(i->second)<<"\"";
+ sep = ",";
+ }
+ os<<"}";
+ return os.str();
+}
+
+
+/*
+ CraftDefinition
+*/
+
void CraftDefinition::serialize(std::ostream &os) const
{
- writeU8(os, 0); // version
- os<<serializeString(output);
- writeU8(os, input.width);
- writeU16(os, input.items.size());
- for(u32 i=0; i<input.items.size(); i++)
- os<<serializeString(input.items[i]);
+ writeU8(os, 1); // version
+ os<<serializeString(getName());
+ serializeBody(os);
}
-void CraftDefinition::deSerialize(std::istream &is)
+CraftDefinition* CraftDefinition::deSerialize(std::istream &is)
{
int version = readU8(is);
- if(version != 0) throw SerializationError(
+ if(version != 1) throw SerializationError(
"unsupported CraftDefinition version");
+ std::string name = deSerializeString(is);
+ CraftDefinition *def = NULL;
+ if(name == "shaped")
+ {
+ def = new CraftDefinitionShaped;
+ }
+ else if(name == "shapeless")
+ {
+ def = new CraftDefinitionShapeless;
+ }
+ else if(name == "toolrepair")
+ {
+ def = new CraftDefinitionToolRepair;
+ }
+ else if(name == "cooking")
+ {
+ def = new CraftDefinitionCooking;
+ }
+ else if(name == "fuel")
+ {
+ def = new CraftDefinitionFuel;
+ }
+ else
+ {
+ infostream<<"Unknown CraftDefinition name=\""<<name<<"\""<<std::endl;
+ throw SerializationError("Unknown CraftDefinition name");
+ }
+ def->deSerializeBody(is, version);
+ return def;
+}
+
+/*
+ CraftDefinitionShaped
+*/
+
+std::string CraftDefinitionShaped::getName() const
+{
+ return "shaped";
+}
+
+bool CraftDefinitionShaped::check(const CraftInput &input, IGameDef *gamedef) const
+{
+ if(input.method != CRAFT_METHOD_NORMAL)
+ return false;
+
+ // Get input item matrix
+ std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
+ unsigned int inp_width = input.width;
+ if(inp_width == 0)
+ return false;
+ while(inp_names.size() % inp_width != 0)
+ inp_names.push_back("");
+
+ // Get input bounds
+ unsigned int inp_min_x=0, inp_max_x=0, inp_min_y=0, inp_max_y=0;
+ if(!craftGetBounds(inp_names, inp_width, inp_min_x, inp_max_x, inp_min_y, inp_max_y))
+ return false; // it was empty
+
+ // Get recipe item matrix
+ std::vector<std::string> rec_names = craftGetItemNames(recipe, gamedef);
+ unsigned int rec_width = width;
+ if(rec_width == 0)
+ return false;
+ while(rec_names.size() % rec_width != 0)
+ rec_names.push_back("");
+
+ // Get recipe bounds
+ unsigned int rec_min_x=0, rec_max_x=0, rec_min_y=0, rec_max_y=0;
+ if(!craftGetBounds(rec_names, rec_width, rec_min_x, rec_max_x, rec_min_y, rec_max_y))
+ return false; // it was empty
+
+ // Different sizes?
+ if(inp_max_x - inp_min_x != rec_max_x - rec_min_x)
+ return false;
+ if(inp_max_y - inp_min_y != rec_max_y - rec_min_y)
+ return false;
+
+ // Verify that all item names in the bounding box are equal
+ unsigned int w = inp_max_x - inp_min_x + 1;
+ unsigned int h = inp_max_y - inp_min_y + 1;
+ for(unsigned int y=0; y<h; y++)
+ for(unsigned int x=0; x<w; x++)
+ {
+ unsigned int inp_x = inp_min_x + x;
+ unsigned int inp_y = inp_min_y + y;
+ unsigned int rec_x = rec_min_x + x;
+ unsigned int rec_y = rec_min_y + y;
+
+ if(
+ inp_names[inp_y * inp_width + inp_x] !=
+ rec_names[rec_y * rec_width + rec_x]
+ ){
+ return false;
+ }
+ }
+
+ return true;
+}
+
+CraftOutput CraftDefinitionShaped::getOutput(const CraftInput &input, IGameDef *gamedef) const
+{
+ return CraftOutput(output, 0);
+}
+
+void CraftDefinitionShaped::decrementInput(CraftInput &input, IGameDef *gamedef) const
+{
+ craftDecrementOrReplaceInput(input, replacements, gamedef);
+}
+
+std::string CraftDefinitionShaped::dump() const
+{
+ std::ostringstream os(std::ios::binary);
+ os<<"(shaped, output=\""<<output
+ <<"\", recipe="<<craftDumpMatrix(recipe, width)
+ <<", replacements="<<replacements.dump()<<")";
+ return os.str();
+}
+
+void CraftDefinitionShaped::serializeBody(std::ostream &os) const
+{
+ os<<serializeString(output);
+ writeU16(os, width);
+ writeU16(os, recipe.size());
+ for(u32 i=0; i<recipe.size(); i++)
+ os<<serializeString(recipe[i]);
+ writeU16(os, replacements.pairs.size());
+ for(u32 i=0; i<replacements.pairs.size(); i++)
+ {
+ os<<serializeString(replacements.pairs[i].first);
+ os<<serializeString(replacements.pairs[i].second);
+ }
+}
+
+void CraftDefinitionShaped::deSerializeBody(std::istream &is, int version)
+{
+ if(version != 1) throw SerializationError(
+ "unsupported CraftDefinitionShaped version");
+ output = deSerializeString(is);
+ width = readU16(is);
+ recipe.clear();
+ u32 count = readU16(is);
+ for(u32 i=0; i<count; i++)
+ recipe.push_back(deSerializeString(is));
+ replacements.pairs.clear();
+ count = readU16(is);
+ for(u32 i=0; i<count; i++)
+ {
+ std::string first = deSerializeString(is);
+ std::string second = deSerializeString(is);
+ replacements.pairs.push_back(std::make_pair(first, second));
+ }
+}
+
+/*
+ CraftDefinitionShapeless
+*/
+
+std::string CraftDefinitionShapeless::getName() const
+{
+ return "shapeless";
+}
+
+bool CraftDefinitionShapeless::check(const CraftInput &input, IGameDef *gamedef) const
+{
+ if(input.method != CRAFT_METHOD_NORMAL)
+ return false;
+
+ // Get input item multiset
+ std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
+ std::multiset<std::string> inp_names_multiset = craftMakeMultiset(inp_names);
+
+ // Get recipe item multiset
+ std::vector<std::string> rec_names = craftGetItemNames(recipe, gamedef);
+ std::multiset<std::string> rec_names_multiset = craftMakeMultiset(rec_names);
+
+ // Recipe is matched when the multisets coincide
+ return inp_names_multiset == rec_names_multiset;
+}
+
+CraftOutput CraftDefinitionShapeless::getOutput(const CraftInput &input, IGameDef *gamedef) const
+{
+ return CraftOutput(output, 0);
+}
+
+void CraftDefinitionShapeless::decrementInput(CraftInput &input, IGameDef *gamedef) const
+{
+ craftDecrementOrReplaceInput(input, replacements, gamedef);
+}
+
+std::string CraftDefinitionShapeless::dump() const
+{
+ std::ostringstream os(std::ios::binary);
+ os<<"(shapeless, output=\""<<output
+ <<"\", recipe="<<craftDumpMatrix(recipe, recipe.size())
+ <<", replacements="<<replacements.dump()<<")";
+ return os.str();
+}
+
+void CraftDefinitionShapeless::serializeBody(std::ostream &os) const
+{
+ os<<serializeString(output);
+ writeU16(os, recipe.size());
+ for(u32 i=0; i<recipe.size(); i++)
+ os<<serializeString(recipe[i]);
+ writeU16(os, replacements.pairs.size());
+ for(u32 i=0; i<replacements.pairs.size(); i++)
+ {
+ os<<serializeString(replacements.pairs[i].first);
+ os<<serializeString(replacements.pairs[i].second);
+ }
+}
+
+void CraftDefinitionShapeless::deSerializeBody(std::istream &is, int version)
+{
+ if(version != 1) throw SerializationError(
+ "unsupported CraftDefinitionShapeless version");
output = deSerializeString(is);
- input.width = readU8(is);
+ recipe.clear();
u32 count = readU16(is);
for(u32 i=0; i<count; i++)
- input.items.push_back(deSerializeString(is));
+ recipe.push_back(deSerializeString(is));
+ replacements.pairs.clear();
+ count = readU16(is);
+ for(u32 i=0; i<count; i++)
+ {
+ std::string first = deSerializeString(is);
+ std::string second = deSerializeString(is);
+ replacements.pairs.push_back(std::make_pair(first, second));
+ }
+}
+
+/*
+ CraftDefinitionToolRepair
+*/
+
+static ItemStack craftToolRepair(
+ const ItemStack &item1,
+ const ItemStack &item2,
+ float additional_wear,
+ IGameDef *gamedef)
+{
+ IItemDefManager *idef = gamedef->idef();
+ if(item1.count != 1 || item2.count != 1 || item1.name != item2.name
+ || idef->get(item1.name).type != ITEM_TOOL
+ || idef->get(item2.name).type != ITEM_TOOL)
+ {
+ // Failure
+ return ItemStack();
+ }
+
+ s32 item1_uses = 65536 - (u32) item1.wear;
+ s32 item2_uses = 65536 - (u32) item2.wear;
+ s32 new_uses = item1_uses + item2_uses;
+ s32 new_wear = 65536 - new_uses + floor(additional_wear * 65536 + 0.5);
+ if(new_wear >= 65536)
+ return ItemStack();
+ if(new_wear < 0)
+ new_wear = 0;
+
+ ItemStack repaired = item1;
+ repaired.wear = new_wear;
+ return repaired;
+}
+
+std::string CraftDefinitionToolRepair::getName() const
+{
+ return "toolrepair";
+}
+
+bool CraftDefinitionToolRepair::check(const CraftInput &input, IGameDef *gamedef) const
+{
+ if(input.method != CRAFT_METHOD_NORMAL)
+ return false;
+
+ ItemStack item1;
+ ItemStack item2;
+ for(std::vector<ItemStack>::const_iterator
+ i = input.items.begin();
+ i != input.items.end(); i++)
+ {
+ if(!i->empty())
+ {
+ if(item1.empty())
+ item1 = *i;
+ else if(item2.empty())
+ item2 = *i;
+ else
+ return false;
+ }
+ }
+ ItemStack repaired = craftToolRepair(item1, item2, additional_wear, gamedef);
+ return !repaired.empty();
+}
+
+CraftOutput CraftDefinitionToolRepair::getOutput(const CraftInput &input, IGameDef *gamedef) const
+{
+ ItemStack item1;
+ ItemStack item2;
+ for(std::vector<ItemStack>::const_iterator
+ i = input.items.begin();
+ i != input.items.end(); i++)
+ {
+ if(!i->empty())
+ {
+ if(item1.empty())
+ item1 = *i;
+ else if(item2.empty())
+ item2 = *i;
+ }
+ }
+ ItemStack repaired = craftToolRepair(item1, item2, additional_wear, gamedef);
+ return CraftOutput(repaired.getItemString(), 0);
+}
+
+void CraftDefinitionToolRepair::decrementInput(CraftInput &input, IGameDef *gamedef) const
+{
+ craftDecrementInput(input, gamedef);
+}
+
+std::string CraftDefinitionToolRepair::dump() const
+{
+ std::ostringstream os(std::ios::binary);
+ os<<"(toolrepair, additional_wear="<<additional_wear<<")";
+ return os.str();
+}
+
+void CraftDefinitionToolRepair::serializeBody(std::ostream &os) const
+{
+ writeF1000(os, additional_wear);
+}
+
+void CraftDefinitionToolRepair::deSerializeBody(std::istream &is, int version)
+{
+ if(version != 1) throw SerializationError(
+ "unsupported CraftDefinitionToolRepair version");
+ additional_wear = readF1000(is);
+}
+
+/*
+ CraftDefinitionCooking
+*/
+
+std::string CraftDefinitionCooking::getName() const
+{
+ return "cooking";
}
+bool CraftDefinitionCooking::check(const CraftInput &input, IGameDef *gamedef) const
+{
+ if(input.method != CRAFT_METHOD_COOKING)
+ return false;
+
+ // Get input item multiset
+ std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
+ std::multiset<std::string> inp_names_multiset = craftMakeMultiset(inp_names);
+
+ // Get recipe item multiset
+ std::multiset<std::string> rec_names_multiset;
+ rec_names_multiset.insert(craftGetItemName(recipe, gamedef));
+
+ // Recipe is matched when the multisets coincide
+ return inp_names_multiset == rec_names_multiset;
+}
+
+CraftOutput CraftDefinitionCooking::getOutput(const CraftInput &input, IGameDef *gamedef) const
+{
+ return CraftOutput(output, cooktime);
+}
+
+void CraftDefinitionCooking::decrementInput(CraftInput &input, IGameDef *gamedef) const
+{
+ craftDecrementInput(input, gamedef);
+}
+
+std::string CraftDefinitionCooking::dump() const
+{
+ std::ostringstream os(std::ios::binary);
+ os<<"(cooking, output=\""<<output
+ <<"\", recipe=\""<<recipe
+ <<"\", cooktime="<<cooktime<<")";
+ return os.str();
+}
+
+void CraftDefinitionCooking::serializeBody(std::ostream &os) const
+{
+ os<<serializeString(output);
+ os<<serializeString(recipe);
+ writeF1000(os, cooktime);
+}
+
+void CraftDefinitionCooking::deSerializeBody(std::istream &is, int version)
+{
+ if(version != 1) throw SerializationError(
+ "unsupported CraftDefinitionCooking version");
+ output = deSerializeString(is);
+ recipe = deSerializeString(is);
+ cooktime = readF1000(is);
+}
+
+/*
+ CraftDefinitionFuel
+*/
+
+std::string CraftDefinitionFuel::getName() const
+{
+ return "fuel";
+}
+
+bool CraftDefinitionFuel::check(const CraftInput &input, IGameDef *gamedef) const
+{
+ if(input.method != CRAFT_METHOD_FUEL)
+ return false;
+
+ // Get input item multiset
+ std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
+ std::multiset<std::string> inp_names_multiset = craftMakeMultiset(inp_names);
+
+ // Get recipe item multiset
+ std::multiset<std::string> rec_names_multiset;
+ rec_names_multiset.insert(craftGetItemName(recipe, gamedef));
+
+ // Recipe is matched when the multisets coincide
+ return inp_names_multiset == rec_names_multiset;
+}
+
+CraftOutput CraftDefinitionFuel::getOutput(const CraftInput &input, IGameDef *gamedef) const
+{
+ return CraftOutput("", burntime);
+}
+
+void CraftDefinitionFuel::decrementInput(CraftInput &input, IGameDef *gamedef) const
+{
+ craftDecrementInput(input, gamedef);
+}
+
+std::string CraftDefinitionFuel::dump() const
+{
+ std::ostringstream os(std::ios::binary);
+ os<<"(fuel, recipe=\""<<recipe
+ <<"\", burntime="<<burntime<<")";
+ return os.str();
+}
+
+void CraftDefinitionFuel::serializeBody(std::ostream &os) const
+{
+ os<<serializeString(recipe);
+ writeF1000(os, burntime);
+}
+
+void CraftDefinitionFuel::deSerializeBody(std::istream &is, int version)
+{
+ if(version != 1) throw SerializationError(
+ "unsupported CraftDefinitionFuel version");
+ recipe = deSerializeString(is);
+ burntime = readF1000(is);
+}
+
+/*
+ Craft definition manager
+*/
+
class CCraftDefManager: public IWritableCraftDefManager
{
public:
@@ -111,58 +761,46 @@ public:
{
clear();
}
- virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
- IGameDef *gamedef) const
+ virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
+ bool decrementInput, IGameDef *gamedef) const
{
- if(input_cpi.width > 3){
- errorstream<<"getCraftResult(): ERROR: "
- <<"input_cpi.width > 3; Failing to craft."<<std::endl;
- return NULL;
- }
- InventoryItem *input_items[9];
- for(u32 y=0; y<3; y++)
- for(u32 x=0; x<3; x++)
+ output.item = "";
+ output.time = 0;
+
+ // If all input items are empty, abort.
+ bool all_empty = true;
+ for(std::vector<ItemStack>::const_iterator
+ i = input.items.begin();
+ i != input.items.end(); i++)
{
- u32 i=y*3+x;
- if(x >= input_cpi.width || y >= input_cpi.height())
- input_items[i] = NULL;
- else
- input_items[i] = input_cpi.items[y*input_cpi.width+x];
+ if(!i->empty())
+ {
+ all_empty = false;
+ break;
+ }
}
- for(core::list<CraftDefinition*>::ConstIterator
- i = m_craft_definitions.begin();
- i != m_craft_definitions.end(); i++)
+ if(all_empty)
+ return false;
+
+ // Walk crafting definitions from back to front, so that later
+ // definitions can override earlier ones.
+ for(std::vector<CraftDefinition*>::const_reverse_iterator
+ i = m_craft_definitions.rbegin();
+ i != m_craft_definitions.rend(); i++)
{
CraftDefinition *def = *i;
- /*infostream<<"Checking "<<createInput(input_cpi).dump()<<std::endl
- <<" against "<<def->input.dump()
- <<" (output=\""<<def->output<<"\")"<<std::endl;*/
+ /*infostream<<"Checking "<<input.dump()<<std::endl
+ <<" against "<<def->dump()<<std::endl;*/
try {
- CraftPointerInput spec_cpi = createPointerInput(def->input, gamedef);
- if(spec_cpi.width > 3){
- errorstream<<"getCraftResult: ERROR: "
- <<"spec_cpi.width > 3 in recipe "
- <<def->dump()<<std::endl;
- continue;
- }
- InventoryItem *spec_items[9];
- for(u32 y=0; y<3; y++)
- for(u32 x=0; x<3; x++)
+ if(def->check(input, gamedef))
{
- u32 i=y*3+x;
- if(x >= spec_cpi.width || y >= spec_cpi.height())
- spec_items[i] = NULL;
- else
- spec_items[i] = spec_cpi.items[y*spec_cpi.width+x];
- }
-
- bool match = checkItemCombination(input_items, spec_items);
-
- if(match){
- std::istringstream iss(def->output, std::ios::binary);
- return InventoryItem::deSerialize(iss, gamedef);
+ // Get output, then decrement input (if requested)
+ output = def->getOutput(input, gamedef);
+ if(decrementInput)
+ def->decrementInput(input, gamedef);
+ return true;
}
}
catch(SerializationError &e)
@@ -173,34 +811,41 @@ public:
// then go on with the next craft definition
}
}
- return NULL;
+ return false;
}
- virtual void registerCraft(const CraftDefinition &def)
+ virtual std::string dump() const
{
- infostream<<"registerCraft: registering craft definition: "
- <<def.dump()<<std::endl;
- if(def.input.width > 3 || def.input.height() > 3){
- errorstream<<"registerCraft: input size is larger than 3x3,"
- <<" ignoring"<<std::endl;
- return;
+ std::ostringstream os(std::ios::binary);
+ os<<"Crafting definitions:\n";
+ for(std::vector<CraftDefinition*>::const_iterator
+ i = m_craft_definitions.begin();
+ i != m_craft_definitions.end(); i++)
+ {
+ os<<(*i)->dump()<<"\n";
}
- m_craft_definitions.push_back(new CraftDefinition(def));
+ return os.str();
+ }
+ virtual void registerCraft(CraftDefinition *def)
+ {
+ infostream<<"registerCraft: registering craft definition: "
+ <<def->dump()<<std::endl;
+ m_craft_definitions.push_back(def);
}
virtual void clear()
{
- for(core::list<CraftDefinition*>::Iterator
+ for(std::vector<CraftDefinition*>::iterator
i = m_craft_definitions.begin();
i != m_craft_definitions.end(); i++){
delete *i;
}
m_craft_definitions.clear();
}
- virtual void serialize(std::ostream &os)
+ virtual void serialize(std::ostream &os) const
{
writeU8(os, 0); // version
u16 count = m_craft_definitions.size();
writeU16(os, count);
- for(core::list<CraftDefinition*>::Iterator
+ for(std::vector<CraftDefinition*>::const_iterator
i = m_craft_definitions.begin();
i != m_craft_definitions.end(); i++){
CraftDefinition *def = *i;
@@ -222,14 +867,13 @@ public:
for(u16 i=0; i<count; i++){
// Deserialize a string and grab a CraftDefinition from it
std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
- CraftDefinition def;
- def.deSerialize(tmp_is);
+ CraftDefinition *def = CraftDefinition::deSerialize(tmp_is);
// Register
registerCraft(def);
}
}
private:
- core::list<CraftDefinition*> m_craft_definitions;
+ std::vector<CraftDefinition*> m_craft_definitions;
};
IWritableCraftDefManager* createCraftDefManager()
diff --git a/src/craftdef.h b/src/craftdef.h
index cfd58ad10..57f26f049 100644
--- a/src/craftdef.h
+++ b/src/craftdef.h
@@ -23,71 +23,328 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include <iostream>
#include <vector>
-class IGameDef;
-class InventoryItem;
+#include <utility>
+#include "gamedef.h"
+#include "inventory.h"
-struct CraftPointerInput
+/*
+ Crafting methods.
+
+ The crafting method depends on the inventory list
+ that the crafting input comes from.
+*/
+enum CraftMethod
+{
+ // Crafting grid
+ CRAFT_METHOD_NORMAL,
+ // Cooking something in a furnace
+ CRAFT_METHOD_COOKING,
+ // Using something as fuel for a furnace
+ CRAFT_METHOD_FUEL,
+};
+
+/*
+ Input: The contents of the crafting slots, arranged in matrix form
+*/
+struct CraftInput
{
+ CraftMethod method;
unsigned int width;
- std::vector<InventoryItem*> items;
+ std::vector<ItemStack> items;
- CraftPointerInput(unsigned int width_, const std::vector<InventoryItem*> &items_):
- width(width_),
- items(items_)
+ CraftInput():
+ method(CRAFT_METHOD_NORMAL), width(0), items()
{}
- CraftPointerInput():
- width(0)
+ CraftInput(CraftMethod method_, unsigned int width_,
+ const std::vector<ItemStack> &items_):
+ method(method_), width(width_), items(items_)
{}
- ~CraftPointerInput();
- unsigned int height() const{
- return (items.size() + width - 1) / width;
- }
+ std::string dump() const;
};
-struct CraftInput
+/*
+ Output: Result of crafting operation
+*/
+struct CraftOutput
{
- unsigned int width;
- std::vector<std::string> items;
+ // Used for normal crafting and cooking, itemstring
+ std::string item;
+ // Used for cooking (cook time) and fuel (burn time), seconds
+ float time;
- CraftInput(unsigned int width_, const std::vector<std::string> &items_):
- width(width_),
- items(items_)
+ CraftOutput():
+ item(""), time(0)
{}
- CraftInput():
- width(0)
+ CraftOutput(std::string item_, float time_):
+ item(item_), time(time_)
{}
- unsigned int height() const{
- return (items.size() + width - 1) / width;
- }
std::string dump() const;
};
-struct CraftDefinition
+/*
+ A list of replacements. A replacement indicates that a specific
+ input item should not be deleted (when crafting) but replaced with
+ a different item. Each replacements is a pair (itemstring to remove,
+ itemstring to replace with)
+
+ Example: If ("bucket:bucket_water", "bucket:bucket_empty") is a
+ replacement pair, the crafting input slot that contained a water
+ bucket will contain an empty bucket after crafting.
+
+ Note: replacements only work correctly when stack_max of the item
+ to be replaced is 1. It is up to the mod writer to ensure this.
+*/
+struct CraftReplacements
{
- std::string output;
- CraftInput input;
+ // List of replacements
+ std::vector<std::pair<std::string, std::string> > pairs;
- CraftDefinition(){}
- CraftDefinition(const std::string &output_, unsigned int width_,
- const std::vector<std::string> &input_):
- output(output_),
- input(width_, input_)
+ CraftReplacements():
+ pairs()
+ {}
+ CraftReplacements(std::vector<std::pair<std::string, std::string> > pairs_):
+ pairs(pairs_)
{}
-
std::string dump() const;
+};
+
+/*
+ Crafting definition base class
+*/
+class CraftDefinition
+{
+public:
+ CraftDefinition(){}
+ virtual ~CraftDefinition(){}
+
void serialize(std::ostream &os) const;
- void deSerialize(std::istream &is);
+ static CraftDefinition* deSerialize(std::istream &is);
+
+ // Returns type of crafting definition
+ virtual std::string getName() const=0;
+
+ // Checks whether the recipe is applicable
+ virtual bool check(const CraftInput &input, IGameDef *gamedef) const=0;
+ // Returns the output structure, meaning depends on crafting method
+ // The implementation can assume that check(input) returns true
+ virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const=0;
+ // Decreases count of every input item
+ virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const=0;
+
+ virtual std::string dump() const=0;
+
+protected:
+ virtual void serializeBody(std::ostream &os) const=0;
+ virtual void deSerializeBody(std::istream &is, int version)=0;
+};
+
+/*
+ A plain-jane (shaped) crafting definition
+
+ Supported crafting method: CRAFT_METHOD_NORMAL.
+ Requires the input items to be arranged exactly like in the recipe.
+*/
+class CraftDefinitionShaped: public CraftDefinition
+{
+public:
+ CraftDefinitionShaped():
+ output(""), width(1), recipe(), replacements()
+ {}
+ CraftDefinitionShaped(
+ const std::string &output_,
+ unsigned int width_,
+ const std::vector<std::string> &recipe_,
+ const CraftReplacements &replacements_):
+ output(output_), width(width_), recipe(recipe_), replacements(replacements_)
+ {}
+ virtual ~CraftDefinitionShaped(){}
+
+ virtual std::string getName() const;
+ virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
+ virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+ virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
+
+ virtual std::string dump() const;
+
+protected:
+ virtual void serializeBody(std::ostream &os) const;
+ virtual void deSerializeBody(std::istream &is, int version);
+
+private:
+ // Output itemstring
+ std::string output;
+ // Width of recipe
+ unsigned int width;
+ // Recipe matrix (itemstrings)
+ std::vector<std::string> recipe;
+ // Replacement items for decrementInput()
+ CraftReplacements replacements;
+};
+
+/*
+ A shapeless crafting definition
+ Supported crafting method: CRAFT_METHOD_NORMAL.
+ Input items can arranged in any way.
+*/
+class CraftDefinitionShapeless: public CraftDefinition
+{
+public:
+ CraftDefinitionShapeless():
+ output(""), recipe(), replacements()
+ {}
+ CraftDefinitionShapeless(
+ const std::string &output_,
+ const std::vector<std::string> &recipe_,
+ const CraftReplacements &replacements_):
+ output(output_), recipe(recipe_), replacements(replacements_)
+ {}
+ virtual ~CraftDefinitionShapeless(){}
+
+ virtual std::string getName() const;
+ virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
+ virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+ virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
+
+ virtual std::string dump() const;
+
+protected:
+ virtual void serializeBody(std::ostream &os) const;
+ virtual void deSerializeBody(std::istream &is, int version);
+
+private:
+ // Output itemstring
+ std::string output;
+ // Recipe list (itemstrings)
+ std::vector<std::string> recipe;
+ // Replacement items for decrementInput()
+ CraftReplacements replacements;
+};
+
+/*
+ Tool repair crafting definition
+ Supported crafting method: CRAFT_METHOD_NORMAL.
+ Put two damaged tools into the crafting grid, get one tool back.
+ There should only be one crafting definition of this type.
+*/
+class CraftDefinitionToolRepair: public CraftDefinition
+{
+public:
+ CraftDefinitionToolRepair():
+ additional_wear(0)
+ {}
+ CraftDefinitionToolRepair(float additional_wear_):
+ additional_wear(additional_wear_)
+ {}
+ virtual ~CraftDefinitionToolRepair(){}
+
+ virtual std::string getName() const;
+ virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
+ virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+ virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
+
+ virtual std::string dump() const;
+
+protected:
+ virtual void serializeBody(std::ostream &os) const;
+ virtual void deSerializeBody(std::istream &is, int version);
+
+private:
+ // This is a constant that is added to the wear of the result.
+ // May be positive or negative, allowed range [-1,1].
+ // 1 = new tool is completely broken
+ // 0 = simply add remaining uses of both input tools
+ // -1 = new tool is completely pristine
+ float additional_wear;
+};
+
+/*
+ A cooking (in furnace) definition
+ Supported crafting method: CRAFT_METHOD_COOKING.
+*/
+class CraftDefinitionCooking: public CraftDefinition
+{
+public:
+ CraftDefinitionCooking():
+ output(""), recipe(""), cooktime()
+ {}
+ CraftDefinitionCooking(
+ const std::string &output_,
+ const std::string &recipe_,
+ float cooktime_):
+ output(output_), recipe(recipe_), cooktime(cooktime_)
+ {}
+ virtual ~CraftDefinitionCooking(){}
+
+ virtual std::string getName() const;
+ virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
+ virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+ virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
+
+ virtual std::string dump() const;
+
+protected:
+ virtual void serializeBody(std::ostream &os) const;
+ virtual void deSerializeBody(std::istream &is, int version);
+
+private:
+ // Output itemstring
+ std::string output;
+ // Recipe itemstring
+ std::string recipe;
+ // Time in seconds
+ float cooktime;
};
+/*
+ A fuel (for furnace) definition
+ Supported crafting method: CRAFT_METHOD_FUEL.
+*/
+class CraftDefinitionFuel: public CraftDefinition
+{
+public:
+ CraftDefinitionFuel():
+ recipe(""), burntime()
+ {}
+ CraftDefinitionFuel(std::string recipe_, float burntime_):
+ recipe(recipe_), burntime(burntime_)
+ {}
+ virtual ~CraftDefinitionFuel(){}
+
+ virtual std::string getName() const;
+ virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
+ virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+ virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
+
+ virtual std::string dump() const;
+
+protected:
+ virtual void serializeBody(std::ostream &os) const;
+ virtual void deSerializeBody(std::istream &is, int version);
+
+private:
+ // Recipe itemstring
+ std::string recipe;
+ // Time in seconds
+ float burntime;
+};
+
+/*
+ Crafting definition manager
+*/
class ICraftDefManager
{
public:
ICraftDefManager(){}
virtual ~ICraftDefManager(){}
- virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
- IGameDef *gamedef) const=0;
+
+ // The main crafting function
+ virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
+ bool decrementInput, IGameDef *gamedef) const=0;
- virtual void serialize(std::ostream &os)=0;
+ // Print crafting recipes for debugging
+ virtual std::string dump() const=0;
+
+ virtual void serialize(std::ostream &os) const=0;
};
class IWritableCraftDefManager : public ICraftDefManager
@@ -95,13 +352,21 @@ class IWritableCraftDefManager : public ICraftDefManager
public:
IWritableCraftDefManager(){}
virtual ~IWritableCraftDefManager(){}
- virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
- IGameDef *gamedef) const=0;
-
- virtual void registerCraft(const CraftDefinition &def)=0;
+
+ // The main crafting function
+ virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
+ bool decrementInput, IGameDef *gamedef) const=0;
+
+ // Print crafting recipes for debugging
+ virtual std::string dump() const=0;
+
+ // Add a crafting definition.
+ // After calling this, the pointer belongs to the manager.
+ virtual void registerCraft(CraftDefinition *def)=0;
+ // Delete all crafting definitions
virtual void clear()=0;
- virtual void serialize(std::ostream &os)=0;
+ virtual void serialize(std::ostream &os) const=0;
virtual void deSerialize(std::istream &is)=0;
};
diff --git a/src/craftitemdef.cpp b/src/craftitemdef.cpp
deleted file mode 100644
index 4461e38a7..000000000
--- a/src/craftitemdef.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
-Minetest-c55
-Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
-Copyright (C) 2011 Kahrl <kahrl@gmx.net>
-
-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 "craftitemdef.h"
-#include "irrlichttypes.h"
-#include "log.h"
-#include <sstream>
-#include "utility.h"
-#include <map>
-
-CraftItemDefinition::CraftItemDefinition():
- imagename(""),
- cookresult_item(""),
- furnace_cooktime(3.0),
- furnace_burntime(-1.0),
- usable(false),
- liquids_pointable(false),
- dropcount(-1),
- stack_max(99)
-{}
-
-std::string CraftItemDefinition::dump()
-{
- std::ostringstream os(std::ios::binary);
- os<<"imagename="<<imagename;
- os<<", cookresult_item="<<cookresult_item;
- os<<", furnace_cooktime="<<furnace_cooktime;
- os<<", furnace_burntime="<<furnace_burntime;
- os<<", usable="<<usable;
- os<<", liquids_pointable="<<liquids_pointable;
- os<<", dropcount="<<dropcount;
- os<<", stack_max="<<stack_max;
- return os.str();
-}
-
-void CraftItemDefinition::serialize(std::ostream &os)
-{
- writeU8(os, 0); // version
- os<<serializeString(imagename);
- os<<serializeString(cookresult_item);
- writeF1000(os, furnace_cooktime);
- writeF1000(os, furnace_burntime);
- writeU8(os, usable);
- writeU8(os, liquids_pointable);
- writeS16(os, dropcount);
- writeS16(os, stack_max);
-}
-
-void CraftItemDefinition::deSerialize(std::istream &is)
-{
- int version = readU8(is);
- if(version != 0) throw SerializationError(
- "unsupported CraftItemDefinition version");
- imagename = deSerializeString(is);
- cookresult_item = deSerializeString(is);
- furnace_cooktime = readF1000(is);
- furnace_burntime = readF1000(is);
- usable = readU8(is);
- liquids_pointable = readU8(is);
- dropcount = readS16(is);
- stack_max = readS16(is);
-}
-
-class CCraftItemDefManager: public IWritableCraftItemDefManager
-{
-public:
- virtual ~CCraftItemDefManager()
- {
- clear();
- }
- virtual const CraftItemDefinition* getCraftItemDefinition(const std::string &itemname_) const
- {
- // Convert name according to possible alias
- std::string itemname = getAlias(itemname_);
- // Get the definition
- core::map<std::string, CraftItemDefinition*>::Node *n;
- n = m_item_definitions.find(itemname);
- if(n == NULL)
- return NULL;
- return n->getValue();
- }
- virtual std::string getImagename(const std::string &itemname) const
- {
- const CraftItemDefinition *def = getCraftItemDefinition(itemname);
- if(def == NULL)
- return "";
- return def->imagename;
- }
- virtual std::string getAlias(const std::string &name) const
- {
- std::map<std::string, std::string>::const_iterator i;
- i = m_aliases.find(name);
- if(i != m_aliases.end())
- return i->second;
- return name;
- }
- virtual bool registerCraftItem(std::string itemname, const CraftItemDefinition &def)
- {
- infostream<<"registerCraftItem: registering CraftItem \""<<itemname<<"\""<<std::endl;
- m_item_definitions[itemname] = new CraftItemDefinition(def);
-
- // Remove conflicting alias if it exists
- bool alias_removed = (m_aliases.erase(itemname) != 0);
- if(alias_removed)
- infostream<<"cidef: erased alias "<<itemname
- <<" because item was defined"<<std::endl;
-
- return true;
- }
- virtual void clear()
- {
- for(core::map<std::string, CraftItemDefinition*>::Iterator
- i = m_item_definitions.getIterator();
- i.atEnd() == false; i++){
- delete i.getNode()->getValue();
- }
- m_item_definitions.clear();
- m_aliases.clear();
- }
- virtual void setAlias(const std::string &name,
- const std::string &convert_to)
- {
- if(getCraftItemDefinition(name) != NULL){
- infostream<<"nidef: not setting alias "<<name<<" -> "<<convert_to
- <<": "<<name<<" is already defined"<<std::endl;
- return;
- }
- infostream<<"nidef: setting alias "<<name<<" -> "<<convert_to
- <<std::endl;
- m_aliases[name] = convert_to;
- }
- virtual void serialize(std::ostream &os)
- {
- writeU8(os, 0); // version
- u16 count = m_item_definitions.size();
- writeU16(os, count);
- for(core::map<std::string, CraftItemDefinition*>::Iterator
- i = m_item_definitions.getIterator();
- i.atEnd() == false; i++){
- std::string name = i.getNode()->getKey();
- CraftItemDefinition *def = i.getNode()->getValue();
- // Serialize name
- os<<serializeString(name);
- // Serialize CraftItemDefinition and write wrapped in a string
- std::ostringstream tmp_os(std::ios::binary);
- def->serialize(tmp_os);
- os<<serializeString(tmp_os.str());
- }
-
- writeU16(os, m_aliases.size());
- for(std::map<std::string, std::string>::const_iterator
- i = m_aliases.begin(); i != m_aliases.end(); i++)
- {
- os<<serializeString(i->first);
- os<<serializeString(i->second);
- }
- }
- virtual void deSerialize(std::istream &is)
- {
- // Clear everything
- clear();
- // Deserialize
- int version = readU8(is);
- if(version != 0) throw SerializationError(
- "unsupported CraftItemDefManager version");
- u16 count = readU16(is);
- for(u16 i=0; i<count; i++){
- // Deserialize name
- std::string name = deSerializeString(is);
- // Deserialize a string and grab a CraftItemDefinition from it
- std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
- CraftItemDefinition def;
- def.deSerialize(tmp_is);
- // Register
- registerCraftItem(name, def);
- }
-
- u16 num_aliases = readU16(is);
- if(!is.eof()){
- for(u16 i=0; i<num_aliases; i++){
- std::string name = deSerializeString(is);
- std::string convert_to = deSerializeString(is);
- m_aliases[name] = convert_to;
- }
- }
- }
-private:
- // Key is name
- core::map<std::string, CraftItemDefinition*> m_item_definitions;
- // Aliases
- std::map<std::string, std::string> m_aliases;
-};
-
-IWritableCraftItemDefManager* createCraftItemDefManager()
-{
- return new CCraftItemDefManager();
-}
diff --git a/src/craftitemdef.h b/src/craftitemdef.h
deleted file mode 100644
index b5d4b9348..000000000
--- a/src/craftitemdef.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
-Minetest-c55
-Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
-Copyright (C) 2011 Kahrl <kahrl@gmx.net>
-
-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 CRAFTITEMDEF_HEADER
-#define CRAFTITEMDEF_HEADER
-
-#include "common_irrlicht.h"
-#include <string>
-#include <iostream>
-
-struct CraftItemDefinition
-{
- std::string imagename;
- std::string cookresult_item;
- float furnace_cooktime;
- float furnace_burntime;
- bool usable;
- bool liquids_pointable;
- s16 dropcount;
- s16 stack_max;
-
- CraftItemDefinition();
- std::string dump();
- void serialize(std::ostream &os);
- void deSerialize(std::istream &is);
-};
-
-class ICraftItemDefManager
-{
-public:
- ICraftItemDefManager(){}
- virtual ~ICraftItemDefManager(){}
- virtual const CraftItemDefinition* getCraftItemDefinition(const std::string &itemname) const=0;
- virtual std::string getImagename(const std::string &itemname) const =0;
- virtual std::string getAlias(const std::string &name) const =0;
-
- virtual void serialize(std::ostream &os)=0;
-};
-
-class IWritableCraftItemDefManager : public ICraftItemDefManager
-{
-public:
- IWritableCraftItemDefManager(){}
- virtual ~IWritableCraftItemDefManager(){}
- virtual const CraftItemDefinition* getCraftItemDefinition(const std::string &itemname) const=0;
- virtual std::string getImagename(const std::string &itemname) const =0;
-
- virtual bool registerCraftItem(std::string itemname, const CraftItemDefinition &def)=0;
- virtual void clear()=0;
- // Set an alias so that entries named <name> will load as <convert_to>.
- // Alias is not set if <name> has already been defined.
- // Alias will be removed if <name> is defined at a later point of time.
- virtual void setAlias(const std::string &name,
- const std::string &convert_to)=0;
-
- virtual void serialize(std::ostream &os)=0;
- virtual void deSerialize(std::istream &is)=0;
-};
-
-IWritableCraftItemDefManager* createCraftItemDefManager();
-
-#endif
diff --git a/src/environment.h b/src/environment.h
index beb49885c..89c9fd676 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "activeobject.h"
class Server;
+class ServerEnvironment;
class ActiveBlockModifier;
class ServerActiveObject;
typedef struct lua_State lua_State;
diff --git a/src/game.cpp b/src/game.cpp
index 0d08074ad..7bd5d9587 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -40,7 +40,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "profiler.h"
#include "mainmenumanager.h"
-#include "craftitemdef.h"
#include "gettext.h"
#include "log.h"
#include "filesys.h"
@@ -48,7 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "nodemetadata.h"
#include "main.h" // For g_settings
-#include "tooldef.h"
+#include "itemdef.h"
#include "tile.h" // For TextureSource
#include "logoutputbuffer.h"
@@ -80,15 +79,6 @@ struct ChatLine
};
/*
- Inventory stuff
-*/
-
-// Inventory actions from the menu are buffered here before sending
-Queue<InventoryAction*> inventory_action_queue;
-// This is a copy of the inventory that the client's environment has
-Inventory local_inventory;
-
-/*
Text input system
*/
@@ -156,7 +146,7 @@ private:
Hotbar draw routine
*/
void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
- ITextureSource *tsrc,
+ IGameDef *gamedef,
v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
Inventory *inventory, s32 halfheartcount, u16 playeritem)
{
@@ -184,7 +174,7 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
for(s32 i=0; i<itemcount; i++)
{
- InventoryItem *item = mainlist->getItem(i);
+ const ItemStack &item = mainlist->getItem(i);
core::rect<s32> rect = imgrect + pos
+ v2s32(padding+i*(imgsize+padding*2), padding);
@@ -245,17 +235,14 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
video::SColor bgcolor2(128,0,0,0);
driver->draw2DRectangle(bgcolor2, rect, NULL);
-
- if(item != NULL)
- {
- drawInventoryItem(driver, font, item, rect, NULL, tsrc);
- }
+ drawItemStack(driver, font, item, rect, NULL, gamedef);
}
/*
Draw hearts
*/
- video::ITexture *heart_texture = tsrc->getTextureRaw("heart.png");
+ video::ITexture *heart_texture =
+ gamedef->getTextureSource()->getTextureRaw("heart.png");
if(heart_texture)
{
v2s32 p = pos + v2s32(0, -20);
@@ -691,12 +678,10 @@ void the_game(
IWritableTextureSource *tsrc = createTextureSource(device);
// These will be filled by data received from the server
- // Create tool definition manager
- IWritableToolDefManager *tooldef = createToolDefManager();
+ // Create item definition manager
+ IWritableItemDefManager *itemdef = createItemDefManager();
// Create node definition manager
IWritableNodeDefManager *nodedef = createNodeDefManager();
- // Create CraftItem definition manager
- IWritableCraftItemDefManager *craftitemdef = createCraftItemDefManager();
// Add chat log output for errors to be shown in chat
LogOutputBuffer chat_log_error_buf(LMT_ERROR);
@@ -725,7 +710,7 @@ void the_game(
MapDrawControl draw_control;
Client client(device, playername.c_str(), password, draw_control,
- tsrc, tooldef, nodedef, craftitemdef);
+ tsrc, itemdef, nodedef);
// Client acts as our GameDef
IGameDef *gamedef = &client;
@@ -835,9 +820,8 @@ void the_game(
// End condition
if(client.texturesReceived() &&
- client.tooldefReceived() &&
- client.nodedefReceived() &&
- client.craftitemdefReceived()){
+ client.itemdefReceived() &&
+ client.nodedefReceived()){
got_content = true;
break;
}
@@ -853,12 +837,10 @@ void the_game(
ss<<(int)(timeout - time_counter + 1.0);
ss<<L" seconds)\n";
- ss<<(client.tooldefReceived()?L"[X]":L"[ ]");
- ss<<L" Tool definitions\n";
+ ss<<(client.itemdefReceived()?L"[X]":L"[ ]");
+ ss<<L" Item definitions\n";
ss<<(client.nodedefReceived()?L"[X]":L"[ ]");
ss<<L" Node definitions\n";
- ss<<(client.craftitemdefReceived()?L"[X]":L"[ ]");
- ss<<L" Item definitions\n";
//ss<<(client.texturesReceived()?L"[X]":L"[ ]");
ss<<L"["<<(int)(client.textureReceiveProgress()*100+0.5)<<L"%] ";
ss<<L" Textures\n";
@@ -872,6 +854,12 @@ void the_game(
}
/*
+ After all content has been received:
+ Update cached textures, meshes and materials
+ */
+ client.afterContentReceived();
+
+ /*
Create skybox
*/
float old_brightness = 1.0;
@@ -911,6 +899,11 @@ void the_game(
}
/*
+ A copy of the local inventory
+ */
+ Inventory local_inventory(itemdef);
+
+ /*
Move into game
*/
@@ -1289,7 +1282,7 @@ void the_game(
// drop selected item
IDropAction *a = new IDropAction();
a->count = 0;
- a->from_inv = "current_player";
+ a->from_inv.setCurrentPlayer();
a->from_list = "main";
a->from_i = client.getPlayerItem();
client.inventoryAction(a);
@@ -1302,18 +1295,20 @@ void the_game(
GUIInventoryMenu *menu =
new GUIInventoryMenu(guienv, guiroot, -1,
&g_menumgr, v2s16(8,7),
- client.getInventoryContext(),
- &client, tsrc);
+ &client, gamedef);
+
+ InventoryLocation inventoryloc;
+ inventoryloc.setCurrentPlayer();
core::array<GUIInventoryMenu::DrawSpec> draw_spec;
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
- "list", "current_player", "main",
+ "list", inventoryloc, "main",
v2s32(0, 3), v2s32(8, 4)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
- "list", "current_player", "craft",
+ "list", inventoryloc, "craft",
v2s32(3, 0), v2s32(3, 3)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
- "list", "current_player", "craftresult",
+ "list", inventoryloc, "craftresult",
v2s32(7, 1), v2s32(1, 1)));
menu->setDrawSpec(draw_spec);
@@ -1691,31 +1686,20 @@ void the_game(
/*
For interaction purposes, get info about the held item
- - Is it a tool, and what is the toolname?
+ - What item is it?
- Is it a usable item?
- Can it point to liquids?
*/
- std::string playeritem_toolname = "";
+ ItemStack playeritem;
bool playeritem_usable = false;
bool playeritem_liquids_pointable = false;
{
InventoryList *mlist = local_inventory.getList("main");
if(mlist != NULL)
{
- InventoryItem *item = mlist->getItem(client.getPlayerItem());
- if(item)
- {
- if((std::string)item->getName() == "ToolItem")
- {
- ToolItem *titem = (ToolItem*)item;
- playeritem_toolname = titem->getToolName();
- }
-
- playeritem_usable = item->isUsable();
-
- playeritem_liquids_pointable =
- item->areLiquidsPointable();
- }
+ playeritem = mlist->getItem(client.getPlayerItem());
+ playeritem_usable = playeritem.getDefinition(itemdef).usable;
+ playeritem_liquids_pointable = playeritem.getDefinition(itemdef).liquids_pointable;
}
}
@@ -1845,7 +1829,7 @@ void the_game(
// Get digging properties for material and tool
content_t material = n.getContent();
ToolDiggingProperties tp =
- tooldef->getDiggingProperties(playeritem_toolname);
+ playeritem.getToolDiggingProperties(itemdef);
DiggingProperties prop =
getDiggingProperties(material, &tp, nodedef);
@@ -1853,9 +1837,6 @@ void the_game(
if(prop.diggable == false)
{
- /*infostream<<"Material "<<(int)material
- <<" not diggable with \""
- <<playeritem_toolname<<"\""<<std::endl;*/
// I guess nobody will wait for this long
dig_time_complete = 10000000.0;
}
@@ -1922,17 +1903,11 @@ void the_game(
if(meta && meta->getInventoryDrawSpecString() != "" && !random_input)
{
infostream<<"Launching custom inventory view"<<std::endl;
- /*
- Construct the unique identification string of the node
- */
- std::string current_name;
- current_name += "nodemeta:";
- current_name += itos(nodepos.X);
- current_name += ",";
- current_name += itos(nodepos.Y);
- current_name += ",";
- current_name += itos(nodepos.Z);
+
+ InventoryLocation inventoryloc;
+ inventoryloc.setNodeMeta(nodepos);
+
/*
Create menu
*/
@@ -1942,13 +1917,12 @@ void the_game(
GUIInventoryMenu::makeDrawSpecArrayFromString(
draw_spec,
meta->getInventoryDrawSpecString(),
- current_name);
+ inventoryloc);
GUIInventoryMenu *menu =
new GUIInventoryMenu(guienv, guiroot, -1,
&g_menumgr, invsize,
- client.getInventoryContext(),
- &client, tsrc);
+ &client, gamedef);
menu->setDrawSpec(draw_spec);
menu->drop();
}
@@ -2001,7 +1975,7 @@ void the_game(
v3f objpos = selected_object->getPosition();
v3f dir = (objpos - player_position).normalize();
- bool disable_send = selected_object->directReportPunch(playeritem_toolname, dir);
+ bool disable_send = selected_object->directReportPunch(playeritem.name, dir);
if(!disable_send)
client.interact(0, pointed);
}
@@ -2285,25 +2259,13 @@ void the_game(
update_wielded_item_trigger = false;
// Update wielded tool
InventoryList *mlist = local_inventory.getList("main");
- InventoryItem *item = NULL;
+ ItemStack item;
if(mlist != NULL)
item = mlist->getItem(client.getPlayerItem());
camera.wield(item, gamedef);
}
/*
- Send actions returned by the inventory menu
- */
- while(inventory_action_queue.size() != 0)
- {
- InventoryAction *a = inventory_action_queue.pop_front();
-
- client.sendInventoryAction(a);
- // Eat it
- delete a;
- }
-
- /*
Drawing begins
*/
@@ -2411,7 +2373,7 @@ void the_game(
Draw hotbar
*/
{
- draw_hotbar(driver, font, tsrc,
+ draw_hotbar(driver, font, gamedef,
v2s32(displaycenter.X, screensize.Y),
hotbar_imagesize, hotbar_itemcount, &local_inventory,
client.getHP(), client.getPlayerItem());
@@ -2482,9 +2444,9 @@ void the_game(
} // Client scope (must be destructed before destructing *def and tsrc
- delete tooldef;
delete tsrc;
delete nodedef;
+ delete itemdef;
}
diff --git a/src/gamedef.h b/src/gamedef.h
index c450568b7..8df6988ad 100644
--- a/src/gamedef.h
+++ b/src/gamedef.h
@@ -21,11 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define GAMEDEF_HEADER
#include <string>
+#include "irrlichttypes.h"
-class IToolDefManager;
+class IItemDefManager;
class INodeDefManager;
class ICraftDefManager;
-class ICraftItemDefManager;
// Mineral too?
class ITextureSource;
@@ -39,10 +39,9 @@ class IGameDef
public:
// These are thread-safe IF they are not edited while running threads.
// Thus, first they are set up and then they are only read.
- virtual IToolDefManager* getToolDefManager()=0;
+ virtual IItemDefManager* getItemDefManager()=0;
virtual INodeDefManager* getNodeDefManager()=0;
virtual ICraftDefManager* getCraftDefManager()=0;
- virtual ICraftItemDefManager* getCraftItemDefManager()=0;
// This is always thread-safe, but referencing the irrlicht texture
// pointers in other threads than main thread will make things explode.
@@ -52,10 +51,9 @@ public:
virtual u16 allocateUnknownNodeId(const std::string &name)=0;
// Shorthands
- IToolDefManager* tdef(){return getToolDefManager();}
+ IItemDefManager* idef(){return getItemDefManager();}
INodeDefManager* ndef(){return getNodeDefManager();}
ICraftDefManager* cdef(){return getCraftDefManager();}
- ICraftItemDefManager* cidef(){return getCraftItemDefManager();}
ITextureSource* tsrc(){return getTextureSource();}
};
diff --git a/src/guiInventoryMenu.cpp b/src/guiInventoryMenu.cpp
index 552e10db2..9b2aed377 100644
--- a/src/guiInventoryMenu.cpp
+++ b/src/guiInventoryMenu.cpp
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiInventoryMenu.h"
#include "constants.h"
+#include "gamedef.h"
#include "keycode.h"
#include "strfnd.h"
#include <IGUICheckBox.h>
@@ -28,20 +29,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "log.h"
-#include "inventorymanager.h"
-void drawInventoryItem(video::IVideoDriver *driver,
+void drawItemStack(video::IVideoDriver *driver,
gui::IGUIFont *font,
- InventoryItem *item, core::rect<s32> rect,
+ const ItemStack &item,
+ const core::rect<s32> &rect,
const core::rect<s32> *clip,
- ITextureSource *tsrc)
+ IGameDef *gamedef)
{
- if(item == NULL)
+ if(item.empty())
return;
- video::ITexture *texture = NULL;
- texture = item->getImage();
+ const ItemDefinition &def = item.getDefinition(gamedef->idef());
+ video::ITexture *texture = def.inventory_texture;
+ // Draw the inventory texture
if(texture != NULL)
{
const video::SColor color(255,255,255,255);
@@ -51,34 +53,59 @@ void drawInventoryItem(video::IVideoDriver *driver,
core::dimension2di(texture->getOriginalSize())),
clip, colors, true);
}
- else
+
+ if(def.type == ITEM_TOOL && item.wear != 0)
{
- video::SColor bgcolor(255,50,50,128);
- driver->draw2DRectangle(bgcolor, rect, clip);
+ // Draw a progressbar
+ float barheight = rect.getHeight()/16;
+ float barpad_x = rect.getWidth()/16;
+ float barpad_y = rect.getHeight()/16;
+ core::rect<s32> progressrect(
+ rect.UpperLeftCorner.X + barpad_x,
+ rect.LowerRightCorner.Y - barpad_y - barheight,
+ rect.LowerRightCorner.X - barpad_x,
+ rect.LowerRightCorner.Y - barpad_y);
+
+ // Shrink progressrect by amount of tool damage
+ float wear = item.wear / 65535.0;
+ progressrect.LowerRightCorner.X =
+ wear * progressrect.UpperLeftCorner.X +
+ (1-wear) * progressrect.LowerRightCorner.X;
+
+ // Compute progressbar color
+ // wear = 0.0: green
+ // wear = 0.5: yellow
+ // wear = 1.0: red
+ video::SColor color(255,255,255,255);
+ int wear_i = floor(wear * 511);
+ wear_i = MYMIN(wear_i + 10, 511);
+ if(wear_i <= 255)
+ color.set(255, wear_i, 255, 0);
+ else
+ color.set(255, 255, 511-wear_i, 0);
+
+ driver->draw2DRectangle(color, progressrect, clip);
}
- if(font != NULL)
+ if(font != NULL && item.count >= 2)
{
- std::string text = item->getText();
- if(font && text != "")
- {
- v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
- v2s32 sdim(dim.X,dim.Y);
-
- core::rect<s32> rect2(
- /*rect.UpperLeftCorner,
- core::dimension2d<u32>(rect.getWidth(), 15)*/
- rect.LowerRightCorner - sdim,
- sdim
- );
-
- video::SColor bgcolor(128,0,0,0);
- driver->draw2DRectangle(bgcolor, rect2, clip);
-
- font->draw(text.c_str(), rect2,
- video::SColor(255,255,255,255), false, false,
- clip);
- }
+ // Get the item count as a string
+ std::string text = itos(item.count);
+ v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
+ v2s32 sdim(dim.X,dim.Y);
+
+ core::rect<s32> rect2(
+ /*rect.UpperLeftCorner,
+ core::dimension2d<u32>(rect.getWidth(), 15)*/
+ rect.LowerRightCorner - sdim,
+ sdim
+ );
+
+ video::SColor bgcolor(128,0,0,0);
+ driver->draw2DRectangle(bgcolor, rect2, clip);
+
+ video::SColor color(255,255,255,255);
+ font->draw(text.c_str(), rect2, color, false, false, clip);
}
}
@@ -90,15 +117,13 @@ GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
v2s16 menu_size,
- InventoryContext *c,
InventoryManager *invmgr,
- ITextureSource *tsrc
+ IGameDef *gamedef
):
GUIModalMenu(env, parent, id, menumgr),
m_menu_size(menu_size),
- m_c(c),
m_invmgr(invmgr),
- m_tsrc(tsrc)
+ m_gamedef(gamedef)
{
m_selected_item = NULL;
}
@@ -214,15 +239,15 @@ GUIInventoryMenu::ItemSpec GUIInventoryMenu::getItemAtPos(v2s32 p) const
core::rect<s32> rect = imgrect + s.pos + p0;
if(rect.isPointInside(p))
{
- return ItemSpec(s.inventoryname, s.listname, i);
+ return ItemSpec(s.inventoryloc, s.listname, i);
}
}
}
- return ItemSpec("", "", -1);
+ return ItemSpec(InventoryLocation(), "", -1);
}
-void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc)
+void GUIInventoryMenu::drawList(const ListDrawSpec &s)
{
video::IVideoDriver* driver = Environment->getVideoDriver();
@@ -232,7 +257,7 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc)
if (skin)
font = skin->getFont();
- Inventory *inv = m_invmgr->getInventory(m_c, s.inventoryname);
+ Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
assert(inv);
InventoryList *ilist = inv->getList(s.listname);
@@ -244,7 +269,7 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc)
s32 y = (i/s.geom.X) * spacing.Y;
v2s32 p(x,y);
core::rect<s32> rect = imgrect + s.pos + p;
- InventoryItem *item = NULL;
+ ItemStack item;
if(ilist)
item = ilist->getItem(i);
@@ -278,10 +303,10 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc)
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
}
- if(item)
+ if(!item.empty())
{
- drawInventoryItem(driver, font, item,
- rect, &AbsoluteClippingRect, tsrc);
+ drawItemStack(driver, font, item,
+ rect, &AbsoluteClippingRect, m_gamedef);
}
}
@@ -303,8 +328,7 @@ void GUIInventoryMenu::drawMenu()
for(u32 i=0; i<m_draw_spec.size(); i++)
{
- ListDrawSpec &s = m_draw_spec[i];
- drawList(s, m_tsrc);
+ drawList(m_draw_spec[i]);
}
/*
@@ -352,14 +376,14 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
//infostream<<"Mouse action at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
if(s.isValid())
{
- infostream<<"Mouse action on "<<s.inventoryname
+ infostream<<"Mouse action on "<<s.inventoryloc.dump()
<<"/"<<s.listname<<" "<<s.i<<std::endl;
if(m_selected_item)
{
- Inventory *inv_from = m_invmgr->getInventory(m_c,
- m_selected_item->inventoryname);
- Inventory *inv_to = m_invmgr->getInventory(m_c,
- s.inventoryname);
+ Inventory *inv_from = m_invmgr->getInventory(
+ m_selected_item->inventoryloc);
+ Inventory *inv_to = m_invmgr->getInventory(
+ s.inventoryloc);
assert(inv_from);
assert(inv_to);
InventoryList *list_from =
@@ -373,21 +397,21 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
// Indicates whether source slot completely empties
bool source_empties = false;
if(list_from && list_to
- && list_from->getItem(m_selected_item->i) != NULL)
+ && !list_from->getItem(m_selected_item->i).empty())
{
infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
IMoveAction *a = new IMoveAction();
a->count = amount;
- a->from_inv = m_selected_item->inventoryname;
+ a->from_inv = m_selected_item->inventoryloc;
a->from_list = m_selected_item->listname;
a->from_i = m_selected_item->i;
- a->to_inv = s.inventoryname;
+ a->to_inv = s.inventoryloc;
a->to_list = s.listname;
a->to_i = s.i;
//ispec.actions->push_back(a);
m_invmgr->inventoryAction(a);
- if(list_from->getItem(m_selected_item->i)->getCount()<=amount)
+ if(list_from->getItem(m_selected_item->i).count<=amount)
source_empties = true;
}
// Remove selection if target was left-clicked or source
@@ -401,13 +425,13 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
else
{
/*
- Select if non-NULL
+ Select if nonempty
*/
- Inventory *inv = m_invmgr->getInventory(m_c,
- s.inventoryname);
+ Inventory *inv = m_invmgr->getInventory(
+ s.inventoryloc);
assert(inv);
InventoryList *list = inv->getList(s.listname);
- if(list->getItem(s.i) != NULL)
+ if(!list->getItem(s.i).empty())
{
m_selected_item = new ItemSpec(s);
}
@@ -489,7 +513,7 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
core::array<GUIInventoryMenu::DrawSpec> &draw_spec,
const std::string &data,
- const std::string &current_name)
+ const InventoryLocation &current_location)
{
v2s16 invsize(8,9);
Strfnd f(data);
@@ -500,8 +524,11 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
if(type == "list")
{
std::string name = f.next(";");
+ InventoryLocation loc;
if(name == "current_name")
- name = current_name;
+ loc = current_location;
+ else
+ loc.deSerialize(name);
std::string subname = f.next(";");
s32 pos_x = stoi(f.next(","));
s32 pos_y = stoi(f.next(";"));
@@ -512,7 +539,7 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
<<", geom=("<<geom_x<<","<<geom_y<<")"
<<std::endl;
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
- type, name, subname,
+ type, loc, subname,
v2s32(pos_x,pos_y),v2s32(geom_x,geom_y)));
f.next("]");
}
diff --git a/src/guiInventoryMenu.h b/src/guiInventoryMenu.h
index 359268687..c3b3e5a64 100644
--- a/src/guiInventoryMenu.h
+++ b/src/guiInventoryMenu.h
@@ -23,18 +23,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "inventory.h"
+#include "inventorymanager.h"
#include "utility.h"
#include "modalMenu.h"
-class ITextureSource;
-class InventoryContext;
+class IGameDef;
class InventoryManager;
-void drawInventoryItem(video::IVideoDriver *driver,
+void drawItemStack(video::IVideoDriver *driver,
gui::IGUIFont *font,
- InventoryItem *item, core::rect<s32> rect,
+ const ItemStack &item,
+ const core::rect<s32> &rect,
const core::rect<s32> *clip,
- ITextureSource *tsrc);
+ IGameDef *gamedef);
class GUIInventoryMenu : public GUIModalMenu
{
@@ -44,11 +45,11 @@ class GUIInventoryMenu : public GUIModalMenu
{
i = -1;
}
- ItemSpec(const std::string &a_inventoryname,
+ ItemSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname,
s32 a_i)
{
- inventoryname = a_inventoryname;
+ inventoryloc = a_inventoryloc;
listname = a_listname;
i = a_i;
}
@@ -57,7 +58,7 @@ class GUIInventoryMenu : public GUIModalMenu
return i != -1;
}
- std::string inventoryname;
+ InventoryLocation inventoryloc;
std::string listname;
s32 i;
};
@@ -67,17 +68,17 @@ class GUIInventoryMenu : public GUIModalMenu
ListDrawSpec()
{
}
- ListDrawSpec(const std::string &a_inventoryname,
+ ListDrawSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname,
v2s32 a_pos, v2s32 a_geom)
{
- inventoryname = a_inventoryname;
+ inventoryloc = a_inventoryloc;
listname = a_listname;
pos = a_pos;
geom = a_geom;
}
- std::string inventoryname;
+ InventoryLocation inventoryloc;
std::string listname;
v2s32 pos;
v2s32 geom;
@@ -89,7 +90,7 @@ public:
{
}
DrawSpec(const std::string &a_type,
- const std::string &a_name,
+ const InventoryLocation &a_name,
const std::string &a_subname,
v2s32 a_pos,
v2s32 a_geom)
@@ -102,7 +103,7 @@ public:
}
std::string type;
- std::string name;
+ InventoryLocation name;
std::string subname;
v2s32 pos;
v2s32 geom;
@@ -112,15 +113,14 @@ public:
static v2s16 makeDrawSpecArrayFromString(
core::array<GUIInventoryMenu::DrawSpec> &draw_spec,
const std::string &data,
- const std::string &current_name);
+ const InventoryLocation &current_location);
GUIInventoryMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
v2s16 menu_size,
- InventoryContext *c,
InventoryManager *invmgr,
- ITextureSource *tsrc
+ IGameDef *gamedef
);
~GUIInventoryMenu();
@@ -136,7 +136,7 @@ public:
void regenerateGui(v2u32 screensize);
ItemSpec getItemAtPos(v2s32 p) const;
- void drawList(const ListDrawSpec &s, ITextureSource *tsrc);
+ void drawList(const ListDrawSpec &s);
void drawMenu();
bool OnEvent(const SEvent& event);
@@ -153,9 +153,8 @@ protected:
v2s32 spacing;
v2s32 imgsize;
- InventoryContext *m_c;
InventoryManager *m_invmgr;
- ITextureSource *m_tsrc;
+ IGameDef *m_gamedef;
core::array<DrawSpec> m_init_draw_spec;
core::array<ListDrawSpec> m_draw_spec;
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 0d38bed78..ebd0b9c23 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -22,545 +22,429 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "utility.h"
#include "debug.h"
#include <sstream>
-#include "main.h" // For tsrc, g_toolmanager
-#include "serverobject.h"
-#include "content_mapnode.h"
-#include "content_sao.h"
-#include "environment.h"
-#include "mapblock.h"
-#include "player.h"
#include "log.h"
-#include "nodedef.h"
-#include "tooldef.h"
-#include "craftitemdef.h"
-#include "gamedef.h"
-#include "scriptapi.h"
+#include "itemdef.h"
#include "strfnd.h"
+#include "content_mapnode.h" // For loading legacy MaterialItems
#include "nameidmapping.h" // For loading legacy MaterialItems
/*
- InventoryItem
+ ItemStack
*/
-InventoryItem::InventoryItem(IGameDef *gamedef, u16 count):
- m_gamedef(gamedef),
- m_count(count)
+static content_t content_translate_from_19_to_internal(content_t c_from)
{
- assert(m_gamedef);
+ for(u32 i=0; i<sizeof(trans_table_19)/sizeof(trans_table_19[0]); i++)
+ {
+ if(trans_table_19[i][1] == c_from)
+ {
+ return trans_table_19[i][0];
+ }
+ }
+ return c_from;
}
-InventoryItem::~InventoryItem()
+// If the string contains spaces, quotes or control characters, encodes as JSON.
+// Else returns the string unmodified.
+static std::string serializeJsonStringIfNeeded(const std::string &s)
{
+ for(size_t i = 0; i < s.size(); ++i)
+ {
+ if(s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"')
+ return serializeJsonString(s);
+ }
+ return s;
}
-content_t content_translate_from_19_to_internal(content_t c_from)
+// Parses a string serialized by serializeJsonStringIfNeeded.
+static std::string deSerializeJsonStringIfNeeded(std::istream &is)
{
- for(u32 i=0; i<sizeof(trans_table_19)/sizeof(trans_table_19[0]); i++)
+ std::ostringstream tmp_os;
+ bool expect_initial_quote = true;
+ bool is_json = false;
+ bool was_backslash = false;
+ for(;;)
{
- if(trans_table_19[i][1] == c_from)
+ char c = is.get();
+ if(is.eof())
+ break;
+ if(expect_initial_quote && c == '"')
{
- return trans_table_19[i][0];
+ tmp_os << c;
+ is_json = true;
+ }
+ else if(is_json)
+ {
+ tmp_os << c;
+ if(was_backslash)
+ was_backslash = false;
+ else if(c == '\\')
+ was_backslash = true;
+ else if(c == '"')
+ break; // Found end of string
+ }
+ else
+ {
+ if(c == ' ')
+ {
+ // Found end of word
+ is.unget();
+ break;
+ }
+ else
+ {
+ tmp_os << c;
+ }
}
+ expect_initial_quote = false;
}
- return c_from;
+ if(is_json)
+ {
+ std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
+ return deSerializeJsonString(tmp_is);
+ }
+ else
+ return tmp_os.str();
+}
+
+
+ItemStack::ItemStack(std::string name_, u16 count_,
+ u16 wear_, std::string metadata_,
+ IItemDefManager *itemdef)
+{
+ name = itemdef->getAlias(name_);
+ count = count_;
+ wear = wear_;
+ metadata = metadata_;
+
+ if(name.empty() || count == 0)
+ clear();
+ else if(itemdef->get(name).type == ITEM_TOOL)
+ count = 1;
}
-InventoryItem* InventoryItem::deSerialize(std::istream &is, IGameDef *gamedef)
+void ItemStack::serialize(std::ostream &os) const
{
DSTACK(__FUNCTION_NAME);
- //is.imbue(std::locale("C"));
+ if(empty())
+ return;
+
+ // Check how many parts of the itemstring are needed
+ int parts = 1;
+ if(count != 1)
+ parts = 2;
+ if(wear != 0)
+ parts = 3;
+ if(metadata != "")
+ parts = 4;
+
+ os<<serializeJsonStringIfNeeded(name);
+ if(parts >= 2)
+ os<<" "<<count;
+ if(parts >= 3)
+ os<<" "<<wear;
+ if(parts >= 4)
+ os<<" "<<serializeJsonStringIfNeeded(metadata);
+}
+
+void ItemStack::deSerialize(std::istream &is, IItemDefManager *itemdef)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ clear();
+
// Read name
- std::string name;
- std::getline(is, name, ' ');
+ name = deSerializeJsonStringIfNeeded(is);
+
+ // Skip space
+ std::string tmp;
+ std::getline(is, tmp, ' ');
+ if(!tmp.empty())
+ throw SerializationError("Unexpected text after item name");
if(name == "MaterialItem")
{
- // u16 reads directly as a number (u8 doesn't)
+ // Obsoleted on 2011-07-30
+
u16 material;
is>>material;
- u16 count;
- is>>count;
+ u16 materialcount;
+ is>>materialcount;
// Convert old materials
if(material <= 0xff)
material = content_translate_from_19_to_internal(material);
if(material > MAX_CONTENT)
throw SerializationError("Too large material number");
- return new MaterialItem(gamedef, material, count);
+ // Convert old id to name
+ NameIdMapping legacy_nimap;
+ content_mapnode_get_name_id_mapping(&legacy_nimap);
+ legacy_nimap.getName(material, name);
+ if(name == "")
+ name = "unknown_block";
+ name = itemdef->getAlias(name);
+ count = materialcount;
}
else if(name == "MaterialItem2")
{
+ // Obsoleted on 2011-11-16
+
u16 material;
is>>material;
- u16 count;
- is>>count;
+ u16 materialcount;
+ is>>materialcount;
if(material > MAX_CONTENT)
throw SerializationError("Too large material number");
- return new MaterialItem(gamedef, material, count);
+ // Convert old id to name
+ NameIdMapping legacy_nimap;
+ content_mapnode_get_name_id_mapping(&legacy_nimap);
+ legacy_nimap.getName(material, name);
+ if(name == "")
+ name = "unknown_block";
+ name = itemdef->getAlias(name);
+ count = materialcount;
}
- else if(name == "node" || name == "NodeItem" || name == "MaterialItem3")
+ else if(name == "node" || name == "NodeItem" || name == "MaterialItem3"
+ || name == "craft" || name == "CraftItem")
{
+ // Obsoleted on 2012-01-07
+
std::string all;
std::getline(is, all, '\n');
- std::string nodename;
// First attempt to read inside ""
Strfnd fnd(all);
fnd.next("\"");
// If didn't skip to end, we have ""s
if(!fnd.atend()){
- nodename = fnd.next("\"");
+ name = fnd.next("\"");
} else { // No luck, just read a word then
fnd.start(all);
- nodename = fnd.next(" ");
+ name = fnd.next(" ");
}
fnd.skip_over(" ");
- u16 count = stoi(trim(fnd.next("")));
+ name = itemdef->getAlias(name);
+ count = stoi(trim(fnd.next("")));
if(count == 0)
count = 1;
- return new MaterialItem(gamedef, nodename, count);
}
else if(name == "MBOItem")
{
- std::string inventorystring;
- std::getline(is, inventorystring, '|');
+ // Obsoleted on 2011-10-14
throw SerializationError("MBOItem not supported anymore");
}
- else if(name == "craft" || name == "CraftItem")
- {
- std::string all;
- std::getline(is, all, '\n');
- std::string subname;
- // First attempt to read inside ""
- Strfnd fnd(all);
- fnd.next("\"");
- // If didn't skip to end, we have ""s
- if(!fnd.atend()){
- subname = fnd.next("\"");
- } else { // No luck, just read a word then
- fnd.start(all);
- subname = fnd.next(" ");
- }
- // Then read count
- fnd.skip_over(" ");
- u16 count = stoi(trim(fnd.next("")));
- if(count == 0)
- count = 1;
- return new CraftItem(gamedef, subname, count);
- }
else if(name == "tool" || name == "ToolItem")
{
+ // Obsoleted on 2012-01-07
+
std::string all;
std::getline(is, all, '\n');
- std::string toolname;
// First attempt to read inside ""
Strfnd fnd(all);
fnd.next("\"");
// If didn't skip to end, we have ""s
if(!fnd.atend()){
- toolname = fnd.next("\"");
+ name = fnd.next("\"");
} else { // No luck, just read a word then
fnd.start(all);
- toolname = fnd.next(" ");
+ name = fnd.next(" ");
}
+ count = 1;
// Then read wear
fnd.skip_over(" ");
- u16 wear = stoi(trim(fnd.next("")));
- return new ToolItem(gamedef, toolname, wear);
+ wear = stoi(trim(fnd.next("")));
}
else
{
- infostream<<"Unknown InventoryItem name=\""<<name<<"\""<<std::endl;
- throw SerializationError("Unknown InventoryItem name");
- }
-}
-
-InventoryItem* InventoryItem::deSerialize(const std::string &str,
- IGameDef *gamedef)
-{
- std::istringstream is(str, std::ios_base::binary);
- return deSerialize(is, gamedef);
-}
-
-std::string InventoryItem::getItemString() {
- // Get item string
- std::ostringstream os(std::ios_base::binary);
- serialize(os);
- return os.str();
-}
-
-bool InventoryItem::dropOrPlace(ServerEnvironment *env,
- ServerActiveObject *dropper,
- v3f pos, bool place, s16 count)
-{
- /*
- Ensure that the block is loaded so that the item
- can properly be added to the static list too
- */
- v3s16 blockpos = getNodeBlockPos(floatToInt(pos, BS));
- MapBlock *block = env->getMap().emergeBlock(blockpos, false);
- if(block==NULL)
- {
- infostream<<"InventoryItem::dropOrPlace(): FAIL: block not found: "
- <<blockpos.X<<","<<blockpos.Y<<","<<blockpos.Z
- <<std::endl;
- return false;
- }
-
- /*
- Take specified number of items,
- but limit to getDropCount().
- */
- s16 dropcount = getDropCount();
- if(count < 0 || count > dropcount)
- count = dropcount;
- if(count < 0 || count > getCount())
- count = getCount();
- if(count > 0)
- {
- /*
- Create an ItemSAO
- */
- pos.Y -= BS*0.25; // let it drop a bit
- // Randomize a bit
- //pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
- //pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
- // Create object
- ServerActiveObject *obj = new ItemSAO(env, pos, getItemString());
- // Add the object to the environment
- env->addActiveObject(obj);
- infostream<<"Dropped item"<<std::endl;
-
- setCount(getCount() - count);
- }
-
- return getCount() < 1; // delete the item?
-}
-
-/*
- MaterialItem
-*/
-
-MaterialItem::MaterialItem(IGameDef *gamedef, std::string nodename, u16 count):
- InventoryItem(gamedef, count)
-{
- if(nodename == "")
- nodename = "unknown_block";
-
- // Convert directly to the correct name through aliases
- m_nodename = gamedef->ndef()->getAlias(nodename);
-}
-// Legacy constructor
-MaterialItem::MaterialItem(IGameDef *gamedef, content_t content, u16 count):
- InventoryItem(gamedef, count)
-{
- NameIdMapping legacy_nimap;
- content_mapnode_get_name_id_mapping(&legacy_nimap);
- std::string nodename;
- legacy_nimap.getName(content, nodename);
- if(nodename == "")
- nodename = "unknown_block";
- m_nodename = nodename;
-}
-
-#ifndef SERVER
-video::ITexture * MaterialItem::getImage() const
-{
- return m_gamedef->getNodeDefManager()->get(m_nodename).inventory_texture;
-}
-#endif
-
-bool MaterialItem::isCookable() const
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- const ContentFeatures &f = ndef->get(m_nodename);
- return (f.cookresult_item != "");
-}
-
-InventoryItem *MaterialItem::createCookResult() const
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- const ContentFeatures &f = ndef->get(m_nodename);
- std::istringstream is(f.cookresult_item, std::ios::binary);
- return InventoryItem::deSerialize(is, m_gamedef);
-}
-
-float MaterialItem::getCookTime() const
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- const ContentFeatures &f = ndef->get(m_nodename);
- return f.furnace_cooktime;
-}
-
-float MaterialItem::getBurnTime() const
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- const ContentFeatures &f = ndef->get(m_nodename);
- return f.furnace_burntime;
-}
-
-content_t MaterialItem::getMaterial() const
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- content_t id = CONTENT_IGNORE;
- ndef->getId(m_nodename, id);
- return id;
-}
-
-/*
- ToolItem
-*/
-
-ToolItem::ToolItem(IGameDef *gamedef, std::string toolname, u16 wear):
- InventoryItem(gamedef, 1)
-{
- // Convert directly to the correct name through aliases
- m_toolname = gamedef->tdef()->getAlias(toolname);
-
- m_wear = wear;
-}
-
-std::string ToolItem::getImageBasename() const
-{
- return m_gamedef->getToolDefManager()->getImagename(m_toolname);
-}
-
-#ifndef SERVER
-video::ITexture * ToolItem::getImage() const
-{
- ITextureSource *tsrc = m_gamedef->tsrc();
-
- std::string basename = getImageBasename();
-
- /*
- Calculate a progress value with sane amount of
- maximum states
- */
- u32 maxprogress = 30;
- u32 toolprogress = (65535-m_wear)/(65535/maxprogress);
-
- float value_f = (float)toolprogress / (float)maxprogress;
- std::ostringstream os;
- os<<basename<<"^[progressbar"<<value_f;
+ do // This loop is just to allow "break;"
+ {
+ // The real thing
- return tsrc->getTextureRaw(os.str());
-}
+ // Apply item aliases
+ name = itemdef->getAlias(name);
-video::ITexture * ToolItem::getImageRaw() const
-{
- ITextureSource *tsrc = m_gamedef->tsrc();
-
- return tsrc->getTextureRaw(getImageBasename());
-}
-#endif
+ // Read the count
+ std::string count_str;
+ std::getline(is, count_str, ' ');
+ if(count_str.empty())
+ {
+ count = 1;
+ break;
+ }
+ else
+ count = stoi(count_str);
-bool ToolItem::isKnown() const
-{
- IToolDefManager *tdef = m_gamedef->tdef();
- const ToolDefinition *def = tdef->getToolDefinition(m_toolname);
- return (def != NULL);
-}
+ // Read the wear
+ std::string wear_str;
+ std::getline(is, wear_str, ' ');
+ if(wear_str.empty())
+ break;
+ else
+ wear = stoi(wear_str);
-/*
- CraftItem
-*/
-
-CraftItem::CraftItem(IGameDef *gamedef, std::string subname, u16 count):
- InventoryItem(gamedef, count)
-{
- // Convert directly to the correct name through aliases
- m_subname = gamedef->cidef()->getAlias(subname);
-}
+ // Read metadata
+ metadata = deSerializeJsonStringIfNeeded(is);
-#ifndef SERVER
-video::ITexture * CraftItem::getImage() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- ITextureSource *tsrc = m_gamedef->tsrc();
- std::string imagename = cidef->getImagename(m_subname);
- return tsrc->getTextureRaw(imagename);
-}
-#endif
+ // In case fields are added after metadata, skip space here:
+ //std::getline(is, tmp, ' ');
+ //if(!tmp.empty())
+ // throw SerializationError("Unexpected text after metadata");
-bool CraftItem::isKnown() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- return (def != NULL);
-}
-
-u16 CraftItem::getStackMax() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- if(def == NULL)
- return InventoryItem::getStackMax();
- return def->stack_max;
-}
-
-bool CraftItem::isUsable() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- return def != NULL && def->usable;
-}
+ } while(false);
+ }
-bool CraftItem::isCookable() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- return def != NULL && def->cookresult_item != "";
+ if(name.empty() || count == 0)
+ clear();
+ else if(itemdef->get(name).type == ITEM_TOOL)
+ count = 1;
}
-InventoryItem *CraftItem::createCookResult() const
+void ItemStack::deSerialize(const std::string &str, IItemDefManager *itemdef)
{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- if(def == NULL)
- return InventoryItem::createCookResult();
- std::istringstream is(def->cookresult_item, std::ios::binary);
- return InventoryItem::deSerialize(is, m_gamedef);
+ std::istringstream is(str, std::ios::binary);
+ deSerialize(is, itemdef);
}
-float CraftItem::getCookTime() const
+std::string ItemStack::getItemString() const
{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- if (def == NULL)
- return InventoryItem::getCookTime();
- return def->furnace_cooktime;
+ // Get item string
+ std::ostringstream os(std::ios::binary);
+ serialize(os);
+ return os.str();
}
-float CraftItem::getBurnTime() const
+ItemStack ItemStack::addItem(const ItemStack &newitem_,
+ IItemDefManager *itemdef)
{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- if (def == NULL)
- return InventoryItem::getBurnTime();
- return def->furnace_burntime;
-}
+ ItemStack newitem = newitem_;
-s16 CraftItem::getDropCount() const
-{
- // Special cases
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- if(def != NULL && def->dropcount >= 0)
- return def->dropcount;
- // Default
- return InventoryItem::getDropCount();
-}
+ // If the item is empty or the position invalid, bail out
+ if(newitem.empty())
+ {
+ // nothing can be added trivially
+ }
+ // If this is an empty item, it's an easy job.
+ else if(empty())
+ {
+ *this = newitem;
+ newitem.clear();
+ }
+ // If item name differs, bail out
+ else if(name != newitem.name)
+ {
+ // cannot be added
+ }
+ // If the item fits fully, add counter and delete it
+ else if(newitem.count <= freeSpace(itemdef))
+ {
+ add(newitem.count);
+ newitem.clear();
+ }
+ // Else the item does not fit fully. Add all that fits and return
+ // the rest.
+ else
+ {
+ u16 freespace = freeSpace(itemdef);
+ add(freespace);
+ newitem.remove(freespace);
+ }
-bool CraftItem::areLiquidsPointable() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- return def != NULL && def->liquids_pointable;
+ return newitem;
}
-bool CraftItem::dropOrPlace(ServerEnvironment *env,
- ServerActiveObject *dropper,
- v3f pos, bool place, s16 count)
+bool ItemStack::itemFits(const ItemStack &newitem_,
+ ItemStack *restitem,
+ IItemDefManager *itemdef) const
{
- if(count == 0)
- return false;
-
- bool callback_exists = false;
- bool result = false;
+ ItemStack newitem = newitem_;
- if(place)
+ // If the item is empty or the position invalid, bail out
+ if(newitem.empty())
{
- result = scriptapi_craftitem_on_place_on_ground(
- env->getLua(),
- m_subname.c_str(), dropper, pos,
- callback_exists);
+ // nothing can be added trivially
}
-
- // note: on_drop is fallback for on_place_on_ground
-
- if(!callback_exists)
+ // If this is an empty item, it's an easy job.
+ else if(empty())
{
- result = scriptapi_craftitem_on_drop(
- env->getLua(),
- m_subname.c_str(), dropper, pos,
- callback_exists);
+ newitem.clear();
}
-
- if(callback_exists)
+ // If item name differs, bail out
+ else if(name != newitem.name)
{
- // If the callback returned true, drop one item
- if(result)
- setCount(getCount() - 1);
- return getCount() < 1;
+ // cannot be added
}
+ // If the item fits fully, delete it
+ else if(newitem.count <= freeSpace(itemdef))
+ {
+ newitem.clear();
+ }
+ // Else the item does not fit fully. Return the rest.
+ // the rest.
else
{
- // If neither on_place_on_ground (if place==true)
- // nor on_drop exists, call the base implementation
- return InventoryItem::dropOrPlace(env, dropper, pos, place, count);
+ u16 freespace = freeSpace(itemdef);
+ newitem.remove(freespace);
}
+
+ if(restitem)
+ *restitem = newitem;
+ return newitem.empty();
}
-bool CraftItem::use(ServerEnvironment *env,
- ServerActiveObject *user,
- const PointedThing& pointed)
+ItemStack ItemStack::takeItem(u32 takecount)
{
- bool callback_exists = false;
- bool result = false;
+ if(takecount == 0 || count == 0)
+ return ItemStack();
- result = scriptapi_craftitem_on_use(
- env->getLua(),
- m_subname.c_str(), user, pointed,
- callback_exists);
-
- if(callback_exists)
+ ItemStack result = *this;
+ if(takecount >= count)
{
- // If the callback returned true, drop one item
- if(result)
- setCount(getCount() - 1);
- return getCount() < 1;
+ // Take all
+ clear();
}
else
{
- // If neither on_place_on_ground (if place==true)
- // nor on_drop exists, call the base implementation
- return InventoryItem::use(env, user, pointed);
+ // Take part
+ remove(takecount);
+ result.count = takecount;
}
+ return result;
+}
+
+ItemStack ItemStack::peekItem(u32 peekcount) const
+{
+ if(peekcount == 0 || count == 0)
+ return ItemStack();
+
+ ItemStack result = *this;
+ if(peekcount < count)
+ result.count = peekcount;
+ return result;
}
/*
Inventory
*/
-InventoryList::InventoryList(std::string name, u32 size)
+InventoryList::InventoryList(std::string name, u32 size, IItemDefManager *itemdef)
{
m_name = name;
m_size = size;
+ m_itemdef = itemdef;
clearItems();
//m_dirty = false;
}
InventoryList::~InventoryList()
{
- for(u32 i=0; i<m_items.size(); i++)
- {
- if(m_items[i])
- delete m_items[i];
- }
}
void InventoryList::clearItems()
{
- for(u32 i=0; i<m_items.size(); i++)
- {
- if(m_items[i])
- delete m_items[i];
- }
-
m_items.clear();
for(u32 i=0; i<m_size; i++)
{
- m_items.push_back(NULL);
+ m_items.push_back(ItemStack());
}
//setDirty(true);
@@ -568,17 +452,8 @@ void InventoryList::clearItems()
void InventoryList::setSize(u32 newsize)
{
- if(newsize < m_items.size()){
- for(u32 i=newsize; i<m_items.size(); i++){
- if(m_items[i])
- delete m_items[i];
- }
- m_items.erase(newsize, m_items.size() - newsize);
- } else {
- for(u32 i=m_items.size(); i<newsize; i++){
- m_items.push_back(NULL);
- }
- }
+ if(newsize != m_items.size())
+ m_items.resize(newsize);
m_size = newsize;
}
@@ -588,15 +463,15 @@ void InventoryList::serialize(std::ostream &os) const
for(u32 i=0; i<m_items.size(); i++)
{
- InventoryItem *item = m_items[i];
- if(item != NULL)
+ const ItemStack &item = m_items[i];
+ if(item.empty())
{
- os<<"Item ";
- item->serialize(os);
+ os<<"Empty";
}
else
{
- os<<"Empty";
+ os<<"Item ";
+ item.serialize(os);
}
os<<"\n";
}
@@ -604,7 +479,7 @@ void InventoryList::serialize(std::ostream &os) const
os<<"EndInventoryList\n";
}
-void InventoryList::deSerialize(std::istream &is, IGameDef *gamedef)
+void InventoryList::deSerialize(std::istream &is)
{
//is.imbue(std::locale("C"));
@@ -635,14 +510,15 @@ void InventoryList::deSerialize(std::istream &is, IGameDef *gamedef)
{
if(item_i > getSize() - 1)
throw SerializationError("too many items");
- InventoryItem *item = InventoryItem::deSerialize(iss, gamedef);
+ ItemStack item;
+ item.deSerialize(iss, m_itemdef);
m_items[item_i++] = item;
}
else if(name == "Empty")
{
if(item_i > getSize() - 1)
throw SerializationError("too many items");
- m_items[item_i++] = NULL;
+ m_items[item_i++].clear();
}
else
{
@@ -653,26 +529,15 @@ void InventoryList::deSerialize(std::istream &is, IGameDef *gamedef)
InventoryList::InventoryList(const InventoryList &other)
{
- /*
- Do this so that the items get cloned. Otherwise the pointers
- in the array will just get copied.
- */
*this = other;
}
InventoryList & InventoryList::operator = (const InventoryList &other)
{
- m_name = other.m_name;
+ m_items = other.m_items;
m_size = other.m_size;
- clearItems();
- for(u32 i=0; i<other.m_items.size(); i++)
- {
- InventoryItem *item = other.m_items[i];
- if(item != NULL)
- {
- m_items[i] = item->clone();
- }
- }
+ m_name = other.m_name;
+ m_itemdef = other.m_itemdef;
//setDirty(true);
return *this;
@@ -683,48 +548,45 @@ const std::string &InventoryList::getName() const
return m_name;
}
-u32 InventoryList::getSize()
+u32 InventoryList::getSize() const
{
return m_items.size();
}
-u32 InventoryList::getUsedSlots()
+u32 InventoryList::getUsedSlots() const
{
u32 num = 0;
for(u32 i=0; i<m_items.size(); i++)
{
- InventoryItem *item = m_items[i];
- if(item != NULL)
+ if(!m_items[i].empty())
num++;
}
return num;
}
-u32 InventoryList::getFreeSlots()
+u32 InventoryList::getFreeSlots() const
{
return getSize() - getUsedSlots();
}
-const InventoryItem * InventoryList::getItem(u32 i) const
+const ItemStack& InventoryList::getItem(u32 i) const
{
- if(i >= m_items.size())
- return NULL;
+ assert(i < m_size);
return m_items[i];
}
-InventoryItem * InventoryList::getItem(u32 i)
+ItemStack& InventoryList::getItem(u32 i)
{
- if(i >= m_items.size())
- return NULL;
+ assert(i < m_size);
return m_items[i];
}
-InventoryItem * InventoryList::changeItem(u32 i, InventoryItem *newitem)
+ItemStack InventoryList::changeItem(u32 i, const ItemStack &newitem)
{
if(i >= m_items.size())
return newitem;
- InventoryItem *olditem = m_items[i];
+ ItemStack olditem = m_items[i];
m_items[i] = newitem;
//setDirty(true);
return olditem;
@@ -733,15 +595,15 @@ InventoryItem * InventoryList::changeItem(u32 i, InventoryItem *newitem)
void InventoryList::deleteItem(u32 i)
{
assert(i < m_items.size());
- InventoryItem *item = changeItem(i, NULL);
- if(item)
- delete item;
+ m_items[i].clear();
}
-InventoryItem * InventoryList::addItem(InventoryItem *newitem)
+ItemStack InventoryList::addItem(const ItemStack &newitem_)
{
- if(newitem == NULL)
- return NULL;
+ ItemStack newitem = newitem_;
+
+ if(newitem.empty())
+ return newitem;
/*
First try to find if it could be added to some existing items
@@ -749,12 +611,12 @@ InventoryItem * InventoryList::addItem(InventoryItem *newitem)
for(u32 i=0; i<m_items.size(); i++)
{
// Ignore empty slots
- if(m_items[i] == NULL)
+ if(m_items[i].empty())
continue;
// Try adding
newitem = addItem(i, newitem);
- if(newitem == NULL)
- return NULL; // All was eaten
+ if(newitem.empty())
+ return newitem; // All was eaten
}
/*
@@ -763,150 +625,112 @@ InventoryItem * InventoryList::addItem(InventoryItem *newitem)
for(u32 i=0; i<m_items.size(); i++)
{
// Ignore unempty slots
- if(m_items[i] != NULL)
+ if(!m_items[i].empty())
continue;
// Try adding
newitem = addItem(i, newitem);
- if(newitem == NULL)
- return NULL; // All was eaten
+ if(newitem.empty())
+ return newitem; // All was eaten
}
// Return leftover
return newitem;
}
-InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
+ItemStack InventoryList::addItem(u32 i, const ItemStack &newitem)
{
- if(newitem == NULL)
- return NULL;
if(i >= m_items.size())
return newitem;
-
- //setDirty(true);
-
- // If it is an empty position, it's an easy job.
- InventoryItem *to_item = getItem(i);
- if(to_item == NULL)
- {
- m_items[i] = newitem;
- return NULL;
- }
-
- // If not addable, return the item
- if(newitem->addableTo(to_item) == false)
- return newitem;
-
- // If the item fits fully in the slot, add counter and delete it
- if(newitem->getCount() <= to_item->freeSpace())
- {
- to_item->add(newitem->getCount());
- delete newitem;
- return NULL;
- }
- // Else the item does not fit fully. Add all that fits and return
- // the rest.
- else
- {
- u16 freespace = to_item->freeSpace();
- to_item->add(freespace);
- newitem->remove(freespace);
- return newitem;
- }
+
+ ItemStack leftover = m_items[i].addItem(newitem, m_itemdef);
+ //if(leftover != newitem)
+ // setDirty(true);
+ return leftover;
}
-bool InventoryList::itemFits(const u32 i, const InventoryItem *newitem)
+bool InventoryList::itemFits(const u32 i, const ItemStack &newitem,
+ ItemStack *restitem) const
{
- // If it is an empty position, it's an easy job.
- const InventoryItem *to_item = getItem(i);
- if(to_item == NULL)
+ if(i >= m_items.size())
{
- return true;
- }
-
- // If not addable, fail
- if(newitem->addableTo(to_item) == false)
+ if(restitem)
+ *restitem = newitem;
return false;
-
- // If the item fits fully in the slot, pass
- if(newitem->getCount() <= to_item->freeSpace())
- {
- return true;
}
- return false;
+ return m_items[i].itemFits(newitem, restitem, m_itemdef);
}
-bool InventoryList::roomForItem(const InventoryItem *item)
+bool InventoryList::roomForItem(const ItemStack &item_) const
{
+ ItemStack item = item_;
+ ItemStack leftover;
for(u32 i=0; i<m_items.size(); i++)
- if(itemFits(i, item))
+ {
+ if(itemFits(i, item, &leftover))
return true;
+ item = leftover;
+ }
return false;
}
-bool InventoryList::roomForCookedItem(const InventoryItem *item)
-{
- if(!item)
- return false;
- const InventoryItem *cook = item->createCookResult();
- if(!cook)
- return false;
- bool room = roomForItem(cook);
- delete cook;
- return room;
-}
-
-InventoryItem * InventoryList::takeItem(u32 i, u32 count)
+bool InventoryList::containsItem(const ItemStack &item) const
{
+ u32 count = item.count;
if(count == 0)
- return NULL;
-
- //setDirty(true);
-
- InventoryItem *item = getItem(i);
- // If it is an empty position, return NULL
- if(item == NULL)
- return NULL;
-
- if(count >= item->getCount())
- {
- // Get the item by swapping NULL to its place
- return changeItem(i, NULL);
- }
- else
+ return true;
+ for(std::vector<ItemStack>::const_reverse_iterator
+ i = m_items.rbegin();
+ i != m_items.rend(); i++)
{
- InventoryItem *item2 = item->clone();
- item->remove(count);
- item2->setCount(count);
- return item2;
+ if(count == 0)
+ break;
+ if(i->name == item.name)
+ {
+ if(i->count >= count)
+ return true;
+ else
+ count -= i->count;
+ }
}
-
return false;
}
-void InventoryList::decrementMaterials(u16 count)
+ItemStack InventoryList::removeItem(const ItemStack &item)
{
- for(u32 i=0; i<m_items.size(); i++)
+ ItemStack removed;
+ for(std::vector<ItemStack>::reverse_iterator
+ i = m_items.rbegin();
+ i != m_items.rend(); i++)
{
- InventoryItem *item = takeItem(i, count);
- if(item)
- delete item;
+ if(i->name == item.name)
+ {
+ u32 still_to_remove = item.count - removed.count;
+ removed.addItem(i->takeItem(still_to_remove), m_itemdef);
+ if(removed.count == item.count)
+ break;
+ }
}
+ return removed;
}
-void InventoryList::print(std::ostream &o)
+ItemStack InventoryList::takeItem(u32 i, u32 takecount)
{
- o<<"InventoryList:"<<std::endl;
- for(u32 i=0; i<m_items.size(); i++)
- {
- InventoryItem *item = m_items[i];
- if(item != NULL)
- {
- o<<i<<": ";
- item->serialize(o);
- o<<"\n";
- }
- }
+ if(i >= m_items.size())
+ return ItemStack();
+
+ ItemStack taken = m_items[i].takeItem(takecount);
+ //if(!taken.empty())
+ // setDirty(true);
+ return taken;
+}
+
+ItemStack InventoryList::peekItem(u32 i, u32 peekcount) const
+{
+ if(i >= m_items.size())
+ return ItemStack();
+
+ return m_items[i].peekItem(peekcount);
}
/*
@@ -927,8 +751,9 @@ void Inventory::clear()
m_lists.clear();
}
-Inventory::Inventory()
+Inventory::Inventory(IItemDefManager *itemdef)
{
+ m_itemdef = itemdef;
}
Inventory::Inventory(const Inventory &other)
@@ -938,10 +763,15 @@ Inventory::Inventory(const Inventory &other)
Inventory & Inventory::operator = (const Inventory &other)
{
- clear();
- for(u32 i=0; i<other.m_lists.size(); i++)
+ // Gracefully handle self assignment
+ if(this != &other)
{
- m_lists.push_back(new InventoryList(*other.m_lists[i]));
+ clear();
+ m_itemdef = other.m_itemdef;
+ for(u32 i=0; i<other.m_lists.size(); i++)
+ {
+ m_lists.push_back(new InventoryList(*other.m_lists[i]));
+ }
}
return *this;
}
@@ -958,7 +788,7 @@ void Inventory::serialize(std::ostream &os) const
os<<"EndInventory\n";
}
-void Inventory::deSerialize(std::istream &is, IGameDef *gamedef)
+void Inventory::deSerialize(std::istream &is)
{
clear();
@@ -989,8 +819,8 @@ void Inventory::deSerialize(std::istream &is, IGameDef *gamedef)
std::getline(iss, listname, ' ');
iss>>listsize;
- InventoryList *list = new InventoryList(listname, listsize);
- list->deSerialize(is, gamedef);
+ InventoryList *list = new InventoryList(listname, listsize, m_itemdef);
+ list->deSerialize(is);
m_lists.push_back(list);
}
@@ -1009,14 +839,15 @@ InventoryList * Inventory::addList(const std::string &name, u32 size)
if(m_lists[i]->getSize() != size)
{
delete m_lists[i];
- m_lists[i] = new InventoryList(name, size);
+ m_lists[i] = new InventoryList(name, size, m_itemdef);
}
return m_lists[i];
}
else
{
- m_lists.push_back(new InventoryList(name, size));
- return m_lists.getLast();
+ InventoryList *list = new InventoryList(name, size, m_itemdef);
+ m_lists.push_back(list);
+ return list;
}
}
@@ -1034,7 +865,7 @@ bool Inventory::deleteList(const std::string &name)
if(i == -1)
return false;
delete m_lists[i];
- m_lists.erase(i);
+ m_lists.erase(m_lists.begin() + i);
return true;
}
diff --git a/src/inventory.h b/src/inventory.h
index 15de3c8e7..3f5d83589 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -23,460 +23,221 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream>
#include <sstream>
#include <string>
+#include <vector>
#include "common_irrlicht.h"
#include "debug.h"
-#include "mapnode.h" // For content_t
+#include "itemdef.h"
-#define QUANTITY_ITEM_MAX_COUNT 99
+struct ToolDiggingProperties;
-class ServerActiveObject;
-class ServerEnvironment;
-struct PointedThing;
-class ITextureSource;
-class IGameDef;
-
-class InventoryItem
+struct ItemStack
{
-public:
- InventoryItem(IGameDef *gamedef, u16 count);
- virtual ~InventoryItem();
-
- static InventoryItem* deSerialize(std::istream &is, IGameDef *gamedef);
- static InventoryItem* deSerialize(const std::string &str,
- IGameDef *gamedef);
-
- virtual const char* getName() const = 0;
- // Shall write the name and the parameters
- virtual void serialize(std::ostream &os) const = 0;
- // Shall make an exact clone of the item
- virtual InventoryItem* clone() = 0;
- // Return the name of the image for this item
- virtual std::string getImageBasename() const { return ""; }
-#ifndef SERVER
- // Shall return an image of the item (or NULL)
- virtual video::ITexture * getImage() const
- { return NULL; }
- // Shall return an image of the item without embellishments (or NULL)
- virtual video::ITexture * getImageRaw() const
- { return getImage(); }
-#endif
- // Shall return a text to show in the GUI
- virtual std::string getText() { return ""; }
+ ItemStack(): name(""), count(0), wear(0), metadata("") {}
+ ItemStack(std::string name_, u16 count_,
+ u16 wear, std::string metadata_,
+ IItemDefManager *itemdef);
+ ~ItemStack() {}
+
+ // Serialization
+ void serialize(std::ostream &os) const;
+ void deSerialize(std::istream &is, IItemDefManager *itemdef);
+ void deSerialize(const std::string &s, IItemDefManager *itemdef);
+
// Returns the string used for inventory
- virtual std::string getItemString();
-
- // Shall return false if item is not known and cannot be used
- virtual bool isKnown() const { return true; }
+ std::string getItemString() const;
/*
Quantity methods
*/
- // Return true if the item can be add()ed to the other
- virtual bool addableTo(const InventoryItem *other) const
- { return false; }
- // Return true if the other item contains this item
- virtual bool isSubsetOf(const InventoryItem *other) const
- { return false; }
- // Remove the other item from this one if possible and return true
- // Return false if not possible
- virtual bool removeOther(const InventoryItem *other)
- { return false; }
-
- u16 getCount() const
- { return m_count; }
- void setCount(u16 count)
- { m_count = count; }
-
- u16 freeSpace() const
+ bool empty() const
{
- u16 max = getStackMax();
- if(m_count > max)
- return 0;
- return max - m_count;
+ return count == 0;
}
- void add(u16 count)
+ void clear()
{
- m_count += count;
- }
- void remove(u16 count)
- {
- assert(m_count >= count);
- m_count -= count;
+ name = "";
+ count = 0;
+ wear = 0;
+ metadata = "";
}
- /*
- Other properties
- */
-
- // Maximum size of a stack
- virtual u16 getStackMax() const {return 1;}
- // Whether it can be used
- virtual bool isUsable() const {return false;}
- // Whether it can be cooked
- virtual bool isCookable() const {return false;}
- // Result of cooking (can randomize)
- virtual InventoryItem *createCookResult() const {return NULL;}
- // Time of cooking
- virtual float getCookTime() const {return 3.0;}
- // Whether it can be burned (<0 = cannot be burned)
- virtual float getBurnTime() const {return -1;}
- // Gets amount of items that dropping one ItemSAO will decrement
- // -1 means as many as possible
- virtual s16 getDropCount() const { return -1; }
- // Whether this item can point to liquids
- virtual bool areLiquidsPointable() const { return false; }
-
- // Creates an object from the item and places it in the world.
- // If return value is true, item should be removed.
- virtual bool dropOrPlace(ServerEnvironment *env,
- ServerActiveObject *dropper,
- v3f pos, bool place, s16 count);
-
- // Eat, press, activate, whatever.
- // Called when item is left-clicked while in hand.
- // If returns true, item shall be deleted.
- virtual bool use(ServerEnvironment *env,
- ServerActiveObject *user,
- const PointedThing& pointed){return false;}
-
-protected:
- IGameDef *m_gamedef;
- u16 m_count;
-};
-
-class MaterialItem : public InventoryItem
-{
-public:
- MaterialItem(IGameDef *gamedef, std::string nodename, u16 count);
- // Legacy constructor
- MaterialItem(IGameDef *gamedef, content_t content, u16 count);
- /*
- Implementation interface
- */
- virtual const char* getName() const
- {
- return "MaterialItem";
- }
- virtual void serialize(std::ostream &os) const
- {
- os<<"node";
- os<<" \"";
- os<<m_nodename;
- os<<"\" ";
- os<<m_count;
- }
- virtual InventoryItem* clone()
- {
- return new MaterialItem(m_gamedef, m_nodename, m_count);
- }
-#ifndef SERVER
- video::ITexture * getImage() const;
-#endif
- std::string getText()
+ void add(u16 n)
{
- std::ostringstream os;
- os<<m_count;
- return os.str();
+ count += n;
}
- virtual bool addableTo(const InventoryItem *other) const
+ void remove(u16 n)
{
- if(std::string(other->getName()) != "MaterialItem")
- return false;
- MaterialItem *m = (MaterialItem*)other;
- if(m->m_nodename != m_nodename)
- return false;
- return true;
- }
- virtual bool isSubsetOf(const InventoryItem *other) const
- {
- if(std::string(other->getName()) != "MaterialItem")
- return false;
- MaterialItem *m = (MaterialItem*)other;
- if(m->m_nodename != m_nodename)
- return false;
- return m_count <= m->m_count;
+ assert(count >= n);
+ count -= n;
+ if(count == 0)
+ clear(); // reset name, wear and metadata too
}
- virtual bool removeOther(const InventoryItem *other)
- {
- if(!other->isSubsetOf(this))
- return false;
- MaterialItem *m = (MaterialItem*)other;
- m_count += m->m_count;
- return true;
- }
-
- u16 getStackMax() const
- {
- return QUANTITY_ITEM_MAX_COUNT;
- }
-
- /*
- Other properties
- */
- bool isCookable() const;
- InventoryItem *createCookResult() const;
- float getCookTime() const;
- float getBurnTime() const;
- /*
- Special properties (not part of virtual interface)
- */
- std::string getNodeName() const
- { return m_nodename; }
- content_t getMaterial() const;
-private:
- std::string m_nodename;
-};
-/*
- An item that is used as a mid-product when crafting.
- Subnames:
- - Stick
-*/
-class CraftItem : public InventoryItem
-{
-public:
- CraftItem(IGameDef *gamedef, std::string subname, u16 count);
- /*
- Implementation interface
- */
- virtual const char* getName() const
- {
- return "CraftItem";
- }
- virtual void serialize(std::ostream &os) const
- {
- os<<"craft";
- os<<" \"";
- os<<m_subname;
- os<<"\" ";
- os<<m_count;
- }
- virtual InventoryItem* clone()
- {
- return new CraftItem(m_gamedef, m_subname, m_count);
- }
-#ifndef SERVER
- video::ITexture * getImage() const;
-#endif
- std::string getText()
- {
- std::ostringstream os;
- os<<m_count;
- return os.str();
- }
-
- virtual bool isKnown() const;
-
- virtual bool addableTo(const InventoryItem *other) const
- {
- if(std::string(other->getName()) != "CraftItem")
- return false;
- CraftItem *m = (CraftItem*)other;
- if(m->m_subname != m_subname)
- return false;
- return true;
- }
- virtual bool isSubsetOf(const InventoryItem *other) const
- {
- if(std::string(other->getName()) != "CraftItem")
- return false;
- CraftItem *m = (CraftItem*)other;
- if(m->m_subname != m_subname)
- return false;
- return m_count <= m->m_count;
- }
- virtual bool removeOther(const InventoryItem *other)
+ // Maximum size of a stack
+ u16 getStackMax(IItemDefManager *itemdef) const
{
- if(!other->isSubsetOf(this))
- return false;
- CraftItem *m = (CraftItem*)other;
- m_count += m->m_count;
- return true;
+ s16 max = itemdef->get(name).stack_max;
+ return (max >= 0) ? max : 0;
}
- /*
- Other properties
- */
-
- u16 getStackMax() const;
- bool isUsable() const;
- bool isCookable() const;
- InventoryItem *createCookResult() const;
- float getCookTime() const;
- float getBurnTime() const;
- s16 getDropCount() const;
- bool areLiquidsPointable() const;
-
- bool dropOrPlace(ServerEnvironment *env,
- ServerActiveObject *dropper,
- v3f pos, bool place, s16 count);
- bool use(ServerEnvironment *env,
- ServerActiveObject *user,
- const PointedThing& pointed);
-
- /*
- Special methods
- */
- std::string getSubName()
+ // Number of items that can be added to this stack
+ u16 freeSpace(IItemDefManager *itemdef) const
{
- return m_subname;
+ u16 max = getStackMax(itemdef);
+ if(count > max)
+ return 0;
+ return max - count;
}
-private:
- std::string m_subname;
-};
-class ToolItem : public InventoryItem
-{
-public:
- ToolItem(IGameDef *gamedef, std::string toolname, u16 wear);
- /*
- Implementation interface
- */
- virtual const char* getName() const
- {
- return "ToolItem";
- }
- virtual void serialize(std::ostream &os) const
- {
- os<<"tool";
- os<<" \"";
- os<<m_toolname;
- os<<"\" ";
- os<<m_wear;
- }
- virtual InventoryItem* clone()
+ // Returns false if item is not known and cannot be used
+ bool isKnown(IItemDefManager *itemdef) const
{
- return new ToolItem(m_gamedef, m_toolname, m_wear);
+ return itemdef->isKnown(name);
}
- std::string getImageBasename() const;
-#ifndef SERVER
- video::ITexture * getImage() const;
- video::ITexture * getImageRaw() const;
-#endif
-
- std::string getText()
+ // Returns a pointer to the item definition struct,
+ // or a fallback one (name="unknown") if the item is unknown.
+ const ItemDefinition& getDefinition(
+ IItemDefManager *itemdef) const
{
- return "";
+ return itemdef->get(name);
}
-
- virtual bool isKnown() const;
- virtual bool isSubsetOf(const InventoryItem *other) const
+ // Get tool digging properties, or those of the hand if not a tool
+ const ToolDiggingProperties& getToolDiggingProperties(
+ IItemDefManager *itemdef) const
{
- if(std::string(other->getName()) != "ToolItem")
- return false;
- ToolItem *m = (ToolItem*)other;
- if(m->m_toolname != m_toolname)
- return false;
- return m_wear <= m->m_wear;
- }
- virtual bool removeOther(const InventoryItem *other)
- {
- if(!other->isSubsetOf(this))
- return false;
- ToolItem *m = (ToolItem*)other;
- m_wear -= m->m_wear;
- return true;
+ ToolDiggingProperties *prop;
+ prop = itemdef->get(name).tool_digging_properties;
+ if(prop == NULL)
+ prop = itemdef->get("").tool_digging_properties;
+ assert(prop != NULL);
+ return *prop;
}
- /*
- Special methods
- */
- std::string getToolName()
- {
- return m_toolname;
- }
- u16 getWear()
+ // Wear out (only tools)
+ // Returns true if the item is (was) a tool
+ bool addWear(s32 amount, IItemDefManager *itemdef)
{
- return m_wear;
- }
- // Returns true if weared out
- bool addWear(u16 add)
- {
- if(m_wear >= 65535 - add)
+ if(getDefinition(itemdef).type == ITEM_TOOL)
{
- m_wear = 65535;
+ if(amount > 65535 - wear)
+ clear();
+ else if(amount < -wear)
+ wear = 0;
+ else
+ wear += amount;
return true;
}
else
{
- m_wear += add;
return false;
}
}
-private:
- std::string m_toolname;
- u16 m_wear;
+
+ // If possible, adds newitem to this item.
+ // If cannot be added at all, returns the item back.
+ // If can be added partly, decremented item is returned back.
+ // If can be added fully, empty item is returned.
+ ItemStack addItem(const ItemStack &newitem,
+ IItemDefManager *itemdef);
+
+ // Checks whether newitem could be added.
+ // If restitem is non-NULL, it receives the part of newitem that
+ // would be left over after adding.
+ bool itemFits(const ItemStack &newitem,
+ ItemStack *restitem, // may be NULL
+ IItemDefManager *itemdef) const;
+
+ // Takes some items.
+ // If there are not enough, takes as many as it can.
+ // Returns empty item if couldn't take any.
+ ItemStack takeItem(u32 takecount);
+
+ // Similar to takeItem, but keeps this ItemStack intact.
+ ItemStack peekItem(u32 peekcount) const;
+
+ /*
+ Properties
+ */
+ std::string name;
+ u16 count;
+ u16 wear;
+ std::string metadata;
};
class InventoryList
{
public:
- InventoryList(std::string name, u32 size);
+ InventoryList(std::string name, u32 size, IItemDefManager *itemdef);
~InventoryList();
void clearItems();
void setSize(u32 newsize);
void serialize(std::ostream &os) const;
- void deSerialize(std::istream &is, IGameDef *gamedef);
+ void deSerialize(std::istream &is);
InventoryList(const InventoryList &other);
InventoryList & operator = (const InventoryList &other);
const std::string &getName() const;
- u32 getSize();
+ u32 getSize() const;
// Count used slots
- u32 getUsedSlots();
- u32 getFreeSlots();
-
- /*bool getDirty(){ return m_dirty; }
- void setDirty(bool dirty=true){ m_dirty = dirty; }*/
-
- // Get pointer to item
- const InventoryItem * getItem(u32 i) const;
- InventoryItem * getItem(u32 i);
- // Returns old item (or NULL). Parameter can be NULL.
- InventoryItem * changeItem(u32 i, InventoryItem *newitem);
+ u32 getUsedSlots() const;
+ u32 getFreeSlots() const;
+
+ // Get reference to item
+ const ItemStack& getItem(u32 i) const;
+ ItemStack& getItem(u32 i);
+ // Returns old item. Parameter can be an empty item.
+ ItemStack changeItem(u32 i, const ItemStack &newitem);
// Delete item
void deleteItem(u32 i);
- // Adds an item to a suitable place. Returns leftover item.
- // If all went into the list, returns NULL.
- InventoryItem * addItem(InventoryItem *newitem);
+ // Adds an item to a suitable place. Returns leftover item (possibly empty).
+ ItemStack addItem(const ItemStack &newitem);
// If possible, adds item to given slot.
// If cannot be added at all, returns the item back.
// If can be added partly, decremented item is returned back.
- // If can be added fully, NULL is returned.
- InventoryItem * addItem(u32 i, InventoryItem *newitem);
+ // If can be added fully, empty item is returned.
+ ItemStack addItem(u32 i, const ItemStack &newitem);
// Checks whether the item could be added to the given slot
- bool itemFits(const u32 i, const InventoryItem *newitem);
+ // If restitem is non-NULL, it receives the part of newitem that
+ // would be left over after adding.
+ bool itemFits(const u32 i, const ItemStack &newitem,
+ ItemStack *restitem = NULL) const;
// Checks whether there is room for a given item
- bool roomForItem(const InventoryItem *item);
+ bool roomForItem(const ItemStack &item) const;
+
+ // Checks whether the given count of the given item name
+ // exists in this inventory list.
+ bool containsItem(const ItemStack &item) const;
- // Checks whether there is room for a given item aftr it has been cooked
- bool roomForCookedItem(const InventoryItem *item);
+ // Removes the given count of the given item name from
+ // this inventory list. Walks the list in reverse order.
+ // If not as many items exist as requested, removes as
+ // many as possible.
+ // Returns the items that were actually removed.
+ ItemStack removeItem(const ItemStack &item);
// Takes some items from a slot.
// If there are not enough, takes as many as it can.
- // Returns NULL if couldn't take any.
- InventoryItem * takeItem(u32 i, u32 count);
+ // Returns empty item if couldn't take any.
+ ItemStack takeItem(u32 i, u32 takecount);
- // Decrements amount of every material item
- void decrementMaterials(u16 count);
+ // Similar to takeItem, but keeps the slot intact.
+ ItemStack peekItem(u32 i, u32 peekcount) const;
- void print(std::ostream &o);
-
private:
- core::array<InventoryItem*> m_items;
+ std::vector<ItemStack> m_items;
u32 m_size;
std::string m_name;
- //bool m_dirty;
+ IItemDefManager *m_itemdef;
};
class Inventory
@@ -486,20 +247,19 @@ public:
void clear();
- Inventory();
+ Inventory(IItemDefManager *itemdef);
Inventory(const Inventory &other);
Inventory & operator = (const Inventory &other);
void serialize(std::ostream &os) const;
- void deSerialize(std::istream &is, IGameDef *gamedef);
+ void deSerialize(std::istream &is);
InventoryList * addList(const std::string &name, u32 size);
InventoryList * getList(const std::string &name);
const InventoryList * getList(const std::string &name) const;
bool deleteList(const std::string &name);
- // A shorthand for adding items.
- // Returns NULL if the item was fully added, leftover otherwise.
- InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
+ // A shorthand for adding items. Returns leftover item (possibly empty).
+ ItemStack addItem(const std::string &listname, const ItemStack &newitem)
{
InventoryList *list = getList(listname);
if(list == NULL)
@@ -511,7 +271,8 @@ private:
// -1 if not found
const s32 getListIndex(const std::string &name) const;
- core::array<InventoryList*> m_lists;
+ std::vector<InventoryList*> m_lists;
+ IItemDefManager *m_itemdef;
};
#endif
diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp
index 195438d26..0149fd9ab 100644
--- a/src/inventorymanager.cpp
+++ b/src/inventorymanager.cpp
@@ -18,73 +18,91 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "inventorymanager.h"
-#include "serverremoteplayer.h"
#include "log.h"
-#include "mapblock.h" // getNodeBlockPos
+#include "environment.h"
+#include "scriptapi.h"
+#include "serverobject.h"
+#include "main.h" // for g_settings
+#include "settings.h"
+#include "utility.h"
/*
- InventoryManager
+ InventoryLocation
*/
-// Wrapper for old code
-Inventory* InventoryManager::getInventory(InventoryContext *c, std::string id)
+std::string InventoryLocation::dump() const
{
- if(id == "current_player")
- {
- assert(c->current_player);
- InventoryLocation loc;
- loc.setPlayer(c->current_player->getName());
- return getInventory(loc);
- }
-
- Strfnd fn(id);
- std::string id0 = fn.next(":");
-
- if(id0 == "nodemeta")
- {
- v3s16 p;
- p.X = stoi(fn.next(","));
- p.Y = stoi(fn.next(","));
- p.Z = stoi(fn.next(","));
+ std::ostringstream os(std::ios::binary);
+ serialize(os);
+ return os.str();
+}
- InventoryLocation loc;
- loc.setNodeMeta(p);
- return getInventory(loc);
+void InventoryLocation::serialize(std::ostream &os) const
+{
+ switch(type){
+ case InventoryLocation::UNDEFINED:
+ {
+ os<<"undefined";
}
-
- errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
- return NULL;
+ break;
+ case InventoryLocation::CURRENT_PLAYER:
+ {
+ os<<"current_player";
+ }
+ break;
+ case InventoryLocation::PLAYER:
+ {
+ os<<"player:"<<name;
+ }
+ break;
+ case InventoryLocation::NODEMETA:
+ {
+ os<<"nodemeta:"<<p.X<<","<<p.Y<<","<<p.Z;
+ }
+ break;
+ default:
+ assert(0);
+ }
}
-// Wrapper for old code
-void InventoryManager::inventoryModified(InventoryContext *c, std::string id)
+
+void InventoryLocation::deSerialize(std::istream &is)
{
- if(id == "current_player")
+ std::string tname;
+ std::getline(is, tname, ':');
+ if(tname == "undefined")
{
- assert(c->current_player);
- InventoryLocation loc;
- loc.setPlayer(c->current_player->getName());
- setInventoryModified(loc);
- return;
+ type = InventoryLocation::UNDEFINED;
}
-
- Strfnd fn(id);
- std::string id0 = fn.next(":");
-
- if(id0 == "nodemeta")
+ else if(tname == "current_player")
+ {
+ type = InventoryLocation::CURRENT_PLAYER;
+ }
+ else if(tname == "player")
+ {
+ type = InventoryLocation::PLAYER;
+ std::getline(is, name, '\n');
+ }
+ else if(tname == "nodemeta")
{
- v3s16 p;
+ type = InventoryLocation::NODEMETA;
+ std::string pos;
+ std::getline(is, pos, '\n');
+ Strfnd fn(pos);
p.X = stoi(fn.next(","));
p.Y = stoi(fn.next(","));
p.Z = stoi(fn.next(","));
- v3s16 blockpos = getNodeBlockPos(p);
-
- InventoryLocation loc;
- loc.setNodeMeta(p);
- setInventoryModified(loc);
- return;
}
+ else
+ {
+ infostream<<"Unknown InventoryLocation type=\""<<tname<<"\""<<std::endl;
+ throw SerializationError("Unknown InventoryLocation type");
+ }
+}
- errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
+void InventoryLocation::deSerialize(std::string s)
+{
+ std::istringstream is(s, std::ios::binary);
+ deSerialize(is);
}
/*
@@ -110,14 +128,6 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
return a;
}
-static std::string describeC(const struct InventoryContext *c)
-{
- if(c->current_player == NULL)
- return "current_player=NULL";
- else
- return std::string("current_player=") + c->current_player->getName();
-}
-
IMoveAction::IMoveAction(std::istream &is)
{
std::string ts;
@@ -125,14 +135,16 @@ IMoveAction::IMoveAction(std::istream &is)
std::getline(is, ts, ' ');
count = stoi(ts);
- std::getline(is, from_inv, ' ');
+ std::getline(is, ts, ' ');
+ from_inv.deSerialize(ts);
std::getline(is, from_list, ' ');
std::getline(is, ts, ' ');
from_i = stoi(ts);
- std::getline(is, to_inv, ' ');
+ std::getline(is, ts, ' ');
+ to_inv.deSerialize(ts);
std::getline(is, to_list, ' ');
@@ -140,22 +152,21 @@ IMoveAction::IMoveAction(std::istream &is)
to_i = stoi(ts);
}
-void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
- ServerEnvironment *env)
+void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player)
{
- Inventory *inv_from = mgr->getInventory(c, from_inv);
- Inventory *inv_to = mgr->getInventory(c, to_inv);
+ Inventory *inv_from = mgr->getInventory(from_inv);
+ Inventory *inv_to = mgr->getInventory(to_inv);
if(!inv_from){
infostream<<"IMoveAction::apply(): FAIL: source inventory not found: "
- <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
- <<", to_inv=\""<<to_inv<<"\""<<std::endl;
+ <<"from_inv=\""<<from_inv.dump()<<"\""
+ <<", to_inv=\""<<to_inv.dump()<<"\""<<std::endl;
return;
}
if(!inv_to){
infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: "
- "context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
- <<", to_inv=\""<<to_inv<<"\""<<std::endl;
+ <<"from_inv=\""<<from_inv.dump()<<"\""
+ <<", to_inv=\""<<to_inv.dump()<<"\""<<std::endl;
return;
}
@@ -167,20 +178,20 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
*/
if(!list_from){
infostream<<"IMoveAction::apply(): FAIL: source list not found: "
- <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
+ <<"from_inv=\""<<from_inv.dump()<<"\""
<<", from_list=\""<<from_list<<"\""<<std::endl;
return;
}
if(!list_to){
infostream<<"IMoveAction::apply(): FAIL: destination list not found: "
- <<"context=["<<describeC(c)<<"], to_inv=\""<<to_inv<<"\""
+ <<"to_inv=\""<<to_inv.dump()<<"\""
<<", to_list=\""<<to_list<<"\""<<std::endl;
return;
}
- if(list_from->getItem(from_i) == NULL)
+ if(list_from->getItem(from_i).empty())
{
infostream<<"IMoveAction::apply(): FAIL: source item not found: "
- <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
+ <<"from_inv=\""<<from_inv.dump()<<"\""
<<", from_list=\""<<from_list<<"\""
<<" from_i="<<from_i<<std::endl;
return;
@@ -191,27 +202,28 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
if(inv_from == inv_to && list_from == list_to && from_i == to_i)
{
infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
- <<"are the same: inv=\""<<from_inv<<"\" list=\""<<from_list
+ <<"are the same: inv=\""<<from_inv.dump()
+ <<"\" list=\""<<from_list
<<"\" i="<<from_i<<std::endl;
return;
}
// Take item from source list
- InventoryItem *item1 = NULL;
+ ItemStack item1;
if(count == 0)
- item1 = list_from->changeItem(from_i, NULL);
+ item1 = list_from->changeItem(from_i, ItemStack());
else
item1 = list_from->takeItem(from_i, count);
// Try to add the item to destination list
- InventoryItem *olditem = item1;
+ int oldcount = item1.count;
item1 = list_to->addItem(to_i, item1);
// If something is returned, the item was not fully added
- if(item1 != NULL)
+ if(!item1.empty())
{
// If olditem is returned, nothing was added.
- bool nothing_added = (item1 == olditem);
+ bool nothing_added = (item1.count == oldcount);
// If something else is returned, part of the item was left unadded.
// Add the other part back to the source item
@@ -222,24 +234,24 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
if(nothing_added)
{
// Take item from source list
- item1 = list_from->changeItem(from_i, NULL);
+ item1 = list_from->changeItem(from_i, ItemStack());
// Adding was not possible, swap the items.
- InventoryItem *item2 = list_to->changeItem(to_i, item1);
+ ItemStack item2 = list_to->changeItem(to_i, item1);
// Put item from destination list to the source list
list_from->changeItem(from_i, item2);
}
}
- mgr->inventoryModified(c, from_inv);
- if(from_inv != to_inv)
- mgr->inventoryModified(c, to_inv);
+ mgr->setInventoryModified(from_inv);
+ if(inv_from != inv_to)
+ mgr->setInventoryModified(to_inv);
infostream<<"IMoveAction::apply(): moved at "
- <<"["<<describeC(c)<<"]"
- <<" from inv=\""<<from_inv<<"\""
+ <<" count="<<count<<"\""
+ <<" from inv=\""<<from_inv.dump()<<"\""
<<" list=\""<<from_list<<"\""
<<" i="<<from_i
- <<" to inv=\""<<to_inv<<"\""
+ <<" to inv=\""<<to_inv.dump()<<"\""
<<" list=\""<<to_list<<"\""
<<" i="<<to_i
<<std::endl;
@@ -252,7 +264,8 @@ IDropAction::IDropAction(std::istream &is)
std::getline(is, ts, ' ');
count = stoi(ts);
- std::getline(is, from_inv, ' ');
+ std::getline(is, ts, ' ');
+ from_inv.deSerialize(ts);
std::getline(is, from_list, ' ');
@@ -260,27 +273,13 @@ IDropAction::IDropAction(std::istream &is)
from_i = stoi(ts);
}
-void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
- ServerEnvironment *env)
+void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player)
{
- if(c->current_player == NULL){
- infostream<<"IDropAction::apply(): FAIL: current_player is NULL"<<std::endl;
- return;
- }
-
- // Do NOT cast directly to ServerActiveObject*, it breaks
- // because of multiple inheritance.
- ServerActiveObject *dropper =
- static_cast<ServerActiveObject*>(
- static_cast<ServerRemotePlayer*>(
- c->current_player
- ));
-
- Inventory *inv_from = mgr->getInventory(c, from_inv);
+ Inventory *inv_from = mgr->getInventory(from_inv);
if(!inv_from){
infostream<<"IDropAction::apply(): FAIL: source inventory not found: "
- <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""<<std::endl;
+ <<"from_inv=\""<<from_inv.dump()<<"\""<<std::endl;
return;
}
@@ -291,254 +290,35 @@ void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
*/
if(!list_from){
infostream<<"IDropAction::apply(): FAIL: source list not found: "
- <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
- <<", from_list=\""<<from_list<<"\""<<std::endl;
+ <<"from_inv=\""<<from_inv.dump()<<"\""<<std::endl;
return;
}
- InventoryItem *item = list_from->getItem(from_i);
- if(item == NULL)
+ if(list_from->getItem(from_i).empty())
{
infostream<<"IDropAction::apply(): FAIL: source item not found: "
- <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
+ <<"from_inv=\""<<from_inv.dump()<<"\""
<<", from_list=\""<<from_list<<"\""
<<" from_i="<<from_i<<std::endl;
return;
}
- v3f pos = dropper->getBasePosition();
- pos.Y += 0.5*BS;
-
- s16 count2 = count;
- if(count2 == 0)
- count2 = -1;
-
/*
Drop the item
*/
- bool remove = item->dropOrPlace(env, dropper, pos, false, count2);
- if(remove)
- list_from->deleteItem(from_i);
-
- mgr->inventoryModified(c, from_inv);
+ ItemStack item = list_from->getItem(from_i);
+ if(scriptapi_item_on_drop(player->getEnv()->getLua(), item, player,
+ player->getBasePosition() + v3f(0,1,0)))
+ {
+ // Apply returned ItemStack
+ if(g_settings->getBool("creative_mode") == false
+ || from_inv.type != InventoryLocation::PLAYER)
+ list_from->changeItem(from_i, item);
+ mgr->setInventoryModified(from_inv);
+ }
infostream<<"IDropAction::apply(): dropped "
- <<"["<<describeC(c)<<"]"
- <<" from inv=\""<<from_inv<<"\""
+ <<" from inv=\""<<from_inv.dump()<<"\""
<<" list=\""<<from_list<<"\""
<<" i="<<from_i
<<std::endl;
}
-
-/*
- Craft checking system
-*/
-
-bool ItemSpec::checkItem(const InventoryItem *item) const
-{
- if(type == ITEM_NONE)
- {
- // Has to be no item
- if(item != NULL)
- return false;
- return true;
- }
-
- // There should be an item
- if(item == NULL)
- return false;
-
- std::string itemname = item->getName();
-
- if(type == ITEM_MATERIAL)
- {
- if(itemname != "MaterialItem")
- return false;
- MaterialItem *mitem = (MaterialItem*)item;
- if(num != 65535){
- if(mitem->getMaterial() != num)
- return false;
- } else {
- if(mitem->getNodeName() != name)
- return false;
- }
- }
- else if(type == ITEM_CRAFT)
- {
- if(itemname != "CraftItem")
- return false;
- CraftItem *mitem = (CraftItem*)item;
- if(mitem->getSubName() != name)
- return false;
- }
- else if(type == ITEM_TOOL)
- {
- // Not supported yet
- assert(0);
- }
- else if(type == ITEM_MBO)
- {
- // Not supported yet
- assert(0);
- }
- else
- {
- // Not supported yet
- assert(0);
- }
- return true;
-}
-
-bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *specs)
-{
- u16 items_min_x = 100;
- u16 items_max_x = 100;
- u16 items_min_y = 100;
- u16 items_max_y = 100;
- for(u16 y=0; y<3; y++)
- for(u16 x=0; x<3; x++)
- {
- if(items[y*3 + x] == NULL)
- continue;
- if(items_min_x == 100 || x < items_min_x)
- items_min_x = x;
- if(items_min_y == 100 || y < items_min_y)
- items_min_y = y;
- if(items_max_x == 100 || x > items_max_x)
- items_max_x = x;
- if(items_max_y == 100 || y > items_max_y)
- items_max_y = y;
- }
- // No items at all, just return false
- if(items_min_x == 100)
- return false;
-
- u16 items_w = items_max_x - items_min_x + 1;
- u16 items_h = items_max_y - items_min_y + 1;
-
- u16 specs_min_x = 100;
- u16 specs_max_x = 100;
- u16 specs_min_y = 100;
- u16 specs_max_y = 100;
- for(u16 y=0; y<3; y++)
- for(u16 x=0; x<3; x++)
- {
- if(specs[y*3 + x].type == ITEM_NONE)
- continue;
- if(specs_min_x == 100 || x < specs_min_x)
- specs_min_x = x;
- if(specs_min_y == 100 || y < specs_min_y)
- specs_min_y = y;
- if(specs_max_x == 100 || x > specs_max_x)
- specs_max_x = x;
- if(specs_max_y == 100 || y > specs_max_y)
- specs_max_y = y;
- }
- // No specs at all, just return false
- if(specs_min_x == 100)
- return false;
-
- u16 specs_w = specs_max_x - specs_min_x + 1;
- u16 specs_h = specs_max_y - specs_min_y + 1;
-
- // Different sizes
- if(items_w != specs_w || items_h != specs_h)
- return false;
-
- for(u16 y=0; y<specs_h; y++)
- for(u16 x=0; x<specs_w; x++)
- {
- u16 items_x = items_min_x + x;
- u16 items_y = items_min_y + y;
- u16 specs_x = specs_min_x + x;
- u16 specs_y = specs_min_y + y;
- const InventoryItem *item = items[items_y * 3 + items_x];
- const ItemSpec &spec = specs[specs_y * 3 + specs_x];
-
- if(spec.checkItem(item) == false)
- return false;
- }
-
- return true;
-}
-
-bool checkItemCombination(const InventoryItem * const * items,
- const InventoryItem * const * specs)
-{
- u16 items_min_x = 100;
- u16 items_max_x = 100;
- u16 items_min_y = 100;
- u16 items_max_y = 100;
- for(u16 y=0; y<3; y++)
- for(u16 x=0; x<3; x++)
- {
- if(items[y*3 + x] == NULL)
- continue;
- if(items_min_x == 100 || x < items_min_x)
- items_min_x = x;
- if(items_min_y == 100 || y < items_min_y)
- items_min_y = y;
- if(items_max_x == 100 || x > items_max_x)
- items_max_x = x;
- if(items_max_y == 100 || y > items_max_y)
- items_max_y = y;
- }
- // No items at all, just return false
- if(items_min_x == 100)
- return false;
-
- u16 items_w = items_max_x - items_min_x + 1;
- u16 items_h = items_max_y - items_min_y + 1;
-
- u16 specs_min_x = 100;
- u16 specs_max_x = 100;
- u16 specs_min_y = 100;
- u16 specs_max_y = 100;
- for(u16 y=0; y<3; y++)
- for(u16 x=0; x<3; x++)
- {
- if(specs[y*3 + x] == NULL)
- continue;
- if(specs_min_x == 100 || x < specs_min_x)
- specs_min_x = x;
- if(specs_min_y == 100 || y < specs_min_y)
- specs_min_y = y;
- if(specs_max_x == 100 || x > specs_max_x)
- specs_max_x = x;
- if(specs_max_y == 100 || y > specs_max_y)
- specs_max_y = y;
- }
- // No specs at all, just return false
- if(specs_min_x == 100)
- return false;
-
- u16 specs_w = specs_max_x - specs_min_x + 1;
- u16 specs_h = specs_max_y - specs_min_y + 1;
-
- // Different sizes
- if(items_w != specs_w || items_h != specs_h)
- return false;
-
- for(u16 y=0; y<specs_h; y++)
- for(u16 x=0; x<specs_w; x++)
- {
- u16 items_x = items_min_x + x;
- u16 items_y = items_min_y + y;
- u16 specs_x = specs_min_x + x;
- u16 specs_y = specs_min_y + y;
- const InventoryItem *item = items[items_y * 3 + items_x];
- const InventoryItem *spec = specs[specs_y * 3 + specs_x];
-
- if(item == NULL && spec == NULL)
- continue;
- if(item == NULL && spec != NULL)
- return false;
- if(item != NULL && spec == NULL)
- return false;
- if(!spec->isSubsetOf(item))
- return false;
- }
-
- return true;
-}
-
-
diff --git a/src/inventorymanager.h b/src/inventorymanager.h
index 4abe5e73d..f6ae4feba 100644
--- a/src/inventorymanager.h
+++ b/src/inventorymanager.h
@@ -21,19 +21,34 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define INVENTORYMANAGER_HEADER
#include "inventory.h"
+#include <iostream>
+#include <string>
+class ServerActiveObject;
-// Should probably somehow replace InventoryContext over time
struct InventoryLocation
{
enum Type{
UNDEFINED,
+ CURRENT_PLAYER,
PLAYER,
- NODEMETA
+ NODEMETA,
} type;
std::string name; // PLAYER
v3s16 p; // NODEMETA
+ InventoryLocation()
+ {
+ setUndefined();
+ }
+ void setUndefined()
+ {
+ type = UNDEFINED;
+ }
+ void setCurrentPlayer()
+ {
+ type = CURRENT_PLAYER;
+ }
void setPlayer(const std::string &name_)
{
type = PLAYER;
@@ -44,17 +59,17 @@ struct InventoryLocation
type = NODEMETA;
p = p_;
}
-};
-class Player;
+ void applyCurrentPlayer(const std::string &name_)
+ {
+ if(type == CURRENT_PLAYER)
+ setPlayer(name_);
+ }
-struct InventoryContext
-{
- Player *current_player;
-
- InventoryContext():
- current_player(NULL)
- {}
+ std::string dump() const;
+ void serialize(std::ostream &os) const;
+ void deSerialize(std::istream &is);
+ void deSerialize(std::string s);
};
struct InventoryAction;
@@ -68,18 +83,11 @@ public:
// Get an inventory or set it modified (so it will be updated over
// network or so)
virtual Inventory* getInventory(const InventoryLocation &loc){return NULL;}
+ virtual std::string getInventoryOwner(const InventoryLocation &loc){return "";}
virtual void setInventoryModified(const InventoryLocation &loc){}
// Used on the client to send an action to the server
virtual void inventoryAction(InventoryAction *a){}
-
- // (Deprecated; these wrap to the latter ones)
- // Get a pointer to an inventory specified by id. id can be:
- // - "current_player"
- // - "nodemeta:X,Y,Z"
- Inventory* getInventory(InventoryContext *c, std::string id);
- // Used on the server by InventoryAction::apply and other stuff
- void inventoryModified(InventoryContext *c, std::string id);
};
#define IACTION_MOVE 0
@@ -91,18 +99,17 @@ struct InventoryAction
virtual u16 getType() const = 0;
virtual void serialize(std::ostream &os) const = 0;
- virtual void apply(InventoryContext *c, InventoryManager *mgr,
- ServerEnvironment *env) = 0;
+ virtual void apply(InventoryManager *mgr, ServerActiveObject *player) = 0;
};
struct IMoveAction : public InventoryAction
{
// count=0 means "everything"
u16 count;
- std::string from_inv;
+ InventoryLocation from_inv;
std::string from_list;
s16 from_i;
- std::string to_inv;
+ InventoryLocation to_inv;
std::string to_list;
s16 to_i;
@@ -124,23 +131,22 @@ struct IMoveAction : public InventoryAction
{
os<<"Move ";
os<<count<<" ";
- os<<from_inv<<" ";
+ os<<from_inv.dump()<<" ";
os<<from_list<<" ";
os<<from_i<<" ";
- os<<to_inv<<" ";
+ os<<to_inv.dump()<<" ";
os<<to_list<<" ";
os<<to_i;
}
- void apply(InventoryContext *c, InventoryManager *mgr,
- ServerEnvironment *env);
+ void apply(InventoryManager *mgr, ServerActiveObject *player);
};
struct IDropAction : public InventoryAction
{
// count=0 means "everything"
u16 count;
- std::string from_inv;
+ InventoryLocation from_inv;
std::string from_list;
s16 from_i;
@@ -161,68 +167,13 @@ struct IDropAction : public InventoryAction
{
os<<"Drop ";
os<<count<<" ";
- os<<from_inv<<" ";
+ os<<from_inv.dump()<<" ";
os<<from_list<<" ";
os<<from_i;
}
- void apply(InventoryContext *c, InventoryManager *mgr,
- ServerEnvironment *env);
-};
-
-/*
- Craft checking system
-*/
-
-enum ItemSpecType
-{
- ITEM_NONE,
- ITEM_MATERIAL,
- ITEM_CRAFT,
- ITEM_TOOL,
- ITEM_MBO
-};
-
-struct ItemSpec
-{
- enum ItemSpecType type;
- // Only other one of these is used
- std::string name;
- u16 num;
-
- ItemSpec():
- type(ITEM_NONE)
- {
- }
- ItemSpec(enum ItemSpecType a_type, std::string a_name):
- type(a_type),
- name(a_name),
- num(65535)
- {
- }
- ItemSpec(enum ItemSpecType a_type, u16 a_num):
- type(a_type),
- name(""),
- num(a_num)
- {
- }
-
- bool checkItem(const InventoryItem *item) const;
+ void apply(InventoryManager *mgr, ServerActiveObject *player);
};
-/*
- items: a pointer to an array of 9 pointers to items
- specs: a pointer to an array of 9 ItemSpecs
-*/
-bool checkItemCombination(const InventoryItem * const*items, const ItemSpec *specs);
-
-/*
- items: a pointer to an array of 9 pointers to items
- specs: a pointer to an array of 9 pointers to items
-*/
-bool checkItemCombination(const InventoryItem * const * items,
- const InventoryItem * const * specs);
-
-
#endif
diff --git a/src/irrlichttypes.h b/src/irrlichttypes.h
index bc17694fc..67c96a653 100644
--- a/src/irrlichttypes.h
+++ b/src/irrlichttypes.h
@@ -39,6 +39,8 @@ typedef core::vector2d<s32> v2s32;
typedef core::vector2d<u32> v2u32;
typedef core::vector2d<f32> v2f32;
+typedef core::aabbox3d<f32> aabb3f;
+
#ifdef _MSC_VER
// Windows
typedef unsigned long long u64;
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
new file mode 100644
index 000000000..aa888bbdf
--- /dev/null
+++ b/src/itemdef.cpp
@@ -0,0 +1,502 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2011 Kahrl <kahrl@gmx.net>
+
+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 "itemdef.h"
+
+#include "gamedef.h"
+#include "nodedef.h"
+#include "materials.h"
+#include "inventory.h"
+#ifndef SERVER
+#include "mapblock_mesh.h"
+#include "mesh.h"
+#include "tile.h"
+#endif
+#include "log.h"
+#include "utility.h"
+#include <map>
+#include <set>
+
+/*
+ ItemDefinition
+*/
+ItemDefinition::ItemDefinition()
+{
+ resetInitial();
+}
+
+ItemDefinition::ItemDefinition(const ItemDefinition &def)
+{
+ resetInitial();
+ *this = def;
+}
+
+ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
+{
+ if(this == &def)
+ return *this;
+
+ reset();
+
+ type = def.type;
+ name = def.name;
+ description = def.description;
+ inventory_image = def.inventory_image;
+ wield_image = def.wield_image;
+ wield_scale = def.wield_scale;
+ stack_max = def.stack_max;
+ usable = def.usable;
+ liquids_pointable = def.liquids_pointable;
+ if(def.tool_digging_properties)
+ {
+ tool_digging_properties = new ToolDiggingProperties(
+ *def.tool_digging_properties);
+ }
+#ifndef SERVER
+ inventory_texture = def.inventory_texture;
+ if(def.wield_mesh)
+ {
+ wield_mesh = def.wield_mesh;
+ wield_mesh->grab();
+ }
+#endif
+ return *this;
+}
+
+ItemDefinition::~ItemDefinition()
+{
+ reset();
+}
+
+void ItemDefinition::resetInitial()
+{
+ // Initialize pointers to NULL so reset() does not delete undefined pointers
+ tool_digging_properties = NULL;
+#ifndef SERVER
+ inventory_texture = NULL;
+ wield_mesh = NULL;
+#endif
+ reset();
+}
+
+void ItemDefinition::reset()
+{
+ type = ITEM_NONE;
+ name = "";
+ description = "";
+ inventory_image = "";
+ wield_image = "";
+ wield_scale = v3f(1.0, 1.0, 1.0);
+ stack_max = 99;
+ usable = false;
+ liquids_pointable = false;
+ if(tool_digging_properties)
+ {
+ delete tool_digging_properties;
+ tool_digging_properties = NULL;
+ }
+
+#ifndef SERVER
+ inventory_texture = NULL;
+ if(wield_mesh)
+ {
+ wield_mesh->drop();
+ wield_mesh = NULL;
+ }
+#endif
+}
+
+void ItemDefinition::serialize(std::ostream &os) const
+{
+ writeU8(os, 0); // version
+ writeU8(os, type);
+ os<<serializeString(name);
+ os<<serializeString(description);
+ os<<serializeString(inventory_image);
+ os<<serializeString(wield_image);
+ writeV3F1000(os, wield_scale);
+ writeS16(os, stack_max);
+ writeU8(os, usable);
+ writeU8(os, liquids_pointable);
+ std::string tool_digging_properties_s = "";
+ if(tool_digging_properties)
+ {
+ std::ostringstream tmp_os(std::ios::binary);
+ tool_digging_properties->serialize(tmp_os);
+ tool_digging_properties_s = tmp_os.str();
+ }
+ os<<serializeString(tool_digging_properties_s);
+}
+
+void ItemDefinition::deSerialize(std::istream &is)
+{
+ // Reset everything
+ reset();
+
+ // Deserialize
+ int version = readU8(is);
+ if(version != 0)
+ 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_digging_properties_s = deSerializeString(is);
+ if(!tool_digging_properties_s.empty())
+ {
+ std::istringstream tmp_is(tool_digging_properties_s, std::ios::binary);
+ tool_digging_properties = new ToolDiggingProperties;
+ tool_digging_properties->deSerialize(tmp_is);
+ }
+}
+
+/*
+ CItemDefManager
+*/
+
+// SUGG: Support chains of aliases?
+
+class CItemDefManager: public IWritableItemDefManager
+{
+public:
+ CItemDefManager()
+ {
+ clear();
+ }
+ virtual ~CItemDefManager()
+ {
+ }
+ virtual const ItemDefinition& get(const std::string &name_) const
+ {
+ // Convert name according to possible alias
+ std::string name = getAlias(name_);
+ // Get the definition
+ std::map<std::string, ItemDefinition*>::const_iterator i;
+ i = m_item_definitions.find(name);
+ if(i == m_item_definitions.end())
+ i = m_item_definitions.find("unknown");
+ assert(i != m_item_definitions.end());
+ return *(i->second);
+ }
+ virtual std::string getAlias(const std::string &name) const
+ {
+ std::map<std::string, std::string>::const_iterator i;
+ i = m_aliases.find(name);
+ if(i != m_aliases.end())
+ return i->second;
+ return name;
+ }
+ virtual std::set<std::string> getAll() const
+ {
+ std::set<std::string> result;
+ for(std::map<std::string, ItemDefinition*>::const_iterator
+ i = m_item_definitions.begin();
+ i != m_item_definitions.end(); i++)
+ {
+ result.insert(i->first);
+ }
+ for(std::map<std::string, std::string>::const_iterator
+ i = m_aliases.begin();
+ i != m_aliases.end(); i++)
+ {
+ result.insert(i->first);
+ }
+ return result;
+ }
+ virtual bool isKnown(const std::string &name_) const
+ {
+ // Convert name according to possible alias
+ std::string name = getAlias(name_);
+ // Get the definition
+ std::map<std::string, ItemDefinition*>::const_iterator i;
+ return m_item_definitions.find(name) != m_item_definitions.end();
+ }
+ void clear()
+ {
+ for(std::map<std::string, ItemDefinition*>::const_iterator
+ i = m_item_definitions.begin();
+ i != m_item_definitions.end(); i++)
+ {
+ delete i->second;
+ }
+ m_item_definitions.clear();
+ m_aliases.clear();
+
+ // Add the four builtin items:
+ // "" is the hand
+ // "unknown" is returned whenever an undefined item is accessed
+ // "air" is the air node
+ // "ignore" is the ignore node
+
+ ItemDefinition* hand_def = new ItemDefinition;
+ hand_def->name = "";
+ hand_def->wield_image = "wieldhand.png";
+ hand_def->tool_digging_properties = new ToolDiggingProperties;
+ m_item_definitions.insert(std::make_pair("", hand_def));
+
+ ItemDefinition* unknown_def = new ItemDefinition;
+ unknown_def->name = "unknown";
+ m_item_definitions.insert(std::make_pair("unknown", unknown_def));
+
+ ItemDefinition* air_def = new ItemDefinition;
+ air_def->type = ITEM_NODE;
+ air_def->name = "air";
+ m_item_definitions.insert(std::make_pair("air", air_def));
+
+ ItemDefinition* ignore_def = new ItemDefinition;
+ ignore_def->type = ITEM_NODE;
+ ignore_def->name = "ignore";
+ m_item_definitions.insert(std::make_pair("ignore", ignore_def));
+ }
+ virtual void registerItem(const ItemDefinition &def)
+ {
+ infostream<<"ItemDefManager: registering \""<<def.name<<"\""<<std::endl;
+ // Ensure that the "" item (the hand) always has ToolDiggingProperties
+ if(def.name == "")
+ assert(def.tool_digging_properties != NULL);
+
+ m_item_definitions[def.name] = new ItemDefinition(def);
+
+ // Remove conflicting alias if it exists
+ bool alias_removed = (m_aliases.erase(def.name) != 0);
+ if(alias_removed)
+ infostream<<"ItemDefManager: erased alias "<<def.name
+ <<" because item was defined"<<std::endl;
+ }
+ virtual void registerAlias(const std::string &name,
+ const std::string &convert_to)
+ {
+ if(m_item_definitions.find(name) == m_item_definitions.end())
+ {
+ infostream<<"ItemDefManager: setting alias "<<name
+ <<" -> "<<convert_to<<std::endl;
+ m_aliases[name] = convert_to;
+ }
+ }
+
+ virtual void updateTexturesAndMeshes(IGameDef *gamedef)
+ {
+#ifndef SERVER
+ infostream<<"ItemDefManager::updateTexturesAndMeshes(): Updating "
+ <<"textures and meshes in item definitions"<<std::endl;
+
+ ITextureSource *tsrc = gamedef->getTextureSource();
+ INodeDefManager *nodedef = gamedef->getNodeDefManager();
+ IrrlichtDevice *device = tsrc->getDevice();
+ video::IVideoDriver *driver = device->getVideoDriver();
+
+ for(std::map<std::string, ItemDefinition*>::iterator
+ i = m_item_definitions.begin();
+ i != m_item_definitions.end(); i++)
+ {
+ ItemDefinition *def = i->second;
+
+ bool need_node_mesh = false;
+
+ // Create an inventory texture
+ def->inventory_texture = NULL;
+ if(def->inventory_image != "")
+ {
+ def->inventory_texture = tsrc->getTextureRaw(def->inventory_image);
+ }
+ else if(def->type == ITEM_NODE)
+ {
+ need_node_mesh = true;
+ }
+
+ // Create a wield mesh
+ if(def->wield_mesh != NULL)
+ {
+ def->wield_mesh->drop();
+ def->wield_mesh = NULL;
+ }
+ if(def->type == ITEM_NODE && def->wield_image == "")
+ {
+ need_node_mesh = true;
+ }
+ else if(def->wield_image != "" || def->inventory_image != "")
+ {
+ // Extrude the wield image into a mesh
+
+ std::string imagename;
+ if(def->wield_image != "")
+ imagename = def->wield_image;
+ else
+ imagename = def->inventory_image;
+
+ def->wield_mesh = createExtrudedMesh(
+ tsrc->getTextureRaw(imagename),
+ driver,
+ def->wield_scale * v3f(40.0, 40.0, 4.0));
+ if(def->wield_mesh == NULL)
+ {
+ infostream<<"ItemDefManager: WARNING: "
+ <<"updateTexturesAndMeshes(): "
+ <<"Unable to create extruded mesh for item "
+ <<def->name<<std::endl;
+ }
+ }
+
+ if(need_node_mesh)
+ {
+ /*
+ Get node properties
+ */
+ content_t id = nodedef->getId(def->name);
+ const ContentFeatures &f = nodedef->get(id);
+
+ /*
+ Make a mesh from the node
+ */
+ MeshMakeData mesh_make_data;
+ MapNode mesh_make_node(
+ id,
+ (f.param_type == CPT_LIGHT) ? 0xee : 0,
+ 0);
+ mesh_make_data.fillSingleNode(1000, &mesh_make_node);
+ scene::IMesh *node_mesh =
+ makeMapBlockMesh(&mesh_make_data, gamedef);
+ setMeshColor(node_mesh, video::SColor(255, 255, 255, 255));
+
+ /*
+ Scale and translate the mesh so it's a unit cube
+ centered on the origin
+ */
+ scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
+ translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));
+
+ /*
+ Draw node mesh into a render target texture
+ */
+ if(def->inventory_texture == NULL && node_mesh != NULL)
+ {
+ core::dimension2d<u32> dim(64,64);
+ std::string rtt_texture_name = "INVENTORY_"
+ + def->name + "_RTT";
+ v3f camera_position(0, 1.0, -1.5);
+ camera_position.rotateXZBy(45);
+ v3f camera_lookat(0, 0, 0);
+ core::CMatrix4<f32> camera_projection_matrix;
+ // Set orthogonal projection
+ camera_projection_matrix.buildProjectionMatrixOrthoLH(
+ 1.65, 1.65, 0, 100);
+
+ video::SColorf ambient_light(0.2,0.2,0.2);
+ v3f light_position(10, 100, -50);
+ video::SColorf light_color(0.5,0.5,0.5);
+ f32 light_radius = 1000;
+
+ def->inventory_texture = generateTextureFromMesh(
+ node_mesh, device, dim, rtt_texture_name,
+ camera_position,
+ camera_lookat,
+ camera_projection_matrix,
+ ambient_light,
+ light_position,
+ light_color,
+ light_radius);
+ // Note: might have returned NULL
+ }
+
+ /*
+ Use the node mesh as the wield mesh
+ */
+ if(def->wield_mesh == NULL && node_mesh != NULL)
+ {
+ // Scale to proper wield mesh proportions
+ scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
+ * def->wield_scale);
+ def->wield_mesh = node_mesh;
+ def->wield_mesh->grab();
+ }
+
+
+ if(node_mesh != NULL)
+ node_mesh->drop();
+ }
+ }
+#endif
+ }
+ void serialize(std::ostream &os)
+ {
+ writeU8(os, 0); // version
+ u16 count = m_item_definitions.size();
+ writeU16(os, count);
+ for(std::map<std::string, ItemDefinition*>::const_iterator
+ i = m_item_definitions.begin();
+ i != m_item_definitions.end(); i++)
+ {
+ ItemDefinition *def = i->second;
+ // Serialize ItemDefinition and write wrapped in a string
+ std::ostringstream tmp_os(std::ios::binary);
+ def->serialize(tmp_os);
+ os<<serializeString(tmp_os.str());
+ }
+ writeU16(os, m_aliases.size());
+ for(std::map<std::string, std::string>::const_iterator
+ i = m_aliases.begin(); i != m_aliases.end(); i++)
+ {
+ os<<serializeString(i->first);
+ os<<serializeString(i->second);
+ }
+ }
+ void deSerialize(std::istream &is)
+ {
+ // Clear everything
+ clear();
+ // Deserialize
+ int version = readU8(is);
+ if(version != 0)
+ throw SerializationError("unsupported ItemDefManager version");
+ u16 count = readU16(is);
+ for(u16 i=0; i<count; i++)
+ {
+ // Deserialize a string and grab an ItemDefinition from it
+ std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
+ ItemDefinition def;
+ def.deSerialize(tmp_is);
+ // Register
+ registerItem(def);
+ }
+ u16 num_aliases = readU16(is);
+ for(u16 i=0; i<num_aliases; i++)
+ {
+ std::string name = deSerializeString(is);
+ std::string convert_to = deSerializeString(is);
+ registerAlias(name, convert_to);
+ }
+ }
+private:
+ // Key is name
+ std::map<std::string, ItemDefinition*> m_item_definitions;
+ // Aliases
+ std::map<std::string, std::string> m_aliases;
+};
+
+IWritableItemDefManager* createItemDefManager()
+{
+ return new CItemDefManager();
+}
+
diff --git a/src/itemdef.h b/src/itemdef.h
new file mode 100644
index 000000000..5a432591d
--- /dev/null
+++ b/src/itemdef.h
@@ -0,0 +1,147 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2011 Kahrl <kahrl@gmx.net>
+
+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 ITEMDEF_HEADER
+#define ITEMDEF_HEADER
+
+#include "common_irrlicht.h"
+#include <string>
+#include <iostream>
+#include <set>
+class IGameDef;
+struct ToolDiggingProperties;
+
+/*
+ Base item definition
+*/
+
+enum ItemType
+{
+ ITEM_NONE,
+ ITEM_NODE,
+ ITEM_CRAFT,
+ ITEM_TOOL,
+};
+
+struct ItemDefinition
+{
+ /*
+ Basic item properties
+ */
+ ItemType type;
+ std::string name; // "" = hand
+ std::string description; // Shown in tooltip.
+
+ /*
+ Visual properties
+ */
+ std::string inventory_image; // Optional for nodes, mandatory for tools/craftitems
+ std::string wield_image; // If empty, inventory_image or mesh (only nodes) is used
+ v3f wield_scale;
+
+ /*
+ Item stack and interaction properties
+ */
+ s16 stack_max;
+ bool usable;
+ bool liquids_pointable;
+ // May be NULL. If non-NULL, deleted by destructor
+ ToolDiggingProperties *tool_digging_properties;
+
+ /*
+ Cached stuff
+ */
+#ifndef SERVER
+ video::ITexture *inventory_texture;
+ scene::IMesh *wield_mesh;
+#endif
+
+ /*
+ Some helpful methods
+ */
+ ItemDefinition();
+ ItemDefinition(const ItemDefinition &def);
+ ItemDefinition& operator=(const ItemDefinition &def);
+ ~ItemDefinition();
+ void reset();
+ void serialize(std::ostream &os) const;
+ void deSerialize(std::istream &is);
+private:
+ void resetInitial();
+};
+
+class IItemDefManager
+{
+public:
+ IItemDefManager(){}
+ virtual ~IItemDefManager(){}
+
+ // Get item definition
+ virtual const ItemDefinition& get(const std::string &name) const=0;
+ // Get alias definition
+ virtual std::string getAlias(const std::string &name) const=0;
+ // Get set of all defined item names and aliases
+ virtual std::set<std::string> getAll() const=0;
+ // Check if item is known
+ virtual bool isKnown(const std::string &name) const=0;
+
+ virtual void serialize(std::ostream &os)=0;
+};
+
+class IWritableItemDefManager : public IItemDefManager
+{
+public:
+ IWritableItemDefManager(){}
+ virtual ~IWritableItemDefManager(){}
+
+ // Get item definition
+ virtual const ItemDefinition& get(const std::string &name) const=0;
+ // Get alias definition
+ virtual std::string getAlias(const std::string &name) const=0;
+ // Get set of all defined item names and aliases
+ virtual std::set<std::string> getAll() const=0;
+ // Check if item is known
+ virtual bool isKnown(const std::string &name) const=0;
+
+ // Remove all registered item and node definitions and aliases
+ // Then re-add the builtin item definitions
+ virtual void clear()=0;
+ // Register item definition
+ virtual void registerItem(const ItemDefinition &def)=0;
+ // Set an alias so that items named <name> will load as <convert_to>.
+ // Alias is not set if <name> has already been defined.
+ // Alias will be removed if <name> is defined at a later point of time.
+ virtual void registerAlias(const std::string &name,
+ const std::string &convert_to)=0;
+
+ /*
+ Update inventory textures and wield meshes to latest
+ return values of ITextureSource and INodeDefManager.
+ Call after updating the texture atlas of a texture source.
+ */
+ virtual void updateTexturesAndMeshes(IGameDef *gamedef)=0;
+
+ virtual void serialize(std::ostream &os)=0;
+ virtual void deSerialize(std::istream &is)=0;
+};
+
+IWritableItemDefManager* createItemDefManager();
+
+#endif
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index 016cb222e..73c13caca 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -30,6 +30,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "nameidmapping.h"
#include "content_mapnode.h" // For legacy name-id mapping
+#ifndef SERVER
+#include "mapblock_mesh.h"
+#endif
/*
MapBlock
diff --git a/src/mapblock.h b/src/mapblock.h
index aa5aa43f7..f2d94753c 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -32,9 +32,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "voxel.h"
#include "staticobject.h"
#include "mapblock_nodemod.h"
-#ifndef SERVER
- #include "mapblock_mesh.h"
-#endif
#include "modifiedstate.h"
class Map;
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index c051dda50..db9057e19 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "profiler.h"
#include "nodedef.h"
-#include "tile.h"
#include "gamedef.h"
#include "content_mapblock.h"
#include "mineral.h" // For mineral_block_texture
@@ -83,6 +82,39 @@ void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
}
}
+void MeshMakeData::fillSingleNode(u32 daynight_ratio, MapNode *node)
+{
+ m_daynight_ratio = daynight_ratio;
+ m_blockpos = v3s16(0,0,0);
+ m_temp_mods.clear();
+
+ v3s16 blockpos_nodes = v3s16(0,0,0);
+ VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
+ blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
+ s32 volume = area.getVolume();
+ s32 our_node_index = area.index(1,1,1);
+
+ // Allocate this block + neighbors
+ m_vmanip.clear();
+ m_vmanip.addArea(area);
+
+ // Fill in data
+ MapNode *data = new MapNode[volume];
+ for(s32 i = 0; i < volume; i++)
+ {
+ if(i == our_node_index)
+ {
+ data[i] = *node;
+ }
+ else
+ {
+ data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
+ }
+ }
+ m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
+ delete[] data;
+}
+
/*
vertex_dirs: v3s16[4]
*/
@@ -207,8 +239,8 @@ static void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
- v3f zerovector = v3f(0,0,0);
-
+ v3f normal(dir.X, dir.Y, dir.Z);
+
u8 alpha = tile.alpha;
/*u8 alpha = 255;
if(tile.id == TILE_WATER)
@@ -230,16 +262,16 @@ static void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
core::vector2d<f32>(x0+w*abs_scale, y0));*/
- face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0),
+ face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
MapBlock_LightColor(alpha, li0),
core::vector2d<f32>(x0+w*abs_scale, y0+h));
- face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0),
+ face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
MapBlock_LightColor(alpha, li1),
core::vector2d<f32>(x0, y0+h));
- face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0),
+ face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
MapBlock_LightColor(alpha, li2),
core::vector2d<f32>(x0, y0));
- face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0),
+ face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
MapBlock_LightColor(alpha, li3),
core::vector2d<f32>(x0+w*abs_scale, y0));
@@ -309,8 +341,8 @@ static TileSpec getTile(const MapNode &node, v3s16 dir,
Gets node tile from any place relative to block.
Returns TILE_NODE if doesn't exist or should not be drawn.
*/
-static TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
- NodeModMap &temp_mods, ITextureSource *tsrc, INodeDefManager *ndef)
+TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
+ NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef)
{
TileSpec spec;
spec = getTile(mn, face_dir, tsrc, ndef);
@@ -325,13 +357,15 @@ static TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
{
struct NodeMod mod = n->getValue();*/
NodeMod mod;
- if(temp_mods.get(p, &mod))
+ if(temp_mods && temp_mods->get(p, &mod))
{
+ #if 0 // NODEMOD_CHANGECONTENT isn't used at the moment
if(mod.type == NODEMOD_CHANGECONTENT)
{
MapNode mn2(mod.param);
spec = getTile(mn2, face_dir, tsrc, ndef);
}
+ #endif
if(mod.type == NODEMOD_CRACK)
{
/*
@@ -361,19 +395,14 @@ static TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
return spec;
}
-static content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
+static content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap *temp_mods)
{
/*
Check temporary modifications on this node
*/
- /*core::map<v3s16, NodeMod>::Node *n;
- n = m_temp_mods.find(p);
- // If modified
- if(n != NULL)
- {
- struct NodeMod mod = n->getValue();*/
+ #if 0 // NODEMOD_CHANGECONTENT isn't used at the moment
NodeMod mod;
- if(temp_mods.get(p, &mod))
+ if(temp_mods && temp_mods->get(p, &mod))
{
if(mod.type == NODEMOD_CHANGECONTENT)
{
@@ -395,6 +424,7 @@ static content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
*/
}
}
+ #endif
return mn.getContent();
}
@@ -469,7 +499,7 @@ static void getTileInfo(
v3s16 face_dir,
u32 daynight_ratio,
VoxelManipulator &vmanip,
- NodeModMap &temp_mods,
+ NodeModMap *temp_mods,
bool smooth_lighting,
IGameDef *gamedef,
// Output:
@@ -553,7 +583,7 @@ static void updateFastFaceRow(
v3s16 face_dir,
v3f face_dir_f,
core::array<FastFace> &dest,
- NodeModMap &temp_mods,
+ NodeModMap *temp_mods,
VoxelManipulator &vmanip,
v3s16 blockpos_nodes,
bool smooth_lighting,
@@ -749,7 +779,7 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef)
v3s16(0,1,0), //face dir
v3f (0,1,0),
fastfaces_new,
- data->m_temp_mods,
+ &data->m_temp_mods,
data->m_vmanip,
blockpos_nodes,
smooth_lighting,
@@ -768,7 +798,7 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef)
v3s16(1,0,0),
v3f (1,0,0),
fastfaces_new,
- data->m_temp_mods,
+ &data->m_temp_mods,
data->m_vmanip,
blockpos_nodes,
smooth_lighting,
@@ -787,7 +817,7 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef)
v3s16(0,0,1),
v3f (0,0,1),
fastfaces_new,
- data->m_temp_mods,
+ &data->m_temp_mods,
data->m_vmanip,
blockpos_nodes,
smooth_lighting,
diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h
index 36cc9be24..4d3e7d29d 100644
--- a/src/mapblock_mesh.h
+++ b/src/mapblock_mesh.h
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "mapblock_nodemod.h"
+#include "tile.h"
#include "voxel.h"
class IGameDef;
@@ -125,6 +126,8 @@ private:
// Helper functions
video::SColor MapBlock_LightColor(u8 alpha, u8 light);
+TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
+ NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef);
class MapBlock;
@@ -140,6 +143,11 @@ struct MeshMakeData
parent of block.
*/
void fill(u32 daynight_ratio, MapBlock *block);
+
+ /*
+ Set up with only a single node at (1,1,1)
+ */
+ void fillSingleNode(u32 daynight_ratio, MapNode *node);
};
// This is the highest-level function in here
diff --git a/src/materials.cpp b/src/materials.cpp
index d2d37ebf4..146209d58 100644
--- a/src/materials.cpp
+++ b/src/materials.cpp
@@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "materials.h"
#include "mapnode.h"
#include "nodedef.h"
-#include "tooldef.h"
#include "utility.h"
void MaterialProperties::serialize(std::ostream &os)
@@ -49,6 +48,56 @@ void MaterialProperties::deSerialize(std::istream &is)
flammability = readF1000(is);
}
+ToolDiggingProperties::ToolDiggingProperties(float full_punch_interval_,
+ float a, float b, float c, float d, float e,
+ float f, float g, float h, float i, float j):
+ full_punch_interval(full_punch_interval_),
+ basetime(a),
+ dt_weight(b),
+ dt_crackiness(c),
+ dt_crumbliness(d),
+ dt_cuttability(e),
+ basedurability(f),
+ dd_weight(g),
+ dd_crackiness(h),
+ dd_crumbliness(i),
+ dd_cuttability(j)
+{}
+
+void ToolDiggingProperties::serialize(std::ostream &os)
+{
+ writeU8(os, 0); // version
+ writeF1000(os, full_punch_interval);
+ writeF1000(os, basetime);
+ writeF1000(os, dt_weight);
+ writeF1000(os, dt_crackiness);
+ writeF1000(os, dt_crumbliness);
+ writeF1000(os, dt_cuttability);
+ writeF1000(os, basedurability);
+ writeF1000(os, dd_weight);
+ writeF1000(os, dd_crackiness);
+ writeF1000(os, dd_crumbliness);
+ writeF1000(os, dd_cuttability);
+}
+
+void ToolDiggingProperties::deSerialize(std::istream &is)
+{
+ int version = readU8(is);
+ if(version != 0) throw SerializationError(
+ "unsupported ToolDiggingProperties version");
+ full_punch_interval = readF1000(is);
+ basetime = readF1000(is);
+ dt_weight = readF1000(is);
+ dt_crackiness = readF1000(is);
+ dt_crumbliness = readF1000(is);
+ dt_cuttability = readF1000(is);
+ basedurability = readF1000(is);
+ dd_weight = readF1000(is);
+ dd_crackiness = readF1000(is);
+ dd_crumbliness = readF1000(is);
+ dd_cuttability = readF1000(is);
+}
+
DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch)
{
diff --git a/src/materials.h b/src/materials.h
index b25d047be..face7d5df 100644
--- a/src/materials.h
+++ b/src/materials.h
@@ -72,6 +72,29 @@ struct MaterialProperties
void deSerialize(std::istream &is);
};
+struct ToolDiggingProperties
+{
+ // time = basetime + sum(feature here * feature in MaterialProperties)
+ float full_punch_interval;
+ float basetime;
+ float dt_weight;
+ float dt_crackiness;
+ float dt_crumbliness;
+ float dt_cuttability;
+ float basedurability;
+ float dd_weight;
+ float dd_crackiness;
+ float dd_crumbliness;
+ float dd_cuttability;
+
+ ToolDiggingProperties(float full_punch_interval_=2.0,
+ float a=0.75, float b=0, float c=0, float d=0, float e=0,
+ float f=50, float g=0, float h=0, float i=0, float j=0);
+
+ void serialize(std::ostream &os);
+ void deSerialize(std::istream &is);
+};
+
struct DiggingProperties
{
bool diggable;
@@ -87,7 +110,6 @@ struct DiggingProperties
{}
};
-struct ToolDiggingProperties;
class INodeDefManager;
DiggingProperties getDiggingProperties(const MaterialProperties *mp,
diff --git a/src/mesh.cpp b/src/mesh.cpp
index 1d347a09f..5afb4af59 100644
--- a/src/mesh.cpp
+++ b/src/mesh.cpp
@@ -18,8 +18,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "mesh.h"
+#include "log.h"
+#include <cassert>
+#include <iostream>
#include <IAnimatedMesh.h>
#include <SAnimatedMesh.h>
+#include <ICameraSceneNode.h>
// In Irrlicht 1.8 the signature of ITexture::lock was changed from
// (bool, u32) to (E_TEXTURE_LOCK_MODE, u32).
@@ -73,9 +77,15 @@ scene::IAnimatedMesh* createCubeMesh(v3f scale)
{
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
buf->append(vertices + 4 * i, 4, indices, 6);
+ // Set default material
+ buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+ buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
+ buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+ // Add mesh buffer to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
+
scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
mesh->drop();
scaleMesh(anim_mesh, scale); // also recalculates bounding box
@@ -280,6 +290,13 @@ scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
}
img1->drop();
}
+
+ // Set default material
+ mesh->getMeshBuffer(0)->getMaterial().setTexture(0, texture);
+ mesh->getMeshBuffer(0)->getMaterial().setFlag(video::EMF_LIGHTING, false);
+ mesh->getMeshBuffer(0)->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
+ mesh->getMeshBuffer(0)->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+
scaleMesh(mesh, scale); // also recalculates bounding box
return mesh;
}
@@ -313,6 +330,35 @@ void scaleMesh(scene::IMesh *mesh, v3f scale)
mesh->setBoundingBox(bbox);
}
+void translateMesh(scene::IMesh *mesh, v3f vec)
+{
+ if(mesh == NULL)
+ return;
+
+ core::aabbox3d<f32> bbox;
+ bbox.reset(0,0,0);
+
+ u16 mc = mesh->getMeshBufferCount();
+ for(u16 j=0; j<mc; j++)
+ {
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
+ u16 vc = buf->getVertexCount();
+ for(u16 i=0; i<vc; i++)
+ {
+ vertices[i].Pos += vec;
+ }
+ buf->recalculateBoundingBox();
+
+ // calculate total bounding box
+ if(j == 0)
+ bbox = buf->getBoundingBox();
+ else
+ bbox.addInternalBox(buf->getBoundingBox());
+ }
+ mesh->setBoundingBox(bbox);
+}
+
void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
{
if(mesh == NULL)
@@ -360,3 +406,74 @@ void setMeshColorByNormalXYZ(scene::IMesh *mesh,
}
}
}
+
+video::ITexture *generateTextureFromMesh(scene::IMesh *mesh,
+ IrrlichtDevice *device,
+ core::dimension2d<u32> dim,
+ std::string texture_name,
+ v3f camera_position,
+ v3f camera_lookat,
+ core::CMatrix4<f32> camera_projection_matrix,
+ video::SColorf ambient_light,
+ v3f light_position,
+ video::SColorf light_color,
+ f32 light_radius)
+{
+ video::IVideoDriver *driver = device->getVideoDriver();
+ if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
+ {
+ errorstream<<"generateTextureFromMesh(): EVDF_RENDER_TO_TARGET"
+ " not supported."<<std::endl;
+ return NULL;
+ }
+
+ // Create render target texture
+ video::ITexture *rtt = driver->addRenderTargetTexture(
+ dim, texture_name.c_str(), video::ECF_A8R8G8B8);
+ if(rtt == NULL)
+ {
+ errorstream<<"generateTextureFromMesh(): addRenderTargetTexture"
+ " returned NULL."<<std::endl;
+ return NULL;
+ }
+
+ // Set render target
+ driver->setRenderTarget(rtt, true, true, video::SColor(0,0,0,0));
+
+ // Get a scene manager
+ scene::ISceneManager *smgr_main = device->getSceneManager();
+ assert(smgr_main);
+ scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
+ assert(smgr);
+
+ scene::IMeshSceneNode* meshnode = smgr->addMeshSceneNode(mesh, NULL, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true);
+ meshnode->setMaterialFlag(video::EMF_LIGHTING, true);
+ meshnode->setMaterialFlag(video::EMF_ANTI_ALIASING, true);
+ meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, true);
+
+ scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
+ camera_position, camera_lookat);
+ // second parameter of setProjectionMatrix (isOrthogonal) is ignored
+ camera->setProjectionMatrix(camera_projection_matrix, false);
+
+ smgr->setAmbientLight(ambient_light);
+ smgr->addLightSceneNode(0, light_position, light_color, light_radius);
+
+ // Render scene
+ driver->beginScene(true, true, video::SColor(0,0,0,0));
+ smgr->drawAll();
+ driver->endScene();
+
+ // NOTE: The scene nodes should not be dropped, otherwise
+ // smgr->drop() segfaults
+ /*cube->drop();
+ camera->drop();
+ light->drop();*/
+ // Drop scene manager
+ smgr->drop();
+
+ // Unset render target
+ driver->setRenderTarget(0, true, true, 0);
+
+ return rtt;
+}
diff --git a/src/mesh.h b/src/mesh.h
index 33e072927..57166235e 100644
--- a/src/mesh.h
+++ b/src/mesh.h
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MESH_HEADER
#include "common_irrlicht.h"
+#include <string>
/*
Create a new cube mesh.
@@ -48,6 +49,11 @@ scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
void scaleMesh(scene::IMesh *mesh, v3f scale);
/*
+ Translate each vertex coordinate by the specified vector.
+*/
+void translateMesh(scene::IMesh *mesh, v3f vec);
+
+/*
Set a constant color for all vertices in the mesh
*/
void setMeshColor(scene::IMesh *mesh, const video::SColor &color);
@@ -63,4 +69,20 @@ void setMeshColorByNormalXYZ(scene::IMesh *mesh,
const video::SColor &colorY,
const video::SColor &colorZ);
+/*
+ Render a mesh to a texture.
+ Returns NULL if render-to-texture failed.
+*/
+video::ITexture *generateTextureFromMesh(scene::IMesh *mesh,
+ IrrlichtDevice *device,
+ core::dimension2d<u32> dim,
+ std::string texture_name,
+ v3f camera_position,
+ v3f camera_lookat,
+ core::CMatrix4<f32> camera_projection_matrix,
+ video::SColorf ambient_light,
+ v3f light_position,
+ video::SColorf light_color,
+ f32 light_radius);
+
#endif
diff --git a/src/mineral.cpp b/src/mineral.cpp
index 038251fa3..4e495fce6 100644
--- a/src/mineral.cpp
+++ b/src/mineral.cpp
@@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "mineral.h"
+#include "gamedef.h"
const char *mineral_filenames[MINERAL_COUNT] =
@@ -47,5 +48,15 @@ std::string mineral_block_texture(u8 mineral)
return mineral_textures[mineral];
}
+ItemStack getDiggedMineralItem(u8 mineral, IGameDef *gamedef)
+{
+ if(mineral == MINERAL_COAL)
+ return ItemStack("default:coal_lump", 1, 0, "", gamedef->idef());
+ else if(mineral == MINERAL_IRON)
+ return ItemStack("default:iron_lump", 1, 0, "", gamedef->idef());
+ else
+ return ItemStack();
+}
+
diff --git a/src/mineral.h b/src/mineral.h
index 4949fe07e..a945d0e02 100644
--- a/src/mineral.h
+++ b/src/mineral.h
@@ -38,19 +38,10 @@ void init_mineral();
#define MINERAL_COUNT 3
-std::string mineral_block_texture(u8 mineral);
-
class IGameDef;
-inline CraftItem * getDiggedMineralItem(u8 mineral, IGameDef *gamedef)
-{
- if(mineral == MINERAL_COAL)
- return new CraftItem(gamedef, "lump_of_coal", 1);
- else if(mineral == MINERAL_IRON)
- return new CraftItem(gamedef, "lump_of_iron", 1);
-
- return NULL;
-}
+std::string mineral_block_texture(u8 mineral);
+ItemStack getDiggedMineralItem(u8 mineral, IGameDef *gamedef);
#endif
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index d7769700b..87469bfb5 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "main.h" // For g_settings
-#include "nodemetadata.h"
+#include "itemdef.h"
#ifndef SERVER
#include "tile.h"
#endif
@@ -103,8 +103,6 @@ void ContentFeatures::reset()
Cached stuff
*/
#ifndef SERVER
- inventory_texture = NULL;
-
for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
special_materials[j] = NULL;
special_aps[j] = NULL;
@@ -113,7 +111,6 @@ void ContentFeatures::reset()
visual_solidness = 0;
backface_culling = true;
#endif
- used_texturenames.clear();
/*
Actual data
@@ -127,7 +124,6 @@ void ContentFeatures::reset()
tname_tiles[i] = "";
for(u16 j=0; j<CF_SPECIAL_COUNT; j++)
mspec_special[j] = MaterialSpec();
- tname_inventory = "";
alpha = 255;
post_effect_color = video::SColor(0, 0, 0, 0);
param_type = CPT_NONE;
@@ -140,7 +136,6 @@ void ContentFeatures::reset()
climbable = false;
buildable_to = false;
wall_mounted = false;
- often_contains_mineral = false;
dug_item = "";
extra_dug_item = "";
extra_dug_item_rarity = 2;
@@ -153,21 +148,20 @@ void ContentFeatures::reset()
damage_per_second = 0;
selection_box = NodeBox();
material = MaterialProperties();
- cookresult_item = ""; // Cannot be cooked
- furnace_cooktime = 3.0;
- furnace_burntime = -1.0; // Cannot be burned
+ // Make unknown blocks diggable
+ material.diggability = DIGGABLE_CONSTANT;
+ material.constant_time = 0.5;
}
void ContentFeatures::serialize(std::ostream &os)
{
- writeU8(os, 0); // version
+ writeU8(os, 1); // version
os<<serializeString(name);
writeU8(os, drawtype);
writeF1000(os, visual_scale);
writeU8(os, 6);
for(u32 i=0; i<6; i++)
os<<serializeString(tname_tiles[i]);
- os<<serializeString(tname_inventory);
writeU8(os, CF_SPECIAL_COUNT);
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
mspec_special[i].serialize(os);
@@ -187,7 +181,6 @@ void ContentFeatures::serialize(std::ostream &os)
writeU8(os, climbable);
writeU8(os, buildable_to);
writeU8(os, wall_mounted);
- writeU8(os, often_contains_mineral);
os<<serializeString(dug_item);
os<<serializeString(extra_dug_item);
writeS32(os, extra_dug_item_rarity);
@@ -200,15 +193,12 @@ void ContentFeatures::serialize(std::ostream &os)
writeU32(os, damage_per_second);
selection_box.serialize(os);
material.serialize(os);
- os<<serializeString(cookresult_item);
- writeF1000(os, furnace_cooktime);
- writeF1000(os, furnace_burntime);
}
-void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
+void ContentFeatures::deSerialize(std::istream &is)
{
int version = readU8(is);
- if(version != 0)
+ if(version != 1)
throw SerializationError("unsupported ContentFeatures version");
name = deSerializeString(is);
drawtype = (enum NodeDrawType)readU8(is);
@@ -216,9 +206,7 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
if(readU8(is) != 6)
throw SerializationError("unsupported tile count");
for(u32 i=0; i<6; i++)
- setTexture(i, deSerializeString(is));
- //tname_tiles[i] = deSerializeString(is);
- tname_inventory = deSerializeString(is);
+ tname_tiles[i] = deSerializeString(is);
if(readU8(is) != CF_SPECIAL_COUNT)
throw SerializationError("unsupported CF_SPECIAL_COUNT");
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
@@ -239,7 +227,6 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
climbable = readU8(is);
buildable_to = readU8(is);
wall_mounted = readU8(is);
- often_contains_mineral = readU8(is);
dug_item = deSerializeString(is);
extra_dug_item = deSerializeString(is);
extra_dug_item_rarity = readS32(is);
@@ -252,53 +239,6 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
damage_per_second = readU32(is);
selection_box.deSerialize(is);
material.deSerialize(is);
- cookresult_item = deSerializeString(is);
- furnace_cooktime = readF1000(is);
- furnace_burntime = readF1000(is);
-}
-
-void ContentFeatures::setTexture(u16 i, std::string name)
-{
- used_texturenames.insert(name);
- tname_tiles[i] = name;
- if(tname_inventory == "")
- tname_inventory = name;
-}
-
-void ContentFeatures::setAllTextures(std::string name)
-{
- for(u16 i=0; i<6; i++)
- setTexture(i, name);
- // Force inventory texture too
- setInventoryTexture(name);
-}
-
-void ContentFeatures::setSpecialMaterial(u16 i, const MaterialSpec &mspec)
-{
- assert(i < CF_SPECIAL_COUNT);
- mspec_special[i] = mspec;
-}
-
-void ContentFeatures::setInventoryTexture(std::string imgname)
-{
- tname_inventory = imgname;
-}
-
-void ContentFeatures::setInventoryTextureCube(std::string top,
- std::string left, std::string right)
-{
- str_replace_char(top, '^', '&');
- str_replace_char(left, '^', '&');
- str_replace_char(right, '^', '&');
-
- std::string imgname_full;
- imgname_full += "[inventorycube{";
- imgname_full += top;
- imgname_full += "{";
- imgname_full += left;
- imgname_full += "{";
- imgname_full += right;
- tname_inventory = imgname_full;
}
/*
@@ -311,14 +251,12 @@ public:
void clear()
{
m_name_id_mapping.clear();
+ m_name_id_mapping_with_aliases.clear();
- m_aliases.clear();
-
for(u16 i=0; i<=MAX_CONTENT; i++)
{
ContentFeatures &f = m_content_features[i];
f.reset(); // Reset to defaults
- f.setAllTextures("unknown_block.png");
}
// Set CONTENT_AIR
@@ -336,7 +274,7 @@ public:
// Insert directly into containers
content_t c = CONTENT_AIR;
m_content_features[c] = f;
- m_name_id_mapping.set(c, f.name);
+ addNameIdMapping(c, f.name);
}
// Set CONTENT_IGNORE
{
@@ -354,7 +292,7 @@ public:
// Insert directly into containers
content_t c = CONTENT_IGNORE;
m_content_features[c] = f;
- m_name_id_mapping.set(c, f.name);
+ addNameIdMapping(c, f.name);
}
}
// CONTENT_IGNORE = not found
@@ -401,12 +339,14 @@ public:
{
return get(n.getContent());
}
- virtual bool getId(const std::string &name_, content_t &result) const
+ virtual bool getId(const std::string &name, content_t &result) const
{
- // Convert name according to possible alias
- std::string name = getAlias(name_);
- // Get id
- return m_name_id_mapping.getId(name, result);
+ std::map<std::string, content_t>::const_iterator
+ i = m_name_id_mapping_with_aliases.find(name);
+ if(i == m_name_id_mapping_with_aliases.end())
+ return false;
+ result = i->second;
+ return true;
}
virtual content_t getId(const std::string &name) const
{
@@ -420,14 +360,6 @@ public:
getId(name, id);
return get(id);
}
- virtual std::string getAlias(const std::string &name) const
- {
- std::map<std::string, std::string>::const_iterator i;
- i = m_aliases.find(name);
- if(i != m_aliases.end())
- return i->second;
- return name;
- }
// IWritableNodeDefManager
virtual void set(content_t c, const ContentFeatures &def)
{
@@ -451,20 +383,14 @@ public:
}
m_content_features[c] = def;
if(def.name != "")
- m_name_id_mapping.set(c, def.name);
-
- // Remove conflicting alias if it exists
- bool alias_removed = (m_aliases.erase(def.name) != 0);
- if(alias_removed)
- infostream<<"ndef: erased alias "<<def.name
- <<" because node was defined"<<std::endl;
+ addNameIdMapping(c, def.name);
}
virtual content_t set(const std::string &name,
const ContentFeatures &def)
{
assert(name == def.name);
u16 id = CONTENT_IGNORE;
- bool found = m_name_id_mapping.getId(name, id);
+ bool found = m_name_id_mapping.getId(name, id); // ignore aliases
if(!found){
// Determine if full param2 is required
bool require_full_param2 = (
@@ -481,7 +407,7 @@ public:
if(id == CONTENT_IGNORE)
return CONTENT_IGNORE;
if(name != "")
- m_name_id_mapping.set(id, name);
+ addNameIdMapping(id, name);
}
set(id, def);
return id;
@@ -491,23 +417,27 @@ public:
assert(name != "");
ContentFeatures f;
f.name = name;
- f.setAllTextures("unknown_block.png");
// Make unknown blocks diggable
- f.material.diggability = DIGGABLE_NORMAL;
+ f.material.diggability = DIGGABLE_CONSTANT;
+ f.material.constant_time = 0.5;
return set(name, f);
}
- virtual void setAlias(const std::string &name,
- const std::string &convert_to)
+ virtual void updateAliases(IItemDefManager *idef)
{
- content_t id;
- if(getId(name, id)){
- infostream<<"ndef: not setting alias "<<name<<" -> "<<convert_to
- <<": "<<name<<" is already defined"<<std::endl;
- return;
+ std::set<std::string> all = idef->getAll();
+ m_name_id_mapping_with_aliases.clear();
+ for(std::set<std::string>::iterator
+ i = all.begin(); i != all.end(); i++)
+ {
+ std::string name = *i;
+ std::string convert_to = idef->getAlias(name);
+ content_t id;
+ if(m_name_id_mapping.getId(convert_to, id))
+ {
+ m_name_id_mapping_with_aliases.insert(
+ std::make_pair(name, id));
+ }
}
- infostream<<"ndef: setting alias "<<name<<" -> "<<convert_to
- <<std::endl;
- m_aliases[name] = convert_to;
}
virtual void updateTextures(ITextureSource *tsrc)
{
@@ -523,6 +453,14 @@ public:
{
ContentFeatures *f = &m_content_features[i];
+ std::string tname_tiles[6];
+ for(u32 j=0; j<6; j++)
+ {
+ tname_tiles[j] = f->tname_tiles[j];
+ if(tname_tiles[j] == "")
+ tname_tiles[j] = "unknown_block.png";
+ }
+
switch(f->drawtype){
default:
case NDT_NORMAL:
@@ -567,8 +505,7 @@ public:
f->drawtype = NDT_NORMAL;
f->solidness = 2;
for(u32 i=0; i<6; i++){
- f->setTexture(i, f->tname_tiles[i]
- + std::string("^[noalpha"));
+ tname_tiles[i] += std::string("^[noalpha");
}
}
break;
@@ -581,16 +518,9 @@ public:
break;
}
- // Inventory texture
- if(f->tname_inventory != "")
- f->inventory_texture = tsrc->getTextureRaw(f->tname_inventory);
- else
- f->inventory_texture = NULL;
// Tile textures
for(u16 j=0; j<6; j++){
- if(f->tname_tiles[j] == "")
- continue;
- f->tiles[j].texture = tsrc->getTexture(f->tname_tiles[j]);
+ f->tiles[j].texture = tsrc->getTexture(tname_tiles[j]);
f->tiles[j].alpha = f->alpha;
if(f->alpha == 255)
f->tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
@@ -649,16 +579,8 @@ public:
}
writeU16(os, count);
os<<serializeLongString(tmp_os.str());
-
- writeU16(os, m_aliases.size());
- for(std::map<std::string, std::string>::const_iterator
- i = m_aliases.begin(); i != m_aliases.end(); i++)
- {
- os<<serializeString(i->first);
- os<<serializeString(i->second);
- }
}
- void deSerialize(std::istream &is, IGameDef *gamedef)
+ void deSerialize(std::istream &is)
{
clear();
u16 count = readU16(is);
@@ -674,27 +596,26 @@ public:
if(i == CONTENT_IGNORE || i == CONTENT_AIR)
continue;*/
ContentFeatures *f = &m_content_features[i];
- f->deSerialize(tmp_is, gamedef);
+ f->deSerialize(tmp_is);
if(f->name != "")
- m_name_id_mapping.set(i, f->name);
- }
-
- u16 num_aliases = readU16(is);
- if(!is.eof()){
- for(u16 i=0; i<num_aliases; i++){
- std::string name = deSerializeString(is);
- std::string convert_to = deSerializeString(is);
- m_aliases[name] = convert_to;
- }
+ addNameIdMapping(i, f->name);
}
}
private:
+ void addNameIdMapping(content_t i, std::string name)
+ {
+ m_name_id_mapping.set(i, name);
+ m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
+ }
+private:
// Features indexed by id
ContentFeatures m_content_features[MAX_CONTENT+1];
// A mapping for fast converting back and forth between names and ids
NameIdMapping m_name_id_mapping;
- // Aliases
- std::map<std::string, std::string> m_aliases;
+ // Like m_name_id_mapping, but only from names to ids, and includes
+ // item aliases too. Updated by updateAliases()
+ // Note: Not serialized.
+ std::map<std::string, content_t> m_name_id_mapping_with_aliases;
};
IWritableNodeDefManager* createNodeDefManager()
diff --git a/src/nodedef.h b/src/nodedef.h
index fdf2f8c45..598ad7fb3 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tile.h"
#endif
#include "materials.h" // MaterialProperties
+class IItemDefManager;
class ITextureSource;
class IGameDef;
@@ -124,7 +125,6 @@ struct ContentFeatures
// 0 1 2 3 4 5
// up down right left back front
TileSpec tiles[6];
- video::ITexture *inventory_texture;
// Special material/texture
// - Currently used for flowing liquids
video::SMaterial *special_materials[CF_SPECIAL_COUNT];
@@ -133,11 +133,7 @@ struct ContentFeatures
u8 visual_solidness; // When solidness=0, this tells how it looks like
bool backface_culling;
#endif
-
- // List of textures that are used and are wanted to be included in
- // the texture atlas
- std::set<std::string> used_texturenames;
-
+
/*
Actual data
*/
@@ -148,7 +144,6 @@ struct ContentFeatures
enum NodeDrawType drawtype;
float visual_scale; // Misc. scale parameter
std::string tname_tiles[6];
- std::string tname_inventory;
MaterialSpec mspec_special[CF_SPECIAL_COUNT]; // Use setter methods
u8 alpha;
@@ -174,10 +169,6 @@ struct ContentFeatures
// 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;
- // Whether this content type often contains mineral.
- // Used for texture atlas creation.
- // Currently only enabled for CONTENT_STONE.
- bool often_contains_mineral;
// Inventory item string as which the node appears in inventory when dug.
// Mineral overrides this.
std::string dug_item;
@@ -202,9 +193,6 @@ struct ContentFeatures
u32 damage_per_second;
NodeBox selection_box;
MaterialProperties material;
- std::string cookresult_item;
- float furnace_cooktime;
- float furnace_burntime;
/*
Methods
@@ -214,23 +202,9 @@ struct ContentFeatures
~ContentFeatures();
void reset();
void serialize(std::ostream &os);
- void deSerialize(std::istream &is, IGameDef *gamedef);
+ void deSerialize(std::istream &is);
/*
- Texture setters.
-
- */
-
- // Texture setters. They also add stuff to used_texturenames.
- void setTexture(u16 i, std::string name);
- void setAllTextures(std::string name);
- void setSpecialMaterial(u16 i, const MaterialSpec &mspec);
-
- void setInventoryTexture(std::string imgname);
- void setInventoryTextureCube(std::string top,
- std::string left, std::string right);
-
- /*
Some handy methods
*/
bool isLiquid() const{
@@ -253,7 +227,6 @@ public:
virtual bool getId(const std::string &name, content_t &result) const=0;
virtual content_t getId(const std::string &name) const=0;
virtual const ContentFeatures& get(const std::string &name) const=0;
- virtual std::string getAlias(const std::string &name) const =0;
virtual void serialize(std::ostream &os)=0;
};
@@ -271,8 +244,7 @@ public:
virtual content_t getId(const std::string &name) const=0;
// If not found, returns the features of CONTENT_IGNORE
virtual const ContentFeatures& get(const std::string &name) const=0;
- virtual std::string getAlias(const std::string &name) const =0;
-
+
// Register node definition
virtual void set(content_t c, const ContentFeatures &def)=0;
// Register node definition by name (allocate an id)
@@ -281,11 +253,12 @@ public:
const ContentFeatures &def)=0;
// If returns CONTENT_IGNORE, could not allocate id
virtual content_t allocateDummy(const std::string &name)=0;
- // Set an alias so that nodes named <name> will load as <convert_to>.
- // Alias is not set if <name> has already been defined.
- // Alias will be removed if <name> is defined at a later point of time.
- virtual void setAlias(const std::string &name,
- const std::string &convert_to)=0;
+
+ /*
+ Update item alias mapping.
+ Call after updating item definitions.
+ */
+ virtual void updateAliases(IItemDefManager *idef)=0;
/*
Update tile textures to latest return values of TextueSource.
@@ -294,7 +267,7 @@ public:
virtual void updateTextures(ITextureSource *tsrc)=0;
virtual void serialize(std::ostream &os)=0;
- virtual void deSerialize(std::istream &is, IGameDef *gamedef)=0;
+ virtual void deSerialize(std::istream &is)=0;
};
IWritableNodeDefManager* createNodeDefManager();
diff --git a/src/player.cpp b/src/player.cpp
index 963f67c28..b072746c6 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // For g_settings
#include "settings.h"
#include "nodedef.h"
+#include "collision.h"
#include "environment.h"
#include "gamedef.h"
@@ -37,13 +38,13 @@ Player::Player(IGameDef *gamedef):
in_water_stable(false),
is_climbing(false),
swimming_up(false),
+ inventory(gamedef->idef()),
inventory_backup(NULL),
craftresult_is_preview(true),
hp(20),
peer_id(PEER_ID_INEXISTENT),
// protected
m_gamedef(gamedef),
- m_selected_item(0),
m_pitch(0),
m_yaw(0),
m_speed(0,0,0),
@@ -58,11 +59,6 @@ Player::~Player()
delete inventory_backup;
}
-void Player::wieldItem(u16 item)
-{
- m_selected_item = item;
-}
-
void Player::resetInventory()
{
inventory.clear();
@@ -172,7 +168,7 @@ void Player::deSerialize(std::istream &is)
hp = 20;
}
- inventory.deSerialize(is, m_gamedef);
+ inventory.deSerialize(is);
}
#ifndef SERVER
diff --git a/src/player.h b/src/player.h
index 1c9dde7e0..43f6ee5ec 100644
--- a/src/player.h
+++ b/src/player.h
@@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "inventory.h"
-#include "collision.h"
#define PLAYERNAME_SIZE 20
@@ -31,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map;
class IGameDef;
+class CollisionInfo;
class Player
{
@@ -117,16 +117,7 @@ public:
snprintf(m_name, PLAYERNAME_SIZE, "%s", name);
}
- virtual void wieldItem(u16 item);
- virtual const InventoryItem *getWieldItem() const
- {
- const InventoryList *list = inventory.getList("main");
- if (list)
- return list->getItem(m_selected_item);
- return NULL;
- }
-
- const char * getName()
+ const char * getName() const
{
return m_name;
}
@@ -174,7 +165,6 @@ protected:
IGameDef *m_gamedef;
char m_name[PLAYERNAME_SIZE];
- u16 m_selected_item;
f32 m_pitch;
f32 m_yaw;
v3f m_speed;
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index b617626a0..187d1a894 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -36,10 +36,9 @@ extern "C" {
//#include "luna.h"
#include "luaentity_common.h"
#include "content_sao.h" // For LuaEntitySAO
-#include "tooldef.h"
+#include "itemdef.h"
#include "nodedef.h"
#include "craftdef.h"
-#include "craftitemdef.h"
#include "main.h" // For g_settings
#include "settings.h" // For accessing g_settings
#include "nodemetadata.h"
@@ -127,46 +126,282 @@ public:
}
};
-std::string get_current_modname(lua_State *L)
+/*
+ Getters for stuff in main tables
+*/
+
+static Server* get_server(lua_State *L)
{
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
- std::string modname = "";
- if(lua_type(L, -1) == LUA_TSTRING)
- modname = lua_tostring(L, -1);
+ // Get server from registry
+ lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
+ Server *server = (Server*)lua_touserdata(L, -1);
lua_pop(L, 1);
- return modname;
+ return server;
}
-void check_modname_prefix(lua_State *L, std::string &name)
+static ServerEnvironment* get_env(lua_State *L)
{
- if(name.size() == 0)
- throw LuaError(L, std::string("Name is empty"));
-
- if(name[0] == ':'){
- name = name.substr(1);
- return;
+ // Get environment from registry
+ lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
+ ServerEnvironment *env = (ServerEnvironment*)lua_touserdata(L, -1);
+ lua_pop(L, 1);
+ return env;
+}
+
+static void objectref_get(lua_State *L, u16 id)
+{
+ // Get minetest.object_refs[i]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "object_refs");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushnumber(L, id);
+ lua_gettable(L, -2);
+ lua_remove(L, -2); // object_refs
+ lua_remove(L, -2); // minetest
+}
+
+static void luaentity_get(lua_State *L, u16 id)
+{
+ // Get minetest.luaentities[i]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "luaentities");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushnumber(L, id);
+ lua_gettable(L, -2);
+ lua_remove(L, -2); // luaentities
+ lua_remove(L, -2); // minetest
+}
+
+/*
+ Table field getters
+*/
+
+static bool getstringfield(lua_State *L, int table,
+ const char *fieldname, std::string &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isstring(L, -1)){
+ size_t len = 0;
+ const char *ptr = lua_tolstring(L, -1, &len);
+ result.assign(ptr, len);
+ got = true;
}
-
- std::string modname = get_current_modname(L);
- assert(modname != "");
-
- // For __builtin, anything goes
- if(modname == "__builtin")
- return;
-
- if(name.substr(0, modname.size()+1) != modname + ":")
- throw LuaError(L, std::string("Name \"")+name
- +"\" does not follow naming conventions: "
- +"\"modname:\" or \":\" prefix required)");
-
- std::string subname = name.substr(modname.size()+1);
- if(!string_allowed(subname, "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
- throw LuaError(L, std::string("Name \"")+name
- +"\" does not follow naming conventions: "
- +"\"contains unallowed characters");
+ lua_pop(L, 1);
+ return got;
+}
+
+static bool getintfield(lua_State *L, int table,
+ const char *fieldname, int &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isnumber(L, -1)){
+ result = lua_tonumber(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+static bool getfloatfield(lua_State *L, int table,
+ const char *fieldname, float &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isnumber(L, -1)){
+ result = lua_tonumber(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+static bool getboolfield(lua_State *L, int table,
+ const char *fieldname, bool &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isboolean(L, -1)){
+ result = lua_toboolean(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+static std::string checkstringfield(lua_State *L, int table,
+ const char *fieldname)
+{
+ lua_getfield(L, table, fieldname);
+ std::string s = luaL_checkstring(L, -1);
+ lua_pop(L, 1);
+ return s;
+}
+
+static std::string getstringfield_default(lua_State *L, int table,
+ const char *fieldname, const std::string &default_)
+{
+ std::string result = default_;
+ getstringfield(L, table, fieldname, result);
+ return result;
+}
+
+static int getintfield_default(lua_State *L, int table,
+ const char *fieldname, int default_)
+{
+ int result = default_;
+ getintfield(L, table, fieldname, result);
+ return result;
+}
+
+static float getfloatfield_default(lua_State *L, int table,
+ const char *fieldname, float default_)
+{
+ float result = default_;
+ getfloatfield(L, table, fieldname, result);
+ return result;
+}
+
+static bool getboolfield_default(lua_State *L, int table,
+ const char *fieldname, bool default_)
+{
+ bool result = default_;
+ getboolfield(L, table, fieldname, result);
+ return result;
+}
+
+struct EnumString
+{
+ int num;
+ const char *str;
+};
+
+static bool string_to_enum(const EnumString *spec, int &result,
+ const std::string &str)
+{
+ const EnumString *esp = spec;
+ while(esp->str){
+ if(str == std::string(esp->str)){
+ result = esp->num;
+ return true;
+ }
+ esp++;
+ }
+ return false;
+}
+
+/*static bool enum_to_string(const EnumString *spec, std::string &result,
+ int num)
+{
+ const EnumString *esp = spec;
+ while(esp){
+ if(num == esp->num){
+ result = esp->str;
+ return true;
+ }
+ esp++;
+ }
+ return false;
+}*/
+
+static int getenumfield(lua_State *L, int table,
+ const char *fieldname, const EnumString *spec, int default_)
+{
+ int result = default_;
+ string_to_enum(spec, result,
+ getstringfield_default(L, table, fieldname, ""));
+ return result;
+}
+
+static void setfloatfield(lua_State *L, int table,
+ const char *fieldname, float value)
+{
+ lua_pushnumber(L, value);
+ if(table < 0)
+ table -= 1;
+ lua_setfield(L, table, fieldname);
+}
+
+static void warn_if_field_exists(lua_State *L, int table,
+ const char *fieldname, const std::string &message)
+{
+ lua_getfield(L, table, fieldname);
+ if(!lua_isnil(L, -1)){
+ infostream<<script_get_backtrace(L)<<std::endl;
+ infostream<<"WARNING: field \""<<fieldname<<"\": "
+ <<message<<std::endl;
+ }
+ lua_pop(L, 1);
}
+/*
+ EnumString definitions
+*/
+
+struct EnumString es_ItemType[] =
+{
+ {ITEM_NONE, "none"},
+ {ITEM_NODE, "node"},
+ {ITEM_CRAFT, "craft"},
+ {ITEM_TOOL, "tool"},
+ {0, NULL},
+};
+
+struct EnumString es_DrawType[] =
+{
+ {NDT_NORMAL, "normal"},
+ {NDT_AIRLIKE, "airlike"},
+ {NDT_LIQUID, "liquid"},
+ {NDT_FLOWINGLIQUID, "flowingliquid"},
+ {NDT_GLASSLIKE, "glasslike"},
+ {NDT_ALLFACES, "allfaces"},
+ {NDT_ALLFACES_OPTIONAL, "allfaces_optional"},
+ {NDT_TORCHLIKE, "torchlike"},
+ {NDT_SIGNLIKE, "signlike"},
+ {NDT_PLANTLIKE, "plantlike"},
+ {NDT_FENCELIKE, "fencelike"},
+ {NDT_RAILLIKE, "raillike"},
+ {0, NULL},
+};
+
+struct EnumString es_ContentParamType[] =
+{
+ {CPT_NONE, "none"},
+ {CPT_LIGHT, "light"},
+ {CPT_MINERAL, "mineral"},
+ {CPT_FACEDIR_SIMPLE, "facedir_simple"},
+ {0, NULL},
+};
+
+struct EnumString es_LiquidType[] =
+{
+ {LIQUID_NONE, "none"},
+ {LIQUID_FLOWING, "flowing"},
+ {LIQUID_SOURCE, "source"},
+ {0, NULL},
+};
+
+struct EnumString es_NodeBoxType[] =
+{
+ {NODEBOX_REGULAR, "regular"},
+ {NODEBOX_FIXED, "fixed"},
+ {NODEBOX_WALLMOUNTED, "wallmounted"},
+ {0, NULL},
+};
+
+struct EnumString es_Diggability[] =
+{
+ {DIGGABLE_NOT, "not"},
+ {DIGGABLE_NORMAL, "normal"},
+ {DIGGABLE_CONSTANT, "constant"},
+ {0, NULL},
+};
+
+/*
+ C struct <-> Lua table converter functions
+*/
+
static void push_v3f(lua_State *L, v3f p)
{
lua_newtable(L);
@@ -204,20 +439,6 @@ static v2f read_v2f(lua_State *L, int index)
return p;
}
-static Server* get_server(lua_State *L)
-{
- // Get server from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
- return (Server*)lua_touserdata(L, -1);
-}
-
-static ServerEnvironment* get_env(lua_State *L)
-{
- // Get environment from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
- return (ServerEnvironment*)lua_touserdata(L, -1);
-}
-
static v3f read_v3f(lua_State *L, int index)
{
v3f pos;
@@ -365,170 +586,321 @@ static core::aabbox3d<f32> read_aabbox3df32(lua_State *L, int index, f32 scale)
return box;
}
-static bool getstringfield(lua_State *L, int table,
- const char *fieldname, std::string &result)
+/*
+ ToolDiggingProperties
+*/
+
+static ToolDiggingProperties read_tool_digging_properties(
+ lua_State *L, int table)
{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isstring(L, -1)){
- result = lua_tostring(L, -1);
- got = true;
- }
- lua_pop(L, 1);
- return got;
+ ToolDiggingProperties prop;
+ getfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
+ getfloatfield(L, table, "basetime", prop.basetime);
+ getfloatfield(L, table, "dt_weight", prop.dt_weight);
+ getfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
+ getfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
+ getfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
+ getfloatfield(L, table, "basedurability", prop.basedurability);
+ getfloatfield(L, table, "dd_weight", prop.dd_weight);
+ getfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
+ getfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
+ getfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
+ return prop;
}
-static bool getintfield(lua_State *L, int table,
- const char *fieldname, int &result)
+static void set_tool_digging_properties(lua_State *L, int table,
+ const ToolDiggingProperties &prop)
{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isnumber(L, -1)){
- result = lua_tonumber(L, -1);
- got = true;
- }
- lua_pop(L, 1);
- return got;
+ setfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
+ setfloatfield(L, table, "basetime", prop.basetime);
+ setfloatfield(L, table, "dt_weight", prop.dt_weight);
+ setfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
+ setfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
+ setfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
+ setfloatfield(L, table, "basedurability", prop.basedurability);
+ setfloatfield(L, table, "dd_weight", prop.dd_weight);
+ setfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
+ setfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
+ setfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
}
-static bool getfloatfield(lua_State *L, int table,
- const char *fieldname, float &result)
+static void push_tool_digging_properties(lua_State *L,
+ const ToolDiggingProperties &prop)
{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isnumber(L, -1)){
- result = lua_tonumber(L, -1);
- got = true;
- }
- lua_pop(L, 1);
- return got;
+ lua_newtable(L);
+ set_tool_digging_properties(L, -1, prop);
}
-static bool getboolfield(lua_State *L, int table,
- const char *fieldname, bool &result)
+/*
+ PointedThing
+*/
+
+static void push_pointed_thing(lua_State *L, const PointedThing& pointed)
{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isboolean(L, -1)){
- result = lua_toboolean(L, -1);
- got = true;
+ lua_newtable(L);
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ lua_pushstring(L, "node");
+ lua_setfield(L, -2, "type");
+ push_v3s16(L, pointed.node_undersurface);
+ lua_setfield(L, -2, "under");
+ push_v3s16(L, pointed.node_abovesurface);
+ lua_setfield(L, -2, "above");
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ lua_pushstring(L, "object");
+ lua_setfield(L, -2, "type");
+ objectref_get(L, pointed.object_id);
+ lua_setfield(L, -2, "ref");
+ }
+ else
+ {
+ lua_pushstring(L, "nothing");
+ lua_setfield(L, -2, "type");
}
- lua_pop(L, 1);
- return got;
}
-static std::string checkstringfield(lua_State *L, int table,
- const char *fieldname)
+/*
+ ItemDefinition
+*/
+
+static ItemDefinition read_item_definition(lua_State *L, int index)
{
- lua_getfield(L, table, fieldname);
- std::string s = luaL_checkstring(L, -1);
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ // Read the item definition
+ ItemDefinition def;
+
+ def.type = (ItemType)getenumfield(L, index, "type",
+ es_ItemType, ITEM_NONE);
+ getstringfield(L, index, "name", def.name);
+ getstringfield(L, index, "description", def.description);
+ getstringfield(L, index, "inventory_image", def.inventory_image);
+ getstringfield(L, index, "wield_image", def.wield_image);
+
+ lua_getfield(L, index, "wield_scale");
+ if(lua_istable(L, -1)){
+ def.wield_scale = check_v3f(L, -1);
+ }
lua_pop(L, 1);
- return s;
-}
-static std::string getstringfield_default(lua_State *L, int table,
- const char *fieldname, const std::string &default_)
-{
- std::string result = default_;
- getstringfield(L, table, fieldname, result);
- return result;
-}
+ def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
+ if(def.stack_max == 0)
+ def.stack_max = 1;
-static int getintfield_default(lua_State *L, int table,
- const char *fieldname, int default_)
-{
- int result = default_;
- getintfield(L, table, fieldname, result);
- return result;
-}
+ lua_getfield(L, index, "on_use");
+ def.usable = lua_isfunction(L, -1);
+ lua_pop(L, 1);
-/*static float getfloatfield_default(lua_State *L, int table,
- const char *fieldname, float default_)
-{
- float result = default_;
- getfloatfield(L, table, fieldname, result);
- return result;
-}*/
+ getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
-static bool getboolfield_default(lua_State *L, int table,
- const char *fieldname, bool default_)
-{
- bool result = default_;
- getboolfield(L, table, fieldname, result);
- return result;
+ lua_getfield(L, index, "tool_digging_properties");
+ if(lua_istable(L, -1)){
+ def.tool_digging_properties = new ToolDiggingProperties(
+ read_tool_digging_properties(L, -1));
+ }
+ lua_pop(L, 1);
+
+ // If name is "" (hand), ensure there are ToolDiggingProperties
+ // because it will be looked up there whenever any other item has
+ // no ToolDiggingProperties
+ if(def.name == "" && def.tool_digging_properties == NULL){
+ def.tool_digging_properties = new ToolDiggingProperties();
+ }
+
+ return def;
}
-struct EnumString
-{
- int num;
- const char *str;
-};
+/*
+ ContentFeatures
+*/
-static bool string_to_enum(const EnumString *spec, int &result,
- const std::string &str)
+static ContentFeatures read_content_features(lua_State *L, int index)
{
- const EnumString *esp = spec;
- while(esp->str){
- if(str == std::string(esp->str)){
- result = esp->num;
- return true;
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ ContentFeatures f;
+ getstringfield(L, index, "name", f.name);
+
+ /* Visual definition */
+
+ f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", es_DrawType,
+ NDT_NORMAL);
+ getfloatfield(L, index, "visual_scale", f.visual_scale);
+
+ 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){
+ // key at index -2 and value at index -1
+ if(lua_isstring(L, -1))
+ f.tname_tiles[i] = lua_tostring(L, -1);
+ else
+ f.tname_tiles[i] = "";
+ // 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){
+ std::string lastname = f.tname_tiles[i-1];
+ while(i < 6){
+ f.tname_tiles[i] = lastname;
+ i++;
+ }
}
- esp++;
}
- return false;
-}
+ lua_pop(L, 1);
-/*static bool enum_to_string(const EnumString *spec, std::string &result,
- int num)
-{
- const EnumString *esp = spec;
- while(esp){
- if(num == esp->num){
- result = esp->str;
- return true;
+ 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){
+ // key at index -2 and value at index -1
+ int smtable = lua_gettop(L);
+ std::string tname = getstringfield_default(
+ L, smtable, "image", "");
+ bool backface_culling = getboolfield_default(
+ L, smtable, "backface_culling", true);
+ MaterialSpec mspec(tname, backface_culling);
+ f.mspec_special[i] = mspec;
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ i++;
+ if(i==6){
+ lua_pop(L, 1);
+ break;
+ }
}
- esp++;
}
- return false;
-}*/
+ lua_pop(L, 1);
-static int getenumfield(lua_State *L, int table,
- const char *fieldname, const EnumString *spec, int default_)
-{
- int result = default_;
- string_to_enum(spec, result,
- getstringfield_default(L, table, fieldname, ""));
- return result;
-}
+ f.alpha = getintfield_default(L, index, "alpha", 255);
-static void setfloatfield(lua_State *L, int table,
- const char *fieldname, float value)
-{
- lua_pushnumber(L, value);
- if(table < 0)
- table -= 1;
- lua_setfield(L, table, fieldname);
-}
+ /* 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);
-static void warn_if_field_exists(lua_State *L, int table,
- const char *fieldname, const std::string &message)
-{
- lua_getfield(L, table, fieldname);
- if(!lua_isnil(L, -1)){
- infostream<<script_get_backtrace(L)<<std::endl;
- infostream<<"WARNING: field \""<<fieldname<<"\": "
- <<message<<std::endl;
+ f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
+ es_ContentParamType, CPT_NONE);
+
+ // 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);
+ warn_if_field_exists(L, index, "light_propagates",
+ "deprecated: determined from paramtype");
+ 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);
+ // If true, param2 is set to direction when placed. Used for torches.
+ // NOTE: the direction format is quite inefficient and should be changed
+ getboolfield(L, index, "wall_mounted", f.wall_mounted);
+ // Inventory item string as which the node appears in inventory when dug.
+ // Mineral overrides this.
+ getstringfield(L, index, "dug_item", f.dug_item);
+ // Extra dug item and its rarity
+ getstringfield(L, index, "extra_dug_item", f.extra_dug_item);
+ // Usual get interval for extra dug item
+ getintfield(L, index, "extra_dug_item_rarity", f.extra_dug_item_rarity);
+ // Metadata name of node (eg. "furnace")
+ getstringfield(L, index, "metadata_name", f.metadata_name);
+ // Whether the node is non-liquid, source liquid or flowing liquid
+ f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
+ 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);
+ // 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, "selection_box");
+ if(lua_istable(L, -1)){
+ f.selection_box.type = (NodeBoxType)getenumfield(L, -1, "type",
+ es_NodeBoxType, NODEBOX_REGULAR);
+
+ lua_getfield(L, -1, "fixed");
+ if(lua_istable(L, -1))
+ f.selection_box.fixed = read_aabbox3df32(L, -1, BS);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "wall_top");
+ if(lua_istable(L, -1))
+ f.selection_box.wall_top = read_aabbox3df32(L, -1, BS);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "wall_bottom");
+ if(lua_istable(L, -1))
+ f.selection_box.wall_bottom = read_aabbox3df32(L, -1, BS);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "wall_side");
+ if(lua_istable(L, -1))
+ f.selection_box.wall_side = read_aabbox3df32(L, -1, BS);
+ lua_pop(L, 1);
}
lua_pop(L, 1);
+
+ lua_getfield(L, index, "material");
+ if(lua_istable(L, -1)){
+ f.material.diggability = (Diggability)getenumfield(L, -1, "diggability",
+ es_Diggability, DIGGABLE_NORMAL);
+
+ getfloatfield(L, -1, "constant_time", f.material.constant_time);
+ getfloatfield(L, -1, "weight", f.material.weight);
+ getfloatfield(L, -1, "crackiness", f.material.crackiness);
+ getfloatfield(L, -1, "crumbliness", f.material.crumbliness);
+ getfloatfield(L, -1, "cuttability", f.material.cuttability);
+ getfloatfield(L, -1, "flammability", f.material.flammability);
+ }
+ lua_pop(L, 1);
+
+ return f;
}
/*
Inventory stuff
*/
+static ItemStack read_item(lua_State *L, int index);
+
static void inventory_set_list_from_lua(Inventory *inv, const char *name,
- lua_State *L, int tableindex, IGameDef *gamedef, int forcesize=-1)
+ lua_State *L, int tableindex, int forcesize=-1)
{
+ dstream<<"inventory_set_list_from_lua\n";
if(tableindex < 0)
tableindex = lua_gettop(L) + 1 + tableindex;
// If nil, delete list
@@ -537,39 +909,30 @@ static void inventory_set_list_from_lua(Inventory *inv, const char *name,
return;
}
// Otherwise set list
- std::list<std::string> items;
+ std::vector<ItemStack> items;
luaL_checktype(L, tableindex, LUA_TTABLE);
- int table = tableindex;
lua_pushnil(L);
- while(lua_next(L, table) != 0){
+ while(lua_next(L, tableindex) != 0){
// key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- std::string itemstring = luaL_checkstring(L, -1);
- items.push_back(itemstring);
+ items.push_back(read_item(L, -1));
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
int listsize = (forcesize != -1) ? forcesize : items.size();
InventoryList *invlist = inv->addList(name, listsize);
int index = 0;
- for(std::list<std::string>::const_iterator
+ for(std::vector<ItemStack>::const_iterator
i = items.begin(); i != items.end(); i++){
if(forcesize != -1 && index == forcesize)
break;
- const std::string &itemstring = *i;
- InventoryItem *newitem = NULL;
- if(itemstring != "")
- newitem = InventoryItem::deSerialize(itemstring,
- gamedef);
- InventoryItem *olditem = invlist->changeItem(index, newitem);
- delete olditem;
+ invlist->changeItem(index, *i);
index++;
}
while(forcesize != -1 && index < forcesize){
- InventoryItem *olditem = invlist->changeItem(index, NULL);
- delete olditem;
+ invlist->deleteItem(index);
index++;
}
+ dstream<<"inventory_set_list_from_lua done\n";
}
static void inventory_get_list_to_lua(Inventory *inv, const char *name,
@@ -588,375 +951,317 @@ static void inventory_get_list_to_lua(Inventory *inv, const char *name,
lua_newtable(L);
int table = lua_gettop(L);
for(u32 i=0; i<invlist->getSize(); i++){
- InventoryItem *item = invlist->getItem(i);
+ ItemStack item = invlist->getItem(i);
lua_pushvalue(L, table_insert);
lua_pushvalue(L, table);
- if(item == NULL){
- lua_pushstring(L, "");
- } else {
- lua_pushstring(L, item->getItemString().c_str());
- }
+ lua_pushstring(L, item.getItemString().c_str());
if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
}
-static void push_stack_item(lua_State *L, InventoryItem *item0)
-{
- if(item0 == NULL){
- lua_pushnil(L);
- }
- else if(std::string("MaterialItem") == item0->getName()){
- MaterialItem *item = (MaterialItem*)item0;
- lua_newtable(L);
- lua_pushstring(L, "node");
- lua_setfield(L, -2, "type");
- lua_pushstring(L, item->getNodeName().c_str());
- lua_setfield(L, -2, "name");
- }
- else if(std::string("CraftItem") == item0->getName()){
- CraftItem *item = (CraftItem*)item0;
- lua_newtable(L);
- lua_pushstring(L, "craft");
- lua_setfield(L, -2, "type");
- lua_pushstring(L, item->getSubName().c_str());
- lua_setfield(L, -2, "name");
- }
- else if(std::string("ToolItem") == item0->getName()){
- ToolItem *item = (ToolItem*)item0;
- lua_newtable(L);
- lua_pushstring(L, "tool");
- lua_setfield(L, -2, "type");
- lua_pushstring(L, item->getToolName().c_str());
- lua_setfield(L, -2, "name");
- lua_pushstring(L, itos(item->getWear()).c_str());
- lua_setfield(L, -2, "wear");
- }
- else{
- errorstream<<"push_stack_item: Unknown item name: \""
- <<item0->getName()<<"\""<<std::endl;
- lua_pushnil(L);
- }
-}
-
-static InventoryItem* check_stack_item(lua_State *L, int index)
-{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
- if(lua_isnil(L, index))
- return NULL;
- if(!lua_istable(L, index))
- throw LuaError(L, "check_stack_item: Item not nil or table");
- // A very crappy implementation for now
- // Will be replaced when unified namespace for items is made
- std::string type = getstringfield_default(L, index, "type", "");
- std::string name = getstringfield_default(L, index, "name", "");
- std::string num = getstringfield_default(L, index, "wear", "_");
- if(num == "_")
- num = 1;
- std::string itemstring = type + " \"" + name + "\" " + num;
- try{
- return InventoryItem::deSerialize(itemstring, get_server(L));
- }catch(SerializationError &e){
- throw LuaError(L, std::string("check_stack_item: "
- "internal error (itemstring=\"")+itemstring+"\")");
- }
-}
-
/*
- ToolDiggingProperties
+ Helpful macros for userdata classes
*/
-static ToolDiggingProperties read_tool_digging_properties(
- lua_State *L, int table)
-{
- ToolDiggingProperties prop;
- getfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
- getfloatfield(L, table, "basetime", prop.basetime);
- getfloatfield(L, table, "dt_weight", prop.dt_weight);
- getfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
- getfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
- getfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
- getfloatfield(L, table, "basedurability", prop.basedurability);
- getfloatfield(L, table, "dd_weight", prop.dd_weight);
- getfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
- getfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
- getfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
- return prop;
-}
-
-static void set_tool_digging_properties(lua_State *L, int table,
- const ToolDiggingProperties &prop)
-{
- setfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
- setfloatfield(L, table, "basetime", prop.basetime);
- setfloatfield(L, table, "dt_weight", prop.dt_weight);
- setfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
- setfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
- setfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
- setfloatfield(L, table, "basedurability", prop.basedurability);
- setfloatfield(L, table, "dd_weight", prop.dd_weight);
- setfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
- setfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
- setfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
-}
-
-static void push_tool_digging_properties(lua_State *L,
- const ToolDiggingProperties &prop)
-{
- lua_newtable(L);
- set_tool_digging_properties(L, -1, prop);
-}
+#define method(class, name) {#name, class::l_##name}
/*
- ToolDefinition
+ LuaItemStack
*/
-static ToolDefinition read_tool_definition(lua_State *L, int table)
+class LuaItemStack
{
- ToolDefinition def;
- getstringfield(L, table, "image", def.imagename);
- def.properties = read_tool_digging_properties(L, table);
- return def;
-}
+private:
+ ItemStack m_stack;
-static void push_tool_definition(lua_State *L, const ToolDefinition &def)
-{
- lua_newtable(L);
- lua_pushstring(L, def.imagename.c_str());
- lua_setfield(L, -2, "image");
- set_tool_digging_properties(L, -1, def.properties);
-}
+ static const char className[];
+ static const luaL_reg methods[];
-/*
- EnumString definitions
-*/
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L)
+ {
+ LuaItemStack *o = *(LuaItemStack **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+ }
-struct EnumString es_DrawType[] =
-{
- {NDT_NORMAL, "normal"},
- {NDT_AIRLIKE, "airlike"},
- {NDT_LIQUID, "liquid"},
- {NDT_FLOWINGLIQUID, "flowingliquid"},
- {NDT_GLASSLIKE, "glasslike"},
- {NDT_ALLFACES, "allfaces"},
- {NDT_ALLFACES_OPTIONAL, "allfaces_optional"},
- {NDT_TORCHLIKE, "torchlike"},
- {NDT_SIGNLIKE, "signlike"},
- {NDT_PLANTLIKE, "plantlike"},
- {NDT_FENCELIKE, "fencelike"},
- {NDT_RAILLIKE, "raillike"},
- {0, NULL},
-};
+ // is_empty(self) -> true/false
+ static int l_is_empty(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushboolean(L, item.empty());
+ return 1;
+ }
-struct EnumString es_ContentParamType[] =
-{
- {CPT_NONE, "none"},
- {CPT_LIGHT, "light"},
- {CPT_MINERAL, "mineral"},
- {CPT_FACEDIR_SIMPLE, "facedir_simple"},
- {0, NULL},
-};
+ // get_name(self) -> string
+ static int l_get_name(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushstring(L, item.name.c_str());
+ return 1;
+ }
-struct EnumString es_LiquidType[] =
-{
- {LIQUID_NONE, "none"},
- {LIQUID_FLOWING, "flowing"},
- {LIQUID_SOURCE, "source"},
- {0, NULL},
-};
+ // get_count(self) -> number
+ static int l_get_count(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.count);
+ return 1;
+ }
-struct EnumString es_NodeBoxType[] =
-{
- {NODEBOX_REGULAR, "regular"},
- {NODEBOX_FIXED, "fixed"},
- {NODEBOX_WALLMOUNTED, "wallmounted"},
- {0, NULL},
-};
+ // get_wear(self) -> number
+ static int l_get_wear(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.wear);
+ return 1;
+ }
-struct EnumString es_Diggability[] =
-{
- {DIGGABLE_NOT, "not"},
- {DIGGABLE_NORMAL, "normal"},
- {DIGGABLE_CONSTANT, "constant"},
- {0, NULL},
-};
+ // get_metadata(self) -> string
+ static int l_get_metadata(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
+ return 1;
+ }
-/*
- Getters for stuff in main tables
-*/
+ // clear(self) -> true
+ static int l_clear(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ o->m_stack.clear();
+ lua_pushboolean(L, true);
+ return 1;
+ }
-static void objectref_get(lua_State *L, u16 id)
-{
- // Get minetest.object_refs[i]
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "object_refs");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushnumber(L, id);
- lua_gettable(L, -2);
- lua_remove(L, -2); // object_refs
- lua_remove(L, -2); // minetest
-}
+ // replace(self, itemstack or itemstring or table or nil) -> true
+ static int l_replace(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ o->m_stack = read_item(L, 2);
+ lua_pushboolean(L, true);
+ return 1;
+ }
-static void luaentity_get(lua_State *L, u16 id)
-{
- // Get minetest.luaentities[i]
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "luaentities");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushnumber(L, id);
- lua_gettable(L, -2);
- lua_remove(L, -2); // luaentities
- lua_remove(L, -2); // minetest
-}
+ // to_string(self) -> string
+ static int l_to_string(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ std::string itemstring = o->m_stack.getItemString();
+ lua_pushstring(L, itemstring.c_str());
+ return 1;
+ }
-/*
- Object wrappers
-*/
+ // to_table(self) -> table or nil
+ static int l_to_table(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ const ItemStack &item = o->m_stack;
+ if(item.empty())
+ {
+ lua_pushnil(L);
+ }
+ else
+ {
+ lua_newtable(L);
+ lua_pushstring(L, item.name.c_str());
+ lua_setfield(L, -2, "name");
+ lua_pushinteger(L, item.count);
+ lua_setfield(L, -2, "count");
+ lua_pushinteger(L, item.wear);
+ lua_setfield(L, -2, "wear");
+ lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
+ lua_setfield(L, -2, "metadata");
+ }
+ return 1;
+ }
-#define method(class, name) {#name, class::l_##name}
+ // get_stack_max(self) -> number
+ static int l_get_stack_max(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.getStackMax(get_server(L)->idef()));
+ return 1;
+ }
-/*
- ItemStack
-*/
+ // get_free_space(self) -> number
+ static int l_get_free_space(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.freeSpace(get_server(L)->idef()));
+ return 1;
+ }
-class ItemStack
-{
-private:
- InventoryItem *m_stack;
+ // is_known(self) -> true/false
+ // Checks if the item is defined.
+ static int l_is_known(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ bool is_known = item.isKnown(get_server(L)->idef());
+ lua_pushboolean(L, is_known);
+ return 1;
+ }
- static const char className[];
- static const luaL_reg methods[];
+ // get_definition(self) -> table
+ // Returns the item definition table from minetest.registered_items,
+ // or a fallback one (name="unknown")
+ static int l_get_definition(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
- // Exported functions
-
- // garbage collector
- static int gc_object(lua_State *L) {
- ItemStack *o = *(ItemStack **)(lua_touserdata(L, 1));
- delete o;
- return 0;
+ // Get minetest.registered_items[name]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_items");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, item.name.c_str());
+ if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "unknown");
+ }
+ return 1;
}
- // peek_item(self)
- static int l_peek_item(lua_State *L)
+ // get_tool_digging_properties(self) -> table
+ // Returns the effective tool digging properties.
+ // Returns those of the hand ("") if this item has none associated.
+ static int l_get_tool_digging_properties(lua_State *L)
{
- ItemStack *o = checkobject(L, 1);
- push_stack_item(L, o->m_stack);
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ const ToolDiggingProperties &prop =
+ item.getToolDiggingProperties(get_server(L)->idef());
+ push_tool_digging_properties(L, prop);
return 1;
}
- // take_item(self)
- static int l_take_item(lua_State *L)
+ // add_wear(self, amount) -> true/false
+ // The range for "amount" is [0,65535]. Wear is only added if the item
+ // is a tool. Adding wear might destroy the item.
+ // Returns true if the item is (or was) a tool.
+ static int l_add_wear(lua_State *L)
{
- ItemStack *o = checkobject(L, 1);
- push_stack_item(L, o->m_stack);
- if(o->m_stack->getCount() <= 1){
- delete o->m_stack;
- o->m_stack = NULL;
- } else {
- o->m_stack->remove(1);
- }
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ int amount = lua_tointeger(L, 2);
+ bool result = item.addWear(amount, get_server(L)->idef());
+ lua_pushboolean(L, result);
return 1;
}
- // put_item(self, item) -> true/false
- static int l_put_item(lua_State *L)
+ // add_item(self, itemstack or itemstring or table or nil) -> itemstack
+ // Returns leftover item stack
+ static int l_add_item(lua_State *L)
{
- ItemStack *o = checkobject(L, 1);
- InventoryItem *item = check_stack_item(L, 2);
- if(!item){ // nil can always be inserted
- lua_pushboolean(L, true);
- return 1;
- }
- if(!item->addableTo(o->m_stack)){
- lua_pushboolean(L, false);
- return 1;
- }
- o->m_stack->add(1);
- delete item;
- lua_pushboolean(L, true);
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ ItemStack newitem = read_item(L, 2);
+ ItemStack leftover = item.addItem(newitem, get_server(L)->idef());
+ create(L, leftover);
return 1;
}
- // put_stackstring(self, stackstring) -> true/false
- static int l_put_stackstring(lua_State *L)
+ // item_fits(self, itemstack or itemstring or table or nil) -> true/false, itemstack
+ // First return value is true iff the new item fits fully into the stack
+ // Second return value is the would-be-left-over item stack
+ static int l_item_fits(lua_State *L)
{
- ItemStack *o = checkobject(L, 1);
- std::string stackstring = luaL_checkstring(L, 2);
- try{
- InventoryItem *item = InventoryItem::deSerialize(stackstring,
- get_server(L));
- if(!item->addableTo(o->m_stack)){
- lua_pushboolean(L, false);
- return 1;
- }
- o->m_stack->add(1);
- delete item;
- lua_pushboolean(L, true);
- return 1;
- }
- catch(SerializationError &e){
- lua_pushboolean(L, false);
- return 1;
- }
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ ItemStack newitem = read_item(L, 2);
+ ItemStack restitem;
+ bool fits = item.itemFits(newitem, &restitem, get_server(L)->idef());
+ lua_pushboolean(L, fits); // first return value
+ create(L, restitem); // second return value
+ return 2;
+ }
+
+ // take_item(self, takecount=1) -> itemstack
+ static int l_take_item(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ u32 takecount = 1;
+ if(!lua_isnone(L, 2))
+ takecount = lua_tointeger(L, 2);
+ ItemStack taken = item.takeItem(takecount);
+ create(L, taken);
+ return 1;
+ }
+
+ // peek_item(self, peekcount=1) -> itemstack
+ static int l_peek_item(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ u32 peekcount = 1;
+ if(!lua_isnone(L, 2))
+ peekcount = lua_tointeger(L, 2);
+ ItemStack peekaboo = item.peekItem(peekcount);
+ create(L, peekaboo);
+ return 1;
}
public:
- ItemStack(InventoryItem *item=NULL):
+ LuaItemStack(const ItemStack &item):
m_stack(item)
{
}
- ~ItemStack()
+ ~LuaItemStack()
{
- delete m_stack;
}
- static ItemStack* checkobject(lua_State *L, int narg)
+ const ItemStack& getItem() const
{
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(ItemStack**)ud; // unbox pointer
+ return m_stack;
}
-
- InventoryItem* getItemCopy()
+ ItemStack& getItem()
{
- if(!m_stack)
- return NULL;
- return m_stack->clone();
+ return m_stack;
}
- // Creates an ItemStack and leaves it on top of stack
+ // LuaItemStack(itemstack or itemstring or table or nil)
+ // Creates an LuaItemStack and leaves it on top of stack
static int create_object(lua_State *L)
{
- InventoryItem *item = NULL;
- if(lua_isstring(L, 1)){
- std::string itemstring = lua_tostring(L, 1);
- if(itemstring != ""){
- try{
- IGameDef *gdef = get_server(L);
- item = InventoryItem::deSerialize(itemstring, gdef);
- }catch(SerializationError &e){
- }
- }
- }
- ItemStack *o = new ItemStack(item);
+ ItemStack item = read_item(L, 1);
+ LuaItemStack *o = new LuaItemStack(item);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
return 1;
}
// Not callable from Lua
- static int create(lua_State *L, InventoryItem *item)
+ static int create(lua_State *L, const ItemStack &item)
{
- ItemStack *o = new ItemStack(item);
+ LuaItemStack *o = new LuaItemStack(item);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
return 1;
}
+ static LuaItemStack* checkobject(lua_State *L, int narg)
+ {
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(LuaItemStack**)ud; // unbox pointer
+ }
+
static void Register(lua_State *L)
{
lua_newtable(L);
@@ -981,19 +1286,83 @@ public:
luaL_openlib(L, 0, methods, 0); // fill methodtable
lua_pop(L, 1); // drop methodtable
- // Can be created from Lua (ItemStack::create(itemstring))
+ // Can be created from Lua (LuaItemStack(itemstack or itemstring or table or nil))
lua_register(L, className, create_object);
}
};
-const char ItemStack::className[] = "ItemStack";
-const luaL_reg ItemStack::methods[] = {
- method(ItemStack, peek_item),
- method(ItemStack, take_item),
- method(ItemStack, put_item),
- method(ItemStack, put_stackstring),
+const char LuaItemStack::className[] = "ItemStack";
+const luaL_reg LuaItemStack::methods[] = {
+ method(LuaItemStack, is_empty),
+ method(LuaItemStack, get_name),
+ method(LuaItemStack, get_count),
+ method(LuaItemStack, get_wear),
+ method(LuaItemStack, get_metadata),
+ method(LuaItemStack, clear),
+ method(LuaItemStack, replace),
+ method(LuaItemStack, to_string),
+ method(LuaItemStack, to_table),
+ method(LuaItemStack, get_stack_max),
+ method(LuaItemStack, get_free_space),
+ method(LuaItemStack, is_known),
+ method(LuaItemStack, get_definition),
+ method(LuaItemStack, get_tool_digging_properties),
+ method(LuaItemStack, add_wear),
+ method(LuaItemStack, add_item),
+ method(LuaItemStack, item_fits),
+ method(LuaItemStack, take_item),
+ method(LuaItemStack, peek_item),
{0,0}
};
+static ItemStack read_item(lua_State *L, int index)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ if(lua_isnil(L, index))
+ {
+ return ItemStack();
+ }
+ else if(lua_isuserdata(L, index))
+ {
+ // Convert from LuaItemStack
+ LuaItemStack *o = LuaItemStack::checkobject(L, index);
+ return o->getItem();
+ }
+ else if(lua_isstring(L, index))
+ {
+ // Convert from itemstring
+ std::string itemstring = lua_tostring(L, index);
+ IItemDefManager *idef = get_server(L)->idef();
+ try
+ {
+ ItemStack item;
+ item.deSerialize(itemstring, idef);
+ return item;
+ }
+ catch(SerializationError &e)
+ {
+ infostream<<"WARNING: unable to create item from itemstring"
+ <<": "<<itemstring<<std::endl;
+ return ItemStack();
+ }
+ }
+ else if(lua_istable(L, index))
+ {
+ // Convert from table
+ IItemDefManager *idef = get_server(L)->idef();
+ std::string name = getstringfield_default(L, index, "name", "");
+ int count = getintfield_default(L, index, "count", 1);
+ int wear = getintfield_default(L, index, "wear", 0);
+ std::string metadata = getstringfield_default(L, index, "metadata", "");
+ return ItemStack(name, count, wear, metadata, idef);
+ }
+ else
+ {
+ throw LuaError(L, "Expecting itemstack, itemstring, table or nil");
+ }
+}
+
/*
InvRef
*/
@@ -1028,15 +1397,6 @@ private:
return inv->getList(listname);
}
- static InventoryItem* getitem(lua_State *L, InvRef *ref,
- const char *listname, int i)
- {
- InventoryList *list = getlist(L, ref, listname);
- if(!list)
- return NULL;
- return list->getItem(i);
- }
-
static void reportInventoryChange(lua_State *L, InvRef *ref)
{
// Inform other things that the inventory has changed
@@ -1088,39 +1448,35 @@ private:
return 0;
}
- // get_stack(self, listname, i)
+ // get_stack(self, listname, i) -> itemstack
static int l_get_stack(lua_State *L)
{
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
int i = luaL_checknumber(L, 3) - 1;
- InventoryItem *item = getitem(L, ref, listname, i);
- if(!item){
- ItemStack::create(L, NULL);
- return 1;
- }
- ItemStack::create(L, item->clone());
+ InventoryList *list = getlist(L, ref, listname);
+ ItemStack item;
+ if(list != NULL && i >= 0 && i < (int) list->getSize())
+ item = list->getItem(i);
+ LuaItemStack::create(L, item);
return 1;
}
- // set_stack(self, listname, i, stack)
+ // set_stack(self, listname, i, stack) -> true/false
static int l_set_stack(lua_State *L)
{
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
int i = luaL_checknumber(L, 3) - 1;
- ItemStack *stack = ItemStack::checkobject(L, 4);
+ ItemStack newitem = read_item(L, 4);
InventoryList *list = getlist(L, ref, listname);
- if(!list){
+ if(list != NULL && i >= 0 && i < (int) list->getSize()){
+ list->changeItem(i, newitem);
+ reportInventoryChange(L, ref);
+ lua_pushboolean(L, true);
+ } else {
lua_pushboolean(L, false);
- return 1;
}
- InventoryItem *newitem = stack->getItemCopy();
- InventoryItem *olditem = list->changeItem(i, newitem);
- bool success = (olditem != newitem);
- delete olditem;
- lua_pushboolean(L, success);
- reportInventoryChange(L, ref);
return 1;
}
@@ -1143,57 +1499,79 @@ private:
InventoryList *list = inv->getList(listname);
if(list)
inventory_set_list_from_lua(inv, listname, L, 3,
- get_server(L), list->getSize());
+ list->getSize());
else
- inventory_set_list_from_lua(inv, listname, L, 3,
- get_server(L));
+ inventory_set_list_from_lua(inv, listname, L, 3);
reportInventoryChange(L, ref);
return 0;
}
- // autoinsert_stack(self, listname, stack)
- static int l_autoinsert_stack(lua_State *L)
+ // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
+ // Returns the leftover stack
+ static int l_add_item(lua_State *L)
{
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
- ItemStack *stack = ItemStack::checkobject(L, 3);
+ ItemStack item = read_item(L, 3);
InventoryList *list = getlist(L, ref, listname);
- if(!list){
- lua_pushboolean(L, false);
- return 1;
+ if(list){
+ ItemStack leftover = list->addItem(item);
+ if(leftover.count != item.count)
+ reportInventoryChange(L, ref);
+ LuaItemStack::create(L, leftover);
+ } else {
+ LuaItemStack::create(L, item);
}
- InventoryItem *item = stack->getItemCopy();
- if(list->roomForItem(item)){
- delete list->addItem(item);
- lua_pushboolean(L, true);
- reportInventoryChange(L, ref);
+ return 1;
+ }
+
+ // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
+ // Returns true if the item completely fits into the list
+ static int l_room_for_item(lua_State *L)
+ {
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ ItemStack item = read_item(L, 3);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list){
+ lua_pushboolean(L, list->roomForItem(item));
} else {
- delete item;
lua_pushboolean(L, false);
}
return 1;
}
- // autoinsert_stackstring(self, listname, stackstring)
- static int l_autoinsert_stackstring(lua_State *L)
+ // contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
+ // Returns true if the list contains the given count of the given item name
+ static int l_contains_item(lua_State *L)
{
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
- const char *stackstring = luaL_checkstring(L, 3);
+ ItemStack item = read_item(L, 3);
InventoryList *list = getlist(L, ref, listname);
- if(!list){
+ if(list){
+ lua_pushboolean(L, list->containsItem(item));
+ } else {
lua_pushboolean(L, false);
- return 1;
}
- InventoryItem *item = InventoryItem::deSerialize(stackstring,
- get_server(L));
- if(list->roomForItem(item)){
- delete list->addItem(item);
- lua_pushboolean(L, true);
- reportInventoryChange(L, ref);
+ return 1;
+ }
+
+ // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
+ // Returns the items that were actually removed
+ static int l_remove_item(lua_State *L)
+ {
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ ItemStack item = read_item(L, 3);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list){
+ ItemStack removed = list->removeItem(item);
+ if(!removed.empty())
+ reportInventoryChange(L, ref);
+ LuaItemStack::create(L, removed);
} else {
- delete item;
- lua_pushboolean(L, false);
+ LuaItemStack::create(L, ItemStack());
}
return 1;
}
@@ -1266,8 +1644,10 @@ const luaL_reg InvRef::methods[] = {
method(InvRef, set_stack),
method(InvRef, get_list),
method(InvRef, set_list),
- method(InvRef, autoinsert_stack),
- method(InvRef, autoinsert_stackstring),
+ method(InvRef, add_item),
+ method(InvRef, room_for_item),
+ method(InvRef, contains_item),
+ method(InvRef, remove_item),
{0,0}
};
@@ -1420,36 +1800,6 @@ private:
return 1;
}
- // deprecated: inventory_set_list(self, name, {item1, item2, ...})
- static int l_inventory_set_list(lua_State *L)
- {
- infostream<<"Deprecated: inventory_set_list"<<std::endl;
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- Inventory *inv = meta->getInventory();
- const char *name = luaL_checkstring(L, 2);
- inventory_set_list_from_lua(inv, name, L, 3,
- ref->m_env->getGameDef());
- reportMetadataChange(ref);
- return 0;
- }
-
- // deprecated: inventory_get_list(self, name)
- static int l_inventory_get_list(lua_State *L)
- {
- infostream<<"Deprecated: inventory_get_list"<<std::endl;
- NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
- // Do it
- Inventory *inv = meta->getInventory();
- const char *name = luaL_checkstring(L, 2);
- inventory_get_list_to_lua(inv, name, L);
- return 1;
- }
-
// set_inventory_draw_spec(self, text)
static int l_set_inventory_draw_spec(lua_State *L)
{
@@ -1636,8 +1986,6 @@ const luaL_reg NodeMetaRef::methods[] = {
method(NodeMetaRef, get_owner),
method(NodeMetaRef, set_infotext),
method(NodeMetaRef, get_inventory),
- method(NodeMetaRef, inventory_set_list), // deprecated
- method(NodeMetaRef, inventory_get_list), // deprecated
method(NodeMetaRef, set_inventory_draw_spec),
method(NodeMetaRef, set_allow_text_input),
method(NodeMetaRef, set_allow_removal),
@@ -1798,122 +2146,98 @@ private:
return 0;
}
- // get_wield_digging_properties(self)
- static int l_get_wield_digging_properties(lua_State *L)
+ // set_hp(self, hp)
+ // hp = number of hitpoints (2 * number of hearts)
+ // returns: nil
+ static int l_set_hp(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
+ luaL_checknumber(L, 2);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
+ int hp = lua_tonumber(L, 2);
+ infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
+ <<" hp="<<hp<<std::endl;
// Do it
- ToolDiggingProperties prop;
- co->getWieldDiggingProperties(&prop);
- push_tool_digging_properties(L, prop);
+ co->setHP(hp);
+ // Return
+ return 0;
+ }
+
+ // get_hp(self)
+ // returns: number of hitpoints (2 * number of hearts)
+ // 0 if not applicable to this type of object
+ static int l_get_hp(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ int hp = co->getHP();
+ infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
+ <<" hp="<<hp<<std::endl;
+ // Return
+ lua_pushnumber(L, hp);
return 1;
}
- // damage_wielded_item(self, amount)
- static int l_damage_wielded_item(lua_State *L)
+ // get_inventory(self)
+ static int l_get_inventory(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
// Do it
- int amount = lua_tonumber(L, 2);
- co->damageWieldedItem(amount);
- return 0;
+ InventoryLocation loc = co->getInventoryLocation();
+ if(get_server(L)->getInventory(loc) != NULL)
+ InvRef::create(L, loc);
+ else
+ lua_pushnil(L);
+ return 1;
}
- // add_to_inventory(self, itemstring)
- // returns: true if item was added, (false, "reason") otherwise
- static int l_add_to_inventory(lua_State *L)
+ // get_wield_list(self)
+ static int l_get_wield_list(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- luaL_checkstring(L, 2);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
- // itemstring
- const char *itemstring = luaL_checkstring(L, 2);
- infostream<<"ObjectRef::l_add_to_inventory(): id="<<co->getId()
- <<" itemstring=\""<<itemstring<<"\""<<std::endl;
// Do it
- std::istringstream is(itemstring, std::ios::binary);
- ServerEnvironment *env = co->getEnv();
- assert(env);
- IGameDef *gamedef = env->getGameDef();
- try{
- InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
- if(item->getCount() == 0)
- item->setCount(1);
- bool added = co->addToInventory(item);
- // Return
- lua_pushboolean(L, added);
- if(!added)
- lua_pushstring(L, "failed to add item");
- return 2;
- } catch(SerializationError &e){
- // Return
- lua_pushboolean(L, false);
- lua_pushstring(L, (std::string("Invalid item: ")
- + e.what()).c_str());
- return 2;
- }
+ lua_pushstring(L, co->getWieldList().c_str());
+ return 1;
}
- // add_to_inventory_later(self, itemstring)
- // returns: nil
- static int l_add_to_inventory_later(lua_State *L)
+ // get_wield_index(self)
+ static int l_get_wield_index(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- luaL_checkstring(L, 2);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
- // itemstring
- const char *itemstring = luaL_checkstring(L, 2);
- infostream<<"ObjectRef::l_add_to_inventory_later(): id="<<co->getId()
- <<" itemstring=\""<<itemstring<<"\""<<std::endl;
// Do it
- std::istringstream is(itemstring, std::ios::binary);
- ServerEnvironment *env = co->getEnv();
- assert(env);
- IGameDef *gamedef = env->getGameDef();
- InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
- infostream<<"item="<<env<<std::endl;
- co->addToInventoryLater(item);
- // Return
- return 0;
+ lua_pushinteger(L, co->getWieldIndex() + 1);
+ return 1;
}
- // set_hp(self, hp)
- // hp = number of hitpoints (2 * number of hearts)
- // returns: nil
- static int l_set_hp(lua_State *L)
+ // get_wielded_item(self)
+ static int l_get_wielded_item(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- luaL_checknumber(L, 2);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
- int hp = lua_tonumber(L, 2);
- infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
- <<" hp="<<hp<<std::endl;
// Do it
- co->setHP(hp);
- // Return
- return 0;
+ LuaItemStack::create(L, co->getWieldedItem());
+ return 1;
}
- // get_hp(self)
- // returns: number of hitpoints (2 * number of hearts)
- // 0 if not applicable to this type of object
- static int l_get_hp(lua_State *L)
+ // set_wielded_item(self, itemstack or itemstring or table or nil)
+ static int l_set_wielded_item(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
- int hp = co->getHP();
- infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
- <<" hp="<<hp<<std::endl;
- // Return
- lua_pushnumber(L, hp);
+ // Do it
+ ItemStack item = read_item(L, 2);
+ bool success = co->setWieldedItem(item);
+ lua_pushboolean(L, success);
return 1;
}
@@ -2070,73 +2394,6 @@ private:
return 1;
}
- // get_inventory(self)
- static int l_get_inventory(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
- if(player == NULL) return 0;
- // Do it
- InvRef::createPlayer(L, player);
- return 1;
- }
-
- // deprecated: inventory_set_list(self, name, {item1, item2, ...})
- static int l_inventory_set_list(lua_State *L)
- {
- infostream<<"Deprecated: inventory_set_list"<<std::endl;
- ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
- if(player == NULL) return 0;
- const char *name = luaL_checkstring(L, 2);
- // Do it
- inventory_set_list_from_lua(&player->inventory, name, L, 3,
- player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE);
- player->m_inventory_not_sent = true;
- return 0;
- }
-
- // deprecated: inventory_get_list(self, name)
- static int l_inventory_get_list(lua_State *L)
- {
- infostream<<"Deprecated: inventory_get_list"<<std::endl;
- ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
- if(player == NULL) return 0;
- const char *name = luaL_checkstring(L, 2);
- // Do it
- inventory_get_list_to_lua(&player->inventory, name, L);
- return 1;
- }
-
- // get_wielded_itemstring(self)
- static int l_get_wielded_itemstring(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
- if(player == NULL) return 0;
- // Do it
- InventoryItem *item = player->getWieldedItem();
- if(item == NULL){
- lua_pushnil(L);
- return 1;
- }
- lua_pushstring(L, item->getItemString().c_str());
- return 1;
- }
-
- // get_wielded_item(self)
- static int l_get_wielded_item(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
- if(player == NULL) return 0;
- // Do it
- InventoryItem *item0 = player->getWieldedItem();
- push_stack_item(L, item0);
- return 1;
- }
-
// get_look_dir(self)
static int l_get_look_dir(lua_State *L)
{
@@ -2243,12 +2500,13 @@ const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, moveto),
method(ObjectRef, punch),
method(ObjectRef, right_click),
- method(ObjectRef, get_wield_digging_properties),
- method(ObjectRef, damage_wielded_item),
- method(ObjectRef, add_to_inventory),
- method(ObjectRef, add_to_inventory_later),
method(ObjectRef, set_hp),
method(ObjectRef, get_hp),
+ method(ObjectRef, get_inventory),
+ method(ObjectRef, get_wield_list),
+ method(ObjectRef, get_wield_index),
+ method(ObjectRef, get_wielded_item),
+ method(ObjectRef, set_wielded_item),
// LuaEntitySAO-only
method(ObjectRef, setvelocity),
method(ObjectRef, getvelocity),
@@ -2262,11 +2520,6 @@ const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, get_luaentity),
// Player-only
method(ObjectRef, get_player_name),
- method(ObjectRef, get_inventory),
- method(ObjectRef, inventory_set_list), // deprecated
- method(ObjectRef, inventory_get_list), // deprecated
- method(ObjectRef, get_wielded_itemstring),
- method(ObjectRef, get_wielded_item),
method(ObjectRef, get_look_dir),
method(ObjectRef, get_look_pitch),
method(ObjectRef, get_look_yaw),
@@ -2408,7 +2661,7 @@ private:
}
}
- // EnvRef:add_entity(pos, entityname)
+ // EnvRef:add_entity(pos, entityname) -> ObjectRef or nil
// pos = {x=num, y=num, z=num}
static int l_add_entity(lua_State *L)
{
@@ -2431,22 +2684,29 @@ private:
return 1;
}
- // EnvRef:add_item(pos, inventorystring)
+ // EnvRef:add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
// pos = {x=num, y=num, z=num}
static int l_add_item(lua_State *L)
{
- infostream<<"EnvRef::l_add_item()"<<std::endl;
+ //infostream<<"EnvRef::l_add_item()"<<std::endl;
EnvRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
// pos
v3f pos = checkFloatPos(L, 2);
- // inventorystring
- const char *inventorystring = luaL_checkstring(L, 3);
+ // item
+ ItemStack item = read_item(L, 3);
+ if(item.empty() || !item.isKnown(get_server(L)->idef()))
+ return 0;
// Do it
- ServerActiveObject *obj = new ItemSAO(env, pos, inventorystring);
- env->addActiveObject(obj);
- return 0;
+ ServerActiveObject *obj = new ItemSAO(env, pos, item.getItemString());
+ int objectid = env->addActiveObject(obj);
+ // If failed to add, return nothing (reads as nil)
+ if(objectid == 0)
+ return 0;
+ // Return ObjectRef
+ objectref_get_or_create(L, obj);
+ return 1;
}
// EnvRef:add_rat(pos)
@@ -2627,55 +2887,6 @@ const luaL_reg EnvRef::methods[] = {
Global functions
*/
-static int l_register_nodedef_defaults(lua_State *L)
-{
- luaL_checktype(L, 1, LUA_TTABLE);
-
- lua_pushvalue(L, 1); // Explicitly put parameter 1 on top of stack
- lua_setfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default");
-
- return 0;
-}
-
-// Register new object prototype
-// register_entity(name, prototype)
-static int l_register_entity(lua_State *L)
-{
- std::string name = luaL_checkstring(L, 1);
- check_modname_prefix(L, name);
- //infostream<<"register_entity: "<<name<<std::endl;
- luaL_checktype(L, 2, LUA_TTABLE);
-
- // Get minetest.registered_entities
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_entities");
- luaL_checktype(L, -1, LUA_TTABLE);
- int registered_entities = lua_gettop(L);
- lua_pushvalue(L, 2); // Object = param 2 -> stack top
- // registered_entities[name] = object
- lua_setfield(L, registered_entities, name.c_str());
-
- // Get registered object to top of stack
- lua_pushvalue(L, 2);
-
- // Set name field
- lua_pushvalue(L, 1);
- lua_setfield(L, -2, "name");
-
- // Set __index to point to itself
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "__index");
-
- // Set metatable.__index = metatable
- luaL_getmetatable(L, "minetest.entity");
- lua_pushvalue(L, -1); // duplicate metatable
- lua_setfield(L, -2, "__index");
- // Set object metatable
- lua_setmetatable(L, -2);
-
- return 0; /* number of results */
-}
-
class LuaABM : public ActiveBlockModifier
{
private:
@@ -2749,454 +2960,318 @@ public:
}
};
-// register_abm({...})
-static int l_register_abm(lua_State *L)
+// debug(text)
+// Writes a line to dstream
+static int l_debug(lua_State *L)
{
- //infostream<<"register_abm"<<std::endl;
- luaL_checktype(L, 1, LUA_TTABLE);
-
- // Get minetest.registered_abms
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_abms");
- luaL_checktype(L, -1, LUA_TTABLE);
- int registered_abms = lua_gettop(L);
+ std::string text = lua_tostring(L, 1);
+ dstream << text << std::endl;
+ return 0;
+}
- int id = 1;
- // Find free id
- for(;;){
- lua_pushnumber(L, id);
- lua_gettable(L, registered_abms);
- if(lua_isnil(L, -1))
- break;
- lua_pop(L, 1);
- id++;
+// log([level,] text)
+// Writes a line to the logger.
+// The one-argument version logs to infostream.
+// The two-argument version accept a log level: error, action, info, or verbose.
+static int l_log(lua_State *L)
+{
+ std::string text;
+ LogMessageLevel level = LMT_INFO;
+ if(lua_isnone(L, 2))
+ {
+ text = lua_tostring(L, 1);
}
- lua_pop(L, 1);
-
- infostream<<"register_abm: id="<<id<<std::endl;
-
- // registered_abms[id] = spec
- lua_pushnumber(L, id);
- lua_pushvalue(L, 1);
- lua_settable(L, registered_abms);
-
- return 0; /* number of results */
+ else
+ {
+ std::string levelname = lua_tostring(L, 1);
+ text = lua_tostring(L, 2);
+ if(levelname == "error")
+ level = LMT_ERROR;
+ else if(levelname == "action")
+ level = LMT_ACTION;
+ else if(levelname == "verbose")
+ level = LMT_VERBOSE;
+ }
+ log_printline(level, text);
+ return 0;
}
-// register_tool(name, {lots of stuff})
-static int l_register_tool(lua_State *L)
+// register_item_raw({lots of stuff})
+static int l_register_item_raw(lua_State *L)
{
- std::string name = luaL_checkstring(L, 1);
- check_modname_prefix(L, name);
- //infostream<<"register_tool: "<<name<<std::endl;
- luaL_checktype(L, 2, LUA_TTABLE);
- int table = 2;
-
- // Get the writable tool definition manager from the server
- IWritableToolDefManager *tooldef =
- get_server(L)->getWritableToolDefManager();
-
- ToolDefinition def = read_tool_definition(L, table);
+ luaL_checktype(L, 1, LUA_TTABLE);
+ int table = 1;
- tooldef->registerTool(name, def);
- return 0; /* number of results */
-}
+ // Get the writable item and node definition managers from the server
+ IWritableItemDefManager *idef =
+ get_server(L)->getWritableItemDefManager();
+ IWritableNodeDefManager *ndef =
+ get_server(L)->getWritableNodeDefManager();
-// register_craftitem(name, {lots of stuff})
-static int l_register_craftitem(lua_State *L)
-{
- std::string name = luaL_checkstring(L, 1);
- check_modname_prefix(L, name);
- //infostream<<"register_craftitem: "<<name<<std::endl;
- luaL_checktype(L, 2, LUA_TTABLE);
- int table = 2;
-
- // Get the writable CraftItem definition manager from the server
- IWritableCraftItemDefManager *craftitemdef =
- get_server(L)->getWritableCraftItemDefManager();
-
- // Check if on_drop is defined
- lua_getfield(L, table, "on_drop");
- bool got_on_drop = !lua_isnil(L, -1);
- lua_pop(L, 1);
+ // Check if name is defined
+ lua_getfield(L, table, "name");
+ if(lua_isstring(L, -1)){
+ std::string name = lua_tostring(L, -1);
+ infostream<<"register_item_raw: "<<name<<std::endl;
+ } else {
+ throw LuaError(L, "register_item_raw: name is not defined or not a string");
+ }
// Check if on_use is defined
- lua_getfield(L, table, "on_use");
- bool got_on_use = !lua_isnil(L, -1);
- lua_pop(L, 1);
- CraftItemDefinition def;
-
- getstringfield(L, table, "image", def.imagename);
- getstringfield(L, table, "cookresult_itemstring", def.cookresult_item);
- getfloatfield(L, table, "furnace_cooktime", def.furnace_cooktime);
- getfloatfield(L, table, "furnace_burntime", def.furnace_burntime);
- def.usable = getboolfield_default(L, table, "usable", got_on_use);
- getboolfield(L, table, "liquids_pointable", def.liquids_pointable);
- def.dropcount = getintfield_default(L, table, "dropcount", def.dropcount);
- def.stack_max = getintfield_default(L, table, "stack_max", def.stack_max);
-
- // If an on_drop callback is defined, force dropcount to 1
- if (got_on_drop)
- def.dropcount = 1;
-
- // Register it
- craftitemdef->registerCraftItem(name, def);
+ // Read the item definition and register it
+ ItemDefinition def = read_item_definition(L, table);
+ idef->registerItem(def);
- lua_pushvalue(L, table);
- scriptapi_add_craftitem(L, name.c_str());
+ // Read the node definition (content features) and register it
+ if(def.type == ITEM_NODE)
+ {
+ ContentFeatures f = read_content_features(L, table);
+ ndef->set(f.name, f);
+ }
return 0; /* number of results */
}
-// register_node(name, {lots of stuff})
-static int l_register_node(lua_State *L)
+// register_alias_raw(name, convert_to_name)
+static int l_register_alias_raw(lua_State *L)
{
std::string name = luaL_checkstring(L, 1);
- check_modname_prefix(L, name);
- //infostream<<"register_node: "<<name<<std::endl;
- luaL_checktype(L, 2, LUA_TTABLE);
- int nodedef_table = 2;
-
- // Get the writable node definition manager from the server
- IWritableNodeDefManager *nodedef =
- get_server(L)->getWritableNodeDefManager();
-
- // Get default node definition from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default");
- int nodedef_default = lua_gettop(L);
-
- /*
- Add to minetest.registered_nodes with default as metatable
- */
-
- // Get the node definition table given as parameter
- lua_pushvalue(L, nodedef_table);
-
- // Set __index to point to itself
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "__index");
-
- // Set nodedef_default as metatable for the definition
- lua_pushvalue(L, nodedef_default);
- lua_setmetatable(L, nodedef_table);
-
- // minetest.registered_nodes[name] = nodedef
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_nodes");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushstring(L, name.c_str());
- lua_pushvalue(L, nodedef_table);
- lua_settable(L, -3);
+ std::string convert_to = luaL_checkstring(L, 2);
- /*
- Create definition
- */
+ // Get the writable item definition manager from the server
+ IWritableItemDefManager *idef =
+ get_server(L)->getWritableItemDefManager();
- ContentFeatures f;
-
- // Default to getting the corresponding NodeItem when dug
- f.dug_item = std::string("NodeItem \"")+name+"\" 1";
+ idef->registerAlias(name, convert_to);
- // Default to unknown_block.png as all textures
- f.setAllTextures("unknown_block.png");
-
- /*
- Read definiton from Lua
- */
+ return 0; /* number of results */
+}
- f.name = name;
-
- /* Visual definition */
+// helper for register_craft
+static bool read_craft_recipe_shaped(lua_State *L, int index,
+ int &width, std::vector<std::string> &recipe)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
- f.drawtype = (NodeDrawType)getenumfield(L, nodedef_table, "drawtype", es_DrawType,
- NDT_NORMAL);
- getfloatfield(L, nodedef_table, "visual_scale", f.visual_scale);
+ if(!lua_istable(L, index))
+ return false;
- lua_getfield(L, nodedef_table, "tile_images");
- if(lua_istable(L, -1)){
- int table = lua_gettop(L);
+ lua_pushnil(L);
+ int rowcount = 0;
+ while(lua_next(L, index) != 0){
+ int colcount = 0;
+ // key at index -2 and value at index -1
+ if(!lua_istable(L, -1))
+ return false;
+ int table2 = lua_gettop(L);
lua_pushnil(L);
- int i = 0;
- while(lua_next(L, table) != 0){
+ while(lua_next(L, table2) != 0){
// key at index -2 and value at index -1
- if(lua_isstring(L, -1))
- f.tname_tiles[i] = lua_tostring(L, -1);
- else
- f.tname_tiles[i] = "";
+ if(!lua_isstring(L, -1))
+ return false;
+ recipe.push_back(lua_tostring(L, -1));
// removes value, keeps key for next iteration
lua_pop(L, 1);
- i++;
- if(i==6){
- lua_pop(L, 1);
- break;
- }
+ colcount++;
}
- // Copy last value to all remaining textures
- if(i >= 1){
- std::string lastname = f.tname_tiles[i-1];
- while(i < 6){
- f.tname_tiles[i] = lastname;
- i++;
- }
- }
- }
- lua_pop(L, 1);
-
- getstringfield(L, nodedef_table, "inventory_image", f.tname_inventory);
-
- lua_getfield(L, nodedef_table, "special_materials");
- if(lua_istable(L, -1)){
- int table = lua_gettop(L);
- lua_pushnil(L);
- int i = 0;
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- int smtable = lua_gettop(L);
- std::string tname = getstringfield_default(
- L, smtable, "image", "");
- bool backface_culling = getboolfield_default(
- L, smtable, "backface_culling", true);
- MaterialSpec mspec(tname, backface_culling);
- f.setSpecialMaterial(i, mspec);
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- i++;
- if(i==6){
- lua_pop(L, 1);
- break;
- }
+ if(rowcount == 0){
+ width = colcount;
+ } else {
+ if(colcount != width)
+ return false;
}
- }
- lua_pop(L, 1);
-
- f.alpha = getintfield_default(L, nodedef_table, "alpha", 255);
-
- /* Other stuff */
-
- lua_getfield(L, nodedef_table, "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, nodedef_table, "paramtype",
- es_ContentParamType, CPT_NONE);
-
- // True for all ground-like things like stone and mud, false for eg. trees
- getboolfield(L, nodedef_table, "is_ground_content", f.is_ground_content);
- f.light_propagates = (f.param_type == CPT_LIGHT);
- warn_if_field_exists(L, nodedef_table, "light_propagates",
- "deprecated: determined from paramtype");
- getboolfield(L, nodedef_table, "sunlight_propagates", f.sunlight_propagates);
- // This is used for collision detection.
- // Also for general solidness queries.
- getboolfield(L, nodedef_table, "walkable", f.walkable);
- // Player can point to these
- getboolfield(L, nodedef_table, "pointable", f.pointable);
- // Player can dig these
- getboolfield(L, nodedef_table, "diggable", f.diggable);
- // Player can climb these
- getboolfield(L, nodedef_table, "climbable", f.climbable);
- // Player can build on these
- getboolfield(L, nodedef_table, "buildable_to", f.buildable_to);
- // If true, param2 is set to direction when placed. Used for torches.
- // NOTE: the direction format is quite inefficient and should be changed
- getboolfield(L, nodedef_table, "wall_mounted", f.wall_mounted);
- // Whether this content type often contains mineral.
- // Used for texture atlas creation.
- // Currently only enabled for CONTENT_STONE.
- getboolfield(L, nodedef_table, "often_contains_mineral", f.often_contains_mineral);
- // Inventory item string as which the node appears in inventory when dug.
- // Mineral overrides this.
- getstringfield(L, nodedef_table, "dug_item", f.dug_item);
- // Extra dug item and its rarity
- getstringfield(L, nodedef_table, "extra_dug_item", f.extra_dug_item);
- // Usual get interval for extra dug item
- getintfield(L, nodedef_table, "extra_dug_item_rarity", f.extra_dug_item_rarity);
- // Metadata name of node (eg. "furnace")
- getstringfield(L, nodedef_table, "metadata_name", f.metadata_name);
- // Whether the node is non-liquid, source liquid or flowing liquid
- f.liquid_type = (LiquidType)getenumfield(L, nodedef_table, "liquidtype",
- es_LiquidType, LIQUID_NONE);
- // If the content is liquid, this is the flowing version of the liquid.
- getstringfield(L, nodedef_table, "liquid_alternative_flowing",
- f.liquid_alternative_flowing);
- // If the content is liquid, this is the source version of the liquid.
- getstringfield(L, nodedef_table, "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, nodedef_table,
- "liquid_viscosity", f.liquid_viscosity);
- // Amount of light the node emits
- f.light_source = getintfield_default(L, nodedef_table,
- "light_source", f.light_source);
- f.damage_per_second = getintfield_default(L, nodedef_table,
- "damage_per_second", f.damage_per_second);
-
- lua_getfield(L, nodedef_table, "selection_box");
- if(lua_istable(L, -1)){
- f.selection_box.type = (NodeBoxType)getenumfield(L, -1, "type",
- es_NodeBoxType, NODEBOX_REGULAR);
-
- lua_getfield(L, -1, "fixed");
- if(lua_istable(L, -1))
- f.selection_box.fixed = read_aabbox3df32(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "wall_top");
- if(lua_istable(L, -1))
- f.selection_box.wall_top = read_aabbox3df32(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "wall_bottom");
- if(lua_istable(L, -1))
- f.selection_box.wall_bottom = read_aabbox3df32(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "wall_side");
- if(lua_istable(L, -1))
- f.selection_box.wall_side = read_aabbox3df32(L, -1, BS);
+ // removes value, keeps key for next iteration
lua_pop(L, 1);
+ rowcount++;
}
- lua_pop(L, 1);
-
- lua_getfield(L, nodedef_table, "material");
- if(lua_istable(L, -1)){
- f.material.diggability = (Diggability)getenumfield(L, -1, "diggability",
- es_Diggability, DIGGABLE_NORMAL);
-
- getfloatfield(L, -1, "constant_time", f.material.constant_time);
- getfloatfield(L, -1, "weight", f.material.weight);
- getfloatfield(L, -1, "crackiness", f.material.crackiness);
- getfloatfield(L, -1, "crumbliness", f.material.crumbliness);
- getfloatfield(L, -1, "cuttability", f.material.cuttability);
- getfloatfield(L, -1, "flammability", f.material.flammability);
- }
- lua_pop(L, 1);
-
- getstringfield(L, nodedef_table, "cookresult_itemstring", f.cookresult_item);
- getfloatfield(L, nodedef_table, "furnace_cooktime", f.furnace_cooktime);
- getfloatfield(L, nodedef_table, "furnace_burntime", f.furnace_burntime);
-
- /*
- Register it
- */
-
- nodedef->set(name, f);
-
- return 0; /* number of results */
-}
-
-// alias_node(name, convert_to_name)
-static int l_alias_node(lua_State *L)
-{
- std::string name = luaL_checkstring(L, 1);
- std::string convert_to = luaL_checkstring(L, 2);
-
- // Get the writable node definition manager from the server
- IWritableNodeDefManager *nodedef =
- get_server(L)->getWritableNodeDefManager();
-
- nodedef->setAlias(name, convert_to);
-
- return 0; /* number of results */
+ return width != 0;
}
-// alias_tool(name, convert_to_name)
-static int l_alias_tool(lua_State *L)
+// helper for register_craft
+static bool read_craft_recipe_shapeless(lua_State *L, int index,
+ std::vector<std::string> &recipe)
{
- std::string name = luaL_checkstring(L, 1);
- std::string convert_to = luaL_checkstring(L, 2);
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
- // Get the writable tool definition manager from the server
- IWritableToolDefManager *tooldef =
- get_server(L)->getWritableToolDefManager();
-
- tooldef->setAlias(name, convert_to);
+ if(!lua_istable(L, index))
+ return false;
- return 0; /* number of results */
+ lua_pushnil(L);
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ if(!lua_isstring(L, -1))
+ return false;
+ recipe.push_back(lua_tostring(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ return true;
}
-// alias_craftitem(name, convert_to_name)
-static int l_alias_craftitem(lua_State *L)
+// helper for register_craft
+static bool read_craft_replacements(lua_State *L, int index,
+ CraftReplacements &replacements)
{
- std::string name = luaL_checkstring(L, 1);
- std::string convert_to = luaL_checkstring(L, 2);
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
- // Get the writable CraftItem definition manager from the server
- IWritableCraftItemDefManager *craftitemdef =
- get_server(L)->getWritableCraftItemDefManager();
-
- craftitemdef->setAlias(name, convert_to);
+ if(!lua_istable(L, index))
+ return false;
- return 0; /* number of results */
+ lua_pushnil(L);
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ if(!lua_istable(L, -1))
+ return false;
+ lua_rawgeti(L, -1, 1);
+ if(!lua_isstring(L, -1))
+ return false;
+ std::string replace_from = lua_tostring(L, -1);
+ lua_pop(L, 1);
+ lua_rawgeti(L, -1, 2);
+ if(!lua_isstring(L, -1))
+ return false;
+ std::string replace_to = lua_tostring(L, -1);
+ lua_pop(L, 1);
+ replacements.pairs.push_back(
+ std::make_pair(replace_from, replace_to));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ return true;
}
-
// register_craft({output=item, recipe={{item00,item10},{item01,item11}})
static int l_register_craft(lua_State *L)
{
//infostream<<"register_craft"<<std::endl;
luaL_checktype(L, 1, LUA_TTABLE);
- int table0 = 1;
+ int table = 1;
// Get the writable craft definition manager from the server
IWritableCraftDefManager *craftdef =
get_server(L)->getWritableCraftDefManager();
- std::string output;
- int width = 0;
- std::vector<std::string> input;
-
- lua_getfield(L, table0, "output");
- luaL_checktype(L, -1, LUA_TSTRING);
- if(lua_isstring(L, -1))
- output = lua_tostring(L, -1);
- lua_pop(L, 1);
+ std::string type = getstringfield_default(L, table, "type", "shaped");
- lua_getfield(L, table0, "recipe");
- luaL_checktype(L, -1, LUA_TTABLE);
- if(lua_istable(L, -1)){
- int table1 = lua_gettop(L);
- lua_pushnil(L);
- int rowcount = 0;
- while(lua_next(L, table1) != 0){
- int colcount = 0;
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TTABLE);
- if(lua_istable(L, -1)){
- int table2 = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table2) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- input.push_back(lua_tostring(L, -1));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- colcount++;
- }
- }
- if(rowcount == 0){
- width = colcount;
- } else {
- if(colcount != width){
- std::string error;
- error += "Invalid crafting recipe (output=\""
- + output + "\")";
- throw LuaError(L, error);
- }
- }
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- rowcount++;
+ /*
+ CraftDefinitionShaped
+ */
+ if(type == "shaped"){
+ std::string output = getstringfield_default(L, table, "output", "");
+ if(output == "")
+ throw LuaError(L, "Crafting definition is missing an output");
+
+ int width = 0;
+ std::vector<std::string> recipe;
+ lua_getfield(L, table, "recipe");
+ if(lua_isnil(L, -1))
+ throw LuaError(L, "Crafting definition is missing a recipe"
+ " (output=\"" + output + "\")");
+ if(!read_craft_recipe_shaped(L, -1, width, recipe))
+ throw LuaError(L, "Invalid crafting recipe"
+ " (output=\"" + output + "\")");
+
+ CraftReplacements replacements;
+ lua_getfield(L, table, "replacements");
+ if(!lua_isnil(L, -1))
+ {
+ if(!read_craft_replacements(L, -1, replacements))
+ throw LuaError(L, "Invalid replacements"
+ " (output=\"" + output + "\")");
}
+
+ CraftDefinition *def = new CraftDefinitionShaped(
+ output, width, recipe, replacements);
+ craftdef->registerCraft(def);
}
- lua_pop(L, 1);
+ /*
+ CraftDefinitionShapeless
+ */
+ else if(type == "shapeless"){
+ std::string output = getstringfield_default(L, table, "output", "");
+ if(output == "")
+ throw LuaError(L, "Crafting definition (shapeless)"
+ " is missing an output");
+
+ std::vector<std::string> recipe;
+ lua_getfield(L, table, "recipe");
+ if(lua_isnil(L, -1))
+ throw LuaError(L, "Crafting definition (shapeless)"
+ " is missing a recipe"
+ " (output=\"" + output + "\")");
+ if(!read_craft_recipe_shapeless(L, -1, recipe))
+ throw LuaError(L, "Invalid crafting recipe"
+ " (output=\"" + output + "\")");
+
+ CraftReplacements replacements;
+ lua_getfield(L, table, "replacements");
+ if(!lua_isnil(L, -1))
+ {
+ if(!read_craft_replacements(L, -1, replacements))
+ throw LuaError(L, "Invalid replacements"
+ " (output=\"" + output + "\")");
+ }
- CraftDefinition def(output, width, input);
- craftdef->registerCraft(def);
+ CraftDefinition *def = new CraftDefinitionShapeless(
+ output, recipe, replacements);
+ craftdef->registerCraft(def);
+ }
+ /*
+ CraftDefinitionToolRepair
+ */
+ else if(type == "toolrepair"){
+ float additional_wear = getfloatfield_default(L, table,
+ "additional_wear", 0.0);
+ CraftDefinition *def = new CraftDefinitionToolRepair(
+ additional_wear);
+ craftdef->registerCraft(def);
+ }
+ /*
+ CraftDefinitionCooking
+ */
+ else if(type == "cooking"){
+ std::string output = getstringfield_default(L, table, "output", "");
+ if(output == "")
+ throw LuaError(L, "Crafting definition (cooking)"
+ " is missing an output");
+
+ std::string recipe = getstringfield_default(L, table, "recipe", "");
+ if(recipe == "")
+ throw LuaError(L, "Crafting definition (cooking)"
+ " is missing a recipe"
+ " (output=\"" + output + "\")");
+
+ float cooktime = getfloatfield_default(L, table, "cooktime", 3.0);
+
+ CraftDefinition *def = new CraftDefinitionCooking(
+ output, recipe, cooktime);
+ craftdef->registerCraft(def);
+ }
+ /*
+ CraftDefinitionFuel
+ */
+ else if(type == "fuel"){
+ std::string recipe = getstringfield_default(L, table, "recipe", "");
+ if(recipe == "")
+ throw LuaError(L, "Crafting definition (fuel)"
+ " is missing a recipe");
+
+ float burntime = getfloatfield_default(L, table, "burntime", 1.0);
+
+ CraftDefinition *def = new CraftDefinitionFuel(
+ recipe, burntime);
+ craftdef->registerCraft(def);
+ }
+ else
+ {
+ throw LuaError(L, "Unknown crafting definition type: \"" + type + "\"");
+ }
+
+ lua_pop(L, 1);
return 0; /* number of results */
}
@@ -3294,15 +3369,19 @@ static int l_get_inventory(lua_State *L)
return 1;
}
+// get_current_modname()
+static int l_get_current_modname(lua_State *L)
+{
+ lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
+ return 1;
+}
+
// get_modpath(modname)
static int l_get_modpath(lua_State *L)
{
const char *modname = luaL_checkstring(L, 1);
- // Get server from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
- Server *server = (Server*)lua_touserdata(L, -1);
// Do it
- const ModSpec *mod = server->getModSpec(modname);
+ const ModSpec *mod = get_server(L)->getModSpec(modname);
if(!mod){
lua_pushnil(L);
return 1;
@@ -3312,35 +3391,23 @@ static int l_get_modpath(lua_State *L)
}
static const struct luaL_Reg minetest_f [] = {
- {"register_nodedef_defaults", l_register_nodedef_defaults},
- {"register_entity", l_register_entity},
- {"register_tool", l_register_tool},
- {"register_craftitem", l_register_craftitem},
- {"register_node", l_register_node},
+ {"debug", l_debug},
+ {"log", l_log},
+ {"register_item_raw", l_register_item_raw},
+ {"register_alias_raw", l_register_alias_raw},
{"register_craft", l_register_craft},
- {"register_abm", l_register_abm},
- {"alias_node", l_alias_node},
- {"alias_tool", l_alias_tool},
- {"alias_craftitem", l_alias_craftitem},
{"setting_get", l_setting_get},
{"setting_getbool", l_setting_getbool},
{"chat_send_all", l_chat_send_all},
{"chat_send_player", l_chat_send_player},
{"get_player_privs", l_get_player_privs},
{"get_inventory", l_get_inventory},
+ {"get_current_modname", l_get_current_modname},
{"get_modpath", l_get_modpath},
{NULL, NULL}
};
/*
- LuaEntity functions
-*/
-
-static const struct luaL_Reg minetest_entity_m [] = {
- {NULL, NULL}
-};
-
-/*
Main export function
*/
@@ -3355,10 +3422,6 @@ void scriptapi_export(lua_State *L, Server *server)
lua_pushlightuserdata(L, server);
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_server");
- // Store nil as minetest_nodedef_defaults in registry
- lua_pushnil(L);
- lua_setfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default");
-
// Register global functions in table minetest
lua_newtable(L);
luaL_register(L, NULL, minetest_f);
@@ -3370,30 +3433,12 @@ void scriptapi_export(lua_State *L, Server *server)
// Add tables to minetest
lua_newtable(L);
- lua_setfield(L, -2, "registered_nodes");
- lua_newtable(L);
- lua_setfield(L, -2, "registered_entities");
- lua_newtable(L);
- lua_setfield(L, -2, "registered_craftitems");
- lua_newtable(L);
- lua_setfield(L, -2, "registered_abms");
-
- lua_newtable(L);
lua_setfield(L, -2, "object_refs");
lua_newtable(L);
lua_setfield(L, -2, "luaentities");
- // Create entity prototype
- luaL_newmetatable(L, "minetest.entity");
- // metatable.__index = metatable
- lua_pushvalue(L, -1); // Duplicate metatable
- lua_setfield(L, -2, "__index");
- // Put functions in metatable
- luaL_register(L, NULL, minetest_entity_m);
- // Put other stuff in metatable
-
// Register wrappers
- ItemStack::Register(L);
+ LuaItemStack::Register(L);
InvRef::Register(L);
NodeMetaRef::Register(L);
ObjectRef::Register(L);
@@ -3705,62 +3750,22 @@ void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player)
lua_getfield(L, -1, "creative_inventory");
luaL_checktype(L, -1, LUA_TTABLE);
inventory_set_list_from_lua(&player->inventory, "main", L, -1,
- player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE);
+ PLAYER_INVENTORY_SIZE);
}
/*
- craftitem
+ item callbacks
*/
-static void pushPointedThing(lua_State *L, const PointedThing& pointed)
+// Retrieves minetest.registered_items[name][callbackname]
+// If that is nil or on error, return false and stack is unchanged
+// If that is a function, returns true and pushes the
+// function onto the stack
+static bool get_item_callback(lua_State *L,
+ const char *name, const char *callbackname)
{
- lua_newtable(L);
- if(pointed.type == POINTEDTHING_NODE)
- {
- lua_pushstring(L, "node");
- lua_setfield(L, -2, "type");
- push_v3s16(L, pointed.node_undersurface);
- lua_setfield(L, -2, "under");
- push_v3s16(L, pointed.node_abovesurface);
- lua_setfield(L, -2, "above");
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
- {
- lua_pushstring(L, "object");
- lua_setfield(L, -2, "type");
- objectref_get(L, pointed.object_id);
- lua_setfield(L, -2, "ref");
- }
- else
- {
- lua_pushstring(L, "nothing");
- lua_setfield(L, -2, "type");
- }
-}
-
-void scriptapi_add_craftitem(lua_State *L, const char *name)
-{
- StackUnroller stack_unroller(L);
- assert(lua_gettop(L) > 0);
-
- // Set minetest.registered_craftitems[name] = table on top of stack
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_craftitems");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushvalue(L, -3); // push another reference to the table to be registered
- lua_setfield(L, -2, name); // set minetest.registered_craftitems[name]
-}
-
-static bool get_craftitem_callback(lua_State *L, const char *name,
- const char *callbackname)
-{
- // Get minetest.registered_craftitems[name][callbackname]
- // If that is nil or on error, return false and stack is unchanged
- // If that is a function, returns true and pushes the
- // function onto the stack
-
lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_craftitems");
+ lua_getfield(L, -1, "registered_items");
lua_remove(L, -2);
luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, name);
@@ -3768,7 +3773,7 @@ static bool get_craftitem_callback(lua_State *L, const char *name,
// Should be a table
if(lua_type(L, -1) != LUA_TTABLE)
{
- errorstream<<"CraftItem name \""<<name<<"\" not defined"<<std::endl;
+ errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
lua_pop(L, 1);
return false;
}
@@ -3786,83 +3791,77 @@ static bool get_craftitem_callback(lua_State *L, const char *name,
}
else
{
- errorstream<<"CraftItem name \""<<name<<"\" callback \""
+ errorstream<<"Item \""<<name<<"\" callback \""
<<callbackname<<" is not a function"<<std::endl;
lua_pop(L, 1);
return false;
}
}
-bool scriptapi_craftitem_on_drop(lua_State *L, const char *name,
- ServerActiveObject *dropper, v3f pos,
- bool &callback_exists)
+bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
+ ServerActiveObject *dropper, v3f pos)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_craftitem_on_drop"<<std::endl;
StackUnroller stack_unroller(L);
- bool result = false;
- callback_exists = get_craftitem_callback(L, name, "on_drop");
- if(callback_exists)
- {
- // Call function
- lua_pushstring(L, name);
- objectref_get_or_create(L, dropper);
- pushFloatPos(L, pos);
- if(lua_pcall(L, 3, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- result = lua_toboolean(L, -1);
- }
- return result;
+ // Push callback function on stack
+ if(!get_item_callback(L, item.name.c_str(), "on_drop"))
+ return false;
+
+ // Call function
+ LuaItemStack::create(L, item);
+ objectref_get_or_create(L, dropper);
+ pushFloatPos(L, pos);
+ if(lua_pcall(L, 3, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnil(L, -1))
+ item = read_item(L, -1);
+ return true;
}
-bool scriptapi_craftitem_on_place_on_ground(lua_State *L, const char *name,
- ServerActiveObject *placer, v3f pos,
- bool &callback_exists)
+bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
+ ServerActiveObject *placer, const PointedThing &pointed)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_craftitem_on_place_on_ground"<<std::endl;
StackUnroller stack_unroller(L);
- bool result = false;
- callback_exists = get_craftitem_callback(L, name, "on_place_on_ground");
- if(callback_exists)
- {
- // Call function
- lua_pushstring(L, name);
- objectref_get_or_create(L, placer);
- pushFloatPos(L, pos);
- if(lua_pcall(L, 3, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- result = lua_toboolean(L, -1);
- }
- return result;
+ // Push callback function on stack
+ if(!get_item_callback(L, item.name.c_str(), "on_place"))
+ return false;
+
+ // Call function
+ LuaItemStack::create(L, item);
+ objectref_get_or_create(L, placer);
+ push_pointed_thing(L, pointed);
+ if(lua_pcall(L, 3, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnil(L, -1))
+ item = read_item(L, -1);
+ return true;
}
-bool scriptapi_craftitem_on_use(lua_State *L, const char *name,
- ServerActiveObject *user, const PointedThing& pointed,
- bool &callback_exists)
+bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
+ ServerActiveObject *user, const PointedThing &pointed)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_craftitem_on_use"<<std::endl;
StackUnroller stack_unroller(L);
- bool result = false;
- callback_exists = get_craftitem_callback(L, name, "on_use");
- if(callback_exists)
- {
- // Call function
- lua_pushstring(L, name);
- objectref_get_or_create(L, user);
- pushPointedThing(L, pointed);
- if(lua_pcall(L, 3, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- result = lua_toboolean(L, -1);
- }
- return result;
+ // Push callback function on stack
+ if(!get_item_callback(L, item.name.c_str(), "on_use"))
+ return false;
+
+ // Call function
+ LuaItemStack::create(L, item);
+ objectref_get_or_create(L, user);
+ push_pointed_thing(L, pointed);
+ if(lua_pcall(L, 3, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnil(L, -1))
+ item = read_item(L, -1);
+ return true;
}
/*
diff --git a/src/scriptapi.h b/src/scriptapi.h
index af8afa3d9..198f60525 100644
--- a/src/scriptapi.h
+++ b/src/scriptapi.h
@@ -27,11 +27,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Server;
class ServerEnvironment;
class ServerActiveObject;
+class ServerRemotePlayer;
typedef struct lua_State lua_State;
struct LuaEntityProperties;
+class ItemStack;
struct PointedThing;
//class IGameDef;
-class ServerRemotePlayer;
void scriptapi_export(lua_State *L, Server *server);
bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
@@ -66,17 +67,13 @@ void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player);
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player);
-/* craftitem */
-void scriptapi_add_craftitem(lua_State *L, const char *name);
-bool scriptapi_craftitem_on_drop(lua_State *L, const char *name,
- ServerActiveObject *dropper, v3f pos,
- bool &callback_exists);
-bool scriptapi_craftitem_on_place_on_ground(lua_State *L, const char *name,
- ServerActiveObject *placer, v3f pos,
- bool &callback_exists);
-bool scriptapi_craftitem_on_use(lua_State *L, const char *name,
- ServerActiveObject *user, const PointedThing& pointed,
- bool &callback_exists);
+/* item callbacks */
+bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
+ ServerActiveObject *dropper, v3f pos);
+bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
+ ServerActiveObject *placer, const PointedThing &pointed);
+bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
+ ServerActiveObject *user, const PointedThing &pointed);
/* luaentity */
// Returns true if succesfully added into Lua; false otherwise.
diff --git a/src/server.cpp b/src/server.cpp
index d704bf861..3c0cab2a9 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -42,9 +42,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "script.h"
#include "scriptapi.h"
#include "nodedef.h"
-#include "tooldef.h"
+#include "itemdef.h"
#include "craftdef.h"
-#include "craftitemdef.h"
#include "mapgen.h"
#include "content_abm.h"
#include "mods.h"
@@ -853,10 +852,9 @@ Server::Server(
m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
m_lua(NULL),
- m_toolmgr(createToolDefManager()),
+ m_itemdef(createItemDefManager()),
m_nodedef(createNodeDefManager()),
m_craftdef(createCraftDefManager()),
- m_craftitemdef(createCraftItemDefManager()),
m_thread(this),
m_emergethread(this),
m_time_counter(0),
@@ -934,6 +932,9 @@ Server::Server(
// Read Textures and calculate sha1 sums
PrepareTextures();
+ // Apply item aliases in the node definition manager
+ m_nodedef->updateAliases(m_itemdef);
+
// Initialize Environment
m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua,
@@ -1042,10 +1043,9 @@ Server::~Server()
// Delete Environment
delete m_env;
- delete m_toolmgr;
+ delete m_itemdef;
delete m_nodedef;
delete m_craftdef;
- delete m_craftitemdef;
// Deinitialize scripting
infostream<<"Server: Deinitializing scripting"<<std::endl;
@@ -2106,15 +2106,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
Send some initialization data
*/
- // Send tool definitions
- SendToolDef(m_con, peer_id, m_toolmgr);
+ // Send item definitions
+ SendItemDef(m_con, peer_id, m_itemdef);
// Send node definitions
SendNodeDef(m_con, peer_id, m_nodedef);
- // Send CraftItem definitions
- SendCraftItemDef(m_con, peer_id, m_craftitemdef);
-
// Send texture announcement
SendTextureAnnouncement(peer_id);
@@ -2362,13 +2359,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
else if(command == TOSERVER_INVENTORY_ACTION)
{
- /*// Ignore inventory changes if in creative mode
- if(g_settings->getBool("creative_mode") == true)
- {
- infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
- <<std::endl;
- return;
- }*/
// Strip command and create a stream
std::string datastring((char*)&data[2], datasize-2);
infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
@@ -2382,15 +2372,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<std::endl;
return;
}
- // Create context
- InventoryContext c;
- c.current_player = player;
/*
Handle restrictions and special cases of the move action
*/
- if(a->getType() == IACTION_MOVE
- && g_settings->getBool("creative_mode") == false)
+ if(a->getType() == IACTION_MOVE)
{
InventoryList *rlist = player->inventory.getList("craftresult");
assert(rlist);
@@ -2401,17 +2387,28 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
IMoveAction *ma = (IMoveAction*)a;
+ ma->from_inv.applyCurrentPlayer(player->getName());
+ ma->to_inv.applyCurrentPlayer(player->getName());
+
+ bool from_inv_is_current_player =
+ (ma->from_inv.type == InventoryLocation::PLAYER) &&
+ (ma->from_inv.name == player->getName());
+
+ bool to_inv_is_current_player =
+ (ma->to_inv.type == InventoryLocation::PLAYER) &&
+ (ma->to_inv.name == player->getName());
+
/*
Disable moving items into craftresult from elsewhere
*/
- if(ma->to_inv == "current_player"
+ if(to_inv_is_current_player
&& ma->to_list == "craftresult"
- && (ma->from_inv != "current_player"
+ && (!from_inv_is_current_player
|| ma->from_list != "craftresult"))
{
infostream<<"Ignoring IMoveAction from "
- <<ma->from_inv<<":"<<ma->from_list
- <<" to "<<ma->to_inv<<":"<<ma->to_list
+ <<(ma->from_inv.dump())<<":"<<ma->from_list
+ <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
<<" because dst is craftresult"
<<" and src isn't craftresult"<<std::endl;
delete a;
@@ -2421,74 +2418,66 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
/*
Handle crafting (source is craftresult, which is preview)
*/
- if(ma->from_inv == "current_player"
+ if(from_inv_is_current_player
&& ma->from_list == "craftresult"
- && player->craftresult_is_preview)
+ && player->craftresult_is_preview
+ && g_settings->getBool("creative_mode") == false)
{
+ ItemStack crafting_result;
+ bool crafting_possible = GetCraftingResult(peer_id,
+ crafting_result, false);
+
/*
- If the craftresult is placed on itself, crafting takes
- place and result is moved into main list
+ If the craftresult is placed on itself,
+ crafting takes place and result is moved
+ into main list.
*/
- if(ma->to_inv == "current_player"
+ if(crafting_possible
+ && to_inv_is_current_player
&& ma->to_list == "craftresult")
{
- // Except if main list doesn't have free slots
- if(mlist->getFreeSlots() == 0){
- infostream<<"Cannot craft: Main list doesn't have"
- <<" free slots"<<std::endl;
- delete a;
- return;
- }
-
- player->craftresult_is_preview = false;
- clist->decrementMaterials(1);
-
- InventoryItem *item1 = rlist->changeItem(0, NULL);
- mlist->addItem(item1);
+ if(mlist->roomForItem(crafting_result))
+ {
+ actionstream<<player->getName()
+ <<" crafts "
+ <<crafting_result.getItemString()
+ <<std::endl;
- srp->m_inventory_not_sent = true;
+ // Decrement crafting materials
+ GetCraftingResult(peer_id, crafting_result, true);
+ mlist->addItem(crafting_result);
+ rlist->clearItems();
+ player->craftresult_is_preview = true;
+ srp->m_inventory_not_sent = true;
+ }
- delete a;
- return;
}
/*
- Disable action if there are no free slots in
- destination
-
- If the item is placed on an item that is not of the
- same kind, the existing item will be first moved to
- craftresult and immediately moved to the free slot.
+ Otherwise, if the destination is part of
+ the same player's inventory, crafting
+ takes place normally.
*/
- do{
- Inventory *inv_to = InventoryManager::getInventory(&c, ma->to_inv);
- if(!inv_to) break;
- InventoryList *list_to = inv_to->getList(ma->to_list);
- if(!list_to) break;
- if(list_to->getFreeSlots() == 0){
- infostream<<"Cannot craft: Destination doesn't have"
- <<" free slots"<<std::endl;
- delete a;
- return;
+ else if(crafting_possible
+ && to_inv_is_current_player)
+ {
+ InventoryList *list = player->inventory.getList(ma->to_list);
+ if(list && list->itemFits(ma->to_i, crafting_result))
+ {
+ actionstream<<player->getName()
+ <<" crafts "
+ <<crafting_result.getItemString()
+ <<std::endl;
+
+ // Decrement crafting materials
+ GetCraftingResult(peer_id, crafting_result, true);
+ list->addItem(ma->to_i, crafting_result);
+ rlist->clearItems();
+ player->craftresult_is_preview = true;
+ srp->m_inventory_not_sent = true;
}
- }while(0); // Allow break
+ }
- /*
- Ok, craft normally.
- */
- player->craftresult_is_preview = false;
- clist->decrementMaterials(1);
-
- /* Print out action */
- InventoryItem *item = rlist->getItem(0);
- std::string itemstring = "NULL";
- if(item)
- itemstring = item->getItemString();
- actionstream<<player->getName()<<" crafts "
- <<itemstring<<std::endl;
-
- // Do the action
- a->apply(&c, this, m_env);
-
+ // Do not apply the action normally.
delete a;
return;
}
@@ -2498,63 +2487,38 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
// Disallow moving items in elsewhere than player's inventory
- // if not allowed to build
+ // if not allowed to interact
if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
- && (ma->from_inv != "current_player"
- || ma->to_inv != "current_player"))
+ && (from_inv_is_current_player
+ || to_inv_is_current_player))
{
infostream<<"Cannot move outside of player's inventory: "
- <<"No build privilege"<<std::endl;
+ <<"No interact privilege"<<std::endl;
delete a;
return;
}
- // If player is not an admin, check for ownership of src
- if(ma->from_inv != "current_player"
- && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
+ // If player is not an admin, check for ownership of src and dst
+ if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
{
- Strfnd fn(ma->from_inv);
- std::string id0 = fn.next(":");
- if(id0 == "nodemeta")
+ std::string owner_from = getInventoryOwner(ma->from_inv);
+ if(owner_from != "" && owner_from != player->getName())
{
- v3s16 p;
- p.X = stoi(fn.next(","));
- p.Y = stoi(fn.next(","));
- p.Z = stoi(fn.next(","));
- NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
- if(meta->getOwner() != "" &&
- meta->getOwner() != player->getName())
- {
- infostream<<"Cannot move item: "
- "not owner of metadata"
- <<std::endl;
- delete a;
- return;
- }
+ infostream<<"WARNING: "<<player->getName()
+ <<" tried to access an inventory that"
+ <<" belongs to "<<owner_from<<std::endl;
+ delete a;
+ return;
}
- }
- // If player is not an admin, check for ownership of dst
- if(ma->to_inv != "current_player"
- && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
- {
- Strfnd fn(ma->to_inv);
- std::string id0 = fn.next(":");
- if(id0 == "nodemeta")
+
+ std::string owner_to = getInventoryOwner(ma->to_inv);
+ if(owner_to != "" && owner_to != player->getName())
{
- v3s16 p;
- p.X = stoi(fn.next(","));
- p.Y = stoi(fn.next(","));
- p.Z = stoi(fn.next(","));
- NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
- if(meta->getOwner() != "" &&
- meta->getOwner() != player->getName())
- {
- infostream<<"Cannot move item: "
- "not owner of metadata"
- <<std::endl;
- delete a;
- return;
- }
+ infostream<<"WARNING: "<<player->getName()
+ <<" tried to access an inventory that"
+ <<" belongs to "<<owner_to<<std::endl;
+ delete a;
+ return;
}
}
}
@@ -2564,40 +2528,32 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
else if(a->getType() == IACTION_DROP)
{
IDropAction *da = (IDropAction*)a;
- // Disallow dropping items if not allowed to build
+
+ da->from_inv.applyCurrentPlayer(player->getName());
+
+ // Disallow dropping items if not allowed to interact
if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
{
delete a;
return;
}
// If player is not an admin, check for ownership
- else if (da->from_inv != "current_player"
- && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
+ else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
{
- Strfnd fn(da->from_inv);
- std::string id0 = fn.next(":");
- if(id0 == "nodemeta")
+ std::string owner_from = getInventoryOwner(da->from_inv);
+ if(owner_from != "" && owner_from != player->getName())
{
- v3s16 p;
- p.X = stoi(fn.next(","));
- p.Y = stoi(fn.next(","));
- p.Z = stoi(fn.next(","));
- NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
- if(meta->getOwner() != "" &&
- meta->getOwner() != player->getName())
- {
- infostream<<"Cannot move item: "
- "not owner of metadata"
- <<std::endl;
- delete a;
- return;
- }
+ infostream<<"WARNING: "<<player->getName()
+ <<" tried to access an inventory that"
+ <<" belongs to "<<owner_from<<std::endl;
+ delete a;
+ return;
}
}
}
// Do the action
- a->apply(&c, this, m_env);
+ a->apply(this, srp);
// Eat the action
delete a;
}
@@ -2809,8 +2765,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return;
u16 item = readU16(&data[2]);
- player->wieldItem(item);
- SendWieldedItem(player);
+ srp->setWieldIndex(item);
+ SendWieldedItem(srp);
}
else if(command == TOSERVER_RESPAWN)
{
@@ -2880,7 +2836,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
v3f player_pos = srp->m_last_good_position;
// Update wielded item
- srp->wieldItem(item_i);
+ if(srp->getWieldIndex() != item_i)
+ {
+ srp->setWieldIndex(item_i);
+ SendWieldedItem(srp);
+ }
// Get pointed to node (undefined if not POINTEDTYPE_NODE)
v3s16 p_under = pointed.node_undersurface;
@@ -2900,23 +2860,26 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
+ v3f pointed_pos_under = player_pos;
+ v3f pointed_pos_above = player_pos;
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ pointed_pos_under = intToFloat(p_under, BS);
+ pointed_pos_above = intToFloat(p_above, BS);
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ pointed_pos_under = pointed_object->getBasePosition();
+ pointed_pos_above = pointed_pos_under;
+ }
+
/*
Check that target is reasonably close
(only when digging or placing things)
*/
if(action == 0 || action == 2 || action == 3)
{
- v3f pointed_pos = player_pos;
- if(pointed.type == POINTEDTHING_NODE)
- {
- pointed_pos = intToFloat(p_under, BS);
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
- {
- pointed_pos = pointed_object->getBasePosition();
- }
-
- float d = player_pos.getDistanceFrom(pointed_pos);
+ float d = player_pos.getDistanceFrom(pointed_pos_under);
float max_d = BS * 10; // Just some large enough value
if(d > max_d){
actionstream<<"Player "<<player->getName()
@@ -2926,7 +2889,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<". ignoring."<<std::endl;
// Re-send block to revert change on client-side
RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos, BS));
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
client->SetBlockNotSent(blockpos);
// Do nothing else
return;
@@ -2936,8 +2899,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
/*
Make sure the player is allowed to do it
*/
- bool build_priv = (getPlayerPrivs(player) & PRIV_INTERACT) != 0;
- if(!build_priv)
+ bool interact_priv = (getPlayerPrivs(player) & PRIV_INTERACT) != 0;
+ if(!interact_priv)
{
infostream<<"Ignoring interaction from player "<<player->getName()
<<" because privileges are "<<getPlayerPrivs(player)
@@ -2956,7 +2919,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
NOTE: This can be used in the future to check if
somebody is cheating, by checking the timing.
*/
- bool cannot_punch_node = !build_priv;
+ bool cannot_punch_node = !interact_priv;
MapNode n(CONTENT_IGNORE);
@@ -2984,7 +2947,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
else if(pointed.type == POINTEDTHING_OBJECT)
{
- if(!build_priv)
+ if(!interact_priv)
return;
// Skip if object has been removed
@@ -3023,7 +2986,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
content_t material = CONTENT_IGNORE;
u8 mineral = MINERAL_NONE;
- bool cannot_remove_node = !build_priv;
+ bool cannot_remove_node = !interact_priv;
MapNode n(CONTENT_IGNORE);
try
@@ -3114,64 +3077,44 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
InventoryList *mlist = player->inventory.getList("main");
if(mlist != NULL)
{
- InventoryItem *item = mlist->getItem(item_i);
- if(item && (std::string)item->getName() == "ToolItem")
- {
- ToolItem *titem = (ToolItem*)item;
- std::string toolname = titem->getToolName();
-
- // Get digging properties for material and tool
- ToolDiggingProperties tp =
- m_toolmgr->getDiggingProperties(toolname);
- DiggingProperties prop =
- getDiggingProperties(material, &tp, m_nodedef);
-
- if(prop.diggable == false)
- {
- infostream<<"Server: WARNING: Player digged"
- <<" with impossible material + tool"
- <<" combination"<<std::endl;
- }
-
- bool weared_out = titem->addWear(prop.wear);
-
- if(weared_out)
- {
- mlist->deleteItem(item_i);
- }
-
- srp->m_inventory_not_sent = true;
- }
+ ItemStack &item = mlist->getItem(item_i);
+
+ // Get digging properties for material and tool
+ ToolDiggingProperties tp =
+ item.getToolDiggingProperties(m_itemdef);
+ DiggingProperties prop =
+ getDiggingProperties(material, &tp, m_nodedef);
+ item.addWear(prop.wear, m_itemdef);
+ srp->m_inventory_not_sent = true;
}
/*
Add dug item to inventory
*/
- InventoryItem *item = NULL;
+ ItemStack item;
if(mineral != MINERAL_NONE)
item = getDiggedMineralItem(mineral, this);
// If not mineral
- if(item == NULL)
+ if(item.empty())
{
const std::string &dug_s = m_nodedef->get(material).dug_item;
if(dug_s != "")
{
- std::istringstream is(dug_s, std::ios::binary);
- item = InventoryItem::deSerialize(is, this);
+ item.deSerialize(dug_s, m_itemdef);
}
}
- if(item != NULL)
+ if(!item.empty())
{
// Add a item to inventory
player->inventory.addItem("main", item);
srp->m_inventory_not_sent = true;
}
- item = NULL;
+ item.clear();
{
const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item;
@@ -3179,12 +3122,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(extra_dug_s != "" && extra_rarity != 0
&& myrand() % extra_rarity == 0)
{
- std::istringstream is(extra_dug_s, std::ios::binary);
- item = InventoryItem::deSerialize(is, this);
+ item.deSerialize(extra_dug_s, m_itemdef);
}
}
- if(item != NULL)
+ if(!item.empty())
{
// Add a item to inventory
player->inventory.addItem("main", item);
@@ -3226,242 +3168,155 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
else if(action == 3)
{
- if(pointed.type == POINTEDTHING_NODE)
+ if(!interact_priv)
{
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist == NULL)
- return;
-
- // Get item
- InventoryItem *item = ilist->getItem(item_i);
-
- // If there is no item, it is not possible to add it anywhere
- if(item == NULL)
- return;
+ infostream<<"Not allowing player "
+ <<player->getName()<<" to place item: "
+ <<"no interact privileges"<<std::endl;
+ return;
+ }
- /*
- Handle material items
- */
- if(std::string("MaterialItem") == item->getName())
- {
- bool cannot_place_node = !build_priv;
-
- try{
- // Don't add a node if this is not a free space
- MapNode n2 = m_env->getMap().getNode(p_above);
- if(m_nodedef->get(n2).buildable_to == false)
- {
- infostream<<"Client "<<peer_id<<" tried to place"
- <<" node in invalid position."<<std::endl;
- cannot_place_node = true;
- }
- }
- catch(InvalidPositionException &e)
- {
- infostream<<"Server: Ignoring ADDNODE: Node not found"
- <<" Adding block to emerge queue."
- <<std::endl;
- m_emerge_queue.addBlock(peer_id,
- getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
- cannot_place_node = true;
- }
+ ItemStack item = srp->getWieldedItem();
- if(cannot_place_node)
- {
- // Client probably has wrong data.
- // Set block not sent, so that client will get
- // a valid one.
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(p_above);
- client->SetBlockNotSent(blockpos);
- return;
- }
+ if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ // Right click object
- // Reset build time counter
- getClient(peer_id)->m_time_from_building = 0.0;
-
- // Create node data
- MaterialItem *mitem = (MaterialItem*)item;
- MapNode n;
- n.setContent(mitem->getMaterial());
-
- actionstream<<player->getName()<<" places material "
- <<(int)mitem->getMaterial()
- <<" at "<<PP(p_under)<<std::endl;
-
- // Calculate direction for wall mounted stuff
- if(m_nodedef->get(n).wall_mounted)
- n.param2 = packDir(p_under - p_above);
+ // Skip if object has been removed
+ if(pointed_object->m_removed)
+ return;
- // Calculate the direction for furnaces and chests and stuff
- if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE)
- {
- v3f playerpos = player->getPosition();
- v3f blockpos = intToFloat(p_above, BS) - playerpos;
- blockpos = blockpos.normalize();
- n.param1 = 0;
- if (fabs(blockpos.X) > fabs(blockpos.Z)) {
- if (blockpos.X < 0)
- n.param1 = 3;
- else
- n.param1 = 1;
- } else {
- if (blockpos.Z < 0)
- n.param1 = 2;
- else
- n.param1 = 0;
- }
- }
+ actionstream<<player->getName()<<" right-clicks object "
+ <<pointed.object_id<<std::endl;
- /*
- Send to all close-by players
- */
- core::list<u16> far_players;
- sendAddNode(p_above, n, 0, &far_players, 30);
-
- /*
- Handle inventory
- */
- InventoryList *ilist = player->inventory.getList("main");
- if(g_settings->getBool("creative_mode") == false && ilist)
- {
- // Remove from inventory and send inventory
- if(mitem->getCount() <= 1)
- ilist->deleteItem(item_i);
- else
- mitem->remove(1);
- srp->m_inventory_not_sent = true;
- }
-
- /*
- Add node.
+ // Do stuff
+ pointed_object->rightClick(srp);
+ }
+ else if(scriptapi_item_on_place(m_lua,
+ item, srp, pointed))
+ {
+ // Placement was handled in lua
- This takes some time so it is done after the quick stuff
- */
- core::map<v3s16, MapBlock*> modified_blocks;
- {
- MapEditEventIgnorer ign(&m_ignore_map_edit_events);
+ // Apply returned ItemStack
+ if(g_settings->getBool("creative_mode") == false)
+ srp->setWieldedItem(item);
+ }
+ else if(pointed.type == POINTEDTHING_NODE &&
+ item.getDefinition(m_itemdef).type == ITEM_NODE)
+ {
+ bool cannot_place_node = !interact_priv;
- std::string p_name = std::string(player->getName());
- m_env->getMap().addNodeAndUpdate(p_above, n, modified_blocks, p_name);
- }
- /*
- Set blocks not sent to far players
- */
- for(core::list<u16>::Iterator
- i = far_players.begin();
- i != far_players.end(); i++)
+ try{
+ // Don't add a node if this is not a free space
+ MapNode n2 = m_env->getMap().getNode(p_above);
+ if(m_nodedef->get(n2).buildable_to == false)
{
- u16 peer_id = *i;
- RemoteClient *client = getClient(peer_id);
- if(client==NULL)
- continue;
- client->SetBlocksNotSent(modified_blocks);
+ infostream<<"Client "<<peer_id<<" tried to place"
+ <<" node in invalid position."<<std::endl;
+ cannot_place_node = true;
}
-
- /*
- Run script hook
- */
- scriptapi_environment_on_placenode(m_lua, p_above, n, srp);
-
- /*
- Calculate special events
- */
-
- /*if(n.d == LEGN(m_nodedef, "CONTENT_MESE"))
- {
- u32 count = 0;
- for(s16 z=-1; z<=1; z++)
- for(s16 y=-1; y<=1; y++)
- for(s16 x=-1; x<=1; x++)
- {
-
- }
- }*/
}
- /*
- Place other item (not a block)
- */
- else
+ catch(InvalidPositionException &e)
{
- if(!build_priv)
- {
- infostream<<"Not allowing player to place item: "
- "no build privileges"<<std::endl;
- return;
- }
+ infostream<<"Server: Ignoring ADDNODE: Node not found"
+ <<" Adding block to emerge queue."
+ <<std::endl;
+ m_emerge_queue.addBlock(peer_id,
+ getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
+ cannot_place_node = true;
+ }
- // Calculate a position for it
- v3f pos = player_pos;
- if(pointed.type == POINTEDTHING_NOTHING)
- {
- infostream<<"Not allowing player to place item: "
- "pointing to nothing"<<std::endl;
- return;
- }
- else if(pointed.type == POINTEDTHING_NODE)
- {
- pos = intToFloat(p_above, BS);
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
- {
- pos = pointed_object->getBasePosition();
+ if(cannot_place_node)
+ {
+ // Client probably has wrong data.
+ // Set block not sent, so that client will get
+ // a valid one.
+ RemoteClient *client = getClient(peer_id);
+ v3s16 blockpos = getNodeBlockPos(p_above);
+ client->SetBlockNotSent(blockpos);
+ return;
+ }
- // Randomize a bit
- pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
- pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
- }
+ // Reset build time counter
+ getClient(peer_id)->m_time_from_building = 0.0;
- //pos.Y -= BS*0.45;
- //pos.Y -= BS*0.25; // let it drop a bit
+ // Create node data
+ MapNode n(m_nodedef, item.name, 0, 0);
- /*
- Check that the block is loaded so that the item
- can properly be added to the static list too
- */
- v3s16 blockpos = getNodeBlockPos(floatToInt(pos, BS));
- MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
- if(block==NULL)
- {
- infostream<<"Error while placing item: "
- "block not found"<<std::endl;
- return;
- }
+ actionstream<<player->getName()<<" places material "
+ <<item.name
+ <<" at "<<PP(p_under)<<std::endl;
- actionstream<<player->getName()<<" places "<<item->getName()
- <<" at "<<PP(pos)<<std::endl;
+ // Calculate direction for wall mounted stuff
+ if(m_nodedef->get(n).wall_mounted)
+ n.param2 = packDir(p_under - p_above);
- /*
- Place the item
- */
- bool remove = item->dropOrPlace(m_env, srp, pos, true, -1);
- if(remove && g_settings->getBool("creative_mode") == false)
- {
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist){
- // Remove from inventory and send inventory
- ilist->deleteItem(item_i);
- srp->m_inventory_not_sent = true;
- }
+ // Calculate the direction for furnaces and chests and stuff
+ if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE)
+ {
+ v3f playerpos = player->getPosition();
+ v3f blockpos = intToFloat(p_above, BS) - playerpos;
+ blockpos = blockpos.normalize();
+ n.param1 = 0;
+ if (fabs(blockpos.X) > fabs(blockpos.Z)) {
+ if (blockpos.X < 0)
+ n.param1 = 3;
+ else
+ n.param1 = 1;
+ } else {
+ if (blockpos.Z < 0)
+ n.param1 = 2;
+ else
+ n.param1 = 0;
}
}
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
- {
- // Right click object
- if(!build_priv)
- return;
+ /*
+ Send to all close-by players
+ */
+ core::list<u16> far_players;
+ sendAddNode(p_above, n, 0, &far_players, 30);
+
+ /*
+ Handle inventory
+ */
+ if(g_settings->getBool("creative_mode") == false)
+ {
+ // Remove from inventory and send inventory
+ item.remove(1);
+ srp->setWieldedItem(item);
+ }
- // Skip if object has been removed
- if(pointed_object->m_removed)
- return;
+ /*
+ Add node.
- actionstream<<player->getName()<<" right-clicks object "
- <<pointed.object_id<<std::endl;
+ This takes some time so it is done after the quick stuff
+ */
+ core::map<v3s16, MapBlock*> modified_blocks;
+ {
+ MapEditEventIgnorer ign(&m_ignore_map_edit_events);
- // Do stuff
- pointed_object->rightClick(srp);
+ std::string p_name = std::string(player->getName());
+ m_env->getMap().addNodeAndUpdate(p_above, n, modified_blocks, p_name);
+ }
+ /*
+ Set blocks not sent to far players
+ */
+ for(core::list<u16>::Iterator
+ i = far_players.begin();
+ i != far_players.end(); i++)
+ {
+ u16 peer_id = *i;
+ RemoteClient *client = getClient(peer_id);
+ if(client==NULL)
+ continue;
+ client->SetBlocksNotSent(modified_blocks);
+ }
+
+ /*
+ Run script hook
+ */
+ scriptapi_environment_on_placenode(m_lua, p_above, n, srp);
}
} // action == 3
@@ -3471,38 +3326,25 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
else if(action == 4)
{
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist == NULL)
- return;
-
- // Get item
- InventoryItem *item = ilist->getItem(item_i);
-
- // If there is no item, it is not possible to add it anywhere
- if(item == NULL)
- return;
-
- // Requires build privs
- if(!build_priv)
+ // Requires interact privs
+ if(!interact_priv)
{
infostream<<"Not allowing player to use item: "
- "no build privileges"<<std::endl;
+ "no interact privileges"<<std::endl;
return;
}
- actionstream<<player->getName()<<" uses "<<item->getName()
+ ItemStack item = srp->getWieldedItem();
+
+ actionstream<<player->getName()<<" uses "<<item.name
<<", pointing at "<<pointed.dump()<<std::endl;
- bool remove = item->use(m_env, srp, pointed);
-
- if(remove && g_settings->getBool("creative_mode") == false)
+ if(scriptapi_item_on_use(m_lua,
+ item, srp, pointed))
{
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist){
- // Remove from inventory and send inventory
- ilist->deleteItem(item_i);
- srp->m_inventory_not_sent = true;
- }
+ // Apply returned ItemStack
+ if(g_settings->getBool("creative_mode") == false)
+ srp->setWieldedItem(item);
}
} // action == 4
@@ -3515,9 +3357,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
infostream<<"WARNING: Server: Invalid action "
<<action<<std::endl;
}
-
- // Complete add_to_inventory_later
- srp->completeAddToInventoryLater(item_i);
}
else
{
@@ -3549,6 +3388,9 @@ Inventory* Server::getInventory(const InventoryLocation &loc)
case InventoryLocation::UNDEFINED:
{}
break;
+ case InventoryLocation::CURRENT_PLAYER:
+ {}
+ break;
case InventoryLocation::PLAYER:
{
Player *player = m_env->getPlayer(loc.name.c_str());
@@ -3570,6 +3412,33 @@ Inventory* Server::getInventory(const InventoryLocation &loc)
}
return NULL;
}
+std::string Server::getInventoryOwner(const InventoryLocation &loc)
+{
+ switch(loc.type){
+ case InventoryLocation::UNDEFINED:
+ {}
+ break;
+ case InventoryLocation::CURRENT_PLAYER:
+ {}
+ break;
+ case InventoryLocation::PLAYER:
+ {
+ return loc.name;
+ }
+ break;
+ case InventoryLocation::NODEMETA:
+ {
+ NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
+ if(!meta)
+ return "";
+ return meta->getOwner();
+ }
+ break;
+ default:
+ assert(0);
+ }
+ return "";
+}
void Server::setInventoryModified(const InventoryLocation &loc)
{
switch(loc.type){
@@ -3604,64 +3473,6 @@ void Server::setInventoryModified(const InventoryLocation &loc)
assert(0);
}
}
-#if 0
-Inventory* Server::getInventory(InventoryContext *c, std::string id)
-{
- if(id == "current_player")
- {
- assert(c->current_player);
- return &(c->current_player->inventory);
- }
-
- Strfnd fn(id);
- std::string id0 = fn.next(":");
-
- if(id0 == "nodemeta")
- {
- v3s16 p;
- p.X = stoi(fn.next(","));
- p.Y = stoi(fn.next(","));
- p.Z = stoi(fn.next(","));
-
- InventoryLocation loc;
- loc.setNodeMeta(p);
- return getInventory(loc);
- }
-
- infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
- return NULL;
-}
-void Server::inventoryModified(InventoryContext *c, std::string id)
-{
- if(id == "current_player")
- {
- assert(c->current_player);
- ServerRemotePlayer *srp =
- static_cast<ServerRemotePlayer*>(c->current_player);
- srp->m_inventory_not_sent = true;
- return;
- }
-
- Strfnd fn(id);
- std::string id0 = fn.next(":");
-
- if(id0 == "nodemeta")
- {
- v3s16 p;
- p.X = stoi(fn.next(","));
- p.Y = stoi(fn.next(","));
- p.Z = stoi(fn.next(","));
- v3s16 blockpos = getNodeBlockPos(p);
-
- InventoryLocation loc;
- loc.setNodeMeta(p);
- setInventoryModified(loc);
- return;
- }
-
- infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
-}
-#endif
core::list<PlayerInfo> Server::getPlayerInfo()
{
@@ -3783,8 +3594,8 @@ void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
con.Send(peer_id, 0, data, true);
}
-void Server::SendToolDef(con::Connection &con, u16 peer_id,
- IToolDefManager *tooldef)
+void Server::SendItemDef(con::Connection &con, u16 peer_id,
+ IItemDefManager *itemdef)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
@@ -3792,16 +3603,18 @@ void Server::SendToolDef(con::Connection &con, u16 peer_id,
/*
u16 command
u32 length of the next item
- serialized ToolDefManager
+ zlib-compressed serialized ItemDefManager
*/
- writeU16(os, TOCLIENT_TOOLDEF);
+ writeU16(os, TOCLIENT_ITEMDEF);
std::ostringstream tmp_os(std::ios::binary);
- tooldef->serialize(tmp_os);
- os<<serializeLongString(tmp_os.str());
+ itemdef->serialize(tmp_os);
+ std::ostringstream tmp_os2(std::ios::binary);
+ compressZlib(tmp_os.str(), tmp_os2);
+ os<<serializeLongString(tmp_os2.str());
// Make data buffer
std::string s = os.str();
- infostream<<"Server::SendToolDef(): Sending tool definitions: size="
+ infostream<<"Server::SendItemDef(): Sending item definitions: size="
<<s.size()<<std::endl;
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
@@ -3817,12 +3630,14 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id,
/*
u16 command
u32 length of the next item
- serialized NodeDefManager
+ zlib-compressed serialized NodeDefManager
*/
writeU16(os, TOCLIENT_NODEDEF);
std::ostringstream tmp_os(std::ios::binary);
nodedef->serialize(tmp_os);
- os<<serializeLongString(tmp_os.str());
+ std::ostringstream tmp_os2(std::ios::binary);
+ compressZlib(tmp_os.str(), tmp_os2);
+ os<<serializeLongString(tmp_os2.str());
// Make data buffer
std::string s = os.str();
@@ -3833,31 +3648,6 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id,
con.Send(peer_id, 0, data, true);
}
-void Server::SendCraftItemDef(con::Connection &con, u16 peer_id,
- ICraftItemDefManager *craftitemdef)
-{
- DSTACK(__FUNCTION_NAME);
- std::ostringstream os(std::ios_base::binary);
-
- /*
- u16 command
- u32 length of the next item
- serialized CraftItemDefManager
- */
- writeU16(os, TOCLIENT_CRAFTITEMDEF);
- std::ostringstream tmp_os(std::ios::binary);
- craftitemdef->serialize(tmp_os);
- os<<serializeLongString(tmp_os.str());
-
- // Make data buffer
- std::string s = os.str();
- infostream<<"Server::SendCraftItemDef(): Sending craft item definitions: size="
- <<s.size()<<std::endl;
- SharedBuffer<u8> data((u8*)s.c_str(), s.size());
- // Send as reliable
- con.Send(peer_id, 0, data, true);
-}
-
/*
Non-static send methods
*/
@@ -3891,28 +3681,18 @@ void Server::SendInventory(u16 peer_id)
m_con.Send(peer_id, 0, data, true);
}
-std::string getWieldedItemString(const Player *player)
-{
- const InventoryItem *item = player->getWieldItem();
- if (item == NULL)
- return std::string("");
- std::ostringstream os(std::ios_base::binary);
- item->serialize(os);
- return os.str();
-}
-
-void Server::SendWieldedItem(const Player* player)
+void Server::SendWieldedItem(const ServerRemotePlayer* srp)
{
DSTACK(__FUNCTION_NAME);
- assert(player);
+ assert(srp);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_PLAYERITEM);
writeU16(os, 1);
- writeU16(os, player->peer_id);
- os<<serializeString(getWieldedItemString(player));
+ writeU16(os, srp->peer_id);
+ os<<serializeString(srp->getWieldedItem().getItemString());
// Make data buffer
std::string s = os.str();
@@ -3934,8 +3714,10 @@ void Server::SendPlayerItems()
for(i = players.begin(); i != players.end(); ++i)
{
Player *p = *i;
+ ServerRemotePlayer *srp =
+ static_cast<ServerRemotePlayer*>(p);
writeU16(os, p->peer_id);
- os<<serializeString(getWieldedItemString(p));
+ os<<serializeString(srp->getWieldedItem().getItemString());
}
// Make data buffer
@@ -4576,6 +4358,44 @@ void Server::RespawnPlayer(Player *player)
SendPlayerHP(player);
}
+bool Server::GetCraftingResult(u16 peer_id, ItemStack &result, bool decrementInput)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ Player* player = m_env->getPlayer(peer_id);
+ assert(player);
+
+ // Get the crafting InventoryList of the player in which we will operate
+ InventoryList *clist = player->inventory.getList("craft");
+ assert(clist);
+
+ // Mangle crafting grid to an another format
+ CraftInput ci;
+ ci.method = CRAFT_METHOD_NORMAL;
+ ci.width = 3;
+ for(u16 i=0; i<9; i++)
+ {
+ ci.items.push_back(clist->getItem(i));
+ }
+
+ // Find out what is crafted and add it to result item slot
+ CraftOutput co;
+ bool found = m_craftdef->getCraftResult(ci, co, decrementInput, this);
+ if(found)
+ result.deSerialize(co.item, m_itemdef);
+
+ if(decrementInput)
+ {
+ // CraftInput has been changed, apply changes in clist
+ for(u16 i=0; i<9; i++)
+ {
+ clist->changeItem(i, ci.items[i]);
+ }
+ }
+
+ return found;
+}
+
void Server::UpdateCrafting(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
@@ -4601,12 +4421,11 @@ void Server::UpdateCrafting(u16 peer_id)
if(!player->craftresult_is_preview && rlist->getUsedSlots() != 0)
{
// Grab item out of craftresult
- InventoryItem *item = rlist->changeItem(0, NULL);
+ ItemStack item = rlist->changeItem(0, ItemStack());
// Try to put in main
- InventoryItem *leftover = mlist->addItem(item);
- // If there are leftovers, put them back to craftresult and
- // delete leftovers
- delete rlist->addItem(leftover);
+ ItemStack leftover = mlist->addItem(item);
+ // If there are leftovers, put them back to craftresult
+ rlist->addItem(leftover);
// Inventory was modified
srp->m_inventory_not_sent = true;
}
@@ -4616,28 +4435,17 @@ void Server::UpdateCrafting(u16 peer_id)
if(rlist->getUsedSlots() == 0)
player->craftresult_is_preview = true;
- // If it is a preview, clear the possible old preview in it
- if(player->craftresult_is_preview)
- rlist->clearItems();
-
// If it is a preview, find out what is the crafting result
// and put it in
if(player->craftresult_is_preview)
{
- // Mangle crafting grid to an another format
- std::vector<InventoryItem*> items;
- for(u16 i=0; i<9; i++){
- if(clist->getItem(i) == NULL)
- items.push_back(NULL);
- else
- items.push_back(clist->getItem(i)->clone());
- }
- CraftPointerInput cpi(3, items);
+ // Clear the possible old preview in it
+ rlist->clearItems();
- // Find out what is crafted and add it to result item slot
- InventoryItem *result = m_craftdef->getCraftResult(cpi, this);
- if(result)
- rlist->addItem(result);
+ // Put the new preview in
+ ItemStack crafting_result;
+ if(GetCraftingResult(peer_id, crafting_result, false))
+ rlist->addItem(crafting_result);
}
}
@@ -4734,9 +4542,9 @@ void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
// IGameDef interface
// Under envlock
-IToolDefManager* Server::getToolDefManager()
+IItemDefManager* Server::getItemDefManager()
{
- return m_toolmgr;
+ return m_itemdef;
}
INodeDefManager* Server::getNodeDefManager()
{
@@ -4746,10 +4554,6 @@ ICraftDefManager* Server::getCraftDefManager()
{
return m_craftdef;
}
-ICraftItemDefManager* Server::getCraftItemDefManager()
-{
- return m_craftitemdef;
-}
ITextureSource* Server::getTextureSource()
{
return NULL;
@@ -4759,9 +4563,9 @@ u16 Server::allocateUnknownNodeId(const std::string &name)
return m_nodedef->allocateDummy(name);
}
-IWritableToolDefManager* Server::getWritableToolDefManager()
+IWritableItemDefManager* Server::getWritableItemDefManager()
{
- return m_toolmgr;
+ return m_itemdef;
}
IWritableNodeDefManager* Server::getWritableNodeDefManager()
{
@@ -4771,10 +4575,6 @@ IWritableCraftDefManager* Server::getWritableCraftDefManager()
{
return m_craftdef;
}
-IWritableCraftItemDefManager* Server::getWritableCraftItemDefManager()
-{
- return m_craftitemdef;
-}
const ModSpec* Server::getModSpec(const std::string &modname)
{
@@ -4874,7 +4674,7 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
{
// Warning: double code below
// Backup actual inventory
- player->inventory_backup = new Inventory();
+ player->inventory_backup = new Inventory(m_itemdef);
*(player->inventory_backup) = player->inventory;
// Set creative inventory
player->resetInventory();
@@ -4919,7 +4719,7 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
{
// Warning: double code above
// Backup actual inventory
- player->inventory_backup = new Inventory();
+ player->inventory_backup = new Inventory(m_itemdef);
*(player->inventory_backup) = player->inventory;
// Set creative inventory
player->resetInventory();
diff --git a/src/server.h b/src/server.h
index 5938f915d..d979cb518 100644
--- a/src/server.h
+++ b/src/server.h
@@ -36,10 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventorymanager.h"
struct LuaState;
typedef struct lua_State lua_State;
-class IWritableToolDefManager;
+class IWritableItemDefManager;
class IWritableNodeDefManager;
class IWritableCraftDefManager;
-class IWritableCraftItemDefManager;
/*
Some random functions
@@ -437,6 +436,7 @@ public:
Shall be called with the environment and the connection locked.
*/
Inventory* getInventory(const InventoryLocation &loc);
+ std::string getInventoryOwner(const InventoryLocation &loc);
void setInventoryModified(const InventoryLocation &loc);
// Connection must be locked when called
@@ -514,17 +514,15 @@ public:
// IGameDef interface
// Under envlock
- virtual IToolDefManager* getToolDefManager();
+ virtual IItemDefManager* getItemDefManager();
virtual INodeDefManager* getNodeDefManager();
virtual ICraftDefManager* getCraftDefManager();
- virtual ICraftItemDefManager* getCraftItemDefManager();
virtual ITextureSource* getTextureSource();
virtual u16 allocateUnknownNodeId(const std::string &name);
- IWritableToolDefManager* getWritableToolDefManager();
+ IWritableItemDefManager* getWritableItemDefManager();
IWritableNodeDefManager* getWritableNodeDefManager();
IWritableCraftDefManager* getWritableCraftDefManager();
- IWritableCraftItemDefManager* getWritableCraftItemDefManager();
const ModSpec* getModSpec(const std::string &modname);
@@ -545,12 +543,10 @@ private:
const std::wstring &reason);
static void SendDeathscreen(con::Connection &con, u16 peer_id,
bool set_camera_point_target, v3f camera_point_target);
- static void SendToolDef(con::Connection &con, u16 peer_id,
- IToolDefManager *tooldef);
+ static void SendItemDef(con::Connection &con, u16 peer_id,
+ IItemDefManager *itemdef);
static void SendNodeDef(con::Connection &con, u16 peer_id,
INodeDefManager *nodedef);
- static void SendCraftItemDef(con::Connection &con, u16 peer_id,
- ICraftItemDefManager *nodedef);
/*
Non-static send methods.
@@ -562,7 +558,7 @@ private:
// Envlock and conlock should be locked when calling these
void SendInventory(u16 peer_id);
// send wielded item info about player to all
- void SendWieldedItem(const Player *player);
+ void SendWieldedItem(const ServerRemotePlayer *srp);
// send wielded item info about all players to all players
void SendPlayerItems();
void SendChatMessage(u16 peer_id, const std::wstring &message);
@@ -599,6 +595,7 @@ private:
void HandlePlayerHP(Player *player, s16 damage);
void RespawnPlayer(Player *player);
+ bool GetCraftingResult(u16 peer_id, ItemStack &result, bool decrementInput);
void UpdateCrafting(u16 peer_id);
// When called, connection mutex should be locked
@@ -664,8 +661,8 @@ private:
// Envlock and conlock should be locked when using Lua
lua_State *m_lua;
- // Tool definition manager
- IWritableToolDefManager *m_toolmgr;
+ // Item definition manager
+ IWritableItemDefManager *m_itemdef;
// Node definition manager
IWritableNodeDefManager *m_nodedef;
@@ -673,9 +670,6 @@ private:
// Craft definition manager
IWritableCraftDefManager *m_craftdef;
- // CraftItem definition manager
- IWritableCraftItemDefManager *m_craftitemdef;
-
// Mods
core::list<ModSpec> m_mods;
@@ -740,7 +734,7 @@ private:
core::list<std::string> m_modspaths;
bool m_shutdown_requested;
-
+
/*
Map edit event queue. Automatically receives all map edits.
The constructor of this class registers us to receive them through
diff --git a/src/serverobject.cpp b/src/serverobject.cpp
index ca3d2c3b9..2609e3015 100644
--- a/src/serverobject.cpp
+++ b/src/serverobject.cpp
@@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h"
#include <fstream>
#include "inventory.h"
-#include "tooldef.h"
+#include "materials.h"
ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos):
ActiveObject(0),
@@ -67,10 +67,31 @@ void ServerActiveObject::registerType(u16 type, Factory f)
m_types.insert(type, f);
}
-void ServerActiveObject::getWieldDiggingProperties(ToolDiggingProperties *dst)
+ItemStack ServerActiveObject::getWieldedItem() const
{
- *dst = ToolDiggingProperties();
+ const Inventory *inv = getInventory();
+ if(inv)
+ {
+ const InventoryList *list = inv->getList(getWieldList());
+ if(list)
+ return list->getItem(getWieldIndex());
+ }
+ return ItemStack();
}
-
+bool ServerActiveObject::setWieldedItem(const ItemStack &item)
+{
+ Inventory *inv = getInventory();
+ if(inv)
+ {
+ InventoryList *list = inv->getList(getWieldList());
+ if (list)
+ {
+ list->changeItem(getWieldIndex(), item);
+ setInventoryModified();
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/serverobject.h b/src/serverobject.h
index fd8a51a9e..94ceb4895 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h"
#include "activeobject.h"
#include "utility.h"
+#include "inventorymanager.h"
/*
@@ -41,7 +42,7 @@ Some planning
*/
class ServerEnvironment;
-class InventoryItem;
+class ItemStack;
class Player;
struct ToolDiggingProperties;
@@ -138,19 +139,27 @@ public:
{}
virtual void rightClick(ServerActiveObject *clicker)
{}
- virtual void getWieldDiggingProperties(ToolDiggingProperties *dst);
- virtual void damageWieldedItem(u16 amount)
- {}
- // If all fits, eats item and returns true. Otherwise returns false.
- virtual bool addToInventory(InventoryItem *item)
- { return false; }
- virtual void addToInventoryLater(InventoryItem *item)
- {}
virtual void setHP(s16 hp)
{}
virtual s16 getHP()
{ return 0; }
+ // Inventory and wielded item
+ virtual Inventory* getInventory()
+ { return NULL; }
+ virtual const Inventory* getInventory() const
+ { return NULL; }
+ virtual InventoryLocation getInventoryLocation() const
+ { return InventoryLocation(); }
+ virtual void setInventoryModified()
+ {}
+ virtual std::string getWieldList() const
+ { return ""; }
+ virtual int getWieldIndex() const
+ { return 0; }
+ virtual ItemStack getWieldedItem() const;
+ virtual bool setWieldedItem(const ItemStack &item);
+
/*
Number of players which know about this object. Object won't be
deleted until this is 0 to keep the id preserved for the right
diff --git a/src/serverremoteplayer.cpp b/src/serverremoteplayer.cpp
index 1681900e0..db4b44707 100644
--- a/src/serverremoteplayer.cpp
+++ b/src/serverremoteplayer.cpp
@@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "log.h"
#include "gamedef.h"
-#include "tooldef.h"
+#include "inventory.h"
#include "environment.h"
#include "materials.h"
@@ -31,6 +31,7 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
ServerActiveObject(env, v3f(0,0,0)),
m_last_good_position(0,0,0),
m_last_good_position_age(0),
+ m_wield_index(0),
m_inventory_not_sent(false),
m_hp_not_sent(false),
m_respawn_active(false),
@@ -57,7 +58,6 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 pee
}
ServerRemotePlayer::~ServerRemotePlayer()
{
- clearAddToInventoryLater();
}
void ServerRemotePlayer::setPosition(const v3f &position)
@@ -67,12 +67,41 @@ void ServerRemotePlayer::setPosition(const v3f &position)
m_position_not_sent = true;
}
-InventoryItem* ServerRemotePlayer::getWieldedItem()
+Inventory* ServerRemotePlayer::getInventory()
{
- InventoryList *list = inventory.getList("main");
- if (list)
- return list->getItem(m_selected_item);
- return NULL;
+ return &inventory;
+}
+
+const Inventory* ServerRemotePlayer::getInventory() const
+{
+ return &inventory;
+}
+
+InventoryLocation ServerRemotePlayer::getInventoryLocation() const
+{
+ InventoryLocation loc;
+ loc.setPlayer(getName());
+ return loc;
+}
+
+void ServerRemotePlayer::setInventoryModified()
+{
+ m_inventory_not_sent = true;
+}
+
+std::string ServerRemotePlayer::getWieldList() const
+{
+ return "main";
+}
+
+int ServerRemotePlayer::getWieldIndex() const
+{
+ return m_wield_index;
+}
+
+void ServerRemotePlayer::setWieldIndex(int i)
+{
+ m_wield_index = i;
}
/* ServerActiveObject interface */
@@ -156,8 +185,10 @@ void ServerRemotePlayer::punch(ServerActiveObject *puncher,
mp.crackiness = -0.5;
mp.cuttability = 0.5;
- ToolDiggingProperties tp;
- puncher->getWieldDiggingProperties(&tp);
+ IItemDefManager *idef = m_env->getGameDef()->idef();
+ ItemStack punchitem = puncher->getWieldedItem();
+ ToolDiggingProperties tp =
+ punchitem.getToolDiggingProperties(idef);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
@@ -167,7 +198,8 @@ void ServerRemotePlayer::punch(ServerActiveObject *puncher,
<<" HP"<<std::endl;
setHP(getHP() - hitprop.hp);
- puncher->damageWieldedItem(hitprop.wear);
+ punchitem.addWear(hitprop.wear, idef);
+ puncher->setWieldedItem(punchitem);
if(hitprop.hp != 0)
{
@@ -201,109 +233,6 @@ void ServerRemotePlayer::moveTo(v3f pos, bool continuous)
m_last_good_position_age = 0;
}
-void ServerRemotePlayer::getWieldDiggingProperties(ToolDiggingProperties *dst)
-{
- IGameDef *gamedef = m_env->getGameDef();
- IToolDefManager *tdef = gamedef->tdef();
-
- InventoryItem *item = getWieldedItem();
- if(item == NULL || std::string(item->getName()) != "ToolItem"){
- *dst = ToolDiggingProperties();
- return;
- }
- ToolItem *titem = (ToolItem*)item;
- *dst = tdef->getDiggingProperties(titem->getToolName());
-}
-
-void ServerRemotePlayer::damageWieldedItem(u16 amount)
-{
- infostream<<"Damaging "<<getName()<<"'s wielded item for amount="
- <<amount<<std::endl;
- InventoryList *list = inventory.getList("main");
- if(!list)
- return;
- InventoryItem *item = list->getItem(m_selected_item);
- if(item && (std::string)item->getName() == "ToolItem"){
- ToolItem *titem = (ToolItem*)item;
- bool weared_out = titem->addWear(amount);
- if(weared_out)
- list->deleteItem(m_selected_item);
- }
-}
-bool ServerRemotePlayer::addToInventory(InventoryItem *item)
-{
- infostream<<"Adding "<<item->getName()<<" into "<<getName()
- <<"'s inventory"<<std::endl;
-
- InventoryList *ilist = inventory.getList("main");
- if(ilist == NULL)
- return false;
-
- // In creative mode, just delete the item
- if(g_settings->getBool("creative_mode")){
- return false;
- }
-
- // Skip if inventory has no free space
- if(ilist->roomForItem(item) == false)
- {
- infostream<<"Player inventory has no free space"<<std::endl;
- return false;
- }
-
- // Add to inventory
- InventoryItem *leftover = ilist->addItem(item);
- assert(!leftover);
-
- m_inventory_not_sent = true;
-
- return true;
-}
-void ServerRemotePlayer::addToInventoryLater(InventoryItem *item)
-{
- infostream<<"Adding (later) "<<item->getName()<<" into "<<getName()
- <<"'s inventory"<<std::endl;
- m_additional_items.push_back(item);
-}
-void ServerRemotePlayer::clearAddToInventoryLater()
-{
- for (std::vector<InventoryItem*>::iterator
- i = m_additional_items.begin();
- i != m_additional_items.end(); i++)
- {
- delete *i;
- }
- m_additional_items.clear();
-}
-void ServerRemotePlayer::completeAddToInventoryLater(u16 preferred_index)
-{
- InventoryList *ilist = inventory.getList("main");
- if(ilist == NULL)
- {
- clearAddToInventoryLater();
- return;
- }
-
- // In creative mode, just delete the items
- if(g_settings->getBool("creative_mode"))
- {
- clearAddToInventoryLater();
- return;
- }
-
- for (std::vector<InventoryItem*>::iterator
- i = m_additional_items.begin();
- i != m_additional_items.end(); i++)
- {
- InventoryItem *item = *i;
- InventoryItem *leftover = item;
- leftover = ilist->addItem(preferred_index, leftover);
- leftover = ilist->addItem(leftover);
- delete leftover;
- }
- m_additional_items.clear();
- m_inventory_not_sent = true;
-}
void ServerRemotePlayer::setHP(s16 hp_)
{
s16 oldhp = hp;
diff --git a/src/serverremoteplayer.h b/src/serverremoteplayer.h
index bdc3bba20..9d9437646 100644
--- a/src/serverremoteplayer.h
+++ b/src/serverremoteplayer.h
@@ -46,9 +46,6 @@ public:
virtual void setPosition(const v3f &position);
- // Returns a reference
- virtual InventoryItem* getWieldedItem();
-
/* ServerActiveObject interface */
u8 getType() const
@@ -77,19 +74,20 @@ public:
virtual std::string getDescription()
{return std::string("player ")+getName();}
- virtual void getWieldDiggingProperties(ToolDiggingProperties *dst);
- virtual void damageWieldedItem(u16 amount);
- // If all fits, eats item and returns true. Otherwise returns false.
- virtual bool addToInventory(InventoryItem *item);
- virtual void addToInventoryLater(InventoryItem *item);
- void clearAddToInventoryLater();
- void completeAddToInventoryLater(u16 preferred_index);
+ virtual Inventory* getInventory();
+ virtual const Inventory* getInventory() const;
+ virtual InventoryLocation getInventoryLocation() const;
+ virtual void setInventoryModified();
+ virtual std::string getWieldList() const;
+ virtual int getWieldIndex() const;
+ virtual void setWieldIndex(int i);
+
virtual void setHP(s16 hp_);
virtual s16 getHP();
v3f m_last_good_position;
float m_last_good_position_age;
- std::vector<InventoryItem*> m_additional_items;
+ int m_wield_index;
bool m_inventory_not_sent;
bool m_hp_not_sent;
bool m_respawn_active;
diff --git a/src/test.cpp b/src/test.cpp
index f778f2d91..caf31d1af 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -47,6 +47,75 @@ with this program; if not, write to the Free Software Foundation, Inc.,
assert(exception_thrown);\
}
+/*
+ A few item and node definitions for those tests that need them
+*/
+
+#define CONTENT_STONE 0
+#define CONTENT_GRASS 0x800
+
+void define_some_nodes(IWritableItemDefManager *idef, IWritableNodeDefManager *ndef)
+{
+ content_t i;
+ ItemDefinition itemdef;
+ ContentFeatures f;
+
+ /*
+ Stone
+ */
+ i = CONTENT_STONE;
+ itemdef = ItemDefinition();
+ itemdef.type = ITEM_NODE;
+ itemdef.name = "default:stone";
+ itemdef.description = "Stone";
+ itemdef.inventory_image = "[inventorycube"
+ "{default_stone.png"
+ "{default_stone.png"
+ "{default_stone.png";
+ f = ContentFeatures();
+ f.name = itemdef.name;
+ for(int i = 0; i < 6; i++)
+ f.tname_tiles[i] = "default_stone.png";
+ f.param_type = CPT_MINERAL;
+ f.is_ground_content = true;
+ f.dug_item = itemdef.name;
+ f.material.diggability = DIGGABLE_NORMAL;
+ f.material.weight = 5.0;
+ f.material.crackiness = 1.0;
+ f.material.crumbliness = -0.1;
+ f.material.cuttability = -0.2;
+ idef->registerItem(itemdef);
+ ndef->set(i, f);
+
+ /*
+ Grass
+ */
+ i = CONTENT_GRASS;
+ itemdef = ItemDefinition();
+ itemdef.type = ITEM_NODE;
+ itemdef.name = "default:dirt_with_grass";
+ itemdef.description = "Dirt with grass";
+ itemdef.inventory_image = "[inventorycube"
+ "{default_grass.png"
+ "{default_dirt.png&default_grass_side.png"
+ "{default_dirt.png&default_grass_side.png";
+ f = ContentFeatures();
+ f.name = itemdef.name;
+ f.tname_tiles[0] = "default_grass.png";
+ f.tname_tiles[1] = "default_dirt.png";
+ for(int i = 2; i < 6; i++)
+ f.tname_tiles[i] = "default_dirt.png^default_grass_side.png";
+ f.is_ground_content = true;
+ f.dug_item = itemdef.name;
+ f.material.diggability = DIGGABLE_NORMAL;
+ f.material.weight = 1.2;
+ f.material.crackiness = 0.0;
+ f.material.crumbliness = 1.2;
+ f.material.cuttability = -0.4;
+ idef->registerItem(itemdef);
+ ndef->set(i, f);
+}
+
struct TestUtilities
{
void Run()
@@ -96,7 +165,118 @@ struct TestSettings
assert(fabs(s.getV3F("coord2").Z - 3.3) < 0.001);
}
};
+
+struct TestSerialization
+{
+ // To be used like this:
+ // mkstr("Some\0string\0with\0embedded\0nuls")
+ // since std::string("...") doesn't work as expected in that case.
+ template<size_t N> std::string mkstr(const char (&s)[N])
+ {
+ return std::string(s, N - 1);
+ }
+
+ void Run()
+ {
+ // Tests some serialization primitives
+
+ assert(serializeString("") == mkstr("\0\0"));
+ assert(serializeWideString(L"") == mkstr("\0\0"));
+ assert(serializeLongString("") == mkstr("\0\0\0\0"));
+ assert(serializeJsonString("") == "\"\"");
+ std::string teststring = "Hello world!";
+ assert(serializeString(teststring) ==
+ mkstr("\0\14Hello world!"));
+ assert(serializeWideString(narrow_to_wide(teststring)) ==
+ mkstr("\0\14\0H\0e\0l\0l\0o\0 \0w\0o\0r\0l\0d\0!"));
+ assert(serializeLongString(teststring) ==
+ mkstr("\0\0\0\14Hello world!"));
+ assert(serializeJsonString(teststring) ==
+ "\"Hello world!\"");
+
+ std::string teststring2;
+ std::wstring teststring2_w;
+ std::string teststring2_w_encoded;
+ {
+ std::ostringstream tmp_os;
+ std::wostringstream tmp_os_w;
+ std::ostringstream tmp_os_w_encoded;
+ for(int i = 0; i < 256; i++)
+ {
+ tmp_os<<(char)i;
+ tmp_os_w<<(wchar_t)i;
+ tmp_os_w_encoded<<(char)0<<(char)i;
+ }
+ teststring2 = tmp_os.str();
+ teststring2_w = tmp_os_w.str();
+ teststring2_w_encoded = tmp_os_w_encoded.str();
+ }
+ assert(serializeString(teststring2) ==
+ mkstr("\1\0") + teststring2);
+ assert(serializeWideString(teststring2_w) ==
+ mkstr("\1\0") + teststring2_w_encoded);
+ assert(serializeLongString(teststring2) ==
+ mkstr("\0\0\1\0") + teststring2);
+ assert(serializeJsonString(teststring2) ==
+ mkstr("\"") +
+ "\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007" +
+ "\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f" +
+ "\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" +
+ "\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f" +
+ " !\\\"" + teststring2.substr(0x23, 0x2f-0x23) +
+ "\\/" + teststring2.substr(0x30, 0x5c-0x30) +
+ "\\\\" + teststring2.substr(0x5d, 0x7f-0x5d) + "\\u007f" +
+ "\\u0080\\u0081\\u0082\\u0083\\u0084\\u0085\\u0086\\u0087" +
+ "\\u0088\\u0089\\u008a\\u008b\\u008c\\u008d\\u008e\\u008f" +
+ "\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" +
+ "\\u0098\\u0099\\u009a\\u009b\\u009c\\u009d\\u009e\\u009f" +
+ "\\u00a0\\u00a1\\u00a2\\u00a3\\u00a4\\u00a5\\u00a6\\u00a7" +
+ "\\u00a8\\u00a9\\u00aa\\u00ab\\u00ac\\u00ad\\u00ae\\u00af" +
+ "\\u00b0\\u00b1\\u00b2\\u00b3\\u00b4\\u00b5\\u00b6\\u00b7" +
+ "\\u00b8\\u00b9\\u00ba\\u00bb\\u00bc\\u00bd\\u00be\\u00bf" +
+ "\\u00c0\\u00c1\\u00c2\\u00c3\\u00c4\\u00c5\\u00c6\\u00c7" +
+ "\\u00c8\\u00c9\\u00ca\\u00cb\\u00cc\\u00cd\\u00ce\\u00cf" +
+ "\\u00d0\\u00d1\\u00d2\\u00d3\\u00d4\\u00d5\\u00d6\\u00d7" +
+ "\\u00d8\\u00d9\\u00da\\u00db\\u00dc\\u00dd\\u00de\\u00df" +
+ "\\u00e0\\u00e1\\u00e2\\u00e3\\u00e4\\u00e5\\u00e6\\u00e7" +
+ "\\u00e8\\u00e9\\u00ea\\u00eb\\u00ec\\u00ed\\u00ee\\u00ef" +
+ "\\u00f0\\u00f1\\u00f2\\u00f3\\u00f4\\u00f5\\u00f6\\u00f7" +
+ "\\u00f8\\u00f9\\u00fa\\u00fb\\u00fc\\u00fd\\u00fe\\u00ff" +
+ "\"");
+
+ {
+ std::istringstream is(serializeString(teststring2), std::ios::binary);
+ assert(deSerializeString(is) == teststring2);
+ assert(!is.eof());
+ is.get();
+ assert(is.eof());
+ }
+ {
+ std::istringstream is(serializeWideString(teststring2_w), std::ios::binary);
+ assert(deSerializeWideString(is) == teststring2_w);
+ assert(!is.eof());
+ is.get();
+ assert(is.eof());
+ }
+ {
+ std::istringstream is(serializeLongString(teststring2), std::ios::binary);
+ assert(deSerializeLongString(is) == teststring2);
+ assert(!is.eof());
+ is.get();
+ assert(is.eof());
+ }
+ {
+ std::istringstream is(serializeJsonString(teststring2), std::ios::binary);
+ //dstream<<serializeJsonString(deSerializeJsonString(is));
+ assert(deSerializeJsonString(is) == teststring2);
+ assert(!is.eof());
+ is.get();
+ assert(is.eof());
+ }
+ }
+};
+
struct TestCompress
{
void Run()
@@ -283,11 +463,11 @@ struct TestVoxelManipulator
infostream<<"*** Setting (-1,0,-1)=2 ***"<<std::endl;
- v.setNodeNoRef(v3s16(-1,0,-1), MapNode(2));
+ v.setNodeNoRef(v3s16(-1,0,-1), MapNode(CONTENT_GRASS));
v.print(infostream, nodedef);
- assert(v.getNode(v3s16(-1,0,-1)).getContent() == 2);
+ assert(v.getNode(v3s16(-1,0,-1)).getContent() == CONTENT_GRASS);
infostream<<"*** Reading from inexistent (0,0,-1) ***"<<std::endl;
@@ -301,7 +481,7 @@ struct TestVoxelManipulator
v.print(infostream, nodedef);
- assert(v.getNode(v3s16(-1,0,-1)).getContent() == 2);
+ assert(v.getNode(v3s16(-1,0,-1)).getContent() == CONTENT_GRASS);
EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,1,1)));
}
};
@@ -1086,16 +1266,18 @@ void run_tests()
{
DSTACK(__FUNCTION_NAME);
- // Create node definitions
- IWritableNodeDefManager *nodedef = createNodeDefManager();
- content_mapnode_init(nodedef);
+ // Create item and node definitions
+ IWritableItemDefManager *idef = createItemDefManager();
+ IWritableNodeDefManager *ndef = createNodeDefManager();
+ define_some_nodes(idef, ndef);
infostream<<"run_tests() started"<<std::endl;
TEST(TestUtilities);
TEST(TestSettings);
TEST(TestCompress);
- TESTPARAMS(TestMapNode, nodedef);
- TESTPARAMS(TestVoxelManipulator, nodedef);
+ TEST(TestSerialization);
+ TESTPARAMS(TestMapNode, ndef);
+ TESTPARAMS(TestVoxelManipulator, ndef);
//TEST(TestMapBlock);
//TEST(TestMapSector);
if(INTERNET_SIMULATOR == false){
diff --git a/src/tile.cpp b/src/tile.cpp
index 89f345197..1d5f4d833 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -337,6 +337,12 @@ public:
return ap.atlas;
}
+ // Returns a pointer to the irrlicht device
+ virtual IrrlichtDevice* getDevice()
+ {
+ return m_device;
+ }
+
// Update new texture pointer and texture coordinates to an
// AtlasPointer based on it's texture id
void updateAP(AtlasPointer &ap);
@@ -469,8 +475,6 @@ u32 TextureSource::getTextureId(const std::string &name)
return 0;
}
-// Draw a progress bar on the image
-void make_progressbar(float value, video::IImage *image);
// Brighten image
void brighten(video::IImage *image);
@@ -816,14 +820,12 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
if(j == CONTENT_IGNORE || j == CONTENT_AIR)
continue;
const ContentFeatures &f = ndef->get(j);
- for(std::set<std::string>::const_iterator
- i = f.used_texturenames.begin();
- i != f.used_texturenames.end(); i++)
+ for(u32 i=0; i<6; i++)
{
- std::string name = *i;
+ std::string name = f.tname_tiles[i];
sourcelist[name] = true;
- if(f.often_contains_mineral){
+ if(f.param_type == CPT_MINERAL){
for(int k=1; k<MINERAL_COUNT; k++){
std::string mineraltexture = mineral_block_texture(k);
std::string fulltexture = name + "^" + mineraltexture;
@@ -1317,23 +1319,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
}
}
/*
- [progressbarN
- Adds a progress bar, 0.0 <= N <= 1.0
- */
- else if(part_of_name.substr(0,12) == "[progressbar")
- {
- if(baseimg == NULL)
- {
- errorstream<<"generate_image(): baseimg==NULL "
- <<"for part_of_name=\""<<part_of_name
- <<"\", cancelling."<<std::endl;
- return false;
- }
-
- float value = stof(part_of_name.substr(12));
- make_progressbar(value, baseimg);
- }
- /*
"[brighten"
*/
else if(part_of_name.substr(0,9) == "[brighten")
@@ -1442,23 +1427,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
std::string imagename_left = sf.next("{");
std::string imagename_right = sf.next("{");
-#if 1
- // TODO: Create cube with different textures on different sides
-
- if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
- {
- errorstream<<"generate_image(): EVDF_RENDER_TO_TARGET"
- " not supported. Creating fallback image"<<std::endl;
- baseimg = generate_image_from_scratch(
- imagename_top, device, sourcecache);
- return true;
- }
-
- u32 w0 = 64;
- u32 h0 = 64;
- //infostream<<"inventorycube w="<<w0<<" h="<<h0<<std::endl;
- core::dimension2d<u32> dim(w0,h0);
-
// Generate images for the faces of the cube
video::IImage *img_top = generate_image_from_scratch(
imagename_top, device, sourcecache);
@@ -1482,84 +1450,65 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
img_left->drop();
img_right->drop();
- // Create render target texture
- video::ITexture *rtt = NULL;
- std::string rtt_name = part_of_name + "_RTT";
- rtt = driver->addRenderTargetTexture(dim, rtt_name.c_str(),
- video::ECF_A8R8G8B8);
- assert(rtt);
-
- // Set render target
- driver->setRenderTarget(rtt, true, true,
- video::SColor(0,0,0,0));
-
- // Get a scene manager
- scene::ISceneManager *smgr_main = device->getSceneManager();
- assert(smgr_main);
- scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
- assert(smgr);
-
/*
- Create scene:
- - An unit cube is centered at 0,0,0
- - Camera looks at cube from Y+, Z- towards Y-, Z+
+ Draw a cube mesh into a render target texture
*/
-
scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1));
setMeshColor(cube, video::SColor(255, 255, 255, 255));
-
- scene::IMeshSceneNode* cubenode = smgr->addMeshSceneNode(cube, NULL, -1, v3f(0,0,0), v3f(0,45,0), v3f(1,1,1), true);
- cube->drop();
-
- // Set texture of cube
- cubenode->getMaterial(0).setTexture(0, texture_top);
- cubenode->getMaterial(1).setTexture(0, texture_top);
- cubenode->getMaterial(2).setTexture(0, texture_right);
- cubenode->getMaterial(3).setTexture(0, texture_right);
- cubenode->getMaterial(4).setTexture(0, texture_left);
- cubenode->getMaterial(5).setTexture(0, texture_left);
- cubenode->setMaterialFlag(video::EMF_LIGHTING, true);
- cubenode->setMaterialFlag(video::EMF_ANTI_ALIASING, true);
- cubenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, true);
-
- scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
- v3f(0, 1.0, -1.5), v3f(0, 0, 0));
+ cube->getMeshBuffer(0)->getMaterial().setTexture(0, texture_top);
+ cube->getMeshBuffer(1)->getMaterial().setTexture(0, texture_top);
+ cube->getMeshBuffer(2)->getMaterial().setTexture(0, texture_right);
+ cube->getMeshBuffer(3)->getMaterial().setTexture(0, texture_right);
+ cube->getMeshBuffer(4)->getMaterial().setTexture(0, texture_left);
+ cube->getMeshBuffer(5)->getMaterial().setTexture(0, texture_left);
+
+ core::dimension2d<u32> dim(64,64);
+ std::string rtt_texture_name = part_of_name + "_RTT";
+
+ v3f camera_position(0, 1.0, -1.5);
+ camera_position.rotateXZBy(45);
+ v3f camera_lookat(0, 0, 0);
+ core::CMatrix4<f32> camera_projection_matrix;
// Set orthogonal projection
- core::CMatrix4<f32> pm;
- pm.buildProjectionMatrixOrthoLH(1.65, 1.65, 0, 100);
- camera->setProjectionMatrix(pm, true);
-
- /*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0,
- v3f(-50, 100, -75), video::SColorf(0.5,0.5,0.5), 1000);
-
- smgr->setAmbientLight(video::SColorf(0.2,0.2,0.2));
-
- // Render scene
- driver->beginScene(true, true, video::SColor(0,0,0,0));
- smgr->drawAll();
- driver->endScene();
+ camera_projection_matrix.buildProjectionMatrixOrthoLH(
+ 1.65, 1.65, 0, 100);
+
+ video::SColorf ambient_light(0.2,0.2,0.2);
+ v3f light_position(10, 100, -50);
+ video::SColorf light_color(0.5,0.5,0.5);
+ f32 light_radius = 1000;
+
+ video::ITexture *rtt = generateTextureFromMesh(
+ cube, device, dim, rtt_texture_name,
+ camera_position,
+ camera_lookat,
+ camera_projection_matrix,
+ ambient_light,
+ light_position,
+ light_color,
+ light_radius);
- // NOTE: The scene nodes should not be dropped, otherwise
- // smgr->drop() segfaults
- /*cube->drop();
- camera->drop();
- light->drop();*/
- // Drop scene manager
- smgr->drop();
-
- // Unset render target
- driver->setRenderTarget(0, true, true, 0);
+ // Drop mesh
+ cube->drop();
// Free textures of images
driver->removeTexture(texture_top);
driver->removeTexture(texture_left);
driver->removeTexture(texture_right);
+ if(rtt == NULL)
+ {
+ errorstream<<"generate_image(): render to texture failed."
+ " Creating fallback image"<<std::endl;
+ baseimg = generate_image_from_scratch(
+ imagename_top, device, sourcecache);
+ return true;
+ }
+
// Create image of render target
video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
-
assert(image);
-
+
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
if(image)
@@ -1567,7 +1516,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
image->copyTo(baseimg);
image->drop();
}
-#endif
}
else
{
@@ -1579,38 +1527,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
return true;
}
-void make_progressbar(float value, video::IImage *image)
-{
- if(image == NULL)
- return;
-
- core::dimension2d<u32> size = image->getDimension();
-
- u32 barheight = size.Height/16;
- u32 barpad_x = size.Width/16;
- u32 barpad_y = size.Height/16;
- u32 barwidth = size.Width - barpad_x*2;
- v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
-
- u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
-
- video::SColor active(255,255,0,0);
- video::SColor inactive(255,0,0,0);
- for(u32 x0=0; x0<barwidth; x0++)
- {
- video::SColor *c;
- if(x0 < barvalue_i)
- c = &active;
- else
- c = &inactive;
- u32 x = x0 + barpos.X;
- for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
- {
- image->setPixel(x,y, *c);
- }
- }
-}
-
void brighten(video::IImage *image)
{
if(image == NULL)
diff --git a/src/tile.h b/src/tile.h
index 23849ca1f..c0d8914b0 100644
--- a/src/tile.h
+++ b/src/tile.h
@@ -110,6 +110,8 @@ public:
{return AtlasPointer(0);}
virtual video::ITexture* getTextureRaw(const std::string &name)
{return NULL;}
+ virtual IrrlichtDevice* getDevice()
+ {return NULL;}
virtual void updateAP(AtlasPointer &ap){};
};
@@ -126,6 +128,8 @@ public:
{return AtlasPointer(0);}
virtual video::ITexture* getTextureRaw(const std::string &name)
{return NULL;}
+ virtual IrrlichtDevice* getDevice()
+ {return NULL;}
virtual void updateAP(AtlasPointer &ap){};
virtual void processQueue()=0;
diff --git a/src/tooldef.cpp b/src/tooldef.cpp
deleted file mode 100644
index 7d7eceab0..000000000
--- a/src/tooldef.cpp
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
-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 "tooldef.h"
-#include "irrlichttypes.h"
-#include "log.h"
-#include <sstream>
-#include "utility.h"
-#include <map>
-
-ToolDiggingProperties::ToolDiggingProperties(float full_punch_interval_,
- float a, float b, float c, float d, float e,
- float f, float g, float h, float i, float j):
- full_punch_interval(full_punch_interval_),
- basetime(a),
- dt_weight(b),
- dt_crackiness(c),
- dt_crumbliness(d),
- dt_cuttability(e),
- basedurability(f),
- dd_weight(g),
- dd_crackiness(h),
- dd_crumbliness(i),
- dd_cuttability(j)
-{}
-
-std::string ToolDefinition::dump()
-{
- std::ostringstream os(std::ios::binary);
- os<<"[ToolDefinition::dump() not implemented due to lazyness]"
- <<std::endl;
- return os.str();
-}
-
-void ToolDefinition::serialize(std::ostream &os)
-{
- writeU8(os, 0); // version
- os<<serializeString(imagename);
- writeF1000(os, properties.basetime);
- writeF1000(os, properties.dt_weight);
- writeF1000(os, properties.dt_crackiness);
- writeF1000(os, properties.dt_crumbliness);
- writeF1000(os, properties.dt_cuttability);
- writeF1000(os, properties.basedurability);
- writeF1000(os, properties.dd_weight);
- writeF1000(os, properties.dd_crackiness);
- writeF1000(os, properties.dd_crumbliness);
- writeF1000(os, properties.dd_cuttability);
- writeF1000(os, properties.full_punch_interval);
-}
-
-void ToolDefinition::deSerialize(std::istream &is)
-{
- int version = readU8(is);
- if(version != 0) throw SerializationError(
- "unsupported ToolDefinition version");
- imagename = deSerializeString(is);
- properties.basetime = readF1000(is);
- properties.dt_weight = readF1000(is);
- properties.dt_crackiness = readF1000(is);
- properties.dt_crumbliness = readF1000(is);
- properties.dt_cuttability = readF1000(is);
- properties.basedurability = readF1000(is);
- properties.dd_weight = readF1000(is);
- properties.dd_crackiness = readF1000(is);
- properties.dd_crumbliness = readF1000(is);
- properties.dd_cuttability = readF1000(is);
- try{
- properties.full_punch_interval = readF1000(is);
- }catch(SerializationError &e){} // Temporary for 0.4.dev
-}
-
-class CToolDefManager: public IWritableToolDefManager
-{
-public:
- virtual ~CToolDefManager()
- {
- clear();
- }
- virtual const ToolDefinition* getToolDefinition(const std::string &toolname_) const
- {
- // Convert name according to possible alias
- std::string toolname = getAlias(toolname_);
- // Get the definition
- core::map<std::string, ToolDefinition*>::Node *n;
- n = m_tool_definitions.find(toolname);
- if(n == NULL)
- return NULL;
- return n->getValue();
- }
- virtual std::string getImagename(const std::string &toolname) const
- {
- const ToolDefinition *def = getToolDefinition(toolname);
- if(def == NULL)
- return "";
- return def->imagename;
- }
- virtual ToolDiggingProperties getDiggingProperties(
- const std::string &toolname) const
- {
- const ToolDefinition *def = getToolDefinition(toolname);
- // If tool does not exist, just return an impossible
- if(def == NULL){
- // If tool does not exist, try empty name
- const ToolDefinition *def = getToolDefinition("");
- if(def == NULL) // If that doesn't exist either, return default
- return ToolDiggingProperties();
- return def->properties;
- }
- return def->properties;
- }
- virtual std::string getAlias(const std::string &name) const
- {
- std::map<std::string, std::string>::const_iterator i;
- i = m_aliases.find(name);
- if(i != m_aliases.end())
- return i->second;
- return name;
- }
- // IWritableToolDefManager
- virtual bool registerTool(std::string toolname, const ToolDefinition &def)
- {
- infostream<<"registerTool: registering tool \""<<toolname<<"\""<<std::endl;
- m_tool_definitions[toolname] = new ToolDefinition(def);
-
- // Remove conflicting alias if it exists
- bool alias_removed = (m_aliases.erase(toolname) != 0);
- if(alias_removed)
- infostream<<"tdef: erased alias "<<toolname
- <<" because tool was defined"<<std::endl;
-
- return true;
- }
- virtual void clear()
- {
- for(core::map<std::string, ToolDefinition*>::Iterator
- i = m_tool_definitions.getIterator();
- i.atEnd() == false; i++){
- delete i.getNode()->getValue();
- }
- m_tool_definitions.clear();
- m_aliases.clear();
- }
- virtual void setAlias(const std::string &name,
- const std::string &convert_to)
- {
- if(getToolDefinition(name) != NULL){
- infostream<<"tdef: not setting alias "<<name<<" -> "<<convert_to
- <<": "<<name<<" is already defined"<<std::endl;
- return;
- }
- infostream<<"tdef: setting alias "<<name<<" -> "<<convert_to
- <<std::endl;
- m_aliases[name] = convert_to;
- }
- virtual void serialize(std::ostream &os)
- {
- writeU8(os, 0); // version
- u16 count = m_tool_definitions.size();
- writeU16(os, count);
- for(core::map<std::string, ToolDefinition*>::Iterator
- i = m_tool_definitions.getIterator();
- i.atEnd() == false; i++){
- std::string name = i.getNode()->getKey();
- ToolDefinition *def = i.getNode()->getValue();
- // Serialize name
- os<<serializeString(name);
- // Serialize ToolDefinition and write wrapped in a string
- std::ostringstream tmp_os(std::ios::binary);
- def->serialize(tmp_os);
- os<<serializeString(tmp_os.str());
- }
-
- writeU16(os, m_aliases.size());
- for(std::map<std::string, std::string>::const_iterator
- i = m_aliases.begin(); i != m_aliases.end(); i++)
- {
- os<<serializeString(i->first);
- os<<serializeString(i->second);
- }
- }
- virtual void deSerialize(std::istream &is)
- {
- // Clear everything
- clear();
- // Deserialize
- int version = readU8(is);
- if(version != 0) throw SerializationError(
- "unsupported ToolDefManager version");
- u16 count = readU16(is);
- for(u16 i=0; i<count; i++){
- // Deserialize name
- std::string name = deSerializeString(is);
- // Deserialize a string and grab a ToolDefinition from it
- std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
- ToolDefinition def;
- def.deSerialize(tmp_is);
- // Register
- registerTool(name, def);
- }
-
- u16 num_aliases = readU16(is);
- if(!is.eof()){
- for(u16 i=0; i<num_aliases; i++){
- std::string name = deSerializeString(is);
- std::string convert_to = deSerializeString(is);
- m_aliases[name] = convert_to;
- }
- }
- }
-private:
- // Key is name
- core::map<std::string, ToolDefinition*> m_tool_definitions;
- // Aliases
- std::map<std::string, std::string> m_aliases;
-};
-
-IWritableToolDefManager* createToolDefManager()
-{
- return new CToolDefManager();
-}
-
diff --git a/src/tooldef.h b/src/tooldef.h
deleted file mode 100644
index 68a894898..000000000
--- a/src/tooldef.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-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 TOOLDEF_HEADER
-#define TOOLDEF_HEADER
-
-#include <string>
-#include <iostream>
-
-struct ToolDiggingProperties
-{
- // time = basetime + sum(feature here * feature in MaterialProperties)
- float full_punch_interval;
- float basetime;
- float dt_weight;
- float dt_crackiness;
- float dt_crumbliness;
- float dt_cuttability;
- float basedurability;
- float dd_weight;
- float dd_crackiness;
- float dd_crumbliness;
- float dd_cuttability;
-
- ToolDiggingProperties(float full_punch_interval_=2.0,
- float a=0.75, float b=0, float c=0, float d=0, float e=0,
- float f=50, float g=0, float h=0, float i=0, float j=0);
-};
-
-struct ToolDefinition
-{
- std::string imagename;
- ToolDiggingProperties properties;
-
- ToolDefinition(){}
- ToolDefinition(const std::string &imagename_,
- ToolDiggingProperties properties_):
- imagename(imagename_),
- properties(properties_)
- {}
-
- std::string dump();
- void serialize(std::ostream &os);
- void deSerialize(std::istream &is);
-};
-
-class IToolDefManager
-{
-public:
- IToolDefManager(){}
- virtual ~IToolDefManager(){}
- virtual const ToolDefinition* getToolDefinition(const std::string &toolname) const=0;
- virtual std::string getImagename(const std::string &toolname) const =0;
- virtual ToolDiggingProperties getDiggingProperties(
- const std::string &toolname) const =0;
- virtual std::string getAlias(const std::string &name) const =0;
-
- virtual void serialize(std::ostream &os)=0;
-};
-
-class IWritableToolDefManager : public IToolDefManager
-{
-public:
- IWritableToolDefManager(){}
- virtual ~IWritableToolDefManager(){}
- virtual const ToolDefinition* getToolDefinition(const std::string &toolname) const=0;
- virtual std::string getImagename(const std::string &toolname) const =0;
- virtual ToolDiggingProperties getDiggingProperties(
- const std::string &toolname) const =0;
- virtual std::string getAlias(const std::string &name) const =0;
-
- virtual bool registerTool(std::string toolname, const ToolDefinition &def)=0;
- virtual void clear()=0;
- // Set an alias so that entries named <name> will load as <convert_to>.
- // Alias is not set if <name> has already been defined.
- // Alias will be removed if <name> is defined at a later point of time.
- virtual void setAlias(const std::string &name,
- const std::string &convert_to)=0;
-
- virtual void serialize(std::ostream &os)=0;
- virtual void deSerialize(std::istream &is)=0;
-};
-
-IWritableToolDefManager* createToolDefManager();
-
-#endif
-
diff --git a/src/utility.cpp b/src/utility.cpp
index 4e9f307d8..06b60884f 100644
--- a/src/utility.cpp
+++ b/src/utility.cpp
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sha1.h"
#include "base64.h"
#include "log.h"
+#include <iomanip>
TimeTaker::TimeTaker(const char *name, u32 *result)
{
@@ -234,6 +235,100 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
return true;
}
+// Creates a string encoded in JSON format (almost equivalent to a C string literal)
+std::string serializeJsonString(const std::string &plain)
+{
+ std::ostringstream os(std::ios::binary);
+ os<<"\"";
+ for(size_t i = 0; i < plain.size(); i++)
+ {
+ char c = plain[i];
+ switch(c)
+ {
+ case '"': os<<"\\\""; break;
+ case '\\': os<<"\\\\"; break;
+ case '/': os<<"\\/"; break;
+ case '\b': os<<"\\b"; break;
+ case '\f': os<<"\\f"; break;
+ case '\n': os<<"\\n"; break;
+ case '\r': os<<"\\r"; break;
+ case '\t': os<<"\\t"; break;
+ default:
+ {
+ if(c >= 32 && c <= 126)
+ {
+ os<<c;
+ }
+ else
+ {
+ u32 cnum = (u32) (u8) c;
+ os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
+ }
+ break;
+ }
+ }
+ }
+ os<<"\"";
+ return os.str();
+}
+
+// Reads a string encoded in JSON format
+std::string deSerializeJsonString(std::istream &is)
+{
+ std::ostringstream os(std::ios::binary);
+ char c, c2;
+
+ // Parse initial doublequote
+ is >> c;
+ if(c != '"')
+ throw SerializationError("JSON string must start with doublequote");
+
+ // Parse characters
+ for(;;)
+ {
+ c = is.get();
+ if(is.eof())
+ throw SerializationError("JSON string ended prematurely");
+ if(c == '"')
+ {
+ return os.str();
+ }
+ else if(c == '\\')
+ {
+ c2 = is.get();
+ if(is.eof())
+ throw SerializationError("JSON string ended prematurely");
+ switch(c2)
+ {
+ default: os<<c2; break;
+ case 'b': os<<'\b'; break;
+ case 'f': os<<'\f'; break;
+ case 'n': os<<'\n'; break;
+ case 'r': os<<'\r'; break;
+ case 't': os<<'\t'; break;
+ case 'u':
+ {
+ char hexdigits[4+1];
+ is.read(hexdigits, 4);
+ if(is.eof())
+ throw SerializationError("JSON string ended prematurely");
+ hexdigits[4] = 0;
+ std::istringstream tmp_is(hexdigits, std::ios::binary);
+ int hexnumber;
+ tmp_is >> std::hex >> hexnumber;
+ os<<((char)hexnumber);
+ break;
+ }
+ }
+ }
+ else
+ {
+ os<<c;
+ }
+ }
+ return os.str();
+}
+
// Get an sha-1 hash of the player's name combined with
// the password entered. That's what the server uses as
// their password. (Exception : if the password field is
diff --git a/src/utility.h b/src/utility.h
index 14b49772b..50f27c11b 100644
--- a/src/utility.h
+++ b/src/utility.h
@@ -1694,6 +1694,12 @@ inline std::string deSerializeLongString(std::istream &is)
return s;
}
+// Creates a string encoded in JSON format (almost equivalent to a C string literal)
+std::string serializeJsonString(const std::string &plain);
+
+// Reads a string encoded in JSON format
+std::string deSerializeJsonString(std::istream &is);
+
//
inline u32 time_to_daynight_ratio(u32 time_of_day)