knightonline/server/GameServer/UserThread.cpp

435 lines
8.8 KiB
C++

#include "stdafx.h"
#include "../shared/Condition.h"
#include "KnightsManager.h"
#include "KingSystem.h"
#include "User.h"
static std::queue<Packet> _queue;
static uint16 _queuerId;
static bool _running = true;
static std::recursive_mutex _locker;
static std::vector<Thread *> s_threads;
static Condition s_hEvent;
static Thread * s_thread;
void CUser::Startup(uint32 dwThreads)
{
for (unsigned long i = 0; i < dwThreads; i++)
s_threads.push_back(new Thread(CUser::UserThreadProc, (void *)i));
}
bool CUser::HandlePacket(Packet & pktx)
{
Packet pkt(uint8(1));
uint8 command = pktx.GetOpcode();
BYTE tmpbuf[4096];
ZeroMemory(tmpbuf, 4096);
if(pktx.size() < 4)
return false;
uint32 crc = *(uint32*)(pktx.contents() + pktx.size() - 4);
uint32 packetcrc = 0;
for (uint16 i = 0; i < pktx.size() - 4; i++)
{
tmpbuf[i] = ((~(pktx.GetByte(i) ^ CRYPT_KEY / 8) ^ CRYPT_KEY * 5) ^ CRYPT_KEY * 22) ^ CRYPT_KEY;
tmpbuf[i] ^= ~((i + 1) ^ ((i + 1) * CRYPT_KEY / 244));
tmpbuf[i] ^= (m_pktcount * CRYPT_KEY);
pkt << uint8(tmpbuf[i]);
packetcrc += ((tmpbuf[i] ^ CRYPT_KEY) * 8);
}
command = ((~(command ^ CRYPT_KEY / 8) ^ CRYPT_KEY * 5) ^ CRYPT_KEY * 22) ^ CRYPT_KEY;
command ^= (m_pktcount * CRYPT_KEY);
pktx.SetOpcode(command);
pkt.SetOpcode(command);
if (crc != packetcrc && command == WIZ_LOGIN)
{
printf("crc1 : %p -- crc2 : %p opcode : %02X", crc, packetcrc, command);
return false;
}
m_pktcount++;
// crc çözümlüyor burda sonra threada yonlendiriyor ayýklayýp normal halde
printf("pktsize: %d, pktcount:%d\n",pkt.size(),m_pktcount);
Packet pks;
pks << uint16(GetSocketID()) << uint8(command);
printf("pkssize: %d, pktcount:%d\n",pks.size(),m_pktcount);
if (pkt.size())
pks.append(pkt.contents(), pkt.size());
printf("pkssize: %d, pktcount:%d\n",pks.size(),m_pktcount);
_lock.lock();
_queue.push(pks);
_lock.unlock();
s_hEvent.Signal();
return true;
}
uint32 THREADCALL CUser::UserThreadProc(void * lpParam)
{
while (true)
{
Packet p;
Packet *l = nullptr;
uint16 uid = -1;
uint8 command;
// Pull the next packet from the shared queue
_locker.lock();
if (_queue.size())
{
p = _queue.front();
_queue.pop();
l = &p;
}
_locker.unlock();
if (l == nullptr)
{
// If we're shutting down, don't bother waiting for more (there are no more).
if (!_running)
break;
s_hEvent.Wait();
continue;
}
//
// References are fun =p
Packet pkt = p;
// Attempt to lookup the user if necessary
CUser *pUser = nullptr;
pkt >> uid >> command;
if (uid >= 0)
{
pUser = g_pMain->GetUserPtr(uid);
// Check to make sure they're still connected.
if (pUser == nullptr)
continue;
}
else
continue;
// If crypto's not been enabled yet, force the version packet to be sent.
if (!pUser->isCryptoEnabled())
{
if (command == WIZ_VERSION_CHECK)
pUser->VersionCheck(pkt);
}
// If we're not authed yet, forced us to before we can do anything else.
// NOTE: We're checking the account ID store here because it's only set on successful auth,
// at which time the other account ID will be cleared out (yes, it's messy -- need to clean it up).
else if (pUser->m_strAccountID.empty())
{
if (command == WIZ_LOGIN)
pUser->LoginProcess(pkt);
}
// If we haven't logged in yet, don't let us hit in-game packets.
// TODO: Make sure we support all packets in the loading stage (and rewrite this logic considerably better).
else if (!pUser->m_bSelectedCharacter)
{
switch (command)
{
case WIZ_SEL_NATION:
pUser->SelNationToAgent(pkt);
break;
case WIZ_BRATE:
pUser->BRATE(pkt);
break;
case WIZ_ALLCHAR_INFO_REQ:
pUser->AllCharInfoToAgent();
break;
case WIZ_CHANGE_HAIR:
pUser->ChangeHair(pkt);
break;
case WIZ_NEW_CHAR:
pUser->NewCharToAgent(pkt);
break;
case WIZ_DEL_CHAR:
pUser->DelCharToAgent(pkt);
break;
case WIZ_SEL_CHAR:
pUser->SelCharToAgent(pkt);
break;
case WIZ_SPEEDHACK_CHECK:
pUser->SpeedHackTime(pkt);
break;
default:
printf("[SID=%d] Unhandled packet (%X) prior to selecting character\n", pUser->GetSocketID(), command);
break;
}
}
else if (pUser->m_bSelectedCharacter)
{
// Otherwise, assume we're authed & in-game.
switch (command)
{
case WIZ_GAMESTART:
pUser->GameStart(pkt);
break;
case WIZ_SERVER_INDEX:
pUser->SendServerIndex();
break;
case WIZ_CHANGE_HAIR:
pUser->ChangeHair(pkt);
break;
case WIZ_RENTAL:
pUser->RentalSystem(pkt);
break;
case WIZ_SKILLDATA:
pUser->SkillDataProcess(pkt);
break;
case WIZ_MOVE:
pUser->MoveProcess(pkt);
break;
case WIZ_ROTATE:
pUser->Rotate(pkt);
break;
case WIZ_ATTACK:
pUser->Attack(pkt);
break;
case WIZ_CHAT:
pUser->Chat(pkt);
break;
case WIZ_CHAT_TARGET:
pUser->ChatTargetSelect(pkt);
break;
case WIZ_REGENE:
pUser->Regene(pkt.read<uint8>()); // respawn type
break;
case WIZ_REQ_USERIN:
pUser->RequestUserIn(pkt);
break;
case WIZ_REQ_NPCIN:
pUser->RequestNpcIn(pkt);
break;
case WIZ_WARP:
if (pUser->isGM())
pUser->RecvWarp(pkt);
break;
case WIZ_ITEM_MOVE:
pUser->ItemMove(pkt);
break;
case WIZ_NPC_EVENT:
pUser->NpcEvent(pkt);
break;
case WIZ_ITEM_TRADE:
pUser->ItemTrade(pkt);
break;
case WIZ_TARGET_HP:
{
uint16 uid = pkt.read<uint16>();
uint8 echo = pkt.read<uint8>();
pUser->SetTargetID(uid);
pUser->SendTargetHP(echo, uid);
}
break;
case WIZ_BUNDLE_OPEN_REQ:
pUser->BundleOpenReq(pkt);
break;
case WIZ_ITEM_GET:
pUser->ItemGet(pkt);
break;
case WIZ_ZONE_CHANGE:
pUser->RecvZoneChange(pkt);
break;
case WIZ_POINT_CHANGE:
pUser->PointChange(pkt);
break;
case WIZ_STATE_CHANGE:
pUser->StateChange(pkt);
break;
case WIZ_PARTY:
pUser->PartyProcess(pkt);
break;
case WIZ_EXCHANGE:
pUser->ExchangeProcess(pkt);
break;
case WIZ_QUEST:
pUser->QuestV2PacketProcess(pkt);
break;
case WIZ_MERCHANT:
pUser->MerchantProcess(pkt);
break;
case WIZ_MAGIC_PROCESS:
CMagicProcess::MagicPacket(pkt, pUser);
break;
case WIZ_SKILLPT_CHANGE:
pUser->SkillPointChange(pkt);
break;
case WIZ_OBJECT_EVENT:
pUser->ObjectEvent(pkt);
break;
case WIZ_WEATHER:
case WIZ_TIME:
pUser->UpdateGameWeather(pkt);
break;
case WIZ_CLASS_CHANGE:
pUser->ClassChange(pkt);
break;
case WIZ_CONCURRENTUSER:
pUser->CountConcurrentUser();
break;
case WIZ_DATASAVE:
pUser->UserDataSaveToAgent();
break;
case WIZ_ITEM_REPAIR:
pUser->ItemRepair(pkt);
break;
case WIZ_KNIGHTS_PROCESS:
CKnightsManager::PacketProcess(pUser, pkt);
break;
case WIZ_ITEM_REMOVE:
pUser->ItemRemove(pkt);
break;
case WIZ_OPERATOR:
pUser->OperatorCommand(pkt);
break;
case WIZ_SPEEDHACK_CHECK:
pUser->SpeedHackTime(pkt);
break;
case WIZ_WAREHOUSE:
pUser->WarehouseProcess(pkt);
break;
case WIZ_HOME:
pUser->Home();
break;
case WIZ_FRIEND_PROCESS:
pUser->FriendProcess(pkt);
break;
case WIZ_WARP_LIST:
pUser->SelectWarpList(pkt);
break;
case WIZ_VIRTUAL_SERVER:
pUser->ServerChangeOk(pkt);
break;
case WIZ_PARTY_BBS:
pUser->PartyBBS(pkt);
break;
case WIZ_MAP_EVENT:
break;
case WIZ_CLIENT_EVENT:
pUser->ClientEvent(pkt.read<uint16>());
break;
case WIZ_SELECT_MSG:
pUser->RecvSelectMsg(pkt);
break;
case WIZ_ITEM_UPGRADE:
pUser->ItemUpgradeProcess(pkt);
break;
case WIZ_EVENT:
pUser->TempleProcess(pkt);
break;
case WIZ_SHOPPING_MALL: // letter system's used in here too
pUser->ShoppingMall(pkt);
break;
case WIZ_NAME_CHANGE:
pUser->HandleNameChange(pkt);
break;
case WIZ_PACKET3:
pUser->HandleCNameChange(pkt);
break;
case WIZ_KING:
CKingSystem::PacketProcess(pUser, pkt);
break;
case WIZ_HELMET:
pUser->HandleHelmet(pkt);
break;
case WIZ_CAPE:
pUser->HandleCapeChange(pkt);
break;
case WIZ_CHALLENGE:
pUser->HandleChallenge(pkt);
break;
case WIZ_RANK:
pUser->HandlePlayerRankings(pkt);
break;
case WIZ_MINING:
pUser->HandleMiningSystem(pkt);
break;
case WIZ_USER_INFO:
pUser->HandleUserInfo(pkt);
break;
case WIZ_ACHIEVE:
pUser->Achieve(pkt);
break;
case WIZ_SIEGE:
pUser->SiegeWarFareNpc(pkt);
break;
case WIZ_LOGOSSHOUT:
pUser->LogosShout(pkt);
break;
case WIZ_GENIE:
pUser->HandleGenie(pkt);
break;
case WIZ_CAPTURE:
pUser->HandleCapture(pkt);
break;
case WIZ_NATION_CHAT:
pUser->ChatRoomHandle(pkt);
break;
default:
TRACE("[SID=%d] Unknown packet %X\n", pUser->GetSocketID(), command);
break;
}
pUser->Update();
}
pkt.clear();
p.clear();
uid = -1;
}
printf("[User Thread %d] Exiting...\n", lpParam);
return 0;
}
void CUser::Shutdown()
{
_running = false;
// Wake them up in case they're sleeping.
if (!s_threads.empty())
{
// Wake them up in case they're sleeping.
s_hEvent.Broadcast();
foreach (itr, s_threads)
{
(*itr)->waitForExit();
delete (*itr);
}
s_threads.clear();
}
_locker.lock();
while (_queue.size())
{
Packet p = _queue.front();
_queue.pop();
p.clear();
}
_locker.unlock();
}