diff options
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/common_irrlicht.h | 29 | ||||
-rw-r--r-- | src/content_cao.cpp | 149 | ||||
-rw-r--r-- | src/content_cao.h | 40 | ||||
-rw-r--r-- | src/content_inventory.cpp | 6 | ||||
-rw-r--r-- | src/content_inventory.h | 2 | ||||
-rw-r--r-- | src/content_object.h | 2 | ||||
-rw-r--r-- | src/content_sao.cpp | 154 | ||||
-rw-r--r-- | src/content_sao.h | 46 | ||||
-rw-r--r-- | src/environment.cpp | 39 | ||||
-rw-r--r-- | src/environment.h | 17 | ||||
-rw-r--r-- | src/inventory.cpp | 4 | ||||
-rw-r--r-- | src/irrlichttypes.h | 52 | ||||
-rw-r--r-- | src/porting.cpp | 10 | ||||
-rw-r--r-- | src/script.cpp | 130 | ||||
-rw-r--r-- | src/script.h | 33 | ||||
-rw-r--r-- | src/scriptapi.cpp | 422 | ||||
-rw-r--r-- | src/scriptapi.h | 43 | ||||
-rw-r--r-- | src/server.cpp | 187 | ||||
-rw-r--r-- | src/server.h | 15 | ||||
-rw-r--r-- | src/serverobject.cpp | 11 | ||||
-rw-r--r-- | src/serverobject.h | 6 |
22 files changed, 1212 insertions, 187 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f75c182bd..b41fc4a6c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -94,6 +94,8 @@ configure_file( ) set(common_SRCS + scriptapi.cpp + script.cpp log.cpp content_sao.cpp mapgen.cpp diff --git a/src/common_irrlicht.h b/src/common_irrlicht.h index f4c2f76ec..379c2d15a 100644 --- a/src/common_irrlicht.h +++ b/src/common_irrlicht.h @@ -23,13 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #define endSceneX(d){d->draw2DLine(v2s32(0,0),v2s32(1,0),\ video::SColor(255,30,30,30));d->endScene();} -#include <irrTypes.h> -#include <vector2d.h> -#include <vector3d.h> -#include <irrMap.h> -#include <irrList.h> -#include <irrArray.h> -#include <aabbox3d.h> +#include "irrlichttypes.h" + #ifndef SERVER #include <SColor.h> #include <IMesh.h> @@ -43,26 +38,6 @@ video::SColor(255,30,30,30));d->endScene();} #include <IGUIElement.h> #include <IGUIEnvironment.h> #endif -using namespace irr; -typedef core::vector3df v3f; -typedef core::vector3d<s16> v3s16; -typedef core::vector3d<s32> v3s32; - -typedef core::vector2d<f32> v2f; -typedef core::vector2d<s16> v2s16; -typedef core::vector2d<s32> v2s32; -typedef core::vector2d<u32> v2u32; -typedef core::vector2d<f32> v2f32; - -#ifdef _MSC_VER - // Windows - typedef unsigned long long u64; -#else - // Posix - #include <stdint.h> - typedef uint64_t u64; - //typedef unsigned long long u64; -#endif #endif diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 6cb2cee38..157a51886 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -1264,3 +1264,152 @@ void MobV2CAO::setLooks(const std::string &looks) selection_size.X); } +/* + LuaEntityCAO +*/ + +// Prototype +LuaEntityCAO proto_LuaEntityCAO; + +LuaEntityCAO::LuaEntityCAO(): + ClientActiveObject(0), + m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.), + m_node(NULL), + m_position(v3f(0,10*BS,0)) +{ + ClientActiveObject::registerType(getType(), create); +} + +LuaEntityCAO::~LuaEntityCAO() +{ +} + +ClientActiveObject* LuaEntityCAO::create() +{ + return new LuaEntityCAO(); +} + +void LuaEntityCAO::addToScene(scene::ISceneManager *smgr) +{ + if(m_node != NULL) + return; + + video::IVideoDriver* driver = smgr->getVideoDriver(); + + scene::SMesh *mesh = new scene::SMesh(); + scene::IMeshBuffer *buf = new scene::SMeshBuffer(); + video::SColor c(255,255,255,255); + video::S3DVertex vertices[4] = + { + /*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1), + video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1), + video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0), + video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/ + video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1), + video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1), + video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0), + video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0), + }; + u16 indices[] = {0,1,2,2,3,0}; + buf->append(vertices, 4, indices, 6); + // Set material + buf->getMaterial().setFlag(video::EMF_LIGHTING, false); + buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false); + //buf->getMaterial().setTexture(0, NULL); + // Initialize with the stick texture + buf->getMaterial().setTexture + (0, driver->getTexture(getTexturePath("mese.png").c_str())); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true); + buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + // Add to mesh + mesh->addMeshBuffer(buf); + 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(); +} + +void LuaEntityCAO::removeFromScene() +{ + if(m_node == NULL) + return; + + m_node->remove(); + m_node = NULL; +} + +void LuaEntityCAO::updateLight(u8 light_at_pos) +{ + if(m_node == NULL) + return; + + u8 li = decode_light(light_at_pos); + video::SColor color(255,li,li,li); + setMeshVerticesColor(m_node->getMesh(), color); +} + +v3s16 LuaEntityCAO::getLightPosition() +{ + return floatToInt(m_position, BS); +} + +void LuaEntityCAO::updateNodePos() +{ + if(m_node == NULL) + return; + + m_node->setPosition(m_position); +} + +void LuaEntityCAO::step(float dtime, ClientEnvironment *env) +{ + if(m_node) + { + /*v3f rot = m_node->getRotation(); + rot.Y += dtime * 120; + m_node->setRotation(rot);*/ + LocalPlayer *player = env->getLocalPlayer(); + assert(player); + v3f rot = m_node->getRotation(); + rot.Y = 180.0 - (player->getYaw()); + m_node->setRotation(rot); + } +} + +void LuaEntityCAO::processMessage(const std::string &data) +{ + infostream<<"LuaEntityCAO: Got message"<<std::endl; + std::istringstream is(data, std::ios::binary); + // command + u8 cmd = readU8(is); + if(cmd == 0) + { + // pos + m_position = readV3F1000(is); + updateNodePos(); + } +} + +void LuaEntityCAO::initialize(const std::string &data) +{ + infostream<<"LuaEntityCAO: Got init data"<<std::endl; + + { + std::istringstream is(data, std::ios::binary); + // version + u8 version = readU8(is); + // check version + if(version != 0) + return; + // pos + m_position = readV3F1000(is); + } + + updateNodePos(); +} + + diff --git a/src/content_cao.h b/src/content_cao.h index 963e1a488..c8554e737 100644 --- a/src/content_cao.h +++ b/src/content_cao.h @@ -376,6 +376,46 @@ private: Settings *m_properties; }; +/* + LuaEntityCAO +*/ + +class LuaEntityCAO : public ClientActiveObject +{ +public: + LuaEntityCAO(); + virtual ~LuaEntityCAO(); + + u8 getType() const + { + return ACTIVEOBJECT_TYPE_LUAENTITY; + } + + static ClientActiveObject* create(); + + void addToScene(scene::ISceneManager *smgr); + void removeFromScene(); + void updateLight(u8 light_at_pos); + v3s16 getLightPosition(); + void updateNodePos(); + + void step(float dtime, ClientEnvironment *env); + + void processMessage(const std::string &data); + + void initialize(const std::string &data); + + core::aabbox3d<f32>* getSelectionBox() + {return &m_selection_box;} + v3f getPosition() + {return m_position;} + +private: + core::aabbox3d<f32> m_selection_box; + scene::IMeshSceneNode *m_node; + v3f m_position; +}; + #endif diff --git a/src/content_inventory.cpp b/src/content_inventory.cpp index 413ae8505..1d5c6b355 100644 --- a/src/content_inventory.cpp +++ b/src/content_inventory.cpp @@ -80,16 +80,16 @@ std::string item_craft_get_image_name(const std::string &subname) } ServerActiveObject* item_craft_create_object(const std::string &subname, - ServerEnvironment *env, u16 id, v3f pos) + ServerEnvironment *env, v3f pos) { if(subname == "rat") { - ServerActiveObject *obj = new RatSAO(env, id, pos); + ServerActiveObject *obj = new RatSAO(env, pos); return obj; } else if(subname == "firefly") { - ServerActiveObject *obj = new FireflySAO(env, id, pos); + ServerActiveObject *obj = new FireflySAO(env, pos); return obj; } diff --git a/src/content_inventory.h b/src/content_inventory.h index 91550bb9a..9fd4cb03b 100644 --- a/src/content_inventory.h +++ b/src/content_inventory.h @@ -33,7 +33,7 @@ InventoryItem* item_material_create_cook_result(content_t content); std::string item_craft_get_image_name(const std::string &subname); ServerActiveObject* item_craft_create_object(const std::string &subname, - ServerEnvironment *env, u16 id, v3f pos); + ServerEnvironment *env, v3f pos); s16 item_craft_get_drop_count(const std::string &subname); bool item_craft_is_cookable(const std::string &subname); InventoryItem* item_craft_create_cook_result(const std::string &subname); diff --git a/src/content_object.h b/src/content_object.h index a5fea7163..f092b2789 100644 --- a/src/content_object.h +++ b/src/content_object.h @@ -27,5 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define ACTIVEOBJECT_TYPE_FIREFLY 5 #define ACTIVEOBJECT_TYPE_MOBV2 6 +#define ACTIVEOBJECT_TYPE_LUAENTITY 7 + #endif diff --git a/src/content_sao.cpp b/src/content_sao.cpp index f22637185..d51e92a8c 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -49,20 +49,20 @@ void accelerate_xz(v3f &speed, v3f target_speed, f32 max_increase) */ // Prototype -TestSAO proto_TestSAO(NULL, 0, v3f(0,0,0)); +TestSAO proto_TestSAO(NULL, v3f(0,0,0)); -TestSAO::TestSAO(ServerEnvironment *env, u16 id, v3f pos): - ServerActiveObject(env, id, pos), +TestSAO::TestSAO(ServerEnvironment *env, v3f pos): + ServerActiveObject(env, pos), m_timer1(0), m_age(0) { ServerActiveObject::registerType(getType(), create); } -ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos, +ServerActiveObject* TestSAO::create(ServerEnvironment *env, v3f pos, const std::string &data) { - return new TestSAO(env, id, pos); + return new TestSAO(env, pos); } void TestSAO::step(float dtime, bool send_recommended) @@ -107,11 +107,11 @@ void TestSAO::step(float dtime, bool send_recommended) */ // Prototype -ItemSAO proto_ItemSAO(NULL, 0, v3f(0,0,0), ""); +ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), ""); -ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos, +ItemSAO::ItemSAO(ServerEnvironment *env, v3f pos, const std::string inventorystring): - ServerActiveObject(env, id, pos), + ServerActiveObject(env, pos), m_inventorystring(inventorystring), m_speed_f(0,0,0), m_last_sent_position(0,0,0) @@ -119,7 +119,7 @@ ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos, ServerActiveObject::registerType(getType(), create); } -ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos, +ServerActiveObject* ItemSAO::create(ServerEnvironment *env, v3f pos, const std::string &data) { std::istringstream is(data, std::ios::binary); @@ -133,7 +133,7 @@ ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos, std::string inventorystring = deSerializeString(is); infostream<<"ItemSAO::create(): Creating item \"" <<inventorystring<<"\""<<std::endl; - return new ItemSAO(env, id, pos, inventorystring); + return new ItemSAO(env, pos, inventorystring); } void ItemSAO::step(float dtime, bool send_recommended) @@ -260,10 +260,10 @@ void ItemSAO::rightClick(Player *player) */ // Prototype -RatSAO proto_RatSAO(NULL, 0, v3f(0,0,0)); +RatSAO proto_RatSAO(NULL, v3f(0,0,0)); -RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos): - ServerActiveObject(env, id, pos), +RatSAO::RatSAO(ServerEnvironment *env, v3f pos): + ServerActiveObject(env, pos), m_is_active(false), m_speed_f(0,0,0) { @@ -278,7 +278,7 @@ RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos): m_touching_ground = false; } -ServerActiveObject* RatSAO::create(ServerEnvironment *env, u16 id, v3f pos, +ServerActiveObject* RatSAO::create(ServerEnvironment *env, v3f pos, const std::string &data) { std::istringstream is(data, std::ios::binary); @@ -289,7 +289,7 @@ ServerActiveObject* RatSAO::create(ServerEnvironment *env, u16 id, v3f pos, // check if version is supported if(version != 0) return NULL; - return new RatSAO(env, id, pos); + return new RatSAO(env, pos); } void RatSAO::step(float dtime, bool send_recommended) @@ -447,10 +447,10 @@ InventoryItem* RatSAO::createPickedUpItem() */ // Prototype -Oerkki1SAO proto_Oerkki1SAO(NULL, 0, v3f(0,0,0)); +Oerkki1SAO proto_Oerkki1SAO(NULL, v3f(0,0,0)); -Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos): - ServerActiveObject(env, id, pos), +Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, v3f pos): + ServerActiveObject(env, pos), m_is_active(false), m_speed_f(0,0,0) { @@ -467,7 +467,7 @@ Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos): m_after_jump_timer = 0; } -ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, v3f pos, +ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, v3f pos, const std::string &data) { std::istringstream is(data, std::ios::binary); @@ -478,7 +478,7 @@ ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, v3f pos, // check if version is supported if(version != 0) return NULL; - Oerkki1SAO *o = new Oerkki1SAO(env, id, pos); + Oerkki1SAO *o = new Oerkki1SAO(env, pos); o->m_hp = hp; return o; } @@ -739,10 +739,10 @@ void Oerkki1SAO::doDamage(u16 d) */ // Prototype -FireflySAO proto_FireflySAO(NULL, 0, v3f(0,0,0)); +FireflySAO proto_FireflySAO(NULL, v3f(0,0,0)); -FireflySAO::FireflySAO(ServerEnvironment *env, u16 id, v3f pos): - ServerActiveObject(env, id, pos), +FireflySAO::FireflySAO(ServerEnvironment *env, v3f pos): + ServerActiveObject(env, pos), m_is_active(false), m_speed_f(0,0,0) { @@ -757,7 +757,7 @@ FireflySAO::FireflySAO(ServerEnvironment *env, u16 id, v3f pos): m_touching_ground = false; } -ServerActiveObject* FireflySAO::create(ServerEnvironment *env, u16 id, v3f pos, +ServerActiveObject* FireflySAO::create(ServerEnvironment *env, v3f pos, const std::string &data) { std::istringstream is(data, std::ios::binary); @@ -768,7 +768,7 @@ ServerActiveObject* FireflySAO::create(ServerEnvironment *env, u16 id, v3f pos, // check if version is supported if(version != 0) return NULL; - return new FireflySAO(env, id, pos); + return new FireflySAO(env, pos); } void FireflySAO::step(float dtime, bool send_recommended) @@ -918,11 +918,11 @@ InventoryItem* FireflySAO::createPickedUpItem() */ // Prototype -MobV2SAO proto_MobV2SAO(NULL, 0, v3f(0,0,0), NULL); +MobV2SAO proto_MobV2SAO(NULL, v3f(0,0,0), NULL); -MobV2SAO::MobV2SAO(ServerEnvironment *env, u16 id, v3f pos, +MobV2SAO::MobV2SAO(ServerEnvironment *env, v3f pos, Settings *init_properties): - ServerActiveObject(env, id, pos), + ServerActiveObject(env, pos), m_move_type("ground_nodes"), m_speed(0,0,0), m_last_sent_position(0,0,0), @@ -961,13 +961,13 @@ MobV2SAO::~MobV2SAO() delete m_properties; } -ServerActiveObject* MobV2SAO::create(ServerEnvironment *env, u16 id, v3f pos, +ServerActiveObject* MobV2SAO::create(ServerEnvironment *env, v3f pos, const std::string &data) { std::istringstream is(data, std::ios::binary); Settings properties; properties.parseConfigLines(is, "MobArgsEnd"); - MobV2SAO *o = new MobV2SAO(env, id, pos, &properties); + MobV2SAO *o = new MobV2SAO(env, pos, &properties); return o; } @@ -1174,7 +1174,7 @@ void MobV2SAO::step(float dtime, bool send_recommended) properties.set("player_hit_damage", "9"); properties.set("player_hit_distance", "2"); properties.set("player_hit_interval", "1"); - ServerActiveObject *obj = new MobV2SAO(m_env, 0, + ServerActiveObject *obj = new MobV2SAO(m_env, pos, &properties); //m_env->addActiveObjectAsStatic(obj); m_env->addActiveObject(obj); @@ -1490,3 +1490,95 @@ void MobV2SAO::doDamage(u16 d) } +/* + LuaEntitySAO +*/ + +#include "scriptapi.h" + +// Prototype +LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", ""); + +LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, + const std::string &name, const std::string &state): + ServerActiveObject(env, pos), + m_init_name(name), + m_init_state(state), + m_registered(false) +{ + if(env == NULL){ + ServerActiveObject::registerType(getType(), create); + return; + } +} + +LuaEntitySAO::~LuaEntitySAO() +{ + if(m_registered){ + lua_State *L = m_env->getLua(); + scriptapi_luaentity_deregister(L, m_id); + } +} + +void LuaEntitySAO::addedToEnvironment(u16 id) +{ + ServerActiveObject::addedToEnvironment(id); + + // Create entity by name and state + m_registered = true; + lua_State *L = m_env->getLua(); + scriptapi_luaentity_register(L, id, m_init_name.c_str(), m_init_state.c_str()); +} + +ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos, + const std::string &data) +{ + std::istringstream is(data, std::ios::binary); + // read version + u8 version = readU8(is); + // check if version is supported + if(version != 0) + return NULL; + // read name + std::string name = deSerializeString(is); + // read state + std::string state = deSerializeLongString(is); + // create object + infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\"" + <<state<<"\")"<<std::endl; + return new LuaEntitySAO(env, pos, name, state); +} + +void LuaEntitySAO::step(float dtime, bool send_recommended) +{ + if(m_registered){ + lua_State *L = m_env->getLua(); + scriptapi_luaentity_step(L, m_id, dtime, send_recommended); + } +} + +std::string LuaEntitySAO::getClientInitializationData() +{ + std::ostringstream os(std::ios::binary); + // version + writeU8(os, 0); + // pos + writeV3F1000(os, m_base_position); + return os.str(); +} + +std::string LuaEntitySAO::getStaticData() +{ + infostream<<__FUNCTION_NAME<<std::endl; + std::ostringstream os(std::ios::binary); + // version + writeU8(os, 0); + // name + os<<serializeString(m_init_name); + // state + std::string state = scriptapi_luaentity_get_state(L, m_id); + os<<serializeString(state); + return os.str(); +} + + diff --git a/src/content_sao.h b/src/content_sao.h index f0ebf4f6f..44c0b7172 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -26,10 +26,10 @@ with this program; if not, write to the Free Software Foundation, Inc., class TestSAO : public ServerActiveObject { public: - TestSAO(ServerEnvironment *env, u16 id, v3f pos); + TestSAO(ServerEnvironment *env, v3f pos); u8 getType() const {return ACTIVEOBJECT_TYPE_TEST;} - static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, + static ServerActiveObject* create(ServerEnvironment *env, v3f pos, const std::string &data); void step(float dtime, bool send_recommended); private: @@ -40,11 +40,11 @@ private: class ItemSAO : public ServerActiveObject { public: - ItemSAO(ServerEnvironment *env, u16 id, v3f pos, + ItemSAO(ServerEnvironment *env, v3f pos, const std::string inventorystring); u8 getType() const {return ACTIVEOBJECT_TYPE_ITEM;} - static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, + static ServerActiveObject* create(ServerEnvironment *env, v3f pos, const std::string &data); void step(float dtime, bool send_recommended); std::string getClientInitializationData(); @@ -62,10 +62,10 @@ private: class RatSAO : public ServerActiveObject { public: - RatSAO(ServerEnvironment *env, u16 id, v3f pos); + RatSAO(ServerEnvironment *env, v3f pos); u8 getType() const {return ACTIVEOBJECT_TYPE_RAT;} - static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, + static ServerActiveObject* create(ServerEnvironment *env, v3f pos, const std::string &data); void step(float dtime, bool send_recommended); std::string getClientInitializationData(); @@ -87,10 +87,10 @@ private: class Oerkki1SAO : public ServerActiveObject { public: - Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos); + Oerkki1SAO(ServerEnvironment *env, v3f pos); u8 getType() const {return ACTIVEOBJECT_TYPE_OERKKI1;} - static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, + static ServerActiveObject* create(ServerEnvironment *env, v3f pos, const std::string &data); void step(float dtime, bool send_recommended); std::string getClientInitializationData(); @@ -119,10 +119,10 @@ private: class FireflySAO : public ServerActiveObject { public: - FireflySAO(ServerEnvironment *env, u16 id, v3f pos); + FireflySAO(ServerEnvironment *env, v3f pos); u8 getType() const {return ACTIVEOBJECT_TYPE_FIREFLY;} - static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, + static ServerActiveObject* create(ServerEnvironment *env, v3f pos, const std::string &data); void step(float dtime, bool send_recommended); std::string getClientInitializationData(); @@ -146,12 +146,12 @@ class Settings; class MobV2SAO : public ServerActiveObject { public: - MobV2SAO(ServerEnvironment *env, u16 id, v3f pos, + MobV2SAO(ServerEnvironment *env, v3f pos, Settings *init_properties); virtual ~MobV2SAO(); u8 getType() const {return ACTIVEOBJECT_TYPE_MOBV2;} - static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, + static ServerActiveObject* create(ServerEnvironment *env, v3f pos, const std::string &data); std::string getStaticData(); std::string getClientInitializationData(); @@ -195,5 +195,27 @@ private: Settings *m_properties; }; +struct LuaState; + +class LuaEntitySAO : public ServerActiveObject +{ +public: + LuaEntitySAO(ServerEnvironment *env, v3f pos, + const std::string &name, const std::string &state); + ~LuaEntitySAO(); + u8 getType() const + {return ACTIVEOBJECT_TYPE_LUAENTITY;} + virtual void addedToEnvironment(u16 id); + static ServerActiveObject* create(ServerEnvironment *env, v3f pos, + const std::string &data); + void step(float dtime, bool send_recommended); + std::string getClientInitializationData(); + std::string getStaticData(); +private: + std::string m_init_name; + std::string m_init_state; + bool m_registered; +}; + #endif diff --git a/src/environment.cpp b/src/environment.cpp index 80e9d5c78..d7a647ac8 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "log.h" #include "profiler.h" +#include "scriptapi.h" #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" @@ -267,9 +268,9 @@ void ActiveBlockList::update(core::list<v3s16> &active_positions, ServerEnvironment */ -ServerEnvironment::ServerEnvironment(ServerMap *map, Server *server): +ServerEnvironment::ServerEnvironment(ServerMap *map, lua_State *L): m_map(map), - m_server(server), + m_lua(L), m_random_spawn_timer(3), m_send_recommended_timer(0), m_game_time(0), @@ -674,6 +675,8 @@ void ServerEnvironment::clearAllObjects() obj->m_removed = true; continue; } + // Deregister in scripting api + scriptapi_rm_object_reference(m_lua, obj); // Delete active object delete obj; // Id to be removed from m_active_objects @@ -1043,7 +1046,7 @@ void ServerEnvironment::step(float dtime) n1.getContent() == CONTENT_AIR) { v3f pos = intToFloat(p1, BS); - ServerActiveObject *obj = new RatSAO(this, 0, pos); + ServerActiveObject *obj = new RatSAO(this, pos); addActiveObject(obj); } } @@ -1071,21 +1074,21 @@ void ServerEnvironment::step(float dtime) Settings properties; getMob_dungeon_master(properties); ServerActiveObject *obj = new MobV2SAO( - this, 0, pos, &properties); + this, pos, &properties); addActiveObject(obj); } else if(i == 2 || i == 3){ actionstream<<"Rats spawn at " <<PP(p1)<<std::endl; for(int j=0; j<3; j++){ ServerActiveObject *obj = new RatSAO( - this, 0, pos); + this, pos); addActiveObject(obj); } } else { actionstream<<"An oerkki spawns at " <<PP(p1)<<std::endl; ServerActiveObject *obj = new Oerkki1SAO( - this, 0, pos); + this, pos); addActiveObject(obj); } } @@ -1228,18 +1231,18 @@ void ServerEnvironment::step(float dtime) Create a ServerActiveObject */ - //TestSAO *obj = new TestSAO(this, 0, pos); - //ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1"); - //ServerActiveObject *obj = new RatSAO(this, 0, pos); - //ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos); - //ServerActiveObject *obj = new FireflySAO(this, 0, pos); + //TestSAO *obj = new TestSAO(this, pos); + //ServerActiveObject *obj = new ItemSAO(this, pos, "CraftItem Stick 1"); + //ServerActiveObject *obj = new RatSAO(this, pos); + //ServerActiveObject *obj = new Oerkki1SAO(this, pos); + //ServerActiveObject *obj = new FireflySAO(this, pos); infostream<<"Server: Spawning MobV2SAO at " <<"("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl; Settings properties; getMob_dungeon_master(properties); - ServerActiveObject *obj = new MobV2SAO(this, 0, pos, &properties); + ServerActiveObject *obj = new MobV2SAO(this, pos, &properties); addActiveObject(obj); } #endif @@ -1493,6 +1496,11 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object, <<"could not find block for storing id="<<object->getId() <<" statically"<<std::endl; } + + // Post-initialize object + object->addedToEnvironment(object->getId()); + // Register reference in scripting api + scriptapi_add_object_reference(m_lua, object); return object->getId(); } @@ -1544,6 +1552,9 @@ void ServerEnvironment::removeRemovedObjects() if(obj->m_known_by_count > 0) continue; + // Deregister in scripting api + scriptapi_rm_object_reference(m_lua, obj); + // Delete delete obj; // Id to be removed from m_active_objects @@ -1815,6 +1826,10 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete) verbosestream<<"ServerEnvironment::deactivateFarObjects(): " <<"object id="<<id<<" is not known by clients" <<"; deleting"<<std::endl; + + // Deregister in scripting api + scriptapi_rm_object_reference(m_lua, obj); + // Delete active object delete obj; // Id to be removed from m_active_objects diff --git a/src/environment.h b/src/environment.h index 5d2fe5551..0e0a5510e 100644 --- a/src/environment.h +++ b/src/environment.h @@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc., class Server; class ActiveBlockModifier; class ServerActiveObject; +typedef struct lua_State lua_State; class Environment { @@ -126,7 +127,7 @@ private: class ServerEnvironment : public Environment { public: - ServerEnvironment(ServerMap *map, Server *server); + ServerEnvironment(ServerMap *map, lua_State *L); ~ServerEnvironment(); Map & getMap() @@ -139,13 +140,11 @@ public: return *m_map; } - Server * getServer() + lua_State* getLua() { - return m_server; + return m_lua; } - void step(f32 dtime); - /* Save players */ @@ -222,7 +221,9 @@ public: // Clear all objects, loading and going through every MapBlock void clearAllObjects(); - + + void step(f32 dtime); + private: /* @@ -269,8 +270,8 @@ private: // The map ServerMap *m_map; - // Pointer to server (which is handling this environment) - Server *m_server; + // Lua state + lua_State *m_lua; // Active object list core::map<u16, ServerActiveObject*> m_active_objects; // Outgoing network message buffer for active objects diff --git a/src/inventory.cpp b/src/inventory.cpp index 92ef3b011..5d4a6e408 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -136,7 +136,7 @@ ServerActiveObject* InventoryItem::createSAO(ServerEnvironment *env, u16 id, v3f Create an ItemSAO */ // Create object - ServerActiveObject *obj = new ItemSAO(env, 0, pos, getItemString()); + ServerActiveObject *obj = new ItemSAO(env, pos, getItemString()); return obj; } @@ -174,7 +174,7 @@ video::ITexture * CraftItem::getImage() const ServerActiveObject* CraftItem::createSAO(ServerEnvironment *env, u16 id, v3f pos) { // Special cases - ServerActiveObject *obj = item_craft_create_object(m_subname, env, id, pos); + ServerActiveObject *obj = item_craft_create_object(m_subname, env, pos); if(obj) return obj; // Default diff --git a/src/irrlichttypes.h b/src/irrlichttypes.h new file mode 100644 index 000000000..7ab83bb7d --- /dev/null +++ b/src/irrlichttypes.h @@ -0,0 +1,52 @@ +/* +Minetest-c55 +Copyright (C) 2010-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 IRRLICHTTYPES_HEADER +#define IRRLICHTTYPES_HEADER + +#include <irrTypes.h> +#include <vector2d.h> +#include <vector3d.h> +#include <irrMap.h> +#include <irrList.h> +#include <irrArray.h> +#include <aabbox3d.h> +using namespace irr; +typedef core::vector3df v3f; +typedef core::vector3d<s16> v3s16; +typedef core::vector3d<s32> v3s32; + +typedef core::vector2d<f32> v2f; +typedef core::vector2d<s16> v2s16; +typedef core::vector2d<s32> v2s32; +typedef core::vector2d<u32> v2u32; +typedef core::vector2d<f32> v2f32; + +#ifdef _MSC_VER + // Windows + typedef unsigned long long u64; +#else + // Posix + #include <stdint.h> + typedef uint64_t u64; + //typedef unsigned long long u64; +#endif + +#endif + diff --git a/src/porting.cpp b/src/porting.cpp index 00595b06c..0adc955a9 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -56,9 +56,10 @@ void sigint_handler(int sig) dstream<<DTIME<<"INFO: sigint_handler(): " <<"Ctrl-C pressed, shutting down."<<std::endl; - dstream<<DTIME<<"INFO: sigint_handler(): " + // Comment out for less clutter when testing scripts + /*dstream<<DTIME<<"INFO: sigint_handler(): " <<"Printing debug stacks"<<std::endl; - debug_stacks_print(); + debug_stacks_print();*/ g_killed = true; } @@ -91,9 +92,10 @@ void signal_handler_init(void) { dstream<<DTIME<<"INFO: event_handler(): " <<"Ctrl+C, Close Event, Logoff Event or Shutdown Event, shutting down."<<std::endl; - dstream<<DTIME<<"INFO: event_handler(): " + // Comment out for less clutter when testing scripts + /*dstream<<DTIME<<"INFO: event_handler(): " <<"Printing debug stacks"<<std::endl; - debug_stacks_print(); + debug_stacks_print();*/ g_killed = true; } diff --git a/src/script.cpp b/src/script.cpp new file mode 100644 index 000000000..edfc596b8 --- /dev/null +++ b/src/script.cpp @@ -0,0 +1,130 @@ +/* +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 "script.h" +#include <cstdarg> +#include <cstring> +#include <cstdio> +#include <cstdlib> +#include "log.h" +#include <iostream> + +extern "C" { +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> +} + +void script_error(lua_State *L, const char *fmt, ...) +{ + va_list argp; + va_start(argp, fmt); + vfprintf(stderr, fmt, argp); + va_end(argp); + lua_close(L); + exit(EXIT_FAILURE); +} + +void script_call_va(lua_State *L, const char *func, const char *sig, ...) +{ + va_list vl; + int narg, nres; /* number of arguments and results */ + + va_start(vl, sig); + lua_getglobal(L, func); /* push function */ + + for (narg = 0; *sig; narg++) { + /* repeat for each argument */ + /* check stack space */ + luaL_checkstack(L, 1, "too many arguments"); + switch (*sig++) { + case 'd': /* double argument */ + lua_pushnumber(L, va_arg(vl, double)); + break; + case 'i': /* int argument */ + lua_pushinteger(L, va_arg(vl, int)); + break; + case 's': /* string argument */ + lua_pushstring(L, va_arg(vl, char *)); + break; + case '>': /* end of arguments */ + goto endargs; + default: + script_error(L, "invalid option (%c)", *(sig - 1)); + } + } +endargs: + + nres = strlen(sig); /* number of expected results */ + + if (lua_pcall(L, narg, nres, 0) != 0) /* do the call */ + script_error(L, "error calling '%s': %s", func, lua_tostring(L, -1)); + + nres = -nres; /* stack index of first result */ + while (*sig) { /* repeat for each result */ + switch (*sig++) { + case 'd': /* double result */ + if (!lua_isnumber(L, nres)) + script_error(L, "wrong result type"); + *va_arg(vl, double *) = lua_tonumber(L, nres); + break; + case 'i': /* int result */ + if (!lua_isnumber(L, nres)) + script_error(L, "wrong result type"); + *va_arg(vl, int *) = lua_tointeger(L, nres); + break; + case 's': /* string result */ + if (!lua_isstring(L, nres)) + script_error(L, "wrong result type"); + *va_arg(vl, const char **) = lua_tostring(L, nres); + break; + default: + script_error(L, "invalid option (%c)", *(sig - 1)); + } + nres++; + } + + va_end(vl); +} + +bool script_load(lua_State *L, const char *path) +{ + infostream<<"Loading and running script from "<<path<<std::endl; + int ret = luaL_loadfile(L, path) || lua_pcall(L, 0, 0, 0); + if(ret){ + errorstream<<"Failed to load and run script from "<<path<<": "<<lua_tostring(L, -1)<<std::endl; + lua_pop(L, 1); // Pop error message from stack + return false; + } + return true; +} + +lua_State* script_init() +{ + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + return L; +} + +lua_State* script_deinit(lua_State *L) +{ + lua_close(L); +} + + diff --git a/src/script.h b/src/script.h new file mode 100644 index 000000000..82254744f --- /dev/null +++ b/src/script.h @@ -0,0 +1,33 @@ +/* +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 SCRIPT_HEADER +#define SCRIPT_HEADER + +typedef struct lua_State lua_State; +//#include <string> + +lua_State* script_init(); +lua_State* script_deinit(lua_State *L); +void script_error(lua_State *L, const char *fmt, ...); +void script_call_va(lua_State *L, const char *func, const char *sig, ...); +bool script_load(lua_State *L, const char *path); + +#endif + diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp new file mode 100644 index 000000000..fbe383075 --- /dev/null +++ b/src/scriptapi.cpp @@ -0,0 +1,422 @@ +/* +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 "scriptapi.h" + +#include <iostream> +extern "C" { +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> +} + +#include "log.h" +#include "server.h" +#include "porting.h" +#include "filesys.h" +#include "serverobject.h" +#include "script.h" +//#include "luna.h" + +static void stackDump(lua_State *L, std::ostream &o) +{ + int i; + int top = lua_gettop(L); + for (i = 1; i <= top; i++) { /* repeat for each level */ + int t = lua_type(L, i); + switch (t) { + + case LUA_TSTRING: /* strings */ + o<<"\""<<lua_tostring(L, i)<<"\""; + break; + + case LUA_TBOOLEAN: /* booleans */ + o<<(lua_toboolean(L, i) ? "true" : "false"); + break; + + case LUA_TNUMBER: /* numbers */ { + char buf[10]; + snprintf(buf, 10, "%g", lua_tonumber(L, i)); + o<<buf; + break; } + + default: /* other values */ + o<<lua_typename(L, t); + break; + + } + o<<" "; + } + o<<std::endl; +} + +static void realitycheck(lua_State *L) +{ + int top = lua_gettop(L); + if(top >= 30){ + dstream<<"Stack is over 30:"<<std::endl; + stackDump(L, dstream); + script_error(L, "Stack is over 30 (reality check)"); + } +} + +// Register new object prototype (must be based on entity) +static int l_register_object(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + luaL_checkany(L, 2); + infostream<<"register_object: "<<name<<std::endl; + // Get the minetest table + lua_getglobal(L, "minetest"); + // Get field "registered_objects" + lua_getfield(L, -1, "registered_objects"); + luaL_checktype(L, -1, LUA_TTABLE); + int objectstable = lua_gettop(L); + // Object is in param 2 + lua_pushvalue(L, 2); // Copy object to top of stack + lua_setfield(L, objectstable, name); // registered_objects[name] = object + + return 0; /* number of results */ +} + +static int l_new_entity(lua_State *L) +{ + /* o = o or {} + setmetatable(o, self) + self.__index = self + return o */ + if(lua_isnil(L, -1)) + lua_newtable(L); + luaL_checktype(L, -1, LUA_TTABLE); + luaL_getmetatable(L, "minetest.entity"); + lua_pushvalue(L, -1); // duplicate metatable + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); + // return table + return 1; +} + +static const struct luaL_Reg minetest_f [] = { + {"register_object", l_register_object}, + {"new_entity", l_new_entity}, + {NULL, NULL} +}; + +static int l_entity_set_deleted(lua_State *L) +{ + return 0; +} + +static const struct luaL_Reg minetest_entity_m [] = { + {"set_deleted", l_entity_set_deleted}, + {NULL, NULL} +}; + +class ObjectRef +{ +private: + ServerActiveObject *m_object; + + static const char className[]; + static const luaL_reg methods[]; + + static ObjectRef *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 *(ObjectRef**)ud; // unbox pointer + } + + // Exported functions + + static int l_remove(lua_State *L) + { + ObjectRef *o = checkobject(L, 1); + ServerActiveObject *co = o->m_object; + if(co == NULL) return 0; + infostream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl; + co->m_removed = true; + return 0; + } + + static int gc_object(lua_State *L) { + //ObjectRef *o = checkobject(L, 1); + ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1)); + //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl; + delete o; + return 0; + } + +public: + ObjectRef(ServerActiveObject *object): + m_object(object) + { + infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl; + } + + ~ObjectRef() + { + if(m_object) + infostream<<"ObjectRef destructing for id="<<m_object->getId()<<std::endl; + else + infostream<<"ObjectRef destructing for id=unknown"<<std::endl; + } + + // Creates an ObjectRef and leaves it on top of stack + // Not callable from Lua; all references are created on the C side. + static void create(lua_State *L, ServerActiveObject *object) + { + ObjectRef *o = new ObjectRef(object); + //infostream<<"ObjectRef::create: o="<<o<<std::endl; + *(void **)(lua_newuserdata(L, sizeof(void *))) = o; + luaL_getmetatable(L, className); + lua_setmetatable(L, -2); + } + + static void set_null(lua_State *L) + { + ObjectRef *o = checkobject(L, -1); + ServerActiveObject *co = o->m_object; + if(co == NULL) + return; + o->m_object = NULL; + } + + static void Register(lua_State *L) + { + lua_newtable(L); + int methodtable = lua_gettop(L); + luaL_newmetatable(L, className); + int metatable = lua_gettop(L); + + lua_pushliteral(L, "__metatable"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); // hide metatable from Lua getmetatable() + + lua_pushliteral(L, "__index"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, gc_object); + lua_settable(L, metatable); + + lua_pop(L, 1); // drop metatable + + luaL_openlib(L, 0, methods, 0); // fill methodtable + lua_pop(L, 1); // drop methodtable + + // Cannot be created from Lua + //lua_register(L, className, create_object); + } +}; + +const char ObjectRef::className[] = "ObjectRef"; + +#define method(class, name) {#name, class::l_##name} + +const luaL_reg ObjectRef::methods[] = { + method(ObjectRef, remove), + {0,0} +}; + +void scriptapi_export(lua_State *L, Server *server) +{ + realitycheck(L); + assert(lua_checkstack(L, 20)); + infostream<<"scriptapi_export"<<std::endl; + + // Register global functions in table minetest + lua_newtable(L); + luaL_register(L, NULL, minetest_f); + lua_setglobal(L, "minetest"); + + // Get the main minetest table + lua_getglobal(L, "minetest"); + + // Add registered_objects table in minetest + lua_newtable(L); + lua_setfield(L, -2, "registered_objects"); + + // Add object_refs table in minetest + lua_newtable(L); + lua_setfield(L, -2, "object_refs"); + + // Add luaentities table in minetest + lua_newtable(L); + lua_setfield(L, -2, "luaentities"); + + // Load and run some base Lua stuff + /*script_load(L, (porting::path_data + DIR_DELIM + "scripts" + + DIR_DELIM + "base.lua").c_str());*/ + + // Create entity reference metatable + luaL_newmetatable(L, "minetest.entity_reference"); + lua_pop(L, 1); + + // 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 + + // Entity C reference + ObjectRef::Register(L); +} + +void scriptapi_luaentity_register(lua_State *L, u16 id, const char *name, + const char *init_state) +{ + realitycheck(L); + assert(lua_checkstack(L, 20)); + infostream<<"scriptapi_luaentity_register: id="<<id<<std::endl; + + // Create object as a dummy string (TODO: Create properly) + lua_pushstring(L, "dummy object string"); + int object = lua_gettop(L); + + // Get minetest.luaentities table + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "luaentities"); + luaL_checktype(L, -1, LUA_TTABLE); + int objectstable = lua_gettop(L); + + // luaentities[id] = object + lua_pushnumber(L, id); // Push id + lua_pushvalue(L, object); // Copy object to top of stack + lua_settable(L, objectstable); + + lua_pop(L, 3); // pop luaentities, minetest and the object +} + +void scriptapi_luaentity_deregister(lua_State *L, u16 id) +{ + realitycheck(L); + assert(lua_checkstack(L, 20)); + infostream<<"scriptapi_luaentity_deregister: id="<<id<<std::endl; + + // Get minetest.luaentities table + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "luaentities"); + luaL_checktype(L, -1, LUA_TTABLE); + int objectstable = lua_gettop(L); + + /*// Get luaentities[id] + lua_pushnumber(L, cobj->getId()); // Push id + lua_gettable(L, objectstable); + // Object is at stack top + lua_pop(L, 1); // pop object*/ + + // Set luaentities[id] = nil + lua_pushnumber(L, cobj->getId()); // Push id + lua_pushnil(L); + lua_settable(L, objectstable); + + lua_pop(L, 2); // pop luaentities, minetest +} + +void scriptapi_luaentity_step(lua_State *L, u16 id, + float dtime, bool send_recommended) +{ + realitycheck(L); + assert(lua_checkstack(L, 20)); + infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; + + // Get minetest.luaentities table + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "luaentities"); + luaL_checktype(L, -1, LUA_TTABLE); + int objectstable = lua_gettop(L); + + // Get luaentities[id] + lua_pushnumber(L, cobj->getId()); // Push id + lua_gettable(L, objectstable); + + // TODO: Call step function + + lua_pop(L, 1); // pop object + lua_pop(L, 2); // pop luaentities, minetest +} + +std::string scriptapi_luaentity_get_state(lua_State *L, u16 id) +{ + realitycheck(L); + assert(lua_checkstack(L, 20)); + infostream<<"scriptapi_luaentity_get_state: id="<<id<<std::endl; + + return ""; +} + +void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj) +{ + realitycheck(L); + assert(lua_checkstack(L, 20)); + infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl; + + // Create object on stack + ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack + int object = lua_gettop(L); + + // Get minetest.object_refs table + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "object_refs"); + luaL_checktype(L, -1, LUA_TTABLE); + int objectstable = lua_gettop(L); + + // object_refs[id] = object + lua_pushnumber(L, cobj->getId()); // Push id + lua_pushvalue(L, object); // Copy object to top of stack + lua_settable(L, objectstable); + + // pop object_refs, minetest and the object + lua_pop(L, 3); +} + +void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj) +{ + realitycheck(L); + assert(lua_checkstack(L, 20)); + infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl; + + // Get minetest.object_refs table + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "object_refs"); + luaL_checktype(L, -1, LUA_TTABLE); + int objectstable = lua_gettop(L); + + // Get object_refs[id] + lua_pushnumber(L, cobj->getId()); // Push id + lua_gettable(L, objectstable); + // Set object reference to NULL + ObjectRef::set_null(L); + lua_pop(L, 1); // pop object + + // Set object_refs[id] = nil + lua_pushnumber(L, cobj->getId()); // Push id + lua_pushnil(L); + lua_settable(L, objectstable); + + // pop object_refs, minetest + lua_pop(L, 2); +} + diff --git a/src/scriptapi.h b/src/scriptapi.h new file mode 100644 index 000000000..a97d707a8 --- /dev/null +++ b/src/scriptapi.h @@ -0,0 +1,43 @@ +/* +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 SCRIPTAPI_HEADER +#define SCRIPTAPI_HEADER + +#include "irrlichttypes.h" +#include <string> + +class Server; +class ServerActiveObject; +typedef struct lua_State lua_State; + +void scriptapi_export(lua_State *L, Server *server); + +void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj); +void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj); + +void scriptapi_luaentity_register(lua_State *L, u16 id, const char *name, + const char *init_state); +void scriptapi_luaentity_deregister(lua_State *L, u16 id); +void scriptapi_luaentity_step(lua_State *L, u16 id, + float dtime, bool send_recommended); +std::string scriptapi_luaentity_get_state(lua_State *L, u16 id); + +#endif + diff --git a/src/server.cpp b/src/server.cpp index e7cfc9afc..1c5d8d937 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -39,6 +39,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "profiler.h" #include "log.h" +#include "script.h" +#include "scriptapi.h" #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" @@ -185,7 +187,7 @@ void * EmergeThread::Thread() <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") " <<"only_from_disk="<<only_from_disk<<std::endl; - ServerMap &map = ((ServerMap&)m_server->m_env.getMap()); + ServerMap &map = ((ServerMap&)m_server->m_env->getMap()); //core::map<v3s16, MapBlock*> changed_blocks; //core::map<v3s16, MapBlock*> lighting_invalidated_blocks; @@ -250,7 +252,7 @@ void * EmergeThread::Thread() MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events); // Activate objects and stuff - m_server->m_env.activateBlock(block, 3600); + m_server->m_env->activateBlock(block, 3600); } } else @@ -371,7 +373,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, //TimeTaker timer("RemoteClient::GetNextBlocks"); - Player *player = server->m_env.getPlayer(peer_id); + Player *player = server->m_env->getPlayer(peer_id); assert(player != NULL); @@ -572,7 +574,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, MAP_BLOCKSIZE*p.Z); // Get ground height in nodes - s16 gh = server->m_env.getServerMap().findGroundLevel( + s16 gh = server->m_env->getServerMap().findGroundLevel( p2d_nodes_center); // If differs a lot, don't generate @@ -611,7 +613,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, /* Check if map has this block */ - MapBlock *block = server->m_env.getMap().getBlockNoCreateNoEx(p); + MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p); bool surely_not_found_on_disk = false; bool block_is_invalid = false; @@ -640,7 +642,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, #if 0 v2s16 p2d(p.X, p.Z); - ServerMap *map = (ServerMap*)(&server->m_env.getMap()); + ServerMap *map = (ServerMap*)(&server->m_env->getMap()); v2s16 chunkpos = map->sector_to_chunk(p2d); if(map->chunkNonVolatile(chunkpos) == false) block_is_invalid = true; @@ -802,7 +804,7 @@ void RemoteClient::SendObjectData( */ // Get connected players - core::list<Player*> players = server->m_env.getPlayers(true); + core::list<Player*> players = server->m_env->getPlayers(true); // Write player count u16 playercount = players.size(); @@ -948,10 +950,12 @@ Server::Server( std::string mapsavedir, std::string configpath ): - m_env(new ServerMap(mapsavedir), this), + m_env(NULL), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"), m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"), + m_lua(NULL), + //m_scriptapi(NULL), m_thread(this), m_emergethread(this), m_time_counter(0), @@ -973,20 +977,38 @@ Server::Server( m_con_mutex.Init(); m_step_dtime_mutex.Init(); m_step_dtime = 0.0; + + JMutexAutoLock envlock(m_env_mutex); + JMutexAutoLock conlock(m_con_mutex); + + // Initialize scripting + + infostream<<"Server: Initializing scripting"<<std::endl; + m_lua = script_init(); + assert(m_lua); + // Export API + scriptapi_export(m_lua, this); + // Load and run scripts + script_load(m_lua, (porting::path_data + DIR_DELIM + "scripts" + + DIR_DELIM + "default.lua").c_str()); + + // Initialize Environment + + m_env = new ServerEnvironment(new ServerMap(mapsavedir), m_lua); // Register us to receive map edit events - m_env.getMap().addEventReceiver(this); + m_env->getMap().addEventReceiver(this); // If file exists, load environment metadata if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt")) { infostream<<"Server: Loading environment metadata"<<std::endl; - m_env.loadMeta(m_mapsavedir); + m_env->loadMeta(m_mapsavedir); } // Load players infostream<<"Server: Loading players"<<std::endl; - m_env.deSerializePlayers(m_mapsavedir); + m_env->deSerializePlayers(m_mapsavedir); } Server::~Server() @@ -1029,13 +1051,13 @@ Server::~Server() Save players */ infostream<<"Server: Saving players"<<std::endl; - m_env.serializePlayers(m_mapsavedir); + m_env->serializePlayers(m_mapsavedir); /* Save environment metadata */ infostream<<"Server: Saving environment metadata"<<std::endl; - m_env.saveMeta(m_mapsavedir); + m_env->saveMeta(m_mapsavedir); } /* @@ -1058,13 +1080,20 @@ Server::~Server() { u16 peer_id = i.getNode()->getKey(); JMutexAutoLock envlock(m_env_mutex); - m_env.removePlayer(peer_id); + m_env->removePlayer(peer_id); }*/ // Delete client delete i.getNode()->getValue(); } } + + // Delete Environment + delete m_env; + + // Deinitialize scripting + infostream<<"Server: Deinitializing scripting"<<std::endl; + script_deinit(m_lua); } void Server::start(unsigned short port) @@ -1173,7 +1202,7 @@ void Server::AsyncRunStep() u32 units = (u32)(m_time_counter*speed); m_time_counter -= (f32)units / speed; - m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000); + m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000); //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl; @@ -1194,10 +1223,10 @@ void Server::AsyncRunStep() i.atEnd() == false; i++) { RemoteClient *client = i.getNode()->getValue(); - //Player *player = m_env.getPlayer(client->peer_id); + //Player *player = m_env->getPlayer(client->peer_id); SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY( - m_env.getTimeOfDay()); + m_env->getTimeOfDay()); // Send as reliable m_con.Send(client->peer_id, 0, data, true); } @@ -1209,7 +1238,7 @@ void Server::AsyncRunStep() // Step environment ScopeProfiler sp(g_profiler, "SEnv step"); ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG); - m_env.step(dtime); + m_env->step(dtime); } const float map_timer_and_unload_dtime = 5.15; @@ -1218,7 +1247,7 @@ void Server::AsyncRunStep() JMutexAutoLock lock(m_env_mutex); // Run Map's timers and unload unused data ScopeProfiler sp(g_profiler, "Server: map timer and unload"); - m_env.getMap().timerUpdate(map_timer_and_unload_dtime, + m_env->getMap().timerUpdate(map_timer_and_unload_dtime, g_settings->getFloat("server_unload_unused_data_timeout")); } @@ -1239,13 +1268,13 @@ void Server::AsyncRunStep() ScopeProfiler sp(g_profiler, "Server: liquid transform"); core::map<v3s16, MapBlock*> modified_blocks; - m_env.getMap().transformLiquids(modified_blocks); + m_env->getMap().transformLiquids(modified_blocks); #if 0 /* Update lighting */ core::map<v3s16, MapBlock*> lighting_modified_blocks; - ServerMap &map = ((ServerMap&)m_env.getMap()); + ServerMap &map = ((ServerMap&)m_env->getMap()); map.updateLighting(modified_blocks, lighting_modified_blocks); // Add blocks modified by lighting to modified_blocks @@ -1295,7 +1324,7 @@ void Server::AsyncRunStep() { //u16 peer_id = i.getNode()->getKey(); RemoteClient *client = i.getNode()->getValue(); - Player *player = m_env.getPlayer(client->peer_id); + Player *player = m_env->getPlayer(client->peer_id); if(player==NULL) continue; infostream<<"* "<<player->getName()<<"\t"; @@ -1326,7 +1355,7 @@ void Server::AsyncRunStep() i.atEnd() == false; i++) { RemoteClient *client = i.getNode()->getValue(); - Player *player = m_env.getPlayer(client->peer_id); + Player *player = m_env->getPlayer(client->peer_id); if(player==NULL) { // This can happen if the client timeouts somehow @@ -1339,9 +1368,9 @@ void Server::AsyncRunStep() core::map<u16, bool> removed_objects; core::map<u16, bool> added_objects; - m_env.getRemovedActiveObjects(pos, radius, + m_env->getRemovedActiveObjects(pos, radius, client->m_known_objects, removed_objects); - m_env.getAddedActiveObjects(pos, radius, + m_env->getAddedActiveObjects(pos, radius, client->m_known_objects, added_objects); // Ignore if nothing happened @@ -1364,7 +1393,7 @@ void Server::AsyncRunStep() { // Get object u16 id = i.getNode()->getKey(); - ServerActiveObject* obj = m_env.getActiveObject(id); + ServerActiveObject* obj = m_env->getActiveObject(id); // Add to data buffer for sending writeU16((u8*)buf, i.getNode()->getKey()); @@ -1386,7 +1415,7 @@ void Server::AsyncRunStep() { // Get object u16 id = i.getNode()->getKey(); - ServerActiveObject* obj = m_env.getActiveObject(id); + ServerActiveObject* obj = m_env->getActiveObject(id); // Get object type u8 type = ACTIVEOBJECT_TYPE_INVALID; @@ -1452,7 +1481,7 @@ void Server::AsyncRunStep() } } - m_env.setKnownActiveObjects(whatever); + m_env->setKnownActiveObjects(whatever); #endif } @@ -1473,7 +1502,7 @@ void Server::AsyncRunStep() // Get active object messages from environment for(;;) { - ActiveObjectMessage aom = m_env.getActiveObjectMessage(); + ActiveObjectMessage aom = m_env->getActiveObjectMessage(); if(aom.id == 0) break; @@ -1662,7 +1691,7 @@ void Server::AsyncRunStep() { v3s16 p = i.getNode()->getKey(); modified_blocks2.insert(p, - m_env.getMap().getBlockNoCreateNoEx(p)); + m_env->getMap().getBlockNoCreateNoEx(p)); } // Set blocks not sent for(core::list<u16>::Iterator @@ -1749,15 +1778,15 @@ void Server::AsyncRunStep() JMutexAutoLock lock(m_env_mutex); /*// Unload unused data (delete from memory) - m_env.getMap().unloadUnusedData( + m_env->getMap().unloadUnusedData( g_settings->getFloat("server_unload_unused_sectors_timeout")); */ - /*u32 deleted_count = m_env.getMap().unloadUnusedData( + /*u32 deleted_count = m_env->getMap().unloadUnusedData( g_settings->getFloat("server_unload_unused_sectors_timeout")); */ // Save only changed parts - m_env.getMap().save(true); + m_env->getMap().save(true); /*if(deleted_count > 0) { @@ -1766,10 +1795,10 @@ void Server::AsyncRunStep() }*/ // Save players - m_env.serializePlayers(m_mapsavedir); + m_env->serializePlayers(m_mapsavedir); // Save environment metadata - m_env.saveMeta(m_mapsavedir); + m_env->saveMeta(m_mapsavedir); } } } @@ -1811,7 +1840,7 @@ void Server::Receive() <<" has apparently closed connection. " <<"Removing player."<<std::endl; - m_env.removePlayer(peer_id);*/ + m_env->removePlayer(peer_id);*/ } } @@ -2026,7 +2055,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) writeU16(&reply[0], TOCLIENT_INIT); writeU8(&reply[2], deployed); writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS)); - writeU64(&reply[2+1+6], m_env.getServerMap().getSeed()); + writeU64(&reply[2+1+6], m_env->getServerMap().getSeed()); // Send as reliable m_con.Send(peer_id, 0, reply, true); @@ -2063,7 +2092,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Send player items to all players SendPlayerItems(); - Player *player = m_env.getPlayer(peer_id); + Player *player = m_env->getPlayer(peer_id); // Send HP SendPlayerHP(player); @@ -2071,7 +2100,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Send time of day { SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY( - m_env.getTimeOfDay()); + m_env->getTimeOfDay()); m_con.Send(peer_id, 0, data, true); } @@ -2081,7 +2110,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Send information about joining in chat { std::wstring name = L"unknown"; - Player *player = m_env.getPlayer(peer_id); + Player *player = m_env->getPlayer(peer_id); if(player != NULL) name = narrow_to_wide(player->getName()); @@ -2117,7 +2146,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(client->serialization_version == SER_FMT_VER_INVALID) continue; // Get player - Player *player = m_env.getPlayer(client->peer_id); + Player *player = m_env->getPlayer(client->peer_id); if(!player) continue; // Get name of player @@ -2139,7 +2168,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; } - Player *player = m_env.getPlayer(peer_id); + Player *player = m_env->getPlayer(peer_id); if(player == NULL){ infostream<<"Server::ProcessData(): Cancelling: " @@ -2247,7 +2276,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) u16 id = readS16(&data[3]); u16 item_i = readU16(&data[5]); - ServerActiveObject *obj = m_env.getActiveObject(id); + ServerActiveObject *obj = m_env->getActiveObject(id); if(obj == NULL) { @@ -2421,7 +2450,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) try { - MapNode n = m_env.getMap().getNode(p_under); + MapNode n = m_env->getMap().getNode(p_under); // Get mineral mineral = n.getMineral(); // Get material at position @@ -2442,7 +2471,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(cannot_remove_node == false) { // Get node metadata - NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under); if(meta && meta->nodeRemovalDisabled() == true) { infostream<<"Server: Not finishing digging: " @@ -2608,7 +2637,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { MapEditEventIgnorer ign(&m_ignore_map_edit_events); - m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); + m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks); } /* Set blocks not sent to far players @@ -2649,7 +2678,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { try{ // Don't add a node if this is not a free space - MapNode n2 = m_env.getMap().getNode(p_over); + MapNode n2 = m_env->getMap().getNode(p_over); bool no_enough_privs = ((getPlayerPrivs(player) & PRIV_BUILD)==0); if(no_enough_privs) @@ -2750,7 +2779,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) MapEditEventIgnorer ign(&m_ignore_map_edit_events); std::string p_name = std::string(player->getName()); - m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name); + m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name); } /* Set blocks not sent to far players @@ -2792,7 +2821,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) Check that the block is loaded so that the item can properly be added to the static list too */ - MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos); + MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos); if(block==NULL) { infostream<<"Error while placing object: " @@ -2823,7 +2852,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) /* Create the object */ - ServerActiveObject *obj = item->createSAO(&m_env, 0, pos); + ServerActiveObject *obj = item->createSAO(m_env, 0, pos); if(obj == NULL) { @@ -2837,7 +2866,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <<" at "<<PP(p_over)<<std::endl; // Add the object to the environment - m_env.addActiveObject(obj); + m_env->addActiveObject(obj); infostream<<"Placed object"<<std::endl; @@ -2924,7 +2953,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) text += (char)buf[0]; } - NodeMetadata *meta = m_env.getMap().getNodeMetadata(p); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); if(!meta) return; if(meta->typeId() != CONTENT_SIGN_WALL) @@ -2936,7 +2965,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <<" at "<<PP(p)<<std::endl; v3s16 blockpos = getNodeBlockPos(p); - MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos); + MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos); if(block) { block->setChangedFlag(); @@ -3052,7 +3081,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) p.X = stoi(fn.next(",")); p.Y = stoi(fn.next(",")); p.Z = stoi(fn.next(",")); - NodeMetadata *meta = m_env.getMap().getNodeMetadata(p); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) { LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta; if (lcm->getOwner() != player->getName()) @@ -3070,7 +3099,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) p.X = stoi(fn.next(",")); p.Y = stoi(fn.next(",")); p.Z = stoi(fn.next(",")); - NodeMetadata *meta = m_env.getMap().getNodeMetadata(p); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) { LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta; if (lcm->getOwner() != player->getName()) @@ -3153,7 +3182,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) str_split(message, L' '), paramstring, this, - &m_env, + m_env, player, privs); @@ -3356,7 +3385,7 @@ Inventory* Server::getInventory(InventoryContext *c, std::string id) p.X = stoi(fn.next(",")); p.Y = stoi(fn.next(",")); p.Z = stoi(fn.next(",")); - NodeMetadata *meta = m_env.getMap().getNodeMetadata(p); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); if(meta) return meta->getInventory(); infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): " @@ -3389,7 +3418,7 @@ void Server::inventoryModified(InventoryContext *c, std::string id) p.Z = stoi(fn.next(",")); v3s16 blockpos = getNodeBlockPos(p); - NodeMetadata *meta = m_env.getMap().getNodeMetadata(p); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); if(meta) meta->inventoryModified(); @@ -3415,7 +3444,7 @@ core::list<PlayerInfo> Server::getPlayerInfo() core::list<PlayerInfo> list; - core::list<Player*> players = m_env.getPlayers(); + core::list<Player*> players = m_env->getPlayers(); core::list<Player*>::Iterator i; for(i = players.begin(); @@ -3559,7 +3588,7 @@ void Server::SendPlayerInfos() //JMutexAutoLock envlock(m_env_mutex); // Get connected players - core::list<Player*> players = m_env.getPlayers(true); + core::list<Player*> players = m_env->getPlayers(true); u32 player_count = players.getSize(); u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count; @@ -3593,7 +3622,7 @@ void Server::SendInventory(u16 peer_id) { DSTACK(__FUNCTION_NAME); - Player* player = m_env.getPlayer(peer_id); + Player* player = m_env->getPlayer(peer_id); assert(player); /* @@ -3650,7 +3679,7 @@ void Server::SendPlayerItems() DSTACK(__FUNCTION_NAME); std::ostringstream os(std::ios_base::binary); - core::list<Player *> players = m_env.getPlayers(true); + core::list<Player *> players = m_env->getPlayers(true); writeU16(os, TOCLIENT_PLAYERITEM); writeU16(os, players.size()); @@ -3779,7 +3808,7 @@ void Server::sendRemoveNode(v3s16 p, u16 ignore_id, if(far_players) { // Get player - Player *player = m_env.getPlayer(client->peer_id); + Player *player = m_env->getPlayer(client->peer_id); if(player) { // If player is far away, only set modified blocks not sent @@ -3820,7 +3849,7 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id, if(far_players) { // Get player - Player *player = m_env.getPlayer(client->peer_id); + Player *player = m_env->getPlayer(client->peer_id); if(player) { // If player is far away, only set modified blocks not sent @@ -3960,7 +3989,7 @@ void Server::SendBlocks(float dtime) MapBlock *block = NULL; try { - block = m_env.getMap().getBlockNoCreate(q.pos); + block = m_env->getMap().getBlockNoCreate(q.pos); } catch(InvalidPositionException &e) { @@ -4019,7 +4048,7 @@ void Server::HandlePlayerHP(Player *player, s16 damage) void Server::RespawnPlayer(Player *player) { - v3f pos = findSpawnPos(m_env.getServerMap()); + v3f pos = findSpawnPos(m_env->getServerMap()); player->setPosition(pos); player->hp = 20; SendMovePlayer(player); @@ -4030,7 +4059,7 @@ void Server::UpdateCrafting(u16 peer_id) { DSTACK(__FUNCTION_NAME); - Player* player = m_env.getPlayer(peer_id); + Player* player = m_env->getPlayer(peer_id); assert(player); /* @@ -4096,7 +4125,7 @@ std::wstring Server::getStatusString() if(client->serialization_version == SER_FMT_VER_INVALID) continue; // Get player - Player *player = m_env.getPlayer(client->peer_id); + Player *player = m_env->getPlayer(client->peer_id); // Get name of player std::wstring name = L"unknown"; if(player != NULL) @@ -4105,7 +4134,7 @@ std::wstring Server::getStatusString() os<<name<<L","; } os<<L"}"; - if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false) + if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false) os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled."; if(g_settings->get("motd") != "") os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd")); @@ -4121,7 +4150,7 @@ void Server::saveConfig() void Server::notifyPlayer(const char *name, const std::wstring msg) { - Player *player = m_env.getPlayer(name); + Player *player = m_env->getPlayer(name); if(!player) return; SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg); @@ -4200,7 +4229,7 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id /* Try to get an existing player */ - Player *player = m_env.getPlayer(name); + Player *player = m_env->getPlayer(name); if(player != NULL) { // If player is already connected, cancel @@ -4230,7 +4259,7 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id /* If player with the wanted peer_id already exists, cancel. */ - if(m_env.getPlayer(peer_id) != NULL) + if(m_env->getPlayer(peer_id) != NULL) { infostream<<"emergePlayer(): Player with wrong name but same" " peer_id already exists"<<std::endl; @@ -4258,7 +4287,7 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id infostream<<"Server: Finding spawn place for player \"" <<player->getName()<<"\""<<std::endl; - v3f pos = findSpawnPos(m_env.getServerMap()); + v3f pos = findSpawnPos(m_env->getServerMap()); player->setPosition(pos); @@ -4266,7 +4295,7 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id Add player to environment */ - m_env.addPlayer(player); + m_env->addPlayer(player); /* Add stuff to inventory @@ -4337,7 +4366,7 @@ void Server::handlePeerChange(PeerChange &c) { // Get object u16 id = i.getNode()->getKey(); - ServerActiveObject* obj = m_env.getActiveObject(id); + ServerActiveObject* obj = m_env->getActiveObject(id); if(obj && obj->m_known_by_count > 0) obj->m_known_by_count--; @@ -4346,7 +4375,7 @@ void Server::handlePeerChange(PeerChange &c) // Collect information about leaving in chat std::wstring message; { - Player *player = m_env.getPlayer(c.peer_id); + Player *player = m_env->getPlayer(c.peer_id); if(player != NULL) { std::wstring name = narrow_to_wide(player->getName()); @@ -4360,12 +4389,12 @@ void Server::handlePeerChange(PeerChange &c) /*// Delete player { - m_env.removePlayer(c.peer_id); + m_env->removePlayer(c.peer_id); }*/ // Set player client disconnected { - Player *player = m_env.getPlayer(c.peer_id); + Player *player = m_env->getPlayer(c.peer_id); if(player != NULL) player->peer_id = 0; @@ -4384,7 +4413,7 @@ void Server::handlePeerChange(PeerChange &c) if(client->serialization_version == SER_FMT_VER_INVALID) continue; // Get player - Player *player = m_env.getPlayer(client->peer_id); + Player *player = m_env->getPlayer(client->peer_id); if(!player) continue; // Get name of player diff --git a/src/server.h b/src/server.h index b238bec26..ab8c31a00 100644 --- a/src/server.h +++ b/src/server.h @@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "inventory.h" #include "auth.h" #include "ban.h" +struct LuaState; +typedef struct lua_State lua_State; /* Some random functions @@ -391,7 +393,7 @@ public: // Environment must be locked when called void setTimeOfDay(u32 time) { - m_env.setTimeOfDay(time); + m_env->setTimeOfDay(time); m_time_of_day_send_timer = 0; } @@ -476,6 +478,9 @@ public: // Envlock and conlock should be locked when calling this void notifyPlayer(const char *name, const std::wstring msg); void notifyPlayers(const std::wstring msg); + + // Envlock and conlock should be locked when using Lua + lua_State *getLua(){ return m_lua; } private: @@ -543,7 +548,7 @@ private: // When called, environment mutex should be locked std::string getPlayerName(u16 peer_id) { - Player *player = m_env.getPlayer(peer_id); + Player *player = m_env->getPlayer(peer_id); if(player == NULL) return "[id="+itos(peer_id); return player->getName(); @@ -582,7 +587,7 @@ private: // environment shall be locked first. // Environment - ServerEnvironment m_env; + ServerEnvironment *m_env; JMutex m_env_mutex; // Connection @@ -596,6 +601,10 @@ private: // Bann checking BanManager m_banmanager; + + // Scripting + // Envlock and conlock should be locked when using Lua + lua_State *m_lua; /* Threads diff --git a/src/serverobject.cpp b/src/serverobject.cpp index ce19ea34f..2a007bda5 100644 --- a/src/serverobject.cpp +++ b/src/serverobject.cpp @@ -21,8 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <fstream> #include "inventory.h" -ServerActiveObject::ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos): - ActiveObject(id), +ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos): + ActiveObject(0), m_known_by_count(0), m_removed(false), m_pending_deactivation(false), @@ -37,6 +37,11 @@ ServerActiveObject::~ServerActiveObject() { } +void ServerActiveObject::addedToEnvironment(u16 id) +{ + setId(id); +} + ServerActiveObject* ServerActiveObject::create(u8 type, ServerEnvironment *env, u16 id, v3f pos, const std::string &data) @@ -53,7 +58,7 @@ ServerActiveObject* ServerActiveObject::create(u8 type, } Factory f = n->getValue(); - ServerActiveObject *object = (*f)(env, id, pos, data); + ServerActiveObject *object = (*f)(env, pos, data); return object; } diff --git a/src/serverobject.h b/src/serverobject.h index cbb50949c..8d6bfd6e8 100644 --- a/src/serverobject.h +++ b/src/serverobject.h @@ -51,9 +51,11 @@ public: NOTE: m_env can be NULL, but step() isn't called if it is. Prototypes are used that way. */ - ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos); + ServerActiveObject(ServerEnvironment *env, v3f pos); virtual ~ServerActiveObject(); + virtual void addedToEnvironment(u16 id); + // Create a certain type of ServerActiveObject static ServerActiveObject* create(u8 type, ServerEnvironment *env, u16 id, v3f pos, @@ -160,7 +162,7 @@ public: protected: // Used for creating objects based on type typedef ServerActiveObject* (*Factory) - (ServerEnvironment *env, u16 id, v3f pos, + (ServerEnvironment *env, v3f pos, const std::string &data); static void registerType(u16 type, Factory f); |