Some work-in-progress in hp and mobs and a frightening amount of random fixes.

This commit is contained in:
Perttu Ahola 2011-04-21 19:35:17 +03:00
parent 3c61d57f6d
commit c638442e78
40 changed files with 1837 additions and 920 deletions

BIN
data/heart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

BIN
data/oerkki1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 947 B

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 990 B

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 B

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 990 B

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 B

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 989 B

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 B

After

Width:  |  Height:  |  Size: 203 B

@ -52,6 +52,8 @@
# Set to true to enable creative mode (unlimited inventory) # Set to true to enable creative mode (unlimited inventory)
#creative_mode = false #creative_mode = false
#enable_damage = false
# Player and object positions are sent at intervals specified by this # Player and object positions are sent at intervals specified by this
#objectdata_inverval = 0.2 #objectdata_inverval = 0.2

@ -40,6 +40,7 @@ struct ActiveObjectMessage
#define ACTIVEOBJECT_TYPE_TEST 1 #define ACTIVEOBJECT_TYPE_TEST 1
#define ACTIVEOBJECT_TYPE_ITEM 2 #define ACTIVEOBJECT_TYPE_ITEM 2
#define ACTIVEOBJECT_TYPE_RAT 3 #define ACTIVEOBJECT_TYPE_RAT 3
#define ACTIVEOBJECT_TYPE_OERKKI1 4
/* /*
Parent class for ServerActiveObject and ClientActiveObject Parent class for ServerActiveObject and ClientActiveObject

@ -90,6 +90,7 @@ Client::Client(
m_connection_reinit_timer = 0.0; m_connection_reinit_timer = 0.0;
m_avg_rtt_timer = 0.0; m_avg_rtt_timer = 0.0;
m_playerpos_send_timer = 0.0; m_playerpos_send_timer = 0.0;
m_ignore_damage_timer = 0.0;
//m_env_mutex.Init(); //m_env_mutex.Init();
//m_con_mutex.Init(); //m_con_mutex.Init();
@ -154,6 +155,10 @@ void Client::step(float dtime)
if(dtime > 2.0) if(dtime > 2.0)
dtime = 2.0; dtime = 2.0;
if(m_ignore_damage_timer > dtime)
m_ignore_damage_timer -= dtime;
else
m_ignore_damage_timer = 0.0;
//dstream<<"Client steps "<<dtime<<std::endl; //dstream<<"Client steps "<<dtime<<std::endl;
@ -311,6 +316,9 @@ void Client::step(float dtime)
Do stuff if connected Do stuff if connected
*/ */
/*
Handle environment
*/
{ {
// 0ms // 0ms
//JMutexAutoLock lock(m_env_mutex); //bulk comment-out //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
@ -341,8 +349,37 @@ void Client::step(float dtime)
{ {
} }
} }
/*
Get events
*/
for(;;)
{
ClientEnvEvent event = m_env.getClientEvent();
if(event.type == CEE_NONE)
{
break;
}
else if(event.type == CEE_PLAYER_DAMAGE)
{
if(m_ignore_damage_timer <= 0)
{
u8 damage = event.player_damage.amount;
sendDamage(damage);
// Add to ClientEvent queue
ClientEvent event;
event.type = CE_PLAYER_DAMAGE;
event.player_damage.amount = damage;
m_client_event_queue.push_back(event);
}
}
}
} }
/*
Print some info
*/
{ {
float &counter = m_avg_rtt_timer; float &counter = m_avg_rtt_timer;
counter += dtime; counter += dtime;
@ -355,6 +392,10 @@ void Client::step(float dtime)
dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl; dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
} }
} }
/*
Send player position to server
*/
{ {
float &counter = m_playerpos_send_timer; float &counter = m_playerpos_send_timer;
counter += dtime; counter += dtime;
@ -388,6 +429,8 @@ void Client::step(float dtime)
} }
if(r.ack_block_to_server) if(r.ack_block_to_server)
{ {
/*dstream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
<<","<<r.p.Z<<")"<<std::endl;*/
/* /*
Acknowledge block Acknowledge block
*/ */
@ -447,7 +490,7 @@ void Client::ReceiveAll()
void Client::Receive() void Client::Receive()
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
u32 data_maxsize = 10000; u32 data_maxsize = 200000;
Buffer<u8> data(data_maxsize); Buffer<u8> data(data_maxsize);
u16 sender_peer_id; u16 sender_peer_id;
u32 datasize; u32 datasize;
@ -1294,248 +1337,63 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
} }
} }
} }
else else if(command == TOCLIENT_HP)
{ {
dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command " std::string datastring((char*)&data[2], datasize-2);
<<command<<std::endl; std::istringstream is(datastring, std::ios_base::binary);
Player *player = m_env.getLocalPlayer();
assert(player != NULL);
u8 hp = readU8(is);
player->hp = hp;
} }
#if 0 else if(command == TOCLIENT_MOVE_PLAYER)
// Default to queueing it (for slow commands)
else
{ {
JMutexAutoLock lock(m_incoming_queue_mutex); std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
Player *player = m_env.getLocalPlayer();
assert(player != NULL);
v3f pos = readV3F1000(is);
f32 pitch = readF1000(is);
f32 yaw = readF1000(is);
player->setPosition(pos);
/*player->setPitch(pitch);
player->setYaw(yaw);*/
IncomingPacket packet(data, datasize); dstream<<"Client got TOCLIENT_MOVE_PLAYER"
m_incoming_queue.push_back(packet); <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
} <<" pitch="<<pitch
#endif <<" yaw="<<yaw
} <<std::endl;
#if 0
/*
Returns true if there was something in queue
*/
bool Client::AsyncProcessPacket()
{
DSTACK(__FUNCTION_NAME);
try //for catching con::PeerNotFoundException
{
con::Peer *peer;
{
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
// All data is coming from the server
peer = m_con.GetPeer(PEER_ID_SERVER);
}
u8 ser_version = m_server_ser_ver;
IncomingPacket packet = getPacket();
u8 *data = packet.m_data;
u32 datasize = packet.m_datalen;
// An empty packet means queue is empty
if(data == NULL){
return false;
}
if(datasize < 2)
return true;
ToClientCommand command = (ToClientCommand)readU16(&data[0]);
if(command == TOCLIENT_BLOCKDATA)
{
// Ignore too small packet
if(datasize < 8)
return true;
v3s16 p;
p.X = readS16(&data[2]);
p.Y = readS16(&data[4]);
p.Z = readS16(&data[6]);
/*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
/*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
std::string datastring((char*)&data[8], datasize-8);
std::istringstream istr(datastring, std::ios_base::binary);
MapSector *sector;
MapBlock *block;
{ //envlock
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
v2s16 p2d(p.X, p.Z);
sector = m_env.getMap().emergeSector(p2d);
v2s16 sp = sector->getPos();
if(sp != p2d)
{
dstream<<"ERROR: Got sector with getPos()="
<<"("<<sp.X<<","<<sp.Y<<"), tried to get"
<<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl;
}
assert(sp == p2d);
//assert(sector->getPos() == p2d);
//TimeTaker timer("MapBlock deSerialize");
// 0ms
try{
block = sector->getBlockNoCreate(p.Y);
/*
Update an existing block
*/
//dstream<<"Updating"<<std::endl;
block->deSerialize(istr, ser_version);
//block->setChangedFlag();
}
catch(InvalidPositionException &e)
{
/*
Create a new block
*/
//dstream<<"Creating new"<<std::endl;
block = new MapBlock(&m_env.getMap(), p);
block->deSerialize(istr, ser_version);
sector->insertBlock(block);
//block->setChangedFlag();
//DEBUG
/*NodeMod mod;
mod.type = NODEMOD_CHANGECONTENT;
mod.param = CONTENT_MESE;
block->setTempMod(v3s16(8,10,8), mod);
block->setTempMod(v3s16(8,9,8), mod);
block->setTempMod(v3s16(8,8,8), mod);
block->setTempMod(v3s16(8,7,8), mod);
block->setTempMod(v3s16(8,6,8), mod);*/
#if 0
/*
Add some coulds
Well, this is a dumb way to do it, they should just
be drawn as separate objects. But the looks of them
can be tested this way.
*/
if(p.Y == 3)
{
NodeMod mod;
mod.type = NODEMOD_CHANGECONTENT;
mod.param = CONTENT_CLOUD;
v3s16 p2;
p2.Y = 8;
for(p2.X=3; p2.X<=13; p2.X++)
for(p2.Z=3; p2.Z<=13; p2.Z++)
{
block->setTempMod(p2, mod);
}
}
#endif
}
} //envlock
/* /*
Acknowledge block. Add to ClientEvent queue.
This has to be sent to the main program because otherwise
it would just force the pitch and yaw values to whatever
the camera points to.
*/ */
/* ClientEvent event;
[0] u16 command event.type = CE_PLAYER_FORCE_MOVE;
[2] u8 count event.player_force_move.pitch = pitch;
[3] v3s16 pos_0 event.player_force_move.yaw = yaw;
[3+6] v3s16 pos_1 m_client_event_queue.push_back(event);
...
*/
u32 replysize = 2+1+6;
SharedBuffer<u8> reply(replysize);
writeU16(&reply[0], TOSERVER_GOTBLOCKS);
reply[2] = 1;
writeV3S16(&reply[3], p);
// Send as reliable
m_con.Send(PEER_ID_SERVER, 1, reply, true);
/* // Ignore damage for a few seconds, so that the player doesn't
Update Mesh of this block and blocks at x-, y- and z-. // get damage from falling on ground
Environment should not be locked as it interlocks with the m_ignore_damage_timer = 3.0;
main thread, from which is will want to retrieve textures.
*/
//m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
MeshMakeData data;
{
//TimeTaker timer("data fill");
// 0ms
data.fill(getDayNightRatio(), block);
}
{
TimeTaker timer("make mesh");
scene::SMesh *mesh_new = NULL;
mesh_new = makeMapBlockMesh(&data);
block->replaceMesh(mesh_new);
}
} }
else else
{ {
dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command " dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
<<command<<std::endl; <<command<<std::endl;
} }
return true;
} //try
catch(con::PeerNotFoundException &e)
{
/*dout_client<<DTIME<<"Client::AsyncProcessData(): Cancelling: The server"
" connection doesn't exist (a timeout or not yet connected?)"<<std::endl;*/
return false;
}
} }
bool Client::AsyncProcessData()
{
for(;;)
{
bool r = AsyncProcessPacket();
if(r == false)
break;
}
return false;
}
#endif
void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable) void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
{ {
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
m_con.Send(PEER_ID_SERVER, channelnum, data, reliable); m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
} }
#if 0
IncomingPacket Client::getPacket()
{
JMutexAutoLock lock(m_incoming_queue_mutex);
core::list<IncomingPacket>::Iterator i;
// Refer to first one
i = m_incoming_queue.begin();
// If queue is empty, return empty packet
if(i == m_incoming_queue.end()){
IncomingPacket packet;
return packet;
}
// Pop out first packet and return it
IncomingPacket packet = *i;
m_incoming_queue.erase(i);
return packet;
}
#endif
void Client::groundAction(u8 action, v3s16 nodepos_undersurface, void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
v3s16 nodepos_oversurface, u16 item) v3s16 nodepos_oversurface, u16 item)
{ {
@ -1739,6 +1597,21 @@ void Client::sendChatMessage(const std::wstring &message)
Send(0, data, true); Send(0, data, true);
} }
void Client::sendDamage(u8 damage)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOSERVER_DAMAGE);
writeU8(os, damage);
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
Send(0, data, true);
}
void Client::sendPlayerPos() void Client::sendPlayerPos()
{ {
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
@ -2061,6 +1934,13 @@ u32 Client::getDayNightRatio()
return m_env.getDayNightRatio(); return m_env.getDayNightRatio();
} }
u16 Client::getHP()
{
Player *player = m_env.getLocalPlayer();
assert(player != NULL);
return player->hp;
}
void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server) void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
{ {
/*dstream<<"Client::addUpdateMeshTask(): " /*dstream<<"Client::addUpdateMeshTask(): "
@ -2141,3 +2021,15 @@ void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
catch(InvalidPositionException &e){} catch(InvalidPositionException &e){}
} }
ClientEvent Client::getClientEvent()
{
if(m_client_event_queue.size() == 0)
{
ClientEvent event;
event.type = CE_NONE;
return event;
}
return m_client_event_queue.pop_front();
}

@ -174,55 +174,28 @@ public:
MutexedQueue<MeshUpdateResult> m_queue_out; MutexedQueue<MeshUpdateResult> m_queue_out;
}; };
#if 0 enum ClientEventType
struct IncomingPacket
{ {
IncomingPacket() CE_NONE,
{ CE_PLAYER_DAMAGE,
m_data = NULL; CE_PLAYER_FORCE_MOVE
m_datalen = 0; };
m_refcount = NULL;
} struct ClientEvent
IncomingPacket(const IncomingPacket &a) {
{ ClientEventType type;
m_data = a.m_data; union{
m_datalen = a.m_datalen; struct{
m_refcount = a.m_refcount; } none;
if(m_refcount != NULL) struct{
(*m_refcount)++; u8 amount;
} } player_damage;
IncomingPacket(u8 *data, u32 datalen) struct{
{ f32 pitch;
m_data = new u8[datalen]; f32 yaw;
memcpy(m_data, data, datalen); } player_force_move;
m_datalen = datalen; };
m_refcount = new s32(1);
}
~IncomingPacket()
{
if(m_refcount != NULL){
assert(*m_refcount > 0);
(*m_refcount)--;
if(*m_refcount == 0){
if(m_data != NULL)
delete[] m_data;
delete m_refcount;
}
}
}
/*IncomingPacket & operator=(IncomingPacket a)
{
m_data = a.m_data;
m_datalen = a.m_datalen;
m_refcount = a.m_refcount;
(*m_refcount)++;
return *this;
}*/
u8 *m_data;
u32 m_datalen;
s32 *m_refcount;
}; };
#endif
class Client : public con::PeerHandler, public InventoryManager class Client : public con::PeerHandler, public InventoryManager
{ {
@ -281,6 +254,7 @@ public:
void sendSignNodeText(v3s16 p, std::string text); void sendSignNodeText(v3s16 p, std::string text);
void sendInventoryAction(InventoryAction *a); void sendInventoryAction(InventoryAction *a);
void sendChatMessage(const std::wstring &message); void sendChatMessage(const std::wstring &message);
void sendDamage(u8 damage);
// locks envlock // locks envlock
void removeNode(v3s16 p); void removeNode(v3s16 p);
@ -330,6 +304,8 @@ public:
u32 getDayNightRatio(); u32 getDayNightRatio();
u16 getHP();
//void updateSomeExpiredMeshes(); //void updateSomeExpiredMeshes();
void setTempMod(v3s16 p, NodeMod mod) void setTempMod(v3s16 p, NodeMod mod)
@ -394,13 +370,13 @@ public:
u64 getMapSeed(){ return m_map_seed; } u64 getMapSeed(){ return m_map_seed; }
/*
These are not thread-safe
*/
void addUpdateMeshTask(v3s16 blockpos, bool ack_to_server=false); void addUpdateMeshTask(v3s16 blockpos, bool ack_to_server=false);
// Including blocks at appropriate edges // Including blocks at appropriate edges
void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false); void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false);
// Get event from queue. CE_NONE is returned if queue is empty.
ClientEvent getClientEvent();
private: private:
// Virtual methods from con::PeerHandler // Virtual methods from con::PeerHandler
@ -419,6 +395,7 @@ private:
float m_connection_reinit_timer; float m_connection_reinit_timer;
float m_avg_rtt_timer; float m_avg_rtt_timer;
float m_playerpos_send_timer; float m_playerpos_send_timer;
float m_ignore_damage_timer; // Used after server moves player
MeshUpdateThread m_mesh_update_thread; MeshUpdateThread m_mesh_update_thread;
@ -454,6 +431,8 @@ private:
u64 m_map_seed; u64 m_map_seed;
InventoryContext m_inventory_context; InventoryContext m_inventory_context;
Queue<ClientEvent> m_client_event_queue;
}; };
#endif // !SERVER #endif // !SERVER

