[svn] *** Source: MaNGOS ***

* Fixed english spelling in src/game/WorldSocket.h/cpp. Author: Derex
* [240_world.sql] Create new command .senditems and remove from moderator level command .sendmail possibility send items. Author: Vladimir
* Added new command: .sendmoney player "subject" "message" money - Sends a mail with money to a player. Author: fredi
* Correctly apply taken damage debufs/bonuses in cases non-physical melee damage. Author: Frankir
* Fix a crash in add friend/ignore callback. (check if player still logged in). Author: Hunuza
* Better args checking in .sendmoney command. Author: Vladimir

--HG--
branch : trunk
This commit is contained in:
visagalis
2008-11-14 17:50:48 -06:00
parent 053b671cb5
commit 3085e66b96
9 changed files with 296 additions and 116 deletions

View File

@@ -0,0 +1,5 @@
delete from `command` where `name` IN ('senditems','sendmail');
insert into `command` (`name`, `security`, `help`) values
('senditems',3,'Syntax: .senditems #playername "#subject" "#text" itemid1[:count1] itemid2[:count2] ... itemidN[:countN]\r\n\r\nSend a mail to a player. Subject and mail text must be in "". If for itemid not provided related count values then expected 1, if count > max items in stack then items will be send in required amount stacks. All stacks amount in mail limited to 12.'),
('sendmail',1,'Syntax: .sendmail #playername "#subject" "#text"\r\n\r\nSend a mail to a player. Subject and mail text must be in "".');

View File

@@ -544,7 +544,9 @@ ChatCommand * ChatHandler::getCommandTable()
{ "password", SEC_PLAYER, false, &ChatHandler::HandlePasswordCommand, "", NULL },
{ "lockaccount", SEC_PLAYER, false, &ChatHandler::HandleLockAccountCommand, "", NULL },
{ "respawn", SEC_ADMINISTRATOR, false, &ChatHandler::HandleRespawnCommand, "", NULL },
{ "sendmail", SEC_MODERATOR, false, &ChatHandler::HandleSendMailCommand, "", NULL },
{ "senditems", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendItemsCommand, "", NULL },
{ "sendmail", SEC_MODERATOR, true, &ChatHandler::HandleSendMailCommand, "", NULL },
{ "sendmoney", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMoneyCommand, "", NULL },
{ "rename", SEC_GAMEMASTER, true, &ChatHandler::HandleRenameCommand, "", NULL },
{ "loadscripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLoadScriptsCommand, "", NULL },
{ "mute", SEC_GAMEMASTER, true, &ChatHandler::HandleMuteCommand, "", NULL },

View File

@@ -117,10 +117,12 @@ class ChatHandler
bool HandleGPSCommand(const char* args);
bool HandleTaxiCheatCommand(const char* args);
bool HandleWhispersCommand(const char* args);
bool HandleSendMailCommand(const char* args);
bool HandleNameTeleCommand(const char* args);
bool HandleGroupTeleCommand(const char* args);
bool HandleDrunkCommand(const char* args);
bool HandleSendItemsCommand(const char* args);
bool HandleSendMailCommand(const char* args);
bool HandleSendMoneyCommand(const char* args);
bool HandleEventActiveListCommand(const char* args);
bool HandleEventStartCommand(const char* args);

View File

@@ -1863,7 +1863,7 @@ bool ChatHandler::HandleSendMailCommand(const char* args)
if(!*args)
return false;
// format: name "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12]
// format: name "subject text" "mail text"
char* pName = strtok((char*)args, " ");
if(!pName)
@@ -1910,60 +1910,6 @@ bool ChatHandler::HandleSendMailCommand(const char* args)
std::string subject = msgSubject;
std::string text = msgText;
// extract items
typedef std::pair<uint32,uint32> ItemPair;
typedef std::list< ItemPair > ItemPairs;
ItemPairs items;
// get all tail string
char* tail = strtok(NULL, "");
// get from tail next item str
while(char* itemStr = strtok(tail, " "))
{
// and get new tail
tail = strtok(NULL, "");
// parse item str
char* itemIdStr = strtok(itemStr, ":");
char* itemCountStr = strtok(NULL, " ");
uint32 item_id = atoi(itemIdStr);
if(!item_id)
return false;
ItemPrototype const* item_proto = objmgr.GetItemPrototype(item_id);
if(!item_proto)
{
PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id);
SetSentErrorMessage(true);
return false;
}
uint32 item_count = itemCountStr ? atoi(itemCountStr) : 1;
if(item_count < 1 || item_proto->MaxCount && item_count > item_proto->MaxCount)
{
PSendSysMessage(LANG_COMMAND_INVALID_ITEM_COUNT, item_count,item_id);
SetSentErrorMessage(true);
return false;
}
while(item_count > item_proto->Stackable)
{
items.push_back(ItemPair(item_id,item_proto->Stackable));
item_count -= item_proto->Stackable;
}
items.push_back(ItemPair(item_id,item_count));
if(items.size() > MAX_MAIL_ITEMS)
{
PSendSysMessage(LANG_COMMAND_MAIL_ITEMS_LIMIT, MAX_MAIL_ITEMS);
SetSentErrorMessage(true);
return false;
}
}
if(!normalizePlayerName(name))
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
@@ -1980,30 +1926,16 @@ bool ChatHandler::HandleSendMailCommand(const char* args)
}
uint32 mailId = objmgr.GenerateMailID();
uint32 sender_guidlo = m_session->GetPlayer()->GetGUIDLow();
// from console show not existed sender
uint32 sender_guidlo = m_session ? m_session->GetPlayer()->GetGUIDLow() : 0;
uint32 messagetype = MAIL_NORMAL;
uint32 stationery = MAIL_STATIONERY_GM;
uint32 itemTextId = 0;
if (!text.empty())
{
itemTextId = objmgr.CreateItemText( text );
}
uint32 itemTextId = !text.empty() ? objmgr.CreateItemText( text ) : 0;
Player *receiver = objmgr.GetPlayer(receiver_guid);
// fill mail
MailItemsInfo mi; // item list preparing
for(ItemPairs::const_iterator itr = items.begin(); itr != items.end(); ++itr)
{
if(Item* item = Item::CreateItem(itr->first,itr->second,m_session->GetPlayer()))
{
item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item);
}
}
WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_NONE);
PSendSysMessage(LANG_MAIL_SENT, name.c_str());
return true;

