disconnect method to connection to be used instead of just timing out

stable-0.2
Perttu Ahola 2010-12-24 17:08:50 +02:00
parent 705de63dcd
commit a26c92d7dd
9 changed files with 690 additions and 245 deletions

View File

@ -117,6 +117,11 @@ Client::Client(
Client::~Client() Client::~Client()
{ {
{
JMutexAutoLock conlock(m_con_mutex);
m_con.Disconnect();
}
m_thread.setRun(false); m_thread.setRun(false);
while(m_thread.IsRunning()) while(m_thread.IsRunning())
sleep_ms(100); sleep_ms(100);
@ -601,7 +606,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
addNode(p, n); addNode(p, n);
} }
if(command == TOCLIENT_PLAYERPOS) else if(command == TOCLIENT_PLAYERPOS)
{ {
dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS" dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
<<std::endl; <<std::endl;

View File

@ -542,6 +542,23 @@ void Connection::Connect(Address address)
//m_waiting_new_peer_id = true; //m_waiting_new_peer_id = true;
} }
void Connection::Disconnect()
{
// Create and send DISCO packet
SharedBuffer<u8> data(2);
writeU8(&data[0], TYPE_CONTROL);
writeU8(&data[1], CONTROLTYPE_DISCO);
// Send to all
core::map<u16, Peer*>::Iterator j;
j = m_peers.getIterator();
for(; j.atEnd() == false; j++)
{
Peer *peer = j.getNode()->getValue();
SendAsPacket(peer->id, 0, data, false);
}
}
bool Connection::Connected() bool Connection::Connected()
{ {
if(m_peers.size() != 1) if(m_peers.size() != 1)
@ -645,7 +662,22 @@ SharedBuffer<u8> Channel::ProcessPacket(
// the timeout counter // the timeout counter
con->PrintInfo(); con->PrintInfo();
dout_con<<"PING"<<std::endl; dout_con<<"PING"<<std::endl;
throw ProcessedSilentlyException("Got a SET_PEER_ID"); throw ProcessedSilentlyException("Got a PING");
}
else if(controltype == CONTROLTYPE_DISCO)
{
// Just ignore it, the incoming data already reset
// the timeout counter
con->PrintInfo();
dout_con<<"DISCO: Removing peer "<<(peer_id)<<std::endl;
if(con->deletePeer(peer_id) == false)
{
con->PrintInfo(derr_con);
derr_con<<"DISCO: Peer not found"<<std::endl;
}
throw ProcessedSilentlyException("Got a DISCO");
} }
else{ else{
con->PrintInfo(derr_con); con->PrintInfo(derr_con);
@ -1323,6 +1355,16 @@ core::list<Peer*> Connection::GetPeers()
return list; return list;
} }
bool Connection::deletePeer(u16 peer_id)
{
if(m_peers.find(peer_id) == NULL)
return false;
m_peerhandler->deletingPeer(m_peers[peer_id], true);
delete m_peers[peer_id];
m_peers.remove(peer_id);
return true;
}
void Connection::PrintInfo(std::ostream &out) void Connection::PrintInfo(std::ostream &out)
{ {
out<<m_socket.GetHandle(); out<<m_socket.GetHandle();

View File

@ -226,12 +226,15 @@ controltype and data description:
CONTROLTYPE_SET_PEER_ID CONTROLTYPE_SET_PEER_ID
[2] u16 peer_id_new [2] u16 peer_id_new
CONTROLTYPE_PING CONTROLTYPE_PING
- This can be sent in a reliable packet to get a reply - There is no actual reply, but this can be sent in a reliable
packet to get a reply
CONTROLTYPE_DISCO
*/ */
#define TYPE_CONTROL 0 #define TYPE_CONTROL 0
#define CONTROLTYPE_ACK 0 #define CONTROLTYPE_ACK 0
#define CONTROLTYPE_SET_PEER_ID 1 #define CONTROLTYPE_SET_PEER_ID 1
#define CONTROLTYPE_PING 2 #define CONTROLTYPE_PING 2
#define CONTROLTYPE_DISCO 3
/* /*
ORIGINAL: This is a plain packet with no control and no error ORIGINAL: This is a plain packet with no control and no error
checking at all. checking at all.
@ -442,12 +445,15 @@ public:
void Connect(Address address); void Connect(Address address);
bool Connected(); bool Connected();
void Disconnect();
// Sets peer_id // Sets peer_id
SharedBuffer<u8> GetFromBuffers(u16 &peer_id); SharedBuffer<u8> GetFromBuffers(u16 &peer_id);
// The peer_id of sender is stored in peer_id // The peer_id of sender is stored in peer_id
// Return value: I guess this always throws an exception or // Return value: I guess this always throws an exception or
// actually gets data // actually gets data
// May call PeerHandler methods
u32 Receive(u16 &peer_id, u8 *data, u32 datasize); u32 Receive(u16 &peer_id, u8 *data, u32 datasize);
// These will automatically package the data as an original or split // These will automatically package the data as an original or split
@ -460,12 +466,18 @@ public:
// Sends a raw packet // Sends a raw packet
void RawSend(const BufferedPacket &packet); void RawSend(const BufferedPacket &packet);
// May call PeerHandler methods
void RunTimeouts(float dtime); void RunTimeouts(float dtime);
// Can throw a PeerNotFoundException // Can throw a PeerNotFoundException
Peer* GetPeer(u16 peer_id); Peer* GetPeer(u16 peer_id);
// returns NULL if failed // returns NULL if failed
Peer* GetPeerNoEx(u16 peer_id); Peer* GetPeerNoEx(u16 peer_id);
core::list<Peer*> GetPeers(); core::list<Peer*> GetPeers();
// Calls PeerHandler::deletingPeer
// Returns false if peer was not found
bool deletePeer(u16 peer_id);
void SetPeerID(u16 id){ m_peer_id = id; } void SetPeerID(u16 id){ m_peer_id = id; }
u16 GetPeerID(){ return m_peer_id; } u16 GetPeerID(){ return m_peer_id; }

View File

@ -228,8 +228,10 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
} }
if(event.EventType==EET_MOUSE_INPUT_EVENT) if(event.EventType==EET_MOUSE_INPUT_EVENT)
{ {
if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN
|| event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
{ {
bool right = (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN);
v2s32 p(event.MouseInput.X, event.MouseInput.Y); v2s32 p(event.MouseInput.X, event.MouseInput.Y);
//dstream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl; //dstream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
ItemSpec s = getItemAtPos(p); ItemSpec s = getItemAtPos(p);
@ -248,15 +250,21 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
dstream<<"Queueing IACTION_MOVE"<<std::endl; dstream<<"Queueing IACTION_MOVE"<<std::endl;
IMoveAction *a = IMoveAction *a =
new IMoveAction(); new IMoveAction();
a->count = 1; a->count = right ? 1 : 0;
a->from_name = m_selected_item->listname; a->from_name = m_selected_item->listname;
a->from_i = m_selected_item->i; a->from_i = m_selected_item->i;
a->to_name = s.listname; a->to_name = s.listname;
a->to_i = s.i; a->to_i = s.i;
m_actions->push_back(a); m_actions->push_back(a);
} }
delete m_selected_item; bool source_empties = false;
m_selected_item = NULL; if(list_from && list_from->getItem(m_selected_item->i)->getCount()==1)
source_empties = true;
if(right == false || source_empties)
{
delete m_selected_item;
m_selected_item = NULL;
}
} }
else else
{ {

View File

@ -32,8 +32,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
InventoryItem InventoryItem
*/ */
InventoryItem::InventoryItem() InventoryItem::InventoryItem(u16 count)
{ {
m_count = count;
} }
InventoryItem::~InventoryItem() InventoryItem::~InventoryItem()
@ -66,6 +67,14 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is)
std::getline(is, inventorystring, '|'); std::getline(is, inventorystring, '|');
return new MapBlockObjectItem(inventorystring); return new MapBlockObjectItem(inventorystring);
} }
else if(name == "CraftItem")
{
std::string subname;
std::getline(is, subname, ' ');
u16 count;
is>>count;
return new CraftItem(subname, count);
}
else if(name == "ToolItem") else if(name == "ToolItem")
{ {
std::string toolname; std::string toolname;
@ -325,83 +334,93 @@ void InventoryList::deleteItem(u32 i)
delete item; delete item;
} }
bool InventoryList::addItem(InventoryItem *newitem) InventoryItem * InventoryList::addItem(InventoryItem *newitem)
{ {
// If it is a MaterialItem, try to find an already existing one /*
// and just increment the counter First try to find if it could be added to some existing items
if(std::string("MaterialItem") == newitem->getName()) */
{
u8 material = ((MaterialItem*)newitem)->getMaterial();
u8 count = ((MaterialItem*)newitem)->getCount();
for(u32 i=0; i<m_items.size(); i++)
{
InventoryItem *item2 = m_items[i];
if(item2 == NULL)
continue;
if(std::string("MaterialItem") != item2->getName())
continue;
// Found one. Check if it is of the right material and has
// free space
MaterialItem *mitem2 = (MaterialItem*)item2;
if(mitem2->getMaterial() != material)
continue;
//TODO: Add all that can be added and add remaining part
// to another place
if(mitem2->freeSpace() < count)
continue;
// Add to the counter
mitem2->add(count);
// Dump the parameter
delete newitem;
return true;
}
}
// Else find an empty position
for(u32 i=0; i<m_items.size(); i++) for(u32 i=0; i<m_items.size(); i++)
{ {
InventoryItem *item = m_items[i]; // Ignore empty slots
if(item != NULL) if(m_items[i] == NULL)
continue; continue;
m_items[i] = newitem; // Try adding
return true; newitem = addItem(i, newitem);
if(newitem == NULL)
return NULL; // All was eaten
} }
// Failed
return false; /*
Then try to add it to empty slots
*/
for(u32 i=0; i<m_items.size(); i++)
{
// Ignore unempty slots
if(m_items[i] != NULL)
continue;
// Try adding
newitem = addItem(i, newitem);
if(newitem == NULL)
return NULL; // All was eaten
}
// Return leftover
return newitem;
} }
bool InventoryList::addItem(u32 i, InventoryItem *newitem) InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
{ {
// If it is an empty position, it's an easy job. // If it is an empty position, it's an easy job.
InventoryItem *item = m_items[i]; InventoryItem *to_item = m_items[i];
if(item == NULL) if(to_item == NULL)
{ {
m_items[i] = newitem; m_items[i] = newitem;
return true; return NULL;
} }
// If it is a material item, try to // If not addable, return the item
if(std::string("MaterialItem") == newitem->getName()) if(newitem->addableTo(to_item) == false)
return newitem;
// If the item fits fully in the slot, add counter and delete it
if(newitem->getCount() <= to_item->freeSpace())
{ {
u8 material = ((MaterialItem*)newitem)->getMaterial(); to_item->add(newitem->getCount());
u8 count = ((MaterialItem*)newitem)->getCount(); delete newitem;
InventoryItem *item2 = m_items[i]; return NULL;
}
// Else the item does not fit fully. Add all that fits and return
// the rest.
else
{
u16 freespace = to_item->freeSpace();
to_item->add(freespace);
newitem->remove(freespace);
return newitem;
}
}
if(item2 != NULL InventoryItem * InventoryList::takeItem(u32 i, u32 count)
&& std::string("MaterialItem") == item2->getName()) {
{ if(count == 0)
// Check if it is of the right material and has free space return NULL;
MaterialItem *mitem2 = (MaterialItem*)item2;
if(mitem2->getMaterial() == material InventoryItem *item = m_items[i];
&& mitem2->freeSpace() >= count) // If it is an empty position, return NULL
{ if(item == NULL)
// Add to the counter return NULL;
mitem2->add(count);
// Dump the parameter if(count >= item->getCount())
delete newitem; {
// Done // Get the item by swapping NULL to its place
return true; return changeItem(i, NULL);
} }
} else
{
InventoryItem *item2 = item->clone();
item->remove(count);
item2->setCount(count);
return item2;
} }
return false; return false;
@ -411,26 +430,9 @@ void InventoryList::decrementMaterials(u16 count)
{ {
for(u32 i=0; i<m_items.size(); i++) for(u32 i=0; i<m_items.size(); i++)
{ {
InventoryItem *item = m_items[i]; InventoryItem *item = takeItem(i, count);
if(item == NULL) if(item)
continue; delete item;
if(std::string("MaterialItem") == item->getName())
{
MaterialItem *mitem = (MaterialItem*)item;
if(mitem->getCount() < count)
{
dstream<<__FUNCTION_NAME<<": decrementMaterials():"
<<" too small material count"<<std::endl;
}
else if(mitem->getCount() == count)
{
deleteItem(i);
}
else
{
mitem->remove(1);
}
}
} }
} }
@ -607,6 +609,10 @@ void IMoveAction::apply(Inventory *inventory)
dstream<<" list_to->getItem(to_i)="<<list_to->getItem(to_i) dstream<<" list_to->getItem(to_i)="<<list_to->getItem(to_i)
<<std::endl;*/ <<std::endl;*/
/*
If a list doesn't exist or the source item doesn't exist
or the source and the destination slots are the same
*/
if(!list_from || !list_to || list_from->getItem(from_i) == NULL if(!list_from || !list_to || list_from->getItem(from_i) == NULL
|| (list_from == list_to && from_i == to_i)) || (list_from == list_to && from_i == to_i))
{ {
@ -615,18 +621,39 @@ void IMoveAction::apply(Inventory *inventory)
} }
// Take item from source list // Take item from source list
InventoryItem *item1 = list_from->changeItem(from_i, NULL); InventoryItem *item1 = NULL;
if(count == 0)
item1 = list_from->changeItem(from_i, NULL);
else
item1 = list_from->takeItem(from_i, count);
// Try to add the item to destination list // Try to add the item to destination list
if(list_to->addItem(to_i, item1)) InventoryItem *olditem = item1;
item1 = list_to->addItem(to_i, item1);
// If nothing is returned, the item was fully added
if(item1 == NULL)
return;
// If olditem is returned, nothing was added.
bool nothing_added = (item1 == olditem);
// If something else is returned, part of the item was left unadded.
// Add the other part back to the source item
list_from->addItem(from_i, item1);
// If olditem is returned, nothing was added.
// Swap the items
if(nothing_added)
{ {
// Done. // Take item from source list
item1 = list_from->changeItem(from_i, NULL);
// Adding was not possible, swap the items.
InventoryItem *item2 = list_to->changeItem(to_i, item1);
// Put item from destination list to the source list
list_from->changeItem(from_i, item2);
return; return;
} }
// Adding was not possible, switch it.
// Switch it to the destination list
InventoryItem *item2 = list_to->changeItem(to_i, item1);
// Put item from destination list to the source list
list_from->changeItem(from_i, item2);
} }
//END //END

View File

@ -33,10 +33,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// For g_materials // For g_materials
#include "main.h" #include "main.h"
#define QUANTITY_ITEM_MAX_COUNT 99
class InventoryItem class InventoryItem
{ {
public: public:
InventoryItem(); InventoryItem(u16 count);
virtual ~InventoryItem(); virtual ~InventoryItem();
static InventoryItem* deSerialize(std::istream &is); static InventoryItem* deSerialize(std::istream &is);
@ -53,18 +55,49 @@ public:
// Shall return a text to show in the GUI // Shall return a text to show in the GUI
virtual std::string getText() { return ""; } virtual std::string getText() { return ""; }
private: // Shall return true if the item can be add()ed to the other
}; virtual bool addableTo(InventoryItem *other)
{
return false;
}
/*
Quantity methods
*/
u16 getCount()
{
return m_count;
}
void setCount(u16 count)
{
m_count = count;
}
virtual u16 freeSpace()
{
return 0;
}
void add(u16 count)
{
assert(m_count + count <= QUANTITY_ITEM_MAX_COUNT);
m_count += count;
}
void remove(u16 count)
{
assert(m_count >= count);
m_count -= count;
}
#define MATERIAL_ITEM_MAX_COUNT 99 protected:
u16 m_count;
};
class MaterialItem : public InventoryItem class MaterialItem : public InventoryItem
{ {
public: public:
MaterialItem(u8 content, u16 count) MaterialItem(u8 content, u16 count):
InventoryItem(count)
{ {
m_content = content; m_content = content;
m_count = count;
} }
/* /*
Implementation interface Implementation interface
@ -107,6 +140,22 @@ public:
os<<m_count; os<<m_count;
return os.str(); return os.str();
} }
virtual bool addableTo(InventoryItem *other)
{
if(std::string(other->getName()) != "MaterialItem")
return false;
MaterialItem *m = (MaterialItem*)other;
if(m->getMaterial() != m_content)
return false;
return true;
}
u16 freeSpace()
{
if(m_count > QUANTITY_ITEM_MAX_COUNT)
return 0;
return QUANTITY_ITEM_MAX_COUNT - m_count;
}
/* /*
Special methods Special methods
*/ */
@ -114,39 +163,15 @@ public:
{ {
return m_content; return m_content;
} }
u16 getCount()
{
return m_count;
}
u16 freeSpace()
{
if(m_count > MATERIAL_ITEM_MAX_COUNT)
return 0;
return MATERIAL_ITEM_MAX_COUNT - m_count;
}
void add(u16 count)
{
assert(m_count + count <= MATERIAL_ITEM_MAX_COUNT);
m_count += count;
}
void remove(u16 count)
{
assert(m_count >= count);
m_count -= count;
}
private: private:
u8 m_content; u8 m_content;
u16 m_count;
}; };
class MapBlockObjectItem : public InventoryItem class MapBlockObjectItem : public InventoryItem
{ {
public: public:
/*MapBlockObjectItem(MapBlockObject *obj) MapBlockObjectItem(std::string inventorystring):
{ InventoryItem(1)
m_inventorystring = obj->getInventoryString();
}*/
MapBlockObjectItem(std::string inventorystring)
{ {
m_inventorystring = inventorystring; m_inventorystring = inventorystring;
} }
@ -196,10 +221,90 @@ private:
std::string m_inventorystring; std::string m_inventorystring;
}; };
/*
An item that is used as a mid-product when crafting.
Subnames:
- Stick
*/
class CraftItem : public InventoryItem
{
public:
CraftItem(std::string subname, u16 count):
InventoryItem(count)
{
m_subname = subname;
}
/*
Implementation interface
*/
virtual const char* getName() const
{
return "CraftItem";
}
virtual void serialize(std::ostream &os)
{
os<<getName();
os<<" ";
os<<m_subname;
os<<" ";
os<<m_count;
}
virtual InventoryItem* clone()
{
return new CraftItem(m_subname, m_count);
}
#ifndef SERVER
video::ITexture * getImage()
{
std::string basename;
if(m_subname == "Stick")
basename = "../data/stick.png";
// Default to cloud texture
else
basename = tile_texture_path_get(TILE_CLOUD);
// Get such a texture
return g_irrlicht->getTexture(basename);
//return g_irrlicht->getTexture(TextureSpec(finalname, basename, mod));
}
#endif
std::string getText()
{
std::ostringstream os;
os<<m_count;
return os.str();
}
virtual bool addableTo(InventoryItem *other)
{
if(std::string(other->getName()) != "CraftItem")
return false;
CraftItem *m = (CraftItem*)other;
if(m->m_subname != m_subname)
return false;
return true;
}
u16 freeSpace()
{
if(m_count > QUANTITY_ITEM_MAX_COUNT)
return 0;
return QUANTITY_ITEM_MAX_COUNT - m_count;
}
/*
Special methods
*/
std::string getSubName()
{
return m_subname;
}
private:
std::string m_subname;
};
class ToolItem : public InventoryItem class ToolItem : public InventoryItem
{ {
public: public:
ToolItem(std::string toolname, u16 wear) ToolItem(std::string toolname, u16 wear):
InventoryItem(1)
{ {
m_toolname = toolname; m_toolname = toolname;
m_wear = wear; m_wear = wear;
@ -313,11 +418,20 @@ public:
InventoryItem * changeItem(u32 i, InventoryItem *newitem); InventoryItem * changeItem(u32 i, InventoryItem *newitem);
// Delete item // Delete item
void deleteItem(u32 i); void deleteItem(u32 i);
// Adds an item to a suitable place. Returns false if failed. // Adds an item to a suitable place. Returns leftover item.
bool addItem(InventoryItem *newitem); // If all went into the list, returns NULL.
// If possible, adds item to given slot. Returns true on success. InventoryItem * addItem(InventoryItem *newitem);
// Fails when slot is populated by a different kind of item.
bool addItem(u32 i, InventoryItem *newitem); // If possible, adds item to given slot.
// If cannot be added at all, returns the item back.
// If can be added partly, decremented item is returned back.
// If can be added fully, NULL is returned.
InventoryItem * addItem(u32 i, InventoryItem *newitem);
// Takes some items from a slot.
// If there are not enough, takes as many as it can.
// Returns NULL if couldn't take any.
InventoryItem * takeItem(u32 i, u32 count);
// Decrements amount of every material item // Decrements amount of every material item
void decrementMaterials(u16 count); void decrementMaterials(u16 count);
@ -347,12 +461,13 @@ public:
InventoryList * addList(const std::string &name, u32 size); InventoryList * addList(const std::string &name, u32 size);
InventoryList * getList(const std::string &name); InventoryList * getList(const std::string &name);
bool deleteList(const std::string &name); bool deleteList(const std::string &name);
// A shorthand for adding items // A shorthand for adding items.
bool addItem(const std::string &listname, InventoryItem *newitem) // Returns NULL if the item was fully added, leftover otherwise.
InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
{ {
InventoryList *list = getList(listname); InventoryList *list = getList(listname);
if(list == NULL) if(list == NULL)
return false; return newitem;
return list->addItem(newitem); return list->addItem(newitem);
} }
@ -376,6 +491,7 @@ struct InventoryAction
struct IMoveAction : public InventoryAction struct IMoveAction : public InventoryAction
{ {
// count=0 means "everything"
u16 count; u16 count;
std::string from_name; std::string from_name;
s16 from_i; s16 from_i;

View File

@ -1513,6 +1513,10 @@ int main(int argc, char *argv[])
// Test the text input system // Test the text input system
/*(new GUITextInputMenu(guienv, guiroot, -1, &g_active_menu_count, /*(new GUITextInputMenu(guienv, guiroot, -1, &g_active_menu_count,
NULL))->drop();*/ NULL))->drop();*/
// Launch pause menu
(new GUIPauseMenu(guienv, guiroot, -1, g_device,
&g_active_menu_count))->drop();
// First line of debug text // First line of debug text
gui::IGUIStaticText *guitext = guienv->addStaticText( gui::IGUIStaticText *guitext = guienv->addStaticText(
@ -2164,9 +2168,11 @@ int main(int argc, char *argv[])
} }
// We want a slight delay to very little // We want a slight delay to very little
// time consuming nodes // time consuming nodes
if(nodig_delay_counter < 0.15) //float mindelay = 0.15;
float mindelay = 0.20;
if(nodig_delay_counter < mindelay)
{ {
nodig_delay_counter = 0.15; nodig_delay_counter = mindelay;
} }
} }

View File

@ -849,40 +849,6 @@ void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
} }
} }
/*void RemoteClient::BlockEmerged()
{
SharedPtr<JMutexAutoLock> lock(m_num_blocks_in_emerge_queue.getLock());
assert(m_num_blocks_in_emerge_queue.m_value > 0);
m_num_blocks_in_emerge_queue.m_value--;
}*/
/*void RemoteClient::RunSendingTimeouts(float dtime, float timeout)
{
JMutexAutoLock sendinglock(m_blocks_sending_mutex);
core::list<v3s16> remove_queue;
for(core::map<v3s16, float>::Iterator
i = m_blocks_sending.getIterator();
i.atEnd()==false; i++)
{
v3s16 p = i.getNode()->getKey();
float t = i.getNode()->getValue();
t += dtime;
i.getNode()->setValue(t);
if(t > timeout)
{
remove_queue.push_back(p);
}
}
for(core::list<v3s16>::Iterator
i = remove_queue.begin();
i != remove_queue.end(); i++)
{
m_blocks_sending.remove(*i);
}
}*/
/* /*
PlayerInfo PlayerInfo
*/ */
@ -931,7 +897,8 @@ Server::Server(
m_emergethread(this), m_emergethread(this),
m_time_of_day(8000), m_time_of_day(8000),
m_time_counter(0), m_time_counter(0),
m_time_of_day_send_timer(0) m_time_of_day_send_timer(0),
m_uptime(0)
{ {
m_flowwater_timer = 0.0; m_flowwater_timer = 0.0;
m_print_info_timer = 0.0; m_print_info_timer = 0.0;
@ -1026,10 +993,20 @@ void Server::AsyncRunStep()
if(dtime < 0.001) if(dtime < 0.001)
return; return;
//dstream<<"Server steps "<<dtime<<std::endl;
//dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
{ {
JMutexAutoLock lock1(m_step_dtime_mutex); JMutexAutoLock lock1(m_step_dtime_mutex);
m_step_dtime -= dtime; m_step_dtime -= dtime;
} }
/*
Update uptime
*/
{
m_uptime.set(m_uptime.get() + dtime);
}
/* /*
Update m_time_of_day Update m_time_of_day
@ -1070,16 +1047,18 @@ void Server::AsyncRunStep()
} }
} }
//dstream<<"Server steps "<<dtime<<std::endl;
//dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
{ {
// Has to be locked for peerAdded/Removed
JMutexAutoLock lock1(m_env_mutex);
// Process connection's timeouts // Process connection's timeouts
JMutexAutoLock lock2(m_con_mutex); JMutexAutoLock lock2(m_con_mutex);
m_con.RunTimeouts(dtime); m_con.RunTimeouts(dtime);
} }
{
// This has to be called so that the client list gets synced
// with the peer list of the connection
handlePeerChanges();
}
{ {
// Step environment // Step environment
// This also runs Map's timers // This also runs Map's timers
@ -1355,9 +1334,14 @@ void Server::Receive()
u32 datasize; u32 datasize;
try{ try{
{ {
JMutexAutoLock lock(m_con_mutex); JMutexAutoLock conlock(m_con_mutex);
datasize = m_con.Receive(peer_id, *data, data_maxsize); datasize = m_con.Receive(peer_id, *data, data_maxsize);
} }
// This has to be called so that the client list gets synced
// with the peer list of the connection
handlePeerChanges();
ProcessData(*data, datasize, peer_id); ProcessData(*data, datasize, peer_id);
} }
catch(con::InvalidIncomingDataException &e) catch(con::InvalidIncomingDataException &e)
@ -1499,6 +1483,36 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
m_time_of_day.get()); m_time_of_day.get());
m_con.Send(peer->id, 0, data, true); m_con.Send(peer->id, 0, data, true);
} }
// Send information about server to player in chat
{
std::wostringstream os(std::ios_base::binary);
os<<L"# Server: ";
// Uptime
os<<L"uptime="<<m_uptime.get();
// Information about clients
os<<L", clients={";
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
// Get client and check that it is valid
RemoteClient *client = i.getNode()->getValue();
assert(client->peer_id == i.getNode()->getKey());
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
// Get name of player
std::wstring name = L"unknown";
Player *player = m_env.getPlayer(client->peer_id);
if(player != NULL)
name = narrow_to_wide(player->getName());
// Add name to information string
os<<name<<L",";
}
os<<L"}";
// Send message
SendChatMessage(peer_id, os.str());
}
// Send information about joining in chat // Send information about joining in chat
{ {
@ -1722,52 +1736,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/ */
if(action == 0) if(action == 0)
{ {
/*
NOTE: This can be used in the future to check if
somebody is cheating, by checking the timing.
*/
#if 0
u8 content;
try
{
// Get content at position
content = m_env.getMap().getNode(p_under).d;
// If it's not diggable, do nothing
if(content_diggable(content) == false)
{
return;
}
}
catch(InvalidPositionException &e)
{
derr_server<<"Server: Not starting digging: Node not found"
<<std::endl;
return;
}
/* /*
Set stuff in RemoteClient NOTE: This can be used in the future to check if
somebody is cheating, by checking the timing.
*/ */
RemoteClient *client = getClient(peer->id);
JMutexAutoLock(client->m_dig_mutex);
client->m_dig_tool_item = 0;
client->m_dig_position = p_under;
float dig_time = 0.5;
if(content == CONTENT_STONE)
{
dig_time = 1.5;
}
else if(content == CONTENT_TORCH)
{
dig_time = 0.0;
}
client->m_dig_time_remaining = dig_time;
// Reset build time counter
getClient(peer->id)->m_time_from_building.set(0.0);
#endif
} // action == 0 } // action == 0
/* /*
@ -2240,7 +2212,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
InventoryList *clist = player->inventory.getList("craft"); InventoryList *clist = player->inventory.getList("craft");
if(clist) if(clist)
{ {
clist->decrementMaterials(ma->count); u16 count = ma->count;
if(count == 0)
count = 1;
clist->decrementMaterials(count);
} }
// Do action // Do action
// Feed action to player inventory // Feed action to player inventory
@ -2424,8 +2399,15 @@ void Server::peerAdded(con::Peer *peer)
dout_server<<"Server::peerAdded(): peer->id=" dout_server<<"Server::peerAdded(): peer->id="
<<peer->id<<std::endl; <<peer->id<<std::endl;
// Connection is already locked when this is called. PeerChange c;
//JMutexAutoLock lock(m_con_mutex); c.type = PEER_ADDED;
c.peer_id = peer->id;
c.timeout = false;
m_peer_change_queue.push_back(c);
#if 0
// NOTE: Connection is already locked when this is called.
// NOTE: Environment is already locked when this is called.
// Error check // Error check
core::map<u16, RemoteClient*>::Node *n; core::map<u16, RemoteClient*>::Node *n;
@ -2440,9 +2422,6 @@ void Server::peerAdded(con::Peer *peer)
// Create player // Create player
{ {
// Already locked when called
//JMutexAutoLock envlock(m_env_mutex);
Player *player = m_env.getPlayer(peer->id); Player *player = m_env.getPlayer(peer->id);
// The player shouldn't already exist // The player shouldn't already exist
@ -2491,8 +2470,8 @@ void Server::peerAdded(con::Peer *peer)
// Give a good pick // Give a good pick
{ {
InventoryItem *item = new ToolItem("STPick", 32000); InventoryItem *item = new ToolItem("STPick", 32000);
bool r = player->inventory.addItem("main", item); void* r = player->inventory.addItem("main", item);
assert(r == true); assert(r == NULL);
} }
// Give all materials // Give all materials
assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE); assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
@ -2508,8 +2487,8 @@ void Server::peerAdded(con::Peer *peer)
// Sign // Sign
{ {
InventoryItem *item = new MapBlockObjectItem("Sign Example text"); InventoryItem *item = new MapBlockObjectItem("Sign Example text");
bool r = player->inventory.addItem("main", item); void* r = player->inventory.addItem("main", item);
assert(r == true); assert(r == NULL);
} }
/*// Rat /*// Rat
{ {
@ -2520,15 +2499,20 @@ void Server::peerAdded(con::Peer *peer)
} }
else else
{ {
{
InventoryItem *item = new CraftItem("Stick", 4);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
{ {
InventoryItem *item = new ToolItem("WPick", 32000); InventoryItem *item = new ToolItem("WPick", 32000);
bool r = player->inventory.addItem("main", item); void* r = player->inventory.addItem("main", item);
assert(r == true); assert(r == NULL);
} }
{ {
InventoryItem *item = new ToolItem("STPick", 32000); InventoryItem *item = new ToolItem("STPick", 32000);
bool r = player->inventory.addItem("main", item); void* r = player->inventory.addItem("main", item);
assert(r == true); assert(r == NULL);
} }
/*// Give some lights /*// Give some lights
{ {
@ -2551,6 +2535,7 @@ void Server::peerAdded(con::Peer *peer)
}*/ }*/
} }
} }
#endif
} }
void Server::deletingPeer(con::Peer *peer, bool timeout) void Server::deletingPeer(con::Peer *peer, bool timeout)
@ -2559,8 +2544,18 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
dout_server<<"Server::deletingPeer(): peer->id=" dout_server<<"Server::deletingPeer(): peer->id="
<<peer->id<<", timeout="<<timeout<<std::endl; <<peer->id<<", timeout="<<timeout<<std::endl;
// Connection is already locked when this is called. PeerChange c;
//JMutexAutoLock lock(m_con_mutex); c.type = PEER_REMOVED;
c.peer_id = peer->id;
c.timeout = timeout;
m_peer_change_queue.push_back(c);
#if 0
// NOTE: Connection is already locked when this is called.
// NOTE: Environment is already locked when this is called.
// NOTE: Locking environment cannot be moved here because connection
// is already locked and env has to be locked before
// Error check // Error check
core::map<u16, RemoteClient*>::Node *n; core::map<u16, RemoteClient*>::Node *n;
@ -2568,10 +2563,22 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
// The client should exist // The client should exist
assert(n != NULL); assert(n != NULL);
// Send information about leaving in chat
{
std::wstring name = L"unknown";
Player *player = m_env.getPlayer(peer->id);
if(player != NULL)
name = narrow_to_wide(player->getName());
std::wstring message;
message += L"*** ";
message += name;
message += L" left game";
BroadcastChatMessage(message);
}
// Delete player // Delete player
{ {
// Already locked when called
//JMutexAutoLock envlock(m_env_mutex);
m_env.removePlayer(peer->id); m_env.removePlayer(peer->id);
} }
@ -2581,6 +2588,7 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
// Send player info to all clients // Send player info to all clients
SendPlayerInfos(); SendPlayerInfos();
#endif
} }
void Server::SendObjectData(float dtime) void Server::SendObjectData(float dtime)
@ -2848,6 +2856,205 @@ void Server::UpdateBlockWaterPressure(MapBlock *block,
v.blitBack(modified_blocks); v.blitBack(modified_blocks);
} }
void Server::handlePeerChange(PeerChange &c)
{
JMutexAutoLock envlock(m_env_mutex);
JMutexAutoLock conlock(m_con_mutex);
if(c.type == PEER_ADDED)
{
/*
Add
*/
// Error check
core::map<u16, RemoteClient*>::Node *n;
n = m_clients.find(c.peer_id);
// The client shouldn't already exist
assert(n == NULL);
// Create client
RemoteClient *client = new RemoteClient();
client->peer_id = c.peer_id;
m_clients.insert(client->peer_id, client);
// Create player
{
Player *player = m_env.getPlayer(c.peer_id);
// The player shouldn't already exist
assert(player == NULL);
player = new ServerRemotePlayer();
player->peer_id = c.peer_id;
/*
Set player position
*/
// We're going to throw the player to this position
//v2s16 nodepos(29990,29990);
//v2s16 nodepos(9990,9990);
v2s16 nodepos(0,0);
v2s16 sectorpos = getNodeSectorPos(nodepos);
// Get zero sector (it could have been unloaded to disk)
m_env.getMap().emergeSector(sectorpos);
// Get ground height at origin
f32 groundheight = m_env.getMap().getGroundHeight(nodepos, true);
// The sector should have been generated -> groundheight exists
assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE);
// Don't go underwater
if(groundheight < WATER_LEVEL)
groundheight = WATER_LEVEL;
player->setPosition(intToFloat(v3s16(
nodepos.X,
groundheight + 1,
nodepos.Y
)));
/*
Add player to environment
*/
m_env.addPlayer(player);
/*
Add stuff to inventory
*/
if(g_settings.getBool("creative_mode"))
{
// Give a good pick
{
InventoryItem *item = new ToolItem("STPick", 32000);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
// Give all materials
assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
{
// Skip some materials
if(i == CONTENT_OCEAN)
continue;
InventoryItem *item = new MaterialItem(i, 1);
player->inventory.addItem("main", item);
}
// Sign
{
InventoryItem *item = new MapBlockObjectItem("Sign Example text");
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
/*// Rat
{
InventoryItem *item = new MapBlockObjectItem("Rat");
bool r = player->inventory.addItem("main", item);
assert(r == true);
}*/
}
else
{
{
InventoryItem *item = new CraftItem("Stick", 4);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
{
InventoryItem *item = new ToolItem("WPick", 32000);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
{
InventoryItem *item = new ToolItem("STPick", 32000);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
}
/*// Give some lights
{
InventoryItem *item = new MaterialItem(CONTENT_TORCH, 999);
bool r = player->inventory.addItem("main", item);
assert(r == true);
}
// and some signs
for(u16 i=0; i<4; i++)
{
InventoryItem *item = new MapBlockObjectItem("Sign Example text");
bool r = player->inventory.addItem("main", item);
assert(r == true);
}*/
/*// Give some other stuff
{
InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
bool r = player->inventory.addItem("main", item);
assert(r == true);
}*/
}
}
} // PEER_ADDED
else if(c.type == PEER_REMOVED)
{
/*
Delete
*/
// Error check
core::map<u16, RemoteClient*>::Node *n;
n = m_clients.find(c.peer_id);
// The client should exist
assert(n != NULL);
// Collect information about leaving in chat
std::wstring message;
{
std::wstring name = L"unknown";
Player *player = m_env.getPlayer(c.peer_id);
if(player != NULL)
name = narrow_to_wide(player->getName());
message += L"*** ";
message += name;
message += L" left game";
}
// Delete player
{
m_env.removePlayer(c.peer_id);
}
// Delete client
delete m_clients[c.peer_id];
m_clients.remove(c.peer_id);
// Send player info to all remaining clients
SendPlayerInfos();
// Send leave chat message to all remaining clients
BroadcastChatMessage(message);
} // PEER_REMOVED
else
{
assert(0);
}
}
void Server::handlePeerChanges()
{
while(m_peer_change_queue.size() > 0)
{
PeerChange c = m_peer_change_queue.pop_front();
dout_server<<"Server: Handling peer change: "
<<"id="<<c.peer_id<<", timeout="<<c.timeout
<<std::endl;
handlePeerChange(c);
}
}

View File

@ -434,6 +434,11 @@ private:
void UpdateBlockWaterPressure(MapBlock *block, void UpdateBlockWaterPressure(MapBlock *block,
core::map<v3s16, MapBlock*> &modified_blocks); core::map<v3s16, MapBlock*> &modified_blocks);
// Locks environment and connection by its own
struct PeerChange;
void handlePeerChange(PeerChange &c);
void handlePeerChanges();
float m_flowwater_timer; float m_flowwater_timer;
float m_print_info_timer; float m_print_info_timer;
float m_objectdata_timer; float m_objectdata_timer;
@ -466,6 +471,23 @@ private:
float m_time_counter; float m_time_counter;
float m_time_of_day_send_timer; float m_time_of_day_send_timer;
MutexedVariable<float> m_uptime;
enum PeerChangeType
{
PEER_ADDED,
PEER_REMOVED
};
struct PeerChange
{
PeerChangeType type;
u16 peer_id;
bool timeout;
};
Queue<PeerChange> m_peer_change_queue;
friend class EmergeThread; friend class EmergeThread;
friend class RemoteClient; friend class RemoteClient;
}; };