@ -494,7 +494,7 @@ void RatCAO::updateLight(u8 light_at_pos)
v3s16 RatCAO::getLightPosition() v3s16 RatCAO::getLightPosition()
{ {
return floatToInt(m_position, BS); return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
} }
void RatCAO::updateNodePos() void RatCAO::updateNodePos()
@ -552,4 +552,181 @@ void RatCAO::initialize(const std::string &data)
updateNodePos(); updateNodePos();
} }
/*
Oerkki1CAO
*/
#include "inventory.h"
// Prototype
Oerkki1CAO proto_Oerkki1CAO;
Oerkki1CAO::Oerkki1CAO():
ClientActiveObject(0),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
m_yaw(0)
{
ClientActiveObject::registerType(getType(), create);
}
Oerkki1CAO::~Oerkki1CAO()
{
}
ClientActiveObject* Oerkki1CAO::create()
{
return new Oerkki1CAO();
}
void Oerkki1CAO::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,0,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS*2,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);
buf->getMaterial().setTexture
(0, driver->getTexture(porting::getDataPath("oerkki1.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 Oerkki1CAO::removeFromScene()
{
if(m_node == NULL)
return;
m_node->remove();
m_node = NULL;
}
void Oerkki1CAO::updateLight(u8 light_at_pos)
{
if(m_node == NULL)
return;
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
scene::IMesh *mesh = m_node->getMesh();
if(mesh == NULL)
return;
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
}
v3s16 Oerkki1CAO::getLightPosition()
{
return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
}
void Oerkki1CAO::updateNodePos()
{
if(m_node == NULL)
return;
//m_node->setPosition(m_position);
m_node->setPosition(pos_translator.vect_show);
v3f rot = m_node->getRotation();
rot.Y = 180.0 - m_yaw + 90.0;
m_node->setRotation(rot);
}
void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
{
pos_translator.translate(dtime);
updateNodePos();
LocalPlayer *player = env->getLocalPlayer();
assert(player);
v3f playerpos = player->getPosition();
v2f playerpos_2d(playerpos.X,playerpos.Z);
v2f objectpos_2d(m_position.X,m_position.Z);
if(fabs(objectpos_2d.Y - playerpos_2d.Y) < 2.0*BS &&
objectpos_2d.getDistanceFrom(playerpos_2d) < 1.0*BS)
{
if(m_attack_interval.step(dtime, 0.5))
{
env->damageLocalPlayer(2);
}
}
}
void Oerkki1CAO::processMessage(const std::string &data)
{
//dstream<<"Oerkki1CAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
if(cmd == 0)
{
// pos
m_position = readV3F1000(is);
pos_translator.update(m_position);
// yaw
m_yaw = readF1000(is);
updateNodePos();
}
}
void Oerkki1CAO::initialize(const std::string &data)
{
//dstream<<"Oerkki1CAO: 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);
pos_translator.init(m_position);
}
updateNodePos();
}

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h" #include "common_irrlicht.h"
#include "activeobject.h" #include "activeobject.h"
#include "utility.h"
/* /*
@ -267,5 +268,49 @@ private:
SmoothTranslator pos_translator; SmoothTranslator pos_translator;
}; };
/*
Oerkki1CAO
*/
class Oerkki1CAO : public ClientActiveObject
{
public:
Oerkki1CAO();
virtual ~Oerkki1CAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_OERKKI1;
}
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 pos_translator.vect_show;}
//{return m_position;}
private:
IntervalLimiter m_attack_interval;
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
float m_yaw;
SmoothTranslator pos_translator;
};
#endif #endif

