Some work-in-progress in hp and mobs and a frightening amount of random fixes.
After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 212 B |
BIN
data/stick.png
Before Width: | Height: | Size: 947 B After Width: | Height: | Size: 182 B |
Before Width: | Height: | Size: 990 B After Width: | Height: | Size: 252 B |
Before Width: | Height: | Size: 207 B After Width: | Height: | Size: 209 B |
Before Width: | Height: | Size: 272 B After Width: | Height: | Size: 271 B |
Before Width: | Height: | Size: 235 B After Width: | Height: | Size: 216 B |
Before Width: | Height: | Size: 196 B After Width: | Height: | Size: 193 B |
Before Width: | Height: | Size: 990 B After Width: | Height: | Size: 262 B |
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 196 B After Width: | Height: | Size: 190 B |
Before Width: | Height: | Size: 989 B After Width: | Height: | Size: 245 B |
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)
|
||||
#creative_mode = false
|
||||
|
||||
#enable_damage = false
|
||||
|
||||
# Player and object positions are sent at intervals specified by this
|
||||
#objectdata_inverval = 0.2
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ struct ActiveObjectMessage
|
|||
#define ACTIVEOBJECT_TYPE_TEST 1
|
||||
#define ACTIVEOBJECT_TYPE_ITEM 2
|
||||
#define ACTIVEOBJECT_TYPE_RAT 3
|
||||
#define ACTIVEOBJECT_TYPE_OERKKI1 4
|
||||
|
||||
/*
|
||||
Parent class for ServerActiveObject and ClientActiveObject
|
||||
|
|
336
src/client.cpp
|
@ -90,6 +90,7 @@ Client::Client(
|
|||
m_connection_reinit_timer = 0.0;
|
||||
m_avg_rtt_timer = 0.0;
|
||||
m_playerpos_send_timer = 0.0;
|
||||
m_ignore_damage_timer = 0.0;
|
||||
|
||||
//m_env_mutex.Init();
|
||||
//m_con_mutex.Init();
|
||||
|
@ -154,6 +155,10 @@ void Client::step(float dtime)
|
|||
if(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;
|
||||
|
||||
|
@ -311,6 +316,9 @@ void Client::step(float dtime)
|
|||
Do stuff if connected
|
||||
*/
|
||||
|
||||
/*
|
||||
Handle environment
|
||||
*/
|
||||
{
|
||||
// 0ms
|
||||
//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;
|
||||
counter += dtime;
|
||||
|
@ -355,6 +392,10 @@ void Client::step(float dtime)
|
|||
dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Send player position to server
|
||||
*/
|
||||
{
|
||||
float &counter = m_playerpos_send_timer;
|
||||
counter += dtime;
|
||||
|
@ -388,6 +429,8 @@ void Client::step(float dtime)
|
|||
}
|
||||
if(r.ack_block_to_server)
|
||||
{
|
||||
/*dstream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
|
||||
<<","<<r.p.Z<<")"<<std::endl;*/
|
||||
/*
|
||||
Acknowledge block
|
||||
*/
|
||||
|
@ -447,7 +490,7 @@ void Client::ReceiveAll()
|
|||
void Client::Receive()
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
u32 data_maxsize = 10000;
|
||||
u32 data_maxsize = 200000;
|
||||
Buffer<u8> data(data_maxsize);
|
||||
u16 sender_peer_id;
|
||||
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 "
|
||||
<<command<<std::endl;
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
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
|
||||
// Default to queueing it (for slow commands)
|
||||
else
|
||||
else if(command == TOCLIENT_MOVE_PLAYER)
|
||||
{
|
||||
JMutexAutoLock lock(m_incoming_queue_mutex);
|
||||
|
||||
IncomingPacket packet(data, datasize);
|
||||
m_incoming_queue.push_back(packet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
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);*/
|
||||
|
||||
#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.
|
||||
*/
|
||||
/*
|
||||
[0] u16 command
|
||||
[2] u8 count
|
||||
[3] v3s16 pos_0
|
||||
[3+6] v3s16 pos_1
|
||||
...
|
||||
*/
|
||||
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);
|
||||
dstream<<"Client got TOCLIENT_MOVE_PLAYER"
|
||||
<<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
|
||||
<<" pitch="<<pitch
|
||||
<<" yaw="<<yaw
|
||||
<<std::endl;
|
||||
|
||||
/*
|
||||
Update Mesh of this block and blocks at x-, y- and z-.
|
||||
Environment should not be locked as it interlocks with the
|
||||
main thread, from which is will want to retrieve textures.
|
||||
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;
|
||||
event.type = CE_PLAYER_FORCE_MOVE;
|
||||
event.player_force_move.pitch = pitch;
|
||||
event.player_force_move.yaw = yaw;
|
||||
m_client_event_queue.push_back(event);
|
||||
|
||||
//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);
|
||||
}
|
||||
// Ignore damage for a few seconds, so that the player doesn't
|
||||
// get damage from falling on ground
|
||||
m_ignore_damage_timer = 3.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
|
||||
<<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)
|
||||
{
|
||||
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
|
||||
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,
|
||||
v3s16 nodepos_oversurface, u16 item)
|
||||
{
|
||||
|
@ -1739,6 +1597,21 @@ void Client::sendChatMessage(const std::wstring &message)
|
|||
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()
|
||||
{
|
||||
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
|
||||
|
@ -2061,6 +1934,13 @@ u32 Client::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)
|
||||
{
|
||||
/*dstream<<"Client::addUpdateMeshTask(): "
|
||||
|
@ -2141,3 +2021,15 @@ void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
|
|||
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();
|
||||
}
|
||||
|
||||
|
||||
|
|
79
src/client.h
|
@ -174,55 +174,28 @@ public:
|
|||
MutexedQueue<MeshUpdateResult> m_queue_out;
|
||||
};
|
||||
|
||||
#if 0
|
||||
struct IncomingPacket
|
||||
enum ClientEventType
|
||||
{
|
||||
IncomingPacket()
|
||||
{
|
||||
m_data = NULL;
|
||||
m_datalen = 0;
|
||||
m_refcount = NULL;
|
||||
}
|
||||
IncomingPacket(const IncomingPacket &a)
|
||||
{
|
||||
m_data = a.m_data;
|
||||
m_datalen = a.m_datalen;
|
||||
m_refcount = a.m_refcount;
|
||||
if(m_refcount != NULL)
|
||||
(*m_refcount)++;
|
||||
}
|
||||
IncomingPacket(u8 *data, u32 datalen)
|
||||
{
|
||||
m_data = new u8[datalen];
|
||||
memcpy(m_data, data, datalen);
|
||||
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;
|
||||
CE_NONE,
|
||||
CE_PLAYER_DAMAGE,
|
||||
CE_PLAYER_FORCE_MOVE
|
||||
};
|
||||
|
||||
struct ClientEvent
|
||||
{
|
||||
ClientEventType type;
|
||||
union{
|
||||
struct{
|
||||
} none;
|
||||
struct{
|
||||
u8 amount;
|
||||
} player_damage;
|
||||
struct{
|
||||
f32 pitch;
|
||||
f32 yaw;
|
||||
} player_force_move;
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
class Client : public con::PeerHandler, public InventoryManager
|
||||
{
|
||||
|
@ -281,6 +254,7 @@ public:
|
|||
void sendSignNodeText(v3s16 p, std::string text);
|
||||
void sendInventoryAction(InventoryAction *a);
|
||||
void sendChatMessage(const std::wstring &message);
|
||||
void sendDamage(u8 damage);
|
||||
|
||||
// locks envlock
|
||||
void removeNode(v3s16 p);
|
||||
|
@ -330,6 +304,8 @@ public:
|
|||
|
||||
u32 getDayNightRatio();
|
||||
|
||||
u16 getHP();
|
||||
|
||||
//void updateSomeExpiredMeshes();
|
||||
|
||||
void setTempMod(v3s16 p, NodeMod mod)
|
||||
|
@ -394,13 +370,13 @@ public:
|
|||
|
||||
u64 getMapSeed(){ return m_map_seed; }
|
||||
|
||||
/*
|
||||
These are not thread-safe
|
||||
*/
|
||||
void addUpdateMeshTask(v3s16 blockpos, bool ack_to_server=false);
|
||||
// Including blocks at appropriate edges
|
||||
void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false);
|
||||
|
||||
// Get event from queue. CE_NONE is returned if queue is empty.
|
||||
ClientEvent getClientEvent();
|
||||
|
||||
private:
|
||||
|
||||
// Virtual methods from con::PeerHandler
|
||||
|
@ -419,6 +395,7 @@ private:
|
|||
float m_connection_reinit_timer;
|
||||
float m_avg_rtt_timer;
|
||||
float m_playerpos_send_timer;
|
||||
float m_ignore_damage_timer; // Used after server moves player
|
||||
|
||||
MeshUpdateThread m_mesh_update_thread;
|
||||
|
||||
|
@ -454,6 +431,8 @@ private:
|
|||
u64 m_map_seed;
|
||||
|
||||
InventoryContext m_inventory_context;
|
||||
|
||||
Queue<ClientEvent> m_client_event_queue;
|
||||
};
|
||||
|
||||
#endif // !SERVER
|
||||
|
|
|
@ -494,7 +494,7 @@ void RatCAO::updateLight(u8 light_at_pos)
|
|||
|
||||
v3s16 RatCAO::getLightPosition()
|
||||
{
|
||||
return floatToInt(m_position, BS);
|
||||
return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
|
||||
}
|
||||
|
||||
void RatCAO::updateNodePos()
|
||||
|
@ -552,4 +552,181 @@ void RatCAO::initialize(const std::string &data)
|
|||
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 "activeobject.h"
|
||||
#include "utility.h"
|
||||
|
||||
/*
|
||||
|
||||
|
@ -267,5 +268,49 @@ private:
|
|||
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
|
||||
|
||||
|
|
|
@ -33,15 +33,18 @@ enum ToClientCommand
|
|||
|
||||
[0] u16 TOSERVER_INIT
|
||||
[2] u8 deployed version
|
||||
[3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
|
||||
[4] u64 map seed (new as of 2011-02-27)
|
||||
[3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
|
||||
([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_ADDNODE = 0x21,
|
||||
TOCLIENT_REMOVENODE = 0x22,
|
||||
|
||||
TOCLIENT_PLAYERPOS = 0x23,
|
||||
TOCLIENT_PLAYERPOS = 0x23, // Obsolete
|
||||
/*
|
||||
[0] u16 command
|
||||
// Followed by an arbitary number of these:
|
||||
|
@ -62,9 +65,9 @@ enum ToClientCommand
|
|||
[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
|
||||
[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
|
||||
|
@ -155,9 +171,9 @@ enum ToServerCommand
|
|||
[0] u16 TOSERVER_INIT2
|
||||
*/
|
||||
|
||||
TOSERVER_GETBLOCK=0x20, // Not used
|
||||
TOSERVER_ADDNODE = 0x21, // Not used
|
||||
TOSERVER_REMOVENODE = 0x22, // deprecated
|
||||
TOSERVER_GETBLOCK=0x20, // Obsolete
|
||||
TOSERVER_ADDNODE = 0x21, // Obsolete
|
||||
TOSERVER_REMOVENODE = 0x22, // Obsolete
|
||||
|
||||
TOSERVER_PLAYERPOS = 0x23,
|
||||
/*
|
||||
|
@ -186,7 +202,7 @@ enum ToServerCommand
|
|||
...
|
||||
*/
|
||||
|
||||
TOSERVER_ADDNODE_FROM_INVENTORY = 0x26, // deprecated
|
||||
TOSERVER_ADDNODE_FROM_INVENTORY = 0x26, // Obsolete
|
||||
/*
|
||||
[0] u16 command
|
||||
[2] v3s16 pos
|
||||
|
@ -218,9 +234,9 @@ enum ToServerCommand
|
|||
3: digging completed
|
||||
*/
|
||||
|
||||
TOSERVER_RELEASE = 0x29, // Not used
|
||||
TOSERVER_RELEASE = 0x29, // Obsolete
|
||||
|
||||
TOSERVER_SIGNTEXT = 0x30,
|
||||
TOSERVER_SIGNTEXT = 0x30, // Old signs
|
||||
/*
|
||||
u16 command
|
||||
v3s16 blockpos
|
||||
|
@ -257,7 +273,12 @@ enum ToServerCommand
|
|||
[3] u16 id
|
||||
[5] u16 item
|
||||
*/
|
||||
|
||||
|
||||
TOSERVER_DAMAGE = 0x35,
|
||||
/*
|
||||
u16 command
|
||||
u8 amount
|
||||
*/
|
||||
};
|
||||
|
||||
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
|
||||
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 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);
|
||||
//{return collisionMoveResult();}
|
||||
|
||||
enum CollisionType
|
||||
{
|
||||
COLLISION_FALL
|
||||
};
|
||||
|
||||
struct CollisionInfo
|
||||
{
|
||||
CollisionType t;
|
||||
f32 speed;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ void set_default_settings()
|
|||
|
||||
g_settings.setDefault("enable_experimental", "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("active_object_range", "2");
|
||||
|
|
|
@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "environment.h"
|
||||
#include "filesys.h"
|
||||
#include "porting.h"
|
||||
#include "collision.h"
|
||||
|
||||
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)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
@ -429,26 +479,29 @@ void ServerEnvironment::step(float dtime)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Step active objects
|
||||
*/
|
||||
|
||||
bool send_recommended = false;
|
||||
m_send_recommended_timer += dtime;
|
||||
if(m_send_recommended_timer > 0.15)
|
||||
{
|
||||
m_send_recommended_timer = 0;
|
||||
send_recommended = true;
|
||||
}
|
||||
//TimeTaker timer("Step active objects");
|
||||
|
||||
for(core::map<u16, ServerActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
ServerActiveObject* obj = i.getNode()->getValue();
|
||||
// Step object, putting messages directly to the queue
|
||||
obj->step(dtime, m_active_object_messages, send_recommended);
|
||||
bool send_recommended = false;
|
||||
m_send_recommended_timer += dtime;
|
||||
if(m_send_recommended_timer > 0.15)
|
||||
{
|
||||
m_send_recommended_timer = 0;
|
||||
send_recommended = true;
|
||||
}
|
||||
|
||||
for(core::map<u16, ServerActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
ServerActiveObject* obj = i.getNode()->getValue();
|
||||
// Step object, putting messages directly to the queue
|
||||
obj->step(dtime, m_active_object_messages, send_recommended);
|
||||
}
|
||||
}
|
||||
|
||||
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 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.
|
||||
|
@ -719,7 +772,8 @@ void ServerEnvironment::step(float dtime)
|
|||
|
||||
//TestSAO *obj = new TestSAO(this, 0, pos);
|
||||
//ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
|
||||
ServerActiveObject *obj = new RatSAO(this, 0, pos);
|
||||
//ServerActiveObject *obj = new RatSAO(this, 0, pos);
|
||||
ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
|
||||
addActiveObject(obj);
|
||||
}
|
||||
#endif
|
||||
|
@ -976,14 +1030,18 @@ void ClientEnvironment::step(float dtime)
|
|||
//TimeTaker timer("Client m_map->timerUpdate()", g_device);
|
||||
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
|
||||
*/
|
||||
f32 player_speed = 0.001; // just some small value
|
||||
LocalPlayer *lplayer = getLocalPlayer();
|
||||
if(lplayer)
|
||||
player_speed = lplayer->getSpeed().getLength();
|
||||
player_speed = lplayer->getSpeed().getLength();
|
||||
|
||||
/*
|
||||
Maximum position increment
|
||||
|
@ -1036,20 +1094,18 @@ void ClientEnvironment::step(float dtime)
|
|||
*/
|
||||
|
||||
{
|
||||
Player *player = getLocalPlayer();
|
||||
|
||||
v3f playerpos = player->getPosition();
|
||||
v3f lplayerpos = lplayer->getPosition();
|
||||
|
||||
// Apply physics
|
||||
if(free_move == false)
|
||||
{
|
||||
// Gravity
|
||||
v3f speed = player->getSpeed();
|
||||
if(player->swimming_up == false)
|
||||
v3f speed = lplayer->getSpeed();
|
||||
if(lplayer->swimming_up == false)
|
||||
speed.Y -= 9.81 * BS * dtime_part * 2;
|
||||
|
||||
// Water resistance
|
||||
if(player->in_water_stable || player->in_water)
|
||||
if(lplayer->in_water_stable || lplayer->in_water)
|
||||
{
|
||||
f32 max_down = 2.0*BS;
|
||||
if(speed.Y < -max_down) speed.Y = -max_down;
|
||||
|
@ -1061,19 +1117,47 @@ void ClientEnvironment::step(float dtime)
|
|||
}
|
||||
}
|
||||
|
||||
player->setSpeed(speed);
|
||||
lplayer->setSpeed(speed);
|
||||
}
|
||||
|
||||
/*
|
||||
Move the player.
|
||||
Move the lplayer.
|
||||
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);
|
||||
|
||||
//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
|
||||
|
@ -1287,6 +1371,30 @@ void ClientEnvironment::processActiveObjectMessage(u16 id,
|
|||
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,
|
||||
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
|
||||
|
||||
|
|
|
@ -170,6 +170,24 @@ private:
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
@ -214,15 +232,29 @@ public:
|
|||
void removeActiveObject(u16 id);
|
||||
|
||||
void processActiveObjectMessage(u16 id, const std::string &data);
|
||||
|
||||
/*
|
||||
Callbacks for activeobjects
|
||||
*/
|
||||
|
||||
void damageLocalPlayer(u8 damage);
|
||||
|
||||
/*
|
||||
Client likes to call these
|
||||
*/
|
||||
|
||||
// Get all nearby objects
|
||||
void getActiveObjects(v3f origin, f32 max_d,
|
||||
core::array<DistanceSortedActiveObject> &dest);
|
||||
|
||||
// Get event from queue. CEE_NONE is returned if queue is empty.
|
||||
ClientEnvEvent getClientEvent();
|
||||
|
||||
private:
|
||||
ClientMap *m_map;
|
||||
scene::ISceneManager *m_smgr;
|
||||
core::map<u16, ClientActiveObject*> m_active_objects;
|
||||
Queue<ClientEnvEvent> m_client_event_queue;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -369,6 +369,12 @@ public:
|
|||
basename = "tool_stoneaxe.png";
|
||||
else if(m_toolname == "SteelAxe")
|
||||
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
|
||||
basename = "cloud.png";
|
||||
|
||||
|
|
551
src/main.cpp
|
@ -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
|
||||
bartwe's game
|
||||
|
||||
SUGG: Background music based on cellular automata?
|
||||
http://www.earslap.com/projectslab/otomata
|
||||
|
||||
|
||||
Gaming ideas:
|
||||
-------------
|
||||
|
||||
|
@ -126,6 +130,12 @@ Game content:
|
|||
- You can drop on top of it, and have some time to attack there
|
||||
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:
|
||||
--------------
|
||||
|
||||
|
@ -1210,7 +1220,7 @@ void updateViewingRange(f32 frametime_in, Client *client)
|
|||
|
||||
void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
|
||||
v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
|
||||
Inventory *inventory)
|
||||
Inventory *inventory, s32 halfheartcount)
|
||||
{
|
||||
InventoryList *mainlist = inventory->getList("main");
|
||||
if(mainlist == NULL)
|
||||
|
@ -1259,6 +1269,40 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
|
|||
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
|
||||
|
@ -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[])
|
||||
{
|
||||
/*
|
||||
|
@ -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,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);
|
||||
|
||||
// Just so big a value that everything rendered is visible
|
||||
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_pitch = 0; // "up/down"
|
||||
|
||||
|
@ -2226,6 +2463,8 @@ int main(int argc, char *argv[])
|
|||
|
||||
core::list<float> frametime_log;
|
||||
|
||||
float damage_flash_timer = 0;
|
||||
|
||||
/*
|
||||
Main loop
|
||||
*/
|
||||
|
@ -2453,6 +2692,16 @@ int main(int argc, char *argv[])
|
|||
);
|
||||
client.setPlayerControl(control);
|
||||
}
|
||||
|
||||
/*
|
||||
Run server
|
||||
*/
|
||||
|
||||
if(server != NULL)
|
||||
{
|
||||
//TimeTaker timer("server->step(dtime)");
|
||||
server->step(dtime);
|
||||
}
|
||||
|
||||
/*
|
||||
Process environment
|
||||
|
@ -2464,12 +2713,28 @@ int main(int argc, char *argv[])
|
|||
//client.step(dtime_avg1);
|
||||
}
|
||||
|
||||
if(server != NULL)
|
||||
// Read client events
|
||||
for(;;)
|
||||
{
|
||||
//TimeTaker timer("server->step(dtime)");
|
||||
server->step(dtime);
|
||||
ClientEvent event = client.getClientEvent();
|
||||
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();
|
||||
|
||||
//TimeTaker //timer2("//timer2");
|
||||
|
@ -2637,22 +2902,6 @@ int main(int argc, char *argv[])
|
|||
else if(g_input->getRightClicked())
|
||||
{
|
||||
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
|
||||
|
@ -2666,205 +2915,13 @@ int main(int argc, char *argv[])
|
|||
v3s16 nodepos;
|
||||
v3s16 neighbourpos;
|
||||
core::aabbox3d<f32> nodehilightbox;
|
||||
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 = 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
|
||||
|
||||
getPointedNode(player_position,
|
||||
camera_direction, camera_position,
|
||||
nodefound, shootline,
|
||||
nodepos, neighbourpos,
|
||||
nodehilightbox, d);
|
||||
|
||||
static float nodig_delay_counter = 0.0;
|
||||
|
||||
if(nodefound)
|
||||
|
@ -3430,10 +3487,26 @@ int main(int argc, char *argv[])
|
|||
*/
|
||||
{
|
||||
draw_hotbar(driver, font, v2s32(displaycenter.X, screensize.Y),
|
||||
hotbar_imagesize, hotbar_itemcount, &local_inventory);
|
||||
hotbar_imagesize, hotbar_itemcount, &local_inventory,
|
||||
client.getHP());
|
||||
}
|
||||
|
||||
/*
|
||||
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 drawing
|
||||
/*
|
||||
End scene
|
||||
*/
|
||||
{
|
||||
TimeTaker timer("endScene");
|
||||
driver->endScene();
|
||||
|
|
36
src/map.cpp
|
@ -37,8 +37,8 @@ Map::Map(std::ostream &dout):
|
|||
m_dout(dout),
|
||||
m_sector_cache(NULL)
|
||||
{
|
||||
m_sector_mutex.Init();
|
||||
assert(m_sector_mutex.IsInitialized());
|
||||
/*m_sector_mutex.Init();
|
||||
assert(m_sector_mutex.IsInitialized());*/
|
||||
}
|
||||
|
||||
Map::~Map()
|
||||
|
@ -104,7 +104,7 @@ MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
|
|||
|
||||
MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
|
||||
{
|
||||
JMutexAutoLock lock(m_sector_mutex);
|
||||
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
||||
|
||||
return getSectorNoGenerateNoExNoLock(p);
|
||||
}
|
||||
|
@ -1347,7 +1347,7 @@ bool Map::dayNightDiffed(v3s16 blockpos)
|
|||
*/
|
||||
void Map::timerUpdate(float dtime)
|
||||
{
|
||||
JMutexAutoLock lock(m_sector_mutex);
|
||||
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
||||
|
||||
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,
|
||||
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::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
|
||||
|
@ -2163,6 +2163,18 @@ void addRandomObjects(MapBlock *block)
|
|||
block->m_static_objects.insert(0, s_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
|
||||
if(m_chunksize == 0)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -4794,7 +4806,7 @@ void ServerMap::save(bool only_changed)
|
|||
u32 block_count = 0;
|
||||
|
||||
{ //sectorlock
|
||||
JMutexAutoLock lock(m_sector_mutex);
|
||||
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
||||
|
||||
core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
|
||||
for(; i.atEnd() == false; i++)
|
||||
|
@ -4856,7 +4868,7 @@ void ServerMap::loadAll()
|
|||
|
||||
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 printed_counter = -100000;
|
||||
|
@ -5163,7 +5175,7 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
|
|||
|
||||
MapSector *sector = NULL;
|
||||
|
||||
JMutexAutoLock lock(m_sector_mutex);
|
||||
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
||||
|
||||
try{
|
||||
sector = loadSectorMeta(sectorsubdir);
|
||||
|
@ -5410,7 +5422,7 @@ MapSector * ClientMap::emergeSector(v2s16 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);
|
||||
}
|
||||
|
||||
|
@ -5422,7 +5434,7 @@ void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
|
|||
DSTACK(__FUNCTION_NAME);
|
||||
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);
|
||||
|
||||
|
@ -5435,7 +5447,7 @@ void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
|
|||
{
|
||||
sector = new ClientMapSector(this, p2d);
|
||||
{
|
||||
JMutexAutoLock lock(m_sector_mutex);
|
||||
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
||||
m_sectors.insert(p2d, sector);
|
||||
}
|
||||
}
|
||||
|
|
10
src/map.h
|
@ -287,6 +287,11 @@ public:
|
|||
void removeNodeMetadata(v3s16 p);
|
||||
void nodeMetadataStep(float dtime,
|
||||
core::map<v3s16, MapBlock*> &changed_blocks);
|
||||
|
||||
/*
|
||||
Misc.
|
||||
*/
|
||||
core::map<v2s16, MapSector*> *getSectorsPtr(){return &m_sectors;}
|
||||
|
||||
/*
|
||||
Variables
|
||||
|
@ -298,16 +303,13 @@ protected:
|
|||
|
||||
core::map<MapEventReceiver*, bool> m_event_receivers;
|
||||
|
||||
// Mutex is important because on client map is accessed asynchronously
|
||||
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
|
||||
MapSector *m_sector_cache;
|
||||
v2s16 m_sector_cache_p;
|
||||
|
||||
//WrapperHeightmap m_hwrapper;
|
||||
|
||||
// Queued transforming water nodes
|
||||
UniqueQueue<v3s16> m_transforming_liquid;
|
||||
};
|
||||
|
|
|
@ -1924,9 +1924,19 @@ void MapBlock::serialize(std::ostream &os, u8 version)
|
|||
*/
|
||||
if(version >= 14)
|
||||
{
|
||||
std::ostringstream oss(std::ios_base::binary);
|
||||
m_node_metadata.serialize(oss);
|
||||
os<<serializeString(oss.str());
|
||||
if(version <= 15)
|
||||
{
|
||||
std::ostringstream oss(std::ios_base::binary);
|
||||
m_node_metadata.serialize(oss);
|
||||
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,9 +2065,20 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
|
|||
{
|
||||
// Ignore errors
|
||||
try{
|
||||
std::string data = deSerializeString(is);
|
||||
std::istringstream iss(data, std::ios_base::binary);
|
||||
m_node_metadata.deSerialize(iss);
|
||||
if(version <= 15)
|
||||
{
|
||||
std::string data = deSerializeString(is);
|
||||
std::istringstream iss(data, std::ios_base::binary);
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -33,6 +33,7 @@ Player::Player():
|
|||
in_water_stable(false),
|
||||
swimming_up(false),
|
||||
craftresult_is_preview(true),
|
||||
hp(20),
|
||||
peer_id(PEER_ID_INEXISTENT),
|
||||
m_pitch(0),
|
||||
m_yaw(0),
|
||||
|
@ -102,6 +103,7 @@ void Player::serialize(std::ostream &os)
|
|||
args.setFloat("yaw", m_yaw);
|
||||
args.setV3F("position", m_position);
|
||||
args.setBool("craftresult_is_preview", craftresult_is_preview);
|
||||
args.setS32("hp", hp);
|
||||
|
||||
args.writeLines(os);
|
||||
|
||||
|
@ -138,6 +140,11 @@ void Player::deSerialize(std::istream &is)
|
|||
}catch(SettingNotFoundException &e){
|
||||
craftresult_is_preview = true;
|
||||
}
|
||||
try{
|
||||
hp = args.getS32("hp");
|
||||
}catch(SettingNotFoundException &e){
|
||||
hp = 20;
|
||||
}
|
||||
|
||||
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 oldpos = position;
|
||||
|
@ -530,9 +538,23 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
|||
*/
|
||||
if(other_axes_overlap && main_axis_collides)
|
||||
{
|
||||
v3f old_speed = m_speed;
|
||||
|
||||
m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
|
||||
position -= position.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);
|
||||
}
|
||||
|
||||
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
||||
{
|
||||
move(dtime, map, pos_max_d, NULL);
|
||||
}
|
||||
|
||||
void LocalPlayer::applyControl(float dtime)
|
||||
{
|
||||
// Clear stuff
|
||||
|
|
|
@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
#include "common_irrlicht.h"
|
||||
#include "inventory.h"
|
||||
#include "collision.h"
|
||||
|
||||
#define PLAYERNAME_SIZE 20
|
||||
|
||||
|
@ -124,6 +125,8 @@ public:
|
|||
|
||||
bool craftresult_is_preview;
|
||||
|
||||
u16 hp;
|
||||
|
||||
u16 peer_id;
|
||||
|
||||
protected:
|
||||
|
@ -325,6 +328,8 @@ public:
|
|||
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 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)
|
||||
{
|
||||
z_stream z;
|
||||
|
|
|
@ -48,17 +48,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
13: (dev) Mapgen v2
|
||||
14: (dev) NodeMetadata
|
||||
15: (dev) StaticObjects
|
||||
16: (dev) larger maximum size of node metadata, and compression
|
||||
*/
|
||||
// This represents an uninitialized or invalid format
|
||||
#define SER_FMT_VER_INVALID 255
|
||||
// Highest supported serialization version
|
||||
#define SER_FMT_VER_HIGHEST 15
|
||||
#define SER_FMT_VER_HIGHEST 16
|
||||
// Lowest supported serialization version
|
||||
#define SER_FMT_VER_LOWEST 0
|
||||
|
||||
#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(const std::string &data, std::ostream &os, u8 version);
|
||||
void decompress(std::istream &is, std::ostream &os, u8 version);
|
||||
|
||||
/*class Serializable
|
||||
|
|
864
src/server.cpp
27
src/server.h
|
@ -33,6 +33,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "map.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
|
||||
{
|
||||
v3s16 pos;
|
||||
|
@ -397,12 +406,24 @@ private:
|
|||
void peerAdded(con::Peer *peer);
|
||||
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
|
||||
void SendObjectData(float dtime);
|
||||
void SendPlayerInfos();
|
||||
void SendInventory(u16 peer_id);
|
||||
void SendChatMessage(u16 peer_id, 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.
|
||||
Additionally, if far_players!=NULL, players further away than
|
||||
|
@ -418,6 +439,12 @@ private:
|
|||
|
||||
// Sends blocks to clients
|
||||
void SendBlocks(float dtime);
|
||||
|
||||
/*
|
||||
Something random
|
||||
*/
|
||||
|
||||
void UpdateCrafting(u16 peer_id);
|
||||
|
||||
// When called, connection mutex should be locked
|
||||
RemoteClient* getClient(u16 peer_id);
|
||||
|
|
|
@ -451,4 +451,219 @@ InventoryItem* RatSAO::createPickedUpItem()
|
|||
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;}
|
||||
|
||||
/*
|
||||
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
|
||||
u16 m_known_by_count;
|
||||
/*
|
||||
|
@ -201,5 +207,33 @@ private:
|
|||
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
|
||||
|
||||
|
|
16
src/test.cpp
|
@ -951,18 +951,18 @@ struct TestConnection
|
|||
assert(got_exception);
|
||||
}
|
||||
{
|
||||
//u8 data1[1100];
|
||||
SharedBuffer<u8> data1(1100);
|
||||
for(u16 i=0; i<1100; i++){
|
||||
const int datasize = 30000;
|
||||
SharedBuffer<u8> data1(datasize);
|
||||
for(u16 i=0; i<datasize; i++){
|
||||
data1[i] = i/4;
|
||||
}
|
||||
|
||||
dstream<<"Sending data (size="<<1100<<"):";
|
||||
for(int i=0; i<1100 && i<20; i++){
|
||||
dstream<<"Sending data (size="<<datasize<<"):";
|
||||
for(int i=0; i<datasize && i<20; i++){
|
||||
if(i%2==0) DEBUGPRINT(" ");
|
||||
DEBUGPRINT("%.2X", ((int)((const char*)*data1)[i])&0xff);
|
||||
}
|
||||
if(1100>20)
|
||||
if(datasize>20)
|
||||
dstream<<"...";
|
||||
dstream<<std::endl;
|
||||
|
||||
|
@ -970,10 +970,10 @@ struct TestConnection
|
|||
|
||||
sleep_ms(50);
|
||||
|
||||
u8 recvdata[2000];
|
||||
u8 recvdata[datasize + 1000];
|
||||
dstream<<"** running client.Receive()"<<std::endl;
|
||||
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
|
||||
<<", size="<<size
|
||||
<<std::endl;
|
||||
|
|
|
@ -215,8 +215,8 @@ inline void writeU16(std::ostream &os, u16 p)
|
|||
}
|
||||
inline u16 readU16(std::istream &is)
|
||||
{
|
||||
char buf[12];
|
||||
is.read(buf, 12);
|
||||
char buf[2];
|
||||
is.read(buf, 2);
|
||||
return readU16((u8*)buf);
|
||||
}
|
||||
|
||||
|
@ -228,8 +228,8 @@ inline void writeF1000(std::ostream &os, f32 p)
|
|||
}
|
||||
inline f32 readF1000(std::istream &is)
|
||||
{
|
||||
char buf[12];
|
||||
is.read(buf, 12);
|
||||
char buf[2];
|
||||
is.read(buf, 2);
|
||||
return readF1000((u8*)buf);
|
||||
}
|
||||
|
||||
|
|