View File

@@ -6201,6 +6201,245 @@ bool ChatHandler::HandleAccountSetAddonCommand(const char* args)
return true;
}
//Send items by mail
bool ChatHandler::HandleSendItemsCommand(const char* args)
{
if(!*args)
return false;
// format: name "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12]
char* pName = strtok((char*)args, " ");
if(!pName)
return false;
char* tail1 = strtok(NULL, "");
if(!tail1)
return false;
char* msgSubject;
if(*tail1=='"')
msgSubject = strtok(tail1+1, "\"");
else
{
char* space = strtok(tail1, "\"");
if(!space)
return false;
msgSubject = strtok(NULL, "\"");
}
if (!msgSubject)
return false;
char* tail2 = strtok(NULL, "");
if(!tail2)
return false;
char* msgText;
if(*tail2=='"')
msgText = strtok(tail2+1, "\"");
else
{
char* space = strtok(tail2, "\"");
if(!space)
return false;
msgText = strtok(NULL, "\"");
}
if (!msgText)
return false;
// pName, msgSubject, msgText isn't NUL after prev. check
std::string name = pName;
std::string subject = msgSubject;
std::string text = msgText;
// extract items
typedef std::pair<uint32,uint32> ItemPair;
typedef std::list< ItemPair > ItemPairs;
ItemPairs items;
// get all tail string
char* tail = strtok(NULL, "");
// get from tail next item str
while(char* itemStr = strtok(tail, " "))
{
// and get new tail
tail = strtok(NULL, "");
// parse item str
char* itemIdStr = strtok(itemStr, ":");
char* itemCountStr = strtok(NULL, " ");
uint32 item_id = atoi(itemIdStr);
if(!item_id)
return false;
ItemPrototype const* item_proto = objmgr.GetItemPrototype(item_id);
if(!item_proto)
{
PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id);
SetSentErrorMessage(true);
return false;
}
uint32 item_count = itemCountStr ? atoi(itemCountStr) : 1;
if(item_count < 1 || item_proto->MaxCount && item_count > item_proto->MaxCount)
{
PSendSysMessage(LANG_COMMAND_INVALID_ITEM_COUNT, item_count,item_id);
SetSentErrorMessage(true);
return false;
}
while(item_count > item_proto->Stackable)
{
items.push_back(ItemPair(item_id,item_proto->Stackable));
item_count -= item_proto->Stackable;
}
items.push_back(ItemPair(item_id,item_count));
if(items.size() > MAX_MAIL_ITEMS)
{
PSendSysMessage(LANG_COMMAND_MAIL_ITEMS_LIMIT, MAX_MAIL_ITEMS);
SetSentErrorMessage(true);
return false;
}
}
if(!normalizePlayerName(name))
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
uint64 receiver_guid = objmgr.GetPlayerGUIDByName(name);
if(!receiver_guid)
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
// from console show not existed sender
uint32 sender_guidlo = m_session ? m_session->GetPlayer()->GetGUIDLow() : 0;
uint32 messagetype = MAIL_NORMAL;
uint32 stationery = MAIL_STATIONERY_GM;
uint32 itemTextId = !text.empty() ? objmgr.CreateItemText( text ) : 0;
Player *receiver = objmgr.GetPlayer(receiver_guid);
// fill mail
MailItemsInfo mi; // item list preparing
for(ItemPairs::const_iterator itr = items.begin(); itr != items.end(); ++itr)
{
if(Item* item = Item::CreateItem(itr->first,itr->second,m_session ? m_session->GetPlayer() : 0))
{
item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item);
}
}
WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
PSendSysMessage(LANG_MAIL_SENT, name.c_str());
return true;
}
///Send money by mail
bool ChatHandler::HandleSendMoneyCommand(const char* args)
{
if (!*args)
return false;
/// format: name "subject text" "mail text" money
char* pName = strtok((char*)args, " ");
if (!pName)
return false;
char* tail1 = strtok(NULL, "");
if (!tail1)
return false;
char* msgSubject;
if (*tail1=='"')
msgSubject = strtok(tail1+1, "\"");
else
{
char* space = strtok(tail1, "\"");
if (!space)
return false;
msgSubject = strtok(NULL, "\"");
}
if (!msgSubject)
return false;
char* tail2 = strtok(NULL, "");
if (!tail2)
return false;
char* msgText;
if (*tail2=='"')
msgText = strtok(tail2+1, "\"");
else
{
char* space = strtok(tail2, "\"");
if (!space)
return false;
msgText = strtok(NULL, "\"");
}
if (!msgText)
return false;
char* money_str = strtok(NULL, "");
int32 money = money_str ? atoi(money_str) : 0;
if (money <= 0)
return false;
// pName, msgSubject, msgText isn't NUL after prev. check
std::string name = pName;
std::string subject = msgSubject;
std::string text = msgText;
if (!normalizePlayerName(name))
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
uint64 receiver_guid = objmgr.GetPlayerGUIDByName(name);
if (!receiver_guid)
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
uint32 mailId = objmgr.GenerateMailID();
// from console show not existed sender
uint32 sender_guidlo = m_session ? m_session->GetPlayer()->GetGUIDLow() : 0;
uint32 messagetype = MAIL_NORMAL;
uint32 stationery = MAIL_STATIONERY_GM;
uint32 itemTextId = !text.empty() ? objmgr.CreateItemText( text ) : 0;
Player *receiver = objmgr.GetPlayer(receiver_guid);
WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, NULL, money, 0, MAIL_CHECK_MASK_NONE);
PSendSysMessage(LANG_MAIL_SENT, name.c_str());
return true;
}
/// Send a message to a player in game
bool ChatHandler::HandleSendMessageCommand(const char* args)
{

View File

@@ -499,7 +499,7 @@ void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult *result, uint32 acc
delete result;
WorldSession * session = sWorld.FindSession(accountId);
if(!session)
if(!session || !session->GetPlayer())
return;
FriendsResult friendResult = FRIEND_NOT_FOUND;
@@ -582,7 +582,7 @@ void WorldSession::HandleAddIgnoreOpcodeCallBack(QueryResult *result, uint32 acc
delete result;
WorldSession * session = sWorld.FindSession(accountId);
if(!session)
if(!session || !session->GetPlayer())
return;
FriendsResult ignoreResult = FRIEND_IGNORE_NOT_FOUND;

View File

@@ -7332,7 +7332,7 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
// ..taken
AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
if( (*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto) )
if((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto))
TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
// .. taken pct: scripted (increases damage of * against targets *)
@@ -8232,7 +8232,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
// ..taken
AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
TakenFlatBenefit += (*i)->GetModifier()->m_amount;
if(attType!=RANGED_ATTACK)
@@ -8256,7 +8256,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
// ..taken
AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
// .. taken pct: dummy auras

View File

@@ -462,20 +462,20 @@ int WorldSocket::handle_input_missing_data (void)
{
if (m_Header.space () > 0)
{
//need to recieve the header
//need to receive the header
const size_t to_header = (message_block.length () > m_Header.space () ? m_Header.space () : message_block.length ());
m_Header.copy (message_block.rd_ptr (), to_header);
message_block.rd_ptr (to_header);
if (m_Header.space () > 0)
{
//couldn't recieve the whole header this time
// Couldn't receive the whole header this time
ACE_ASSERT (message_block.length () == 0);
errno = EWOULDBLOCK;
return -1;
}
//we just recieved nice new header
// We just received nice new header
if (handle_input_header () == -1)
{
ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));
@@ -484,16 +484,16 @@ int WorldSocket::handle_input_missing_data (void)
}
// Its possible on some error situations that this happens
// for example on closing when epoll recieves more chunked data and stuff
// for example on closing when epoll receives more chunked data and stuff
// hope this is not hack ,as proper m_RecvWPct is asserted around
if (!m_RecvWPct)
{
sLog.outError ("Forsing close on input m_RecvWPct = NULL");
sLog.outError ("Forcing close on input m_RecvWPct = NULL");
errno = EINVAL;
return -1;
}
// We have full readed header, now check the data payload
// We have full read header, now check the data payload
if (m_RecvPct.space () > 0)
{
//need more data in the payload
@@ -503,14 +503,14 @@ int WorldSocket::handle_input_missing_data (void)
if (m_RecvPct.space () > 0)
{
//couldn't recieve the whole data this time
//couldn't receive the whole data this time
ACE_ASSERT (message_block.length () == 0);
errno = EWOULDBLOCK;
return -1;
}
}
//just recieved fresh new payload
//just received fresh new payload
if (handle_input_payload () == -1)
{
ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));
@@ -572,7 +572,7 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
if (closing_)
return -1;
// dump recieved packet
// Dump received packet
if (sWorldLog.LogWorld ())
{
sWorldLog.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
@@ -637,7 +637,7 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
{
// NOTE: ATM the socket is singlethreaded, have this in mind ...
// NOTE: ATM the socket is singlethread, have this in mind ...
uint8 digest[20];
uint32 clientSeed;
uint32 unk2;
@@ -929,7 +929,7 @@ int WorldSocket::HandlePing (WorldPacket& recvPacket)
if (m_Session && m_Session->GetSecurity () == SEC_PLAYER)
{
sLog.outError ("WorldSocket::HandlePing: Player kicked for "
"overspeeded pings adress = %s",
"over-speed pings address = %s",
GetRemoteAddress ().c_str ());
return -1;
@@ -950,7 +950,7 @@ int WorldSocket::HandlePing (WorldPacket& recvPacket)
{
sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, "
"but is not authenticated or got recently kicked,"
" adress = %s",
" address = %s",
GetRemoteAddress ().c_str ());
return -1;
}

View File

@@ -55,36 +55,36 @@ typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> WorldHandler;
/**
* WorldSocket.
*
* This class is responsible for the comunication with
* This class is responsible for the communication with
* remote clients.
* Most methods return -1 on failure.
* The class uses refferece counting.
* The class uses reference counting.
*
* For output the class uses one buffer (64K usually) and
* a queue where it stores packet if there is no place on
* the queue. The reason this is done, is because the server
* does realy a lot of small-size writes to it, and it doesn't
* does really a lot of small-size writes to it, and it doesn't
* scale well to allocate memory for every. When something is
* writen to the output buffer the socket is not immideately
* written to the output buffer the socket is not immediately
* activated for output (again for the same reason), there
* is 10ms celling (thats why there is Update() method).
* This concept is simmilar to TCP_CORK, but TCP_CORK
* usses 200ms celling. As result overhead generated by
* This concept is similar to TCP_CORK, but TCP_CORK
* uses 200ms celling. As result overhead generated by
* sending packets from "producer" threads is minimal,
* and doing a lot of writes with small size is tollerated.
* and doing a lot of writes with small size is tolerated.
*
* The calls to Upate () method are managed by WorldSocketMgr
* The calls to Update () method are managed by WorldSocketMgr
* and ReactorRunnable.
*
* For input ,the class uses one 1024 bytes buffer on stack
* to which it does recv() calls. And then recieved data is
* distributed where its needed. 1024 matches pritey well the
* to which it does recv() calls. And then received data is
* distributed where its needed. 1024 matches pretty well the
* traffic generated by client for now.
*
* The input/output do speculative reads/writes (AKA it tryes
* to read all data avaible in the kernel buffer or tryes to
* write everything avaible in userspace buffer),
* which is ok for using with Level and Edge Trigered IO
* to read all data available in the kernel buffer or tryes to
* write everything available in userspace buffer),
* which is ok for using with Level and Edge Triggered IO
* notification.
*
*/
@@ -99,7 +99,7 @@ class WorldSocket : protected WorldHandler
/// Declare the acceptor for this class
typedef ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR > Acceptor;
/// Mutex type used for various syncronizations.
/// Mutex type used for various synchronizations.
typedef ACE_Thread_Mutex LockType;
typedef ACE_Guard<LockType> GuardType;
@@ -120,10 +120,10 @@ class WorldSocket : protected WorldHandler
/// @return -1 of failure
int SendPacket (const WorldPacket& pct);
/// Add refference to this object.
/// Add reference to this object.
long AddReference (void);
/// Remove refference to this object.
/// Remove reference to this object.
long RemoveReference (void);
protected:
@@ -185,7 +185,7 @@ class WorldSocket : protected WorldHandler
/// Time in which the last ping was received
ACE_Time_Value m_LastPingTime;
/// Keep track of overspeed pings ,to prevent ping flood.
/// Keep track of over-speed pings ,to prevent ping flood.
uint32 m_OverSpeedPings;
/// Address of the remote peer
@@ -197,21 +197,21 @@ class WorldSocket : protected WorldHandler
/// Mutex lock to protect m_Session
LockType m_SessionLock;
/// Session to which recieved packets are routed
/// Session to which received packets are routed
WorldSession* m_Session;
/// here are stored the fragmens of the recieved data
/// here are stored the fragments of the received data
WorldPacket* m_RecvWPct;
/// This block actually refers to m_RecvWPct contents,
/// which alows easy and safe writing to it.
/// which allows easy and safe writing to it.
/// It wont free memory when its deleted. m_RecvWPct takes care of freeing.
ACE_Message_Block m_RecvPct;
/// Fragment of the recieved header.
/// Fragment of the received header.
ACE_Message_Block m_Header;
/// Mutex for protecting otuput related data.
/// Mutex for protecting output related data.
LockType m_OutBufferLock;
/// Buffer used for writing output.
@@ -221,7 +221,7 @@ class WorldSocket : protected WorldHandler
size_t m_OutBufferSize;
/// Here are stored packets for which there was no space on m_OutBuffer,
/// this alows not-to kick player if its buffer is overflowed.
/// this allows not-to kick player if its buffer is overflowed.
PacketQueueT m_PacketQueue;
/// True if the socket is registered with the reactor for output