@ -34,14 +34,17 @@ enum ToClientCommand
[0] u16 TOSERVER_INIT [0] u16 TOSERVER_INIT
[2] u8 deployed version [2] u8 deployed version
[3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd [3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
[4] u64 map seed (new as of 2011-02-27) ([4] u64 map seed (new as of 2011-02-27))
NOTE: The position in here is deprecated; position is
explicitly sent afterwards
*/ */
TOCLIENT_BLOCKDATA = 0x20, //TODO: Multiple blocks TOCLIENT_BLOCKDATA = 0x20, //TODO: Multiple blocks
TOCLIENT_ADDNODE = 0x21, TOCLIENT_ADDNODE = 0x21,
TOCLIENT_REMOVENODE = 0x22, TOCLIENT_REMOVENODE = 0x22,
TOCLIENT_PLAYERPOS = 0x23, TOCLIENT_PLAYERPOS = 0x23, // Obsolete
/* /*
[0] u16 command [0] u16 command
// Followed by an arbitary number of these: // Followed by an arbitary number of these:
@ -62,9 +65,9 @@ enum ToClientCommand
[N] char[20] name [N] char[20] name
*/ */
TOCLIENT_OPT_BLOCK_NOT_FOUND = 0x25, // Not used TOCLIENT_OPT_BLOCK_NOT_FOUND = 0x25, // Obsolete
TOCLIENT_SECTORMETA = 0x26, // Not used TOCLIENT_SECTORMETA = 0x26, // Obsolete
/* /*
[0] u16 command [0] u16 command
[2] u8 sector count [2] u8 sector count
@ -134,6 +137,19 @@ enum ToClientCommand
} }
*/ */
TOCLIENT_HP = 0x33,
/*
u16 command
u8 hp
*/
TOCLIENT_MOVE_PLAYER = 0x34,
/*
u16 command
v3f1000 player position
f1000 player pitch
f1000 player yaw
*/
}; };
enum ToServerCommand enum ToServerCommand
@ -155,9 +171,9 @@ enum ToServerCommand
[0] u16 TOSERVER_INIT2 [0] u16 TOSERVER_INIT2
*/ */
TOSERVER_GETBLOCK=0x20, // Not used TOSERVER_GETBLOCK=0x20, // Obsolete
TOSERVER_ADDNODE = 0x21, // Not used TOSERVER_ADDNODE = 0x21, // Obsolete
TOSERVER_REMOVENODE = 0x22, // deprecated TOSERVER_REMOVENODE = 0x22, // Obsolete
TOSERVER_PLAYERPOS = 0x23, TOSERVER_PLAYERPOS = 0x23,
/* /*
@ -186,7 +202,7 @@ enum ToServerCommand
... ...
*/ */
TOSERVER_ADDNODE_FROM_INVENTORY = 0x26, // deprecated TOSERVER_ADDNODE_FROM_INVENTORY = 0x26, // Obsolete
/* /*
[0] u16 command [0] u16 command
[2] v3s16 pos [2] v3s16 pos
@ -218,9 +234,9 @@ enum ToServerCommand
3: digging completed 3: digging completed
*/ */
TOSERVER_RELEASE = 0x29, // Not used TOSERVER_RELEASE = 0x29, // Obsolete
TOSERVER_SIGNTEXT = 0x30, TOSERVER_SIGNTEXT = 0x30, // Old signs
/* /*
u16 command u16 command
v3s16 blockpos v3s16 blockpos
@ -258,6 +274,11 @@ enum ToServerCommand
[5] u16 item [5] u16 item
*/ */
TOSERVER_DAMAGE = 0x35,
/*
u16 command
u8 amount
*/
}; };
inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time) inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time)

@ -70,6 +70,7 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
/* /*
Go through every node around the object Go through every node around the object
TODO: Calculate the range of nodes that need to be checked
*/ */
for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++) for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++) for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)

@ -38,6 +38,16 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
f32 dtime, v3f &pos_f, v3f &speed_f); f32 dtime, v3f &pos_f, v3f &speed_f);
//{return collisionMoveResult();} //{return collisionMoveResult();}
enum CollisionType
{
COLLISION_FALL
};
struct CollisionInfo
{
CollisionType t;
f32 speed;
};
#endif #endif

@ -55,6 +55,7 @@ void set_default_settings()
g_settings.setDefault("enable_experimental", "false"); g_settings.setDefault("enable_experimental", "false");
g_settings.setDefault("creative_mode", "false"); g_settings.setDefault("creative_mode", "false");
g_settings.setDefault("enable_damage", "false"); //TODO: Set to true
g_settings.setDefault("objectdata_interval", "0.2"); g_settings.setDefault("objectdata_interval", "0.2");
g_settings.setDefault("active_object_range", "2"); g_settings.setDefault("active_object_range", "2");

