/* * Copyright (C) 2005-2008 MaNGOS * * Copyright (C) 2008 Trinity * * 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 */ #include "Common.h" #include "ByteBuffer.h" #include "WorldPacket.h" #include "UpdateData.h" #include "Log.h" #include "Opcodes.h" #include "World.h" #include UpdateData::UpdateData() : m_blockCount(0) { } void UpdateData::AddOutOfRangeGUID(std::set& guids) { m_outOfRangeGUIDs.insert(guids.begin(),guids.end()); } void UpdateData::AddOutOfRangeGUID(const uint64 &guid) { m_outOfRangeGUIDs.insert(guid); } void UpdateData::AddUpdateBlock(const ByteBuffer &block) { m_data.append(block); ++m_blockCount; } void UpdateData::Compress(void* dst, uint32 *dst_size, void* src, int src_size) { z_stream c_stream; c_stream.zalloc = (alloc_func)0; c_stream.zfree = (free_func)0; c_stream.opaque = (voidpf)0; // default Z_BEST_SPEED (1) int z_res = deflateInit(&c_stream, sWorld.getConfig(CONFIG_COMPRESSION)); if (z_res != Z_OK) { sLog.outError("Can't compress update packet (zlib: deflateInit) Error code: %i (%s)",z_res,zError(z_res)); *dst_size = 0; return; } c_stream.next_out = (Bytef*)dst; c_stream.avail_out = *dst_size; c_stream.next_in = (Bytef*)src; c_stream.avail_in = (uInt)src_size; z_res = deflate(&c_stream, Z_NO_FLUSH); if (z_res != Z_OK) { sLog.outError("Can't compress update packet (zlib: deflate) Error code: %i (%s)",z_res,zError(z_res)); *dst_size = 0; return; } if (c_stream.avail_in != 0) { sLog.outError("Can't compress update packet (zlib: deflate not greedy)"); *dst_size = 0; return; } z_res = deflate(&c_stream, Z_FINISH); if (z_res != Z_STREAM_END) { sLog.outError("Can't compress update packet (zlib: deflate should report Z_STREAM_END instead %i (%s)",z_res,zError(z_res)); *dst_size = 0; return; } z_res = deflateEnd(&c_stream); if (z_res != Z_OK) { sLog.outError("Can't compress update packet (zlib: deflateEnd) Error code: %i (%s)",z_res,zError(z_res)); *dst_size = 0; return; } *dst_size = c_stream.total_out; } bool UpdateData::BuildPacket(WorldPacket *packet, bool hasTransport) { ByteBuffer buf(m_data.size() + 10 + m_outOfRangeGUIDs.size()*8); buf << (uint32) (!m_outOfRangeGUIDs.empty() ? m_blockCount + 1 : m_blockCount); buf << (uint8) (hasTransport ? 1 : 0); if(!m_outOfRangeGUIDs.empty()) { buf << (uint8) UPDATETYPE_OUT_OF_RANGE_OBJECTS; buf << (uint32) m_outOfRangeGUIDs.size(); for(std::set::const_iterator i = m_outOfRangeGUIDs.begin(); i != m_outOfRangeGUIDs.end(); i++) { //buf.appendPackGUID(*i); buf << (uint8)0xFF; buf << (uint64) *i; } } buf.append(m_data); packet->clear(); if (m_data.size() > 50 ) { uint32 destsize = buf.size() + buf.size()/10 + 16; packet->resize( destsize ); packet->put(0, (uint32)buf.size()); Compress(const_cast(packet->contents()) + sizeof(uint32), &destsize, (void*)buf.contents(), buf.size()); if (destsize == 0) return false; packet->resize( destsize + sizeof(uint32) ); packet->SetOpcode( SMSG_COMPRESSED_UPDATE_OBJECT ); } else { packet->append( buf ); packet->SetOpcode( SMSG_UPDATE_OBJECT ); } return true; } void UpdateData::Clear() { m_data.clear(); m_outOfRangeGUIDs.clear(); m_blockCount = 0; }