diff --git a/Minecraft.World/AbstractContainerMenu.cpp b/Minecraft.World/AbstractContainerMenu.cpp index 93eb4372..6e00be6d 100644 --- a/Minecraft.World/AbstractContainerMenu.cpp +++ b/Minecraft.World/AbstractContainerMenu.cpp @@ -552,12 +552,13 @@ bool AbstractContainerMenu::isPauseScreen() void AbstractContainerMenu::setItem(unsigned int slot, shared_ptr item) { + if (slot >= slots->size()) return; getSlot(slot)->set(item); } void AbstractContainerMenu::setAll(ItemInstanceArray *items) { - for (unsigned int i = 0; i < items->length; i++) + for (unsigned int i = 0; i < items->length && i < slots->size(); i++) { getSlot(i)->set( (*items)[i] ); } diff --git a/Minecraft.World/AwardStatPacket.cpp b/Minecraft.World/AwardStatPacket.cpp index b1e3d9e4..6e856a53 100644 --- a/Minecraft.World/AwardStatPacket.cpp +++ b/Minecraft.World/AwardStatPacket.cpp @@ -47,7 +47,7 @@ void AwardStatPacket::read(DataInputStream *dis) //throws IOException // Read parameter blob. int length = dis->readInt(); - if(length > 0) + if(length > 0 && length <= 65536) { m_paramData = byteArray(length); dis->readFully(m_paramData); diff --git a/Minecraft.World/BlockRegionUpdatePacket.cpp b/Minecraft.World/BlockRegionUpdatePacket.cpp index 441501d6..6aee1e49 100644 --- a/Minecraft.World/BlockRegionUpdatePacket.cpp +++ b/Minecraft.World/BlockRegionUpdatePacket.cpp @@ -103,6 +103,12 @@ void BlockRegionUpdatePacket::read(DataInputStream *dis) //throws IOException levelIdx = ( size >> 30 ) & 3; size &= 0x3fffffff; + const int MAX_COMPRESSED_CHUNK_SIZE = 5 * 1024 * 1024; + if(size < 0 || size > MAX_COMPRESSED_CHUNK_SIZE) + { + size = 0; + } + if(size == 0) { buffer = byteArray(); @@ -131,7 +137,10 @@ void BlockRegionUpdatePacket::read(DataInputStream *dis) //throws IOException delete [] compressedBuffer.data; - assert(buffer.length == outputSize); + if(buffer.length != outputSize) + { + app.DebugPrintf("BlockRegionUpdatePacket: decompressed size mismatch (expected %d, got %d)\n", buffer.length, outputSize); + } } } diff --git a/Minecraft.World/ByteArrayInputStream.cpp b/Minecraft.World/ByteArrayInputStream.cpp index 3fd24933..21322183 100644 --- a/Minecraft.World/ByteArrayInputStream.cpp +++ b/Minecraft.World/ByteArrayInputStream.cpp @@ -9,12 +9,17 @@ //buf - the input buffer. //offset - the offset in the buffer of the first byte to read. //length - the maximum number of bytes to read from the buffer. -ByteArrayInputStream::ByteArrayInputStream(byteArray buf, unsigned int offset, unsigned int length) - : pos( offset ), count( min( offset+length, buf.length ) ), mark( offset ) -{ - this->buf = buf; +ByteArrayInputStream::ByteArrayInputStream(byteArray buf, unsigned int offset, unsigned int length) + : pos( offset ), mark( offset ) +{ + if( offset > buf.length ) + count = buf.length; + else if( length > buf.length - offset ) + count = buf.length; + else + count = offset + length; + this->buf = buf; } - //Creates a ByteArrayInputStream so that it uses buf as its buffer array. The buffer array is not copied. //The initial value of pos is 0 and the initial value of count is the length of buf. //Parameters: diff --git a/Minecraft.World/ByteArrayOutputStream.cpp b/Minecraft.World/ByteArrayOutputStream.cpp index 5d971031..cf06f8ff 100644 --- a/Minecraft.World/ByteArrayOutputStream.cpp +++ b/Minecraft.World/ByteArrayOutputStream.cpp @@ -49,18 +49,27 @@ void ByteArrayOutputStream::write(byteArray b) //b - the data. //off - the start offset in the data. //len - the number of bytes to write. -void ByteArrayOutputStream::write(byteArray b, unsigned int offset, unsigned int length) -{ - assert( b.length >= offset + length ); - - // If we will fill the buffer we need to make it bigger - if( count + length >= buf.length ) - buf.resize( max( count + length + 1, buf.length * 2 ) ); - - XMemCpy( &buf[count], &b[offset], length ); - //std::copy( b->data+offset, b->data+offset+length, buf->data + count ); // Or this instead? - - count += length; +void ByteArrayOutputStream::write(byteArray b, unsigned int offset, unsigned int length) +{ + + if (offset > b.length || length > b.length - offset) + return; + + if (length > 0xFFFFFFFF - count) + return; + + // If we will fill the buffer we need to make it bigger + if( count + length >= buf.length ) + { + unsigned int newSize = (std::max)( count + length + 1, buf.length * 2 ); + if( newSize <= buf.length ) + return; + buf.resize( newSize ); + } + + XMemCpy( &buf[count], &b[offset], length ); + + count += length; } //Closing a ByteArrayOutputStream has no effect. diff --git a/Minecraft.World/ByteArrayTag.h b/Minecraft.World/ByteArrayTag.h index 7ecc88f4..6b797845 100644 --- a/Minecraft.World/ByteArrayTag.h +++ b/Minecraft.World/ByteArrayTag.h @@ -18,13 +18,14 @@ public: dos->write(data); } - void load(DataInput *dis, int tagDepth) - { - int length = dis->readInt(); - - if ( data.data ) delete[] data.data; - data = byteArray(length); - dis->readFully(data); + void load(DataInput *dis) + { + int length = dis->readInt(); + if (length < 0 || length > 2 * 1024 * 1024) length = 0; + + if ( data.data ) delete[] data.data; + data = byteArray(length); + dis->readFully(data); } byte getId() { return TAG_Byte_Array; } diff --git a/Minecraft.World/C4JThread.cpp b/Minecraft.World/C4JThread.cpp index f7cf8a89..0b4c315c 100644 --- a/Minecraft.World/C4JThread.cpp +++ b/Minecraft.World/C4JThread.cpp @@ -112,6 +112,7 @@ C4JThread::C4JThread( C4JThreadStartFunc* startFunc, void* param, const char* th m_threadID = sceKernelCreateThread(m_threadName, entryPoint, g_DefaultPriority, m_stackSize, 0, CPU, NULL); app.DebugPrintf("***************************** start thread %s **************************\n", m_threadName); #else + m_completionFlag = new Event(Event::e_modeManualClear); m_threadID = 0; m_threadHandle = 0; m_threadHandle = CreateThread(NULL, m_stackSize, entryPoint, this, CREATE_SUSPENDED, &m_threadID); @@ -160,6 +161,7 @@ C4JThread::C4JThread( const char* mainThreadName) // sceKernelChangeThreadPriority(m_threadID, g_DefaultPriority + 1); g_DefaultCPU = SCE_KERNEL_CPU_MASK_USER_ALL;//sceKernelGetThreadCpuAffinityMask(m_threadID); #else + m_completionFlag = new Event(Event::e_modeManualClear); m_threadID = GetCurrentThreadId(); m_threadHandle = GetCurrentThread(); #endif @@ -173,9 +175,7 @@ C4JThread::C4JThread( const char* mainThreadName) C4JThread::~C4JThread() { -#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ delete m_completionFlag; -#endif #if defined __ORBIS__ scePthreadJoin(m_threadID, NULL); @@ -243,6 +243,7 @@ DWORD WINAPI C4JThread::entryPoint(LPVOID lpParam) C4JThread* pThread = (C4JThread*)lpParam; SetThreadName(-1, pThread->m_threadName); pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam); + pThread->m_completionFlag->Set(); pThread->m_isRunning = false; return pThread->m_exitCode; } @@ -388,7 +389,7 @@ DWORD C4JThread::WaitForCompletion( int timeoutMs ) // return m_exitCode; #else - return WaitForSingleObject(m_threadHandle, timeoutMs); + return m_completionFlag->WaitForSignal(timeoutMs); #endif // __PS3__ } diff --git a/Minecraft.World/ComplexItemDataPacket.cpp b/Minecraft.World/ComplexItemDataPacket.cpp index fdb6e122..4740f0a0 100644 --- a/Minecraft.World/ComplexItemDataPacket.cpp +++ b/Minecraft.World/ComplexItemDataPacket.cpp @@ -27,13 +27,15 @@ ComplexItemDataPacket::ComplexItemDataPacket(short itemType, short itemId, charA memcpy(this->data.data, data.data, data.length); } -void ComplexItemDataPacket::read(DataInputStream *dis) //throws IOException -{ - itemType = dis->readShort(); - itemId = dis->readShort(); - - data = charArray(dis->readUnsignedShort() & 0xffff); - dis->readFully(data); +void ComplexItemDataPacket::read(DataInputStream *dis) //throws IOException +{ + itemType = dis->readShort(); + itemId = dis->readShort(); + + int dataLength = dis->readShort() & 0xffff; + if(dataLength > 32767) dataLength = 0; + data = charArray(dataLength); + dis->readFully(data); } void ComplexItemDataPacket::write(DataOutputStream *dos) //throws IOException diff --git a/Minecraft.World/Connection.cpp b/Minecraft.World/Connection.cpp index 32c706ed..740d0eda 100644 --- a/Minecraft.World/Connection.cpp +++ b/Minecraft.World/Connection.cpp @@ -29,6 +29,7 @@ void Connection::_init() running = true; quitting = false; disconnected = false; + m_closeState = 0; disconnectReason = DisconnectPacket::eDisconnect_None; noInputTicks = 0; estimatedRemaining = 0; @@ -43,14 +44,21 @@ void Connection::_init() } // 4J Jev, need to delete the critical section. -Connection::~Connection() -{ - // 4J Stu - Just to be sure, make sure the read and write threads terminate themselves before the connection object is destroyed - running = false; - if( dis ) dis->close(); // The input stream needs closed before the readThread, or the readThread - // may get stuck whilst blocking waiting on a read - readThread->WaitForCompletion(INFINITE); - writeThread->WaitForCompletion(INFINITE); +Connection::~Connection() +{ + LONG closeState = InterlockedCompareExchange(&m_closeState, 1, 0); + if (closeState == 0) + { + shutdownConnectionResources(); + InterlockedExchange(&m_closeState, 2); + } + else if (closeState == 1) + { + while (InterlockedCompareExchange(&m_closeState, 2, 2) != 2) + { + Sleep(0); + } + } DeleteCriticalSection(&writeLock); DeleteCriticalSection(&threadCounterLock); @@ -74,6 +82,37 @@ Connection::~Connection() dis = NULL; } +void Connection::shutdownConnectionResources() +{ + running = false; + if( dis ) dis->close(); + + if( readThread ) readThread->WaitForCompletion(INFINITE); + if( writeThread ) writeThread->WaitForCompletion(INFINITE); + + delete dis; + dis = NULL; + if( bufferedDos ) + { + bufferedDos->close(); + bufferedDos->deleteChildStream(); + delete bufferedDos; + bufferedDos = NULL; + } + if( byteArrayDos ) + { + byteArrayDos->close(); + delete byteArrayDos; + byteArrayDos = NULL; + } + if( socket ) + { + socket->close(packetListener != NULL ? packetListener->isServerPacketListener() : false); + socket = NULL; + } +} + + Connection::Connection(Socket *socket, const wstring& id, PacketListener *packetListener) // throws IOException { _init(); @@ -108,8 +147,8 @@ Connection::Connection(Socket *socket, const wstring& id, PacketListener *packet const char *szId = wstringtofilename(id); char readThreadName[256]; char writeThreadName[256]; - sprintf(readThreadName,"%s read\n",szId); - sprintf(writeThreadName,"%s write\n",szId); + sprintf_s(readThreadName, sizeof(readThreadName), "%.240s read\n", szId); + sprintf_s(writeThreadName, sizeof(writeThreadName), "%.240s write\n", szId); readThread = new C4JThread(runRead, (void*)this, readThreadName, READ_STACK_SIZE); writeThread = new C4JThread(runWrite, this, writeThreadName, WRITE_STACK_SIZE); @@ -364,80 +403,38 @@ close("disconnect.genericReason", "Internal exception: " + e.toString()); }*/ -void Connection::close(DisconnectPacket::eDisconnectReason reason, ...) -{ -// printf("Con:0x%x close\n",this); - if (!running) return; -// printf("Con:0x%x close doing something\n",this); - disconnected = true; - - va_list input; - va_start( input, reason ); - - disconnectReason = reason;//va_arg( input, const wstring ); - - vector objs = vector(); - void *i = NULL; - while (i != NULL) - { - i = va_arg( input, void* ); - objs.push_back(i); - } - - if( objs.size() ) - { - disconnectReasonObjects = &objs[0]; - } - else - { - disconnectReasonObjects = NULL; - } - - // int count = 0, sum = 0, i = first; - // va_list marker; - // - // va_start( marker, first ); - // while( i != -1 ) - // { - // sum += i; - // count++; - // i = va_arg( marker, int); - // } - // va_end( marker ); - // return( sum ? (sum / count) : 0 ); - - -// CreateThread(NULL, 0, runClose, this, 0, &closeThreadID); - - running = false; - - if( dis ) dis->close(); // The input stream needs closed before the readThread, or the readThread - // may get stuck whilst blocking waiting on a read - - // Make sure that the read & write threads are dead before we go and kill the streams that they depend on - readThread->WaitForCompletion(INFINITE); - writeThread->WaitForCompletion(INFINITE); - - delete dis; - dis = NULL; - if( bufferedDos ) - { - bufferedDos->close(); - bufferedDos->deleteChildStream(); - delete bufferedDos; - bufferedDos = NULL; - } - if( byteArrayDos ) - { - byteArrayDos->close(); - delete byteArrayDos; - byteArrayDos = NULL; - } - if( socket ) - { - socket->close(packetListener->isServerPacketListener()); - socket = NULL; - } +void Connection::close(DisconnectPacket::eDisconnectReason reason, ...) +{ +// printf("Con:0x%x close\n",this); + if (InterlockedCompareExchange(&m_closeState, 1, 0) != 0) return; +// printf("Con:0x%x close doing something\n",this); + disconnected = true; + + va_list input; + va_start( input, reason ); + + disconnectReason = reason; + disconnectReasonObjects = NULL; + va_end(input); + + // int count = 0, sum = 0, i = first; + // va_list marker; + // + // va_start( marker, first ); + // while( i != -1 ) + // { + // sum += i; + // count++; + // i = va_arg( marker, int); + // } + // va_end( marker ); + // return( sum ? (sum / count) : 0 ); + + +// CreateThread(NULL, 0, runClose, this, 0, &closeThreadID); + + shutdownConnectionResources(); + InterlockedExchange(&m_closeState, 2); } void Connection::tick() @@ -500,6 +497,11 @@ void Connection::tick() // MGH - moved the packet handling outside of the incoming_cs block, as it was locking up sometimes when disconnecting for(int i=0; igetId()); packetsToHandle[i]->handle(packetListener); PIXEndNamedEvent(); diff --git a/Minecraft.World/Connection.h b/Minecraft.World/Connection.h index afcb6056..28be82a0 100644 --- a/Minecraft.World/Connection.h +++ b/Minecraft.World/Connection.h @@ -49,6 +49,7 @@ private: DataOutputStream *byteArrayDos; // 4J This dos allows us to write individual packets to the socket ByteArrayOutputStream *baos; Socket::SocketOutputStream *sos; + volatile LONG m_closeState; bool running; @@ -87,6 +88,7 @@ public: private: void _init(); + void shutdownConnectionResources(); // 4J Jev, these might be better of as private CRITICAL_SECTION threadCounterLock; diff --git a/Minecraft.World/ConsoleSaveFileOriginal.cpp b/Minecraft.World/ConsoleSaveFileOriginal.cpp index d3e734e1..4399439a 100644 --- a/Minecraft.World/ConsoleSaveFileOriginal.cpp +++ b/Minecraft.World/ConsoleSaveFileOriginal.cpp @@ -213,7 +213,7 @@ ConsoleSaveFileOriginal::~ConsoleSaveFileOriginal() VirtualFree( pvHeap, MAX_PAGE_COUNT * CSF_PAGE_SIZE, MEM_DECOMMIT ); pagesCommitted = 0; // Make sure we don't have any thumbnail data still waiting round - we can't need it now we've destroyed the save file anyway -#if defined _XBOX +#if defined _XBOX || defined _WINDOWS64 app.GetSaveThumbnail(NULL,NULL); #elif defined __PS3__ app.GetSaveThumbnail(NULL,NULL, NULL,NULL); @@ -749,7 +749,7 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail ) PBYTE pbDataSaveImage=NULL; DWORD dwDataSizeSaveImage=0; -#if ( defined _XBOX || defined _DURANGO ) +#if ( defined _XBOX || defined _DURANGO || defined _WINDOWS64 ) app.GetSaveThumbnail(&pbThumbnailData,&dwThumbnailDataSize); #elif ( defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ ) app.GetSaveThumbnail(&pbThumbnailData,&dwThumbnailDataSize,&pbDataSaveImage,&dwDataSizeSaveImage); @@ -819,7 +819,8 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail ) int ConsoleSaveFileOriginal::SaveSaveDataCallback(LPVOID lpParam,bool bRes) { - ConsoleSaveFile *pClass=(ConsoleSaveFile *)lpParam; + (void)lpParam; + (void)bRes; return 0; } diff --git a/Minecraft.World/ConsoleSaveFileSplit.cpp b/Minecraft.World/ConsoleSaveFileSplit.cpp index 87983a02..2cee2e40 100644 --- a/Minecraft.World/ConsoleSaveFileSplit.cpp +++ b/Minecraft.World/ConsoleSaveFileSplit.cpp @@ -586,7 +586,7 @@ ConsoleSaveFileSplit::~ConsoleSaveFileSplit() VirtualFree( pvHeap, MAX_PAGE_COUNT * CSF_PAGE_SIZE, MEM_DECOMMIT ); pagesCommitted = 0; // Make sure we don't have any thumbnail data still waiting round - we can't need it now we've destroyed the save file anyway -#if defined _XBOX +#if defined _XBOX || defined _WINDOWS64 app.GetSaveThumbnail(NULL,NULL); #elif defined __PS3__ app.GetSaveThumbnail(NULL,NULL, NULL,NULL); @@ -1412,7 +1412,7 @@ void ConsoleSaveFileSplit::Flush(bool autosave, bool updateThumbnail) PBYTE pbDataSaveImage=NULL; DWORD dwDataSizeSaveImage=0; -#if ( defined _XBOX || defined _DURANGO ) +#if ( defined _XBOX || defined _DURANGO || defined _WINDOWS64 ) app.GetSaveThumbnail(&pbThumbnailData,&dwThumbnailDataSize); #elif ( defined __PS3__ || defined __ORBIS__ ) app.GetSaveThumbnail(&pbThumbnailData,&dwThumbnailDataSize,&pbDataSaveImage,&dwDataSizeSaveImage); diff --git a/Minecraft.World/ContainerSetContentPacket.cpp b/Minecraft.World/ContainerSetContentPacket.cpp index 9fb2df06..fd2ab8c5 100644 --- a/Minecraft.World/ContainerSetContentPacket.cpp +++ b/Minecraft.World/ContainerSetContentPacket.cpp @@ -32,6 +32,9 @@ void ContainerSetContentPacket::read(DataInputStream *dis) //throws IOException { containerId = dis->readByte(); int count = dis->readShort(); + + if(count < 0 || count > 256) count = 0; + items = ItemInstanceArray(count); for (int i = 0; i < count; i++) { diff --git a/Minecraft.World/ContainerSetSlotPacket.cpp b/Minecraft.World/ContainerSetSlotPacket.cpp index 39b25112..da98a8dc 100644 --- a/Minecraft.World/ContainerSetSlotPacket.cpp +++ b/Minecraft.World/ContainerSetSlotPacket.cpp @@ -35,7 +35,7 @@ void ContainerSetSlotPacket::read(DataInputStream *dis) //throws IOException // 4J Stu - TU-1 hotfix // Fix for #13142 - Holding down the A button on the furnace ingredient slot causes the UI to display incorrect item counts BYTE byteId = dis->readByte(); - containerId = *(char *)&byteId; + containerId = (char)(signed char)byteId; slot = dis->readShort(); item = readItem(dis); } diff --git a/Minecraft.World/CustomPayloadPacket.cpp b/Minecraft.World/CustomPayloadPacket.cpp index 7d108d11..43c213eb 100644 --- a/Minecraft.World/CustomPayloadPacket.cpp +++ b/Minecraft.World/CustomPayloadPacket.cpp @@ -43,7 +43,7 @@ void CustomPayloadPacket::read(DataInputStream *dis) identifier = readUtf(dis, 20); length = dis->readShort(); - if (length > 0 && length < Short::MAX_VALUE) + if (length > 0 && length <= Short::MAX_VALUE) { if(data.data != NULL) { diff --git a/Minecraft.World/DataInputStream.cpp b/Minecraft.World/DataInputStream.cpp index b1c5a77c..45ced2d0 100644 --- a/Minecraft.World/DataInputStream.cpp +++ b/Minecraft.World/DataInputStream.cpp @@ -303,6 +303,10 @@ wstring DataInputStream::readUTF() int b = stream->read(); unsigned short UTFLength = (unsigned short) (((a & 0xff) << 8) | (b & 0xff)); + const unsigned short MAX_UTF_LENGTH = 32767; + if( UTFLength > MAX_UTF_LENGTH ) + return outputString; + //// 4J Stu - I decided while writing DataOutputStream that we didn't need to bother using the UTF8 format //// used in the java libs, and just write in/out as wchar_t all the time diff --git a/Minecraft.World/DirectoryLevelStorage.cpp b/Minecraft.World/DirectoryLevelStorage.cpp index ecea1087..c01fc9e5 100644 --- a/Minecraft.World/DirectoryLevelStorage.cpp +++ b/Minecraft.World/DirectoryLevelStorage.cpp @@ -432,6 +432,27 @@ void DirectoryLevelStorage::save(shared_ptr player) CompoundTag *DirectoryLevelStorage::load(shared_ptr player) { CompoundTag *tag = loadPlayerDataTag( player->getXuid() ); +#ifdef _WINDOWS64 + if (tag == NULL) + { + const PlayerUID WIN64_XUID_BASE = (PlayerUID)0xe000d45248242f2e; + for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++) + { + PlayerUID oldXuid = WIN64_XUID_BASE + i; + tag = loadPlayerDataTag(oldXuid); + if (tag != NULL) + { + ConsoleSavePath oldFile = ConsoleSavePath(playerDir.getName() + _toString(oldXuid) + L".dat"); + if (m_saveFile->doesFileExist(oldFile)) + { + m_saveFile->deleteFile(m_saveFile->createFile(oldFile)); + } + app.DebugPrintf("Migrated player data from old XUID %llu to new XUID %llu\n", oldXuid, player->getXuid()); + break; + } + } + } +#endif if (tag != NULL) { player->load(tag); diff --git a/Minecraft.World/DisconnectPacket.h b/Minecraft.World/DisconnectPacket.h index 7672f349..7c88ec01 100644 --- a/Minecraft.World/DisconnectPacket.h +++ b/Minecraft.World/DisconnectPacket.h @@ -50,6 +50,11 @@ public: #ifdef _XBOX_ONE eDisconnect_ExitedGame, #endif + + eDisconnect_NotWhitelisted = 100, + eDisconnect_ServerBanned, + eDisconnect_IPBanned, + eDisconnect_InvalidUsername, }; // 4J Stu - The reason was a string, but we need to send a non-locale specific reason diff --git a/Minecraft.World/EnchantmentMenu.cpp b/Minecraft.World/EnchantmentMenu.cpp index 3d1c94c3..214ddb8d 100644 --- a/Minecraft.World/EnchantmentMenu.cpp +++ b/Minecraft.World/EnchantmentMenu.cpp @@ -152,6 +152,7 @@ void EnchantmentMenu::slotsChanged() // 4J used to take a shared_ptr bool EnchantmentMenu::clickMenuButton(shared_ptr player, int i) { + if (i < 0 || i >= 3) return false; shared_ptr item = enchantSlots->getItem(0); if (costs[i] > 0 && item != NULL && (player->experienceLevel >= costs[i] || player->abilities.instabuild) ) { diff --git a/Minecraft.World/ExplodePacket.cpp b/Minecraft.World/ExplodePacket.cpp index edcd755c..1b87d1d8 100644 --- a/Minecraft.World/ExplodePacket.cpp +++ b/Minecraft.World/ExplodePacket.cpp @@ -56,6 +56,8 @@ void ExplodePacket::read(DataInputStream *dis) //throws IOException r = dis->readFloat(); int count = dis->readInt(); + if(count < 0 || count > 32768) count = 0; + int xp = (int)x; int yp = (int)y; int zp = (int)z; diff --git a/Minecraft.World/GameCommandPacket.cpp b/Minecraft.World/GameCommandPacket.cpp index 37b207d7..0bf54624 100644 --- a/Minecraft.World/GameCommandPacket.cpp +++ b/Minecraft.World/GameCommandPacket.cpp @@ -40,7 +40,7 @@ void GameCommandPacket::read(DataInputStream *dis) command = (EGameCommand)dis->readInt(); length = dis->readShort(); - if (length > 0 && length < Short::MAX_VALUE) + if (length > 0 && length <= Short::MAX_VALUE) { if(data.data != NULL) { diff --git a/Minecraft.World/Hasher.cpp b/Minecraft.World/Hasher.cpp index 63c9f432..beb7e2af 100644 --- a/Minecraft.World/Hasher.cpp +++ b/Minecraft.World/Hasher.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include +#include #include "Hasher.h" @@ -19,7 +20,11 @@ wstring Hasher::getHash(wstring &name) //return new BigInteger(1, m.digest()).toString(16); // TODO 4J Stu - Will this hash us with the same distribution as the MD5? - return _toString( hash_value( s ) ); +#if !defined(_MSC_VER) || _MSC_VER >= 1900 + return _toString( std::hash{}( s ) ); +#else + return _toString( stdext::hash_value( s ) ); +#endif //} //catch (NoSuchAlgorithmException e) //{ diff --git a/Minecraft.World/I18n.cpp b/Minecraft.World/I18n.cpp index e7a70016..75923032 100644 --- a/Minecraft.World/I18n.cpp +++ b/Minecraft.World/I18n.cpp @@ -7,6 +7,8 @@ wstring I18n::get(const wstring& id, ...) { #ifdef __PSVITA__ // 4J - vita doesn't like having a reference type as the last parameter passed to va_start - we shouldn't need this method anyway return L""; +#elif _MSC_VER >= 1930 // VS2022+ also disallows va_start with reference types + return id; #else va_list va; va_start(va, id); diff --git a/Minecraft.World/IntArrayTag.h b/Minecraft.World/IntArrayTag.h index 808b9894..74dc341a 100644 --- a/Minecraft.World/IntArrayTag.h +++ b/Minecraft.World/IntArrayTag.h @@ -35,6 +35,7 @@ public: void load(DataInput *dis, int tagDepth) { int length = dis->readInt(); + if (length < 0 || length > 65536) length = 0; if ( data.data ) delete[] data.data; data = intArray(length); diff --git a/Minecraft.World/Inventory.cpp b/Minecraft.World/Inventory.cpp index c53f57c5..ce92879f 100644 --- a/Minecraft.World/Inventory.cpp +++ b/Minecraft.World/Inventory.cpp @@ -143,9 +143,6 @@ void Inventory::grabTexture(int id, int data, bool checkData, bool mayReplace) void Inventory::swapPaint(int wheel) { - if (wheel > 0) wheel = 1; - if (wheel < 0) wheel = -1; - selected -= wheel; while (selected < 0) diff --git a/Minecraft.World/Language.cpp b/Minecraft.World/Language.cpp index ec974698..7fbe995a 100644 --- a/Minecraft.World/Language.cpp +++ b/Minecraft.World/Language.cpp @@ -24,6 +24,8 @@ wstring Language::getElement(const wstring& elementId, ...) { #ifdef __PSVITA__ // 4J - vita doesn't like having a reference type as the last parameter passed to va_start - we shouldn't need this method anyway return L""; +#elif _MSC_VER >= 1930 // VS2022+ also disallows va_start with reference types + return elementId; #else va_list args; va_start(args, elementId); diff --git a/Minecraft.World/Level.cpp b/Minecraft.World/Level.cpp index ec087554..475754c6 100644 --- a/Minecraft.World/Level.cpp +++ b/Minecraft.World/Level.cpp @@ -1951,7 +1951,8 @@ AABBList *Level::getCubes(shared_ptr source, AABB *box, bool noEntities/ // 4J - now add in collision for any blocks which have actually been removed, but haven't had their render data updated to reflect this yet. This is to stop the player // being able to move the view position inside a tile which is (visually) still there, and see out of the world. This is particularly a problem when moving upwards in // creative mode as the player can get very close to the edge of tiles whilst looking upwards and can therefore very quickly move inside one. - Minecraft::GetInstance()->levelRenderer->destroyedTileManager->addAABBs( this, box, &boxes); + if(Minecraft::GetInstance()->levelRenderer != NULL) + Minecraft::GetInstance()->levelRenderer->destroyedTileManager->addAABBs( this, box, &boxes); // 4J - added if( noEntities ) return &boxes; diff --git a/Minecraft.World/ListTag.h b/Minecraft.World/ListTag.h index 888ca3ad..59277d4e 100644 --- a/Minecraft.World/ListTag.h +++ b/Minecraft.World/ListTag.h @@ -37,11 +37,13 @@ public: } type = dis->readByte(); int size = dis->readInt(); + if (size < 0 || size > 10000) size = 0; list.clear(); for (int i = 0; i < size; i++) { Tag *tag = Tag::newTag(type, L""); + if (tag == NULL) break; tag->load(dis, tagDepth); list.push_back(tag); } @@ -58,7 +60,7 @@ public: void print(char *prefix, ostream out) { - Tag::print(prefix, out); + Tag::print(out); out << prefix << "{" << endl; @@ -67,7 +69,7 @@ public: strcat( newPrefix, " "); AUTO_VAR(itEnd, list.end()); for (AUTO_VAR(it, list.begin()); it != itEnd; it++) - (*it)->print(newPrefix, out); + (*it)->print(out); delete[] newPrefix; out << prefix << "}" << endl; } diff --git a/Minecraft.World/McRegionChunkStorage.cpp b/Minecraft.World/McRegionChunkStorage.cpp index 465ba826..415bda94 100644 --- a/Minecraft.World/McRegionChunkStorage.cpp +++ b/Minecraft.World/McRegionChunkStorage.cpp @@ -14,6 +14,7 @@ C4JThread *McRegionChunkStorage::s_saveThreads[3]; McRegionChunkStorage::McRegionChunkStorage(ConsoleSaveFile *saveFile, const wstring &prefix) : m_prefix( prefix ) { m_saveFile = saveFile; + InitializeCriticalSectionAndSpinCount(&m_csEntityData, 4000); // Make sure that if there are any files for regions to be created, that they are created in the order that suits us for making the initial level save work fast if( prefix == L"" ) @@ -68,6 +69,7 @@ McRegionChunkStorage::~McRegionChunkStorage() { delete it->second.data; } + DeleteCriticalSection(&m_csEntityData); } LevelChunk *McRegionChunkStorage::load(Level *level, int x, int z) @@ -80,12 +82,14 @@ LevelChunk *McRegionChunkStorage::load(Level *level, int x, int z) { __int64 index = ((__int64)(x) << 32) | (((__int64)(z))&0x00000000FFFFFFFF); + EnterCriticalSection(&m_csEntityData); AUTO_VAR(it, m_entityData.find(index)); if(it != m_entityData.end()) { delete it->second.data; m_entityData.erase(it); } + LeaveCriticalSection(&m_csEntityData); } #endif @@ -244,11 +248,12 @@ void McRegionChunkStorage::saveEntities(Level *level, LevelChunk *levelChunk) PIXBeginNamedEvent(0,"Saving entities"); __int64 index = ((__int64)(levelChunk->x) << 32) | (((__int64)(levelChunk->z))&0x00000000FFFFFFFF); - delete m_entityData[index].data; - CompoundTag *newTag = new CompoundTag(); bool savedEntities = OldChunkStorage::saveEntities(levelChunk, level, newTag); + EnterCriticalSection(&m_csEntityData); + delete m_entityData[index].data; + if(savedEntities) { ByteArrayOutputStream bos; @@ -268,6 +273,7 @@ void McRegionChunkStorage::saveEntities(Level *level, LevelChunk *levelChunk) m_entityData.erase(it); } } + LeaveCriticalSection(&m_csEntityData); delete newTag; PIXEndNamedEvent(); #endif @@ -278,16 +284,22 @@ void McRegionChunkStorage::loadEntities(Level *level, LevelChunk *levelChunk) #ifdef SPLIT_SAVES __int64 index = ((__int64)(levelChunk->x) << 32) | (((__int64)(levelChunk->z))&0x00000000FFFFFFFF); + EnterCriticalSection(&m_csEntityData); AUTO_VAR(it, m_entityData.find(index)); if(it != m_entityData.end()) { ByteArrayInputStream bais(it->second); DataInputStream dis(&bais); CompoundTag *tag = NbtIo::read(&dis); + LeaveCriticalSection(&m_csEntityData); OldChunkStorage::loadEntities(levelChunk, level, tag); bais.reset(); delete tag; } + else + { + LeaveCriticalSection(&m_csEntityData); + } #endif } @@ -306,6 +318,7 @@ void McRegionChunkStorage::flush() DataOutputStream dos(&bos); PIXBeginNamedEvent(0,"Writing to stream"); + EnterCriticalSection(&m_csEntityData); dos.writeInt(m_entityData.size()); for(AUTO_VAR(it,m_entityData.begin()); it != m_entityData.end(); ++it) @@ -313,6 +326,7 @@ void McRegionChunkStorage::flush() dos.writeLong(it->first); dos.write(it->second,0,it->second.length); } + LeaveCriticalSection(&m_csEntityData); bos.flush(); PIXEndNamedEvent(); PIXEndNamedEvent(); diff --git a/Minecraft.World/McRegionChunkStorage.h b/Minecraft.World/McRegionChunkStorage.h index ed305b60..e3fbd5e9 100644 --- a/Minecraft.World/McRegionChunkStorage.h +++ b/Minecraft.World/McRegionChunkStorage.h @@ -17,6 +17,7 @@ private: static CRITICAL_SECTION cs_memory; unordered_map<__int64, byteArray> m_entityData; + CRITICAL_SECTION m_csEntityData; static std::deque s_chunkDataQueue; static int s_runningThreadCount; diff --git a/Minecraft.World/MobSpawner.cpp b/Minecraft.World/MobSpawner.cpp index d969bb58..4614dd3d 100644 --- a/Minecraft.World/MobSpawner.cpp +++ b/Minecraft.World/MobSpawner.cpp @@ -32,13 +32,6 @@ TilePos MobSpawner::getRandomPosWithin(Level *level, int cx, int cz) return TilePos(x, y, z); } -#ifdef __PSVITA__ - // AP - See CustomMap.h for an explanation of this - CustomMap MobSpawner::chunksToPoll; -#else - unordered_map MobSpawner::chunksToPoll; -#endif - const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies, bool spawnPersistent) { #ifndef _CONTENT_PACKAGE @@ -99,7 +92,12 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie return 0; } MemSect(20); - chunksToPoll.clear(); +#ifdef __PSVITA__ + // AP - See CustomMap.h for an explanation of this + CustomMap MobSpawner::chunksToPoll; +#else + unordered_map chunksToPoll; +#endif #if 0 AUTO_VAR(itEnd, level->players.end()); diff --git a/Minecraft.World/MobSpawner.h b/Minecraft.World/MobSpawner.h index 594f5f02..d5730633 100644 --- a/Minecraft.World/MobSpawner.h +++ b/Minecraft.World/MobSpawner.h @@ -17,14 +17,6 @@ private: protected: static TilePos getRandomPosWithin(Level *level, int cx, int cz); -private: -#ifdef __PSVITA__ - // AP - See CustomMap.h for an explanation of this - static CustomMap chunksToPoll; -#else - static unordered_map chunksToPoll; -#endif - public: static const int tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies, bool spawnPersistent); static bool isSpawnPositionOk(MobCategory *category, Level *level, int x, int y, int z); diff --git a/Minecraft.World/OldChunkStorage.cpp b/Minecraft.World/OldChunkStorage.cpp index bb87e39d..acfaecc3 100644 --- a/Minecraft.World/OldChunkStorage.cpp +++ b/Minecraft.World/OldChunkStorage.cpp @@ -476,29 +476,28 @@ LevelChunk *OldChunkStorage::load(Level *level, DataInputStream *dis) CompoundTag *tag = NbtIo::read(dis); - loadEntities(levelChunk, level, tag); - - if (tag->contains(L"TileTicks")) - { - PIXBeginNamedEvent(0,"Loading TileTicks"); - ListTag *tileTicks = (ListTag *) tag->getList(L"TileTicks"); - - if (tileTicks != NULL) - { - for (int i = 0; i < tileTicks->size(); i++) - { - CompoundTag *teTag = tileTicks->get(i); - - level->forceAddTileTick(teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), teTag->getInt(L"t"), teTag->getInt(L"p")); - } - } - PIXEndNamedEvent(); - } - - delete tag; - - PIXEndNamedEvent(); - + if (tag != NULL) + { + loadEntities(levelChunk, level, tag); + + if (tag->contains(L"TileTicks")) + { + ListTag *tileTicks = (ListTag *) tag->getList(L"TileTicks"); + + if (tileTicks != NULL) + { + for (int i = 0; i < tileTicks->size(); i++) + { + CompoundTag *teTag = tileTicks->get(i); + + level->forceAddTileTick(teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), teTag->getInt(L"t")); + } + } + } + + delete tag; + } + return levelChunk; } diff --git a/Minecraft.World/Packet.cpp b/Minecraft.World/Packet.cpp index a58ebe6e..ae7098bf 100644 --- a/Minecraft.World/Packet.cpp +++ b/Minecraft.World/Packet.cpp @@ -265,10 +265,11 @@ void Packet::updatePacketStatsPIX() #endif } -shared_ptr Packet::getPacket(int id) -{ - // 4J: Removed try/catch - return idToCreateMap[id](); +shared_ptr Packet::getPacket(int id) +{ + auto it = idToCreateMap.find(id); + if (it == idToCreateMap.end()) return nullptr; + return it->second(); } void Packet::writeBytes(DataOutputStream *dataoutputstream, byteArray bytes) diff --git a/Minecraft.World/Player.cpp b/Minecraft.World/Player.cpp index 804fa149..f725c05b 100644 --- a/Minecraft.World/Player.cpp +++ b/Minecraft.World/Player.cpp @@ -2706,14 +2706,16 @@ int Player::getTexture() } } -int Player::hash_fnct(const shared_ptr k) -{ - // TODO 4J Stu - Should we just be using the pointers and hashing them? -#ifdef __PS3__ - return (int)boost::hash_value( k->name ); // 4J Stu - Names are completely unique? -#else - return (int)std::hash_value( k->name ); // 4J Stu - Names are completely unique? -#endif //__PS3__ +int Player::hash_fnct(const shared_ptr k) +{ + // TODO 4J Stu - Should we just be using the pointers and hashing them? +#ifdef __PS3__ + return (int)boost::hash_value( k->name ); // 4J Stu - Names are completely unique? +#elif !defined(_MSC_VER) || _MSC_VER >= 1900 + return (int)std::hash{}( k->name ); // 4J Stu - Names are completely unique? +#else + return (int)stdext::hash_value( k->name ); // 4J Stu - Names are completely unique? +#endif } bool Player::eq_test(const shared_ptr x, const shared_ptr y) diff --git a/Minecraft.World/PotionBrewing.cpp b/Minecraft.World/PotionBrewing.cpp index 4c091d12..e7cb6ba1 100644 --- a/Minecraft.World/PotionBrewing.cpp +++ b/Minecraft.World/PotionBrewing.cpp @@ -180,11 +180,39 @@ int PotionBrewing::getAppearanceValue(int brew) return valueOf(brew, 5, 4, 3, 2, 1); } +static unsigned int GetFallbackPotionColour(eMinecraftColour id) +{ + switch (id) + { + case eMinecraftColour_Potion_BaseColour: return 0x385DC6; + case eMinecraftColour_Effect_MovementSpeed: return 0x7CAFC6; + case eMinecraftColour_Effect_MovementSlowDown: return 0x5A6C81; + case eMinecraftColour_Effect_DigSpeed: return 0xD9C043; + case eMinecraftColour_Effect_DigSlowdown: return 0x4A4217; + case eMinecraftColour_Effect_DamageBoost: return 0x932423; + case eMinecraftColour_Effect_Heal: return 0xF82423; + case eMinecraftColour_Effect_Harm: return 0x430A09; + case eMinecraftColour_Effect_Jump: return 0x786297; + case eMinecraftColour_Effect_Confusion: return 0x551D4A; + case eMinecraftColour_Effect_Regeneration: return 0xCD5CAB; + case eMinecraftColour_Effect_DamageResistance: return 0x99453A; + case eMinecraftColour_Effect_FireResistance: return 0xE49A3A; + case eMinecraftColour_Effect_WaterBreathing: return 0x2E5299; + case eMinecraftColour_Effect_Invisiblity: return 0x7F8392; + case eMinecraftColour_Effect_Blindness: return 0x1F1F23; + case eMinecraftColour_Effect_NightVision: return 0x1F1FA1; + case eMinecraftColour_Effect_Hunger: return 0x587653; + case eMinecraftColour_Effect_Weakness: return 0x484D48; + case eMinecraftColour_Effect_Poison: return 0x4E9331; + default: return 0xFFFFFF; + } +} + int PotionBrewing::getColorValue(vector *effects) { ColourTable *colourTable = Minecraft::GetInstance()->getColourTable(); - int baseColor = colourTable->getColor( eMinecraftColour_Potion_BaseColour ); + int baseColor = colourTable != NULL ? colourTable->getColor(eMinecraftColour_Potion_BaseColour) : GetFallbackPotionColour(eMinecraftColour_Potion_BaseColour); if (effects == NULL || effects->empty()) { @@ -200,7 +228,8 @@ int PotionBrewing::getColorValue(vector *effects) for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it) { MobEffectInstance *effect = *it; - int potionColor = colourTable->getColor( MobEffect::effects[effect->getId()]->getColor() ); + eMinecraftColour effectColorId = MobEffect::effects[effect->getId()]->getColor(); + int potionColor = colourTable != NULL ? colourTable->getColor(effectColorId) : GetFallbackPotionColour(effectColorId); for (int potency = 0; potency <= effect->getAmplifier(); potency++) { diff --git a/Minecraft.World/PreLoginPacket.cpp b/Minecraft.World/PreLoginPacket.cpp index 8ce838e0..b357e5a0 100644 --- a/Minecraft.World/PreLoginPacket.cpp +++ b/Minecraft.World/PreLoginPacket.cpp @@ -62,6 +62,7 @@ void PreLoginPacket::read(DataInputStream *dis) //throws IOException m_friendsOnlyBits = dis->readByte(); m_ugcPlayersVersion = dis->readInt(); m_dwPlayerCount = dis->readByte(); + if( m_dwPlayerCount > MINECRAFT_NET_MAX_PLAYERS ) m_dwPlayerCount = MINECRAFT_NET_MAX_PLAYERS; if( m_dwPlayerCount > 0 ) { m_playerXuids = new PlayerUID[m_dwPlayerCount]; @@ -74,6 +75,7 @@ void PreLoginPacket::read(DataInputStream *dis) //throws IOException { m_szUniqueSaveName[i]=dis->readByte(); } + m_szUniqueSaveName[m_iSaveNameLen - 1] = 0; m_serverSettings = dis->readInt(); m_hostIndex = dis->readByte(); diff --git a/Minecraft.World/RandomLevelSource.cpp b/Minecraft.World/RandomLevelSource.cpp index 9c24e4b3..51954be9 100644 --- a/Minecraft.World/RandomLevelSource.cpp +++ b/Minecraft.World/RandomLevelSource.cpp @@ -778,7 +778,7 @@ void RandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) mineShaftFeature->postProcess(level, pprandom, xt, zt); hasVillage = villageFeature->postProcess(level, pprandom, xt, zt); strongholdFeature->postProcess(level, pprandom, xt, zt); - scatteredFeature->postProcess(level, random, xt, zt); + scatteredFeature->postProcess(level, pprandom, xt, zt); } PIXEndNamedEvent(); diff --git a/Minecraft.World/Recipes.cpp b/Minecraft.World/Recipes.cpp index c7dac880..9369590a 100644 --- a/Minecraft.World/Recipes.cpp +++ b/Minecraft.World/Recipes.cpp @@ -1099,7 +1099,7 @@ ShapedRecipy *Recipes::addShapedRecipy(ItemInstance *result, ...) break; case L'c': - wchFrom=va_arg(vl,wchar_t); + wchFrom=(wchar_t)va_arg(vl,int); break; case L'z': pItemInstance=va_arg(vl,ItemInstance *); @@ -1116,7 +1116,7 @@ ShapedRecipy *Recipes::addShapedRecipy(ItemInstance *result, ...) mappings->insert(myMap::value_type(wchFrom,pItemInstance)); break; case L'g': - wchFrom=va_arg(vl,wchar_t); + wchFrom=(wchar_t)va_arg(vl,int); switch(wchFrom) { // case L'W': @@ -1214,7 +1214,7 @@ void Recipes::addShapelessRecipy(ItemInstance *result,... ) ingredients->push_back(new ItemInstance(pTile)); break; case L'g': - wchFrom=va_arg(vl,wchar_t); + wchFrom=(wchar_t)va_arg(vl,int); switch(wchFrom) { diff --git a/Minecraft.World/RegionFile.cpp b/Minecraft.World/RegionFile.cpp index 305337a8..26d12fb2 100644 --- a/Minecraft.World/RegionFile.cpp +++ b/Minecraft.World/RegionFile.cpp @@ -10,6 +10,7 @@ byteArray RegionFile::emptySector(SECTOR_BYTES); RegionFile::RegionFile(ConsoleSaveFile *saveFile, File *path) { + InitializeCriticalSectionAndSpinCount(&m_cs, 4000); _lastModified = 0; m_saveFile = saveFile; @@ -38,7 +39,12 @@ RegionFile::RegionFile(ConsoleSaveFile *saveFile, File *path) } */ - fileEntry = m_saveFile->createFile( fileName->getName() ); + wstring saveName = fileName->getPath(); + for (size_t i = 0; i < saveName.size(); i++) + { + if (saveName[i] == L'\\') saveName[i] = L'/'; + } + fileEntry = m_saveFile->createFile( ConsoleSavePath(saveName) ); m_saveFile->setFilePointer( fileEntry, 0, NULL, FILE_END ); if ( fileEntry->getFileSize() < SECTOR_BYTES) @@ -135,6 +141,8 @@ void RegionFile::writeAllOffsets() // used for the file ConsoleSaveFile conversi { if(m_bIsEmpty == false) { + EnterCriticalSection(&m_cs); + // save all the offsets and timestamps m_saveFile->LockSaveAccess(); @@ -147,6 +155,7 @@ void RegionFile::writeAllOffsets() // used for the file ConsoleSaveFile conversi m_saveFile->writeFile(fileEntry, chunkTimestamps, SECTOR_BYTES, &numberOfBytesWritten); m_saveFile->ReleaseSaveAccess(); + LeaveCriticalSection(&m_cs); } } @@ -156,6 +165,7 @@ RegionFile::~RegionFile() delete[] chunkTimestamps; delete sectorFree; m_saveFile->closeHandle( fileEntry ); + DeleteCriticalSection(&m_cs); } __int64 RegionFile::lastModified() @@ -165,8 +175,10 @@ __int64 RegionFile::lastModified() int RegionFile::getSizeDelta() // TODO - was synchronized { + EnterCriticalSection(&m_cs); int ret = sizeDelta; sizeDelta = 0; + LeaveCriticalSection(&m_cs); return ret; } @@ -178,12 +190,14 @@ DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was return NULL; } + EnterCriticalSection(&m_cs); // 4J - removed try/catch // try { int offset = getOffset(x, z); if (offset == 0) { // debugln("READ", x, z, "miss"); + LeaveCriticalSection(&m_cs); return NULL; } @@ -192,6 +206,7 @@ DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was if (sectorNumber + numSectors > sectorFree->size()) { + LeaveCriticalSection(&m_cs); // debugln("READ", x, z, "invalid sector"); return NULL; } @@ -227,7 +242,7 @@ DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was if (length > SECTOR_BYTES * numSectors) { // debugln("READ", x, z, "invalid length: " + length + " > 4096 * " + numSectors); - + LeaveCriticalSection(&m_cs); m_saveFile->ReleaseSaveAccess(); return NULL; } @@ -240,6 +255,7 @@ DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was m_saveFile->readFile(fileEntry,data,length,&numberOfBytesRead); m_saveFile->ReleaseSaveAccess(); + LeaveCriticalSection(&m_cs); Compression::getCompression()->SetDecompressionType(m_saveFile->getSavePlatform()); // if this save is from another platform, set the correct decompression type @@ -290,6 +306,7 @@ void RegionFile::write(int x, int z, byte *data, int length) // TODO - was sync return; } + EnterCriticalSection(&m_cs); m_saveFile->LockSaveAccess(); { int offset = getOffset(x, z); @@ -396,6 +413,7 @@ void RegionFile::write(int x, int z, byte *data, int length) // TODO - was sync setTimestamp(x, z, (int) (System::currentTimeMillis() / 1000L)); } m_saveFile->ReleaseSaveAccess(); + LeaveCriticalSection(&m_cs); // } catch (IOException e) { // e.printStackTrace(); diff --git a/Minecraft.World/RegionFile.h b/Minecraft.World/RegionFile.h index 0c803b2d..e981891d 100644 --- a/Minecraft.World/RegionFile.h +++ b/Minecraft.World/RegionFile.h @@ -33,6 +33,7 @@ private: int sizeDelta; __int64 _lastModified; bool m_bIsEmpty; // 4J added + CRITICAL_SECTION m_cs; public: RegionFile(ConsoleSaveFile *saveFile, File *path); diff --git a/Minecraft.World/RegionFileCache.cpp b/Minecraft.World/RegionFileCache.cpp index 6b88f4e0..06bd498a 100644 --- a/Minecraft.World/RegionFileCache.cpp +++ b/Minecraft.World/RegionFileCache.cpp @@ -38,6 +38,7 @@ RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wst } MemSect(0); + EnterCriticalSection(&m_cs); RegionFile *ref = NULL; AUTO_VAR(it, cache.find(file)); if( it != cache.end() ) @@ -46,6 +47,7 @@ RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wst // 4J Jev, put back in. if (ref != NULL) { + LeaveCriticalSection(&m_cs); return ref; } @@ -63,6 +65,7 @@ RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wst RegionFile *reg = new RegionFile(saveFile, &file); cache[file] = reg; // 4J - this was originally a softReferenc + LeaveCriticalSection(&m_cs); return reg; } @@ -85,6 +88,7 @@ void RegionFileCache::_clear() // 4J - TODO was synchronized // } } cache.clear(); + LeaveCriticalSection(&m_cs); } int RegionFileCache::_getSizeDelta(ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ) diff --git a/Minecraft.World/RegionFileCache.h b/Minecraft.World/RegionFileCache.h index 822e49c9..9361ca4f 100644 --- a/Minecraft.World/RegionFileCache.h +++ b/Minecraft.World/RegionFileCache.h @@ -10,13 +10,14 @@ private: static const int MAX_CACHE_SIZE = 256; unordered_map cache; + CRITICAL_SECTION m_cs; static RegionFileCache s_defaultCache; public: // Made public and non-static so we can have a cache for input and output files - RegionFileCache() {} - ~RegionFileCache(); + RegionFileCache() { InitializeCriticalSectionAndSpinCount(&m_cs, 4000); } + ~RegionFileCache() { DeleteCriticalSection(&m_cs); } RegionFile *_getRegionFile(ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ); // 4J - TODO was synchronized void _clear(); // 4J - TODO was synchronized diff --git a/Minecraft.World/RemoveEntitiesPacket.cpp b/Minecraft.World/RemoveEntitiesPacket.cpp index b6c75e18..d9afe528 100644 --- a/Minecraft.World/RemoveEntitiesPacket.cpp +++ b/Minecraft.World/RemoveEntitiesPacket.cpp @@ -19,13 +19,15 @@ RemoveEntitiesPacket::~RemoveEntitiesPacket() delete ids.data; } -void RemoveEntitiesPacket::read(DataInputStream *dis) //throws IOException -{ - ids = intArray(dis->readByte()); - for(unsigned int i = 0; i < ids.length; ++i) - { - ids[i] = dis->readInt(); - } +void RemoveEntitiesPacket::read(DataInputStream *dis) //throws IOException +{ + int count = dis->readByte(); + if(count < 0) count = 0; + ids = intArray(count); + for(unsigned int i = 0; i < ids.length; ++i) + { + ids[i] = dis->readInt(); + } } void RemoveEntitiesPacket::write(DataOutputStream *dos) //throws IOException diff --git a/Minecraft.World/Socket.cpp b/Minecraft.World/Socket.cpp index cecc030e..454ab068 100644 --- a/Minecraft.World/Socket.cpp +++ b/Minecraft.World/Socket.cpp @@ -138,6 +138,11 @@ void Socket::pushDataToQueue(const BYTE * pbData, DWORD dwDataSize, bool fromHos } EnterCriticalSection(&m_queueLockNetwork[queueIdx]); + if(m_queueNetwork[queueIdx].size() + dwDataSize > 2 * 1024 * 1024) + { + LeaveCriticalSection(&m_queueLockNetwork[queueIdx]); + return; + } for( unsigned int i = 0; i < dwDataSize; i++ ) { m_queueNetwork[queueIdx].push(*pbData++); diff --git a/Minecraft.World/SparseDataStorage.cpp b/Minecraft.World/SparseDataStorage.cpp index dc32a431..90c3426b 100644 --- a/Minecraft.World/SparseDataStorage.cpp +++ b/Minecraft.World/SparseDataStorage.cpp @@ -600,13 +600,14 @@ bool SparseDataStorage::isCompressed() } -void SparseDataStorage::write(DataOutputStream *dos) -{ - int count = ( dataAndCount >> 48 ) & 0xffff; - dos->writeInt(count); - unsigned char *dataPointer = (unsigned char *)(dataAndCount & 0x0000ffffffffffff); - byteArray wrapper(dataPointer, count * 128 + 128); - dos->write(wrapper); +void SparseDataStorage::write(DataOutputStream *dos) +{ + __int64 snapshot = dataAndCount; + int count = ( snapshot >> 48 ) & 0xffff; + dos->writeInt(count); + unsigned char *dataPointer = (unsigned char *)(snapshot & 0x0000ffffffffffff); + byteArray wrapper(dataPointer, count * 128 + 128); + dos->write(wrapper); } void SparseDataStorage::read(DataInputStream *dis) diff --git a/Minecraft.World/SparseLightStorage.cpp b/Minecraft.World/SparseLightStorage.cpp index 8b848520..4897e625 100644 --- a/Minecraft.World/SparseLightStorage.cpp +++ b/Minecraft.World/SparseLightStorage.cpp @@ -617,13 +617,14 @@ bool SparseLightStorage::isCompressed() } -void SparseLightStorage::write(DataOutputStream *dos) -{ - int count = ( dataAndCount >> 48 ) & 0xffff; - dos->writeInt(count); - unsigned char *dataPointer = (unsigned char *)(dataAndCount & 0x0000ffffffffffff); - byteArray wrapper(dataPointer, count * 128 + 128); - dos->write(wrapper); +void SparseLightStorage::write(DataOutputStream *dos) +{ + __int64 snapshot = dataAndCount; + int count = ( snapshot >> 48 ) & 0xffff; + dos->writeInt(count); + unsigned char *dataPointer = (unsigned char *)(snapshot & 0x0000ffffffffffff); + byteArray wrapper(dataPointer, count * 128 + 128); + dos->write(wrapper); } void SparseLightStorage::read(DataInputStream *dis) diff --git a/Minecraft.World/StructureFeature.cpp b/Minecraft.World/StructureFeature.cpp index ab4e37db..d2d9e22b 100644 --- a/Minecraft.World/StructureFeature.cpp +++ b/Minecraft.World/StructureFeature.cpp @@ -9,6 +9,7 @@ StructureFeature::StructureFeature() { + InitializeCriticalSectionAndSpinCount(&m_csCachedStructures, 4000); #ifdef ENABLE_STRUCTURE_SAVING savedData = nullptr; #endif @@ -16,10 +17,13 @@ StructureFeature::StructureFeature() StructureFeature::~StructureFeature() { + EnterCriticalSection(&m_csCachedStructures); for( AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); it++ ) { delete it->second; } + LeaveCriticalSection(&m_csCachedStructures); + DeleteCriticalSection(&m_csCachedStructures); } void StructureFeature::addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks) @@ -30,10 +34,13 @@ void StructureFeature::addFeature(Level *level, int x, int z, int xOffs, int zOf restoreSavedData(level); + EnterCriticalSection(&m_csCachedStructures); if (cachedStructures.find(ChunkPos::hashCode(x, z)) != cachedStructures.end()) { + LeaveCriticalSection(&m_csCachedStructures); return; } + LeaveCriticalSection(&m_csCachedStructures); // clear random key random->nextInt(); @@ -41,8 +48,10 @@ void StructureFeature::addFeature(Level *level, int x, int z, int xOffs, int zOf if (isFeatureChunk(x, z,level->getLevelData()->getGenerator() == LevelType::lvl_flat)) { StructureStart *start = createStructureStart(x, z); + EnterCriticalSection(&m_csCachedStructures); cachedStructures[ChunkPos::hashCode(x, z)] = start; saveFeature(x, z, start); + LeaveCriticalSection(&m_csCachedStructures); } } @@ -58,6 +67,7 @@ bool StructureFeature::postProcess(Level *level, Random *random, int chunkX, int int cz = (chunkZ << 4); // + 8; bool intersection = false; + EnterCriticalSection(&m_csCachedStructures); for( AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); it++ ) { StructureStart *structureStart = it->second; @@ -76,6 +86,7 @@ bool StructureFeature::postProcess(Level *level, Random *random, int chunkX, int } } } + LeaveCriticalSection(&m_csCachedStructures); return intersection; } @@ -84,6 +95,7 @@ bool StructureFeature::isIntersection(int cellX, int cellZ) { restoreSavedData(level); + EnterCriticalSection(&m_csCachedStructures); for( AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); it++ ) { StructureStart *structureStart = it->second; @@ -97,12 +109,14 @@ bool StructureFeature::isIntersection(int cellX, int cellZ) StructurePiece *next = *it2++; if (next->getBoundingBox()->intersects(cellX, cellZ, cellX, cellZ)) { + LeaveCriticalSection(&m_csCachedStructures); return true; } } } } } + LeaveCriticalSection(&m_csCachedStructures); return false; } @@ -115,6 +129,7 @@ bool StructureFeature::isInsideFeature(int cellX, int cellY, int cellZ) StructureStart *StructureFeature::getStructureAt(int cellX, int cellY, int cellZ) { //for (StructureStart structureStart : cachedStructures.values()) + EnterCriticalSection(&m_csCachedStructures); for(AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); ++it) { StructureStart *pStructureStart = it->second; @@ -138,12 +153,14 @@ StructureStart *StructureFeature::getStructureAt(int cellX, int cellY, int cellZ StructurePiece* piece = *it2; if ( piece->getBoundingBox()->isInside(cellX, cellY, cellZ) ) { + LeaveCriticalSection(&m_csCachedStructures); return pStructureStart; } } } } } + LeaveCriticalSection(&m_csCachedStructures); return NULL; } @@ -182,6 +199,7 @@ TilePos *StructureFeature::getNearestGeneratedFeature(Level *level, int cellX, i double minDistance = DBL_MAX; TilePos *selected = NULL; + EnterCriticalSection(&m_csCachedStructures); for(AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); ++it) { StructureStart *pStructureStart = it->second; @@ -205,6 +223,7 @@ TilePos *StructureFeature::getNearestGeneratedFeature(Level *level, int cellX, i } } } + LeaveCriticalSection(&m_csCachedStructures); if (selected != NULL) { return selected; diff --git a/Minecraft.World/StructureFeature.h b/Minecraft.World/StructureFeature.h index 5159343a..16e246cb 100644 --- a/Minecraft.World/StructureFeature.h +++ b/Minecraft.World/StructureFeature.h @@ -27,6 +27,7 @@ private: protected: unordered_map<__int64, StructureStart *> cachedStructures; + CRITICAL_SECTION m_csCachedStructures; public: StructureFeature(); diff --git a/Minecraft.World/SynchedEntityData.cpp b/Minecraft.World/SynchedEntityData.cpp index 8ffda5d8..cd5110e9 100644 --- a/Minecraft.World/SynchedEntityData.cpp +++ b/Minecraft.World/SynchedEntityData.cpp @@ -343,8 +343,10 @@ vector > *SynchedEntityData::unpack(Data vector > *result = NULL; int currentHeader = input->readByte(); + int itemCount = 0; + const int MAX_ENTITY_DATA_ITEMS = 256; - while (currentHeader != EOF_MARKER) + while (currentHeader != EOF_MARKER && itemCount < MAX_ENTITY_DATA_ITEMS) { if (result == NULL) @@ -399,6 +401,7 @@ vector > *SynchedEntityData::unpack(Data break; } result->push_back(item); + itemCount++; currentHeader = input->readByte(); } diff --git a/Minecraft.World/Tag.cpp b/Minecraft.World/Tag.cpp index 0051368d..2cd9c229 100644 --- a/Minecraft.World/Tag.cpp +++ b/Minecraft.World/Tag.cpp @@ -79,32 +79,44 @@ Tag *Tag::setName(const wstring& name) Tag *Tag::readNamedTag(DataInput *dis) { - return readNamedTag(dis,0); -} + static __declspec(thread) int depth = 0; + static __declspec(thread) int totalTagCount = 0; -Tag *Tag::readNamedTag(DataInput *dis, int tagDepth) -{ - byte type = dis->readByte(); - if (type == 0) return new EndTag(); + if (depth == 0) + totalTagCount = 0; - // 4J Stu - readByte can return -1, so if it's that then also mark as the end tag - if(type == 255) + depth++; + + if (depth > 256) { - app.DebugPrintf("readNamedTag read a type of 255\n"); -#ifndef _CONTENT_PACKAGE - __debugbreak(); -#endif + depth--; return new EndTag(); } - wstring name = dis->readUTF();//new String(bytes, "UTF-8"); + totalTagCount++; + const int MAX_TOTAL_TAGS = 32768; + if (totalTagCount > MAX_TOTAL_TAGS) + { + depth--; + return new EndTag(); + } + + byte type = dis->readByte(); + if (type == 0) { depth--; return new EndTag(); } + + if(type == 255) + { + depth--; + return new EndTag(); + } + + wstring name = dis->readUTF(); Tag *tag = newTag(type, name); - // short length = dis.readShort(); - // byte[] bytes = new byte[length]; - // dis.readFully(bytes); + if (tag == NULL) { depth--; return new EndTag(); } - tag->load(dis, tagDepth); + tag->load(dis); + depth--; return tag; } diff --git a/Minecraft.World/TextureAndGeometryPacket.cpp b/Minecraft.World/TextureAndGeometryPacket.cpp index b6fc6ce7..64054b30 100644 --- a/Minecraft.World/TextureAndGeometryPacket.cpp +++ b/Minecraft.World/TextureAndGeometryPacket.cpp @@ -123,7 +123,17 @@ void TextureAndGeometryPacket::read(DataInputStream *dis) //throws IOException { textureName = dis->readUTF(); dwSkinID = (DWORD)dis->readInt(); - dwTextureBytes = (DWORD)dis->readShort(); + + short rawTextureBytes = dis->readShort(); + if(rawTextureBytes <= 0) + { + dwTextureBytes = 0; + } + else + { + dwTextureBytes = (DWORD)(unsigned short)rawTextureBytes; + if(dwTextureBytes > 65536) dwTextureBytes = 0; + } if(dwTextureBytes>0) { @@ -136,7 +146,16 @@ void TextureAndGeometryPacket::read(DataInputStream *dis) //throws IOException } uiAnimOverrideBitmask = dis->readInt(); - dwBoxC = (DWORD)dis->readShort(); + short rawBoxC = dis->readShort(); + if(rawBoxC <= 0) + { + dwBoxC = 0; + } + else + { + dwBoxC = (DWORD)(unsigned short)rawBoxC; + if(dwBoxC > 256) dwBoxC = 0; // sane limit for skin boxes + } if(dwBoxC>0) { diff --git a/Minecraft.World/TexturePacket.cpp b/Minecraft.World/TexturePacket.cpp index c5eebb0d..48cdbe74 100644 --- a/Minecraft.World/TexturePacket.cpp +++ b/Minecraft.World/TexturePacket.cpp @@ -37,9 +37,19 @@ void TexturePacket::handle(PacketListener *listener) void TexturePacket::read(DataInputStream *dis) //throws IOException { textureName = dis->readUTF(); - dwBytes = (DWORD)dis->readShort(); + short rawBytes = dis->readShort(); + if(rawBytes <= 0) + { + dwBytes = 0; + return; + } + dwBytes = (DWORD)(unsigned short)rawBytes; + if(dwBytes > 65536) + { + dwBytes = 0; + return; + } - if(dwBytes>0) { this->pbData= new BYTE [dwBytes]; diff --git a/Minecraft.World/ThreadName.cpp b/Minecraft.World/ThreadName.cpp index a08f11b8..8fcc28ea 100644 --- a/Minecraft.World/ThreadName.cpp +++ b/Minecraft.World/ThreadName.cpp @@ -20,11 +20,11 @@ void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName ) info.dwFlags = 0; #if ( defined _WINDOWS64 | defined _DURANGO ) - __try - { - RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR *)&info ); - } - __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER ) + __try + { + RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR *)&info ); + } + __except( EXCEPTION_EXECUTE_HANDLER ) { } #endif diff --git a/Minecraft.World/UpdateGameRuleProgressPacket.cpp b/Minecraft.World/UpdateGameRuleProgressPacket.cpp index 29430bb2..8a2c3d4f 100644 --- a/Minecraft.World/UpdateGameRuleProgressPacket.cpp +++ b/Minecraft.World/UpdateGameRuleProgressPacket.cpp @@ -42,7 +42,7 @@ void UpdateGameRuleProgressPacket::read(DataInputStream *dis) //throws IOExcepti m_dataTag = dis->readInt(); int dataLength = dis->readInt(); - if(dataLength > 0) + if(dataLength > 0 && dataLength <= 65536) { m_data = byteArray(dataLength); dis->readFully(m_data); diff --git a/Minecraft.World/compression.cpp b/Minecraft.World/compression.cpp index aa07c005..9490255c 100644 --- a/Minecraft.World/compression.cpp +++ b/Minecraft.World/compression.cpp @@ -180,120 +180,143 @@ HRESULT Compression::CompressRLE(void *pDestination, unsigned int *pDestSize, vo return S_OK; } -HRESULT Compression::DecompressLZXRLE(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize) -{ - EnterCriticalSection(&rleDecompressLock); - // 4J Stu - Fix for #13676 - Crash: Crash while attempting to load a world after updating TU - // Some saves can have chunks that decompress into very large sizes, so I have doubled the size of this buffer - // Ideally we should be able to dynamically allocate the buffer if it's going to be too big, as most chunks - // only use 5% of this buffer - - // 4J Stu - Changed this again to dynamically allocate a buffer if it's going to be too big - unsigned char *pucIn = NULL; - - //const unsigned int staticRleSize = 1024*200; - //static unsigned char rleBuf[staticRleSize]; - unsigned int rleSize = staticRleSize; - unsigned char *dynamicRleBuf = NULL; - - if(*pDestSize > rleSize) - { - rleSize = *pDestSize; - dynamicRleBuf = new unsigned char[rleSize]; - Decompress(dynamicRleBuf, &rleSize, pSource, SrcSize); - pucIn = (unsigned char *)dynamicRleBuf; - } - else - { - Decompress(rleDecompressBuf, &rleSize, pSource, SrcSize); - pucIn = (unsigned char *)rleDecompressBuf; - } - - //unsigned char *pucIn = (unsigned char *)rleDecompressBuf; - unsigned char *pucEnd = pucIn + rleSize; - unsigned char *pucOut = (unsigned char *)pDestination; - - while( pucIn != pucEnd ) - { - unsigned char thisOne = *pucIn++; - if( thisOne == 255 ) - { - unsigned int count = *pucIn++; - if( count < 3 ) - { - count++; - for( unsigned int i = 0; i < count; i++ ) - { - *pucOut++ = 255; - } - } - else - { - count++; - unsigned char data = *pucIn++; - for( unsigned int i = 0; i < count; i++ ) - { - *pucOut++ = data; - } - } - } - else - { - *pucOut++ = thisOne; - } - } - *pDestSize = (unsigned int)(pucOut - (unsigned char *)pDestination); - -// printf("Decompressed from %d to %d to %d\n",SrcSize,rleSize,*pDestSize); - - if(dynamicRleBuf != NULL) delete [] dynamicRleBuf; - - LeaveCriticalSection(&rleDecompressLock); - return S_OK; +HRESULT Compression::DecompressLZXRLE(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize) +{ + EnterCriticalSection(&rleDecompressLock); + // 4J Stu - Fix for #13676 - Crash: Crash while attempting to load a world after updating TU + // Some saves can have chunks that decompress into very large sizes, so I have doubled the size of this buffer + // Ideally we should be able to dynamically allocate the buffer if it's going to be too big, as most chunks + // only use 5% of this buffer + + // 4J Stu - Changed this again to dynamically allocate a buffer if it's going to be too big + unsigned char *pucIn = NULL; + + //const unsigned int staticRleSize = 1024*200; + //static unsigned char rleBuf[staticRleSize]; + unsigned int rleSize = staticRleSize; + unsigned char *dynamicRleBuf = NULL; + + + unsigned int safeRleSize = max(rleSize, *pDestSize); + + const unsigned int MAX_RLE_ALLOC = 16 * 1024 * 1024; // 16 MB + if(safeRleSize > MAX_RLE_ALLOC) + { + LeaveCriticalSection(&rleDecompressLock); + *pDestSize = 0; + return E_FAIL; + } + + if(safeRleSize > staticRleSize) + { + rleSize = safeRleSize; + dynamicRleBuf = new unsigned char[rleSize]; + Decompress(dynamicRleBuf, &rleSize, pSource, SrcSize); + pucIn = (unsigned char *)dynamicRleBuf; + } + else + { + Decompress(rleDecompressBuf, &rleSize, pSource, SrcSize); + pucIn = (unsigned char *)rleDecompressBuf; + } + + //unsigned char *pucIn = (unsigned char *)rleDecompressBuf; + unsigned char *pucEnd = pucIn + rleSize; + unsigned char *pucOut = (unsigned char *)pDestination; + unsigned char *pucOutEnd = pucOut + *pDestSize; + + while( pucIn != pucEnd ) + { + unsigned char thisOne = *pucIn++; + if( thisOne == 255 ) + { + if( pucIn >= pucEnd ) break; + unsigned int count = *pucIn++; + if( count < 3 ) + { + count++; + if( pucOut + count > pucOutEnd ) { pucOut = pucOutEnd; break; } + for( unsigned int i = 0; i < count; i++ ) + { + *pucOut++ = 255; + } + } + else + { + count++; + if( pucIn >= pucEnd ) break; + unsigned char data = *pucIn++; + if( pucOut + count > pucOutEnd ) { pucOut = pucOutEnd; break; } + for( unsigned int i = 0; i < count; i++ ) + { + *pucOut++ = data; + } + } + } + else + { + if( pucOut >= pucOutEnd ) break; + *pucOut++ = thisOne; + } + } + *pDestSize = (unsigned int)(pucOut - (unsigned char *)pDestination); + +// printf("Decompressed from %d to %d to %d\n",SrcSize,rleSize,*pDestSize); + + if(dynamicRleBuf != NULL) delete [] dynamicRleBuf; + + LeaveCriticalSection(&rleDecompressLock); + return S_OK; } -HRESULT Compression::DecompressRLE(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize) -{ - EnterCriticalSection(&rleDecompressLock); - - //unsigned char *pucIn = (unsigned char *)rleDecompressBuf; - unsigned char *pucIn = (unsigned char *)pSource; - unsigned char *pucEnd = pucIn + SrcSize; - unsigned char *pucOut = (unsigned char *)pDestination; - - while( pucIn != pucEnd ) - { - unsigned char thisOne = *pucIn++; - if( thisOne == 255 ) - { - unsigned int count = *pucIn++; - if( count < 3 ) - { - count++; - for( unsigned int i = 0; i < count; i++ ) - { - *pucOut++ = 255; - } - } - else - { - count++; - unsigned char data = *pucIn++; - for( unsigned int i = 0; i < count; i++ ) - { - *pucOut++ = data; - } - } - } - else - { - *pucOut++ = thisOne; - } - } - *pDestSize = (unsigned int)(pucOut - (unsigned char *)pDestination); - - LeaveCriticalSection(&rleDecompressLock); - return S_OK; +HRESULT Compression::DecompressRLE(void *pDestination, unsigned int *pDestSize, void *pSource, unsigned int SrcSize) +{ + EnterCriticalSection(&rleDecompressLock); + + //unsigned char *pucIn = (unsigned char *)rleDecompressBuf; + unsigned char *pucIn = (unsigned char *)pSource; + unsigned char *pucEnd = pucIn + SrcSize; + unsigned char *pucOut = (unsigned char *)pDestination; + unsigned char *pucOutEnd = pucOut + *pDestSize; + + while( pucIn != pucEnd ) + { + unsigned char thisOne = *pucIn++; + if( thisOne == 255 ) + { + if( pucIn >= pucEnd ) break; + unsigned int count = *pucIn++; + if( count < 3 ) + { + count++; + if( pucOut + count > pucOutEnd ) { pucOut = pucOutEnd; break; } + for( unsigned int i = 0; i < count; i++ ) + { + *pucOut++ = 255; + } + } + else + { + count++; + if( pucIn >= pucEnd ) break; + unsigned char data = *pucIn++; + if( pucOut + count > pucOutEnd ) { pucOut = pucOutEnd; break; } + for( unsigned int i = 0; i < count; i++ ) + { + *pucOut++ = data; + } + } + } + else + { + if( pucOut >= pucOutEnd ) break; + *pucOut++ = thisOne; + } + } + *pDestSize = (unsigned int)(pucOut - (unsigned char *)pDestination); + + LeaveCriticalSection(&rleDecompressLock); + return S_OK; } diff --git a/Minecraft.World/system.cpp b/Minecraft.World/system.cpp index 364fa6a0..3924304c 100644 --- a/Minecraft.World/system.cpp +++ b/Minecraft.World/system.cpp @@ -52,7 +52,14 @@ void System::arraycopy(arrayWithLength src, unsigned int srcPos, arrayWithL //The current value of the system timer, in nanoseconds. __int64 System::nanoTime() { - return GetTickCount() * 1000000LL; + static LARGE_INTEGER s_frequency = { 0 }; + if (s_frequency.QuadPart == 0) + QueryPerformanceFrequency(&s_frequency); + + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + + return (__int64)((double)counter.QuadPart * 1000000000.0 / (double)s_frequency.QuadPart); } //Returns the current time in milliseconds. Note that while the unit of time of the return value is a millisecond, diff --git a/Minecraft.World/x64headers/extraX64.h b/Minecraft.World/x64headers/extraX64.h index 0049ffbc..f2299f58 100644 --- a/Minecraft.World/x64headers/extraX64.h +++ b/Minecraft.World/x64headers/extraX64.h @@ -13,15 +13,27 @@ typedef unsigned char byte; -const int XUSER_INDEX_ANY = 255; -const int XUSER_INDEX_FOCUS = 254; - -#ifdef __PSVITA__ -const int XUSER_MAX_COUNT = 1; -const int MINECRAFT_NET_MAX_PLAYERS = 4; -#else -const int XUSER_MAX_COUNT = 4; -const int MINECRAFT_NET_MAX_PLAYERS = 8; +#ifndef XUSER_INDEX_ANY +const int XUSER_INDEX_ANY = 255; +#endif +#ifndef XUSER_INDEX_FOCUS +const int XUSER_INDEX_FOCUS = 254; +#endif + +#ifdef __PSVITA__ +#ifndef XUSER_MAX_COUNT +const int XUSER_MAX_COUNT = 1; +#endif +const int MINECRAFT_NET_MAX_PLAYERS = 4; +#else +#ifndef XUSER_MAX_COUNT +const int XUSER_MAX_COUNT = 4; +#endif +#if defined(_DEDICATED_SERVER) || defined(_WINDOWS64) +const int MINECRAFT_NET_MAX_PLAYERS = 255; +#else +const int MINECRAFT_NET_MAX_PLAYERS = 8; +#endif #endif @@ -215,10 +227,19 @@ public: int GetUserIndex(); void SetCustomDataValue(ULONG_PTR ulpCustomDataValue); ULONG_PTR GetCustomDataValue(); + + BYTE m_smallId; + bool m_isRemote; + bool m_isHostPlayer; + wchar_t m_gamertag[32]; private: ULONG_PTR m_customData; }; +void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost, bool isLocal); +PlayerUID Win64_UsernameToXuid(const char* username); +PlayerUID Win64_UsernameToXuid(const wchar_t* username); + const int QNET_GETSENDQUEUESIZE_SECONDARY_TYPE = 0; const int QNET_GETSENDQUEUESIZE_MESSAGES = 0; const int QNET_GETSENDQUEUESIZE_BYTES = 0; @@ -309,9 +330,15 @@ public: bool IsHost(); HRESULT JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO *pInviteInfo); void HostGame(); + void ClientJoinGame(); void EndGame(); - - static IQNetPlayer m_player[4]; + static void SetPlayerCapacity(DWORD capacity); + static DWORD GetPlayerCapacity(); + + static IQNetPlayer *m_player; + static DWORD s_playerCapacity; + static DWORD s_playerCount; + static bool s_isHosting; }; #ifdef _DURANGO diff --git a/Minecraft.World/x64headers/qnet.h b/Minecraft.World/x64headers/qnet.h index e69de29b..bb4c056a 100644 --- a/Minecraft.World/x64headers/qnet.h +++ b/Minecraft.World/x64headers/qnet.h @@ -0,0 +1,2 @@ +#pragma once +#include "extraX64.h" diff --git a/Minecraft.World/x64headers/xmcore.h b/Minecraft.World/x64headers/xmcore.h index e69de29b..bb4c056a 100644 --- a/Minecraft.World/x64headers/xmcore.h +++ b/Minecraft.World/x64headers/xmcore.h @@ -0,0 +1,2 @@ +#pragma once +#include "extraX64.h" diff --git a/Minecraft.World/x64headers/xrnm.h b/Minecraft.World/x64headers/xrnm.h index e69de29b..bb4c056a 100644 --- a/Minecraft.World/x64headers/xrnm.h +++ b/Minecraft.World/x64headers/xrnm.h @@ -0,0 +1,2 @@ +#pragma once +#include "extraX64.h" diff --git a/Minecraft.World/x64headers/xsocialpost.h b/Minecraft.World/x64headers/xsocialpost.h index e69de29b..bb4c056a 100644 --- a/Minecraft.World/x64headers/xsocialpost.h +++ b/Minecraft.World/x64headers/xsocialpost.h @@ -0,0 +1,2 @@ +#pragma once +#include "extraX64.h" diff --git a/Minecraft.World/x64headers/xuiapp.h b/Minecraft.World/x64headers/xuiapp.h index e69de29b..bb4c056a 100644 --- a/Minecraft.World/x64headers/xuiapp.h +++ b/Minecraft.World/x64headers/xuiapp.h @@ -0,0 +1,2 @@ +#pragma once +#include "extraX64.h" diff --git a/Minecraft.World/x64headers/xuiresource.h b/Minecraft.World/x64headers/xuiresource.h index e69de29b..bb4c056a 100644 --- a/Minecraft.World/x64headers/xuiresource.h +++ b/Minecraft.World/x64headers/xuiresource.h @@ -0,0 +1,2 @@ +#pragma once +#include "extraX64.h"