@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "environment.h" #include "environment.h"
#include "filesys.h" #include "filesys.h"
#include "porting.h" #include "porting.h"
#include "collision.h"
Environment::Environment() Environment::Environment()
{ {
@ -377,6 +378,55 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir)
} }
} }
#if 0
void spawnRandomObjects(MapBlock *block)
{
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
{
bool last_node_walkable = false;
for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
{
v3s16 p(x0,y0,z0);
MapNode n = block->getNodeNoEx(p);
if(n.d == CONTENT_IGNORE)
continue;
if(content_features(n.d).liquid_type != LIQUID_NONE)
continue;
if(content_features(n.d).walkable)
{
last_node_walkable = true;
continue;
}
if(last_node_walkable)
{
// If block contains light information
if(content_features(n.d).param_type == CPT_LIGHT)
{
if(n.getLight(LIGHTBANK_DAY) <= 5)
{
if(myrand() % 1000 == 0)
{
v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
pos_f.Y -= BS*0.4;
ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
std::string data = obj->getStaticData();
StaticObject s_obj(obj->getType(),
obj->getBasePosition(), data);
// Add one
block->m_static_objects.insert(0, s_obj);
delete obj;
block->setChangedFlag();
}
}
}
}
last_node_walkable = false;
}
}
}
#endif
void ServerEnvironment::step(float dtime) void ServerEnvironment::step(float dtime)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
@ -433,6 +483,8 @@ void ServerEnvironment::step(float dtime)
/* /*
Step active objects Step active objects
*/ */
{
//TimeTaker timer("Step active objects");
bool send_recommended = false; bool send_recommended = false;
m_send_recommended_timer += dtime; m_send_recommended_timer += dtime;
@ -450,6 +502,7 @@ void ServerEnvironment::step(float dtime)
// Step object, putting messages directly to the queue // Step object, putting messages directly to the queue
obj->step(dtime, m_active_object_messages, send_recommended); obj->step(dtime, m_active_object_messages, send_recommended);
} }
}
if(m_object_management_interval.step(dtime, 0.5)) if(m_object_management_interval.step(dtime, 0.5))
{ {
@ -506,7 +559,7 @@ void ServerEnvironment::step(float dtime)
const s16 to_active_max_blocks = 3; const s16 to_active_max_blocks = 3;
const f32 to_static_max_f = (to_active_max_blocks+1)*MAP_BLOCKSIZE*BS; const f32 to_static_max_f = (to_active_max_blocks+2)*MAP_BLOCKSIZE*BS;
/* /*
Convert stored objects from blocks near the players to active. Convert stored objects from blocks near the players to active.
@ -719,7 +772,8 @@ void ServerEnvironment::step(float dtime)
//TestSAO *obj = new TestSAO(this, 0, pos); //TestSAO *obj = new TestSAO(this, 0, pos);
//ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1"); //ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
ServerActiveObject *obj = new RatSAO(this, 0, pos); //ServerActiveObject *obj = new RatSAO(this, 0, pos);
ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
addActiveObject(obj); addActiveObject(obj);
} }
#endif #endif
@ -977,12 +1031,16 @@ void ClientEnvironment::step(float dtime)
m_map->timerUpdate(dtime); m_map->timerUpdate(dtime);
} }
// Get local player
LocalPlayer *lplayer = getLocalPlayer();
assert(lplayer);
// collision info queue
core::list<CollisionInfo> player_collisions;
/* /*
Get the speed the player is going Get the speed the player is going
*/ */
f32 player_speed = 0.001; // just some small value f32 player_speed = 0.001; // just some small value
LocalPlayer *lplayer = getLocalPlayer();
if(lplayer)
player_speed = lplayer->getSpeed().getLength(); player_speed = lplayer->getSpeed().getLength();
/* /*
@ -1036,20 +1094,18 @@ void ClientEnvironment::step(float dtime)
*/ */
{ {
Player *player = getLocalPlayer(); v3f lplayerpos = lplayer->getPosition();
v3f playerpos = player->getPosition();
// Apply physics // Apply physics
if(free_move == false) if(free_move == false)
{ {
// Gravity // Gravity
v3f speed = player->getSpeed(); v3f speed = lplayer->getSpeed();
if(player->swimming_up == false) if(lplayer->swimming_up == false)
speed.Y -= 9.81 * BS * dtime_part * 2; speed.Y -= 9.81 * BS * dtime_part * 2;
// Water resistance // Water resistance
if(player->in_water_stable || player->in_water) if(lplayer->in_water_stable || lplayer->in_water)
{ {
f32 max_down = 2.0*BS; f32 max_down = 2.0*BS;
if(speed.Y < -max_down) speed.Y = -max_down; if(speed.Y < -max_down) speed.Y = -max_down;
@ -1061,20 +1117,48 @@ void ClientEnvironment::step(float dtime)
} }
} }
player->setSpeed(speed); lplayer->setSpeed(speed);
} }
/* /*
Move the player. Move the lplayer.
This also does collision detection. This also does collision detection.
*/ */
player->move(dtime_part, *m_map, position_max_increment); lplayer->move(dtime_part, *m_map, position_max_increment,
&player_collisions);
} }
} }
while(dtime_downcount > 0.001); while(dtime_downcount > 0.001);
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl; //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
for(core::list<CollisionInfo>::Iterator
i = player_collisions.begin();
i != player_collisions.end(); i++)
{
CollisionInfo &info = *i;
if(info.t == COLLISION_FALL)
{
//f32 tolerance = BS*10; // 2 without damage
f32 tolerance = BS*12; // 3 without damage
f32 factor = 1;
if(info.speed > tolerance)
{
f32 damage_f = (info.speed - tolerance)/BS*factor;
u16 damage = (u16)(damage_f+0.5);
if(lplayer->hp > damage)
lplayer->hp -= damage;
else
lplayer->hp = 0;
ClientEnvEvent event;
event.type = CEE_PLAYER_DAMAGE;
event.player_damage.amount = damage;
m_client_event_queue.push_back(event);
}
}
}
/* /*
Stuff that can be done in an arbitarily large dtime Stuff that can be done in an arbitarily large dtime
*/ */
@ -1287,6 +1371,30 @@ void ClientEnvironment::processActiveObjectMessage(u16 id,
obj->processMessage(data); obj->processMessage(data);
} }
/*
Callbacks for activeobjects
*/
void ClientEnvironment::damageLocalPlayer(u8 damage)
{
LocalPlayer *lplayer = getLocalPlayer();
assert(lplayer);
if(lplayer->hp > damage)
lplayer->hp -= damage;
else
lplayer->hp = 0;
ClientEnvEvent event;
event.type = CEE_PLAYER_DAMAGE;
event.player_damage.amount = damage;
m_client_event_queue.push_back(event);
}
/*
Client likes to call these
*/
void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d, void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
core::array<DistanceSortedActiveObject> &dest) core::array<DistanceSortedActiveObject> &dest)
{ {
@ -1307,6 +1415,16 @@ void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
} }
} }
ClientEnvEvent ClientEnvironment::getClientEvent()
{
if(m_client_event_queue.size() == 0)
{
ClientEnvEvent event;
event.type = CEE_NONE;
return event;
}
return m_client_event_queue.pop_front();
}
#endif // #ifndef SERVER #endif // #ifndef SERVER

@ -170,6 +170,24 @@ private:
Client uses an environment mutex. Client uses an environment mutex.
*/ */
enum ClientEnvEventType
{
CEE_NONE,
CEE_PLAYER_DAMAGE
};
struct ClientEnvEvent
{
ClientEnvEventType type;
union {
struct{
} none;
struct{
u8 amount;
} player_damage;
};
};
class ClientEnvironment : public Environment class ClientEnvironment : public Environment
{ {
public: public:
@ -215,14 +233,28 @@ public:
void processActiveObjectMessage(u16 id, const std::string &data); void processActiveObjectMessage(u16 id, const std::string &data);
/*
Callbacks for activeobjects
*/
void damageLocalPlayer(u8 damage);
/*
Client likes to call these
*/
// Get all nearby objects // Get all nearby objects
void getActiveObjects(v3f origin, f32 max_d, void getActiveObjects(v3f origin, f32 max_d,
core::array<DistanceSortedActiveObject> &dest); core::array<DistanceSortedActiveObject> &dest);
// Get event from queue. CEE_NONE is returned if queue is empty.
ClientEnvEvent getClientEvent();
private: private:
ClientMap *m_map; ClientMap *m_map;
scene::ISceneManager *m_smgr; scene::ISceneManager *m_smgr;
core::map<u16, ClientActiveObject*> m_active_objects; core::map<u16, ClientActiveObject*> m_active_objects;
Queue<ClientEnvEvent> m_client_event_queue;
}; };
#endif #endif

@ -369,6 +369,12 @@ public:
basename = "tool_stoneaxe.png"; basename = "tool_stoneaxe.png";
else if(m_toolname == "SteelAxe") else if(m_toolname == "SteelAxe")
basename = "tool_steelaxe.png"; basename = "tool_steelaxe.png";
else if(m_toolname == "WSword")
basename = "tool_woodsword.png";
else if(m_toolname == "STSword")
basename = "tool_stonesword.png";
else if(m_toolname == "SteelSword")
basename = "tool_steelsword.png";
else else
basename = "cloud.png"; basename = "cloud.png";

