Scripting WIP

This commit is contained in:
Perttu Ahola 2011-11-11 19:33:17 +02:00
parent ee8b6d3444
commit bfc68d3151
22 changed files with 1212 additions and 187 deletions

@ -94,6 +94,8 @@ configure_file(
) )
set(common_SRCS set(common_SRCS
scriptapi.cpp
script.cpp
log.cpp log.cpp
content_sao.cpp content_sao.cpp
mapgen.cpp mapgen.cpp

@ -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),\ #define endSceneX(d){d->draw2DLine(v2s32(0,0),v2s32(1,0),\
video::SColor(255,30,30,30));d->endScene();} video::SColor(255,30,30,30));d->endScene();}
#include <irrTypes.h> #include "irrlichttypes.h"
#include <vector2d.h>
#include <vector3d.h>
#include <irrMap.h>
#include <irrList.h>
#include <irrArray.h>
#include <aabbox3d.h>
#ifndef SERVER #ifndef SERVER
#include <SColor.h> #include <SColor.h>
#include <IMesh.h> #include <IMesh.h>
@ -43,26 +38,6 @@ video::SColor(255,30,30,30));d->endScene();}
#include <IGUIElement.h> #include <IGUIElement.h>
#include <IGUIEnvironment.h> #include <IGUIEnvironment.h>
#endif #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 #endif

@ -1264,3 +1264,152 @@ void MobV2CAO::setLooks(const std::string &looks)
selection_size.X); 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();
}

@ -376,6 +376,46 @@ private:
Settings *m_properties; 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 #endif

@ -80,16 +80,16 @@ std::string item_craft_get_image_name(const std::string &subname)
} }
ServerActiveObject* item_craft_create_object(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") if(subname == "rat")
{ {
ServerActiveObject *obj = new RatSAO(env, id, pos); ServerActiveObject *obj = new RatSAO(env, pos);
return obj; return obj;
} }
else if(subname == "firefly") else if(subname == "firefly")
{ {
ServerActiveObject *obj = new FireflySAO(env, id, pos); ServerActiveObject *obj = new FireflySAO(env, pos);
return obj; return obj;
} }

@ -33,7 +33,7 @@ InventoryItem* item_material_create_cook_result(content_t content);
std::string item_craft_get_image_name(const std::string &subname); std::string item_craft_get_image_name(const std::string &subname);
ServerActiveObject* item_craft_create_object(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); s16 item_craft_get_drop_count(const std::string &subname);
bool item_craft_is_cookable(const std::string &subname); bool item_craft_is_cookable(const std::string &subname);
InventoryItem* item_craft_create_cook_result(const std::string &subname); InventoryItem* item_craft_create_cook_result(const std::string &subname);

@ -27,5 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define ACTIVEOBJECT_TYPE_FIREFLY 5 #define ACTIVEOBJECT_TYPE_FIREFLY 5
#define ACTIVEOBJECT_TYPE_MOBV2 6 #define ACTIVEOBJECT_TYPE_MOBV2 6
#define ACTIVEOBJECT_TYPE_LUAENTITY 7
#endif #endif

@ -49,20 +49,20 @@ void accelerate_xz(v3f &speed, v3f target_speed, f32 max_increase)
*/ */
// Prototype // 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): TestSAO::TestSAO(ServerEnvironment *env, v3f pos):
ServerActiveObject(env, id, pos), ServerActiveObject(env, pos),
m_timer1(0), m_timer1(0),
m_age(0) m_age(0)
{ {
ServerActiveObject::registerType(getType(), create); ServerActiveObject::registerType(getType(), create);
} }
ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos, ServerActiveObject* TestSAO::create(ServerEnvironment *env, v3f pos,
const std::string &data) const std::string &data)
{ {
return new TestSAO(env, id, pos); return new TestSAO(env, pos);
} }
void TestSAO::step(float dtime, bool send_recommended) void TestSAO::step(float dtime, bool send_recommended)
@ -107,11 +107,11 @@ void TestSAO::step(float dtime, bool send_recommended)
*/ */
// Prototype // 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): const std::string inventorystring):
ServerActiveObject(env, id, pos), ServerActiveObject(env, pos),
m_inventorystring(inventorystring), m_inventorystring(inventorystring),
m_speed_f(0,0,0), m_speed_f(0,0,0),
m_last_sent_position(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::registerType(getType(), create);
} }
ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos, ServerActiveObject* ItemSAO::create(ServerEnvironment *env, v3f pos,
const std::string &data) const std::string &data)
{ {
std::istringstream is(data, std::ios::binary); 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); std::string inventorystring = deSerializeString(is);
infostream<<"ItemSAO::create(): Creating item \"" infostream<<"ItemSAO::create(): Creating item \""
<<inventorystring<<"\""<<std::endl; <<inventorystring<<"\""<<std::endl;
return new ItemSAO(env, id, pos, inventorystring); return new ItemSAO(env, pos, inventorystring);
} }
void ItemSAO::step(float dtime, bool send_recommended) void ItemSAO::step(float dtime, bool send_recommended)
@ -260,10 +260,10 @@ void ItemSAO::rightClick(Player *player)
*/ */
// Prototype // 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): RatSAO::RatSAO(ServerEnvironment *env, v3f pos):
ServerActiveObject(env, id, pos), ServerActiveObject(env, pos),
m_is_active(false), m_is_active(false),
m_speed_f(0,0,0) m_speed_f(0,0,0)
{ {
@ -278,7 +278,7 @@ RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos):
m_touching_ground = false; m_touching_ground = false;
} }
ServerActiveObject* RatSAO::create(ServerEnvironment *env, u16 id, v3f pos, ServerActiveObject* RatSAO::create(ServerEnvironment *env, v3f pos,
const std::string &data) const std::string &data)
{ {
std::istringstream is(data, std::ios::binary); 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 // check if version is supported
if(version != 0) if(version != 0)
return NULL; return NULL;
return new RatSAO(env, id, pos); return new RatSAO(env, pos);
} }
void RatSAO::step(float dtime, bool send_recommended) void RatSAO::step(float dtime, bool send_recommended)
@ -447,10 +447,10 @@ InventoryItem* RatSAO::createPickedUpItem()
*/ */
// Prototype // 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): Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, v3f pos):
ServerActiveObject(env, id, pos), ServerActiveObject(env, pos),
m_is_active(false), m_is_active(false),
m_speed_f(0,0,0) m_speed_f(0,0,0)
{ {
@ -467,7 +467,7 @@ Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos):
m_after_jump_timer = 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) const std::string &data)
{ {
std::istringstream is(data, std::ios::binary); 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 // check if version is supported
if(version != 0) if(version != 0)
return NULL; return NULL;
Oerkki1SAO *o = new Oerkki1SAO(env, id, pos); Oerkki1SAO *o = new Oerkki1SAO(env, pos);
o->m_hp = hp; o->m_hp = hp;
return o; return o;
} }
@ -739,10 +739,10 @@ void Oerkki1SAO::doDamage(u16 d)
*/ */
// Prototype // 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): FireflySAO::FireflySAO(ServerEnvironment *env, v3f pos):
ServerActiveObject(env, id, pos), ServerActiveObject(env, pos),
m_is_active(false), m_is_active(false),
m_speed_f(0,0,0) m_speed_f(0,0,0)
{ {
@ -757,7 +757,7 @@ FireflySAO::FireflySAO(ServerEnvironment *env, u16 id, v3f pos):
m_touching_ground = false; m_touching_ground = false;
} }
ServerActiveObject* FireflySAO::create(ServerEnvironment *env, u16 id, v3f pos, ServerActiveObject* FireflySAO::create(ServerEnvironment *env, v3f pos,
const std::string &data) const std::string &data)
{ {
std::istringstream is(data, std::ios::binary); 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 // check if version is supported
if(version != 0) if(version != 0)
return NULL; return NULL;
return new FireflySAO(env, id, pos); return new FireflySAO(env, pos);
} }
void FireflySAO::step(float dtime, bool send_recommended) void FireflySAO::step(float dtime, bool send_recommended)
@ -918,11 +918,11 @@ InventoryItem* FireflySAO::createPickedUpItem()
*/ */
// Prototype // 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): Settings *init_properties):
ServerActiveObject(env, id, pos), ServerActiveObject(env, pos),
m_move_type("ground_nodes"), m_move_type("ground_nodes"),
m_speed(0,0,0), m_speed(0,0,0),
m_last_sent_position(0,0,0), m_last_sent_position(0,0,0),
@ -961,13 +961,13 @@ MobV2SAO::~MobV2SAO()
delete m_properties; delete m_properties;
} }
ServerActiveObject* MobV2SAO::create(ServerEnvironment *env, u16 id, v3f pos, ServerActiveObject* MobV2SAO::create(ServerEnvironment *env, v3f pos,
const std::string &data) const std::string &data)
{ {
std::istringstream is(data, std::ios::binary); std::istringstream is(data, std::ios::binary);
Settings properties; Settings properties;
properties.parseConfigLines(is, "MobArgsEnd"); properties.parseConfigLines(is, "MobArgsEnd");
MobV2SAO *o = new MobV2SAO(env, id, pos, &properties); MobV2SAO *o = new MobV2SAO(env, pos, &properties);
return o; return o;
} }
@ -1174,7 +1174,7 @@ void MobV2SAO::step(float dtime, bool send_recommended)
properties.set("player_hit_damage", "9"); properties.set("player_hit_damage", "9");
properties.set("player_hit_distance", "2"); properties.set("player_hit_distance", "2");
properties.set("player_hit_interval", "1"); properties.set("player_hit_interval", "1");
ServerActiveObject *obj = new MobV2SAO(m_env, 0, ServerActiveObject *obj = new MobV2SAO(m_env,
pos, &properties); pos, &properties);
//m_env->addActiveObjectAsStatic(obj); //m_env->addActiveObjectAsStatic(obj);
m_env->addActiveObject(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();
}

