Client::~Client()
{
+ {
+ JMutexAutoLock conlock(m_con_mutex);
+ m_con.Disconnect();
+ }
+
m_thread.setRun(false);
while(m_thread.IsRunning())
sleep_ms(100);
addNode(p, n);
}
- if(command == TOCLIENT_PLAYERPOS)
+ else if(command == TOCLIENT_PLAYERPOS)
{
dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
<<std::endl;
//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()
{
if(m_peers.size() != 1)
// the timeout counter
con->PrintInfo();
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{
con->PrintInfo(derr_con);
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)
{
out<<m_socket.GetHandle();
CONTROLTYPE_SET_PEER_ID
[2] u16 peer_id_new
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 CONTROLTYPE_ACK 0
#define CONTROLTYPE_SET_PEER_ID 1
#define CONTROLTYPE_PING 2
+#define CONTROLTYPE_DISCO 3
/*
ORIGINAL: This is a plain packet with no control and no error
checking at all.
void Connect(Address address);
bool Connected();
+ void Disconnect();
+
// Sets peer_id
SharedBuffer<u8> GetFromBuffers(u16 &peer_id);
// The peer_id of sender is stored in peer_id
// Return value: I guess this always throws an exception or
// actually gets data
+ // May call PeerHandler methods
u32 Receive(u16 &peer_id, u8 *data, u32 datasize);
// These will automatically package the data as an original or split
// Sends a raw packet
void RawSend(const BufferedPacket &packet);
+ // May call PeerHandler methods
void RunTimeouts(float dtime);
+
// Can throw a PeerNotFoundException
Peer* GetPeer(u16 peer_id);
// returns NULL if failed
Peer* GetPeerNoEx(u16 peer_id);
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; }
u16 GetPeerID(){ return m_peer_id; }
}
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);
//dstream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
ItemSpec s = getItemAtPos(p);
dstream<<"Queueing IACTION_MOVE"<<std::endl;
IMoveAction *a =
new IMoveAction();
- a->count = 1;
+ a->count = right ? 1 : 0;
a->from_name = m_selected_item->listname;
a->from_i = m_selected_item->i;
a->to_name = s.listname;
a->to_i = s.i;
m_actions->push_back(a);
}
- delete m_selected_item;
- m_selected_item = NULL;
+ bool source_empties = false;
+ 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
{
InventoryItem
*/
-InventoryItem::InventoryItem()
+InventoryItem::InventoryItem(u16 count)
{
+ m_count = count;
}
InventoryItem::~InventoryItem()
std::getline(is, 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")
{
std::string toolname;
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
- if(std::string("MaterialItem") == newitem->getName())
+ /*
+ First try to find if it could be added to some existing items
+ */
+ for(u32 i=0; i<m_items.size(); i++)
{
- 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;
- }
+ // Ignore empty slots
+ if(m_items[i] == NULL)
+ continue;
+ // Try adding
+ newitem = addItem(i, newitem);
+ if(newitem == NULL)
+ return NULL; // All was eaten
}
- // Else find an empty position
+
+ /*
+ Then try to add it to empty slots
+ */
for(u32 i=0; i<m_items.size(); i++)
{
- InventoryItem *item = m_items[i];
- if(item != NULL)
+ // Ignore unempty slots
+ if(m_items[i] != NULL)
continue;
- m_items[i] = newitem;
- return true;
+ // Try adding
+ newitem = addItem(i, newitem);
+ if(newitem == NULL)
+ return NULL; // All was eaten
}
- // Failed
- return false;
+
+ // 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.
- InventoryItem *item = m_items[i];
- if(item == NULL)
+ InventoryItem *to_item = m_items[i];
+ if(to_item == NULL)
{
m_items[i] = newitem;
- return true;
+ return NULL;
}
-
- // If it is a material item, try to
- if(std::string("MaterialItem") == newitem->getName())
+
+ // If not addable, return the item
+ 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())
+ {
+ to_item->add(newitem->getCount());
+ delete newitem;
+ return NULL;
+ }
+ // Else the item does not fit fully. Add all that fits and return
+ // the rest.
+ else
{
- u8 material = ((MaterialItem*)newitem)->getMaterial();
- u8 count = ((MaterialItem*)newitem)->getCount();
- InventoryItem *item2 = m_items[i];
+ u16 freespace = to_item->freeSpace();
+ to_item->add(freespace);
+ newitem->remove(freespace);
+ return newitem;
+ }
+}
- if(item2 != NULL
- && std::string("MaterialItem") == item2->getName())
- {
- // Check if it is of the right material and has free space
- MaterialItem *mitem2 = (MaterialItem*)item2;
- if(mitem2->getMaterial() == material
- && mitem2->freeSpace() >= count)
- {
- // Add to the counter
- mitem2->add(count);
- // Dump the parameter
- delete newitem;
- // Done
- return true;
- }
- }
+InventoryItem * InventoryList::takeItem(u32 i, u32 count)
+{
+ if(count == 0)
+ return NULL;
+
+ InventoryItem *item = m_items[i];
+ // If it is an empty position, return NULL
+ if(item == NULL)
+ return NULL;
+
+ if(count >= item->getCount())
+ {
+ // Get the item by swapping NULL to its place
+ return changeItem(i, NULL);
+ }
+ else
+ {
+ InventoryItem *item2 = item->clone();
+ item->remove(count);
+ item2->setCount(count);
+ return item2;
}
return false;
{
for(u32 i=0; i<m_items.size(); i++)
{
- InventoryItem *item = m_items[i];
- if(item == NULL)
- continue;
- 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);
- }
- }
+ InventoryItem *item = takeItem(i, count);
+ if(item)
+ delete item;
}
}
dstream<<" list_to->getItem(to_i)="<<list_to->getItem(to_i)
<<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
|| (list_from == list_to && from_i == to_i))
{
}
// 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
- if(list_to->addItem(to_i, item1))
- {
- // Done.
+ 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)
+ {
+ // 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;
}
- // 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
// For g_materials
#include "main.h"
+#define QUANTITY_ITEM_MAX_COUNT 99
+
class InventoryItem
{
public:
- InventoryItem();
+ InventoryItem(u16 count);
virtual ~InventoryItem();
static InventoryItem* deSerialize(std::istream &is);
// Shall return a text to show in the GUI
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
{
public:
- MaterialItem(u8 content, u16 count)
+ MaterialItem(u8 content, u16 count):
+ InventoryItem(count)
{
m_content = content;
- m_count = count;
}
/*
Implementation interface
os<<m_count;
return os.str();
}
- /*
- Special methods
- */
- u8 getMaterial()
- {
- return m_content;
- }
- u16 getCount()
+
+ virtual bool addableTo(InventoryItem *other)
{
- return m_count;
+ 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 > MATERIAL_ITEM_MAX_COUNT)
+ if(m_count > QUANTITY_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;
+ return QUANTITY_ITEM_MAX_COUNT - m_count;
}
- void remove(u16 count)
+ /*
+ Special methods
+ */
+ u8 getMaterial()
{
- assert(m_count >= count);
- m_count -= count;
+ return m_content;
}
private:
u8 m_content;
- u16 m_count;
};
class MapBlockObjectItem : public InventoryItem
{
public:
- /*MapBlockObjectItem(MapBlockObject *obj)
- {
- m_inventorystring = obj->getInventoryString();
- }*/
- MapBlockObjectItem(std::string inventorystring)
+ MapBlockObjectItem(std::string inventorystring):
+ InventoryItem(1)
{
m_inventorystring = 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
{
public:
- ToolItem(std::string toolname, u16 wear)
+ ToolItem(std::string toolname, u16 wear):
+ InventoryItem(1)
{
m_toolname = toolname;
m_wear = wear;
InventoryItem * changeItem(u32 i, InventoryItem *newitem);
// Delete item
void deleteItem(u32 i);
- // Adds an item to a suitable place. Returns false if failed.
- bool addItem(InventoryItem *newitem);
- // If possible, adds item to given slot. Returns true on success.
- // Fails when slot is populated by a different kind of item.
- bool addItem(u32 i, InventoryItem *newitem);
+ // Adds an item to a suitable place. Returns leftover item.
+ // If all went into the list, returns NULL.
+ InventoryItem * addItem(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
void decrementMaterials(u16 count);
InventoryList * addList(const std::string &name, u32 size);
InventoryList * getList(const std::string &name);
bool deleteList(const std::string &name);
- // A shorthand for adding items
- bool addItem(const std::string &listname, InventoryItem *newitem)
+ // A shorthand for adding items.
+ // Returns NULL if the item was fully added, leftover otherwise.
+ InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
{
InventoryList *list = getList(listname);
if(list == NULL)
- return false;
+ return newitem;
return list->addItem(newitem);
}
struct IMoveAction : public InventoryAction
{
+ // count=0 means "everything"
u16 count;
std::string from_name;
s16 from_i;
// Test the text input system\r
/*(new GUITextInputMenu(guienv, guiroot, -1, &g_active_menu_count,\r
NULL))->drop();*/\r
+ \r
+ // Launch pause menu\r
+ (new GUIPauseMenu(guienv, guiroot, -1, g_device,\r
+ &g_active_menu_count))->drop();\r
\r
// First line of debug text\r
gui::IGUIStaticText *guitext = guienv->addStaticText(\r
}\r
// We want a slight delay to very little\r
// time consuming nodes\r
- if(nodig_delay_counter < 0.15)\r
+ //float mindelay = 0.15;\r
+ float mindelay = 0.20;\r
+ if(nodig_delay_counter < mindelay)\r
{\r
- nodig_delay_counter = 0.15;\r
+ nodig_delay_counter = mindelay;\r
}\r
}\r
\r
}
}
-/*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
*/
m_emergethread(this),
m_time_of_day(8000),
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_print_info_timer = 0.0;
if(dtime < 0.001)
return;
+ //dstream<<"Server steps "<<dtime<<std::endl;
+ //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
+
{
JMutexAutoLock lock1(m_step_dtime_mutex);
m_step_dtime -= dtime;
}
+
+ /*
+ Update uptime
+ */
+ {
+ m_uptime.set(m_uptime.get() + dtime);
+ }
/*
Update m_time_of_day
}
}
- //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
JMutexAutoLock lock2(m_con_mutex);
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
// This also runs Map's timers
u32 datasize;
try{
{
- JMutexAutoLock lock(m_con_mutex);
+ JMutexAutoLock conlock(m_con_mutex);
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);
}
catch(con::InvalidIncomingDataException &e)
m_time_of_day.get());
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
{
*/
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
/*
InventoryList *clist = player->inventory.getList("craft");
if(clist)
{
- clist->decrementMaterials(ma->count);
+ u16 count = ma->count;
+ if(count == 0)
+ count = 1;
+ clist->decrementMaterials(count);
}
// Do action
// Feed action to player inventory
dout_server<<"Server::peerAdded(): peer->id="
<<peer->id<<std::endl;
- // Connection is already locked when this is called.
- //JMutexAutoLock lock(m_con_mutex);
+ PeerChange c;
+ 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
core::map<u16, RemoteClient*>::Node *n;
// Create player
{
- // Already locked when called
- //JMutexAutoLock envlock(m_env_mutex);
-
Player *player = m_env.getPlayer(peer->id);
// The player shouldn't already exist
// Give a good pick
{
InventoryItem *item = new ToolItem("STPick", 32000);
- bool r = player->inventory.addItem("main", item);
- assert(r == true);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
}
// Give all materials
assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
// Sign
{
InventoryItem *item = new MapBlockObjectItem("Sign Example text");
- bool r = player->inventory.addItem("main", item);
- assert(r == true);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
}
/*// Rat
{
}
else
{
+ {
+ InventoryItem *item = new CraftItem("Stick", 4);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
{
InventoryItem *item = new ToolItem("WPick", 32000);
- bool r = player->inventory.addItem("main", item);
- assert(r == true);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
}
{
InventoryItem *item = new ToolItem("STPick", 32000);
- bool r = player->inventory.addItem("main", item);
- assert(r == true);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
}
/*// Give some lights
{
}*/
}
}
+#endif
}
void Server::deletingPeer(con::Peer *peer, bool timeout)
dout_server<<"Server::deletingPeer(): peer->id="
<<peer->id<<", timeout="<<timeout<<std::endl;
- // Connection is already locked when this is called.
- //JMutexAutoLock lock(m_con_mutex);
+ PeerChange c;
+ 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
core::map<u16, RemoteClient*>::Node *n;
// The client should exist
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
{
- // Already locked when called
- //JMutexAutoLock envlock(m_env_mutex);
m_env.removePlayer(peer->id);
}
// Send player info to all clients
SendPlayerInfos();
+#endif
}
void Server::SendObjectData(float dtime)
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);
+ }
+}
void UpdateBlockWaterPressure(MapBlock *block,
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_print_info_timer;
float m_objectdata_timer;
float m_time_counter;
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 RemoteClient;
};