@ -93,6 +93,10 @@ SUGG: Meshes of blocks could be split into 6 meshes facing into
SUGG: Calculate lighting per vertex to get a lighting effect like in SUGG: Calculate lighting per vertex to get a lighting effect like in
bartwe's game bartwe's game
SUGG: Background music based on cellular automata?
http://www.earslap.com/projectslab/otomata
Gaming ideas: Gaming ideas:
------------- -------------
@ -126,6 +130,12 @@ Game content:
- You can drop on top of it, and have some time to attack there - You can drop on top of it, and have some time to attack there
before he shakes you off before he shakes you off
- Maybe the difficulty could come from monsters getting tougher in
far-away places, and the player starting to need something from
there when time goes by.
- The player would have some of that stuff at the beginning, and
would need new supplies of it when it runs out
Documentation: Documentation:
-------------- --------------
@ -1210,7 +1220,7 @@ void updateViewingRange(f32 frametime_in, Client *client)
void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font, void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
v2s32 centerlowerpos, s32 imgsize, s32 itemcount, v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
Inventory *inventory) Inventory *inventory, s32 halfheartcount)
{ {
InventoryList *mainlist = inventory->getList("main"); InventoryList *mainlist = inventory->getList("main");
if(mainlist == NULL) if(mainlist == NULL)
@ -1259,6 +1269,40 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
drawInventoryItem(driver, font, item, rect, NULL); drawInventoryItem(driver, font, item, rect, NULL);
} }
} }
/*
Draw hearts
*/
{
video::ITexture *heart_texture =
driver->getTexture(porting::getDataPath("heart.png").c_str());
v2s32 p = pos + v2s32(0, -20);
for(s32 i=0; i<halfheartcount/2; i++)
{
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
core::rect<s32> rect(0,0,16,16);
rect += p;
driver->draw2DImage(heart_texture, rect,
core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(heart_texture->getOriginalSize())),
NULL, colors, true);
p += v2s32(20,0);
}
if(halfheartcount % 2 == 1)
{
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
core::rect<s32> rect(0,0,16/2,16);
rect += p;
core::dimension2di srcd(heart_texture->getOriginalSize());
srcd.Width /= 2;
driver->draw2DImage(heart_texture, rect,
core::rect<s32>(core::position2d<s32>(0,0), srcd),
NULL, colors, true);
p += v2s32(20,0);
}
}
} }
#if 0 #if 0
@ -1519,6 +1563,215 @@ void SpeedTests()
} }
} }
void getPointedNode(v3f player_position,
v3f camera_direction, v3f camera_position,
bool &nodefound, core::line3d<f32> shootline,
v3s16 &nodepos, v3s16 &neighbourpos,
core::aabbox3d<f32> &nodehilightbox,
f32 d)
{
assert(g_client);
f32 mindistance = BS * 1001;
v3s16 pos_i = floatToInt(player_position, BS);
/*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
<<std::endl;*/
s16 a = d;
s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
for(s16 y = ystart; y <= yend; y++)
for(s16 z = zstart; z <= zend; z++)
for(s16 x = xstart; x <= xend; x++)
{
MapNode n;
try
{
n = g_client->getNode(v3s16(x,y,z));
if(content_pointable(n.d) == false)
continue;
}
catch(InvalidPositionException &e)
{
continue;
}
v3s16 np(x,y,z);
v3f npf = intToFloat(np, BS);
f32 d = 0.01;
v3s16 dirs[6] = {
v3s16(0,0,1), // back
v3s16(0,1,0), // top
v3s16(1,0,0), // right
v3s16(0,0,-1), // front
v3s16(0,-1,0), // bottom
v3s16(-1,0,0), // left
};
/*
Meta-objects
*/
if(n.d == CONTENT_TORCH)
{
v3s16 dir = unpackDir(n.dir);
v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
dir_f *= BS/2 - BS/6 - BS/20;
v3f cpf = npf + dir_f;
f32 distance = (cpf - camera_position).getLength();
core::aabbox3d<f32> box;
// bottom
if(dir == v3s16(0,-1,0))
{
box = core::aabbox3d<f32>(
npf - v3f(BS/6, BS/2, BS/6),
npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)
);
}
// top
else if(dir == v3s16(0,1,0))
{
box = core::aabbox3d<f32>(
npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),
npf + v3f(BS/6, BS/2, BS/6)
);
}
// side
else
{
box = core::aabbox3d<f32>(
cpf - v3f(BS/6, BS/3, BS/6),
cpf + v3f(BS/6, BS/3, BS/6)
);
}
if(distance < mindistance)
{
if(box.intersectsWithLine(shootline))
{
nodefound = true;
nodepos = np;
neighbourpos = np;
mindistance = distance;
nodehilightbox = box;
}
}
}
else if(n.d == CONTENT_SIGN_WALL)
{
v3s16 dir = unpackDir(n.dir);
v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
dir_f *= BS/2 - BS/6 - BS/20;
v3f cpf = npf + dir_f;
f32 distance = (cpf - camera_position).getLength();
v3f vertices[4] =
{
v3f(BS*0.42,-BS*0.35,-BS*0.4),
v3f(BS*0.49, BS*0.35, BS*0.4),
};
for(s32 i=0; i<2; i++)
{
if(dir == v3s16(1,0,0))
vertices[i].rotateXZBy(0);
if(dir == v3s16(-1,0,0))
vertices[i].rotateXZBy(180);
if(dir == v3s16(0,0,1))
vertices[i].rotateXZBy(90);
if(dir == v3s16(0,0,-1))
vertices[i].rotateXZBy(-90);
if(dir == v3s16(0,-1,0))
vertices[i].rotateXYBy(-90);
if(dir == v3s16(0,1,0))
vertices[i].rotateXYBy(90);
vertices[i] += npf;
}
core::aabbox3d<f32> box;
box = core::aabbox3d<f32>(vertices[0]);
box.addInternalPoint(vertices[1]);
if(distance < mindistance)
{
if(box.intersectsWithLine(shootline))
{
nodefound = true;
nodepos = np;
neighbourpos = np;
mindistance = distance;
nodehilightbox = box;
}
}
}
/*
Regular blocks
*/
else
{
for(u16 i=0; i<6; i++)
{
v3f dir_f = v3f(dirs[i].X,
dirs[i].Y, dirs[i].Z);
v3f centerpoint = npf + dir_f * BS/2;
f32 distance =
(centerpoint - camera_position).getLength();
if(distance < mindistance)
{
core::CMatrix4<f32> m;
m.buildRotateFromTo(v3f(0,0,1), dir_f);
// This is the back face
v3f corners[2] = {
v3f(BS/2, BS/2, BS/2),
v3f(-BS/2, -BS/2, BS/2+d)
};
for(u16 j=0; j<2; j++)
{
m.rotateVect(corners[j]);
corners[j] += npf;
}
core::aabbox3d<f32> facebox(corners[0]);
facebox.addInternalPoint(corners[1]);
if(facebox.intersectsWithLine(shootline))
{
nodefound = true;
nodepos = np;
neighbourpos = np + dirs[i];
mindistance = distance;
//nodehilightbox = facebox;
const float d = 0.502;
core::aabbox3d<f32> nodebox
(-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
v3f nodepos_f = intToFloat(nodepos, BS);
nodebox.MinEdge += nodepos_f;
nodebox.MaxEdge += nodepos_f;
nodehilightbox = nodebox;
}
} // if distance < mindistance
} // for dirs
} // regular block
} // for coords
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
/* /*
@ -2148,30 +2401,14 @@ int main(int argc, char *argv[])
//video::SColor skycolor = video::SColor(255,90,140,200); //video::SColor skycolor = video::SColor(255,90,140,200);
//video::SColor skycolor = video::SColor(255,166,202,244); //video::SColor skycolor = video::SColor(255,166,202,244);
video::SColor skycolor = video::SColor(255,120,185,244); //video::SColor skycolor = video::SColor(255,120,185,244);
video::SColor skycolor = video::SColor(255,140,186,250);
camera->setFOV(FOV_ANGLE); camera->setFOV(FOV_ANGLE);
// Just so big a value that everything rendered is visible // Just so big a value that everything rendered is visible
camera->setFarValue(100000*BS); camera->setFarValue(100000*BS);
/*
Lighting test code. Doesn't quite work this way.
The CPU-computed lighting is good.
*/
/*
smgr->addLightSceneNode(NULL,
v3f(0, BS*1000000, 0),
video::SColorf(0.3,0.3,0.3),
BS*10000000);
smgr->setAmbientLight(video::SColorf(0.0, 0.0, 0.0));
scene::ILightSceneNode *light = smgr->addLightSceneNode(camera,
v3f(0, 0, 0), video::SColorf(0.5,0.5,0.5), BS*4);
*/
f32 camera_yaw = 0; // "right/left" f32 camera_yaw = 0; // "right/left"
f32 camera_pitch = 0; // "up/down" f32 camera_pitch = 0; // "up/down"
@ -2226,6 +2463,8 @@ int main(int argc, char *argv[])
core::list<float> frametime_log; core::list<float> frametime_log;
float damage_flash_timer = 0;
/* /*
Main loop Main loop
*/ */
@ -2454,6 +2693,16 @@ int main(int argc, char *argv[])
client.setPlayerControl(control); client.setPlayerControl(control);
} }
/*
Run server
*/
if(server != NULL)
{
//TimeTaker timer("server->step(dtime)");
server->step(dtime);
}
/* /*
Process environment Process environment
*/ */
@ -2464,12 +2713,28 @@ int main(int argc, char *argv[])
//client.step(dtime_avg1); //client.step(dtime_avg1);
} }
if(server != NULL) // Read client events
for(;;)
{ {
//TimeTaker timer("server->step(dtime)"); ClientEvent event = client.getClientEvent();
server->step(dtime); if(event.type == CE_NONE)
{
break;
}
else if(event.type == CE_PLAYER_DAMAGE)
{
//u16 damage = event.player_damage.amount;
//dstream<<"Player damage: "<<damage<<std::endl;
damage_flash_timer = 0.05;
}
else if(event.type == CE_PLAYER_FORCE_MOVE)
{
camera_yaw = event.player_force_move.yaw;
camera_pitch = event.player_force_move.pitch;
}
} }
// Get player position
v3f player_position = client.getPlayerPosition(); v3f player_position = client.getPlayerPosition();
//TimeTaker //timer2("//timer2"); //TimeTaker //timer2("//timer2");
@ -2637,22 +2902,6 @@ int main(int argc, char *argv[])
else if(g_input->getRightClicked()) else if(g_input->getRightClicked())
{ {
std::cout<<DTIME<<"Right-clicked object"<<std::endl; std::cout<<DTIME<<"Right-clicked object"<<std::endl;
#if 0
/*
Check if we want to modify the object ourselves
*/
if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)
{
}
/*
Otherwise pass the event to the server as-is
*/
else
{
client.clickObject(1, selected_object->getBlock()->getPos(),
selected_object->getId(), g_selected_item);
}
#endif
} }
} }
else // selected_object == NULL else // selected_object == NULL
@ -2666,204 +2915,12 @@ int main(int argc, char *argv[])
v3s16 nodepos; v3s16 nodepos;
v3s16 neighbourpos; v3s16 neighbourpos;
core::aabbox3d<f32> nodehilightbox; core::aabbox3d<f32> nodehilightbox;
f32 mindistance = BS * 1001;
v3s16 pos_i = floatToInt(player_position, BS); getPointedNode(player_position,
camera_direction, camera_position,
/*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")" nodefound, shootline,
<<std::endl;*/ nodepos, neighbourpos,
nodehilightbox, d);
s16 a = d;
s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
for(s16 y = ystart; y <= yend; y++)
for(s16 z = zstart; z <= zend; z++)
for(s16 x = xstart; x <= xend; x++)
{
MapNode n;
try
{
n = client.getNode(v3s16(x,y,z));
if(content_pointable(n.d) == false)
continue;
}
catch(InvalidPositionException &e)
{
continue;
}
v3s16 np(x,y,z);
v3f npf = intToFloat(np, BS);
f32 d = 0.01;
v3s16 dirs[6] = {
v3s16(0,0,1), // back
v3s16(0,1,0), // top
v3s16(1,0,0), // right
v3s16(0,0,-1), // front
v3s16(0,-1,0), // bottom
v3s16(-1,0,0), // left
};
/*
Meta-objects
*/
if(n.d == CONTENT_TORCH)
{
v3s16 dir = unpackDir(n.dir);
v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
dir_f *= BS/2 - BS/6 - BS/20;
v3f cpf = npf + dir_f;
f32 distance = (cpf - camera_position).getLength();
core::aabbox3d<f32> box;
// bottom
if(dir == v3s16(0,-1,0))
{
box = core::aabbox3d<f32>(
npf - v3f(BS/6, BS/2, BS/6),
npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)
);
}
// top
else if(dir == v3s16(0,1,0))
{
box = core::aabbox3d<f32>(
npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),
npf + v3f(BS/6, BS/2, BS/6)
);
}
// side
else
{
box = core::aabbox3d<f32>(
cpf - v3f(BS/6, BS/3, BS/6),
cpf + v3f(BS/6, BS/3, BS/6)
);
}
if(distance < mindistance)
{
if(box.intersectsWithLine(shootline))
{
nodefound = true;
nodepos = np;
neighbourpos = np;
mindistance = distance;
nodehilightbox = box;
}
}
}
else if(n.d == CONTENT_SIGN_WALL)
{
v3s16 dir = unpackDir(n.dir);
v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
dir_f *= BS/2 - BS/6 - BS/20;
v3f cpf = npf + dir_f;
f32 distance = (cpf - camera_position).getLength();
v3f vertices[4] =
{
v3f(BS*0.42,-BS*0.35,-BS*0.4),
v3f(BS*0.49, BS*0.35, BS*0.4),
};
for(s32 i=0; i<2; i++)
{
if(dir == v3s16(1,0,0))
vertices[i].rotateXZBy(0);
if(dir == v3s16(-1,0,0))
vertices[i].rotateXZBy(180);
if(dir == v3s16(0,0,1))
vertices[i].rotateXZBy(90);
if(dir == v3s16(0,0,-1))
vertices[i].rotateXZBy(-90);
if(dir == v3s16(0,-1,0))
vertices[i].rotateXYBy(-90);
if(dir == v3s16(0,1,0))
vertices[i].rotateXYBy(90);
vertices[i] += npf;
}
core::aabbox3d<f32> box;
box = core::aabbox3d<f32>(vertices[0]);
box.addInternalPoint(vertices[1]);
if(distance < mindistance)
{
if(box.intersectsWithLine(shootline))
{
nodefound = true;
nodepos = np;
neighbourpos = np;
mindistance = distance;
nodehilightbox = box;
}
}
}
/*
Regular blocks
*/
else
{
for(u16 i=0; i<6; i++)
{
v3f dir_f = v3f(dirs[i].X,
dirs[i].Y, dirs[i].Z);
v3f centerpoint = npf + dir_f * BS/2;
f32 distance =
(centerpoint - camera_position).getLength();
if(distance < mindistance)
{
core::CMatrix4<f32> m;
m.buildRotateFromTo(v3f(0,0,1), dir_f);
// This is the back face
v3f corners[2] = {
v3f(BS/2, BS/2, BS/2),
v3f(-BS/2, -BS/2, BS/2+d)
};
for(u16 j=0; j<2; j++)
{
m.rotateVect(corners[j]);
corners[j] += npf;
}
core::aabbox3d<f32> facebox(corners[0]);
facebox.addInternalPoint(corners[1]);
if(facebox.intersectsWithLine(shootline))
{
nodefound = true;
nodepos = np;
neighbourpos = np + dirs[i];
mindistance = distance;
//nodehilightbox = facebox;
const float d = 0.502;
core::aabbox3d<f32> nodebox
(-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
v3f nodepos_f = intToFloat(nodepos, BS);
nodebox.MinEdge += nodepos_f;
nodebox.MaxEdge += nodepos_f;
nodehilightbox = nodebox;
}
} // if distance < mindistance
} // for dirs
} // regular block
} // for coords
static float nodig_delay_counter = 0.0; static float nodig_delay_counter = 0.0;
@ -3430,10 +3487,26 @@ int main(int argc, char *argv[])
*/ */
{ {
draw_hotbar(driver, font, v2s32(displaycenter.X, screensize.Y), draw_hotbar(driver, font, v2s32(displaycenter.X, screensize.Y),
hotbar_imagesize, hotbar_itemcount, &local_inventory); hotbar_imagesize, hotbar_itemcount, &local_inventory,
client.getHP());
} }
// End drawing /*
Damage flash
*/
if(damage_flash_timer > 0.0)
{
damage_flash_timer -= dtime;
video::SColor color(128,255,0,0);
driver->draw2DRectangle(color,
core::rect<s32>(0,0,screensize.X,screensize.Y),
NULL);
}
/*
End scene
*/
{ {
TimeTaker timer("endScene"); TimeTaker timer("endScene");
driver->endScene(); driver->endScene();

@ -37,8 +37,8 @@ Map::Map(std::ostream &dout):
m_dout(dout), m_dout(dout),
m_sector_cache(NULL) m_sector_cache(NULL)
{ {
m_sector_mutex.Init(); /*m_sector_mutex.Init();
assert(m_sector_mutex.IsInitialized()); assert(m_sector_mutex.IsInitialized());*/
} }
Map::~Map() Map::~Map()
@ -104,7 +104,7 @@ MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
MapSector * Map::getSectorNoGenerateNoEx(v2s16 p) MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
{ {
JMutexAutoLock lock(m_sector_mutex); //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
return getSectorNoGenerateNoExNoLock(p); return getSectorNoGenerateNoExNoLock(p);
} }
@ -1347,7 +1347,7 @@ bool Map::dayNightDiffed(v3s16 blockpos)
*/ */
void Map::timerUpdate(float dtime) void Map::timerUpdate(float dtime)
{ {
JMutexAutoLock lock(m_sector_mutex); //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::map<v2s16, MapSector*>::Iterator si; core::map<v2s16, MapSector*>::Iterator si;
@ -1397,7 +1397,7 @@ void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
u32 Map::deleteUnusedSectors(float timeout, bool only_blocks, u32 Map::deleteUnusedSectors(float timeout, bool only_blocks,
core::list<v3s16> *deleted_blocks) core::list<v3s16> *deleted_blocks)
{ {
JMutexAutoLock lock(m_sector_mutex); //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::list<v2s16> sector_deletion_queue; core::list<v2s16> sector_deletion_queue;
core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator(); core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
@ -2163,6 +2163,18 @@ void addRandomObjects(MapBlock *block)
block->m_static_objects.insert(0, s_obj); block->m_static_objects.insert(0, s_obj);
delete obj; delete obj;
} }
if(myrand() % 300 == 0)
{
v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
pos_f.Y -= BS*0.4;
ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
std::string data = obj->getStaticData();
StaticObject s_obj(obj->getType(),
obj->getBasePosition(), data);
// Add one
block->m_static_objects.insert(0, s_obj);
delete obj;
}
} }
} }
} }
@ -4714,7 +4726,7 @@ plan_b:
// This won't work if proper generation is disabled // This won't work if proper generation is disabled
if(m_chunksize == 0) if(m_chunksize == 0)
return WATER_LEVEL+2; return WATER_LEVEL+2;
double level = base_rock_level_2d(m_seed, p2d); double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
return (s16)level; return (s16)level;
} }
@ -4794,7 +4806,7 @@ void ServerMap::save(bool only_changed)
u32 block_count = 0; u32 block_count = 0;
{ //sectorlock { //sectorlock
JMutexAutoLock lock(m_sector_mutex); //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator(); core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
for(; i.atEnd() == false; i++) for(; i.atEnd() == false; i++)
@ -4856,7 +4868,7 @@ void ServerMap::loadAll()
dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl; dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
JMutexAutoLock lock(m_sector_mutex); //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
s32 counter = 0; s32 counter = 0;
s32 printed_counter = -100000; s32 printed_counter = -100000;
@ -5163,7 +5175,7 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
MapSector *sector = NULL; MapSector *sector = NULL;
JMutexAutoLock lock(m_sector_mutex); //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
try{ try{
sector = loadSectorMeta(sectorsubdir); sector = loadSectorMeta(sectorsubdir);
@ -5410,7 +5422,7 @@ MapSector * ClientMap::emergeSector(v2s16 p2d)
ClientMapSector *sector = new ClientMapSector(this, p2d); ClientMapSector *sector = new ClientMapSector(this, p2d);
{ {
JMutexAutoLock lock(m_sector_mutex); //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
m_sectors.insert(p2d, sector); m_sectors.insert(p2d, sector);
} }
@ -5422,7 +5434,7 @@ void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
ClientMapSector *sector = NULL; ClientMapSector *sector = NULL;
JMutexAutoLock lock(m_sector_mutex); //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d); core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
@ -5435,7 +5447,7 @@ void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
{ {
sector = new ClientMapSector(this, p2d); sector = new ClientMapSector(this, p2d);
{ {
JMutexAutoLock lock(m_sector_mutex); //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
m_sectors.insert(p2d, sector); m_sectors.insert(p2d, sector);
} }
} }

@ -288,6 +288,11 @@ public:
void nodeMetadataStep(float dtime, void nodeMetadataStep(float dtime,
core::map<v3s16, MapBlock*> &changed_blocks); core::map<v3s16, MapBlock*> &changed_blocks);
/*
Misc.
*/
core::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
/* /*
Variables Variables
*/ */
@ -298,16 +303,13 @@ protected:
core::map<MapEventReceiver*, bool> m_event_receivers; core::map<MapEventReceiver*, bool> m_event_receivers;
// Mutex is important because on client map is accessed asynchronously
core::map<v2s16, MapSector*> m_sectors; core::map<v2s16, MapSector*> m_sectors;
JMutex m_sector_mutex; //JMutex m_sector_mutex;
// Be sure to set this to NULL when the cached sector is deleted // Be sure to set this to NULL when the cached sector is deleted
MapSector *m_sector_cache; MapSector *m_sector_cache;
v2s16 m_sector_cache_p; v2s16 m_sector_cache_p;
//WrapperHeightmap m_hwrapper;
// Queued transforming water nodes // Queued transforming water nodes
UniqueQueue<v3s16> m_transforming_liquid; UniqueQueue<v3s16> m_transforming_liquid;
}; };

@ -1923,11 +1923,21 @@ void MapBlock::serialize(std::ostream &os, u8 version)
NodeMetadata NodeMetadata
*/ */
if(version >= 14) if(version >= 14)
{
if(version <= 15)
{ {
std::ostringstream oss(std::ios_base::binary); std::ostringstream oss(std::ios_base::binary);
m_node_metadata.serialize(oss); m_node_metadata.serialize(oss);
os<<serializeString(oss.str()); os<<serializeString(oss.str());
} }
else
{
std::ostringstream oss(std::ios_base::binary);
m_node_metadata.serialize(oss);
compressZlib(oss.str(), os);
//os<<serializeLongString(oss.str());
}
}
} }
} }
@ -2055,10 +2065,21 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
{ {
// Ignore errors // Ignore errors
try{ try{
if(version <= 15)
{
std::string data = deSerializeString(is); std::string data = deSerializeString(is);
std::istringstream iss(data, std::ios_base::binary); std::istringstream iss(data, std::ios_base::binary);
m_node_metadata.deSerialize(iss); m_node_metadata.deSerialize(iss);
} }
else
{
//std::string data = deSerializeLongString(is);
std::ostringstream oss(std::ios_base::binary);
decompressZlib(is, oss);
std::istringstream iss(oss.str(), std::ios_base::binary);
m_node_metadata.deSerialize(iss);
}
}
catch(SerializationError &e) catch(SerializationError &e)
{ {
dstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error" dstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"

@ -33,6 +33,7 @@ Player::Player():
in_water_stable(false), in_water_stable(false),
swimming_up(false), swimming_up(false),
craftresult_is_preview(true), craftresult_is_preview(true),
hp(20),
peer_id(PEER_ID_INEXISTENT), peer_id(PEER_ID_INEXISTENT),
m_pitch(0), m_pitch(0),
m_yaw(0), m_yaw(0),
@ -102,6 +103,7 @@ void Player::serialize(std::ostream &os)
args.setFloat("yaw", m_yaw); args.setFloat("yaw", m_yaw);
args.setV3F("position", m_position); args.setV3F("position", m_position);
args.setBool("craftresult_is_preview", craftresult_is_preview); args.setBool("craftresult_is_preview", craftresult_is_preview);
args.setS32("hp", hp);
args.writeLines(os); args.writeLines(os);
@ -138,6 +140,11 @@ void Player::deSerialize(std::istream &is)
}catch(SettingNotFoundException &e){ }catch(SettingNotFoundException &e){
craftresult_is_preview = true; craftresult_is_preview = true;
} }
try{
hp = args.getS32("hp");
}catch(SettingNotFoundException &e){
hp = 20;
}
inventory.deSerialize(is); inventory.deSerialize(is);
} }
@ -276,7 +283,8 @@ LocalPlayer::~LocalPlayer()
{ {
} }
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d) void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
core::list<CollisionInfo> *collision_info)
{ {
v3f position = getPosition(); v3f position = getPosition();
v3f oldpos = position; v3f oldpos = position;
@ -530,9 +538,23 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
*/ */
if(other_axes_overlap && main_axis_collides) if(other_axes_overlap && main_axis_collides)
{ {
v3f old_speed = m_speed;
m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i]; m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
position -= position.dotProduct(dirs[i]) * dirs[i]; position -= position.dotProduct(dirs[i]) * dirs[i];
position += oldpos.dotProduct(dirs[i]) * dirs[i]; position += oldpos.dotProduct(dirs[i]) * dirs[i];
if(collision_info)
{
// Report fall collision
if(old_speed.Y < m_speed.Y - 0.1)
{
CollisionInfo info;
info.t = COLLISION_FALL;
info.speed = m_speed.Y - old_speed.Y;
collision_info->push_back(info);
}
}
} }
} }
@ -617,6 +639,11 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
setPosition(position); setPosition(position);
} }
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
{
move(dtime, map, pos_max_d, NULL);
}
void LocalPlayer::applyControl(float dtime) void LocalPlayer::applyControl(float dtime)
{ {
// Clear stuff // Clear stuff

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h" #include "common_irrlicht.h"
#include "inventory.h" #include "inventory.h"
#include "collision.h"
#define PLAYERNAME_SIZE 20 #define PLAYERNAME_SIZE 20
@ -124,6 +125,8 @@ public:
bool craftresult_is_preview; bool craftresult_is_preview;
u16 hp;
u16 peer_id; u16 peer_id;
protected: protected:
@ -325,6 +328,8 @@ public:
return true; return true;
} }
void move(f32 dtime, Map &map, f32 pos_max_d,
core::list<CollisionInfo> *collision_info);
void move(f32 dtime, Map &map, f32 pos_max_d); void move(f32 dtime, Map &map, f32 pos_max_d);
void applyControl(float dtime); void applyControl(float dtime);