@ -26,10 +26,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class TestSAO : public ServerActiveObject class TestSAO : public ServerActiveObject
{ {
public: public:
TestSAO(ServerEnvironment *env, u16 id, v3f pos); TestSAO(ServerEnvironment *env, v3f pos);
u8 getType() const u8 getType() const
{return ACTIVEOBJECT_TYPE_TEST;} {return ACTIVEOBJECT_TYPE_TEST;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data); const std::string &data);
void step(float dtime, bool send_recommended); void step(float dtime, bool send_recommended);
private: private:
@ -40,11 +40,11 @@ private:
class ItemSAO : public ServerActiveObject class ItemSAO : public ServerActiveObject
{ {
public: public:
ItemSAO(ServerEnvironment *env, u16 id, v3f pos, ItemSAO(ServerEnvironment *env, v3f pos,
const std::string inventorystring); const std::string inventorystring);
u8 getType() const u8 getType() const
{return ACTIVEOBJECT_TYPE_ITEM;} {return ACTIVEOBJECT_TYPE_ITEM;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data); const std::string &data);
void step(float dtime, bool send_recommended); void step(float dtime, bool send_recommended);
std::string getClientInitializationData(); std::string getClientInitializationData();
@ -62,10 +62,10 @@ private:
class RatSAO : public ServerActiveObject class RatSAO : public ServerActiveObject
{ {
public: public:
RatSAO(ServerEnvironment *env, u16 id, v3f pos); RatSAO(ServerEnvironment *env, v3f pos);
u8 getType() const u8 getType() const
{return ACTIVEOBJECT_TYPE_RAT;} {return ACTIVEOBJECT_TYPE_RAT;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data); const std::string &data);
void step(float dtime, bool send_recommended); void step(float dtime, bool send_recommended);
std::string getClientInitializationData(); std::string getClientInitializationData();
@ -87,10 +87,10 @@ private:
class Oerkki1SAO : public ServerActiveObject class Oerkki1SAO : public ServerActiveObject
{ {
public: public:
Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos); Oerkki1SAO(ServerEnvironment *env, v3f pos);
u8 getType() const u8 getType() const
{return ACTIVEOBJECT_TYPE_OERKKI1;} {return ACTIVEOBJECT_TYPE_OERKKI1;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data); const std::string &data);
void step(float dtime, bool send_recommended); void step(float dtime, bool send_recommended);
std::string getClientInitializationData(); std::string getClientInitializationData();
@ -119,10 +119,10 @@ private:
class FireflySAO : public ServerActiveObject class FireflySAO : public ServerActiveObject
{ {
public: public:
FireflySAO(ServerEnvironment *env, u16 id, v3f pos); FireflySAO(ServerEnvironment *env, v3f pos);
u8 getType() const u8 getType() const
{return ACTIVEOBJECT_TYPE_FIREFLY;} {return ACTIVEOBJECT_TYPE_FIREFLY;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data); const std::string &data);
void step(float dtime, bool send_recommended); void step(float dtime, bool send_recommended);
std::string getClientInitializationData(); std::string getClientInitializationData();
@ -146,12 +146,12 @@ class Settings;
class MobV2SAO : public ServerActiveObject class MobV2SAO : public ServerActiveObject
{ {
public: public:
MobV2SAO(ServerEnvironment *env, u16 id, v3f pos, MobV2SAO(ServerEnvironment *env, v3f pos,
Settings *init_properties); Settings *init_properties);
virtual ~MobV2SAO(); virtual ~MobV2SAO();
u8 getType() const u8 getType() const
{return ACTIVEOBJECT_TYPE_MOBV2;} {return ACTIVEOBJECT_TYPE_MOBV2;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos, static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data); const std::string &data);
std::string getStaticData(); std::string getStaticData();
std::string getClientInitializationData(); std::string getClientInitializationData();
@ -195,5 +195,27 @@ private:
Settings *m_properties; 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 #endif

@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h" #include "settings.h"
#include "log.h" #include "log.h"
#include "profiler.h" #include "profiler.h"
#include "scriptapi.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@ -267,9 +268,9 @@ void ActiveBlockList::update(core::list<v3s16> &active_positions,
ServerEnvironment ServerEnvironment
*/ */
ServerEnvironment::ServerEnvironment(ServerMap *map, Server *server): ServerEnvironment::ServerEnvironment(ServerMap *map, lua_State *L):
m_map(map), m_map(map),
m_server(server), m_lua(L),
m_random_spawn_timer(3), m_random_spawn_timer(3),
m_send_recommended_timer(0), m_send_recommended_timer(0),
m_game_time(0), m_game_time(0),
@ -674,6 +675,8 @@ void ServerEnvironment::clearAllObjects()
obj->m_removed = true; obj->m_removed = true;
continue; continue;
} }
// Deregister in scripting api
scriptapi_rm_object_reference(m_lua, obj);
// Delete active object // Delete active object
delete obj; delete obj;
// Id to be removed from m_active_objects // Id to be removed from m_active_objects
@ -1043,7 +1046,7 @@ void ServerEnvironment::step(float dtime)
n1.getContent() == CONTENT_AIR) n1.getContent() == CONTENT_AIR)
{ {
v3f pos = intToFloat(p1, BS); v3f pos = intToFloat(p1, BS);
ServerActiveObject *obj = new RatSAO(this, 0, pos); ServerActiveObject *obj = new RatSAO(this, pos);
addActiveObject(obj); addActiveObject(obj);
} }
} }
@ -1071,21 +1074,21 @@ void ServerEnvironment::step(float dtime)
Settings properties; Settings properties;
getMob_dungeon_master(properties); getMob_dungeon_master(properties);
ServerActiveObject *obj = new MobV2SAO( ServerActiveObject *obj = new MobV2SAO(
this, 0, pos, &properties); this, pos, &properties);
addActiveObject(obj); addActiveObject(obj);
} else if(i == 2 || i == 3){ } else if(i == 2 || i == 3){
actionstream<<"Rats spawn at " actionstream<<"Rats spawn at "
<<PP(p1)<<std::endl; <<PP(p1)<<std::endl;
for(int j=0; j<3; j++){ for(int j=0; j<3; j++){
ServerActiveObject *obj = new RatSAO( ServerActiveObject *obj = new RatSAO(
this, 0, pos); this, pos);
addActiveObject(obj); addActiveObject(obj);
} }
} else { } else {
actionstream<<"An oerkki spawns at " actionstream<<"An oerkki spawns at "
<<PP(p1)<<std::endl; <<PP(p1)<<std::endl;
ServerActiveObject *obj = new Oerkki1SAO( ServerActiveObject *obj = new Oerkki1SAO(
this, 0, pos); this, pos);
addActiveObject(obj); addActiveObject(obj);
} }
} }
@ -1228,18 +1231,18 @@ void ServerEnvironment::step(float dtime)
Create a ServerActiveObject Create a ServerActiveObject
*/ */
//TestSAO *obj = new TestSAO(this, 0, pos); //TestSAO *obj = new TestSAO(this, pos);
//ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1"); //ServerActiveObject *obj = new ItemSAO(this, pos, "CraftItem Stick 1");
//ServerActiveObject *obj = new RatSAO(this, 0, pos); //ServerActiveObject *obj = new RatSAO(this, pos);
//ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos); //ServerActiveObject *obj = new Oerkki1SAO(this, pos);
//ServerActiveObject *obj = new FireflySAO(this, 0, pos); //ServerActiveObject *obj = new FireflySAO(this, pos);
infostream<<"Server: Spawning MobV2SAO at " infostream<<"Server: Spawning MobV2SAO at "
<<"("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl; <<"("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
Settings properties; Settings properties;
getMob_dungeon_master(properties); getMob_dungeon_master(properties);
ServerActiveObject *obj = new MobV2SAO(this, 0, pos, &properties); ServerActiveObject *obj = new MobV2SAO(this, pos, &properties);
addActiveObject(obj); addActiveObject(obj);
} }
#endif #endif
@ -1493,6 +1496,11 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
<<"could not find block for storing id="<<object->getId() <<"could not find block for storing id="<<object->getId()
<<" statically"<<std::endl; <<" 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(); return object->getId();
} }
@ -1544,6 +1552,9 @@ void ServerEnvironment::removeRemovedObjects()
if(obj->m_known_by_count > 0) if(obj->m_known_by_count > 0)
continue; continue;
// Deregister in scripting api
scriptapi_rm_object_reference(m_lua, obj);
// Delete // Delete
delete obj; delete obj;
// Id to be removed from m_active_objects // Id to be removed from m_active_objects
@ -1815,6 +1826,10 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
verbosestream<<"ServerEnvironment::deactivateFarObjects(): " verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
<<"object id="<<id<<" is not known by clients" <<"object id="<<id<<" is not known by clients"
<<"; deleting"<<std::endl; <<"; deleting"<<std::endl;
// Deregister in scripting api
scriptapi_rm_object_reference(m_lua, obj);
// Delete active object // Delete active object
delete obj; delete obj;
// Id to be removed from m_active_objects // Id to be removed from m_active_objects

