www.pudn.com > loseserver.rar > LoseServerBeta3.cpp
/* Copyright (C) 2004 freeplay.dk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. You may contact me for further information on admin@freeplay.dk */ #define WIN32_LEAN_AND_MEAN // disable map warnings for std::map #pragma warning (disable: 4786) #pragma warning (disable: 4788) #include#include #include #include #include #include #include #include #include #include #include #include #include #include #include "resource.h" #include "LoseServerBeta3.h" #include "Logging.h" #include "AccountMaker.h" #include "ComWindows.h" #include "Database.h" #include "Types.h" #include "OpCodes.h" #include "random.h" #include "Loginserver.h" #include "GS_Attack.h" #include "GS_Chat.h" #include "GameServer.h" #include "DoorSpawn.h" #include "NPCSpawn.h" #include "WorldTpUrls.h" #include "WorldNPC.h" #include "WorldKnown.h" #include "LoginMap.h" #include "CharMap.h" #include "ObjectsMultimap.h" #include "Serversettings.h" #include "cave_teleport.h" using namespace std; //******************************************* // defines //******************************************* #define SIZE 65000 //******************************************* // class defines //******************************************* CNetworking Networking; CConnection* Connection = NULL; ComWindows com; database db; LoginServer lserver; GS_Attack Attack; GS_Chat Chat; GameServer gs; /** memory mappings **/ lineage enc; LoginMap dblmap; charmap chm; objects obj; ServerSettings ss; worldnpc npc; WorldKnown wk; world_tp wtp; /** spawn maps **/ door_parser dp; npc_parser np; /** scriptings **/ Cave_Teleporters_Scripting cts; //******************************************* // main handle //******************************************* HWND hdwnd; //******************************************* // threads //******************************************* struct thread1 { HWND hwnd1; }; HANDLE hThrd1; thread1 obj1; struct thread2 { HWND hwnd2; }; HANDLE hThrd2; thread2 obj2; struct thread3 { HWND hwnd3; }; HANDLE hThrd3; thread3 obj3; //******************************************* // main program init dialog //******************************************* int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgs, int nCmdShow ) { MSG msg; hMainInstance = hInstance; HACCEL hAccelTable; hdwnd = CreateDialog(hMainInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)DialogFunc); if( !hdwnd ) return FALSE; ShowWindow( hdwnd, nCmdShow ); UpdateWindow( hdwnd ); hAccelTable = LoadAccelerators(hMainInstance, (LPCTSTR)IDR_ACCELERATOR1); while( GetMessage(&msg, NULL, 0, 0) ) { if (IsDialogMessage(hdwnd, &msg)) continue; TranslateMessage( &msg ); DispatchMessage( &msg ); } return msg.wParam; } //******************************************* // display main dialog //******************************************* BOOL CALLBACK DialogFunc(HWND hdwnd, UINT Msg, WPARAM wParam, LPARAM lParam) { INITCOMMONCONTROLSEX InitCtrlEx; InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX); InitCtrlEx.dwICC = ICC_PROGRESS_CLASS; InitCommonControlsEx(&InitCtrlEx); switch(Msg) { case WM_INITDIALOG: { // Load Icons hLargeIcon = LoadIcon ( hMainInstance, MAKEINTRESOURCE(IDI_LINLARGE) ); hSmallIcon = (HICON) LoadImage ( hMainInstance, MAKEINTRESOURCE(IDI_LINSMALL), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ); SendMessage ( hdwnd, WM_SETICON, ICON_BIG, (LPARAM)hLargeIcon ); SendMessage ( hdwnd, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon ); // status bar init hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hdwnd, (HMENU)IDC_MAIN_STATUS, GetModuleHandle(NULL), NULL); //modify system menu //(remove Restore, Maximize and Resize) HMENU hSysMenu=GetSystemMenu(hdwnd, FALSE); DeleteMenu(hSysMenu, 0, MF_BYPOSITION); DeleteMenu(hSysMenu, 1, MF_BYPOSITION); DeleteMenu(hSysMenu, 2, MF_BYPOSITION); //store main window handle // message handling tru dialog hAppTime=GetDlgItem(hdwnd, IDC_APPTIMER); hData=GetDlgItem(hdwnd, IDC_LIST); hKick=GetDlgItem(hdwnd, IDC_KICKUSER); hBan=GetDlgItem(hdwnd, IDC_BANUSER); hLoginServer=GetDlgItem(hdwnd, IDC_LOGINSERVERSTATUS); hDBServer=GetDlgItem(hdwnd, IDC_DBSERVERSTATUS); // status bar size hStatus = GetDlgItem(hdwnd, IDC_MAIN_STATUS); SendMessage(hStatus, WM_SIZE, 0, 0); // status bar messages int statwidths[] = {165, -1}; SendMessage(hStatus, SB_SETPARTS, sizeof(statwidths)/sizeof(int), (LPARAM)statwidths); // Logging Inits createlogdir(); // Create Log Dir Log2File(FALSE, "o-------------------------------------------------------------------------------------o\n"); Log2File(FALSE, "| LoSE - Lineage online Server (Beta 0.4.1) Logfile |\n"); Log2File(FALSE, "| -------------------------- |\n"); Log2File(FALSE, "| Logfile Createt By LoSE - Lineage online Server Emulator. |\n"); Log2File(FALSE, "| |\n"); Log2File(FALSE, "| Keep this data clasified!! |\n"); Log2File(FALSE, "o-------------------------------------------------------------------------------------o\n\n"); Log2File(TRUE, "Initializing Login Server Startup Sequence\n"); com.WriteEditStr(hLoginServer, "OFFLINE"); com.WriteEditStr(hDBServer, "OFFLINE"); com.WriteDataStr(hdwnd , "Initializing Login Server....."); // startups if(ss.readsettings(hdwnd) == 1) { com.WriteDataStr(hdwnd, "Network settings succesfully loaded."); } //cts.readsettings(hdwnd); // status bar max users statusbarmsg("init"); // database init if(!db.CheckDatabase(hdwnd)) { // error connecting to database. MessageBox(hdwnd, "FATAL ERROR : connecting to database failed.\nCheck setting in network.ini", "Fatal Error", MB_OK | MB_ICONERROR); Log2File(TRUE, "Error connecting to database, check settings in network.ini"); exit(1); } else { // ping database connection every 1 minutes obj3.hwnd3 = hdwnd; hThrd3 = CreateThread(NULL, // no security attributes 0, // use default stack size (LPTHREAD_START_ROUTINE) ThreadProcPingTimer, (LPVOID)&obj3, // param to thread func CREATE_SUSPENDED, // creation flag NULL); // ResumeThread(hThrd3); SetThreadPriority(hThrd3,THREAD_PRIORITY_NORMAL); } // some more startups CompTime = GetTickCount(); SetTimer(hdwnd, 1, 100, NULL); EnableWindow(hKick, FALSE); EnableWindow(hBan, FALSE); // default spawns dp.door_parse(hdwnd); np.npc_parse(hdwnd); wtp.opentpfile(hdwnd); // startup network char * cip = ss.getServerip("GameserverIP"); // startup network if (!Networking.Listen (CONNECT_PORT)) { com.WriteDataStr(hdwnd , "ERROR : Unable to listen at port %i", CONNECT_PORT); Log2File(TRUE, "ERROR : Unable to listen at port %i", CONNECT_PORT); } else { com.WriteDataStr(hdwnd , "Listening for connections at %s port %i", cip, CONNECT_PORT); Log2File(TRUE, "Listening for connections at %s port %i\n", cip, CONNECT_PORT); com.WriteEditStr(hLoginServer, "ONLINE"); } // what to run if connection is acceptet Networking.SetAcceptFunc (AcceptCallback); // threads // status timer: obj1.hwnd1 = hdwnd; hThrd1 = CreateThread(NULL, // no security attributes 0, // use default stack size (LPTHREAD_START_ROUTINE) ThreadProcStatusTimer, (LPVOID)&obj1, // param to thread func CREATE_SUSPENDED, // creation flag NULL); // ResumeThread(hThrd1); SetThreadPriority(hThrd1,THREAD_PRIORITY_NORMAL); // server & client time obj2.hwnd2 = hdwnd; hThrd2 = CreateThread(NULL, // no security attributes 0, // use default stack size (LPTHREAD_START_ROUTINE) ThreadProcClientTimer, (LPVOID)&obj2, // param to thread func CREATE_SUSPENDED, // creation flag NULL); // ResumeThread(hThrd2); SetThreadPriority(hThrd2,THREAD_PRIORITY_NORMAL); return TRUE; } // server uptime static unsigned int ApplicationHours, ApplicationMinutes, ApplicationSeconds; case WM_TIMER: { unsigned long CurTickValue = GetTickCount(); unsigned int Difference = CurTickValue - CompTime; ApplicationHours = (Difference / (3600 * 999)) % 24; ApplicationMinutes = (Difference / (60 * 999)) % 60; ApplicationSeconds = (Difference / 999) % 60; char StrBuffer[256]; sprintf( StrBuffer, "%d hrs %d mins %d secs", ApplicationHours, ApplicationMinutes, ApplicationSeconds ); SendMessage(hAppTime, WM_SETTEXT, 0, (LPARAM)(LPSTR)StrBuffer); return TRUE; } break; case WM_COMMAND: switch(LOWORD(wParam)) { // display dialogs case ID_HELP_ABOUT: { int ret = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hdwnd, AboutDlgProc); } break; case IDC_CLEARTEXT: { SendMessage(hData, LB_RESETCONTENT, 0, 0); } break; case ID_TOOLS_CREATEACCOUNT: { int ret = DialogBox(GetModuleHandle(NULL) , MAKEINTRESOURCE(IDD_ACCOUNTMAKER), hdwnd, AccountDlgProc); } break; //main program exit warning case IDOK: case IDCANCEL: case ID_FILE_EXIT: int nResult; nResult = MessageBox(hdwnd, "Are you sure you want to exit?", "Quit?", MB_YESNO | MB_ICONQUESTION); if (nResult == IDYES) { DestroyWindow(hdwnd); } else { return TRUE; } return TRUE; } break; case WM_DESTROY: Log2File(TRUE, "Closing down all threads and exiting program.\n"); Networking.StopListen(); TerminateThread(hThrd1, 0); TerminateThread(hThrd2, 0); TerminateThread(hThrd3, 0); db.resetDB(); db.mysqlclose(); char StrBuffer[256]; sprintf( StrBuffer, "%d hrs %d mins %d secs", ApplicationHours, ApplicationMinutes, ApplicationSeconds ); Log2File(TRUE, "Server closed down after %s uptime.\n", StrBuffer); PostQuitMessage(0); return TRUE; } return FALSE; } //******************************************* // show about dialog //******************************************* BOOL CALLBACK AboutDlgProc(HWND hdwnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_INITDIALOG: hLargeIcon = LoadIcon ( hMainInstance, MAKEINTRESOURCE(IDI_LINLARGE) ); hSmallIcon = (HICON) LoadImage ( hMainInstance, MAKEINTRESOURCE(IDI_LINSMALL), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR ); SendMessage ( hdwnd, WM_SETICON, ICON_BIG, (LPARAM)hLargeIcon ); SendMessage ( hdwnd, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon ); return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: EndDialog(hdwnd, IDOK); break; case IDCANCEL: EndDialog(hdwnd, IDCANCEL); break; } break; default: return FALSE; } return TRUE; } //******************************************* // status timer //******************************************* int StatusTimer() { // date, time char buffer[SIZE]; time_t curtime; struct tm *loctime; curtime = time (NULL); loctime = localtime (&curtime); strftime (buffer, SIZE, " Date: %d/%m-%Y %H:%M:%S", loctime); SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)buffer); Sleep(1000); return 0; } //******************************************* // status timer thread. //******************************************* UINT ThreadProcStatusTimer(LPVOID pParam) { while(1) { StatusTimer();// starts the timer main loop } } //******************************************* // server and client time thread. //******************************************* UINT ThreadProcClientTimer(LPVOID pParam) { while(1) { db.setclienttime(0); Sleep(1000); } } //******************************************* // Ping Database connection. //******************************************* UINT ThreadProcPingTimer(LPVOID pParam) { while(1) { db.mysqlping(); Sleep(10000); } } //******************************************* // status bar message (users online) //******************************************* void statusbarmsg(char * todo) { char* line0; int line1; char* line2; char* line3; char* line4; static int currentuser; static int alluser; if (strcmp(todo,"add") == 0) { currentuser = alluser; alluser = currentuser + 1; ss.setUsersonline(alluser); } if (strcmp(todo,"remove") == 0) { currentuser = alluser; alluser = currentuser - 1; ss.setUsersonline(alluser); } if (strcmp(todo,"init") == 0) { alluser = 0; ss.setUsersonline(alluser); } char * maxuser = ss.getMaxusers("Maxusers"); // put the status bar message together line0 = " Users Online: "; line1 = alluser; line2 = "/"; line3 = (char*)maxuser; line4 = " (total/max)"; char* sbbuf = new char[strlen(line0)+4+strlen(line2)+strlen(line3)+strlen(line4)]; sprintf(sbbuf,"%s%i%s%s%s",line0,line1,line2,line3,line4); // set the status bar message SendMessage(hStatus, SB_SETTEXT, 1, (LPARAM)sbbuf); return; } //*************************************************************** // did we accept a connection, if so, what do we do // TODO : Add key startup system //*************************************************************** int connections[8]; void AcceptCallback (DWORD ptr) { char cip[15]; unsigned int cp = 0; CNetworking* net = reinterpret_cast (ptr); Connection = net->GetAccepted (); Connection->PeerInfo (&cip[0], 15, &cp); com.WriteDataStr(hdwnd , "Acceptet connection from %s", cip); Log2File(TRUE, "Acceptet connection from %s on socket %i\n", cip, cp); statusbarmsg("add"); initRand(); int thiskey = random(100000, 500000); int16 random2 = random(1, 900); int8 random3 = random(1, 99); unsigned char sizepack[] = { 0x0A, 0x00 }; // size + opcode int8 opcode = l_sc_keypacket; unsigned long key = (unsigned long)thiskey; // random key char buf[10]; char* buf_ptr= buf; memcpy(buf_ptr,(char*)&sizepack, 2); buf_ptr+=2; memcpy(buf_ptr,(char*)&opcode, 1); buf_ptr+=1; memcpy(buf_ptr,(char*)&key, 4); buf_ptr+=4; memcpy(buf_ptr,(char*)&random2, 2); buf_ptr+=2; memcpy(buf_ptr,(char*)&random3, 1); if(Connection->IsConnected()) { // send key Connection->Send((char *)&buf, 10); // set networking stuff Connection->SetReceiveFunc (ReceiveCallback); Connection->SetCloseFunc (CloseCallback); } else { // connection isnt connectet } } //*************************************************************** // what do we do if client closes connection // TODO : add saving of chars and so on. //*************************************************************** void CloseCallback (DWORD ptr) { CConnection* c = reinterpret_cast (ptr); char cip[15]; unsigned int cp = 0; c->PeerInfo (&cip[0], 15, &cp); statusbarmsg("remove"); if(cp > 0) { string name = dblmap.getUsername(cp); char * username = strdup(name.c_str()); com.RemoveUserOnline(hdwnd, username); com.WriteDataStr(hdwnd , "Connection was closed from %s", cip); Log2File(TRUE, "Connection was closed from %s on socket %i\n", cip, cp); db.saveuserobject(ptr); obj.removeknownobjectlogout(cp, chm.getObjectid(cp)); int accountid = dblmap.getAccountid(cp); db.setisplaying(accountid, 0); dblmap.removeMap(cp); obj.removeMap(cp); obj.removeknownobject(cp, chm.getObjectid(cp)); wk.removeknownobjectlogout(ptr); chm.removeMap(cp); } } //*************************************************************** // send a packet to the client from anywhere. //*************************************************************** struct SendPacket { int16 size; /* sends xx xx */ char data[65536]; /* data */ }; void sendpacket(char * data, int size, DWORD ptr) { CConnection* c = reinterpret_cast (ptr); char cip[15]; unsigned int cp = 0; c->PeerInfo (&cip[0], 15, &cp); struct SendPacket out; out.size = sizeof(out.size)+size; memcpy(&out.data,data,size); char outdata[sizeof(out.size)+sizeof(out.data)]; char* buf_ptr= outdata; // done so we can mover buf_ptr to were we need to memcpy memcpy(buf_ptr,(char*)&out.size,sizeof(out.size)); buf_ptr+=sizeof(out.size); memcpy(buf_ptr,out.data,out.size); c->Send((char*)&out, out.size); } //*************************************************************** // We received a packet from the client, what do we do with it //*************************************************************** void ReceiveCallback (DWORD ptr) { //char * buff = new char[1460]; char buff[1460] = ""; CConnection* c = reinterpret_cast (ptr); // peer info char cip[15]; unsigned int cp = 0; c->PeerInfo (&cip[0], 15, &cp); // receive message int size = c->Receive (buff, 1460); // check message if (size > 0) { PacketReceiver ( ptr, buff , size); } else { // bad packet ? } } void PacketReceiver (DWORD ptr, char * buff, int size) { CConnection* c = reinterpret_cast (ptr); char cip[15]; unsigned int cp = 0; c->PeerInfo (&cip[0], 15, &cp); int z; BYTE OpCode; // remove size of message from the buffer int16 lengh = buff[0]; int indatasize = lengh - 2; char * recdata = new char[indatasize]; recdata = &buff[2]; // check the opcode switch(recdata[0]) { //************************************* // Login Server Packets //************************************* case l_cs_handshake: { // send final packet before login (version packet), need fixing later lserver.sendversionpack(ptr, (char *)&recdata[1]); } break; case l_cs_loginpack: { // request login lserver.checkname(hdwnd, (char *)&recdata[1], ptr); } break; case l_cs_createchar: { // create char request string us = dblmap.getUsername(cp); char * username = strdup(us.c_str()); char * charname = (char*)&recdata[1]; com.WriteDataStr(hdwnd, "%s is creating character : %s", username, charname); int acc = dblmap.getAccountid(cp); lserver.createchar(acc, (char *)&recdata[1], ptr); } break; case l_cs_returnloginscreen: { // return back to login screen (i think) string us = dblmap.getUsername(cp); char * username = strdup(us.c_str()); com.RemoveUserOnline(hdwnd, (char*)username); int accountid = dblmap.getAccountid(cp); db.setisplaying(accountid, 0); } break; case l_cs_deletechar: { // delete a character string us = dblmap.getUsername(cp); char * username = strdup(us.c_str()); char * charname = (char*)&recdata[1]; com.WriteDataStr(hdwnd, "%s Is deleting character : %s", username, charname); db.deletechar((char *)&recdata[1], ptr); } break; case l_cs_loginselectchar: { // user wants to login with selectet char string us = dblmap.getUsername(cp); char * username = strdup(us.c_str()); char * charname = (char*)&recdata[1]; com.WriteDataStr(hdwnd, "%s Requestet login with character : %s", username, charname); lserver.reqlogin(hdwnd, ptr, charname); } break; //************************************* // Game Server Packets //************************************* case g_cs_restart: { // restart to select new character (remove all know objects + stuff about the character logging out). // later need to add this to remove user from all others knownobjects // also send a packet to remove the users ingame. obj.removeknownobjectlogout(cp, chm.getObjectid(cp)); wk.removeknownobjectlogout(ptr); obj.removeMap(cp); db.saveuserobject(ptr); chm.removeMap(cp); } break; case g_cs_chat: { // chatting (normal), second byte deside what kind Chat.chat((char*)&recdata[1], ptr); } break; case g_cs_chatglobal: { // chatting (normal), second byte deside what kind Chat.chat((char*)&recdata[1], ptr); } break; case g_cs_chatwhisper: { // chatting (whisper) Chat.whisper((char*)&recdata[1], ptr); } break; case g_cs_chatcommandwho: { // chatting command (/who) Chat.who((char*)&recdata[1], ptr); } break; case g_cs_movecharacter: { // user is moving around... gs.Moving((char*)&recdata[1], ptr); } break; case g_cs_changeheading: { // change heading gs.newheading((char*)&recdata[1], ptr); } break; case g_cs_changedoorstatus: { wk.changedoorstatus((char*)&recdata[1]); } break; case g_cs_requestnpctalk: { np.request_npctalk(ptr, (char*)&recdata[1]); } break; case g_cs_requesthtmlaction: // request html (hypertext) action { np.requesthtmlaction(ptr, (char*)&recdata[1]); } break; case g_cs_requestattack: { // request attact target (target objid, target x, target y) Attack.requestAttack(ptr, (char*)&recdata[1]); } break; case g_cs_useskill: { gs.skilleffect((char*)&recdata[1], ptr, lengh); } break; //************************************* // Default Server Packets //************************************* case g_cs_disconnect: { // user is disconnecting, check (CloseCallback) for what we do in that case. string us = dblmap.getUsername(cp); char * username = strdup(us.c_str()); com.WriteDataStr(hdwnd, "%s is logging out.", username); } break; default: { Log2File(TRUE, "[ CX ] "); for(z=0;z lengh) PacketReceiver (ptr, (char *)&buff[lengh], size-lengh); }