@ -105,6 +105,12 @@ void compressZlib(SharedBuffer<u8> data, std::ostream &os)
} }
void compressZlib(const std::string &data, std::ostream &os)
{
SharedBuffer<u8> databuf((u8*)data.c_str(), data.size());
compressZlib(databuf, os);
}
void decompressZlib(std::istream &is, std::ostream &os) void decompressZlib(std::istream &is, std::ostream &os)
{ {
z_stream z; z_stream z;

@ -48,17 +48,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
13: (dev) Mapgen v2 13: (dev) Mapgen v2
14: (dev) NodeMetadata 14: (dev) NodeMetadata
15: (dev) StaticObjects 15: (dev) StaticObjects
16: (dev) larger maximum size of node metadata, and compression
*/ */
// This represents an uninitialized or invalid format // This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255 #define SER_FMT_VER_INVALID 255
// Highest supported serialization version // Highest supported serialization version
#define SER_FMT_VER_HIGHEST 15 #define SER_FMT_VER_HIGHEST 16
// Lowest supported serialization version // Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0 #define SER_FMT_VER_LOWEST 0
#define ser_ver_supported(v) (v >= SER_FMT_VER_LOWEST && v <= SER_FMT_VER_HIGHEST) #define ser_ver_supported(v) (v >= SER_FMT_VER_LOWEST && v <= SER_FMT_VER_HIGHEST)
void compressZlib(SharedBuffer<u8> data, std::ostream &os);
void compressZlib(const std::string &data, std::ostream &os);
void decompressZlib(std::istream &is, std::ostream &os);
void compress(SharedBuffer<u8> data, std::ostream &os, u8 version); void compress(SharedBuffer<u8> data, std::ostream &os, u8 version);
//void compress(const std::string &data, std::ostream &os, u8 version);
void decompress(std::istream &is, std::ostream &os, u8 version); void decompress(std::istream &is, std::ostream &os, u8 version);
/*class Serializable /*class Serializable

File diff suppressed because it is too large Load Diff

@ -33,6 +33,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h" #include "map.h"
#include "inventory.h" #include "inventory.h"
/*
Some random functions
*/
v3f findSpawnPos(ServerMap &map);
/*
A structure containing the data needed for queueing the fetching
of blocks.
*/
struct QueuedBlockEmerge struct QueuedBlockEmerge
{ {
v3s16 pos; v3s16 pos;
@ -397,12 +406,24 @@ private:
void peerAdded(con::Peer *peer); void peerAdded(con::Peer *peer);
void deletingPeer(con::Peer *peer, bool timeout); void deletingPeer(con::Peer *peer, bool timeout);
/*
Static send methods
*/
static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
/*
Non-static send methods
*/
// Envlock and conlock should be locked when calling these // Envlock and conlock should be locked when calling these
void SendObjectData(float dtime); void SendObjectData(float dtime);
void SendPlayerInfos(); void SendPlayerInfos();
void SendInventory(u16 peer_id); void SendInventory(u16 peer_id);
void SendChatMessage(u16 peer_id, const std::wstring &message); void SendChatMessage(u16 peer_id, const std::wstring &message);
void BroadcastChatMessage(const std::wstring &message); void BroadcastChatMessage(const std::wstring &message);
void SendPlayerHP(Player *player);
void SendMovePlayer(Player *player);
/* /*
Send a node removal/addition event to all clients except ignore_id. Send a node removal/addition event to all clients except ignore_id.
Additionally, if far_players!=NULL, players further away than Additionally, if far_players!=NULL, players further away than
@ -419,6 +440,12 @@ private:
// Sends blocks to clients // Sends blocks to clients
void SendBlocks(float dtime); void SendBlocks(float dtime);
/*
Something random
*/
void UpdateCrafting(u16 peer_id);
// When called, connection mutex should be locked // When called, connection mutex should be locked
RemoteClient* getClient(u16 peer_id); RemoteClient* getClient(u16 peer_id);

@ -451,4 +451,219 @@ InventoryItem* RatSAO::createPickedUpItem()
return item; return item;
} }
/*
Oerkki1SAO
*/
// Prototype
Oerkki1SAO proto_Oerkki1SAO(NULL, 0, v3f(0,0,0));
Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos):
ServerActiveObject(env, id, pos),
m_is_active(false),
m_speed_f(0,0,0)
{
ServerActiveObject::registerType(getType(), create);
m_oldpos = v3f(0,0,0);
m_last_sent_position = v3f(0,0,0);
m_yaw = 0;
m_counter1 = 0;
m_counter2 = 0;
m_age = 0;
m_touching_ground = false;
m_hp = 20;
}
ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, v3f pos,
const std::string &data)
{
std::istringstream is(data, std::ios::binary);
// read version
u8 version = readU8(is);
// read hp
u8 hp = readU8(is);
// check if version is supported
if(version != 0)
return NULL;
Oerkki1SAO *o = new Oerkki1SAO(env, id, pos);
o->m_hp = hp;
return o;
}
void Oerkki1SAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
bool send_recommended)
{
assert(m_env);
if(m_is_active == false)
{
if(m_inactive_interval.step(dtime, 0.5)==false)
return;
}
/*
The AI
*/
m_age += dtime;
if(m_age > 60)
{
// Die
m_removed = true;
return;
}
// Apply gravity
m_speed_f.Y -= dtime*9.81*BS;
/*
Move around if some player is close
*/
bool player_is_close = false;
v3f near_player_pos;
// Check connected players
core::list<Player*> players = m_env->getPlayers(true);
core::list<Player*>::Iterator i;
for(i = players.begin();
i != players.end(); i++)
{
Player *player = *i;
v3f playerpos = player->getPosition();
if(m_base_position.getDistanceFrom(playerpos) < BS*15.0)
{
player_is_close = true;
near_player_pos = playerpos;
break;
}
}
m_is_active = player_is_close;
if(player_is_close == false)
{
m_speed_f.X = 0;
m_speed_f.Z = 0;
}
else
{
// Move around
v3f ndir = near_player_pos - m_base_position;
ndir.Y = 0;
ndir /= ndir.getLength();
f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X);
if(nyaw < m_yaw - 180)
nyaw += 360;
else if(nyaw > m_yaw + 180)
nyaw -= 360;
m_yaw = 0.95*m_yaw + 0.05*nyaw;
m_yaw = wrapDegrees(m_yaw);
v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
f32 speed = 2*BS;
m_speed_f.X = speed * dir.X;
m_speed_f.Z = speed * dir.Z;
if(m_touching_ground && (m_oldpos - m_base_position).getLength()
< dtime*speed/2)
{
m_counter1 -= dtime;
if(m_counter1 < 0.0)
{
m_counter1 += 1.0;
// Jump
m_speed_f.Y = 5.0*BS;
}
}
{
m_counter2 -= dtime;
if(m_counter2 < 0.0)
{
m_counter2 += (float)(myrand()%100)/100*3.0;
//m_yaw += ((float)(myrand()%200)-100)/100*180;
m_yaw += ((float)(myrand()%200)-100)/100*90;
m_yaw = wrapDegrees(m_yaw);
}
}
}
m_oldpos = m_base_position;
/*
Move it, with collision detection
*/
core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.);
collisionMoveResult moveresult;
// Maximum movement without glitches
f32 pos_max_d = BS*0.25;
// Limit speed
if(m_speed_f.getLength()*dtime > pos_max_d)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
box, dtime, pos_f, m_speed_f);
m_touching_ground = moveresult.touching_ground;
setBasePosition(pos_f);
if(send_recommended == false)
return;
if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
{
m_last_sent_position = pos_f;
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, 0);
// pos
writeV3F1000(os, m_base_position);
// yaw
writeF1000(os, m_yaw);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
messages.push_back(aom);
}
}
std::string Oerkki1SAO::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// pos
writeV3F1000(os, m_base_position);
return os.str();
}
std::string Oerkki1SAO::getStaticData()
{
//dstream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// hp
writeU8(os, m_hp);
return os.str();
}
u16 Oerkki1SAO::punch(const std::string &toolname)
{
u16 amount = 5;
if(amount < m_hp)
{
m_hp -= amount;
}
else
{
// Die
m_removed = true;
}
return 65536/100;
}