@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Server; class Server;
class ActiveBlockModifier; class ActiveBlockModifier;
class ServerActiveObject; class ServerActiveObject;
typedef struct lua_State lua_State;
class Environment class Environment
{ {
@ -126,7 +127,7 @@ private:
class ServerEnvironment : public Environment class ServerEnvironment : public Environment
{ {
public: public:
ServerEnvironment(ServerMap *map, Server *server); ServerEnvironment(ServerMap *map, lua_State *L);
~ServerEnvironment(); ~ServerEnvironment();
Map & getMap() Map & getMap()
@ -139,13 +140,11 @@ public:
return *m_map; return *m_map;
} }
Server * getServer() lua_State* getLua()
{ {
return m_server; return m_lua;
} }
void step(f32 dtime);
/* /*
Save players Save players
*/ */
@ -222,7 +221,9 @@ public:
// Clear all objects, loading and going through every MapBlock // Clear all objects, loading and going through every MapBlock
void clearAllObjects(); void clearAllObjects();
void step(f32 dtime);
private: private:
/* /*
@ -269,8 +270,8 @@ private:
// The map // The map
ServerMap *m_map; ServerMap *m_map;
// Pointer to server (which is handling this environment) // Lua state
Server *m_server; lua_State *m_lua;
// Active object list // Active object list
core::map<u16, ServerActiveObject*> m_active_objects; core::map<u16, ServerActiveObject*> m_active_objects;
// Outgoing network message buffer for active objects // Outgoing network message buffer for active objects

@ -136,7 +136,7 @@ ServerActiveObject* InventoryItem::createSAO(ServerEnvironment *env, u16 id, v3f
Create an ItemSAO Create an ItemSAO
*/ */
// Create object // Create object
ServerActiveObject *obj = new ItemSAO(env, 0, pos, getItemString()); ServerActiveObject *obj = new ItemSAO(env, pos, getItemString());
return obj; return obj;
} }
@ -174,7 +174,7 @@ video::ITexture * CraftItem::getImage() const
ServerActiveObject* CraftItem::createSAO(ServerEnvironment *env, u16 id, v3f pos) ServerActiveObject* CraftItem::createSAO(ServerEnvironment *env, u16 id, v3f pos)
{ {
// Special cases // 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) if(obj)
return obj; return obj;
// Default // Default

52
src/irrlichttypes.h Normal file

@ -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

@ -56,9 +56,10 @@ void sigint_handler(int sig)
dstream<<DTIME<<"INFO: sigint_handler(): " dstream<<DTIME<<"INFO: sigint_handler(): "
<<"Ctrl-C pressed, shutting down."<<std::endl; <<"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; <<"Printing debug stacks"<<std::endl;
debug_stacks_print(); debug_stacks_print();*/
g_killed = true; g_killed = true;
} }
@ -91,9 +92,10 @@ void signal_handler_init(void)
{ {
dstream<<DTIME<<"INFO: event_handler(): " dstream<<DTIME<<"INFO: event_handler(): "
<<"Ctrl+C, Close Event, Logoff Event or Shutdown Event, shutting down."<<std::endl; <<"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; <<"Printing debug stacks"<<std::endl;
debug_stacks_print(); debug_stacks_print();*/
g_killed = true; g_killed = true;
} }

