diff --git a/src/Client/DefScript/DefScript.cpp b/src/Client/DefScript/DefScript.cpp index bb22efb..7fd8bc1 100644 --- a/src/Client/DefScript/DefScript.cpp +++ b/src/Client/DefScript/DefScript.cpp @@ -259,7 +259,7 @@ bool DefScriptPackage::LoadScriptFromFile(std::string fn){ _UpdateOrCreateScriptByName(sn); curScript=Script[sn]; - DeleteScript(SN_ONLOAD); + DeleteScript(sn + SN_ONLOAD); while(!f.eof()) { @@ -354,13 +354,13 @@ bool DefScriptPackage::LoadScriptFromFile(std::string fn){ } else if(line=="onload") { - _UpdateOrCreateScriptByName(SN_ONLOAD); - curScript=Script[SN_ONLOAD]; + _UpdateOrCreateScriptByName(sn + SN_ONLOAD); + curScript=Script[sn + SN_ONLOAD]; } else if(line=="endonload" || line=="/onload") { - RunScript(SN_ONLOAD,NULL,sn); - DeleteScript(SN_ONLOAD); + RunScript(sn + SN_ONLOAD,NULL,sn); + DeleteScript(sn + SN_ONLOAD); curScript=Script[sn]; } else if(line=="cs" || line=="comments-start") @@ -1118,7 +1118,7 @@ DefReturnResult DefScriptPackage::Interpret(CmdSet& Set) // if nothing has been found its maybe an external script file to run result=RunScript(Set.cmd, &Set); if((!result.ok) /*&& Script[Set.cmd]->GetDebug()*/) - std::cout << "Could not execute script command '" << Set.cmd << "'\n"; + PRINT_ERROR("Could not execute script command '%s'",Set.cmd.c_str()); return result; diff --git a/src/Client/Realm/RealmSession.cpp b/src/Client/Realm/RealmSession.cpp index ce1decd..f4e9400 100644 --- a/src/Client/Realm/RealmSession.cpp +++ b/src/Client/Realm/RealmSession.cpp @@ -516,7 +516,7 @@ void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt) void RealmSession::_HandleLogonProof(ByteBuffer& pkt) { PseuGUI *gui = GetInstance()->GetGUI(); - logdebug("RealmSocket: Got AUTH_LOGON_PROOF [%u of %u bytes]",pkt.size(),26); + logdebug("RealmSocket: Got AUTH_LOGON_PROOF [%u of %u bytes]",pkt.size(),sizeof(sAuthLogonProof_S)); if(pkt.size() < 2) { logerror("AUTH_LOGON_PROOF: Recieved incorrect/unknown packet. Hexdump:"); @@ -561,7 +561,7 @@ void RealmSession::_HandleLogonProof(ByteBuffer& pkt) sAuthLogonProof_S lp; - pkt.read((uint8*)&lp, 26); // the compiler didnt like 'sizeof(sAuthLogonProof_S)', said it was 28 + pkt.read((uint8*)&lp, sizeof(sAuthLogonProof_S)); //printchex((char*)&lp, sizeof(sAuthLogonProof_S),true); if(!memcmp(lp.M2,this->_m2,20)) { diff --git a/src/Client/SCPDatabase.cpp b/src/Client/SCPDatabase.cpp index 34d86b6..6150868 100644 --- a/src/Client/SCPDatabase.cpp +++ b/src/Client/SCPDatabase.cpp @@ -200,6 +200,11 @@ uint32 SCPDatabaseMgr::AutoLoadFile(char *fn) continue; while(line.size() && (line[0]==' ' || line[0]=='\t')) line.erase(0,1); + if(line.size() < 2 || (line[0] == '/' && line[1] == '/')) + { + line.clear(); + continue; + } uint32 eq = line.find("="); if(eq != std::string::npos) { diff --git a/src/Client/World/CMSGConstructor.cpp b/src/Client/World/CMSGConstructor.cpp index bde505e..f43ac3c 100644 --- a/src/Client/World/CMSGConstructor.cpp +++ b/src/Client/World/CMSGConstructor.cpp @@ -192,5 +192,18 @@ void WorldSession::SendQueryCreature(uint32 entry, uint64 guid) SendWorldPacket(wp); } +void WorldSession::SendQueryGameobject(uint32 entry, uint64 guid) +{ + if(objmgr.GONonExistent(entry)) + { + logdebug("Skipped query of gameobject %u (was marked as nonexistent before)",entry); + return; + } + logdebug("Sending gameobject query, id=%u",entry); + WorldPacket wp(CMSG_GAMEOBJECT_QUERY,4+8); + wp << entry << guid; + SendWorldPacket(wp); +} + diff --git a/src/Client/World/CacheHandler.cpp b/src/Client/World/CacheHandler.cpp index f1d2964..3f85da0 100644 --- a/src/Client/World/CacheHandler.cpp +++ b/src/Client/World/CacheHandler.cpp @@ -13,6 +13,7 @@ // increase this number whenever you change something that makes old files unusable uint32 ITEMPROTOTYPES_CACHE_VERSION = 3; uint32 CREATURETEMPLATES_CACHE_VERSION = 0; +uint32 GOTEMPLATES_CACHE_VERSION = 0; PlayerNameCache::~PlayerNameCache() { @@ -528,3 +529,113 @@ void CreatureTemplateCache_WriteDataToCache(WorldSession *session) fh.close(); log("CreatureTemplateCache: Saved %u Creature Templates",counter); } + +void GOTemplateCache_InsertDataToSession(WorldSession *session) +{ + logdetail("GOTemplateCache: Loading..."); + char* fn = "./cache/GOTemplates.cache"; + std::fstream fh; + fh.open(fn, std::ios_base::in | std::ios_base::binary); + if(!fh) + { + logerror("GOTemplateCache: Could not open file '%s'!",fn); + return; + } + + uint32 cacheversion, total, counter = 0; + + try + { + + fh.read((char*)&cacheversion,4); + if(cacheversion != GOTEMPLATES_CACHE_VERSION) + { + logerror("GOTemplateCache is outdated! Creating new cache."); + fh.close(); + return; + } + fh.read((char*)&total,4); + logdetail("GOTemplateCache: %u gameobject templates stored",total); + + uint32 datasize; + ByteBuffer buf; + for(uint32 i = 0; i < total && !fh.eof(); i++) + { + buf.clear(); + fh.read((char*)&datasize,sizeof(uint32)); + buf.resize(datasize); + fh.read((char*)buf.contents(),datasize); + GameobjectTemplate *go = new GameobjectTemplate(); + buf >> go->entry; + buf >> go->type; + buf >> go->displayId; + buf >> go->name; + buf >> go->castBarCaption; + buf >> go->faction; + buf >> go->flags; + buf >> go->size; + for(uint32 i = 0; i < GAMEOBJECT_DATA_FIELDS; i++) + buf >> go->raw.data[i]; + + if(go->entry) + { + session->objmgr.Add(go); + counter++; + } else + delete go; + } + + } + catch (ByteBufferException bbe) + { + logerror("ByteBuffer exception: attempt to \"%s\" %u bytes at position %u out of total %u bytes. (wpos=%u)", + bbe.action, bbe.readsize, bbe.rpos, bbe.cursize, bbe.wpos); + } + + fh.close(); + logdetail("GOTemplateCache: Loaded %u Gameobject Templates",counter); +} + +void GOTemplateCache_WriteDataToCache(WorldSession *session) +{ + if (!session->objmgr.GetGOTemplateCount()) + return; + + char* fn = "./cache/GOTemplates.cache"; + std::fstream fh; + fh.open(fn, std::ios_base::out | std::ios_base::binary); + if(!fh) + { + logerror("GOTemplateCache: Could not write to file '%s'!",fn); + return; + } + uint32 total = session->objmgr.GetGOTemplateCount(); + fh.write((char*)&GOTEMPLATES_CACHE_VERSION,4); + fh.write((char*)&total,4); + uint32 counter=0; + ByteBuffer buf; + for(GOTemplateMap::iterator it = session->objmgr.GetGOTemplateStorage()->begin(); it != session->objmgr.GetGOTemplateStorage()->end(); it++) + { + buf.clear(); + GameobjectTemplate *go = new GameobjectTemplate(); + buf << go->entry; + buf << go->type; + buf << go->displayId; + buf << go->name; + buf << go->castBarCaption; + buf << go->faction; + buf << go->flags; + buf << go->size; + for(uint32 i = 0; i < GAMEOBJECT_DATA_FIELDS; i++) + buf << go->raw.data[i]; + + uint32 size = buf.size(); + fh.write((char*)&size,sizeof(uint32)); + fh.write((char*)buf.contents(),buf.size()); + counter++; + } + fh.flush(); + fh.close(); + log("GOTemplateCache: Saved %u Gameobject Templates",counter); +} + diff --git a/src/Client/World/CacheHandler.h b/src/Client/World/CacheHandler.h index 8bb11e4..3ae5e9c 100644 --- a/src/Client/World/CacheHandler.h +++ b/src/Client/World/CacheHandler.h @@ -28,4 +28,7 @@ void ItemProtoCache_WriteDataToCache(WorldSession *session); void CreatureTemplateCache_InsertDataToSession(WorldSession *session); void CreatureTemplateCache_WriteDataToCache(WorldSession *session); +void GOTemplateCache_InsertDataToSession(WorldSession *session); +void GOTemplateCache_WriteDataToCache(WorldSession *session); + #endif diff --git a/src/Client/World/GameObject.h b/src/Client/World/GameObject.h index 7b5af61..b4d5bfc 100644 --- a/src/Client/World/GameObject.h +++ b/src/Client/World/GameObject.h @@ -3,6 +3,149 @@ #include "Object.h" +#define GAMEOBJECT_DATA_FIELDS 24 + +struct GameobjectTemplate +{ + uint32 entry; + uint32 type; + uint32 displayId; + std::string name; + std::string castBarCaption; + uint32 faction; + uint32 flags; + float size; + union // different GO types have different data field + { + //0 GAMEOBJECT_TYPE_DOOR + struct + { + uint32 _data0; + uint32 lockId; //1 + uint16 _data2lo; //2 lower part of data2, unknown + uint16 autoCloseTime; //2 (unit16) + } door; + //1 GAMEOBJECT_TYPE_BUTTON + struct + { + uint32 _data0; + uint32 lockId; //1 + uint16 _data2lo; //2 lower part of data2, unknown + uint16 autoCloseTime; //2 (unit16) + uint32 _data3; + uint32 isBattlegroundObject; //4 + } button; + //3 GAMEOBJECT_TYPE_CHEST + struct + { + uint32 lockId; //0 + uint32 lootId; //1 + uint32 _data2[2]; + uint32 minSuccessOpens; //4 + uint32 maxSuccessOpens; //5 + uint32 eventId; //6 + uint32 linkedTrapId; //7 + uint32 questId; //8 not used currently but store quest required for GO activation for player + uint32 _data9[5]; + uint32 _data14; //14 something == trap.data12 == goober.data14 (openText?) + } chest; + //6 GAMEOBJECT_TYPE_TRAP + struct + { + uint32 _data0; //0 lockid??? + uint32 _data1; + uint32 radius; //2 radius for trap activation + uint32 spellId; //3 + uint32 isNeedDespawn; //4 (if >0) + uint32 _data5; //5 + uint32 _data6[6]; + uint32 _data12; //12 something == chest.data14 == goober.data14 (openText?) + } trap; + //7 GAMEOBJECT_TYPE_CHAIR + struct + { + uint32 slots; //0 not used currently + uint32 height; //1 + } chair; + //8 GAMEOBJECT_TYPE_SPELL_FOCUS + struct + { + uint32 focusId; //0 + uint32 dist; //1 + uint32 linkedTrapId; //2 + } spellFocus; + //10 GAMEOBJECT_TYPE_GOOBER + struct + { + uint32 _data0; //0 lockid ??? + uint32 questId; //1 + uint32 eventId; //2 + uint32 _data3[4]; + uint32 pageId; //7 + uint32 _data8[2]; + uint32 spellId; //10 + uint32 _data11; + uint32 linkedTrapId; //12 + uint32 _data13; + uint32 _data14; //14 something == trap.data12 == chest.data14 (openText?) + uint32 _data15; + uint32 isBattlegroundObject; //16 + } goober; + //13 GAMEOBJECT_TYPE_CAMERA + struct + { + uint32 _data0; + uint32 cinematicId; //1 + } camera; + //15 GAMEOBJECT_TYPE_MO_TRANSPORT + struct + { + uint32 taxiPathId; //0 + } moTransport; + //17 GAMEOBJECT_TYPE_FISHINGNODE + struct + { + uint32 _data0; + uint32 lootId; //1 + } fishnode; + //18 GAMEOBJECT_TYPE_SUMMONING_RITUAL + struct + { + uint32 reqParticipants; //0 + uint32 spellId; //1 + } summoningRitual; + //22 GAMEOBJECT_TYPE_SPELLCASTER + struct + { + uint32 spellId; //0 + uint32 charges; //1 + uint32 partyOnly; //2 + uint32 spellId2; //3 (is it used in this way?) + } spellcaster; + //23 GAMEOBJECT_TYPE_MEETINGSTONE + struct + { + uint32 minLevel; //0 + uint32 maxLevel; //1 + } meetingstone; + //25 GAMEOBJECT_TYPE_FISHINGHOLE // not implemented yet + struct + { + uint32 radius; //0 how close bobber must land for sending loot + uint32 lootId; //1 + uint32 minSuccessOpens; //2 + uint32 maxSuccessOpens; //3 + uint32 lockId; //4 possibly 1628 for all? + } fishinghole; + + // not use for specific field access (only for output with loop by all filed), also this determinate max union size + struct // GAMEOBJECT_TYPE_SPELLCASTER + { + uint32 data[GAMEOBJECT_DATA_FIELDS]; + } raw; + }; +}; + class GameObject : public WorldObject { public: diff --git a/src/Client/World/ObjMgr.cpp b/src/Client/World/ObjMgr.cpp index 2969525..39f5afb 100644 --- a/src/Client/World/ObjMgr.cpp +++ b/src/Client/World/ObjMgr.cpp @@ -30,6 +30,10 @@ void ObjMgr::RemoveAll(void) { delete i->second; } + for(GOTemplateMap::iterator i = _go_templ.begin(); i!=_go_templ.end(); i++) + { + delete i->second; + } while(_obj.size()) { Remove(_obj.begin()->first, true); @@ -179,6 +183,31 @@ bool ObjMgr::CreatureNonExistent(uint32 id) return _nocreature.find(id) != _nocreature.end(); } +// -- Gameobject part -- + +void ObjMgr::Add(GameobjectTemplate *go) +{ + _go_templ[go->entry] = go; +} + +GameobjectTemplate *ObjMgr::GetGOTemplate(uint32 entry) +{ + GOTemplateMap::iterator it = _go_templ.find(entry); + if(it != _go_templ.end()) + return it->second; + return NULL; +} + +void ObjMgr::AddNonexistentGO(uint32 id) +{ + _nogameobj.insert(id); +} + +bool ObjMgr::GONonExistent(uint32 id) +{ + return _nogameobj.find(id) != _nogameobj.end(); +} + // -- misc part -- void ObjMgr::AddRequestedPlayerGUID(uint32 loguid) diff --git a/src/Client/World/ObjMgr.h b/src/Client/World/ObjMgr.h index a892e64..0b9f0df 100644 --- a/src/Client/World/ObjMgr.h +++ b/src/Client/World/ObjMgr.h @@ -5,9 +5,11 @@ #include #include "Item.h" #include "Unit.h" +#include "Gameobject.h" typedef std::map ItemProtoMap; typedef std::map CreatureTemplateMap; +typedef std::map GOTemplateMap; typedef std::map ObjectMap; class PseuInstance; @@ -40,6 +42,16 @@ public: void AddNonexistentCreature(uint32); bool CreatureNonExistent(uint32); + // Gameobject template functions + uint32 GetGOTemplateCount(void) { return _go_templ.size(); } + GameobjectTemplate *GetGOTemplate(uint32); + void Add(GameobjectTemplate*); + GOTemplateMap *GetGOTemplateStorage(void) { return &_go_templ; } + + // nonexistent gameobjects handler + void AddNonexistentGO(uint32); + bool GONonExistent(uint32); + // player names related void AddRequestedPlayerGUID(uint32); bool IsRequestedPlayerGUID(uint32); @@ -58,10 +70,13 @@ public: private: ItemProtoMap _iproto; CreatureTemplateMap _creature_templ; + GOTemplateMap _go_templ; + ObjectMap _obj; std::set _noitem; std::set _reqpnames; std::set _nocreature; + std::set _nogameobj; PseuInstance *_instance; }; diff --git a/src/Client/World/UpdateData.cpp b/src/Client/World/UpdateData.cpp index 3719db6..13fa168 100644 --- a/src/Client/World/UpdateData.cpp +++ b/src/Client/World/UpdateData.cpp @@ -468,6 +468,15 @@ void WorldSession::_QueryObjectInfo(uint64 guid) SendQueryCreature(obj->GetEntry(),guid); break; } + case TYPEID_GAMEOBJECT: + { + GameobjectTemplate *go = objmgr.GetGOTemplate(obj->GetEntry()); + if(go) + obj->SetName(go->name); + else + SendQueryGameobject(obj->GetEntry(),guid); + break; + } //case... } } diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index f843217..812a887 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -315,6 +315,7 @@ OpcodeHandler *WorldSession::_GetOpcodeHandlerTable() const {SMSG_NOTIFICATION, &WorldSession::_HandleNotificationOpcode}, {SMSG_WHO, &WorldSession::_HandleWhoOpcode}, {SMSG_CREATURE_QUERY_RESPONSE, &WorldSession::_HandleCreatureQueryResponseOpcode}, + {SMSG_GAMEOBJECT_QUERY_RESPONSE, &WorldSession::_HandleGameobjectQueryResponseOpcode}, // table termination { 0, NULL } @@ -700,9 +701,11 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) recvPacket >> target_guid >> msglen >> msg; SCPDatabase *langdb = GetDBMgr().GetDB("language"); - const char* ln = ""; + const char* ln; + std::string langname; if(langdb) - langdb->GetString(lang,"name"); + langname = langdb->GetString(lang,"name"); + ln = langname.c_str(); std::string name; if(type == CHAT_MSG_MONSTER_SAY) @@ -747,7 +750,7 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) { logcustom(0,WHITE,"CHAT: %s yells [%s]: %s ",name.c_str(),ln,msg.c_str()); } - else if (type==CHAT_MSG_WHISPER_INFORM ) + else if (type==CHAT_MSG_REPLY ) { logcustom(0,WHITE,"TO %s [%s]: %s",name.c_str(),ln,msg.c_str()); } @@ -1249,6 +1252,7 @@ void WorldSession::_HandleLoginVerifyWorldOpcode(WorldPacket& recvPacket) // update the world as soon as the server confirmed that we are where we are. _world->UpdatePos(x,y,m); _world->Update(); + _world->CreateMoveMgr(); // temp. solution to test terrain rendering if(PseuGUI *gui = GetInstance()->GetGUI()) @@ -1371,6 +1375,43 @@ void WorldSession::_HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket) objmgr.AssignNameToObj(entry, TYPEID_UNIT, ct->name); } +void WorldSession::_HandleGameobjectQueryResponseOpcode(WorldPacket& recvPacket) +{ + uint32 entry; + recvPacket >> entry; + if(entry & 0x80000000) + { + uint32 real_entry = entry & ~0x80000000; + logerror("Gameobject %u does not exist!"); + objmgr.AddNonexistentGO(real_entry); + return; + } + + std::string other_names, unks; + + GameobjectTemplate *go = new GameobjectTemplate(); + go->entry = entry; + recvPacket >> go->type; + recvPacket >> go->displayId; + recvPacket >> go->name; + recvPacket >> other_names; // name1 + recvPacket >> other_names; // name2 + recvPacket >> other_names; // name3 (all unused) + recvPacket >> unks; + recvPacket >> go->castBarCaption; + recvPacket >> unks; + for(uint32 i = 0; i < GAMEOBJECT_DATA_FIELDS; i++) + recvPacket >> go->raw.data[i]; + + std::stringstream ss; + ss << "Got info for gameobject " << entry << ":" << go->name; + ss << " type " << go->type; + ss << " displayid " << go->displayId; + logdetail("%s",ss.str().c_str()); + + objmgr.Add(go); + objmgr.AssignNameToObj(entry, TYPEID_GAMEOBJECT, go->name); +} // TODO: delete world on LogoutComplete once implemented diff --git a/src/Client/World/WorldSession.h b/src/Client/World/WorldSession.h index 0878e81..f9a894a 100644 --- a/src/Client/World/WorldSession.h +++ b/src/Client/World/WorldSession.h @@ -85,6 +85,7 @@ public: void SendCastSpell(uint32 spellid, bool nocheck=false); void SendWhoListRequest(uint32 minlvl=0, uint32 maxlvl=100, uint32 racemask=-1, uint32 classmask=-1, std::string name="", std::string guildname="", std::vector *zonelist=NULL, std::vector *strlist=NULL); void SendQueryCreature(uint32 entry, uint64 guid = 0); + void SendQueryGameobject(uint32 entry, uint64 guid = 0); void HandleWorldPacket(WorldPacket*); @@ -139,6 +140,7 @@ private: void _HandleNotificationOpcode(WorldPacket& recvPacket); void _HandleWhoOpcode(WorldPacket& recvPacket); void _HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket); + void _HandleGameobjectQueryResponseOpcode(WorldPacket& recvPacket); // helper functions to keep SMSG_(COMPRESSED_)UPDATE_OBJECT easy to handle void _MovementUpdate(uint8 objtypeid, uint64 guid, WorldPacket& recvPacket); // Helper for _HandleUpdateObjectOpcode