@ -100,6 +100,12 @@ public:
*/ */
virtual InventoryItem* createPickedUpItem(){return NULL;} virtual InventoryItem* createPickedUpItem(){return NULL;}
/*
If the object doesn't return an item, this will be called.
Return value is tool wear.
*/
virtual u16 punch(const std::string &toolname){return 0;}
// Number of players which know about this object // Number of players which know about this object
u16 m_known_by_count; u16 m_known_by_count;
/* /*
@ -201,5 +207,33 @@ private:
bool m_touching_ground; bool m_touching_ground;
}; };
class Oerkki1SAO : public ServerActiveObject
{
public:
Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos);
u8 getType() const
{return ACTIVEOBJECT_TYPE_OERKKI1;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
const std::string &data);
void step(float dtime, Queue<ActiveObjectMessage> &messages,
bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
InventoryItem* createPickedUpItem(){return NULL;}
u16 punch(const std::string &toolname);
private:
bool m_is_active;
IntervalLimiter m_inactive_interval;
v3f m_speed_f;
v3f m_oldpos;
v3f m_last_sent_position;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
u8 m_hp;
};
#endif #endif

@ -951,18 +951,18 @@ struct TestConnection
assert(got_exception); assert(got_exception);
} }
{ {
//u8 data1[1100]; const int datasize = 30000;
SharedBuffer<u8> data1(1100); SharedBuffer<u8> data1(datasize);
for(u16 i=0; i<1100; i++){ for(u16 i=0; i<datasize; i++){
data1[i] = i/4; data1[i] = i/4;
} }
dstream<<"Sending data (size="<<1100<<"):"; dstream<<"Sending data (size="<<datasize<<"):";
for(int i=0; i<1100 && i<20; i++){ for(int i=0; i<datasize && i<20; i++){
if(i%2==0) DEBUGPRINT(" "); if(i%2==0) DEBUGPRINT(" ");
DEBUGPRINT("%.2X", ((int)((const char*)*data1)[i])&0xff); DEBUGPRINT("%.2X", ((int)((const char*)*data1)[i])&0xff);
} }
if(1100>20) if(datasize>20)
dstream<<"..."; dstream<<"...";
dstream<<std::endl; dstream<<std::endl;
@ -970,10 +970,10 @@ struct TestConnection
sleep_ms(50); sleep_ms(50);
u8 recvdata[2000]; u8 recvdata[datasize + 1000];
dstream<<"** running client.Receive()"<<std::endl; dstream<<"** running client.Receive()"<<std::endl;
u16 peer_id = 132; u16 peer_id = 132;
u16 size = client.Receive(peer_id, recvdata, 2000); u16 size = client.Receive(peer_id, recvdata, datasize + 1000);
dstream<<"** Client received: peer_id="<<peer_id dstream<<"** Client received: peer_id="<<peer_id
<<", size="<<size <<", size="<<size
<<std::endl; <<std::endl;

@ -215,8 +215,8 @@ inline void writeU16(std::ostream &os, u16 p)
} }
inline u16 readU16(std::istream &is) inline u16 readU16(std::istream &is)
{ {
char buf[12]; char buf[2];
is.read(buf, 12); is.read(buf, 2);
return readU16((u8*)buf); return readU16((u8*)buf);
} }
@ -228,8 +228,8 @@ inline void writeF1000(std::ostream &os, f32 p)
} }
inline f32 readF1000(std::istream &is) inline f32 readF1000(std::istream &is)
{ {
char buf[12]; char buf[2];
is.read(buf, 12); is.read(buf, 2);
return readF1000((u8*)buf); return readF1000((u8*)buf);
} }