+/*
+Minetest-c55
+Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
#include "client.h"
#include "utility.h"
#include <iostream>
#include "jmutexautolock.h"
#include "main.h"
#include <sstream>
-
-#ifdef _WIN32
- #include <windows.h>
- #define sleep_ms(x) Sleep(x)
-#else
- #include <unistd.h>
- #define sleep_ms(x) usleep(x*1000)
-#endif
+#include "porting.h"
void * ClientUpdateThread::Thread()
{
ThreadStarted();
DSTACK(__FUNCTION_NAME);
-
-#if CATCH_UNHANDLED_EXCEPTIONS
- try
+
+ BEGIN_DEBUG_EXCEPTION_HANDLER
+
+ while(getRun())
{
-#endif
- while(getRun())
- {
- m_client->asyncStep();
+ m_client->asyncStep();
- bool was = m_client->AsyncProcessData();
+ //m_client->updateSomeExpiredMeshes();
- if(was == false)
- sleep_ms(10);
- }
-#if CATCH_UNHANDLED_EXCEPTIONS
- }
- /*
- This is what has to be done in threads to get suitable debug info
- */
- catch(std::exception &e)
- {
- dstream<<std::endl<<DTIME<<"An unhandled exception occurred: "
- <<e.what()<<std::endl;
- assert(0);
+ bool was = m_client->AsyncProcessData();
+
+ if(was == false)
+ sleep_ms(10);
}
-#endif
+
+ END_DEBUG_EXCEPTION_HANDLER
return NULL;
}
-Client::Client(IrrlichtDevice *device, video::SMaterial *materials,
- float delete_unused_sectors_timeout,
- const char *playername):
+Client::Client(
+ IrrlichtDevice *device,
+ const char *playername,
+ MapDrawControl &control):
m_thread(this),
- m_env(new ClientMap(this, materials,
+ m_env(new ClientMap(this, control,
device->getSceneManager()->getRootSceneNode(),
device->getSceneManager(), 666),
dout_client),
camera_direction(0,0,1),
m_server_ser_ver(SER_FMT_VER_INVALID),
m_step_dtime(0.0),
- m_delete_unused_sectors_timeout(delete_unused_sectors_timeout),
- m_inventory_updated(false)
+ m_inventory_updated(false),
+ m_time_of_day(0)
{
+ m_packetcounter_timer = 0.0;
+ m_delete_unused_sectors_timer = 0.0;
+ m_connection_reinit_timer = 0.0;
+ m_avg_rtt_timer = 0.0;
+ m_playerpos_send_timer = 0.0;
+
//m_fetchblock_mutex.Init();
m_incoming_queue_mutex.Init();
m_env_mutex.Init();
Client::~Client()
{
+ {
+ JMutexAutoLock conlock(m_con_mutex);
+ m_con.Disconnect();
+ }
+
m_thread.setRun(false);
while(m_thread.IsRunning())
sleep_ms(100);
if(dtime > 2.0)
dtime = 2.0;
+
//dstream<<"Client steps "<<dtime<<std::endl;
{
Packet counter
*/
{
- static float counter = -0.001;
+ float &counter = m_packetcounter_timer;
counter -= dtime;
if(counter <= 0.0)
{
clear caches
*/
- static float counter = -0.001;
+ float &counter = m_delete_unused_sectors_timer;
counter -= dtime;
if(counter <= 0.0)
{
// 3 minute interval
- counter = 180.0;
+ //counter = 180.0;
+ counter = 60.0;
JMutexAutoLock lock(m_env_mutex);
core::list<v3s16> deleted_blocks;
+
+ float delete_unused_sectors_timeout =
+ g_settings.getFloat("client_delete_unused_sectors_timeout");
// Delete sector blocks
/*u32 num = m_env.getMap().deleteUnusedSectors
- (m_delete_unused_sectors_timeout,
+ (delete_unused_sectors_timeout,
true, &deleted_blocks);*/
// Delete whole sectors
u32 num = m_env.getMap().deleteUnusedSectors
- (m_delete_unused_sectors_timeout,
+ (delete_unused_sectors_timeout,
false, &deleted_blocks);
if(num > 0)
if(connected == false)
{
- static float counter = -0.001;
+ float &counter = m_connection_reinit_timer;
counter -= dtime;
if(counter <= 0.0)
{
try
{
block = m_env.getMap().getBlockNoCreate(p);
- block->stepObjects(dtime, false);
+ block->stepObjects(dtime, false, m_env.getDayNightRatio());
}
catch(InvalidPositionException &e)
{
}
{
- // Fetch some nearby blocks
- //fetchBlocks();
- }
-
- {
- static float counter = 0.0;
+ float &counter = m_avg_rtt_timer;
counter += dtime;
if(counter >= 10)
{
}
}
{
- // Update at reasonable intervals (0.2s)
- static float counter = 0.0;
+ float &counter = m_playerpos_send_timer;
counter += dtime;
if(counter >= 0.2)
{
}
}
-#if 0
- /*
- Clear old entries from fetchblock history
- */
- {
- JMutexAutoLock lock(m_fetchblock_mutex);
-
- core::list<v3s16> remove_queue;
- core::map<v3s16, float>::Iterator i;
- i = m_fetchblock_history.getIterator();
- for(; i.atEnd() == false; i++)
- {
- float value = i.getNode()->getValue();
- value += dtime;
- i.getNode()->setValue(value);
- if(value >= 60.0)
- remove_queue.push_back(i.getNode()->getKey());
- }
- core::list<v3s16>::Iterator j;
- j = remove_queue.begin();
- for(; j != remove_queue.end(); j++)
- {
- m_fetchblock_history.remove(*j);
- }
- }
-#endif
-
/*{
JMutexAutoLock lock(m_step_dtime_mutex);
m_step_dtime += dtime;
}*/
-
- /*
- BEGIN TEST CODE
- */
-
- /*
- END OF TEST CODE
- */
}
float Client::asyncStep()
"InvalidIncomingDataException: what()="
<<e.what()<<std::endl;
}
- //TODO: Testing
- //break;
}
}
// making some copypasta
{}
- if(command == TOCLIENT_PLAYERPOS)
+ if(command == TOCLIENT_REMOVENODE)
+ {
+ if(datasize < 8)
+ return;
+ v3s16 p;
+ p.X = readS16(&data[2]);
+ p.Y = readS16(&data[4]);
+ p.Z = readS16(&data[6]);
+
+ //TimeTaker t1("TOCLIENT_REMOVENODE", g_device);
+
+ // This will clear the cracking animation after digging
+ ((ClientMap&)m_env.getMap()).clearTempMod(p);
+
+ removeNode(p);
+ }
+ else if(command == TOCLIENT_ADDNODE)
+ {
+ if(datasize < 8 + MapNode::serializedLength(ser_version))
+ return;
+
+ v3s16 p;
+ p.X = readS16(&data[2]);
+ p.Y = readS16(&data[4]);
+ p.Z = readS16(&data[6]);
+
+ //TimeTaker t1("TOCLIENT_ADDNODE", g_device);
+
+ MapNode n;
+ n.deSerialize(&data[8], ser_version);
+
+ addNode(p, n);
+ }
+ else if(command == TOCLIENT_PLAYERPOS)
{
dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
<<std::endl;
our_peer_id = m_con.GetPeerID();
}
// Cancel if we don't have a peer id
- if(our_peer_id == PEER_ID_NEW){
+ if(our_peer_id == PEER_ID_INEXISTENT){
dout_client<<DTIME<<"TOCLIENT_PLAYERPOS cancelled: "
"we have no peer id"
<<std::endl;
our_peer_id = m_con.GetPeerID();
}
// Cancel if we don't have a peer id
- if(our_peer_id == PEER_ID_NEW){
+ if(our_peer_id == PEER_ID_INEXISTENT){
dout_client<<DTIME<<"TOCLIENT_PLAYERINFO cancelled: "
"we have no peer id"
<<std::endl;
if(abs_to_delete.find(p) != NULL)
abs_to_delete.remove(p);
- // Update objects of block
+ /*
+ Update objects of block
+
+ NOTE: Be sure this is done in the main thread.
+ */
block->updateObjects(is, m_server_ser_ver,
- m_device->getSceneManager());
+ m_device->getSceneManager(), m_env.getDayNightRatio());
}
/*dstream<<"Final delete queue size: "<<abs_to_delete.size()
} //envlock
}
+ else if(command == TOCLIENT_TIME_OF_DAY)
+ {
+ if(datasize < 4)
+ return;
+
+ u16 time = readU16(&data[2]);
+ time = time % 24000;
+ m_time_of_day.set(time);
+ //dstream<<"Client: time="<<time<<std::endl;
+
+ /*
+ Day/night
+
+ time_of_day:
+ 0 = midnight
+ 12000 = midday
+ */
+ {
+ const s32 daylength = 16;
+ const s32 nightlength = 6;
+ const s32 daytimelength = 8;
+ s32 d = daylength;
+ s32 t = (((m_time_of_day.get())%24000)/(24000/d));
+ u32 dr;
+ if(t < nightlength/2 || t >= d - nightlength/2)
+ dr = 400;
+ else if(t >= d/2 - daytimelength/2 && t < d/2 + daytimelength/2)
+ dr = 1000;
+ else
+ dr = 750;
+
+ dstream<<"time_of_day="<<m_time_of_day.get()
+ <<", t="<<t
+ <<", dr="<<dr
+ <<std::endl;
+
+ if(dr != m_env.getDayNightRatio())
+ {
+ //dstream<<"dr="<<dr<<std::endl;
+ dout_client<<DTIME<<"Client: changing day-night ratio"<<std::endl;
+ m_env.setDayNightRatio(dr);
+ m_env.expireMeshes(true);
+ }
+ }
+
+ }
+ else if(command == TOCLIENT_CHAT_MESSAGE)
+ {
+ /*
+ u16 command
+ u16 length
+ wstring message
+ */
+ u8 buf[6];
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ // Read stuff
+ is.read((char*)buf, 2);
+ u16 len = readU16(buf);
+
+ std::wstring message;
+ for(u16 i=0; i<len; i++)
+ {
+ is.read((char*)buf, 2);
+ message += (wchar_t)readU16(buf);
+ }
+
+ /*dstream<<"Client received chat message: "
+ <<wide_to_narrow(message)<<std::endl;*/
+
+ m_chat_queue.push_back(message);
+ }
// Default to queueing it (for slow commands)
else
{
/*
Returns true if there was something in queue
*/
-bool Client::AsyncProcessPacket(LazyMeshUpdater &mesh_updater)
+bool Client::AsyncProcessPacket()
{
DSTACK(__FUNCTION_NAME);
ToClientCommand command = (ToClientCommand)readU16(&data[0]);
- if(command == TOCLIENT_REMOVENODE)
- {
- if(datasize < 8)
- return true;
- v3s16 p;
- p.X = readS16(&data[2]);
- p.Y = readS16(&data[4]);
- p.Z = readS16(&data[6]);
-
- //TimeTaker t1("TOCLIENT_REMOVENODE", g_device);
-
- core::map<v3s16, MapBlock*> modified_blocks;
-
- try
- {
- JMutexAutoLock envlock(m_env_mutex);
- //TimeTaker t("removeNodeAndUpdate", m_device);
- m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
- }
- catch(InvalidPositionException &e)
- {
- }
-
- for(core::map<v3s16, MapBlock * >::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
- {
- v3s16 p = i.getNode()->getKey();
- //m_env.getMap().updateMeshes(p);
- mesh_updater.add(p);
- }
- }
- else if(command == TOCLIENT_ADDNODE)
- {
- if(datasize < 8 + MapNode::serializedLength(ser_version))
- return true;
-
- v3s16 p;
- p.X = readS16(&data[2]);
- p.Y = readS16(&data[4]);
- p.Z = readS16(&data[6]);
-
- //TimeTaker t1("TOCLIENT_ADDNODE", g_device);
-
- MapNode n;
- n.deSerialize(&data[8], ser_version);
-
- core::map<v3s16, MapBlock*> modified_blocks;
-
- try
- {
- JMutexAutoLock envlock(m_env_mutex);
- m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
- }
- catch(InvalidPositionException &e)
- {}
-
- for(core::map<v3s16, MapBlock * >::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
- {
- v3s16 p = i.getNode()->getKey();
- //m_env.getMap().updateMeshes(p);
- mesh_updater.add(p);
- }
- }
- else if(command == TOCLIENT_BLOCKDATA)
+ if(command == TOCLIENT_BLOCKDATA)
{
// Ignore too small packet
if(datasize < 8)
<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
/*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
- <<p.X<<","<<p.Y<<","<<p.Z<<"): ";*/
+ <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
std::string datastring((char*)&data[8], datasize-8);
std::istringstream istr(datastring, std::ios_base::binary);
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);*/
+
+ /*
+ Add some coulds
+ Well, this is a dumb way to do it, they should just
+ be drawn as separate objects.
+ */
+ /*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);
+ }
+ }*/
}
} //envlock
-
- // Old version has zero lighting, update it.
- if(ser_version == 0 || ser_version == 1)
- {
- derr_client<<"Client: Block in old format: "
- "Calculating lighting"<<std::endl;
- core::map<v3s16, MapBlock*> blocks_changed;
- blocks_changed.insert(block->getPos(), block);
- core::map<v3s16, MapBlock*> modified_blocks;
- m_env.getMap().updateLighting(blocks_changed, modified_blocks);
- }
-
- /*
- Update Mesh of this block and blocks at x-, y- and z-
- */
-
- //m_env.getMap().updateMeshes(block->getPos());
- mesh_updater.add(block->getPos());
-
/*
Acknowledge block.
*/
// Send as reliable
m_con.Send(PEER_ID_SERVER, 1, reply, true);
-#if 0
/*
- Remove from history
+ 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.
*/
- {
- JMutexAutoLock lock(m_fetchblock_mutex);
-
- if(m_fetchblock_history.find(p) != NULL)
- {
- m_fetchblock_history.remove(p);
- }
- else
- {
- /*
- 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);
- }
- }
-#endif
+
+ m_env.getMap().updateMeshes(block->getPos(), getDayNightRatio());
}
else
{
} //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;
+ /*dout_client<<DTIME<<"Client::AsyncProcessData(): Cancelling: The server"
+ " connection doesn't exist (a timeout or not yet connected?)"<<std::endl;*/
return false;
}
}
{
for(;;)
{
- // We want to update the meshes as soon as a single packet has
- // been processed
- LazyMeshUpdater mesh_updater(&m_env);
- bool r = AsyncProcessPacket(mesh_updater);
+ bool r = AsyncProcessPacket();
if(r == false)
break;
}
return false;
-
- /*
- LazyMeshUpdater mesh_updater(&m_env);
- for(;;)
- {
- bool r = AsyncProcessPacket(mesh_updater);
- if(r == false)
- break;
- }
- return false;*/
}
void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
}
-#if 0
-void Client::fetchBlock(v3s16 p, u8 flags)
-{
- if(connectedAndInitialized() == false)
- throw ClientNotReadyException
- ("ClientNotReadyException: connectedAndInitialized() == false");
-
- /*dstream<<"Client::fetchBlock(): Sending GETBLOCK for ("
- <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-
- JMutexAutoLock conlock(m_con_mutex);
-
- SharedBuffer<u8> data(9);
- writeU16(&data[0], TOSERVER_GETBLOCK);
- writeS16(&data[2], p.X);
- writeS16(&data[4], p.Y);
- writeS16(&data[6], p.Z);
- writeU8(&data[8], flags);
- m_con.Send(PEER_ID_SERVER, 1, data, true);
-}
-
-/*
- Calls fetchBlock() on some nearby missing blocks.
-
- Returns when any of various network load indicators go over limit.
-
- Does nearly the same thing as the old updateChangedVisibleArea()
-*/
-void Client::fetchBlocks()
-{
- if(connectedAndInitialized() == false)
- throw ClientNotReadyException
- ("ClientNotReadyException: connectedAndInitialized() == false");
-}
-#endif
-
-bool Client::isFetchingBlocks()
-{
- JMutexAutoLock conlock(m_con_mutex);
- con::Peer *peer = m_con.GetPeerNoEx(PEER_ID_SERVER);
- // Not really fetching but can't fetch more.
- if(peer == NULL) return true;
-
- con::Channel *channel = &(peer->channels[1]);
- /*
- NOTE: Channel 0 should always be used for fetching blocks,
- and for nothing else.
- */
- if(channel->incoming_reliables.size() > 0)
- return true;
- if(channel->outgoing_reliables.size() > 0)
- return true;
- return false;
-}
-
IncomingPacket Client::getPacket()
{
JMutexAutoLock lock(m_incoming_queue_mutex);
return packet;
}
-#if 0
-void Client::removeNode(v3s16 nodepos)
-{
- if(connectedAndInitialized() == false){
- dout_client<<DTIME<<"Client::removeNode() cancelled (not connected)"
- <<std::endl;
- return;
- }
-
- // Test that the position exists
- try{
- JMutexAutoLock envlock(m_env_mutex);
- m_env.getMap().getNode(nodepos);
- }
- catch(InvalidPositionException &e)
- {
- dout_client<<DTIME<<"Client::removeNode() cancelled (doesn't exist)"
- <<std::endl;
- return;
- }
-
- SharedBuffer<u8> data(8);
- writeU16(&data[0], TOSERVER_REMOVENODE);
- writeS16(&data[2], nodepos.X);
- writeS16(&data[4], nodepos.Y);
- writeS16(&data[6], nodepos.Z);
- Send(0, data, true);
-}
-
-void Client::addNodeFromInventory(v3s16 nodepos, u16 i)
-{
- if(connectedAndInitialized() == false){
- dout_client<<DTIME<<"Client::addNodeFromInventory() "
- "cancelled (not connected)"
- <<std::endl;
- return;
- }
-
- // Test that the position exists
- try{
- JMutexAutoLock envlock(m_env_mutex);
- m_env.getMap().getNode(nodepos);
- }
- catch(InvalidPositionException &e)
- {
- dout_client<<DTIME<<"Client::addNode() cancelled (doesn't exist)"
- <<std::endl;
- return;
- }
-
- //u8 ser_version = m_server_ser_ver;
-
- // SUGGESTION: The validity of the operation could be checked here too
-
- u8 datasize = 2 + 6 + 2;
- SharedBuffer<u8> data(datasize);
- writeU16(&data[0], TOSERVER_ADDNODE_FROM_INVENTORY);
- writeS16(&data[2], nodepos.X);
- writeS16(&data[4], nodepos.Y);
- writeS16(&data[6], nodepos.Z);
- writeU16(&data[8], i);
- Send(0, data, true);
-}
-#endif
-
-void Client::clickGround(u8 button, v3s16 nodepos_undersurface,
+void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
v3s16 nodepos_oversurface, u16 item)
{
if(connectedAndInitialized() == false){
- dout_client<<DTIME<<"Client::clickGround() "
+ dout_client<<DTIME<<"Client::groundAction() "
"cancelled (not connected)"
<<std::endl;
return;
}
/*
- length: 19
+ length: 17
[0] u16 command
- [2] u8 button (0=left, 1=right)
+ [2] u8 action
[3] v3s16 nodepos_undersurface
[9] v3s16 nodepos_abovesurface
[15] u16 item
+ actions:
+ 0: start digging
+ 1: place block
+ 2: stop digging (all parameters ignored)
+ 3: digging completed
*/
u8 datasize = 2 + 1 + 6 + 6 + 2;
SharedBuffer<u8> data(datasize);
- writeU16(&data[0], TOSERVER_CLICK_GROUND);
- writeU8(&data[2], button);
+ writeU16(&data[0], TOSERVER_GROUND_ACTION);
+ writeU8(&data[2], action);
writeV3S16(&data[3], nodepos_undersurface);
writeV3S16(&data[9], nodepos_oversurface);
writeU16(&data[15], item);
}
/*
- [0] u16 command
+ [0] u16 command=TOSERVER_CLICK_OBJECT
[2] u8 button (0=left, 1=right)
[3] v3s16 block
[9] s16 id
Send(0, data, true);
}
-void Client::release(u8 button)
-{
- //TODO
-}
-
void Client::sendSignText(v3s16 blockpos, s16 id, std::string text)
{
/*
// Send as reliable
Send(0, data, true);
}
+
+void Client::sendInventoryAction(InventoryAction *a)
+{
+ std::ostringstream os(std::ios_base::binary);
+ u8 buf[12];
+
+ // Write command
+ writeU16(buf, TOSERVER_INVENTORY_ACTION);
+ os.write((char*)buf, 2);
+
+ a->serialize(os);
+
+ // 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::sendChatMessage(const std::wstring &message)
+{
+ std::ostringstream os(std::ios_base::binary);
+ u8 buf[12];
+
+ // Write command
+ writeU16(buf, TOSERVER_CHAT_MESSAGE);
+ os.write((char*)buf, 2);
+
+ // Write length
+ writeU16(buf, message.size());
+ os.write((char*)buf, 2);
+
+ // Write string
+ for(u32 i=0; i<message.size(); i++)
+ {
+ u16 w = message[i];
+ writeU16(buf, w);
+ os.write((char*)buf, 2);
+ }
+
+ // 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()
{
}
// Set peer id if not set already
- if(myplayer->peer_id == PEER_ID_NEW)
+ if(myplayer->peer_id == PEER_ID_INEXISTENT)
myplayer->peer_id = our_peer_id;
// Check that an existing peer_id is the same as the connection's
assert(myplayer->peer_id == our_peer_id);
Send(0, data, false);
}
+void Client::removeNode(v3s16 p)
+{
+ JMutexAutoLock envlock(m_env_mutex);
+
+ core::map<v3s16, MapBlock*> modified_blocks;
+
+ try
+ {
+ //TimeTaker t("removeNodeAndUpdate", m_device);
+ m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
+ }
+ catch(InvalidPositionException &e)
+ {
+ }
+
+ for(core::map<v3s16, MapBlock * >::Iterator
+ i = modified_blocks.getIterator();
+ i.atEnd() == false; i++)
+ {
+ v3s16 p = i.getNode()->getKey();
+ m_env.getMap().updateMeshes(p, m_env.getDayNightRatio());
+ }
+}
+
+void Client::addNode(v3s16 p, MapNode n)
+{
+ JMutexAutoLock envlock(m_env_mutex);
+
+ core::map<v3s16, MapBlock*> modified_blocks;
+ try
+ {
+ m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
+ }
+ catch(InvalidPositionException &e)
+ {}
+
+ for(core::map<v3s16, MapBlock * >::Iterator
+ i = modified_blocks.getIterator();
+ i.atEnd() == false; i++)
+ {
+ v3s16 p = i.getNode()->getKey();
+ m_env.getMap().updateMeshes(p, m_env.getDayNightRatio());
+ }
+}
+
void Client::updateCamera(v3f pos, v3f dir)
{
m_env.getMap().updateCamera(pos, dir);
return m_env.getMap().getNode(p);
}
+/*void Client::getNode(v3s16 p, MapNode n)
+{
+ JMutexAutoLock envlock(m_env_mutex);
+ m_env.getMap().setNode(p, n);
+}*/
+
/*f32 Client::getGroundHeight(v2s16 p)
{
JMutexAutoLock envlock(m_env_mutex);
return m_env.getMap().getGroundHeight(p);
}*/
-bool Client::isNodeUnderground(v3s16 p)
+/*bool Client::isNodeUnderground(v3s16 p)
{
JMutexAutoLock envlock(m_env_mutex);
return m_env.getMap().isNodeUnderground(p);
-}
+}*/
/*Player * Client::getLocalPlayer()
{
v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map;
block->getObjects(from_pos_f_on_block, max_d, objects);
+ //block->getPseudoObjects(from_pos_f_on_block, max_d, objects);
}
//dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
<<std::endl;
}
+/*s32 Client::getDayNightIndex()
+{
+ assert(m_daynight_i >= 0 && m_daynight_i < DAYNIGHT_CACHE_COUNT);
+ return m_daynight_i;
+}*/
+
+u32 Client::getDayNightRatio()
+{
+ JMutexAutoLock envlock(m_env_mutex);
+ return m_env.getDayNightRatio();
+}
+
+/*void Client::updateSomeExpiredMeshes()
+{
+ TimeTaker timer("updateSomeExpiredMeshes()", g_device);
+
+ Player *player;
+ {
+ JMutexAutoLock envlock(m_env_mutex);
+ player = m_env.getLocalPlayer();
+ }
+
+ u32 daynight_ratio = getDayNightRatio();
+
+ v3f playerpos = player->getPosition();
+ v3f playerspeed = player->getSpeed();
+
+ v3s16 center_nodepos = floatToInt(playerpos);
+ v3s16 center = getNodeBlockPos(center_nodepos);
+
+ u32 counter = 0;
+
+ s16 d_max = 5;
+
+ for(s16 d = 0; d <= d_max; d++)
+ {
+ core::list<v3s16> list;
+ getFacePositions(list, d);
+
+ core::list<v3s16>::Iterator li;
+ for(li=list.begin(); li!=list.end(); li++)
+ {
+ v3s16 p = *li + center;
+ MapBlock *block = NULL;
+ try
+ {
+ //JMutexAutoLock envlock(m_env_mutex);
+ block = m_env.getMap().getBlockNoCreate(p);
+ }
+ catch(InvalidPositionException &e)
+ {
+ }
+
+ if(block == NULL)
+ continue;
+
+ if(block->getMeshExpired() == false)
+ continue;
+
+ block->updateMesh(daynight_ratio);
+
+ counter++;
+ if(counter >= 5)
+ return;
+ }
+ }
+}*/