130
src/script.cpp Normal file

@ -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);
}

33
src/script.h Normal file

@ -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

422
src/scriptapi.cpp Normal file

@ -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);
}

43
src/scriptapi.h Normal file

@ -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

@ -39,6 +39,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h" #include "settings.h"
#include "profiler.h" #include "profiler.h"
#include "log.h" #include "log.h"
#include "script.h"
#include "scriptapi.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@ -185,7 +187,7 @@ void * EmergeThread::Thread()
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<") " <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
<<"only_from_disk="<<only_from_disk<<std::endl; <<"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*> changed_blocks;
//core::map<v3s16, MapBlock*> lighting_invalidated_blocks; //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
@ -250,7 +252,7 @@ void * EmergeThread::Thread()
MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events); MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
// Activate objects and stuff // Activate objects and stuff
m_server->m_env.activateBlock(block, 3600); m_server->m_env->activateBlock(block, 3600);
} }
} }
else else
@ -371,7 +373,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
//TimeTaker timer("RemoteClient::GetNextBlocks"); //TimeTaker timer("RemoteClient::GetNextBlocks");
Player *player = server->m_env.getPlayer(peer_id); Player *player = server->m_env->getPlayer(peer_id);
assert(player != NULL); assert(player != NULL);
@ -572,7 +574,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
MAP_BLOCKSIZE*p.Z); MAP_BLOCKSIZE*p.Z);
// Get ground height in nodes // Get ground height in nodes
s16 gh = server->m_env.getServerMap().findGroundLevel( s16 gh = server->m_env->getServerMap().findGroundLevel(
p2d_nodes_center); p2d_nodes_center);
// If differs a lot, don't generate // If differs a lot, don't generate
@ -611,7 +613,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
/* /*
Check if map has this block 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 surely_not_found_on_disk = false;
bool block_is_invalid = false; bool block_is_invalid = false;
@ -640,7 +642,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
#if 0 #if 0
v2s16 p2d(p.X, p.Z); 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); v2s16 chunkpos = map->sector_to_chunk(p2d);
if(map->chunkNonVolatile(chunkpos) == false) if(map->chunkNonVolatile(chunkpos) == false)
block_is_invalid = true; block_is_invalid = true;
@ -802,7 +804,7 @@ void RemoteClient::SendObjectData(
*/ */
// Get connected players // Get connected players
core::list<Player*> players = server->m_env.getPlayers(true); core::list<Player*> players = server->m_env->getPlayers(true);
// Write player count // Write player count
u16 playercount = players.size(); u16 playercount = players.size();
@ -948,10 +950,12 @@ Server::Server(
std::string mapsavedir, std::string mapsavedir,
std::string configpath std::string configpath
): ):
m_env(new ServerMap(mapsavedir), this), m_env(NULL),
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"), m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"), m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
m_lua(NULL),
//m_scriptapi(NULL),
m_thread(this), m_thread(this),
m_emergethread(this), m_emergethread(this),
m_time_counter(0), m_time_counter(0),
@ -973,20 +977,38 @@ Server::Server(
m_con_mutex.Init(); m_con_mutex.Init();
m_step_dtime_mutex.Init(); m_step_dtime_mutex.Init();
m_step_dtime = 0.0; 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 // Register us to receive map edit events
m_env.getMap().addEventReceiver(this); m_env->getMap().addEventReceiver(this);
// If file exists, load environment metadata // If file exists, load environment metadata
if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt")) if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt"))
{ {
infostream<<"Server: Loading environment metadata"<<std::endl; infostream<<"Server: Loading environment metadata"<<std::endl;
m_env.loadMeta(m_mapsavedir); m_env->loadMeta(m_mapsavedir);
} }
// Load players // Load players
infostream<<"Server: Loading players"<<std::endl; infostream<<"Server: Loading players"<<std::endl;
m_env.deSerializePlayers(m_mapsavedir); m_env->deSerializePlayers(m_mapsavedir);
} }
Server::~Server() Server::~Server()
@ -1029,13 +1051,13 @@ Server::~Server()
Save players Save players
*/ */
infostream<<"Server: Saving players"<<std::endl; infostream<<"Server: Saving players"<<std::endl;
m_env.serializePlayers(m_mapsavedir); m_env->serializePlayers(m_mapsavedir);
/* /*
Save environment metadata Save environment metadata
*/ */
infostream<<"Server: Saving environment metadata"<<std::endl; 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(); u16 peer_id = i.getNode()->getKey();
JMutexAutoLock envlock(m_env_mutex); JMutexAutoLock envlock(m_env_mutex);
m_env.removePlayer(peer_id); m_env->removePlayer(peer_id);
}*/ }*/
// Delete client // Delete client
delete i.getNode()->getValue(); 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) void Server::start(unsigned short port)
@ -1173,7 +1202,7 @@ void Server::AsyncRunStep()
u32 units = (u32)(m_time_counter*speed); u32 units = (u32)(m_time_counter*speed);
m_time_counter -= (f32)units / 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; //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
@ -1194,10 +1223,10 @@ void Server::AsyncRunStep()
i.atEnd() == false; i++) i.atEnd() == false; i++)
{ {
RemoteClient *client = i.getNode()->getValue(); 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( SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
m_env.getTimeOfDay()); m_env->getTimeOfDay());
// Send as reliable // Send as reliable
m_con.Send(client->peer_id, 0, data, true); m_con.Send(client->peer_id, 0, data, true);
} }
@ -1209,7 +1238,7 @@ void Server::AsyncRunStep()
// Step environment // Step environment
ScopeProfiler sp(g_profiler, "SEnv step"); ScopeProfiler sp(g_profiler, "SEnv step");
ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG); 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; const float map_timer_and_unload_dtime = 5.15;
@ -1218,7 +1247,7 @@ void Server::AsyncRunStep()
JMutexAutoLock lock(m_env_mutex); JMutexAutoLock lock(m_env_mutex);
// Run Map's timers and unload unused data // Run Map's timers and unload unused data
ScopeProfiler sp(g_profiler, "Server: map timer and unload"); 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")); g_settings->getFloat("server_unload_unused_data_timeout"));
} }
@ -1239,13 +1268,13 @@ void Server::AsyncRunStep()
ScopeProfiler sp(g_profiler, "Server: liquid transform"); ScopeProfiler sp(g_profiler, "Server: liquid transform");
core::map<v3s16, MapBlock*> modified_blocks; core::map<v3s16, MapBlock*> modified_blocks;
m_env.getMap().transformLiquids(modified_blocks); m_env->getMap().transformLiquids(modified_blocks);
#if 0 #if 0
/* /*
Update lighting Update lighting
*/ */
core::map<v3s16, MapBlock*> lighting_modified_blocks; 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); map.updateLighting(modified_blocks, lighting_modified_blocks);
// Add blocks modified by lighting to modified_blocks // Add blocks modified by lighting to modified_blocks
@ -1295,7 +1324,7 @@ void Server::AsyncRunStep()
{ {
//u16 peer_id = i.getNode()->getKey(); //u16 peer_id = i.getNode()->getKey();
RemoteClient *client = i.getNode()->getValue(); RemoteClient *client = i.getNode()->getValue();
Player *player = m_env.getPlayer(client->peer_id); Player *player = m_env->getPlayer(client->peer_id);
if(player==NULL) if(player==NULL)
continue; continue;
infostream<<"* "<<player->getName()<<"\t"; infostream<<"* "<<player->getName()<<"\t";
@ -1326,7 +1355,7 @@ void Server::AsyncRunStep()
i.atEnd() == false; i++) i.atEnd() == false; i++)
{ {
RemoteClient *client = i.getNode()->getValue(); RemoteClient *client = i.getNode()->getValue();
Player *player = m_env.getPlayer(client->peer_id); Player *player = m_env->getPlayer(client->peer_id);
if(player==NULL) if(player==NULL)
{ {
// This can happen if the client timeouts somehow // 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> removed_objects;
core::map<u16, bool> added_objects; core::map<u16, bool> added_objects;
m_env.getRemovedActiveObjects(pos, radius, m_env->getRemovedActiveObjects(pos, radius,
client->m_known_objects, removed_objects); client->m_known_objects, removed_objects);
m_env.getAddedActiveObjects(pos, radius, m_env->getAddedActiveObjects(pos, radius,
client->m_known_objects, added_objects); client->m_known_objects, added_objects);
// Ignore if nothing happened // Ignore if nothing happened
@ -1364,7 +1393,7 @@ void Server::AsyncRunStep()
{ {
// Get object // Get object
u16 id = i.getNode()->getKey(); u16 id = i.getNode()->getKey();
ServerActiveObject* obj = m_env.getActiveObject(id); ServerActiveObject* obj = m_env->getActiveObject(id);
// Add to data buffer for sending // Add to data buffer for sending
writeU16((u8*)buf, i.getNode()->getKey()); writeU16((u8*)buf, i.getNode()->getKey());
@ -1386,7 +1415,7 @@ void Server::AsyncRunStep()
{ {
// Get object // Get object
u16 id = i.getNode()->getKey(); u16 id = i.getNode()->getKey();
ServerActiveObject* obj = m_env.getActiveObject(id); ServerActiveObject* obj = m_env->getActiveObject(id);
// Get object type // Get object type
u8 type = ACTIVEOBJECT_TYPE_INVALID; u8 type = ACTIVEOBJECT_TYPE_INVALID;
@ -1452,7 +1481,7 @@ void Server::AsyncRunStep()
} }
} }
m_env.setKnownActiveObjects(whatever); m_env->setKnownActiveObjects(whatever);
#endif #endif
} }
@ -1473,7 +1502,7 @@ void Server::AsyncRunStep()
// Get active object messages from environment // Get active object messages from environment
for(;;) for(;;)
{ {
ActiveObjectMessage aom = m_env.getActiveObjectMessage(); ActiveObjectMessage aom = m_env->getActiveObjectMessage();
if(aom.id == 0) if(aom.id == 0)
break; break;
@ -1662,7 +1691,7 @@ void Server::AsyncRunStep()
{ {
v3s16 p = i.getNode()->getKey(); v3s16 p = i.getNode()->getKey();
modified_blocks2.insert(p, modified_blocks2.insert(p,
m_env.getMap().getBlockNoCreateNoEx(p)); m_env->getMap().getBlockNoCreateNoEx(p));
} }
// Set blocks not sent // Set blocks not sent
for(core::list<u16>::Iterator for(core::list<u16>::Iterator
@ -1749,15 +1778,15 @@ void Server::AsyncRunStep()
JMutexAutoLock lock(m_env_mutex); JMutexAutoLock lock(m_env_mutex);
/*// Unload unused data (delete from memory) /*// Unload unused data (delete from memory)
m_env.getMap().unloadUnusedData( m_env->getMap().unloadUnusedData(
g_settings->getFloat("server_unload_unused_sectors_timeout")); 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")); g_settings->getFloat("server_unload_unused_sectors_timeout"));
*/ */
// Save only changed parts // Save only changed parts
m_env.getMap().save(true); m_env->getMap().save(true);
/*if(deleted_count > 0) /*if(deleted_count > 0)
{ {
@ -1766,10 +1795,10 @@ void Server::AsyncRunStep()
}*/ }*/
// Save players // Save players
m_env.serializePlayers(m_mapsavedir); m_env->serializePlayers(m_mapsavedir);
// Save environment metadata // Save environment metadata
m_env.saveMeta(m_mapsavedir); m_env->saveMeta(m_mapsavedir);
} }
} }
} }
@ -1811,7 +1840,7 @@ void Server::Receive()
<<" has apparently closed connection. " <<" has apparently closed connection. "
<<"Removing player."<<std::endl; <<"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); writeU16(&reply[0], TOCLIENT_INIT);
writeU8(&reply[2], deployed); writeU8(&reply[2], deployed);
writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS)); 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 // Send as reliable
m_con.Send(peer_id, 0, reply, true); 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 // Send player items to all players
SendPlayerItems(); SendPlayerItems();
Player *player = m_env.getPlayer(peer_id); Player *player = m_env->getPlayer(peer_id);
// Send HP // Send HP
SendPlayerHP(player); SendPlayerHP(player);
@ -2071,7 +2100,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Send time of day // Send time of day
{ {
SharedBuffer<u8> data = makePacket_TOCLIENT_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); 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 // Send information about joining in chat
{ {
std::wstring name = L"unknown"; std::wstring name = L"unknown";
Player *player = m_env.getPlayer(peer_id); Player *player = m_env->getPlayer(peer_id);
if(player != NULL) if(player != NULL)
name = narrow_to_wide(player->getName()); 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) if(client->serialization_version == SER_FMT_VER_INVALID)
continue; continue;
// Get player // Get player
Player *player = m_env.getPlayer(client->peer_id); Player *player = m_env->getPlayer(client->peer_id);
if(!player) if(!player)
continue; continue;
// Get name of player // Get name of player
@ -2139,7 +2168,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return; return;
} }
Player *player = m_env.getPlayer(peer_id); Player *player = m_env->getPlayer(peer_id);
if(player == NULL){ if(player == NULL){
infostream<<"Server::ProcessData(): Cancelling: " infostream<<"Server::ProcessData(): Cancelling: "
@ -2247,7 +2276,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
u16 id = readS16(&data[3]); u16 id = readS16(&data[3]);
u16 item_i = readU16(&data[5]); u16 item_i = readU16(&data[5]);
ServerActiveObject *obj = m_env.getActiveObject(id); ServerActiveObject *obj = m_env->getActiveObject(id);
if(obj == NULL) if(obj == NULL)
{ {
@ -2421,7 +2450,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
try try
{ {
MapNode n = m_env.getMap().getNode(p_under); MapNode n = m_env->getMap().getNode(p_under);
// Get mineral // Get mineral
mineral = n.getMineral(); mineral = n.getMineral();
// Get material at position // Get material at position
@ -2442,7 +2471,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(cannot_remove_node == false) if(cannot_remove_node == false)
{ {
// Get node metadata // Get node metadata
NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under); NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
if(meta && meta->nodeRemovalDisabled() == true) if(meta && meta->nodeRemovalDisabled() == true)
{ {
infostream<<"Server: Not finishing digging: " 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); 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 Set blocks not sent to far players
@ -2649,7 +2678,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{ {
try{ try{
// Don't add a node if this is not a free space // 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 = bool no_enough_privs =
((getPlayerPrivs(player) & PRIV_BUILD)==0); ((getPlayerPrivs(player) & PRIV_BUILD)==0);
if(no_enough_privs) 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); MapEditEventIgnorer ign(&m_ignore_map_edit_events);
std::string p_name = std::string(player->getName()); 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 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 Check that the block is loaded so that the item
can properly be added to the static list too 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) if(block==NULL)
{ {
infostream<<"Error while placing object: " infostream<<"Error while placing object: "
@ -2823,7 +2852,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
/* /*
Create the object Create the object
*/ */
ServerActiveObject *obj = item->createSAO(&m_env, 0, pos); ServerActiveObject *obj = item->createSAO(m_env, 0, pos);
if(obj == NULL) if(obj == NULL)
{ {
@ -2837,7 +2866,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<" at "<<PP(p_over)<<std::endl; <<" at "<<PP(p_over)<<std::endl;
// Add the object to the environment // Add the object to the environment
m_env.addActiveObject(obj); m_env->addActiveObject(obj);
infostream<<"Placed object"<<std::endl; infostream<<"Placed object"<<std::endl;
@ -2924,7 +2953,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
text += (char)buf[0]; text += (char)buf[0];
} }
NodeMetadata *meta = m_env.getMap().getNodeMetadata(p); NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
if(!meta) if(!meta)
return; return;
if(meta->typeId() != CONTENT_SIGN_WALL) 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; <<" at "<<PP(p)<<std::endl;
v3s16 blockpos = getNodeBlockPos(p); v3s16 blockpos = getNodeBlockPos(p);
MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos); MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
if(block) if(block)
{ {
block->setChangedFlag(); block->setChangedFlag();
@ -3052,7 +3081,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
p.X = stoi(fn.next(",")); p.X = stoi(fn.next(","));
p.Y = stoi(fn.next(",")); p.Y = stoi(fn.next(","));
p.Z = 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) { if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta; LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
if (lcm->getOwner() != player->getName()) 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.X = stoi(fn.next(","));
p.Y = stoi(fn.next(",")); p.Y = stoi(fn.next(","));
p.Z = 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) { if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta; LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
if (lcm->getOwner() != player->getName()) if (lcm->getOwner() != player->getName())
@ -3153,7 +3182,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
str_split(message, L' '), str_split(message, L' '),
paramstring, paramstring,
this, this,
&m_env, m_env,
player, player,
privs); privs);
@ -3356,7 +3385,7 @@ Inventory* Server::getInventory(InventoryContext *c, std::string id)
p.X = stoi(fn.next(",")); p.X = stoi(fn.next(","));
p.Y = stoi(fn.next(",")); p.Y = stoi(fn.next(","));
p.Z = stoi(fn.next(",")); p.Z = stoi(fn.next(","));
NodeMetadata *meta = m_env.getMap().getNodeMetadata(p); NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
if(meta) if(meta)
return meta->getInventory(); return meta->getInventory();
infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): " 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(",")); p.Z = stoi(fn.next(","));
v3s16 blockpos = getNodeBlockPos(p); v3s16 blockpos = getNodeBlockPos(p);
NodeMetadata *meta = m_env.getMap().getNodeMetadata(p); NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
if(meta) if(meta)
meta->inventoryModified(); meta->inventoryModified();
@ -3415,7 +3444,7 @@ core::list<PlayerInfo> Server::getPlayerInfo()
core::list<PlayerInfo> list; core::list<PlayerInfo> list;
core::list<Player*> players = m_env.getPlayers(); core::list<Player*> players = m_env->getPlayers();
core::list<Player*>::Iterator i; core::list<Player*>::Iterator i;
for(i = players.begin(); for(i = players.begin();
@ -3559,7 +3588,7 @@ void Server::SendPlayerInfos()
//JMutexAutoLock envlock(m_env_mutex); //JMutexAutoLock envlock(m_env_mutex);
// Get connected players // 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 player_count = players.getSize();
u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count; u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
@ -3593,7 +3622,7 @@ void Server::SendInventory(u16 peer_id)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
Player* player = m_env.getPlayer(peer_id); Player* player = m_env->getPlayer(peer_id);
assert(player); assert(player);
/* /*
@ -3650,7 +3679,7 @@ void Server::SendPlayerItems()
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary); 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, TOCLIENT_PLAYERITEM);
writeU16(os, players.size()); writeU16(os, players.size());
@ -3779,7 +3808,7 @@ void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
if(far_players) if(far_players)
{ {
// Get player // Get player
Player *player = m_env.getPlayer(client->peer_id); Player *player = m_env->getPlayer(client->peer_id);
if(player) if(player)
{ {
// If player is far away, only set modified blocks not sent // 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) if(far_players)
{ {
// Get player // Get player
Player *player = m_env.getPlayer(client->peer_id); Player *player = m_env->getPlayer(client->peer_id);
if(player) if(player)
{ {
// If player is far away, only set modified blocks not sent // If player is far away, only set modified blocks not sent
@ -3960,7 +3989,7 @@ void Server::SendBlocks(float dtime)
MapBlock *block = NULL; MapBlock *block = NULL;
try try
{ {
block = m_env.getMap().getBlockNoCreate(q.pos); block = m_env->getMap().getBlockNoCreate(q.pos);
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
{ {
@ -4019,7 +4048,7 @@ void Server::HandlePlayerHP(Player *player, s16 damage)
void Server::RespawnPlayer(Player *player) void Server::RespawnPlayer(Player *player)
{ {
v3f pos = findSpawnPos(m_env.getServerMap()); v3f pos = findSpawnPos(m_env->getServerMap());
player->setPosition(pos); player->setPosition(pos);
player->hp = 20; player->hp = 20;
SendMovePlayer(player); SendMovePlayer(player);
@ -4030,7 +4059,7 @@ void Server::UpdateCrafting(u16 peer_id)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
Player* player = m_env.getPlayer(peer_id); Player* player = m_env->getPlayer(peer_id);
assert(player); assert(player);
/* /*
@ -4096,7 +4125,7 @@ std::wstring Server::getStatusString()
if(client->serialization_version == SER_FMT_VER_INVALID) if(client->serialization_version == SER_FMT_VER_INVALID)
continue; continue;
// Get player // Get player
Player *player = m_env.getPlayer(client->peer_id); Player *player = m_env->getPlayer(client->peer_id);
// Get name of player // Get name of player
std::wstring name = L"unknown"; std::wstring name = L"unknown";
if(player != NULL) if(player != NULL)
@ -4105,7 +4134,7 @@ std::wstring Server::getStatusString()
os<<name<<L","; os<<name<<L",";
} }
os<<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."; os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
if(g_settings->get("motd") != "") if(g_settings->get("motd") != "")
os<<std::endl<<L"# Server: "<<narrow_to_wide(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) void Server::notifyPlayer(const char *name, const std::wstring msg)
{ {
Player *player = m_env.getPlayer(name); Player *player = m_env->getPlayer(name);
if(!player) if(!player)
return; return;
SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg); 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 Try to get an existing player
*/ */
Player *player = m_env.getPlayer(name); Player *player = m_env->getPlayer(name);
if(player != NULL) if(player != NULL)
{ {
// If player is already connected, cancel // 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 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" infostream<<"emergePlayer(): Player with wrong name but same"
" peer_id already exists"<<std::endl; " 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 \"" infostream<<"Server: Finding spawn place for player \""
<<player->getName()<<"\""<<std::endl; <<player->getName()<<"\""<<std::endl;
v3f pos = findSpawnPos(m_env.getServerMap()); v3f pos = findSpawnPos(m_env->getServerMap());
player->setPosition(pos); player->setPosition(pos);
@ -4266,7 +4295,7 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
Add player to environment Add player to environment
*/ */
m_env.addPlayer(player); m_env->addPlayer(player);
/* /*
Add stuff to inventory Add stuff to inventory
@ -4337,7 +4366,7 @@ void Server::handlePeerChange(PeerChange &c)
{ {
// Get object // Get object
u16 id = i.getNode()->getKey(); 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) if(obj && obj->m_known_by_count > 0)
obj->m_known_by_count--; obj->m_known_by_count--;
@ -4346,7 +4375,7 @@ void Server::handlePeerChange(PeerChange &c)
// Collect information about leaving in chat // Collect information about leaving in chat
std::wstring message; std::wstring message;
{ {
Player *player = m_env.getPlayer(c.peer_id); Player *player = m_env->getPlayer(c.peer_id);
if(player != NULL) if(player != NULL)
{ {
std::wstring name = narrow_to_wide(player->getName()); std::wstring name = narrow_to_wide(player->getName());
@ -4360,12 +4389,12 @@ void Server::handlePeerChange(PeerChange &c)
/*// Delete player /*// Delete player
{ {
m_env.removePlayer(c.peer_id); m_env->removePlayer(c.peer_id);
}*/ }*/
// Set player client disconnected // Set player client disconnected
{ {
Player *player = m_env.getPlayer(c.peer_id); Player *player = m_env->getPlayer(c.peer_id);
if(player != NULL) if(player != NULL)
player->peer_id = 0; player->peer_id = 0;
@ -4384,7 +4413,7 @@ void Server::handlePeerChange(PeerChange &c)
if(client->serialization_version == SER_FMT_VER_INVALID) if(client->serialization_version == SER_FMT_VER_INVALID)
continue; continue;
// Get player // Get player
Player *player = m_env.getPlayer(client->peer_id); Player *player = m_env->getPlayer(client->peer_id);
if(!player) if(!player)
continue; continue;
// Get name of player // Get name of player

@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventory.h" #include "inventory.h"
#include "auth.h" #include "auth.h"
#include "ban.h" #include "ban.h"
struct LuaState;
typedef struct lua_State lua_State;
/* /*
Some random functions Some random functions
@ -391,7 +393,7 @@ public:
// Environment must be locked when called // Environment must be locked when called
void setTimeOfDay(u32 time) void setTimeOfDay(u32 time)
{ {
m_env.setTimeOfDay(time); m_env->setTimeOfDay(time);
m_time_of_day_send_timer = 0; m_time_of_day_send_timer = 0;
} }
@ -476,6 +478,9 @@ public:
// Envlock and conlock should be locked when calling this // Envlock and conlock should be locked when calling this
void notifyPlayer(const char *name, const std::wstring msg); void notifyPlayer(const char *name, const std::wstring msg);
void notifyPlayers(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: private:
@ -543,7 +548,7 @@ private:
// When called, environment mutex should be locked // When called, environment mutex should be locked
std::string getPlayerName(u16 peer_id) std::string getPlayerName(u16 peer_id)
{ {
Player *player = m_env.getPlayer(peer_id); Player *player = m_env->getPlayer(peer_id);
if(player == NULL) if(player == NULL)
return "[id="+itos(peer_id); return "[id="+itos(peer_id);
return player->getName(); return player->getName();
@ -582,7 +587,7 @@ private:
// environment shall be locked first. // environment shall be locked first.
// Environment // Environment
ServerEnvironment m_env; ServerEnvironment *m_env;
JMutex m_env_mutex; JMutex m_env_mutex;
// Connection // Connection
@ -596,6 +601,10 @@ private:
// Bann checking // Bann checking
BanManager m_banmanager; BanManager m_banmanager;
// Scripting
// Envlock and conlock should be locked when using Lua
lua_State *m_lua;
/* /*
Threads Threads

@ -21,8 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <fstream> #include <fstream>
#include "inventory.h" #include "inventory.h"
ServerActiveObject::ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos): ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos):
ActiveObject(id), ActiveObject(0),
m_known_by_count(0), m_known_by_count(0),
m_removed(false), m_removed(false),
m_pending_deactivation(false), m_pending_deactivation(false),
@ -37,6 +37,11 @@ ServerActiveObject::~ServerActiveObject()
{ {
} }
void ServerActiveObject::addedToEnvironment(u16 id)
{
setId(id);
}
ServerActiveObject* ServerActiveObject::create(u8 type, ServerActiveObject* ServerActiveObject::create(u8 type,
ServerEnvironment *env, u16 id, v3f pos, ServerEnvironment *env, u16 id, v3f pos,
const std::string &data) const std::string &data)
@ -53,7 +58,7 @@ ServerActiveObject* ServerActiveObject::create(u8 type,
} }
Factory f = n->getValue(); Factory f = n->getValue();
ServerActiveObject *object = (*f)(env, id, pos, data); ServerActiveObject *object = (*f)(env, pos, data);
return object; return object;
} }

@ -51,9 +51,11 @@ public:
NOTE: m_env can be NULL, but step() isn't called if it is. NOTE: m_env can be NULL, but step() isn't called if it is.
Prototypes are used that way. Prototypes are used that way.
*/ */
ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos); ServerActiveObject(ServerEnvironment *env, v3f pos);
virtual ~ServerActiveObject(); virtual ~ServerActiveObject();
virtual void addedToEnvironment(u16 id);
// Create a certain type of ServerActiveObject // Create a certain type of ServerActiveObject
static ServerActiveObject* create(u8 type, static ServerActiveObject* create(u8 type,
ServerEnvironment *env, u16 id, v3f pos, ServerEnvironment *env, u16 id, v3f pos,
@ -160,7 +162,7 @@ public:
protected: protected:
// Used for creating objects based on type // Used for creating objects based on type
typedef ServerActiveObject* (*Factory) typedef ServerActiveObject* (*Factory)
(ServerEnvironment *env, u16 id, v3f pos, (ServerEnvironment *env, v3f pos,
const std::string &data); const std::string &data);
static void registerType(u16 type, Factory f); static void registerType(u16 type, Factory f);