)
set(common_SRCS
+ scriptapi.cpp
+ script.cpp
log.cpp
content_sao.cpp
mapgen.cpp
#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>
#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
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();
+}
+
+
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
}
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;
}
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);
#define ACTIVEOBJECT_TYPE_FIREFLY 5
#define ACTIVEOBJECT_TYPE_MOBV2 6
+#define ACTIVEOBJECT_TYPE_LUAENTITY 7
+
#endif
*/
// 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)
*/
// 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)
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);
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)
*/
// 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)
{
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);
// 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)
*/
// 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)
{
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);
// 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;
}
*/
// 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)
{
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);
// 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)
*/
// 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),
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;
}
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);
}
+/*
+ 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();
+}
+
+
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:
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();
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();
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();
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();
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();
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
#include "settings.h"
#include "log.h"
#include "profiler.h"
+#include "scriptapi.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
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),
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
n1.getContent() == CONTENT_AIR)
{
v3f pos = intToFloat(p1, BS);
- ServerActiveObject *obj = new RatSAO(this, 0, pos);
+ ServerActiveObject *obj = new RatSAO(this, pos);
addActiveObject(obj);
}
}
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);
}
}
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
<<"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();
}
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
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
class Server;
class ActiveBlockModifier;
class ServerActiveObject;
+typedef struct lua_State lua_State;
class Environment
{
class ServerEnvironment : public Environment
{
public:
- ServerEnvironment(ServerMap *map, Server *server);
+ ServerEnvironment(ServerMap *map, lua_State *L);
~ServerEnvironment();
Map & getMap()
return *m_map;
}
- Server * getServer()
+ lua_State* getLua()
{
- return m_server;
+ return m_lua;
}
- void step(f32 dtime);
-
/*
Save players
*/
// Clear all objects, loading and going through every MapBlock
void clearAllObjects();
-
+
+ void step(f32 dtime);
+
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
Create an ItemSAO
*/
// Create object
- ServerActiveObject *obj = new ItemSAO(env, 0, pos, getItemString());
+ ServerActiveObject *obj = new ItemSAO(env, pos, getItemString());
return obj;
}
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
--- /dev/null
+/*
+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
+
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;
}
{
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;
}
--- /dev/null
+/*
+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);
+}
+
+
--- /dev/null
+/*
+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
+
--- /dev/null
+/*
+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);
+}
+
--- /dev/null
+/*
+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
+
#include "settings.h"
#include "profiler.h"
#include "log.h"
+#include "script.h"
+#include "scriptapi.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
<<"("<<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;
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
//TimeTaker timer("RemoteClient::GetNextBlocks");
- Player *player = server->m_env.getPlayer(peer_id);
+ Player *player = server->m_env->getPlayer(peer_id);
assert(player != NULL);
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
/*
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;
#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;
*/
// 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();
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),
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()
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);
}
/*
{
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)
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;
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);
}
// 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;
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"));
}
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
{
//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";
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
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
{
// 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());
{
// 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;
}
}
- m_env.setKnownActiveObjects(whatever);
+ m_env->setKnownActiveObjects(whatever);
#endif
}
// Get active object messages from environment
for(;;)
{
- ActiveObjectMessage aom = m_env.getActiveObjectMessage();
+ ActiveObjectMessage aom = m_env->getActiveObjectMessage();
if(aom.id == 0)
break;
{
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
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)
{
}*/
// 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);
}
}
}
<<" has apparently closed connection. "
<<"Removing player."<<std::endl;
- m_env.removePlayer(peer_id);*/
+ m_env->removePlayer(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);
// 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);
// 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);
}
// 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());
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
return;
}
- Player *player = m_env.getPlayer(peer_id);
+ Player *player = m_env->getPlayer(peer_id);
if(player == NULL){
infostream<<"Server::ProcessData(): Cancelling: "
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)
{
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
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: "
{
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
{
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)
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
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: "
/*
Create the object
*/
- ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
+ ServerActiveObject *obj = item->createSAO(m_env, 0, pos);
if(obj == NULL)
{
<<" 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;
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)
<<" 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();
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())
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())
str_split(message, L' '),
paramstring,
this,
- &m_env,
+ m_env,
player,
privs);
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<<"): "
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();
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();
//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;
{
DSTACK(__FUNCTION_NAME);
- Player* player = m_env.getPlayer(peer_id);
+ Player* player = m_env->getPlayer(peer_id);
assert(player);
/*
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());
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
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
MapBlock *block = NULL;
try
{
- block = m_env.getMap().getBlockNoCreate(q.pos);
+ block = m_env->getMap().getBlockNoCreate(q.pos);
}
catch(InvalidPositionException &e)
{
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);
{
DSTACK(__FUNCTION_NAME);
- Player* player = m_env.getPlayer(peer_id);
+ Player* player = m_env->getPlayer(peer_id);
assert(player);
/*
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)
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"));
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);
/*
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
/*
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;
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);
Add player to environment
*/
- m_env.addPlayer(player);
+ m_env->addPlayer(player);
/*
Add stuff to inventory
{
// 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--;
// 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());
/*// 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;
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
#include "inventory.h"
#include "auth.h"
#include "ban.h"
+struct LuaState;
+typedef struct lua_State lua_State;
/*
Some random functions
// 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;
}
// 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:
// 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();
// environment shall be locked first.
// Environment
- ServerEnvironment m_env;
+ ServerEnvironment *m_env;
JMutex m_env_mutex;
// Connection
// Bann checking
BanManager m_banmanager;
+
+ // Scripting
+ // Envlock and conlock should be locked when using Lua
+ lua_State *m_lua;
/*
Threads
#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),
{
}
+void ServerActiveObject::addedToEnvironment(u16 id)
+{
+ setId(id);
+}
+
ServerActiveObject* ServerActiveObject::create(u8 type,
ServerEnvironment *env, u16 id, v3f pos,
const std::string &data)
}
Factory f = n->getValue();
- ServerActiveObject *object = (*f)(env, id, pos, data);
+ ServerActiveObject *object = (*f)(env, pos, data);
return object;
}
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,
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);