This commit is contained in:
YkPhysics 2026-03-03 15:18:04 -05:00
parent 39ffeedde1
commit 341963b9c0
61 changed files with 5764 additions and 773 deletions

View file

@ -49,12 +49,11 @@ void BufferedImage::ByteFlip4(unsigned int &data)
// 24-bits used (ie no alpha channel) whereas method 0 is a full 32-bit image with a valid alpha channel.
BufferedImage::BufferedImage(const wstring& File, bool filenameHasExtension /*=false*/, bool bTitleUpdateTexture /*=false*/, const wstring &drive /*=L""*/)
{
HRESULT hr;
wstring wDrive;
wstring filePath;
filePath = File;
wDrive = drive;
HRESULT hr = ERROR_SUCCESS;
wstring wDrive = drive;
wstring filePath = File;
width = 0;
height = 0;
if(wDrive.empty())
{
#ifdef _XBOX
@ -170,9 +169,53 @@ BufferedImage::BufferedImage(const wstring& File, bool filenameHasExtension /*=f
ZeroMemory(&ImageInfo,sizeof(D3DXIMAGE_INFO));
hr=RenderManager.LoadTextureData(pchTextureName,&ImageInfo,&data[l]);
#if defined(_WINDOWS64)
if (hr != ERROR_SUCCESS && l == 0 && drive.empty())
{
static const wchar_t *fallbackDrives[] =
{
L"Minecraft.Client/Common/",
L"Common/",
L"../Minecraft.Client/Common/",
L"../Common/",
L"..\\Minecraft.Client\\Common\\",
L"..\\Common\\"
};
const unsigned int fallbackDriveCount = sizeof(fallbackDrives) / sizeof(fallbackDrives[0]);
for (unsigned int f = 0; f < fallbackDriveCount; ++f)
{
const wstring fallbackDrive = fallbackDrives[f];
if (fallbackDrive == wDrive)
{
continue;
}
wstring fallbackName;
if (filenameHasExtension)
{
fallbackName = fallbackDrive + L"res" + filePath.substr(0, filePath.length());
}
else
{
fallbackName = fallbackDrive + L"res" + filePath.substr(0, filePath.length() - 4) + mipMapPath + L".png";
}
const char *fallbackTextureName = wstringtofilename(fallbackName);
hr = RenderManager.LoadTextureData(fallbackTextureName, &ImageInfo, &data[l]);
if (hr == ERROR_SUCCESS)
{
app.DebugPrintf("BufferedImage: fallback load succeeded for '%s'\n", fallbackTextureName);
wDrive = fallbackDrive;
break;
}
}
}
#endif
if(hr!=ERROR_SUCCESS)
{
app.DebugPrintf("BufferedImage: failed to load texture '%s' (hr=0x%08X)\n", pchTextureName, (unsigned int)hr);
// 4J - If we haven't loaded the non-mipmap version then exit the game
if( l == 0 )
{

View file

@ -47,6 +47,9 @@
#else
#include "Common\UI\UI.h"
#endif
#ifdef _WINDOWS64
#include "Common\Network\PlatformNetworkManagerStub.h"
#endif
#ifdef __PS3__
#include "PS3/Network/SonyVoiceChat.h"
#endif
@ -57,6 +60,26 @@
#include "..\Minecraft.World\GenericStats.h"
#endif
namespace
{
const wstring LCE_TRANSFER_PACKET = L"LCE|Xfer";
string NarrowAscii(const wstring &value)
{
string out;
out.reserve(value.length());
for (size_t i = 0; i < value.length(); ++i)
{
const wchar_t ch = value[i];
if (ch >= 32 && ch <= 126)
{
out.push_back((char)ch);
}
}
return out;
}
}
ClientConnection::ClientConnection(Minecraft *minecraft, const wstring& ip, int port)
{
// 4J Stu - No longer used as we use the socket version below.
@ -140,6 +163,19 @@ ClientConnection::~ClientConnection()
void ClientConnection::tick()
{
if (connection == NULL)
{
return;
}
#ifdef _WINDOWS64
if (CPlatformNetworkManagerStub::IsServerTransferInProgress())
{
connection->flush();
return;
}
#endif
if (!done) connection->tick();
connection->flush();
}
@ -704,6 +740,17 @@ void ClientConnection::handleAddPainting(shared_ptr<AddPaintingPacket> packet)
void ClientConnection::handleSetEntityMotion(shared_ptr<SetEntityMotionPacket> packet)
{
#ifdef _WINDOWS64
if (CPlatformNetworkManagerStub::IsServerTransferInProgress())
{
return;
}
#endif
if (!started || level == NULL || minecraft == NULL || minecraft->level == NULL)
{
return;
}
shared_ptr<Entity> e = getEntity(packet->id);
if (e == NULL) return;
e->lerpMotion(packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0);
@ -1136,6 +1183,16 @@ void ClientConnection::handleDisconnect(shared_ptr<DisconnectPacket> packet)
{
connection->close(DisconnectPacket::eDisconnect_Kicked);
done = true;
#ifdef _WINDOWS64
if (CPlatformNetworkManagerStub::IsServerTransferInProgress())
{
level = NULL;
started = false;
app.DebugPrintf("Win64 LAN: Ignoring handleDisconnect during in-progress server transfer\n");
return;
}
#endif
Minecraft *pMinecraft = Minecraft::GetInstance();
pMinecraft->connectionDisconnected( m_userIndex , packet->reason );
@ -1152,6 +1209,16 @@ void ClientConnection::onDisconnect(DisconnectPacket::eDisconnectReason reason,
if (done) return;
done = true;
#ifdef _WINDOWS64
if (CPlatformNetworkManagerStub::IsServerTransferInProgress())
{
level = NULL;
started = false;
app.DebugPrintf("Win64 LAN: Ignoring onDisconnect during in-progress server transfer (reason=%d)\n", (int)reason);
return;
}
#endif
Minecraft *pMinecraft = Minecraft::GetInstance();
pMinecraft->connectionDisconnected( m_userIndex , reason );
@ -1281,6 +1348,20 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
switch(packet->m_messageType)
{
case ChatPacket::e_ChatCustom:
if(packet->m_stringArgs.size() >= 2)
{
message = L"<" + playerDisplayName + L"> " + packet->m_stringArgs[1];
}
else if(packet->m_stringArgs.size() >= 1)
{
message = packet->m_stringArgs[0];
}
else
{
message = L"";
}
break;
case ChatPacket::e_ChatBedOccupied:
message = app.GetString(IDS_TILE_BED_OCCUPIED);
break;
@ -2186,6 +2267,21 @@ void ClientConnection::handleEntityEvent(shared_ptr<EntityEventPacket> packet)
shared_ptr<Entity> ClientConnection::getEntity(int entityId)
{
if (!started || level == NULL || minecraft == NULL || minecraft->level == NULL)
{
return shared_ptr<Entity>();
}
if (m_userIndex < 0 || m_userIndex >= XUSER_MAX_COUNT)
{
return shared_ptr<Entity>();
}
if (minecraft->localplayers[m_userIndex] == NULL)
{
return shared_ptr<Entity>();
}
//if (entityId == minecraft->player->entityId)
if(entityId == minecraft->localplayers[m_userIndex]->entityId)
{
@ -2841,7 +2937,15 @@ void ClientConnection::handleTileDestruction(shared_ptr<TileDestructionPacket> p
bool ClientConnection::canHandleAsyncPackets()
{
return minecraft != NULL && minecraft->level != NULL && minecraft->localplayers[m_userIndex] != NULL && level != NULL;
if (minecraft == NULL || level == NULL || minecraft->level == NULL || !started)
{
return false;
}
if (m_userIndex < 0 || m_userIndex >= XUSER_MAX_COUNT)
{
return false;
}
return minecraft->localplayers[m_userIndex] != NULL;
}
void ClientConnection::handleGameEvent(shared_ptr<GameEventPacket> gameEventPacket)
@ -3148,6 +3252,41 @@ void ClientConnection::handleSoundEvent(shared_ptr<LevelSoundPacket> packet)
void ClientConnection::handleCustomPayload(shared_ptr<CustomPayloadPacket> customPayloadPacket)
{
if (LCE_TRANSFER_PACKET.compare(customPayloadPacket->identifier) == 0)
{
#ifdef _WINDOWS64
ByteArrayInputStream bais(customPayloadPacket->data);
DataInputStream input(&bais);
const int payloadVersion = (int)input.readUnsignedByte();
const int queueIndex = (int)input.readUnsignedByte();
const int hostPort = input.readInt();
const wstring hostIpW = input.readUTF();
const wstring queueLabel = input.readUTF();
const string hostIp = NarrowAscii(hostIpW);
app.DebugPrintf("Win64 LAN: Received transfer payload v%d queue=%d target=%s:%d label=%ls\n",
payloadVersion, queueIndex, hostIp.c_str(), hostPort, queueLabel.c_str());
if (!hostIp.empty() && hostPort > 0)
{
CPlatformNetworkManagerStub::RequestServerTransfer(hostIp.c_str(), hostPort);
wstring message = L"Match found";
if (!queueLabel.empty())
{
message += L" for ";
message += queueLabel;
}
message += L". Transferring...";
minecraft->gui->addMessage(message, m_userIndex);
}
else
{
app.DebugPrintf("Win64 LAN: Ignoring invalid transfer payload target\n");
}
#endif
return;
}
if (CustomPayloadPacket::TRADER_LIST_PACKET.compare(customPayloadPacket->identifier) == 0)
{
ByteArrayInputStream bais(customPayloadPacket->data);

View file

@ -456,9 +456,6 @@ void SoundEngine::updateMiles()
if ( SoundInfo.Status != MILESEVENT_SOUND_STATUS_COMPLETE )
{
if (SoundInfo.Sample == NULL)
continue;
// apply the master volume
// watch for the 'special' volume levels
bool isThunder = false;

View file

@ -69,6 +69,62 @@
#include "..\Common\Leaderboards\LeaderboardManager.h"
#ifdef _WINDOWS64
extern void Windows64_DedicatedGuiPushLog(const char *text);
static void WriteStandaloneDebugLog(const char *text)
{
if (text == NULL)
{
return;
}
wchar_t exePath[MAX_PATH];
if (!GetModuleFileNameW(NULL, exePath, MAX_PATH))
{
return;
}
wstring logPath(exePath);
size_t lastSlash = logPath.find_last_of(L"\\/");
if (lastSlash != wstring::npos)
{
logPath = logPath.substr(0, lastSlash + 1) + L"StandaloneDebug.log";
}
else
{
logPath = L"StandaloneDebug.log";
}
HANDLE file = CreateFileW(logPath.c_str(), FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE)
{
return;
}
SYSTEMTIME st;
GetLocalTime(&st);
char prefix[64];
_snprintf_s(prefix, sizeof(prefix), _TRUNCATE, "[%02d:%02d:%02d.%03d] ",
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
DWORD bytesWritten = 0;
WriteFile(file, prefix, (DWORD)strlen(prefix), &bytesWritten, NULL);
WriteFile(file, text, (DWORD)strlen(text), &bytesWritten, NULL);
size_t len = strlen(text);
if (len == 0 || (text[len - 1] != '\n' && text[len - 1] != '\r'))
{
const char *newline = "\r\n";
WriteFile(file, newline, (DWORD)strlen(newline), &bytesWritten, NULL);
}
CloseHandle(file);
Windows64_DedicatedGuiPushLog(text);
}
#endif
//CMinecraftApp app;
unsigned int CMinecraftApp::m_uiLastSignInData = 0;
@ -233,21 +289,23 @@ CMinecraftApp::CMinecraftApp()
void CMinecraftApp::DebugPrintf(const char *szFormat, ...)
{
#ifndef _FINAL_BUILD
char buf[1024];
va_list ap;
va_start(ap, szFormat);
vsnprintf(buf, sizeof(buf), szFormat, ap);
va_end(ap);
#ifndef _FINAL_BUILD
OutputDebugStringA(buf);
#endif
#ifdef _WINDOWS64
WriteStandaloneDebugLog(buf);
#endif
}
void CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...)
{
#ifndef _FINAL_BUILD
if(user == USER_NONE)
return;
char buf[1024];
@ -255,6 +313,7 @@ void CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...)
va_start(ap, szFormat);
vsnprintf(buf, sizeof(buf), szFormat, ap);
va_end(ap);
#ifndef _FINAL_BUILD
#ifdef __PS3__
unsigned int writelen;
sys_tty_write(SYS_TTYP_USER1 + ( user - 1 ), buf, strlen(buf), &writelen );
@ -297,12 +356,26 @@ void CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...)
}
#endif
#endif
#ifdef _WINDOWS64
WriteStandaloneDebugLog(buf);
#endif
}
LPCWSTR CMinecraftApp::GetString(int iID)
{
//return L"Değişiklikler ve Yenilikler";
//return L"ÕÕÕÕÖÖÖÖ";
if (app.m_stringTable == NULL)
{
static int s_missingStringTableLogCount = 0;
if (s_missingStringTableLogCount < 16)
{
app.DebugPrintf("CMinecraftApp::GetString - null m_stringTable for id %d\n", iID);
s_missingStringTableLogCount++;
}
return L"";
}
return app.m_stringTable->getString(iID);
}
@ -4085,23 +4158,65 @@ int CMinecraftApp::BannedLevelDialogReturned(void *pParam,int iPad,const C4JStor
void CMinecraftApp::loadMediaArchive()
{
wstring mediapath = L"";
wstring mediaFileName = L"";
#ifdef __PS3__
mediapath = L"Common\\Media\\MediaPS3.arc";
mediaFileName = L"MediaPS3.arc";
#elif _WINDOWS64
mediapath = L"Common\\Media\\MediaWindows64.arc";
mediaFileName = L"MediaWindows64.arc";
#elif __ORBIS__
mediapath = L"Common\\Media\\MediaOrbis.arc";
mediaFileName = L"MediaOrbis.arc";
#elif _DURANGO
mediapath = L"Common\\Media\\MediaDurango.arc";
mediaFileName = L"MediaDurango.arc";
#elif __PSVITA__
mediapath = L"Common\\Media\\MediaPSVita.arc";
mediaFileName = L"MediaPSVita.arc";
#endif
if (!mediapath.empty())
if (!mediaFileName.empty())
{
m_mediaArchive = new ArchiveFile( File(mediapath) );
if (m_mediaArchive != NULL)
{
delete m_mediaArchive;
m_mediaArchive = NULL;
}
vector<wstring> candidates;
candidates.push_back(L"Common\\Media\\" + mediaFileName);
candidates.push_back(L"Minecraft.Client\\Common\\Media\\" + mediaFileName);
#if defined(_WINDOWS64) || defined(_WIN32)
wchar_t exePath[MAX_PATH];
if (GetModuleFileNameW(NULL, exePath, MAX_PATH))
{
wstring exeDir(exePath);
size_t lastSlash = exeDir.find_last_of(L"\\/");
if (lastSlash != wstring::npos)
{
exeDir = exeDir.substr(0, lastSlash);
wstring root = exeDir;
for (int i = 0; i < 8; ++i)
{
candidates.push_back(root + L"\\Common\\Media\\" + mediaFileName);
candidates.push_back(root + L"\\Minecraft.Client\\Common\\Media\\" + mediaFileName);
root += L"\\..";
}
}
}
#endif
for (AUTO_VAR(it, candidates.begin()); it != candidates.end(); ++it)
{
File archiveCandidate(*it);
if (archiveCandidate.exists())
{
app.DebugPrintf("CMinecraftApp::loadMediaArchive - using '%ls'\n", it->c_str());
m_mediaArchive = new ArchiveFile(archiveCandidate);
return;
}
}
app.DebugPrintf("CMinecraftApp::loadMediaArchive - failed to locate '%ls'\n", mediaFileName.c_str());
m_mediaArchive = NULL;
}
#if 0
string path = "Common\\media.arc";
@ -4153,6 +4268,18 @@ void CMinecraftApp::loadStringTable()
// we need to unload the current string table, this is a reload
delete m_stringTable;
}
m_stringTable = NULL;
if (m_mediaArchive == NULL)
{
loadMediaArchive();
if (m_mediaArchive == NULL)
{
DebugPrintf("CMinecraftApp::loadStringTable - media archive not loaded\n");
return;
}
}
wstring localisationFile = L"languages.loc";
if (m_mediaArchive->hasFile(localisationFile))
{
@ -4162,9 +4289,7 @@ void CMinecraftApp::loadStringTable()
}
else
{
m_stringTable = NULL;
assert(false);
// AHHHHHHHHH.
DebugPrintf("CMinecraftApp::loadStringTable - missing file '%ls'\n", localisationFile.c_str());
}
#endif
}
@ -8864,7 +8989,17 @@ int CMinecraftApp::getArchiveFileSize(const wstring &filename)
{
return tPack->getArchiveFile()->getFileSize(filename);
}
else return m_mediaArchive->getFileSize(filename);
if (m_mediaArchive == NULL)
{
loadMediaArchive();
}
if (m_mediaArchive != NULL)
{
return m_mediaArchive->getFileSize(filename);
}
return -1;
}
bool CMinecraftApp::hasArchiveFile(const wstring &filename)
@ -8873,7 +9008,12 @@ bool CMinecraftApp::hasArchiveFile(const wstring &filename)
Minecraft *pMinecraft = Minecraft::GetInstance();
if(pMinecraft && pMinecraft->skins) tPack = pMinecraft->skins->getSelected();
if(tPack && tPack->hasData() && tPack->getArchiveFile() && tPack->getArchiveFile()->hasFile(filename)) return true;
else return m_mediaArchive->hasFile(filename);
if (m_mediaArchive == NULL)
{
loadMediaArchive();
}
return m_mediaArchive != NULL && m_mediaArchive->hasFile(filename);
}
byteArray CMinecraftApp::getArchiveFile(const wstring &filename)
@ -8885,7 +9025,17 @@ byteArray CMinecraftApp::getArchiveFile(const wstring &filename)
{
return tPack->getArchiveFile()->getFile(filename);
}
else return m_mediaArchive->getFile(filename);
if (m_mediaArchive == NULL)
{
loadMediaArchive();
}
if (m_mediaArchive != NULL)
{
return m_mediaArchive->getFile(filename);
}
return byteArray();
}
// DLC
@ -9536,4 +9686,4 @@ bool CMinecraftApp::HasReachedMainMenu()
{
return m_hasReachedMainMenu;
}
#endif
#endif

View file

@ -40,6 +40,10 @@
#include "..\Minecraft.World\DurangoStats.h"
#endif
#ifdef _WINDOWS64
extern bool g_Win64DedicatedServerMode;
#endif
// Global instance
CGameNetworkManager g_NetworkManager;
CPlatformNetworkManager *CGameNetworkManager::s_pPlatformNetworkManager;
@ -281,186 +285,199 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame
// PRIMARY PLAYER
vector<ClientConnection *> createdConnections;
ClientConnection *connection;
ClientConnection *connection = NULL;
#ifdef _WINDOWS64
const bool dedicatedHeadlessHost = (g_NetworkManager.IsHost() && g_Win64DedicatedServerMode);
#else
const bool dedicatedHeadlessHost = false;
#endif
if( g_NetworkManager.IsHost() )
if (!dedicatedHeadlessHost)
{
connection = new ClientConnection(minecraft, NULL);
}
else
{
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(ProfileManager.GetLockedProfile());
if(pNetworkPlayer == NULL)
if( g_NetworkManager.IsHost() )
{
MinecraftServer::HaltServer();
app.DebugPrintf("%d\n",ProfileManager.GetLockedProfile());
// If the player is NULL here then something went wrong in the session setup, and continuing will end up in a crash
return false;
}
Socket *socket = pNetworkPlayer->GetSocket();
// Fix for #13259 - CRASH: Gameplay: loading process is halted when player loads saved data
if(socket == NULL)
{
assert(false);
MinecraftServer::HaltServer();
// If the socket is NULL here then something went wrong in the session setup, and continuing will end up in a crash
return false;
}
connection = new ClientConnection(minecraft, socket);
}
if( !connection->createdOk )
{
assert(false);
delete connection;
connection = NULL;
MinecraftServer::HaltServer();
return false;
}
connection->send( shared_ptr<PreLoginPacket>( new PreLoginPacket(minecraft->user->name) ) );
// Tick connection until we're ready to go. The stages involved in this are:
// (1) Creating the ClientConnection sends a prelogin packet to the server
// (2) the server sends a prelogin back, which is handled by the clientConnection, and returns a login packet
// (3) the server sends a login back, which is handled by the client connection to start the game
if( !g_NetworkManager.IsHost() )
{
Minecraft::GetInstance()->progressRenderer->progressStart(IDS_PROGRESS_CONNECTING);
}
else
{
// 4J Stu - Host needs to generate a unique multiplayer id for sentient telemetry reporting
INT multiplayerInstanceId = TelemetryManager->GenerateMultiplayerInstanceId();
TelemetryManager->SetMultiplayerInstanceId(multiplayerInstanceId);
}
TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected();
do
{
app.DebugPrintf("ticking connection A\n");
connection->tick();
// 4J Stu - We were ticking this way too fast which could cause the connection to time out
// The connections should tick at 20 per second
Sleep(50);
} while ( (IsInSession() && !connection->isStarted() && !connection->isClosed() && !g_NetworkManager.IsLeavingGame()) || tPack->isLoadingData() || (Minecraft::GetInstance()->skins->needsUIUpdate() || ui.IsReloadingSkin()) );
ui.CleanUpSkinReload();
// 4J Stu - Fix for #11279 - CRASH: TCR 001: BAS Game Stability: Signing out of game will cause title to crash
// We need to break out of the above loop if m_bLeavingGame is set, and close the connection
if( g_NetworkManager.IsLeavingGame() || !IsInSession() )
{
connection->close();
}
if( connection->isStarted() && !connection->isClosed() )
{
createdConnections.push_back( connection );
int primaryPad = ProfileManager.GetPrimaryPad();
app.SetRichPresenceContext(primaryPad,CONTEXT_GAME_STATE_BLANK);
if (GetPlayerCount() > 1) // Are we offline or online, and how many players are there
{
if (IsLocalGame()) ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false);
else ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER,false);
connection = new ClientConnection(minecraft, NULL);
}
else
{
if(IsLocalGame()) ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE,false);
else ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER_1P,false);
}
// ALL OTHER LOCAL PLAYERS
for(int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
{
// Already have setup the primary pad
if(idx == ProfileManager.GetPrimaryPad() ) continue;
if( GetLocalPlayerByUserIndex(idx) != NULL && !ProfileManager.IsSignedIn(idx) )
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(ProfileManager.GetLockedProfile());
if(pNetworkPlayer == NULL)
{
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx);
Socket *socket = pNetworkPlayer->GetSocket();
app.DebugPrintf("Closing socket due to player %d not being signed in any more\n");
if( !socket->close(false) ) socket->close(true);
continue;
MinecraftServer::HaltServer();
app.DebugPrintf("%d\n",ProfileManager.GetLockedProfile());
// If the player is NULL here then something went wrong in the session setup, and continuing will end up in a crash
return false;
}
// By default when we host we only have the local player, but currently allow multiple local players to join
// when joining any other way, so just because they are signed in doesn't mean they are in the session
// 4J Stu - If they are in the session, then we should add them to the game. Otherwise we won't be able to add them later
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx);
if( pNetworkPlayer == NULL )
continue;
ClientConnection *connection;
Socket *socket = pNetworkPlayer->GetSocket();
connection = new ClientConnection(minecraft, socket, idx);
minecraft->addPendingLocalConnection(idx, connection);
//minecraft->createExtraLocalPlayer(idx, (convStringToWstring( ProfileManager.GetGamertag(idx) )).c_str(), idx, connection);
// Fix for #13259 - CRASH: Gameplay: loading process is halted when player loads saved data
if(socket == NULL)
{
assert(false);
MinecraftServer::HaltServer();
// If the socket is NULL here then something went wrong in the session setup, and continuing will end up in a crash
return false;
}
// Open the socket on the server end to accept incoming data
Socket::addIncomingSocket(socket);
connection = new ClientConnection(minecraft, socket);
}
connection->send( shared_ptr<PreLoginPacket>( new PreLoginPacket(convStringToWstring( ProfileManager.GetGamertag(idx) )) ) );
if( !connection->createdOk )
{
assert(false);
delete connection;
connection = NULL;
MinecraftServer::HaltServer();
return false;
}
connection->send( shared_ptr<PreLoginPacket>( new PreLoginPacket(minecraft->user->name) ) );
// Tick connection until we're ready to go. The stages involved in this are:
// (1) Creating the ClientConnection sends a prelogin packet to the server
// (2) the server sends a prelogin back, which is handled by the clientConnection, and returns a login packet
// (3) the server sends a login back, which is handled by the client connection to start the game
if( !g_NetworkManager.IsHost() )
{
Minecraft::GetInstance()->progressRenderer->progressStart(IDS_PROGRESS_CONNECTING);
}
else
{
// 4J Stu - Host needs to generate a unique multiplayer id for sentient telemetry reporting
INT multiplayerInstanceId = TelemetryManager->GenerateMultiplayerInstanceId();
TelemetryManager->SetMultiplayerInstanceId(multiplayerInstanceId);
}
TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected();
do
{
app.DebugPrintf("ticking connection A\n");
connection->tick();
// 4J Stu - We were ticking this way too fast which could cause the connection to time out
// The connections should tick at 20 per second
Sleep(50);
} while ( (IsInSession() && !connection->isStarted() && !connection->isClosed() && !g_NetworkManager.IsLeavingGame()) || tPack->isLoadingData() || (Minecraft::GetInstance()->skins->needsUIUpdate() || ui.IsReloadingSkin()) );
ui.CleanUpSkinReload();
// 4J Stu - Fix for #11279 - CRASH: TCR 001: BAS Game Stability: Signing out of game will cause title to crash
// We need to break out of the above loop if m_bLeavingGame is set, and close the connection
if( g_NetworkManager.IsLeavingGame() || !IsInSession() )
{
connection->close();
}
if( connection->isStarted() && !connection->isClosed() )
{
createdConnections.push_back( connection );
// Tick connection until we're ready to go. The stages involved in this are:
// (1) Creating the ClientConnection sends a prelogin packet to the server
// (2) the server sends a prelogin back, which is handled by the clientConnection, and returns a login packet
// (3) the server sends a login back, which is handled by the client connection to start the game
do
int primaryPad = ProfileManager.GetPrimaryPad();
app.SetRichPresenceContext(primaryPad,CONTEXT_GAME_STATE_BLANK);
if (GetPlayerCount() > 1) // Are we offline or online, and how many players are there
{
// We need to keep ticking the connections for players that already logged in
for(AUTO_VAR(it, createdConnections.begin()); it < createdConnections.end(); ++it)
{
(*it)->tick();
}
// 4J Stu - We were ticking this way too fast which could cause the connection to time out
// The connections should tick at 20 per second
Sleep(50);
app.DebugPrintf("<***> %d %d %d %d %d\n",IsInSession(), !connection->isStarted(),!connection->isClosed(),ProfileManager.IsSignedIn(idx),!g_NetworkManager.IsLeavingGame());
#if defined _XBOX || __PS3__
} while (IsInSession() && !connection->isStarted() && !connection->isClosed() && ProfileManager.IsSignedIn(idx) && !g_NetworkManager.IsLeavingGame() );
#else
// TODO - This SHOULD be something just like the code above but temporarily changing here so that we don't have to depend on the profilemanager behaviour
} while (IsInSession() && !connection->isStarted() && !connection->isClosed() && !g_NetworkManager.IsLeavingGame() );
#endif
// 4J Stu - Fix for #11279 - CRASH: TCR 001: BAS Game Stability: Signing out of game will cause title to crash
// We need to break out of the above loop if m_bLeavingGame is set, and stop creating new connections
// The connections in the createdConnections vector get closed at the end of the thread
if( g_NetworkManager.IsLeavingGame() || !IsInSession() ) break;
if( ProfileManager.IsSignedIn(idx) && !connection->isClosed() )
{
app.SetRichPresenceContext(idx,CONTEXT_GAME_STATE_BLANK);
if (IsLocalGame()) ProfileManager.SetCurrentGameActivity(idx,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false);
else ProfileManager.SetCurrentGameActivity(idx,CONTEXT_PRESENCE_MULTIPLAYER,false);
if (IsLocalGame()) ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false);
else ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER,false);
}
else
{
connection->close();
AUTO_VAR(it, find( createdConnections.begin(), createdConnections.end(), connection ));
if(it != createdConnections.end() ) createdConnections.erase( it );
if(IsLocalGame()) ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE,false);
else ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER_1P,false);
}
}
app.SetGameMode( eMode_Multiplayer );
}
else if ( connection->isClosed() || !IsInSession())
{
// ALL OTHER LOCAL PLAYERS
for(int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
{
// Already have setup the primary pad
if(idx == ProfileManager.GetPrimaryPad() ) continue;
if( GetLocalPlayerByUserIndex(idx) != NULL && !ProfileManager.IsSignedIn(idx) )
{
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx);
Socket *socket = pNetworkPlayer->GetSocket();
app.DebugPrintf("Closing socket due to player %d not being signed in any more\n");
if( !socket->close(false) ) socket->close(true);
continue;
}
// By default when we host we only have the local player, but currently allow multiple local players to join
// when joining any other way, so just because they are signed in doesn't mean they are in the session
// 4J Stu - If they are in the session, then we should add them to the game. Otherwise we won't be able to add them later
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx);
if( pNetworkPlayer == NULL )
continue;
ClientConnection *connection;
Socket *socket = pNetworkPlayer->GetSocket();
connection = new ClientConnection(minecraft, socket, idx);
minecraft->addPendingLocalConnection(idx, connection);
//minecraft->createExtraLocalPlayer(idx, (convStringToWstring( ProfileManager.GetGamertag(idx) )).c_str(), idx, connection);
// Open the socket on the server end to accept incoming data
Socket::addIncomingSocket(socket);
connection->send( shared_ptr<PreLoginPacket>( new PreLoginPacket(convStringToWstring( ProfileManager.GetGamertag(idx) )) ) );
createdConnections.push_back( connection );
// Tick connection until we're ready to go. The stages involved in this are:
// (1) Creating the ClientConnection sends a prelogin packet to the server
// (2) the server sends a prelogin back, which is handled by the clientConnection, and returns a login packet
// (3) the server sends a login back, which is handled by the client connection to start the game
do
{
// We need to keep ticking the connections for players that already logged in
for(AUTO_VAR(it, createdConnections.begin()); it < createdConnections.end(); ++it)
{
(*it)->tick();
}
// 4J Stu - We were ticking this way too fast which could cause the connection to time out
// The connections should tick at 20 per second
Sleep(50);
app.DebugPrintf("<***> %d %d %d %d %d\n",IsInSession(), !connection->isStarted(),!connection->isClosed(),ProfileManager.IsSignedIn(idx),!g_NetworkManager.IsLeavingGame());
#if defined _XBOX || __PS3__
} while (IsInSession() && !connection->isStarted() && !connection->isClosed() && ProfileManager.IsSignedIn(idx) && !g_NetworkManager.IsLeavingGame() );
#else
// TODO - This SHOULD be something just like the code above but temporarily changing here so that we don't have to depend on the profilemanager behaviour
} while (IsInSession() && !connection->isStarted() && !connection->isClosed() && !g_NetworkManager.IsLeavingGame() );
#endif
// 4J Stu - Fix for #11279 - CRASH: TCR 001: BAS Game Stability: Signing out of game will cause title to crash
// We need to break out of the above loop if m_bLeavingGame is set, and stop creating new connections
// The connections in the createdConnections vector get closed at the end of the thread
if( g_NetworkManager.IsLeavingGame() || !IsInSession() ) break;
if( ProfileManager.IsSignedIn(idx) && !connection->isClosed() )
{
app.SetRichPresenceContext(idx,CONTEXT_GAME_STATE_BLANK);
if (IsLocalGame()) ProfileManager.SetCurrentGameActivity(idx,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false);
else ProfileManager.SetCurrentGameActivity(idx,CONTEXT_PRESENCE_MULTIPLAYER,false);
}
else
{
connection->close();
AUTO_VAR(it, find( createdConnections.begin(), createdConnections.end(), connection ));
if(it != createdConnections.end() ) createdConnections.erase( it );
}
}
app.SetGameMode( eMode_Multiplayer );
}
else if ( connection->isClosed() || !IsInSession())
{
// assert(false);
MinecraftServer::HaltServer();
return false;
MinecraftServer::HaltServer();
return false;
}
}
else
{
app.DebugPrintf("Win64 dedicated: skipping primary local player connection\n");
app.SetGameMode( eMode_Multiplayer );
}

View file

@ -7,6 +7,15 @@
#include "..\..\Windows64\Network\WinsockNetLayer.h"
#include "..\..\Minecraft.h"
#include "..\..\User.h"
extern bool g_Win64DedicatedServerMode;
namespace
{
static unsigned long long GetNowMs64()
{
return (unsigned long long)GetTickCount64();
}
}
#endif
CPlatformNetworkManagerStub *g_pPlatformNetworkManager;
@ -14,6 +23,12 @@ CPlatformNetworkManagerStub *g_pPlatformNetworkManager;
void CPlatformNetworkManagerStub::NotifyPlayerJoined(IQNetPlayer *pQNetPlayer )
{
if (pQNetPlayer == NULL)
{
app.DebugPrintf("NotifyPlayerJoined called with NULL player\n");
return;
}
const char * pszDescription;
// 4J Stu - We create a fake socket for every where that we need an INBOUND queue of game data. Outbound
@ -94,7 +109,7 @@ void CPlatformNetworkManagerStub::NotifyPlayerJoined(IQNetPlayer *pQNetPlayer )
if( m_pIQNet->IsHost() )
{
// 4J-PB - only the host should do this
// g_NetworkManager.UpdateAndSetGameSessionData();
g_NetworkManager.UpdateAndSetGameSessionData();
SystemFlagAddPlayer( networkPlayer );
}
@ -121,6 +136,12 @@ void CPlatformNetworkManagerStub::NotifyPlayerJoined(IQNetPlayer *pQNetPlayer )
void CPlatformNetworkManagerStub::NotifyPlayerLeaving(IQNetPlayer *pQNetPlayer)
{
if (pQNetPlayer == NULL)
{
app.DebugPrintf("NotifyPlayerLeaving called with NULL player\n");
return;
}
app.DebugPrintf("Player 0x%p \"%ls\" leaving.\n", pQNetPlayer, pQNetPlayer->GetGamertag());
INetworkPlayer *networkPlayer = getNetworkPlayer(pQNetPlayer);
@ -148,6 +169,12 @@ void CPlatformNetworkManagerStub::NotifyPlayerLeaving(IQNetPlayer *pQNetPlayer)
}
removeNetworkPlayer(pQNetPlayer);
if (m_pIQNet->IsHost())
{
// Exclude the leaving player from advertised count immediately.
g_NetworkManager.UpdateAndSetGameSessionData(networkPlayer);
}
}
bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkManager, int flagIndexSize)
@ -164,6 +191,13 @@ bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkMa
m_bLeavingGame = false;
m_bLeaveGameOnTick = false;
m_bHostChanged = false;
#ifdef _WINDOWS64
m_bTransferPending = false;
m_bTransferLeaving = false;
m_transferHostIp[0] = 0;
m_transferHostPort = 0;
m_transferSuppressErrorsUntilMs = 0;
#endif
m_bSearchResultsReady = false;
m_bSearchPending = false;
@ -213,6 +247,46 @@ void CPlatformNetworkManagerStub::DoWork()
{
#ifdef _WINDOWS64
extern QNET_STATE _iQNetStubState;
if (m_bTransferPending)
{
if (g_NetworkManager.IsInSession())
{
if (!m_bTransferLeaving)
{
m_bTransferLeaving = true;
app.DebugPrintf("Win64 LAN: Transfer requested to %s:%d, leaving current session\n",
m_transferHostIp, m_transferHostPort);
g_NetworkManager.LeaveGame(false);
}
return;
}
FriendSessionInfo targetSession;
memset(&targetSession, 0, sizeof(targetSession));
strncpy_s(targetSession.data.hostIP, sizeof(targetSession.data.hostIP), m_transferHostIp, _TRUNCATE);
targetSession.data.hostPort = m_transferHostPort;
wcsncpy_s(targetSession.data.hostName, XUSER_NAME_SIZE, L"Server Transfer", _TRUNCATE);
targetSession.data.netVersion = MINECRAFT_NET_VERSION;
targetSession.data.isJoinable = true;
targetSession.data.isReadyToJoin = true;
int primaryPad = ProfileManager.GetPrimaryPad();
if (primaryPad < 0)
{
primaryPad = 0;
}
const int localUsersMask = GetLocalPlayerMask(primaryPad);
const int joinResult = JoinGame(&targetSession, localUsersMask, ProfileManager.GetLockedProfile());
app.DebugPrintf("Win64 LAN: Transfer join result=%d for %s:%d\n",
joinResult, m_transferHostIp, m_transferHostPort);
m_bTransferPending = false;
m_bTransferLeaving = false;
m_transferHostIp[0] = 0;
m_transferHostPort = 0;
m_transferSuppressErrorsUntilMs = GetNowMs64() + 10000ULL;
}
if (_iQNetStubState == QNET_STATE_SESSION_STARTING && app.GetGameStarted())
{
_iQNetStubState = QNET_STATE_GAME_PLAY;
@ -236,8 +310,21 @@ void CPlatformNetworkManagerStub::DoWork()
qnetPlayer->m_gamertag[0] = 0;
qnetPlayer->SetCustomDataValue(0);
WinsockNetLayer::PushFreeSmallId(disconnectedSmallId);
if (IQNet::s_playerCount > 1)
IQNet::s_playerCount--;
// Recompute active slot span instead of blindly decrementing.
// A lower smallId can disconnect while higher smallIds are still active.
DWORD highestActive = 1;
for (DWORD idx = 1; idx < MINECRAFT_NET_MAX_PLAYERS; ++idx)
{
if (IQNet::m_player[idx].GetCustomDataValue() != 0)
{
highestActive = idx + 1;
}
}
IQNet::s_playerCount = highestActive;
app.DebugPrintf("Win64 LAN: Recomputed active player slot span to %u after disconnect smallId=%u\n",
(unsigned int)IQNet::s_playerCount,
(unsigned int)disconnectedSmallId);
}
}
}
@ -321,6 +408,14 @@ bool CPlatformNetworkManagerStub::LeaveGame(bool bMigrateHost)
m_machineQNetPrimaryPlayers.clear();
SystemFlagReset();
#ifdef _WINDOWS64
// Clear all back-pointers from IQNet slots to deleted network players.
for (int idx = 0; idx < MINECRAFT_NET_MAX_PLAYERS; ++idx)
{
IQNet::m_player[idx].SetCustomDataValue(0);
}
#endif
#ifdef _WINDOWS64
WinsockNetLayer::Shutdown();
WinsockNetLayer::Initialize();
@ -356,13 +451,26 @@ void CPlatformNetworkManagerStub::HostGame(int localUsersMask, bool bOnlineGame,
_HostGame( localUsersMask, publicSlots, privateSlots );
#ifdef _WINDOWS64
int port = WIN64_NET_DEFAULT_PORT;
unsigned char advertiseMaxPlayers = publicSlots;
if (advertiseMaxPlayers == 0 || advertiseMaxPlayers > MINECRAFT_NET_MAX_PLAYERS)
{
advertiseMaxPlayers = MINECRAFT_NET_MAX_PLAYERS;
}
g_Win64MultiplayerMaxPlayers = (int)advertiseMaxPlayers;
int port = g_Win64MultiplayerPort;
if (port <= 0)
{
port = WIN64_NET_DEFAULT_PORT;
}
if (!WinsockNetLayer::IsActive())
WinsockNetLayer::HostGame(port);
const wchar_t *hostName = IQNet::m_player[0].m_gamertag;
unsigned int settings = app.GetGameHostOption(eGameHostOption_All);
WinsockNetLayer::StartAdvertising(port, hostName, settings, 0, 0, MINECRAFT_NET_VERSION);
WinsockNetLayer::StartAdvertising(port, hostName, settings, 0, 0, MINECRAFT_NET_VERSION, advertiseMaxPlayers);
UpdateAndSetGameSessionData();
#endif
}
@ -401,6 +509,9 @@ int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo *searchResult, int l
if (!WinsockNetLayer::JoinGame(hostIP, hostPort))
{
app.DebugPrintf("Win64 LAN: Failed to connect to %s:%d\n", hostIP, hostPort);
// Reset transient join state so a failed attempt does not poison subsequent joins.
m_pIQNet->EndGame();
WinsockNetLayer::StartDiscovery();
return CGameNetworkManager::JOINGAME_FAIL_GENERAL;
}
@ -481,44 +592,40 @@ bool CPlatformNetworkManagerStub::_RunNetworkGame()
void CPlatformNetworkManagerStub::UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving /*= NULL*/)
{
// DWORD playerCount = m_pIQNet->GetPlayerCount();
//
// if( this->m_bLeavingGame )
// return;
//
// if( GetHostPlayer() == NULL )
// return;
//
// for(unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i)
// {
// if( i < playerCount )
// {
// INetworkPlayer *pNetworkPlayer = GetPlayerByIndex(i);
//
// // We can call this from NotifyPlayerLeaving but at that point the player is still considered in the session
// if( pNetworkPlayer != pNetworkPlayerLeaving )
// {
// m_hostGameSessionData.players[i] = ((NetworkPlayerXbox *)pNetworkPlayer)->GetUID();
//
// char *temp;
// temp = (char *)wstringtofilename( pNetworkPlayer->GetOnlineName() );
// memcpy(m_hostGameSessionData.szPlayers[i],temp,XUSER_NAME_SIZE);
// }
// else
// {
// m_hostGameSessionData.players[i] = NULL;
// memset(m_hostGameSessionData.szPlayers[i],0,XUSER_NAME_SIZE);
// }
// }
// else
// {
// m_hostGameSessionData.players[i] = NULL;
// memset(m_hostGameSessionData.szPlayers[i],0,XUSER_NAME_SIZE);
// }
// }
//
// m_hostGameSessionData.hostPlayerUID = ((NetworkPlayerXbox *)GetHostPlayer())->GetQNetPlayer()->GetXuid();
// m_hostGameSessionData.m_uiGameHostSettings = app.GetGameHostOption(eGameHostOption_All);
#ifdef _WINDOWS64
if (this->m_bLeavingGame || !m_pIQNet->IsHost() || !WinsockNetLayer::IsHosting())
{
return;
}
BYTE advertisedCount = (BYTE)m_pIQNet->GetPlayerCount();
if (g_Win64DedicatedServerMode && advertisedCount > 0)
{
// Dedicated host keeps slot 0 active internally for network scheduling,
// but should not be shown as an in-game player in server browser counts.
--advertisedCount;
}
if (pNetworkPlayerLeaving != NULL && advertisedCount > 0)
{
--advertisedCount;
}
if (advertisedCount == 0 && !g_Win64DedicatedServerMode)
{
advertisedCount = 1;
}
extern QNET_STATE _iQNetStubState;
const BYTE maxPlayers = WinsockNetLayer::GetMaxPlayers();
const bool joinable = (_iQNetStubState == QNET_STATE_GAME_PLAY) && (advertisedCount < maxPlayers);
const unsigned int advertisedSettings = app.GetGameHostOption(eGameHostOption_All);
WinsockNetLayer::UpdateAdvertiseGameSettings(advertisedSettings);
WinsockNetLayer::UpdateAdvertisePlayerCount(advertisedCount);
WinsockNetLayer::UpdateAdvertiseJoinable(joinable);
app.DebugPrintf("Win64 LAN: Updated advertised session data (players=%d, joinable=%d, settings=0x%08X)\n",
(int)advertisedCount, joinable ? 1 : 0, advertisedSettings);
#endif
}
int CPlatformNetworkManagerStub::RemovePlayerOnSocketClosedThreadProc( void* lpParam )
@ -806,12 +913,102 @@ INetworkPlayer *CPlatformNetworkManagerStub::GetPlayerByIndex(int playerIndex)
INetworkPlayer * CPlatformNetworkManagerStub::GetPlayerByXuid(PlayerUID xuid)
{
return getNetworkPlayer( m_pIQNet->GetPlayerByXuid(xuid)) ;
IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerByXuid(xuid);
#ifdef _WINDOWS64
if (qnetPlayer == NULL)
{
const unsigned __int64 kWin64StubXuidBase = 0xe000d45248242f2eULL;
const unsigned __int64 uxuid = (unsigned __int64)xuid;
if (uxuid >= kWin64StubXuidBase)
{
const unsigned __int64 delta = uxuid - kWin64StubXuidBase;
if (delta < (unsigned __int64)MINECRAFT_NET_MAX_PLAYERS)
{
const BYTE smallId = (BYTE)delta;
// Clients can legitimately resolve remote players by XUID before the
// platform join callback has materialized the slot's NetworkPlayer.
// Hosts keep the stricter check to avoid creating phantom entries.
const bool slotActive = (!m_pIQNet->IsHost()) ||
(smallId == 0) ||
(IQNet::m_player[smallId].GetCustomDataValue() != 0);
if (slotActive)
{
qnetPlayer = &IQNet::m_player[smallId];
qnetPlayer->m_smallId = smallId;
if (smallId == 0)
{
qnetPlayer->m_isHostPlayer = true;
qnetPlayer->m_isRemote = !m_pIQNet->IsHost();
}
else
{
const BYTE localSmallId = WinsockNetLayer::GetLocalSmallId();
const bool isLocalSlot = (!m_pIQNet->IsHost() && (smallId == localSmallId));
qnetPlayer->m_isHostPlayer = false;
qnetPlayer->m_isRemote = !isLocalSlot;
}
if (smallId >= IQNet::s_playerCount)
{
IQNet::s_playerCount = smallId + 1;
}
app.DebugPrintf("Win64 LAN: Materialized player slot from XUID (smallId=%u, isRemote=%d)\n",
(unsigned int)smallId,
qnetPlayer->m_isRemote ? 1 : 0);
}
}
}
}
#endif
if (qnetPlayer == NULL)
{
return NULL;
}
INetworkPlayer *networkPlayer = getNetworkPlayer(qnetPlayer);
#ifdef _WINDOWS64
if (networkPlayer == NULL)
{
NotifyPlayerJoined(qnetPlayer);
networkPlayer = getNetworkPlayer(qnetPlayer);
app.DebugPrintf("Win64 LAN: Lazily created network player from XUID (smallId=%u)\n",
(unsigned int)qnetPlayer->GetSmallId());
}
#endif
return networkPlayer;
}
INetworkPlayer * CPlatformNetworkManagerStub::GetPlayerBySmallId(unsigned char smallId)
{
return getNetworkPlayer(m_pIQNet->GetPlayerBySmallId(smallId));
IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(smallId);
if (qnetPlayer == NULL)
{
return NULL;
}
INetworkPlayer *networkPlayer = getNetworkPlayer(qnetPlayer);
#ifdef _WINDOWS64
if (networkPlayer == NULL && smallId != 0 && !m_pIQNet->IsHost())
{
const BYTE localSmallId = WinsockNetLayer::GetLocalSmallId();
const bool isLocalSlot = (smallId == localSmallId);
qnetPlayer->m_smallId = smallId;
qnetPlayer->m_isHostPlayer = false;
qnetPlayer->m_isRemote = !isLocalSlot;
if (smallId >= IQNet::s_playerCount)
{
IQNet::s_playerCount = smallId + 1;
}
// On Win64 clients we may receive player/entity packets for remote users before a
// platform-layer "player joined" callback has been issued for that slot.
NotifyPlayerJoined(qnetPlayer);
networkPlayer = getNetworkPlayer(qnetPlayer);
app.DebugPrintf("Win64 LAN: Lazily created network player for smallId=%u\n", (unsigned int)smallId);
}
#endif
return networkPlayer;
}
INetworkPlayer *CPlatformNetworkManagerStub::GetHostPlayer()
@ -857,3 +1054,39 @@ bool CPlatformNetworkManagerStub::IsReadyToPlayOrIdle()
{
return true;
}
#ifdef _WINDOWS64
void CPlatformNetworkManagerStub::QueueServerTransfer(const char *hostIp, int hostPort)
{
if (hostIp == NULL || hostIp[0] == 0 || hostPort <= 0)
{
return;
}
strncpy_s(m_transferHostIp, sizeof(m_transferHostIp), hostIp, _TRUNCATE);
m_transferHostPort = hostPort;
m_bTransferPending = true;
m_bTransferLeaving = false;
m_transferSuppressErrorsUntilMs = GetNowMs64() + 10000ULL;
app.DebugPrintf("Win64 LAN: Queued server transfer target %s:%d\n", m_transferHostIp, m_transferHostPort);
}
void CPlatformNetworkManagerStub::RequestServerTransfer(const char *hostIp, int hostPort)
{
if (g_pPlatformNetworkManager == NULL)
{
return;
}
g_pPlatformNetworkManager->QueueServerTransfer(hostIp, hostPort);
}
bool CPlatformNetworkManagerStub::IsServerTransferInProgress()
{
return (g_pPlatformNetworkManager != NULL) &&
(g_pPlatformNetworkManager->m_bTransferPending ||
g_pPlatformNetworkManager->m_bTransferLeaving ||
(GetNowMs64() < g_pPlatformNetworkManager->m_transferSuppressErrorsUntilMs));
}
#endif

View file

@ -48,6 +48,10 @@ public:
virtual bool IsPrivateGame() { return m_bIsPrivateGame; }
virtual bool IsLeavingGame() { return m_bLeavingGame; }
virtual void ResetLeavingGame() { m_bLeavingGame = false; }
#ifdef _WINDOWS64
static void RequestServerTransfer(const char *hostIp, int hostPort);
static bool IsServerTransferInProgress();
#endif
virtual void RegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam);
virtual void UnRegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam);
@ -61,6 +65,9 @@ private:
virtual bool _LeaveGame(bool bMigrateHost, bool bLeaveRoom);
virtual void _HostGame(int dwUsersMask, unsigned char publicSlots = MINECRAFT_NET_MAX_PLAYERS, unsigned char privateSlots = 0);
virtual bool _StartGame();
#ifdef _WINDOWS64
void QueueServerTransfer(const char *hostIp, int hostPort);
#endif
IQNet * m_pIQNet; // pointer to QNet interface
@ -72,6 +79,13 @@ private:
bool m_bLeaveGameOnTick;
bool m_migrateHostOnLeave;
bool m_bHostChanged;
#ifdef _WINDOWS64
bool m_bTransferPending;
bool m_bTransferLeaving;
char m_transferHostIp[64];
int m_transferHostPort;
unsigned long long m_transferSuppressErrorsUntilMs;
#endif
bool m_bIsOfflineGame;
bool m_bIsPrivateGame;
@ -166,6 +180,17 @@ public:
void NotifyPlayerLeaving( IQNetPlayer *pQNetPlayer );
#ifndef _XBOX
void FakeLocalPlayerJoined() { NotifyPlayerJoined(m_pIQNet->GetLocalPlayerByUserIndex(0)); }
void FakeLocalPlayerJoined()
{
IQNetPlayer *player = m_pIQNet->GetLocalPlayerByUserIndex(0);
if (player == NULL)
{
// Dedicated/headless host can suppress slot 0 from "active local player"
// queries. Fall back to the canonical host slot so platform bookkeeping
// can still be initialized.
player = &IQNet::m_player[0];
}
NotifyPlayerJoined(player);
}
#endif
};

View file

@ -15,9 +15,6 @@
#ifdef _WINDOWS64
#include "..\..\KeyboardMouseInput.h"
#include "UI.h"
SavedInventoryCursorPos g_savedInventoryCursorPos = { 0.0f, 0.0f, false };
#endif
IUIScene_AbstractContainerMenu::IUIScene_AbstractContainerMenu()
@ -473,26 +470,20 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
#ifdef _WINDOWS64
if (!g_KBMInput.IsMouseGrabbed())
{
int deltaX = g_KBMInput.GetMouseDeltaX();
int deltaY = g_KBMInput.GetMouseDeltaY();
extern HWND g_hWnd;
RECT rc;
GetClientRect(g_hWnd, &rc);
int winW = rc.right - rc.left;
int winH = rc.bottom - rc.top;
if (winW > 0 && winH > 0)
int dx = g_KBMInput.GetMouseDeltaX();
int dy = g_KBMInput.GetMouseDeltaY();
if (dx != 0 || dy != 0)
{
float scaleX = (float)getMovieWidth() / (float)winW;
float scaleY = (float)getMovieHeight() / (float)winH;
float sensitivity = (float)app.GetGameSettings(iPad, eGameSetting_Sensitivity_InMenu) / 100.0f;
float mouseScale = sensitivity * 1.0f;
vPointerPos.x += (float)dx * mouseScale;
vPointerPos.y += (float)dy * mouseScale;
if (vPointerPos.x < m_fPointerMinX) vPointerPos.x = m_fPointerMinX;
else if (vPointerPos.x > m_fPointerMaxX) vPointerPos.x = m_fPointerMaxX;
if (vPointerPos.y < m_fPointerMinY) vPointerPos.y = m_fPointerMinY;
else if (vPointerPos.y > m_fPointerMaxY) vPointerPos.y = m_fPointerMaxY;
vPointerPos.x += (float)deltaX * scaleX;
vPointerPos.y += (float)deltaY * scaleY;
}
if (deltaX != 0 || deltaY != 0)
{
bStickInput = true;
}
}
@ -715,11 +706,7 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
// If there is no stick input, and we are over a slot, then snap pointer to slot centre.
// 4J - TomK - only if this particular component allows so!
#ifdef _WINDOWS64
if(g_KBMInput.IsMouseGrabbed() && CanHaveFocus(eSectionUnderPointer))
#else
if(CanHaveFocus(eSectionUnderPointer))
#endif
{
vPointerPos.x = vSnapPos.x;
vPointerPos.y = vSnapPos.y;
@ -727,8 +714,7 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
}
}
// Clamp to pointer extents
// Clamp to pointer extents.
if ( vPointerPos.x < m_fPointerMinX ) vPointerPos.x = m_fPointerMinX;
else if ( vPointerPos.x > m_fPointerMaxX ) vPointerPos.x = m_fPointerMaxX;
if ( vPointerPos.y < m_fPointerMinY ) vPointerPos.y = m_fPointerMinY;
@ -1250,15 +1236,8 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
// Offset back to image top left.
#ifdef _WINDOWS64
if (g_KBMInput.IsMouseGrabbed())
{
#endif
vPointerPos.x -= m_fPointerImageOffsetX;
vPointerPos.y -= m_fPointerImageOffsetY;
#ifdef _WINDOWS64
}
#endif
vPointerPos.x -= m_fPointerImageOffsetX;
vPointerPos.y -= m_fPointerImageOffsetY;
// Update pointer position.
// 4J-PB - do not allow sub pixel positions or we get broken lines in box edges

View file

@ -1,15 +1,5 @@
#pragma once
#ifdef _WINDOWS64
struct SavedInventoryCursorPos
{
float x;
float y;
bool hasSavedPos;
};
extern SavedInventoryCursorPos g_savedInventoryCursorPos;
#endif
// Uncomment to enable tap input detection to jump 1 slot. Doesn't work particularly well yet, and I feel the system does not need it.
// Would probably be required if we decide to slow down the pointer movement.
// 4J Stu - There was a request to be able to navigate the scenes with the dpad, so I have used much of the TAP_DETECTION
@ -230,6 +220,4 @@ protected:
public:
virtual int getPad() = 0;
virtual int getMovieWidth() = 0;
virtual int getMovieHeight() = 0;
};

View file

@ -10,6 +10,9 @@
#include "..\..\TexturePack.h"
#include "..\..\DLCTexturePack.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#ifdef _WINDOWS64
#include "..\Network\PlatformNetworkManagerStub.h"
#endif
int IUIScene_PauseMenu::ExitGameDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
@ -393,6 +396,14 @@ int IUIScene_PauseMenu::ExitWorldThreadProc( void* lpParameter )
// This function performs the meat of exiting from a level. It should be called from a thread other than the main thread.
void IUIScene_PauseMenu::_ExitWorld(LPVOID lpParameter)
{
#ifdef _WINDOWS64
if (CPlatformNetworkManagerStub::IsServerTransferInProgress())
{
app.DebugPrintf("Win64 LAN: Skipping _ExitWorld teardown during server transfer\n");
return;
}
#endif
Minecraft *pMinecraft=Minecraft::GetInstance();
int exitReasonStringId = pMinecraft->progressRenderer->getCurrentTitle();
@ -688,4 +699,4 @@ int IUIScene_PauseMenu::DisableAutosaveDialogReturned(void *pParam,int iPad,C4JS
app.SetAction(iPad,eAppAction_SaveGame);
}
return 0;
}
}

View file

@ -95,9 +95,14 @@ UIBitmapFont::UIBitmapFont( SFontData &sfontdata )
: UIAbstractBitmapFont( sfontdata.m_strFontName )
{
m_numGlyphs = sfontdata.m_uiGlyphCount;
m_cFontData = NULL;
BufferedImage bimg(sfontdata.m_wstrFilename);
int *bimgData = bimg.getData();
if (bimgData == NULL)
{
app.DebugPrintf("UIBitmapFont: missing texture data for '%s'\n", sfontdata.m_strFontName.c_str());
}
m_cFontData = new CFontData(sfontdata, bimgData);
@ -106,12 +111,27 @@ UIBitmapFont::UIBitmapFont( SFontData &sfontdata )
UIBitmapFont::~UIBitmapFont()
{
m_cFontData->release();
if (m_cFontData)
{
m_cFontData->release();
delete m_cFontData;
m_cFontData = NULL;
}
}
//Callback function type for returning vertical font metrics
IggyFontMetrics *UIBitmapFont::GetFontMetrics(IggyFontMetrics *metrics)
{
if (metrics == NULL)
{
return NULL;
}
if (m_cFontData == NULL || m_cFontData->getFontData() == NULL)
{
memset(metrics, 0, sizeof(*metrics));
return metrics;
}
//Description
// Vertical metrics for a font
//Members
@ -138,6 +158,11 @@ IggyFontMetrics *UIBitmapFont::GetFontMetrics(IggyFontMetrics *metrics)
//Callback function type for mapping 32-bit unicode code point to internal font glyph number; use IGGY_GLYPH_INVALID to mean "invalid character"
S32 UIBitmapFont::GetCodepointGlyph(U32 codepoint)
{
if (m_cFontData == NULL)
{
return 0;
}
// 4J-JEV: Change "right single quotation marks" to apostrophies.
if (codepoint == 0x2019) codepoint = 0x27;
@ -147,6 +172,16 @@ S32 UIBitmapFont::GetCodepointGlyph(U32 codepoint)
//Callback function type for returning horizontal metrics for each glyph
IggyGlyphMetrics * UIBitmapFont::GetGlyphMetrics(S32 glyph,IggyGlyphMetrics *metrics)
{
if (metrics == NULL)
{
return NULL;
}
if (m_cFontData == NULL || m_cFontData->getFontData() == NULL)
{
memset(metrics, 0, sizeof(*metrics));
return metrics;
}
// 4J-JEV: Information about 'Glyph Metrics'.
// http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-3.html - Overview.
// http://en.wikipedia.org/wiki/Kerning#Kerning_values - 'Font Units'
@ -196,6 +231,10 @@ IggyGlyphMetrics * UIBitmapFont::GetGlyphMetrics(S32 glyph,IggyGlyphMetrics *met
//Callback function type that should return true iff the glyph has no visible elements
rrbool UIBitmapFont::IsGlyphEmpty (S32 glyph)
{
if (m_cFontData == NULL)
{
return true;
}
if (m_cFontData->glyphIsWhitespace(glyph)) return true;
return false;//app.DebugPrintf("Is glyph %d empty? %s\n",glyph,isEmpty?"TRUE":"FALSE");
}
@ -214,6 +253,10 @@ F32 UIBitmapFont::GetKerningForGlyphPair(S32 first_glyph,S32 second_glyph)
//Callback function type used for reporting whether a bitmap supports a given glyph at the given scale
rrbool UIBitmapFont::CanProvideBitmap(S32 glyph,F32 pixel_scale)
{
if (m_cFontData == NULL || m_cFontData->getFontData() == NULL)
{
return false;
}
//app.DebugPrintf("Can provide bitmap for glyph %d at scale %f? %s\n",glyph,pixel_scale,canProvideBitmap?"TRUE":"FALSE");
return true;
}
@ -226,6 +269,16 @@ rrbool UIBitmapFont::CanProvideBitmap(S32 glyph,F32 pixel_scale)
// bitmap The structure to store the bitmap into
rrbool UIBitmapFont::GetGlyphBitmap(S32 glyph,F32 pixel_scale,IggyBitmapCharacter *bitmap)
{
if (bitmap == NULL)
{
return false;
}
if (m_cFontData == NULL || m_cFontData->getFontData() == NULL)
{
memset(bitmap, 0, sizeof(*bitmap));
return false;
}
//Description
// Data structure used to return to Iggy the bitmap to use for a glyph
//Members

View file

@ -10,7 +10,6 @@
#include "..\..\..\Minecraft.World\net.minecraft.world.entity.boss.enderdragon.h"
#ifdef _WINDOWS64
#include "..\..\KeyboardMouseInput.h"
#include "UIControl_Slider.h"
#endif
#include "..\..\EnderDragonRenderer.h"
#include "..\..\MultiPlayerLocalPlayer.h"
@ -690,100 +689,6 @@ void UIController::tickInput()
else
#endif
{
#ifdef _WINDOWS64
if (!g_KBMInput.IsMouseGrabbed())
{
UIScene *pScene = NULL;
for (int grp = 0; grp < eUIGroup_COUNT && !pScene; ++grp)
{
pScene = m_groups[grp]->GetTopScene(eUILayer_Debug);
if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Tooltips);
if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Error);
if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Alert);
if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Popup);
if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Fullscreen);
if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Scene);
}
if (pScene && pScene->getMovie())
{
Iggy *movie = pScene->getMovie();
F32 mouseX = (F32)g_KBMInput.GetMouseX();
F32 mouseY = (F32)g_KBMInput.GetMouseY();
extern HWND g_hWnd;
if (g_hWnd)
{
RECT rc;
GetClientRect(g_hWnd, &rc);
int winW = rc.right - rc.left;
int winH = rc.bottom - rc.top;
if (winW > 0 && winH > 0)
{
mouseX = mouseX * (m_fScreenWidth / (F32)winW);
mouseY = mouseY * (m_fScreenHeight / (F32)winH);
}
}
IggyFocusHandle currentFocus = IGGY_FOCUS_NULL;
IggyFocusableObject focusables[64];
S32 numFocusables = 0;
IggyPlayerGetFocusableObjects(movie, &currentFocus, focusables, 64, &numFocusables);
IggyFocusHandle hitObject = IGGY_FOCUS_NULL;
for (S32 i = 0; i < numFocusables; ++i)
{
if (mouseX >= focusables[i].x0 && mouseX <= focusables[i].x1 &&
mouseY >= focusables[i].y0 && mouseY <= focusables[i].y1)
{
hitObject = focusables[i].object;
break;
}
}
if (hitObject != IGGY_FOCUS_NULL && hitObject != currentFocus)
{
IggyPlayerSetFocusRS(movie, hitObject, 0);
}
if (g_KBMInput.IsMouseButtonDown(0) || g_KBMInput.IsMouseButtonPressed(0))
{
vector<UIControl *> *controls = pScene->GetControls();
if (controls)
{
for (size_t i = 0; i < controls->size(); i++)
{
UIControl *ctrl = (*controls)[i];
if (ctrl && ctrl->getControlType() == UIControl::eSlider && ctrl->getVisible())
{
S32 cx = ctrl->getXPos();
S32 cy = ctrl->getYPos();
S32 cw = ctrl->getWidth();
S32 ch = ctrl->getHeight();
if (mouseX >= cx && mouseX <= cx + cw &&
mouseY >= cy && mouseY <= cy + ch)
{
UIControl_Slider *pSlider = (UIControl_Slider *)ctrl;
float fNewSliderPos = (mouseX - (float)cx) / (float)pSlider->GetRealWidth();
if (fNewSliderPos < 0.0f) fNewSliderPos = 0.0f;
if (fNewSliderPos > 1.0f) fNewSliderPos = 1.0f;
pSlider->SetSliderTouchPos(fNewSliderPos);
break;
}
}
}
}
}
}
int wheel = g_KBMInput.GetMouseWheel();
if (wheel > 0)
handleKeyPress(0, ACTION_MENU_UP);
else if (wheel < 0)
handleKeyPress(0, ACTION_MENU_DOWN);
}
#endif
handleInput();
++m_accumulatedTicks;
}
@ -3145,4 +3050,4 @@ void UIController::SendTouchInput(unsigned int iPad, unsigned int key, bool bPre
}
#endif
#endif

View file

@ -148,24 +148,41 @@ CFontData::CFontData()
m_sFontData = NULL;
m_kerningTable = NULL;
m_pbRawImage = NULL;
m_pfAdvanceTable = NULL;
}
CFontData::CFontData(SFontData &sFontData, int *pbRawImage)
: m_unicodeMap( sFontData.m_uiGlyphCount + 2 )
{
this->m_sFontData = &sFontData;
m_kerningTable = NULL;
m_pbRawImage = NULL;
m_pfAdvanceTable = NULL;
// INITIALISE ALPHA CHANNEL //
// Glyph Archive (1Byte per pixel).
unsigned int archiveSize = sFontData.m_uiGlyphMapX * sFontData.m_uiGlyphMapY;
if (archiveSize == 0)
{
app.DebugPrintf("CFontData: invalid archive size for '%s'\n", sFontData.m_strFontName.c_str());
return;
}
this->m_pbRawImage = new unsigned char[archiveSize];
// 4J-JEV: Take the alpha channel from each pixel.
for (unsigned int i = 0; i < archiveSize; i++)
if (pbRawImage == NULL)
{
this->m_pbRawImage[i] = (pbRawImage[i] & 0xFF000000) >> 24;
app.DebugPrintf("CFontData: raw font image missing for '%s', using blank fallback\n", sFontData.m_strFontName.c_str());
memset(this->m_pbRawImage, 0, archiveSize);
}
else
{
// 4J-JEV: Take the alpha channel from each pixel.
for (unsigned int i = 0; i < archiveSize; i++)
{
this->m_pbRawImage[i] = (pbRawImage[i] & 0xFF000000) >> 24;
}
}
// CREATE UNICODE MAP //
@ -267,10 +284,17 @@ void CFontData::release()
delete [] m_kerningTable;
delete [] m_pfAdvanceTable;
delete [] m_pbRawImage;
m_kerningTable = NULL;
m_pfAdvanceTable = NULL;
m_pbRawImage = NULL;
}
const string CFontData::getFontName()
{
if (m_sFontData == NULL)
{
return "";
}
return m_sFontData->m_strFontName;
}
@ -289,11 +313,19 @@ unsigned short CFontData::getGlyphId(unsigned int unicodepoint)
unsigned int CFontData::getUnicode(unsigned short glyphId)
{
if (m_sFontData == NULL || glyphId >= m_sFontData->m_uiGlyphCount)
{
return 0;
}
return m_sFontData->Codepoints[glyphId];
}
unsigned char *CFontData::topLeftPixel(int row, int col)
{
if (m_pbRawImage == NULL || m_sFontData == NULL)
{
return NULL;
}
unsigned char *out = m_pbRawImage;
moveCursor(out, col * m_sFontData->m_uiGlyphWidth, row* m_sFontData->m_uiGlyphHeight);
return out;
@ -301,22 +333,40 @@ unsigned char *CFontData::topLeftPixel(int row, int col)
void CFontData::getPos(unsigned short glyphId, int &rowOut, int &colOut)
{
if (m_sFontData == NULL || m_sFontData->m_uiGlyphMapCols == 0)
{
rowOut = 0;
colOut = 0;
return;
}
rowOut = glyphId / m_sFontData->m_uiGlyphMapCols;
colOut = glyphId % m_sFontData->m_uiGlyphMapCols;
}
float CFontData::getAdvance(unsigned short glyphId)
{
if (m_pfAdvanceTable == NULL || m_sFontData == NULL || glyphId >= m_sFontData->m_uiGlyphCount)
{
return 0.0f;
}
return m_pfAdvanceTable[glyphId];
}
int CFontData::getWidth(unsigned short glyphId)
{
if (m_kerningTable == NULL || m_sFontData == NULL || glyphId >= m_sFontData->m_uiGlyphCount)
{
return 0;
}
return m_kerningTable[glyphId];
}
bool CFontData::glyphIsWhitespace(unsigned short glyphId)
{
if (m_sFontData == NULL || glyphId >= m_sFontData->m_uiGlyphCount)
{
return true;
}
return unicodeIsWhitespace( getUnicode(glyphId) );
}
@ -337,5 +387,9 @@ bool CFontData::unicodeIsWhitespace(unsigned int unicode)
void CFontData::moveCursor(unsigned char *&cursor, unsigned int dx, unsigned int dy)
{
if (m_sFontData == NULL || cursor == NULL)
{
return;
}
cursor += (dy * m_sFontData->m_uiGlyphMapX) + dx;
}

View file

@ -12,6 +12,7 @@ UIGroup::UIGroup(EUIGroup group, int iPad)
m_bIgnorePlayerJoinMenuDisplayed = false;
m_updateFocusStateCountdown = 0;
m_viewportType = C4JRender::VIEWPORT_TYPE_FULLSCREEN;
for(unsigned int i = 0; i < eUILayer_COUNT; ++i)
{
@ -31,16 +32,12 @@ UIGroup::UIGroup(EUIGroup group, int iPad)
m_tutorialPopup = (UIComponent_TutorialPopup *)m_layers[(int)eUILayer_Popup]->addComponent(m_iPad, eUIComponent_TutorialPopup);
m_hud = (UIScene_HUD *)m_layers[(int)eUILayer_HUD]->addComponent(m_iPad, eUIScene_HUD);
//m_layers[(int)eUILayer_Chat]->addComponent(m_iPad, eUIComponent_Chat);
}
else
{
m_pressStartToPlay = (UIComponent_PressStartToPlay *)m_layers[(int)eUILayer_Tooltips]->addComponent(0, eUIComponent_PressStartToPlay);
}
m_viewportType = C4JRender::VIEWPORT_TYPE_FULLSCREEN;
// 4J Stu - Pre-allocate this for cached rendering in scenes. It's horribly slow to do dynamically, but we should only need one
// per group as we will only be displaying one of these types of scenes at a time
m_commandBufferList = MemoryTracker::genLists(1);
@ -419,3 +416,4 @@ UIScene *UIGroup::FindScene(EUIScene sceneType)
return pScene;
}

View file

@ -109,8 +109,6 @@ public:
#ifdef __PSVITA__
UILayer *GetParentLayer() {return m_parentLayer;}
EUIGroup GetParentLayerGroup() {return m_parentLayer->m_parentGroup->GetGroup();}
#endif
#if defined(__PSVITA__) || defined(_WINDOWS64)
vector<UIControl *> *GetControls() {return &m_controls;}
#endif

View file

@ -2,10 +2,6 @@
#include "UI.h"
#include "UIScene_AbstractContainerMenu.h"
#ifdef _WINDOWS64
#include "..\..\KeyboardMouseInput.h"
#endif
#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.item.h"
#include "..\..\MultiplayerLocalPlayer.h"
@ -39,15 +35,6 @@ UIScene_AbstractContainerMenu::~UIScene_AbstractContainerMenu()
void UIScene_AbstractContainerMenu::handleDestroy()
{
app.DebugPrintf("UIScene_AbstractContainerMenu::handleDestroy\n");
#ifdef _WINDOWS64
g_savedInventoryCursorPos.x = m_pointerPos.x;
g_savedInventoryCursorPos.y = m_pointerPos.y;
g_savedInventoryCursorPos.hasSavedPos = true;
g_KBMInput.SetCursorHiddenForUI(false);
#endif
Minecraft *pMinecraft = Minecraft::GetInstance();
if( pMinecraft->localgameModes[m_iPad] != NULL )
{
@ -72,7 +59,6 @@ void UIScene_AbstractContainerMenu::handleDestroy()
ui.OverrideSFX(m_iPad,ACTION_MENU_RIGHT,false);
ui.OverrideSFX(m_iPad,ACTION_MENU_UP,false);
ui.OverrideSFX(m_iPad,ACTION_MENU_DOWN,false);
}
void UIScene_AbstractContainerMenu::InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex)
@ -81,9 +67,6 @@ void UIScene_AbstractContainerMenu::InitDataAssociations(int iPad, AbstractConta
void UIScene_AbstractContainerMenu::PlatformInitialize(int iPad, int startIndex)
{
#ifdef _WINDOWS64
g_KBMInput.SetCursorHiddenForUI(true);
#endif
m_labelInventory.init( app.GetString(IDS_INVENTORY) );
@ -123,8 +106,8 @@ void UIScene_AbstractContainerMenu::PlatformInitialize(int iPad, int startIndex)
#ifdef __ORBIS__
// we need to map the touchpad rectangle to the UI rectangle. While it works great for the creative menu, it is much too sensitive for the smaller menus.
//X coordinate of the touch point (0 to 1919)
//Y coordinate of the touch point (0 to 941: DUALSHOCK<EFBFBD>4 wireless controllers and the CUH-ZCT1J/CAP-ZCT1J/CAP-ZCT1U controllers for the PlayStation<6F>4 development tool,
//0 to 753: JDX-1000x series controllers for the PlayStation<EFBFBD>4 development tool,)
//Y coordinate of the touch point (0 to 941: DUALSHOCK®4 wireless controllers and the CUH-ZCT1J/CAP-ZCT1J/CAP-ZCT1U controllers for the PlayStation®4 development tool,
//0 to 753: JDX-1000x series controllers for the PlayStation®4 development tool,)
m_fTouchPadMulX=fPanelWidth/1919.0f;
m_fTouchPadMulY=fPanelHeight/941.0f;
m_fTouchPadDeadZoneX=15.0f*m_fTouchPadMulX;
@ -168,30 +151,17 @@ void UIScene_AbstractContainerMenu::PlatformInitialize(int iPad, int startIndex)
//m_pointerControl->SetPosition( &vPointerPos );
m_pointerPos = vPointerPos;
#ifdef _WINDOWS64
if (g_savedInventoryCursorPos.hasSavedPos)
{
m_pointerPos.x = g_savedInventoryCursorPos.x;
m_pointerPos.y = g_savedInventoryCursorPos.y;
if (m_pointerPos.x < m_fPointerMinX) m_pointerPos.x = m_fPointerMinX;
if (m_pointerPos.x > m_fPointerMaxX) m_pointerPos.x = m_fPointerMaxX;
if (m_pointerPos.y < m_fPointerMinY) m_pointerPos.y = m_fPointerMinY;
if (m_pointerPos.y > m_fPointerMaxY) m_pointerPos.y = m_fPointerMaxY;
}
#endif
IggyEvent mouseEvent;
S32 width, height;
m_parentLayer->getRenderDimensions(width, height);
S32 x = m_pointerPos.x*((float)width/m_movieWidth);
S32 y = m_pointerPos.y*((float)height/m_movieHeight);
S32 y = m_pointerPos.y*((float)height/m_movieHeight);
IggyMakeEventMouseMove( &mouseEvent, x, y);
IggyEventResult result;
IggyPlayerDispatchEventRS ( getMovie() , &mouseEvent , &result );
#ifdef USE_POINTER_ACCEL
#ifdef USE_POINTER_ACCEL
m_fPointerVelX = 0.0f;
m_fPointerVelY = 0.0f;
m_fPointerAccelX = 0.0f;
@ -208,10 +178,8 @@ void UIScene_AbstractContainerMenu::tick()
IggyEvent mouseEvent;
S32 width, height;
m_parentLayer->getRenderDimensions(width, height);
S32 x = (S32)(m_pointerPos.x * ((float)width / m_movieWidth));
S32 y = (S32)(m_pointerPos.y * ((float)height / m_movieHeight));
S32 x = m_pointerPos.x*((float)width/m_movieWidth);
S32 y = m_pointerPos.y*((float)height/m_movieHeight);
IggyMakeEventMouseMove( &mouseEvent, x, y);
// 4J Stu - This seems to be broken on Durango, so do it ourself
@ -224,7 +192,6 @@ void UIScene_AbstractContainerMenu::tick()
IggyPlayerDispatchEventRS ( getMovie() , &mouseEvent , &result );
}
void UIScene_AbstractContainerMenu::render(S32 width, S32 height, C4JRender::eViewportType viewpBort)
{
m_cacheSlotRenders = true;

View file

@ -36,8 +36,6 @@ public:
virtual void handleDestroy();
int getPad() { return m_iPad; }
int getMovieWidth() { return m_movieWidth; }
int getMovieHeight() { return m_movieHeight; }
bool getIgnoreInput() { return m_bIgnoreInput; }
void setIgnoreInput(bool bVal) { m_bIgnoreInput=bVal; }

View file

@ -2,6 +2,9 @@
#include "UI.h"
#include "UIScene_ConnectingProgress.h"
#include "..\..\Minecraft.h"
#ifdef _WINDOWS64
#include "..\Network\PlatformNetworkManagerStub.h"
#endif
UIScene_ConnectingProgress::UIScene_ConnectingProgress(int iPad, void *_initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
{
@ -113,6 +116,16 @@ void UIScene_ConnectingProgress::handleTimerComplete(int id)
// Check if the connection failed
Minecraft *pMinecraft = Minecraft::GetInstance();
#ifdef _WINDOWS64
if (CPlatformNetworkManagerStub::IsServerTransferInProgress())
{
pMinecraft->m_connectionFailed[m_iPad] = false;
pMinecraft->m_connectionFailedReason[m_iPad] = DisconnectPacket::eDisconnect_None;
addTimer(0, m_timerTime);
return;
}
#endif
if( pMinecraft->m_connectionFailed[m_iPad] || !g_NetworkManager.IsInSession() )
{
@ -132,6 +145,9 @@ void UIScene_ConnectingProgress::handleTimerComplete(int id)
case DisconnectPacket::eDisconnect_Kicked:
exitReasonStringId = IDS_DISCONNECTED_KICKED;
break;
case DisconnectPacket::eDisconnect_Banned:
exitReasonStringId = IDS_DISCONNECTED_BANNED;
break;
case DisconnectPacket::eDisconnect_NoUGC_AllLocal:
exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL;
break;

View file

@ -1,8 +1,10 @@
#include "stdafx.h"
#include "UI.h"
#include "UIScene_LoadOrJoinMenu.h"
#include <cwctype>
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "..\..\..\Minecraft.World\LevelSettings.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.item.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.level.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.level.chunk.storage.h"
@ -11,9 +13,14 @@
#include "..\..\..\Minecraft.World\ConsoleSaveFileSplit.h"
#include "..\..\ProgressRenderer.h"
#include "..\..\MinecraftServer.h"
#include "..\..\User.h"
#include "..\..\Options.h"
#include "..\..\TexturePackRepository.h"
#include "..\..\TexturePack.h"
#include "..\Network\SessionInfo.h"
#ifdef _WINDOWS64
#include "..\..\Windows64\Network\WinsockNetLayer.h"
#endif
#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
#include "Common\Network\Sony\SonyHttp.h"
#include "Common\Network\Sony\SonyRemoteStorage.h"
@ -25,6 +32,79 @@
#include "message_dialog.h"
#endif
namespace
{
// Custom, Windows64-only metadata packed into the host settings bitfield so LAN browser rows
// can show the selected LCE minigame type.
const unsigned int MINIGAME_SETTINGS_FLAG = 0x80000000u;
const unsigned int MINIGAME_SETTINGS_TYPE_MASK = 0x70000000u;
const unsigned int MINIGAME_SETTINGS_TYPE_SHIFT = 28u;
const unsigned int MINIGAME_SETTINGS_ROLE_MASK = 0x0C000000u;
const unsigned int MINIGAME_SETTINGS_ROLE_SHIFT = 26u;
const unsigned int MINIGAME_SETTINGS_QUEUE_MASK = 0x03000000u;
const unsigned int MINIGAME_SETTINGS_QUEUE_SHIFT = 24u;
const unsigned int MINIGAME_ROLE_HUB = 0u;
const unsigned int MINIGAME_ROLE_MATCH = 1u;
const wchar_t *GetQueueLabelFromSettings(unsigned int gameHostSettings)
{
const unsigned int queueMode = (gameHostSettings & MINIGAME_SETTINGS_QUEUE_MASK) >> MINIGAME_SETTINGS_QUEUE_SHIFT;
switch(queueMode)
{
case 0: return L"Solo";
case 1: return L"Doubles";
case 2: return L"Squads";
case 3: return L"Practice";
default: return L"Unknown";
}
}
const wchar_t *GetMinigameNameFromSettings(unsigned int gameHostSettings)
{
if ((gameHostSettings & MINIGAME_SETTINGS_FLAG) == 0)
{
return L"Unknown";
}
const unsigned int minigameIndex = (gameHostSettings & MINIGAME_SETTINGS_TYPE_MASK) >> MINIGAME_SETTINGS_TYPE_SHIFT;
switch(minigameIndex)
{
case 0: return L"Battle";
case 1: return L"Tumble";
case 2: return L"Glide";
case 3:
{
const unsigned int role = (gameHostSettings & MINIGAME_SETTINGS_ROLE_MASK) >> MINIGAME_SETTINGS_ROLE_SHIFT;
if (role == MINIGAME_ROLE_MATCH)
{
static wchar_t bedwarsMatchLabel[64];
swprintf_s(bedwarsMatchLabel, 64, L"Bedwars %ls Match", GetQueueLabelFromSettings(gameHostSettings));
return bedwarsMatchLabel;
}
return L"Bedwars Hub";
}
default: return L"Unknown";
}
}
wstring TrimWhitespace(const wstring &input)
{
size_t first = 0;
while(first < input.length() && std::iswspace(input[first]))
{
++first;
}
size_t last = input.length();
while(last > first && std::iswspace(input[last - 1]))
{
--last;
}
return input.substr(first, last - first);
}
}
#ifdef SONY_REMOTE_STORAGE_DOWNLOAD
unsigned long UIScene_LoadOrJoinMenu::m_ulFileSize=0L;
@ -119,6 +199,7 @@ UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer
m_bAllLoaded = false;
m_bRetrievingSaveThumbnails = false;
m_bSaveThumbnailReady = false;
m_bMinigamesMode = false;
m_bExitScene=false;
m_pSaveDetails=NULL;
m_bSavesDisplayed=false;
@ -133,6 +214,22 @@ UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer
m_bSaveTransferInProgress=false;
#endif
m_eAction = eAction_None;
m_pDirectConnectSession = NULL;
LoadOrJoinMenuInitData *loadOrJoinInit = (LoadOrJoinMenuInitData *)initData;
if(loadOrJoinInit != NULL &&
loadOrJoinInit->magic == LOAD_OR_JOIN_MENU_INIT_MAGIC &&
loadOrJoinInit->bMinigamesMode)
{
m_bMinigamesMode = true;
}
if(m_bMinigamesMode)
{
m_labelSavesListTitle.init(L"Create Minigame Server");
m_labelJoinListTitle.init(L"Server Browser");
m_labelNoGames.init(L"No servers found");
}
m_bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad);
@ -164,7 +261,11 @@ UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer
#endif
// block input if we're waiting for DLC to install, and wipe the saves list. The end of dlc mounting custom message will fill the list again
if(app.StartInstallDLCProcess(m_iPad)==true || app.DLCInstallPending())
if(m_bMinigamesMode)
{
Initialise();
}
else if(app.StartInstallDLCProcess(m_iPad)==true || app.DLCInstallPending())
{
// if we're waiting for DLC to mount, don't fill the save list. The custom message on end of dlc mounting will do that
m_bIgnoreInput = true;
@ -192,7 +293,7 @@ UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer
MinecraftServer::resetFlags();
// If we're not ignoring input, then we aren't still waiting for the DLC to mount, and can now check for corrupt dlc. Otherwise this will happen when the dlc has finished mounting.
if( !m_bIgnoreInput)
if( !m_bIgnoreInput && !m_bMinigamesMode)
{
app.m_dlcManager.checkForCorruptDLCAndAlert();
}
@ -299,10 +400,24 @@ UIScene_LoadOrJoinMenu::~UIScene_LoadOrJoinMenu()
}
delete [] m_saveDetails;
}
delete m_pDirectConnectSession;
m_pDirectConnectSession = NULL;
}
void UIScene_LoadOrJoinMenu::updateTooltips()
{
if(m_bMinigamesMode)
{
int iY = -1;
if(DoesGamesListHaveFocus() && m_buttonListGames.getItemCount() > 0)
{
iY = IDS_TOOLTIPS_VIEW_GAMERCARD;
}
ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, iY);
return;
}
// update the tooltips
// if the saves list has focus, then we should show the Delete Save tooltip
// if the games list has focus, then we should the the View Gamercard tooltip
@ -391,6 +506,12 @@ void UIScene_LoadOrJoinMenu::updateTooltips()
//
void UIScene_LoadOrJoinMenu::Initialise()
{
if(m_bMinigamesMode)
{
InitialiseMinigamesMode();
return;
}
m_iSaveListIndex = 0;
m_iGameListIndex = 0;
@ -445,6 +566,35 @@ void UIScene_LoadOrJoinMenu::Initialise()
app.m_dlcManager.checkForCorruptDLCAndAlert();
}
void UIScene_LoadOrJoinMenu::InitialiseMinigamesMode()
{
app.DebugPrintf("UIScene_LoadOrJoinMenu::InitialiseMinigamesMode\n");
m_iSaveListIndex = 0;
m_iGameListIndex = 0;
m_iDefaultButtonsC = 0;
m_iMashUpButtonsC = 0;
m_generators.clear();
m_buttonListSaves.clearList();
m_buttonListSaves.addItem(L"Battle");
m_buttonListSaves.addItem(L"Tumble");
m_buttonListSaves.addItem(L"Glide");
m_buttonListSaves.addItem(L"Bedwars");
m_buttonListSaves.addItem(L"Direct Connect");
m_iDefaultButtonsC = m_buttonListSaves.getItemCount();
m_controlSavesTimer.setVisible(false);
m_labelNoGames.setVisible(false);
m_iRequestingThumbnailId = 0;
m_bAllLoaded = true;
m_bSavesDisplayed = true;
m_bRetrievingSaveThumbnails = false;
m_bSaveThumbnailReady = false;
m_bIgnoreInput = false;
}
void UIScene_LoadOrJoinMenu::updateComponents()
{
m_parentLayer->showComponent(m_iPad,eUIComponent_Panorama,true);
@ -472,6 +622,16 @@ void UIScene_LoadOrJoinMenu::handleGainFocus(bool navBack)
// Add load online timer
addTimer(JOIN_LOAD_ONLINE_TIMER_ID,JOIN_LOAD_ONLINE_TIMER_TIME);
if(m_bMinigamesMode)
{
if(navBack)
{
m_bIgnoreInput = false;
UpdateGamesList();
}
return;
}
if(navBack)
{
app.SetLiveLinkRequired( true );
@ -962,6 +1122,15 @@ void UIScene_LoadOrJoinMenu::handleInput(int iPad, int key, bool repeat, bool pr
}
break;
case ACTION_MENU_X:
if(m_bMinigamesMode)
{
if(pressed)
{
StartDirectConnectKeyboard();
handled = true;
}
break;
}
#if TO_BE_IMPLEMENTED
// Change device
// Fix for #12531 - TCR 001: BAS Game Stability: When a player selects to change a storage
@ -1041,6 +1210,10 @@ void UIScene_LoadOrJoinMenu::handleInput(int iPad, int key, bool repeat, bool pr
break;
case ACTION_MENU_RIGHT_SCROLL:
if(m_bMinigamesMode)
{
break;
}
if(DoesSavesListHaveFocus())
{
// 4J-PB - check we are on a valid save
@ -1194,6 +1367,139 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo
return 0;
}
void UIScene_LoadOrJoinMenu::StartDirectConnectKeyboard()
{
#ifdef _WINDOWS64
m_bIgnoreInput = true;
ui.PlayUISFX(eSFX_Press);
InputManager.RequestKeyboard(L"Direct Connect", L"", (DWORD)m_iPad, 63, &UIScene_LoadOrJoinMenu::KeyboardCompleteDirectConnectCallback, this, C_4JInput::EKeyboardMode_Default);
#else
UINT uiIDA[1];
uiIDA[0] = IDS_CONFIRM_OK;
ui.RequestMessageBox(IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, m_iPad, NULL, NULL, app.GetStringTable());
#endif
}
int UIScene_LoadOrJoinMenu::KeyboardCompleteDirectConnectCallback(LPVOID lpParam, bool bRes)
{
UIScene_LoadOrJoinMenu *pClass = (UIScene_LoadOrJoinMenu *)lpParam;
pClass->m_bIgnoreInput = false;
if(!bRes)
{
pClass->updateTooltips();
return 0;
}
uint16_t ui16Text[128];
ZeroMemory(ui16Text, sizeof(ui16Text));
InputManager.GetText(ui16Text);
pClass->HandleDirectConnectInput((const wchar_t *)ui16Text);
return 0;
}
void UIScene_LoadOrJoinMenu::HandleDirectConnectInput(const wchar_t *inputText)
{
#ifdef _WINDOWS64
char hostIp[64];
int hostPort = WIN64_NET_DEFAULT_PORT;
if(!ParseDirectConnectAddress(inputText, hostIp, sizeof(hostIp), hostPort))
{
app.DebugPrintf("UIScene_LoadOrJoinMenu::HandleDirectConnectInput - invalid address input\n");
UINT uiIDA[1];
uiIDA[0] = IDS_CONFIRM_OK;
ui.RequestMessageBox(IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, m_iPad, NULL, NULL, app.GetStringTable());
return;
}
delete m_pDirectConnectSession;
m_pDirectConnectSession = new FriendSessionInfo();
wstring label = TrimWhitespace(inputText != NULL ? inputText : L"");
if(label.length() == 0)
{
label = convStringToWstring(string(hostIp));
}
size_t labelLen = label.length();
m_pDirectConnectSession->displayLabel = new wchar_t[labelLen + 1];
wcscpy_s(m_pDirectConnectSession->displayLabel, labelLen + 1, label.c_str());
m_pDirectConnectSession->displayLabelLength = (unsigned char)((labelLen > 255) ? 255 : labelLen);
m_pDirectConnectSession->displayLabelViewableStartIndex = 0;
m_pDirectConnectSession->data.isJoinable = true;
m_pDirectConnectSession->data.isReadyToJoin = true;
m_pDirectConnectSession->data.hostPort = hostPort;
m_pDirectConnectSession->data.playerCount = 0;
m_pDirectConnectSession->data.maxPlayers = MINECRAFT_NET_MAX_PLAYERS;
strncpy_s(m_pDirectConnectSession->data.hostIP, sizeof(m_pDirectConnectSession->data.hostIP), hostIp, _TRUNCATE);
wstring hostName = convStringToWstring(string(hostIp));
wcsncpy_s(m_pDirectConnectSession->data.hostName, XUSER_NAME_SIZE, hostName.c_str(), _TRUNCATE);
m_pDirectConnectSession->sessionId = 0;
app.DebugPrintf("UIScene_LoadOrJoinMenu::HandleDirectConnectInput - joining %s:%d\n", hostIp, hostPort);
m_initData->iPad = 0;
m_initData->selectedSession = m_pDirectConnectSession;
m_controlJoinTimer.setVisible(false);
m_bIgnoreInput = true;
ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_JoinMenu, m_initData);
#else
(void)inputText;
#endif
}
#ifdef _WINDOWS64
bool UIScene_LoadOrJoinMenu::ParseDirectConnectAddress(const wchar_t *inputText, char *outHostIp, size_t outHostIpSize, int &outHostPort)
{
if(inputText == NULL || outHostIp == NULL || outHostIpSize == 0)
{
return false;
}
outHostIp[0] = '\0';
outHostPort = WIN64_NET_DEFAULT_PORT;
wstring trimmedInput = TrimWhitespace(inputText);
if(trimmedInput.length() == 0)
{
return false;
}
wstring hostPart = trimmedInput;
wstring portPart;
size_t separatorPos = trimmedInput.rfind(L':');
if(separatorPos != wstring::npos)
{
hostPart = TrimWhitespace(trimmedInput.substr(0, separatorPos));
portPart = TrimWhitespace(trimmedInput.substr(separatorPos + 1));
if(hostPart.length() == 0 || portPart.length() == 0)
{
return false;
}
int parsedPort = _wtoi(portPart.c_str());
if(parsedPort <= 0 || parsedPort > 65535)
{
return false;
}
outHostPort = parsedPort;
}
size_t convertedCount = 0;
errno_t convertResult = wcstombs_s(&convertedCount, outHostIp, outHostIpSize, hostPart.c_str(), _TRUNCATE);
if(convertResult != 0 || outHostIp[0] == '\0')
{
return false;
}
return true;
}
#endif
void UIScene_LoadOrJoinMenu::handleInitFocus(F64 controlId, F64 childId)
{
app.DebugPrintf(app.USER_SR, "UIScene_LoadOrJoinMenu::handleInitFocus - %d , %d\n", (int)controlId, (int)childId);
@ -1235,11 +1541,24 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
{
m_bIgnoreInput=true;
int lGenID = (int)childId - 1;
//CD - Added for audio
ui.PlayUISFX(eSFX_Press);
if(m_bMinigamesMode)
{
if((int)childId == (int)eMinigame_Count)
{
StartDirectConnectKeyboard();
}
else
{
StartMinigameServer((int)childId);
}
break;
}
int lGenID = (int)childId - 1;
if((int)childId == JOIN_LOAD_CREATE_BUTTON_INDEX)
{
app.SetTutorialMode( false );
@ -1354,8 +1673,10 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
{
if( m_buttonListGames.getItemCount() > 0 && gameIndex < m_currentSessions->size() )
if( m_currentSessions != NULL && m_buttonListGames.getItemCount() > 0 && gameIndex >= 0 && gameIndex < (int)m_currentSessions->size() )
{
FriendSessionInfo *selectedSession = m_currentSessions->at(gameIndex);
#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
// 4J-PB - is the player allowed to join games?
bool noUGC=false;
@ -1472,7 +1793,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
//CScene_MultiGameInfo::JoinMenuInitData *initData = new CScene_MultiGameInfo::JoinMenuInitData();
m_initData->iPad = 0;;
m_initData->selectedSession = m_currentSessions->at( gameIndex );
m_initData->selectedSession = selectedSession;
// check that we have the texture pack available
// If it's not the default texture pack
@ -1526,6 +1847,165 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
}
}
void UIScene_LoadOrJoinMenu::StartMinigameServer(int minigameIndex)
{
static const wchar_t *minigameNames[eMinigame_Count] =
{
L"Battle",
L"Tumble",
L"Glide",
L"Bedwars",
};
if(minigameIndex < 0 || minigameIndex >= (int)eMinigame_Count)
{
app.DebugPrintf("UIScene_LoadOrJoinMenu::StartMinigameServer - invalid minigame index %d\n", minigameIndex);
m_bIgnoreInput = false;
return;
}
app.DebugPrintf("UIScene_LoadOrJoinMenu::StartMinigameServer - selected %ls (%d)\n",
minigameNames[minigameIndex], minigameIndex);
int hostPad = m_iPad;
if(hostPad < 0 || !ProfileManager.IsSignedIn(hostPad))
{
hostPad = ProfileManager.GetPrimaryPad();
}
UINT uiIDA[1];
uiIDA[0] = IDS_OK;
if(hostPad < 0)
{
app.DebugPrintf("UIScene_LoadOrJoinMenu::StartMinigameServer - no signed in host pad\n");
m_bIgnoreInput = false;
ui.RequestMessageBox(IDS_MUST_SIGN_IN_TITLE, IDS_MUST_SIGN_IN_TEXT, uiIDA, 1, m_iPad, NULL, NULL, app.GetStringTable());
return;
}
if(ProfileManager.IsGuest(hostPad))
{
app.DebugPrintf("UIScene_LoadOrJoinMenu::StartMinigameServer - host pad %d is guest\n", hostPad);
m_bIgnoreInput = false;
ui.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1);
return;
}
bool isClientSide = ProfileManager.IsSignedInLive(hostPad);
#ifdef __PSVITA__
if(app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_PSVita_NetworkModeAdhoc) == true)
{
CGameNetworkManager::setAdhocMode(true);
isClientSide = SQRNetworkManager_AdHoc_Vita::GetAdhocStatus();
}
else
{
CGameNetworkManager::setAdhocMode(false);
}
#endif
if(!isClientSide)
{
app.DebugPrintf("UIScene_LoadOrJoinMenu::StartMinigameServer - host pad %d is offline\n", hostPad);
m_bIgnoreInput = false;
ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, hostPad, NULL, NULL, app.GetStringTable());
return;
}
Minecraft *pMinecraft = Minecraft::GetInstance();
ProfileManager.SetLockedProfile(hostPad);
ProfileManager.QuerySigninStatus();
pMinecraft->user->name = convStringToWstring(ProfileManager.GetGamertag(hostPad));
app.ApplyGameSettingsChanged(hostPad);
const bool launchingBedwarsHub = (minigameIndex == (int)eMinigame_Bedwars);
wstring saveTitle = L"LCE ";
saveTitle += launchingBedwarsHub ? L"Bedwars Hub" : minigameNames[minigameIndex];
app.ClearTerrainFeaturePosition();
StorageManager.ResetSaveData();
StorageManager.SetSaveTitle(saveTitle.c_str());
app.SetTutorialMode(false);
app.setLevelGenerationOptions(NULL);
int difficulty = 2;
if(pMinecraft->options != NULL)
{
difficulty = pMinecraft->options->difficulty;
}
app.SetGameHostOption(eGameHostOption_Difficulty, difficulty);
app.SetGameHostOption(eGameHostOption_FriendsOfFriends, 1);
app.SetGameHostOption(eGameHostOption_Gamertags, app.GetGameSettings(hostPad, eGameSetting_GamertagsVisible) ? 1 : 0);
app.SetGameHostOption(eGameHostOption_BedrockFog, app.GetGameSettings(hostPad, eGameSetting_BedrockFog) ? 1 : 0);
app.SetGameHostOption(eGameHostOption_GameType, GameType::SURVIVAL->getId());
app.SetGameHostOption(eGameHostOption_LevelType, 1);
app.SetGameHostOption(eGameHostOption_Structures, 0);
app.SetGameHostOption(eGameHostOption_BonusChest, 0);
app.SetGameHostOption(eGameHostOption_DisableSaving, 1);
StorageManager.SetSaveDisabled(true);
app.SetGameHostOption(eGameHostOption_PvP, launchingBedwarsHub ? 0 : 1);
app.SetGameHostOption(eGameHostOption_TrustPlayers, 0);
app.SetGameHostOption(eGameHostOption_FireSpreads, launchingBedwarsHub ? 0 : 1);
app.SetGameHostOption(eGameHostOption_TNT, launchingBedwarsHub ? 0 : 1);
app.SetGameHostOption(eGameHostOption_HostCanFly, 0);
app.SetGameHostOption(eGameHostOption_HostCanChangeHunger, 0);
app.SetGameHostOption(eGameHostOption_HostCanBeInvisible, 0);
// Tag the session with a minigame type so the server browser can show it.
unsigned int hostSettings = app.GetGameHostOption(eGameHostOption_All);
hostSettings |= MINIGAME_SETTINGS_FLAG;
hostSettings &= ~MINIGAME_SETTINGS_TYPE_MASK;
hostSettings |= ((unsigned int)(minigameIndex & 0x7) << MINIGAME_SETTINGS_TYPE_SHIFT);
hostSettings &= ~MINIGAME_SETTINGS_ROLE_MASK;
hostSettings |= (MINIGAME_ROLE_HUB << MINIGAME_SETTINGS_ROLE_SHIFT);
hostSettings &= ~MINIGAME_SETTINGS_QUEUE_MASK;
hostSettings |= (0u << MINIGAME_SETTINGS_QUEUE_SHIFT);
app.SetGameHostOption(eGameHostOption_All, hostSettings);
DWORD dwLocalUsersMask = CGameNetworkManager::GetLocalPlayerMask(hostPad);
if(dwLocalUsersMask == 0)
{
dwLocalUsersMask = CGameNetworkManager::GetLocalPlayerMask(ProfileManager.GetPrimaryPad());
}
g_NetworkManager.HostGame(dwLocalUsersMask, isClientSide, false, MINECRAFT_NET_MAX_PLAYERS, 0);
app.DebugPrintf("UIScene_LoadOrJoinMenu::StartMinigameServer - HostGame called (mask=0x%08X)\n", dwLocalUsersMask);
#ifndef _XBOX
g_NetworkManager.FakeLocalPlayerJoined();
#endif
NetworkGameInitData *param = new NetworkGameInitData();
param->seed = 0;
param->findSeed = true;
param->saveData = NULL;
param->settings = app.GetGameHostOption(eGameHostOption_All);
param->texturePackId = pMinecraft->getCurrentTexturePackId();
param->xzSize = LEVEL_MAX_WIDTH;
param->hellScale = HELL_LEVEL_MAX_SCALE;
LoadingInputParams *loadingParams = new LoadingInputParams();
loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc;
loadingParams->lpParam = (LPVOID)param;
app.SetAutosaveTimerTime();
UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData();
completionData->bShowBackground = TRUE;
completionData->bShowLogo = TRUE;
completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes;
completionData->iPad = DEFAULT_XUI_MENU_USER;
loadingParams->completionData = completionData;
ui.NavigateToScene(hostPad, eUIScene_FullscreenProgress, loadingParams);
app.DebugPrintf("UIScene_LoadOrJoinMenu::StartMinigameServer - navigating to fullscreen progress\n");
}
void UIScene_LoadOrJoinMenu::LoadLevelGen(LevelGenerationOptions *levelGen)
{
// Load data from disc
@ -1610,10 +2090,13 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
FriendSessionInfo *pSelectedSession = NULL;
if(DoesGamesListHaveFocus() && m_buttonListGames.getItemCount() > 0)
if(DoesGamesListHaveFocus() && m_buttonListGames.getItemCount() > 0 && m_currentSessions != NULL)
{
unsigned int nIndex = m_buttonListGames.getCurrentSelection();
pSelectedSession = m_currentSessions->at( nIndex );
if(nIndex < m_currentSessions->size())
{
pSelectedSession = m_currentSessions->at( nIndex );
}
}
SessionID selectedSessionId;
@ -1729,7 +2212,32 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
}
}
#ifdef _WINDOWS64
wstring rowLabel = sessionInfo->displayLabel != NULL ? sessionInfo->displayLabel : L"Unknown Host";
int playerCount = (int)sessionInfo->data.playerCount;
int maxPlayers = (int)sessionInfo->data.maxPlayers;
if(maxPlayers <= 0)
{
maxPlayers = MINECRAFT_NET_MAX_PLAYERS;
}
wchar_t sessionDetail[96];
if(m_bMinigamesMode)
{
const wchar_t *minigameName = GetMinigameNameFromSettings(sessionInfo->data.m_uiGameHostSettings);
swprintf(sessionDetail, 96, L" [%d/%d] - %ls", playerCount, maxPlayers, minigameName);
}
else
{
swprintf(sessionDetail, 96, L" [%d/%d]", playerCount, maxPlayers);
}
rowLabel += sessionDetail;
m_buttonListGames.addItem(rowLabel, textureName);
#else
m_buttonListGames.addItem( sessionInfo->displayLabel, textureName );
#endif
if(memcmp( &selectedSessionId, &sessionInfo->sessionId, sizeof(SessionID) ) == 0)
{
@ -3529,3 +4037,7 @@ int UIScene_LoadOrJoinMenu::CopySaveErrorDialogFinishedCallback(void *pParam,int
}
#endif // _XBOX_ONE

View file

@ -42,6 +42,15 @@ private:
};
eActions m_eAction;
enum EMinigameButtons
{
eMinigame_Battle = 0,
eMinigame_Tumble,
eMinigame_Glide,
eMinigame_Bedwars,
eMinigame_Count,
};
static const int JOIN_LOAD_CREATE_BUTTON_INDEX = 0;
SaveListDetails *m_saveDetails;
@ -85,6 +94,7 @@ private:
bool m_bAllLoaded;
bool m_bRetrievingSaveThumbnails;
bool m_bSaveThumbnailReady;
bool m_bMinigamesMode;
bool m_bShowingPartyGamesOnly;
bool m_bInParty;
JoinMenuInitData *m_initData;
@ -105,6 +115,7 @@ private:
bool m_bSaveTransferCancelled;
#endif
bool m_bUpdateSaveSize;
FriendSessionInfo *m_pDirectConnectSession;
public:
UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer *parentLayer);
@ -132,6 +143,7 @@ public:
private:
void Initialise();
void InitialiseMinigamesMode();
void GetSaveInfo();
void UpdateGamesList();
void AddDefaultButtons();
@ -153,8 +165,15 @@ public:
static int DeleteSaveDataReturned(LPVOID lpParam,bool bRes);
static int RenameSaveDataReturned(LPVOID lpParam,bool bRes);
static int KeyboardCompleteWorldNameCallback(LPVOID lpParam,bool bRes);
static int KeyboardCompleteDirectConnectCallback(LPVOID lpParam,bool bRes);
protected:
void handlePress(F64 controlId, F64 childId);
void StartMinigameServer(int minigameIndex);
void StartDirectConnectKeyboard();
void HandleDirectConnectInput(const wchar_t *inputText);
#ifdef _WINDOWS64
bool ParseDirectConnectAddress(const wchar_t *inputText, char *outHostIp, size_t outHostIpSize, int &outHostPort);
#endif
void LoadLevelGen(LevelGenerationOptions *levelGen);
void LoadSaveFromDisk(File *saveFile, ESavePlatform savePlatform = SAVE_FILE_PLATFORM_LOCAL);
#if defined(__PS3__) || defined(__PSVITA__) || defined(__ORBIS__)

View file

@ -2,8 +2,10 @@
#include "..\..\..\Minecraft.World\Mth.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "..\..\..\Minecraft.World\Random.h"
#include "..\..\..\Minecraft.World\LevelSettings.h"
#include "..\..\User.h"
#include "..\..\MinecraftServer.h"
#include "..\..\Options.h"
#include "UI.h"
#include "UIScene_MainMenu.h"
#ifdef __ORBIS__
@ -51,6 +53,7 @@ UIScene_MainMenu::UIScene_MainMenu(int iPad, void *initData, UILayer *parentLaye
m_bTrialVersion=true;
m_buttons[(int)eControl_UnlockOrDLC].init(app.GetString(IDS_UNLOCK_FULL_GAME),eControl_UnlockOrDLC);
}
m_buttons[(int)eControl_Minigames].init(L"LCE Minigames", eControl_Minigames);
#ifndef _DURANGO
m_buttons[(int)eControl_Exit].init(app.GetString(IDS_EXIT_GAME),eControl_Exit);
@ -334,6 +337,12 @@ void UIScene_MainMenu::handlePress(F64 controlId, F64 childId)
m_eAction=eAction_RunUnlockOrDLC;
signInReturnedFunc = &UIScene_MainMenu::UnlockFullGame_SignInReturned;
break;
case eControl_Minigames:
// Launch the dedicated LCE minigames world flow.
ui.PlayUISFX(eSFX_Press);
m_eAction = eAction_RunMinigames;
signInReturnedFunc = &UIScene_MainMenu::Minigames_SignInReturned;
break;
#if defined _XBOX
case eControl_Exit:
if( ProfileManager.IsFullVersion() )
@ -400,6 +409,9 @@ void UIScene_MainMenu::RunAction(int iPad)
case eAction_RunGame:
RunPlayGame(iPad);
break;
case eAction_RunMinigames:
RunMinigames(iPad);
break;
case eAction_RunLeaderboards:
RunLeaderboards(iPad);
break;
@ -493,6 +505,7 @@ int UIScene_MainMenu::MustSignInReturned(void *pParam, int iPad, C4JStorage::EMe
switch(pClass->m_eAction)
{
case eAction_RunGame: ProfileManager.RequestSignInUI(false, true, false, false, true, &UIScene_MainMenu::CreateLoad_SignInReturned, pClass, iPad ); break;
case eAction_RunMinigames: ProfileManager.RequestSignInUI(false, false, true, false, true, &UIScene_MainMenu::Minigames_SignInReturned, pClass, iPad ); break;
case eAction_RunHelpAndOptions: ProfileManager.RequestSignInUI(false, false, true, false, true, &UIScene_MainMenu::HelpAndOptions_SignInReturned, pClass, iPad ); break;
case eAction_RunLeaderboards: ProfileManager.RequestSignInUI(false, false, true, false, true, &UIScene_MainMenu::Leaderboards_SignInReturned, pClass, iPad ); break;
case eAction_RunAchievements: ProfileManager.RequestSignInUI(false, false, true, false, true, &UIScene_MainMenu::Achievements_SignInReturned, pClass, iPad ); break;
@ -658,6 +671,30 @@ int UIScene_MainMenu::HelpAndOptions_SignInReturned(void *pParam,bool bContinue,
return 0;
}
int UIScene_MainMenu::Minigames_SignInReturned(void *pParam,bool bContinue,int iPad)
{
UIScene_MainMenu *pClass = (UIScene_MainMenu *)pParam;
if(bContinue)
{
pClass->RunMinigames(iPad);
}
else
{
pClass->m_bIgnorePress=false;
ProfileManager.SetLockedProfile(-1);
for(int i=0;i<XUSER_MAX_COUNT;i++)
{
if(ProfileManager.IsSignedIn(i))
{
ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MENUS,false);
}
}
}
return 0;
}
#ifdef _XBOX_ONE
int UIScene_MainMenu::ChooseUser_SignInReturned(void *pParam, bool bContinue, int iPad)
{
@ -1471,6 +1508,66 @@ void UIScene_MainMenu::RunPlayGame(int iPad)
}
}
void UIScene_MainMenu::RunMinigames(int iPad)
{
app.DebugPrintf("UIScene_MainMenu::RunMinigames - requested by pad %d\n", iPad);
int hostPad = iPad;
if(hostPad < 0 || !ProfileManager.IsSignedIn(hostPad))
{
hostPad = ProfileManager.GetPrimaryPad();
}
UINT uiIDA[1];
uiIDA[0]=IDS_OK;
if(hostPad < 0)
{
m_bIgnorePress=false;
ui.RequestMessageBox(IDS_MUST_SIGN_IN_TITLE, IDS_MUST_SIGN_IN_TEXT, uiIDA, 1, iPad, NULL, NULL, app.GetStringTable());
return;
}
if(ProfileManager.IsGuest(hostPad))
{
m_bIgnorePress=false;
ui.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1);
return;
}
bool isClientSide = ProfileManager.IsSignedInLive(hostPad);
#ifdef __PSVITA__
if(app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_PSVita_NetworkModeAdhoc) == true)
{
CGameNetworkManager::setAdhocMode(true);
isClientSide = SQRNetworkManager_AdHoc_Vita::GetAdhocStatus();
}
else
{
CGameNetworkManager::setAdhocMode(false);
}
#endif
if(!isClientSide)
{
m_bIgnorePress=false;
ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, hostPad, NULL, NULL, app.GetStringTable());
return;
}
ProfileManager.SetLockedProfile(hostPad);
ProfileManager.QuerySigninStatus();
Minecraft *pMinecraft = Minecraft::GetInstance();
pMinecraft->user->name = convStringToWstring(ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad()));
app.ApplyGameSettingsChanged(hostPad);
LoadOrJoinMenuInitData *params = new LoadOrJoinMenuInitData();
params->bMinigamesMode = TRUE;
app.DebugPrintf("UIScene_MainMenu::RunMinigames - navigating to LoadOrJoin minigames hub (hostPad=%d)\n", hostPad);
ui.NavigateToScene(hostPad, eUIScene_LoadOrJoinMenu, params);
}
void UIScene_MainMenu::RunLeaderboards(int iPad)
{
UINT uiIDA[1];

View file

@ -8,6 +8,7 @@ private:
enum EControls
{
eControl_PlayGame,
eControl_Minigames,
eControl_Leaderboards,
eControl_Achievements,
eControl_HelpAndOptions,
@ -33,14 +34,15 @@ private:
UIControl m_controlTimer;
UI_BEGIN_MAP_ELEMENTS_AND_NAMES(UIScene)
UI_MAP_ELEMENT( m_buttons[(int)eControl_PlayGame], "Button1")
UI_MAP_ELEMENT( m_buttons[(int)eControl_Leaderboards], "Button2")
UI_MAP_ELEMENT( m_buttons[(int)eControl_Achievements], "Button3")
UI_MAP_ELEMENT( m_buttons[(int)eControl_HelpAndOptions], "Button4")
UI_MAP_ELEMENT( m_buttons[(int)eControl_UnlockOrDLC], "Button5")
UI_MAP_ELEMENT( m_buttons[(int)eControl_Minigames], "Button2")
UI_MAP_ELEMENT( m_buttons[(int)eControl_Leaderboards], "Button3")
UI_MAP_ELEMENT( m_buttons[(int)eControl_Achievements], "Button4")
UI_MAP_ELEMENT( m_buttons[(int)eControl_HelpAndOptions], "Button5")
UI_MAP_ELEMENT( m_buttons[(int)eControl_UnlockOrDLC], "Button6")
#ifndef _DURANGO
UI_MAP_ELEMENT( m_buttons[(int)eControl_Exit], "Button6")
UI_MAP_ELEMENT( m_buttons[(int)eControl_Exit], "Button7")
#else
UI_MAP_ELEMENT( m_buttons[(int)eControl_XboxHelp], "Button6")
UI_MAP_ELEMENT( m_buttons[(int)eControl_XboxHelp], "Button7")
#endif
UI_MAP_ELEMENT( m_controlTimer, "Timer")
UI_END_MAP_ELEMENTS_AND_NAMES()
@ -76,6 +78,7 @@ private:
{
eAction_None=0,
eAction_RunGame,
eAction_RunMinigames,
eAction_RunLeaderboards,
eAction_RunAchievements,
eAction_RunHelpAndOptions,
@ -127,6 +130,7 @@ protected:
private:
void RunPlayGame(int iPad);
void RunMinigames(int iPad);
void RunLeaderboards(int iPad);
void RunUnlockOrDLC(int iPad);
void RunAchievements(int iPad);
@ -141,6 +145,7 @@ private:
#endif
static int CreateLoad_SignInReturned(void *pParam,bool bContinue, int iPad);
static int HelpAndOptions_SignInReturned(void *pParam,bool bContinue,int iPad);
static int Minigames_SignInReturned(void *pParam,bool bContinue,int iPad);
static int Achievements_SignInReturned(void *pParam,bool bContinue,int iPad);
static int MustSignInReturned(void *pParam,int iPad,C4JStorage::EMessageResult result);

View file

@ -216,6 +216,19 @@ typedef struct _SaveListDetails
} SaveListDetails;
#define LOAD_OR_JOIN_MENU_INIT_MAGIC 0x4C4F4A4D
typedef struct _LoadOrJoinMenuInitData
{
DWORD magic;
BOOL bMinigamesMode;
_LoadOrJoinMenuInitData()
{
magic = LOAD_OR_JOIN_MENU_INIT_MAGIC;
bMinigamesMode = FALSE;
}
} LoadOrJoinMenuInitData;
// Load world
typedef struct _LoadMenuInitData
{

View file

@ -6,6 +6,9 @@
#include <assert.h>
#include "..\..\Minecraft.h"
#include "..\..\..\Minecraft.World\DisconnectPacket.h"
#ifdef _WINDOWS64
#include "..\Network\PlatformNetworkManagerStub.h"
#endif
//----------------------------------------------------------------------------------
// Performs initialization tasks - retrieves controls.
@ -144,6 +147,15 @@ HRESULT CScene_ConnectingProgress::OnTimer( XUIMessageTimer *pTimer, BOOL& bHand
// Check if the connection failed
Minecraft *pMinecraft = Minecraft::GetInstance();
#ifdef _WINDOWS64
if (CPlatformNetworkManagerStub::IsServerTransferInProgress())
{
pMinecraft->m_connectionFailed[m_iPad] = false;
pMinecraft->m_connectionFailedReason[m_iPad] = DisconnectPacket::eDisconnect_None;
return S_OK;
}
#endif
if( pMinecraft->m_connectionFailed[m_iPad] || !g_NetworkManager.IsInSession() )
{
app.RemoveBackScene(m_iPad);

View file

@ -14,10 +14,12 @@
//#include "XUI_CreateLoad.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "..\..\..\Minecraft.World\Random.h"
#include "..\..\..\Minecraft.World\LevelSettings.h"
#include "..\..\MinecraftServer.h"
#include "..\..\Minecraft.h"
#include "..\..\Options.h"
#include "..\..\Font.h"
#include "..\UI\UIStructs.h"
#include "..\..\Common\GameRules\ConsoleGameRules.h"
#define DLC_INSTALLED_TIMER_ID 1
@ -38,6 +40,7 @@ HRESULT CScene_Main::OnInit( XUIMessageInit* pInitData, BOOL& bHandled )
XuiControlSetText(m_Buttons[BUTTON_ACHIEVEMENTS],app.GetString(IDS_ACHIEVEMENTS));
XuiControlSetText(m_Buttons[BUTTON_HELPANDOPTIONS],app.GetString(IDS_HELP_AND_OPTIONS));
XuiControlSetText(m_Buttons[BUTTON_UNLOCKFULLGAME],app.GetString(IDS_UNLOCK_FULL_GAME));
XuiControlSetText(m_Buttons[BUTTON_MINIGAMES],L"LCE Minigames");
XuiControlSetText(m_Buttons[BUTTON_EXITGAME],app.GetString(IDS_EXIT_GAME));
m_Timer.SetShow(FALSE);
@ -261,6 +264,20 @@ HRESULT CScene_Main::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotif
}
}
break;
case BUTTON_MINIGAMES:
m_eAction = eAction_RunMinigames;
if(ProfileManager.IsSignedIn(pNotifyPressData->UserIndex))
{
RunMinigames(pNotifyPressData->UserIndex);
}
else
{
UINT uiIDA[2];
uiIDA[0]=IDS_CONFIRM_OK;
uiIDA[1]=IDS_CONFIRM_CANCEL;
StorageManager.RequestMessageBox(IDS_MUST_SIGN_IN_TITLE, IDS_MUST_SIGN_IN_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_Main::MustSignInReturned,this, app.GetStringTable());
}
break;
case BUTTON_EXITGAME:
if( ProfileManager.IsFullVersion() )
{
@ -672,6 +689,9 @@ int CScene_Main::MustSignInReturned(void *pParam,int iPad,C4JStorage::EMessageRe
case eAction_RunGame:
ProfileManager.RequestSignInUI(false, true, false,false,true,&CScene_Main::CreateLoad_SignInReturned,pClass ,iPad);
break;
case eAction_RunMinigames:
ProfileManager.RequestSignInUI(false, false, true,false,true,&CScene_Main::Minigames_SignInReturned,pClass,iPad );
break;
case eAction_RunLeaderboards:
ProfileManager.RequestSignInUI(false, false, true,false,true, &CScene_Main::Leaderboards_SignInReturned, pClass,iPad);
break;
@ -704,6 +724,29 @@ int CScene_Main::MustSignInReturned(void *pParam,int iPad,C4JStorage::EMessageRe
return 0;
}
int CScene_Main::Minigames_SignInReturned(void *pParam,bool bContinue,int iPad)
{
CScene_Main* pClass = (CScene_Main*)pParam;
if(bContinue==true)
{
pClass->RunMinigames(iPad);
}
else
{
ProfileManager.SetLockedProfile(-1);
for(int i=0;i<XUSER_MAX_COUNT;i++)
{
if(ProfileManager.IsSignedIn(i))
{
ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MENUS,false);
}
}
}
return 0;
}
@ -1031,6 +1074,50 @@ void CScene_Main::RunPlayGame(int iPad)
}
}
void CScene_Main::RunMinigames(int iPad)
{
app.DebugPrintf("CScene_Main::RunMinigames - requested by pad %d\n", iPad);
int hostPad = iPad;
if(hostPad < 0 || !ProfileManager.IsSignedIn(hostPad))
{
hostPad = ProfileManager.GetPrimaryPad();
}
UINT uiIDA[1];
uiIDA[0]=IDS_OK;
if(hostPad < 0)
{
StorageManager.RequestMessageBox(IDS_MUST_SIGN_IN_TITLE, IDS_MUST_SIGN_IN_TEXT, uiIDA, 1, iPad, NULL, NULL, app.GetStringTable());
return;
}
if(ProfileManager.IsGuest(hostPad))
{
StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1);
return;
}
if(!ProfileManager.IsSignedInLive(hostPad))
{
StorageManager.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1);
return;
}
ProfileManager.SetLockedProfile(hostPad);
ProfileManager.QuerySigninStatus();
Minecraft *pMinecraft=Minecraft::GetInstance();
pMinecraft->user->name = convStringToWstring(ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad()));
app.ApplyGameSettingsChanged(hostPad);
LoadOrJoinMenuInitData *params = new LoadOrJoinMenuInitData();
params->bMinigamesMode = TRUE;
app.DebugPrintf("CScene_Main::RunMinigames - navigating to LoadOrJoin minigames hub (hostPad=%d)\n", hostPad);
app.NavigateToScene(hostPad, eUIScene_LoadOrJoinMenu, params);
}
HRESULT CScene_Main::OnTMSBanFileRetrieved()
{
Minecraft *pMinecraft=Minecraft::GetInstance();
@ -1285,4 +1372,4 @@ HRESULT CScene_Main::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled )
}
return S_OK;
}
}

View file

@ -4,11 +4,12 @@
#include "XUI_CustomMessages.h"
#define BUTTON_PLAYGAME 0
#define BUTTON_LEADERBOARDS 1
#define BUTTON_ACHIEVEMENTS 2
#define BUTTON_HELPANDOPTIONS 3
#define BUTTON_UNLOCKFULLGAME 4
#define BUTTON_EXITGAME 5
#define BUTTON_MINIGAMES 1
#define BUTTON_LEADERBOARDS 2
#define BUTTON_ACHIEVEMENTS 3
#define BUTTON_HELPANDOPTIONS 4
#define BUTTON_UNLOCKFULLGAME 5
#define BUTTON_EXITGAME 6
#define BUTTONS_MAX BUTTON_EXITGAME + 1
#define MAIN_MENU_MAX_TEXT_SCALE 1.5f
@ -41,6 +42,7 @@ private:
{
eAction_None=0,
eAction_RunGame,
eAction_RunMinigames,
eAction_RunLeaderboards,
eAction_RunAchievements,
eAction_RunHelpAndOptions,
@ -70,11 +72,12 @@ protected:
// Control mapping to objects
BEGIN_CONTROL_MAP()
MAP_CONTROL(IDC_XuiButton1, m_Buttons[BUTTON_PLAYGAME])
MAP_CONTROL(IDC_XuiButton2, m_Buttons[BUTTON_LEADERBOARDS ])
MAP_CONTROL(IDC_XuiButton3, m_Buttons[BUTTON_ACHIEVEMENTS ])
MAP_CONTROL(IDC_XuiButton4, m_Buttons[BUTTON_HELPANDOPTIONS])
MAP_CONTROL(IDC_XuiButton5, m_Buttons[BUTTON_UNLOCKFULLGAME])
MAP_CONTROL(IDC_XuiButton6, m_Buttons[BUTTON_EXITGAME])
MAP_CONTROL(IDC_XuiButton2, m_Buttons[BUTTON_MINIGAMES])
MAP_CONTROL(IDC_XuiButton3, m_Buttons[BUTTON_LEADERBOARDS ])
MAP_CONTROL(IDC_XuiButton4, m_Buttons[BUTTON_ACHIEVEMENTS ])
MAP_CONTROL(IDC_XuiButton5, m_Buttons[BUTTON_HELPANDOPTIONS])
MAP_CONTROL(IDC_XuiButton6, m_Buttons[BUTTON_UNLOCKFULLGAME])
MAP_CONTROL(IDC_XuiButton7, m_Buttons[BUTTON_EXITGAME])
MAP_CONTROL(IDC_XuiSplash, m_Subtitle)
MAP_CONTROL(IDC_XuiSplashMCFont, m_SubtitleMCFont)
MAP_CONTROL(IDC_Timer, m_Timer)
@ -95,6 +98,7 @@ protected:
static void LoadTrial();
void RunPlayGame(int iPad);
void RunMinigames(int iPad);
void RunLeaderboards(int iPad);
void RunAchievements(int iPad);
void RunHelpAndOptions(int iPad);
@ -114,6 +118,7 @@ public:
static int DeviceSelectReturned(void *pParam,bool bContinue);
static int SaveGameReturned(void *pParam,bool bContinue);
static int HelpAndOptions_SignInReturned(void *pParam,bool bContinue,int iPad);
static int Minigames_SignInReturned(void *pParam,bool bContinue,int iPad);
static int ExitGameReturned(void *pParam,int iPad,C4JStorage::EMessageResult result);
static int AchievementsDeviceSelectReturned(void *pParam,bool bContinue);
static int Achievements_SignInReturned(void *pParam,bool bContinue,int iPad);

View file

@ -168,7 +168,7 @@ void PIXSetMarkerDeprecated(int a, char *b, ...) {}
bool IsEqualXUID(PlayerUID a, PlayerUID b)
{
#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) || defined(_DURANGO)
#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) || defined(_DURANGO) || defined(_WINDOWS64)
return (a == b);
#else
return false;
@ -187,6 +187,8 @@ D3DXVECTOR3& D3DXVECTOR3::operator += ( CONST D3DXVECTOR3& add ) { x += add.x; y
#include "Windows64\Network\WinsockNetLayer.h"
extern bool g_Win64DedicatedServerMode;
BYTE IQNetPlayer::GetSmallId() { return m_smallId; }
void IQNetPlayer::SendData(IQNetPlayer *player, const void *pvData, DWORD dwDataSize, DWORD dwFlags)
{
@ -195,7 +197,14 @@ void IQNetPlayer::SendData(IQNetPlayer *player, const void *pvData, DWORD dwData
WinsockNetLayer::SendToSmallId(player->m_smallId, pvData, dwDataSize);
}
}
bool IQNetPlayer::IsSameSystem(IQNetPlayer *player) { return (this == player) || (!m_isRemote && !player->m_isRemote); }
bool IQNetPlayer::IsSameSystem(IQNetPlayer *player)
{
if (player == NULL)
{
return false;
}
return (this == player) || (!m_isRemote && !player->m_isRemote);
}
DWORD IQNetPlayer::GetSendQueueSize( IQNetPlayer *player, DWORD dwFlags ) { return 0; }
DWORD IQNetPlayer::GetCurrentRtt() { return 0; }
bool IQNetPlayer::IsHost() { return m_isHostPlayer; }
@ -232,13 +241,17 @@ void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost,
IQNet::s_playerCount = smallId + 1;
}
static bool Win64_IsActivePlayer(IQNetPlayer *p, DWORD index);
HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex){ return S_OK; }
IQNetPlayer *IQNet::GetHostPlayer() { return &m_player[0]; }
IQNetPlayer *IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
{
if (s_isHosting)
{
if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS && !m_player[dwUserIndex].m_isRemote)
if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS &&
!m_player[dwUserIndex].m_isRemote &&
Win64_IsActivePlayer(&m_player[dwUserIndex], dwUserIndex))
return &m_player[dwUserIndex];
return NULL;
}
@ -246,14 +259,20 @@ IQNetPlayer *IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
return NULL;
for (DWORD i = 0; i < s_playerCount; i++)
{
if (!m_player[i].m_isRemote)
if (!m_player[i].m_isRemote && Win64_IsActivePlayer(&m_player[i], i))
return &m_player[i];
}
return NULL;
}
static bool Win64_IsActivePlayer(IQNetPlayer *p, DWORD index)
{
if (index == 0) return true;
if (index == 0)
{
// Keep host slot active for index/session-id consistency in server queue logic.
// Dedicated mode suppresses host "player count" through advertising logic instead.
(void)g_Win64DedicatedServerMode;
return true;
}
return (p->GetCustomDataValue() != 0);
}
@ -272,19 +291,24 @@ IQNetPlayer *IQNet::GetPlayerByIndex(DWORD dwPlayerIndex)
}
IQNetPlayer *IQNet::GetPlayerBySmallId(BYTE SmallId)
{
for (DWORD i = 0; i < s_playerCount; i++)
{
if (m_player[i].m_smallId == SmallId && Win64_IsActivePlayer(&m_player[i], i)) return &m_player[i];
}
return NULL;
if (SmallId >= MINECRAFT_NET_MAX_PLAYERS)
return NULL;
// On Win64 LAN, clients can receive packets for a newly-joined higher smallId
// before local span bookkeeping catches up (e.g. local smallId=1 receiving smallId=2).
// Always provide the slot and grow the span so downstream code can materialize it.
m_player[SmallId].m_smallId = SmallId;
if (SmallId >= s_playerCount)
s_playerCount = SmallId + 1;
return &m_player[SmallId];
}
IQNetPlayer *IQNet::GetPlayerByXuid(PlayerUID xuid)
{
for (DWORD i = 0; i < s_playerCount; i++)
for (DWORD i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
{
if (Win64_IsActivePlayer(&m_player[i], i) && m_player[i].GetXuid() == xuid) return &m_player[i];
}
return &m_player[0];
return NULL;
}
DWORD IQNet::GetPlayerCount()
{
@ -299,15 +323,29 @@ QNET_STATE IQNet::GetState() { return _iQNetStubState; }
bool IQNet::IsHost() { return s_isHosting; }
HRESULT IQNet::JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO *pInviteInfo) { return S_OK; }
void IQNet::HostGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = true; }
void IQNet::ClientJoinGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = false; }
void IQNet::ClientJoinGame()
{
_iQNetStubState = QNET_STATE_SESSION_STARTING;
s_isHosting = false;
// Reset all slots so no stale network-player pointers survive between sessions.
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
{
m_player[i].m_smallId = (BYTE)i;
m_player[i].m_isRemote = true;
m_player[i].m_isHostPlayer = false;
m_player[i].m_gamertag[0] = 0;
m_player[i].SetCustomDataValue(0);
}
}
void IQNet::EndGame()
{
_iQNetStubState = QNET_STATE_IDLE;
s_isHosting = false;
s_playerCount = 1;
for (int i = 1; i < MINECRAFT_NET_MAX_PLAYERS; i++)
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
{
m_player[i].m_smallId = 0;
m_player[i].m_smallId = (BYTE)i;
m_player[i].m_isRemote = false;
m_player[i].m_isHostPlayer = false;
m_player[i].m_gamertag[0] = 0;

View file

@ -48,6 +48,9 @@
#include "TexturePackRepository.h"
#include "TexturePack.h"
#ifdef _WINDOWS64
#include "Common\Network\PlatformNetworkManagerStub.h"
#endif
bool GameRenderer::anaglyph3d = false;
int GameRenderer::anaglyphPass = 0;
@ -1164,6 +1167,26 @@ int GameRenderer::runUpdate(LPVOID lpParam)
m_updateEvents->Set(eUpdateCanRun);
#ifdef _WINDOWS64
// Cross-server transfer can overlap old-level teardown and new-level connect.
// Do not touch chunk rebuild queues in this transition window.
if (CPlatformNetworkManagerStub::IsServerTransferInProgress())
{
RenderManager.CBuffDeferredModeEnd();
m_updateEvents->Set(eUpdateEventIsFinished);
Sleep(1);
continue;
}
#endif
if (minecraft == NULL || minecraft->levelRenderer == NULL || minecraft->level == NULL)
{
RenderManager.CBuffDeferredModeEnd();
m_updateEvents->Set(eUpdateEventIsFinished);
Sleep(1);
continue;
}
// PIXBeginNamedEvent(0,"Updating dirty chunks %d",(count++)&7);
// Update chunks atomically until there aren't any very near ones left - they will be deferred for rendering

View file

@ -27,6 +27,8 @@
#include "..\Minecraft.World\net.minecraft.world.h"
#include "..\Minecraft.World\LevelChunk.h"
#include "..\Minecraft.World\Biome.h"
#include <algorithm>
#include <cmath>
#define RENDER_HUD 0
//#ifndef _XBOX
@ -34,6 +36,50 @@
//#define RENDER_HUD 1
//#endif
namespace
{
const unsigned int MINIGAME_SETTINGS_FLAG = 0x80000000u;
const unsigned int MINIGAME_SETTINGS_TYPE_MASK = 0x70000000u;
const unsigned int MINIGAME_SETTINGS_TYPE_SHIFT = 28u;
const unsigned int MINIGAME_SETTINGS_ROLE_MASK = 0x0C000000u;
const unsigned int MINIGAME_SETTINGS_ROLE_SHIFT = 26u;
const unsigned int MINIGAME_SETTINGS_QUEUE_MASK = 0x03000000u;
const unsigned int MINIGAME_SETTINGS_QUEUE_SHIFT = 24u;
const unsigned int MINIGAME_TYPE_BEDWARS = 3u;
const unsigned int MINIGAME_ROLE_HUB = 0u;
struct BedwarsHudRow
{
wstring name;
int health;
int distanceBlocks;
bool isSelf;
};
bool IsBedwarsSettings(unsigned int hostSettings)
{
if ((hostSettings & MINIGAME_SETTINGS_FLAG) == 0)
{
return false;
}
const unsigned int minigameType = (hostSettings & MINIGAME_SETTINGS_TYPE_MASK) >> MINIGAME_SETTINGS_TYPE_SHIFT;
return (minigameType == MINIGAME_TYPE_BEDWARS);
}
wstring GetBedwarsQueueLabel(unsigned int hostSettings)
{
const unsigned int queueMode = (hostSettings & MINIGAME_SETTINGS_QUEUE_MASK) >> MINIGAME_SETTINGS_QUEUE_SHIFT;
switch (queueMode)
{
case 0u: return L"Solo";
case 1u: return L"Doubles";
case 2u: return L"Squads";
case 3u: return L"Practice";
default: return L"Unknown";
}
}
}
float Gui::currentGuiBlendFactor = 1.0f; // 4J added
float Gui::currentGuiScaleFactor = 1.0f; // 4J added
ItemRenderer *Gui::itemRenderer = new ItemRenderer();
@ -735,6 +781,91 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Bedwars party/status panel (mid-right)
if (bDisplayGui && !bTwoPlayerSplitscreen && minecraft->level != NULL && minecraft->player != NULL)
{
const unsigned int hostSettings = app.GetGameHostOption(eGameHostOption_All);
if (IsBedwarsSettings(hostSettings))
{
vector<BedwarsHudRow> rows;
rows.reserve(minecraft->level->players.size());
for (AUTO_VAR(itP, minecraft->level->players.begin()); itP != minecraft->level->players.end(); ++itP)
{
shared_ptr<Player> p = *itP;
if (p == NULL)
{
continue;
}
BedwarsHudRow row;
row.name = p->displayName.empty() ? p->name : p->displayName;
row.health = p->getHealth();
const double dx = p->x - minecraft->player->x;
const double dy = p->y - minecraft->player->y;
const double dz = p->z - minecraft->player->z;
row.distanceBlocks = (int)std::sqrt(dx * dx + dy * dy + dz * dz);
row.isSelf = (p.get() == minecraft->player.get());
rows.push_back(row);
}
std::sort(rows.begin(), rows.end(), [](const BedwarsHudRow &a, const BedwarsHudRow &b)
{
if (a.isSelf != b.isSelf)
{
return a.isSelf;
}
if (a.distanceBlocks != b.distanceBlocks)
{
return a.distanceBlocks < b.distanceBlocks;
}
return a.name < b.name;
});
const int shownCount = (int)std::min<size_t>(rows.size(), 6);
const int panelWidth = 144;
const int headerHeight = 12;
const int lineHeight = 9;
const int bodyTop = headerHeight + 12;
const int bodyHeight = shownCount * lineHeight;
const int footerHeight = 10;
const int panelHeight = bodyTop + bodyHeight + footerHeight;
const int panelX = screenWidth - panelWidth - 2;
const int panelY = (screenHeight / 2) - (panelHeight / 2);
fill(panelX - 1, panelY - 1, panelX + panelWidth + 1, panelY + panelHeight + 1, 0xA0101010);
fill(panelX, panelY, panelX + panelWidth, panelY + headerHeight, 0xB0303030);
fill(panelX, panelY + headerHeight, panelX + panelWidth, panelY + panelHeight, 0x70101010);
drawString(font, L"Party", panelX + 3, panelY + 2, 0x55FFFF);
const bool isHubRole = (((hostSettings & MINIGAME_SETTINGS_ROLE_MASK) >> MINIGAME_SETTINGS_ROLE_SHIFT) == MINIGAME_ROLE_HUB);
const wstring modeText = isHubRole ? L"Hub" : L"Match";
const wstring queueText = GetBedwarsQueueLabel(hostSettings);
wchar_t infoLine[96];
swprintf_s(infoLine, L"%ls | %ls | %d online", modeText.c_str(), queueText.c_str(), (int)rows.size());
drawString(font, infoLine, panelX + 3, panelY + headerHeight + 1, 0xCFCFCF);
for (int i = 0; i < shownCount; ++i)
{
const BedwarsHudRow &r = rows[(size_t)i];
const int y = panelY + bodyTop + i * lineHeight;
const int nameColor = r.isSelf ? 0xFFFF55 : 0xE0E0E0;
drawString(font, r.name, panelX + 3, y, nameColor);
wchar_t rightText[48];
const int clampedHp = (r.health < 0) ? 0 : r.health;
swprintf_s(rightText, L"%dHP %dm", clampedHp, r.distanceBlocks);
int hpColor = 0x55FF55;
if (clampedHp <= 10) hpColor = 0xFFAA55;
if (clampedHp <= 4) hpColor = 0xFF5555;
drawString(font, rightText, panelX + panelWidth - font->width(rightText) - 3, y, hpColor);
}
drawString(font, L"/party /queue", panelX + 3, panelY + panelHeight - 9, 0x909090);
}
}
// if the player is falling asleep we render a dark overlay
if (minecraft->player->getSleepTimer() > 0)
{

View file

@ -18,7 +18,6 @@ Input::Input()
wasJumping = false;
jumping = false;
sneaking = false;
sprinting = false;
lReset = false;
rReset = false;
@ -94,35 +93,11 @@ void Input::tick(LocalPlayer *player)
}
#ifdef _WINDOWS64
if (iPad == 0 && g_KBMInput.IsMouseGrabbed())
if (iPad == 0 && g_KBMInput.IsMouseGrabbed() && pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_SNEAK_TOGGLE))
{
// Left Shift = sneak (hold to crouch)
if (pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_SNEAK_TOGGLE))
{
if (!player->abilities.flying)
{
sneaking = g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_SNEAK);
}
}
// Left Ctrl + forward = sprint (hold to sprint)
if (!player->abilities.flying)
{
bool ctrlHeld = g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_SPRINT);
bool movingForward = (kbYA > 0.0f);
if (ctrlHeld && movingForward)
{
sprinting = true;
}
else
{
sprinting = false;
}
}
else
{
sprinting = false;
sneaking = g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_SNEAK);
}
}
#endif
@ -169,7 +144,7 @@ void Input::tick(LocalPlayer *player)
if (iPad == 0 && g_KBMInput.IsMouseGrabbed())
{
float mouseSensitivity = ((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InGame)) / 100.0f;
float mouseLookScale = 5.0f;
float mouseLookScale = 1.0f;
float mx = g_KBMInput.GetLookX(mouseSensitivity * mouseLookScale);
float my = g_KBMInput.GetLookY(mouseSensitivity * mouseLookScale);

View file

@ -10,8 +10,7 @@ public:
bool wasJumping;
bool jumping;
bool sneaking;
bool sprinting;
Input(); // 4J - added
virtual void tick(LocalPlayer *player);

View file

@ -6,9 +6,6 @@ KeyboardMouseInput g_KBMInput;
extern HWND g_hWnd;
// Forward declaration
static void ClipCursorToWindow(HWND hWnd);
// coded by notpies fr
void KeyboardMouseInput::Init()
{
@ -33,7 +30,6 @@ void KeyboardMouseInput::Init()
m_mouseWheel = 0;
m_mouseWheelAccum = 0;
m_mouseGrabbed = false;
m_cursorHiddenForUI = false;
m_windowFocused = true;
m_hasInput = false;
@ -44,6 +40,10 @@ void KeyboardMouseInput::Init()
rid.hwndTarget = g_hWnd;
RegisterRawInputDevices(&rid, 1, sizeof(rid));
if (g_hWnd)
{
while (ShowCursor(FALSE) >= 0) {}
}
}
void KeyboardMouseInput::ClearAllState()
@ -107,7 +107,7 @@ void KeyboardMouseInput::Tick()
}
}
if ((m_mouseGrabbed || m_cursorHiddenForUI) && g_hWnd)
if (m_mouseGrabbed && g_hWnd)
{
RECT rc;
GetClientRect(g_hWnd, &rc);
@ -226,9 +226,6 @@ void KeyboardMouseInput::SetMouseGrabbed(bool grabbed)
m_mouseGrabbed = grabbed;
if (grabbed && g_hWnd)
{
while (ShowCursor(FALSE) >= 0) {}
ClipCursorToWindow(g_hWnd);
RECT rc;
GetClientRect(g_hWnd, &rc);
POINT center;
@ -240,40 +237,6 @@ void KeyboardMouseInput::SetMouseGrabbed(bool grabbed)
m_mouseDeltaAccumX = 0;
m_mouseDeltaAccumY = 0;
}
else if (!grabbed && !m_cursorHiddenForUI && g_hWnd)
{
while (ShowCursor(TRUE) < 0) {}
ClipCursor(NULL);
}
}
void KeyboardMouseInput::SetCursorHiddenForUI(bool hidden)
{
if (m_cursorHiddenForUI == hidden)
return;
m_cursorHiddenForUI = hidden;
if (hidden && g_hWnd)
{
while (ShowCursor(FALSE) >= 0) {}
ClipCursorToWindow(g_hWnd);
RECT rc;
GetClientRect(g_hWnd, &rc);
POINT center;
center.x = (rc.right - rc.left) / 2;
center.y = (rc.bottom - rc.top) / 2;
ClientToScreen(g_hWnd, &center);
SetCursorPos(center.x, center.y);
m_mouseDeltaAccumX = 0;
m_mouseDeltaAccumY = 0;
}
else if (!hidden && !m_mouseGrabbed && g_hWnd)
{
while (ShowCursor(TRUE) < 0) {}
ClipCursor(NULL);
}
}
static void ClipCursorToWindow(HWND hWnd)
@ -294,16 +257,8 @@ void KeyboardMouseInput::SetWindowFocused(bool focused)
m_windowFocused = focused;
if (focused)
{
if (m_mouseGrabbed || m_cursorHiddenForUI)
{
while (ShowCursor(FALSE) >= 0) {}
ClipCursorToWindow(g_hWnd);
}
else
{
while (ShowCursor(TRUE) < 0) {}
ClipCursor(NULL);
}
while (ShowCursor(FALSE) >= 0) {}
ClipCursorToWindow(g_hWnd);
}
else
{

View file

@ -18,11 +18,9 @@ public:
static const int KEY_RIGHT = 'D';
static const int KEY_JUMP = VK_SPACE;
static const int KEY_SNEAK = VK_LSHIFT;
static const int KEY_SPRINT = VK_LCONTROL;
static const int KEY_INVENTORY = 'E';
static const int KEY_DROP = 'Q';
static const int KEY_CRAFTING = VK_TAB;
static const int KEY_CRAFTING_ALT = 'R';
static const int KEY_PAUSE = VK_ESCAPE;
static const int KEY_THIRD_PERSON = VK_F5;
static const int KEY_DEBUG_INFO = VK_F3;
@ -58,9 +56,6 @@ public:
void SetMouseGrabbed(bool grabbed);
bool IsMouseGrabbed() const { return m_mouseGrabbed; }
void SetCursorHiddenForUI(bool hidden);
bool IsCursorHiddenForUI() const { return m_cursorHiddenForUI; }
void SetWindowFocused(bool focused);
bool IsWindowFocused() const { return m_windowFocused; }
@ -102,8 +97,6 @@ private:
bool m_mouseGrabbed;
bool m_cursorHiddenForUI;
bool m_windowFocused;
bool m_hasInput;

View file

@ -1794,6 +1794,11 @@ void LevelRenderer::renderAdvancedClouds(float alpha)
bool LevelRenderer::updateDirtyChunks()
{
if (level == NULL || mc == NULL || mc->level == NULL || globalChunkFlags == NULL)
{
return false;
}
#ifdef _LARGE_WORLDS
std::list< std::pair<ClipChunk *, int> > nearestClipChunks;
#endif
@ -3641,4 +3646,4 @@ int LevelRenderer::rebuildChunkThreadProc(LPVOID lpParam)
void LevelRenderer::nonStackDirtyChunksAdded()
{
dirtyChunksLockFreeStack.Push((int *)1);
}
}

View file

@ -328,12 +328,6 @@ void LocalPlayer::aiStep()
}
}
if (isSneaking()) sprintTriggerTime = 0;
#ifdef _WINDOWS64
if (input->sprinting && onGround && enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness) && !isSneaking())
{
setSprinting(true);
}
#endif
// 4J-PB - try not stopping sprint on collision
//if (isSprinting() && (input->ya < runTreshold || horizontalCollision || !enoughFoodToSprint))
if (isSprinting() && (input->ya < runTreshold || !enoughFoodToSprint))
@ -591,9 +585,7 @@ void LocalPlayer::closeContainer()
void LocalPlayer::openTextEdit(shared_ptr<SignTileEntity> sign)
{
bool success = app.LoadSignEntryMenu(GetXboxPad(), sign );
if( success ) ui.PlayUISFX(eSFX_Press);
//minecraft->setScreen(new TextEditScreen(sign));
minecraft->setScreen(new TextEditScreen(sign));
}
bool LocalPlayer::openContainer(shared_ptr<Container> container)
@ -1619,4 +1611,3 @@ void LocalPlayer::SetPlayerAdditionalModelParts(vector<ModelPart *>pAdditionalMo
{
m_pAdditionalModelParts=pAdditionalModelParts;
}

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="ContentPackage_NO_TU|Durango">
@ -1311,17 +1311,6 @@ if not exist "$(TargetDir)\savedata" mkdir "$(TargetDir)\savedata"</Command>
<DeploymentType>CopyToHardDrive</DeploymentType>
<DeploymentFiles>$(RemoteRoot)=$(ImagePath);$(RemoteRoot)\res=Xbox\res;$(RemoteRoot)=Xbox\AvatarAwards;$(RemoteRoot)\Tutorial=Xbox\Tutorial\Tutorial;$(RemoteRoot)=Xbox\584111F70AAAAAAA;$(RemoteRoot)=Xbox\kinect\speech;$(RemoteRoot)=Xbox\XZP\TMSFiles.xzp</DeploymentFiles>
</Deploy>
<PostBuildEvent>
<Command>copy /Y "$(TargetPath)" "$(ProjectDir)"
copy /Y "$(ProjectDir)Windows64\Iggy\lib\redist64\iggy_w64.dll" "$(ProjectDir)"
copy /Y "$(ProjectDir)Windows64\Miles\lib\redist64\mss64.dll" "$(ProjectDir)"
copy /Y "$(ProjectDir)Windows64\Iggy\lib\redist64\iggy_w64.dll" "$(OutDir)"
copy /Y "$(ProjectDir)Windows64\Miles\lib\redist64\mss64.dll" "$(OutDir)"
xcopy /Y /I /E "$(ProjectDir)redist64" "$(OutDir)redist64\"
if not exist "$(OutDir)Durango\Sound\" mkdir "$(OutDir)Durango\Sound\"
copy /Y "$(ProjectDir)Durango\Sound\Minecraft.msscmp" "$(OutDir)Durango\Sound\"</Command>
<Message>Copying exe and DLLs to Minecraft.Client and output folders</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Durango'">
<ClCompile>
@ -1432,7 +1421,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
<AdditionalDependencies>d3d11.lib;..\Minecraft.World\x64_Release\Minecraft.World.lib;XInput9_1_0.lib;Windows64\Iggy\lib\iggy_w64.lib;..\Minecraft.Client\Windows64\Miles\Lib\mss64.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>d3d11.lib;..\Minecraft.World\x64_Release\Minecraft.World.lib;XInput9_1_0.lib;Windows64\Iggy\lib\iggy_w64.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ShowProgress>NotSet</ShowProgress>
<SuppressStartupBanner>false</SuppressStartupBanner>
</Link>
@ -1450,17 +1439,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<DeploymentType>CopyToHardDrive</DeploymentType>
<DeploymentFiles>$(RemoteRoot)=$(ImagePath);$(RemoteRoot)\res=Xbox\res;$(RemoteRoot)=Xbox\AvatarAwards;$(RemoteRoot)\Tutorial=Xbox\Tutorial\Tutorial;$(RemoteRoot)=Xbox\584111F70AAAAAAA;$(RemoteRoot)=Xbox\kinect\speech;$(RemoteRoot)=Xbox\XZP\TMSFiles.xzp</DeploymentFiles>
</Deploy>
<PostBuildEvent>
<Command>copy /Y "$(TargetPath)" "$(ProjectDir)"
copy /Y "$(ProjectDir)Windows64\Iggy\lib\redist64\iggy_w64.dll" "$(ProjectDir)"
copy /Y "$(ProjectDir)Windows64\Miles\lib\redist64\mss64.dll" "$(ProjectDir)"
copy /Y "$(ProjectDir)Windows64\Iggy\lib\redist64\iggy_w64.dll" "$(OutDir)"
copy /Y "$(ProjectDir)Windows64\Miles\lib\redist64\mss64.dll" "$(OutDir)"
xcopy /Y /I /E "$(ProjectDir)redist64" "$(OutDir)redist64\"
if not exist "$(OutDir)Durango\Sound\" mkdir "$(OutDir)Durango\Sound\"
copy /Y "$(ProjectDir)Durango\Sound\Minecraft.msscmp" "$(OutDir)Durango\Sound\"</Command>
<Message>Copying exe and DLLs to Minecraft.Client and output folders</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|x64'">
<ClCompile>
@ -2850,7 +2828,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
@ -2894,8 +2872,8 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
@ -2939,7 +2917,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Xbox 360'">true</ExcludedFromBuild>
@ -28935,7 +28913,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Xbox 360'">true</ExcludedFromBuild>
@ -28943,7 +28921,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Texture.cpp" />
@ -34103,7 +34081,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Input.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34148,7 +34125,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Input_d.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34193,7 +34169,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Input_r.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34238,7 +34213,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Profile.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34283,7 +34257,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Profile_d.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34328,7 +34301,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Profile_r.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34373,7 +34345,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Render.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34418,7 +34389,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Render_d.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34463,7 +34433,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Render_r.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34508,7 +34477,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Storage.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34553,7 +34521,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Storage_d.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34598,7 +34565,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\4J_Storage_r.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
@ -34643,21 +34609,14 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\libSceNpToolkitUtils_rtti.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PSVita'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\libSceNpToolkitUtils_rtti_dbg.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\libSceNpToolkitUtils_rtti_dbg.a" />
<Library Include="PSVita\4JLibs\libs\libSceNpToolkit_rtti.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PSVita'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\libSceNpToolkit_rtti_dbg.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\4JLibs\libs\libSceNpToolkit_rtti_dbg.a" />
<Library Include="PSVita\Iggy\lib\libiggyperfmon_psp2.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|Durango'">true</ExcludedFromBuild>
@ -34695,7 +34654,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\Iggy\lib\libiggy_psp2.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|Durango'">true</ExcludedFromBuild>
@ -34732,18 +34690,10 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\Miles\lib\binkapsp2.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\Miles\lib\fltpsp2.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\Miles\lib\msspsp2.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\Miles\lib\msspsp2midi.a">
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
</Library>
<Library Include="PSVita\Miles\lib\binkapsp2.a" />
<Library Include="PSVita\Miles\lib\fltpsp2.a" />
<Library Include="PSVita\Miles\lib\msspsp2.a" />
<Library Include="PSVita\Miles\lib\msspsp2midi.a" />
<Library Include="Windows64\4JLibs\libs\4J_Input.lib">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Durango'">true</ExcludedFromBuild>
@ -36889,4 +36839,5 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -29,6 +29,7 @@
#include "TitleScreen.h"
#include "InventoryScreen.h"
#include "InBedChatScreen.h"
#include "ChatScreen.h"
#include "AchievementPopup.h"
#include "Input.h"
#include "FrustumCuller.h"
@ -172,7 +173,6 @@ Minecraft::Minecraft(Component *mouseComponent, Canvas *parent, MinecraftApplet
//lastTickTime = System::currentTimeMillis();
recheckPlayerIn = 0;
running = true;
showFpsCounter = false;
unoccupiedQuadrant = -1;
Stats::init();
@ -1481,7 +1481,7 @@ void Minecraft::run_middle()
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DROP))
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_DROP;
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING) || g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING_ALT))
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING))
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_CRAFTING;
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_PAUSE))
@ -1494,15 +1494,7 @@ void Minecraft::run_middle()
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON;
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_INFO))
{
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_GAME_INFO;
//localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_DEBUG;
}
if(g_KBMInput.IsKeyPressed(VK_F4))
{
showFpsCounter = !showFpsCounter;
}
int wheel = g_KBMInput.GetMouseWheel();
if (wheel > 0)
@ -1529,7 +1521,7 @@ void Minecraft::run_middle()
localplayers[i]->ullDpad_filtered = 0;
if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_DPAD_RIGHT)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_CHANGE_SKIN;
if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_DPAD_UP)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_FLY_TOGGLE;
if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_DPAD_DOWN)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_DEBUG;
if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_DPAD_DOWN)) //localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_DEBUG;
if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_DPAD_LEFT)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_SPAWN_CREEPER;
}
else
@ -2324,6 +2316,21 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
{
g_KBMInput.SetMouseGrabbed(true);
}
if (iPad == 0)
{
const int vkChat = Keyboard::toVK(Keyboard::KEY_T);
static bool s_chatKeyWasDown = false;
const bool chatKeyDown = (vkChat != 0) && g_KBMInput.IsKeyDown(vkChat);
if (chatKeyDown && !s_chatKeyWasDown)
{
app.DebugPrintf("Chat hotkey pressed - opening ChatScreen");
setScreen(new ChatScreen());
s_chatKeyWasDown = true;
return;
}
s_chatKeyWasDown = chatKeyDown;
}
#endif
// 4J-PB - add some tooltips if required
int iA=-1, iB=-1, iX, iY=IDS_CONTROLS_INVENTORY, iLT=-1, iRT=-1, iLB=-1, iRB=-1;
@ -3691,7 +3698,7 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
if (Keyboard.getEventKey() == options.keyDrop.key) {
player->drop();
}
if (isClientSide() && Keyboard.getEventKey() == options.keyChat.key) {
if ((isClientSide() || g_NetworkManager.IsInSession()) && Keyboard.getEventKey() == options.keyChat.key) {
setScreen(new ChatScreen());
}
}
@ -4989,4 +4996,3 @@ int Minecraft::MustSignInReturnedPSN(void *pParam, int iPad, C4JStorage::EMessag
return 0;
}
#endif

View file

@ -211,7 +211,6 @@ private:
public:
void destroy();
volatile bool running;
bool showFpsCounter;
wstring fpsString;
void run();
// 4J-PB - split the run into 3 parts so we can run it from our xbox game loop

View file

@ -22,6 +22,7 @@
#include "..\Minecraft.World\net.minecraft.world.h"
#include "..\Minecraft.World\net.minecraft.world.level.h"
#include "..\Minecraft.World\net.minecraft.world.level.tile.h"
#include "..\Minecraft.World\net.minecraft.world.level.tile.entity.h"
#include "..\Minecraft.World\Pos.h"
#include "..\Minecraft.World\System.h"
#include "..\Minecraft.World\StringHelpers.h"
@ -66,6 +67,227 @@ bool MinecraftServer::s_slowQueuePacketSent = false;
unordered_map<wstring, int> MinecraftServer::ironTimers;
namespace
{
const unsigned int MINIGAME_SETTINGS_FLAG = 0x80000000u;
const unsigned int MINIGAME_SETTINGS_TYPE_MASK = 0x70000000u;
const unsigned int MINIGAME_SETTINGS_TYPE_SHIFT = 28u;
const unsigned int MINIGAME_SETTINGS_ROLE_MASK = 0x0C000000u;
const unsigned int MINIGAME_SETTINGS_ROLE_SHIFT = 26u;
const unsigned int MINIGAME_TYPE_BEDWARS = 3u;
const unsigned int MINIGAME_ROLE_HUB = 0u;
struct BedwarsNpcDef
{
const wchar_t *label;
int offX;
int offZ;
float yRot;
};
static const BedwarsNpcDef kBedwarsNpcDefs[] =
{
{ L"Solo Queue", -3, 0, 90.0f },
{ L"Doubles Queue", 0, 3, 180.0f },
{ L"Squads Queue", 3, 0, 270.0f },
{ L"Practice NPC", 0, -3, 0.0f },
};
static const wchar_t *kBedwarsNpcRainbowLabels[] =
{
L"\u00A7cS\u00A76o\u00A7el\u00A7ao \u00A7bQ\u00A7du\u00A7ce\u00A76u\u00A7ee",
L"\u00A7cD\u00A76o\u00A7eu\u00A7ab\u00A7bl\u00A7de\u00A7cs",
L"\u00A7cS\u00A76q\u00A7eu\u00A7aa\u00A7bd\u00A7ds",
L"\u00A7cP\u00A76r\u00A7ea\u00A7ac\u00A7bt\u00A7di\u00A7cc\u00A76e"
};
bool IsBedwarsMinigameSettings(unsigned int hostSettings)
{
if ((hostSettings & MINIGAME_SETTINGS_FLAG) == 0)
{
return false;
}
const unsigned int minigameType = (hostSettings & MINIGAME_SETTINGS_TYPE_MASK) >> MINIGAME_SETTINGS_TYPE_SHIFT;
return (minigameType == MINIGAME_TYPE_BEDWARS);
}
bool IsBedwarsHubSettings(unsigned int hostSettings)
{
if (!IsBedwarsMinigameSettings(hostSettings))
{
return false;
}
const unsigned int role = (hostSettings & MINIGAME_SETTINGS_ROLE_MASK) >> MINIGAME_SETTINGS_ROLE_SHIFT;
return (role == MINIGAME_ROLE_HUB);
}
void SpawnBedwarsQueueSign(ServerLevel *level, int x, int y, int z, const wchar_t *line1, const wchar_t *line2)
{
if (level == NULL)
{
return;
}
level->setTile(x, y - 1, z, Tile::cloth_Id);
level->setTileAndData(x, y, z, Tile::sign_Id, 8);
shared_ptr<SignTileEntity> sign = dynamic_pointer_cast<SignTileEntity>(level->getTileEntity(x, y, z));
if (sign != NULL)
{
wstring s1 = line1 != NULL ? line1 : L"";
wstring s2 = line2 != NULL ? line2 : L"";
wstring s3 = L"\u00A7aClick NPC";
wstring s4 = L"to join";
sign->SetMessage(0, s1);
sign->SetMessage(1, s2);
sign->SetMessage(2, s3);
sign->SetMessage(3, s4);
sign->setChanged();
}
}
void KeepBedwarsLobbyNpcsStationary(ServerLevel *level)
{
if (level == NULL)
{
return;
}
Pos *spawnPos = level->getSharedSpawnPos();
if (spawnPos == NULL)
{
return;
}
const double spawnX = (double)spawnPos->x + 0.5;
const double spawnY = (double)spawnPos->y + 1.0;
const double spawnZ = (double)spawnPos->z + 0.5;
delete spawnPos;
vector<shared_ptr<Entity> > entities = level->getAllEntities();
for (size_t i = 0; i < entities.size(); ++i)
{
shared_ptr<Entity> entity = entities[i];
if (entity == NULL || entity->GetType() != eTYPE_VILLAGER)
{
continue;
}
for (size_t j = 0; j < (sizeof(kBedwarsNpcDefs) / sizeof(kBedwarsNpcDefs[0])); ++j)
{
const BedwarsNpcDef &def = kBedwarsNpcDefs[j];
const double anchorX = spawnX + (double)def.offX;
const double anchorZ = spawnZ + (double)def.offZ;
const double dx = entity->x - anchorX;
const double dz = entity->z - anchorZ;
if ((dx * dx + dz * dz) <= (3.0 * 3.0))
{
entity->xd = 0.0;
entity->yd = 0.0;
entity->zd = 0.0;
entity->moveTo(anchorX, spawnY, anchorZ, def.yRot, 0.0f);
break;
}
}
}
}
void BuildBedwarsHub(ServerLevel *level)
{
if (level == NULL)
{
return;
}
Pos *spawnPos = level->getSharedSpawnPos();
if (spawnPos == NULL)
{
return;
}
const int sx = spawnPos->x;
const int sy = spawnPos->y;
const int sz = spawnPos->z;
delete spawnPos;
for (int dx = -14; dx <= 14; ++dx)
{
for (int dz = -14; dz <= 14; ++dz)
{
const int x = sx + dx;
const int z = sz + dz;
const int ax = abs(dx);
const int az = abs(dz);
for (int y = sy + 1; y <= sy + 6; ++y)
{
level->setTile(x, y, z, 0);
}
if (ax == 14 || az == 14)
{
level->setTile(x, sy, z, Tile::stoneBrick_Id);
if (((dx + dz) & 1) == 0)
{
level->setTile(x, sy + 1, z, Tile::glass_Id);
}
}
else if (ax <= 2 || az <= 2)
{
level->setTile(x, sy, z, Tile::stoneBrick_Id);
}
}
}
for (size_t i = 0; i < (sizeof(kBedwarsNpcDefs) / sizeof(kBedwarsNpcDefs[0])); ++i)
{
const BedwarsNpcDef &def = kBedwarsNpcDefs[i];
const int px = sx + def.offX;
const int pz = sz + def.offZ;
const int woolColor = (int)i + 1;
for (int ox = -1; ox <= 1; ++ox)
{
for (int oz = -1; oz <= 1; ++oz)
{
level->setTileAndData(px + ox, sy, pz + oz, Tile::cloth_Id, woolColor);
}
}
}
}
void SpawnBedwarsLobbyNpcs(ServerLevel *level)
{
if (level == NULL)
{
return;
}
Pos *spawnPos = level->getSharedSpawnPos();
if (spawnPos == NULL)
{
return;
}
const int spawnXi = spawnPos->x;
const int spawnYi = spawnPos->y;
const int spawnZi = spawnPos->z;
const double spawnX = (double)spawnXi + 0.5;
const double spawnY = (double)spawnYi + 1.0;
const double spawnZ = (double)spawnZi + 0.5;
delete spawnPos;
for (size_t i = 0; i < (sizeof(kBedwarsNpcDefs) / sizeof(kBedwarsNpcDefs[0])); ++i)
{
const BedwarsNpcDef &def = kBedwarsNpcDefs[i];
shared_ptr<Entity> npc(EntityIO::newByEnumType(eTYPE_VILLAGER, level));
if (npc == NULL)
{
continue;
}
npc->moveTo(spawnX + (double)def.offX, spawnY, spawnZ + (double)def.offZ, def.yRot, 0.0f);
npc->setDespawnProtected();
level->addEntity(npc);
const wchar_t *rainbowLabel = kBedwarsNpcRainbowLabels[i];
SpawnBedwarsQueueSign(level, spawnXi + def.offX, spawnYi + 2, spawnZi + def.offZ, L"\u00A7cB\u00A76e\u00A7ed\u00A7aw\u00A7ba\u00A7dr\u00A7cs", rainbowLabel);
app.DebugPrintf("Bedwars lobby NPC spawned: %ls at (%.1f, %.1f, %.1f)\n",
def.label,
spawnX + (double)def.offX,
spawnY,
spawnZ + (double)def.offZ);
}
}
}
MinecraftServer::MinecraftServer()
{
// 4J - added initialisers
@ -91,6 +313,9 @@ MinecraftServer::MinecraftServer()
m_texturePackId = 0;
maxBuildHeight = Level::maxBuildHeight;
m_postUpdateThread = NULL;
m_recentTps = (float)SharedConstants::TICKS_PER_SECOND;
m_lastTpsSampleMs = 0;
m_lastTpsSampleTick = 0;
commandDispatcher = new ServerCommandDispatcher();
}
@ -1060,6 +1285,12 @@ void MinecraftServer::run(__int64 seed, void *lpParameter)
if (initServer(seed, initData, initSettings,findSeed))
{
ServerLevel *levelNormalDimension = levels[0];
if (IsBedwarsHubSettings(initSettings))
{
app.DebugPrintf("Bedwars mode detected - building hub and spawning lobby NPCs\n");
BuildBedwarsHub(levelNormalDimension);
SpawnBedwarsLobbyNpcs(levelNormalDimension);
}
// 4J-PB - Set the Stronghold position in the leveldata if there isn't one in there
Minecraft *pMinecraft = Minecraft::GetInstance();
LevelData *pLevelData=levelNormalDimension->getLevelData();
@ -1077,6 +1308,8 @@ void MinecraftServer::run(__int64 seed, void *lpParameter)
__int64 lastTime = System::currentTimeMillis();
__int64 unprocessedTime = 0;
m_lastTpsSampleMs = lastTime;
m_lastTpsSampleTick = tickCount;
while (running && !s_bServerHalted)
{
__int64 now = System::currentTimeMillis();
@ -1152,6 +1385,21 @@ void MinecraftServer::run(__int64 seed, void *lpParameter)
connection->tick();
}
}
__int64 tpsNow = System::currentTimeMillis();
__int64 tpsElapsed = tpsNow - m_lastTpsSampleMs;
if (tpsElapsed >= 1000)
{
int tickDelta = tickCount - m_lastTpsSampleTick;
if (tpsElapsed > 0)
{
m_recentTps = ((float)tickDelta * 1000.0f) / (float)tpsElapsed;
if (m_recentTps < 0.0f) m_recentTps = 0.0f;
float maxTps = (float)SharedConstants::TICKS_PER_SECOND;
if (m_recentTps > maxTps) m_recentTps = maxTps;
}
m_lastTpsSampleMs = tpsNow;
m_lastTpsSampleTick = tickCount;
}
if(MinecraftServer::setTimeAtEndOfTick)
{
MinecraftServer::setTimeAtEndOfTick = false;
@ -1468,6 +1716,11 @@ void MinecraftServer::tick()
// 4J Stu - We set the levels difficulty based on the minecraft options
level->difficulty = app.GetGameHostOption(eGameHostOption_Difficulty); //pMinecraft->options->difficulty;
if (i == 0 && IsBedwarsHubSettings(app.GetGameHostOption(eGameHostOption_All)))
{
KeepBedwarsLobbyNpcsStationary(level);
}
#if DEBUG_SERVER_DONT_SPAWN_MOBS
level->setSpawnSettings(false, false);
#else
@ -1682,4 +1935,14 @@ bool MinecraftServer::flagEntitiesToBeRemoved(unsigned int *flags)
}
}
return removedFound;
}
}

View file

@ -111,6 +111,9 @@ public:
private:
// 4J Added
//int m_lastSentDifficulty;
float m_recentTps;
__int64 m_lastTpsSampleMs;
int m_lastTpsSampleTick;
public:
// 4J Stu - This value should be incremented every time the list of players with friends-only UGC settings changes
@ -236,6 +239,7 @@ public:
//static int getSlowQueueIndex() { return s_slowQueuePlayerIndex; }
static bool canSendOnSlowQueue(INetworkPlayer *player);
static void cycleSlowQueueIndex();
float getRecentTps() const { return m_recentTps; }
void setSaveOnExit(bool save) { m_saveOnExit = save; s_bSaveOnExitAnswered = true; }
void Suspend();

View file

@ -102,12 +102,20 @@ MultiPlayerChunkCache::~MultiPlayerChunkCache()
{
delete emptyChunk;
delete waterChunk;
delete cache;
delete hasData;
// Defensive: avoid deleting loaded chunk objects here.
// During transfer/exit there can still be shared or duplicated references to chunk internals
// (especially light storage) across teardown paths, which can lead to double-free crashes.
// We release cache containers and clear references; chunk memory is reclaimed with process lifetime.
EnterCriticalSection(&m_csLoadCreate);
if (cache != NULL)
{
memset(cache, 0, XZSIZE * XZSIZE * sizeof(LevelChunk *));
}
loadedChunkList.clear();
LeaveCriticalSection(&m_csLoadCreate);
AUTO_VAR(itEnd, loadedChunkList.end());
for (AUTO_VAR(it, loadedChunkList.begin()); it != itEnd; it++)
delete *it;
delete[] cache;
delete[] hasData;
DeleteCriticalSection(&m_csLoadCreate);
}
@ -172,7 +180,11 @@ LevelChunk *MultiPlayerChunkCache::create(int x, int z)
if( g_NetworkManager.IsHost() ) // force here to disable sharing of data
{
// 4J-JEV: We are about to use shared data, abort if the server is stopped and the data is deleted.
if (MinecraftServer::getInstance()->serverHalted()) return NULL;
if (MinecraftServer::getInstance()->serverHalted())
{
LeaveCriticalSection(&m_csLoadCreate);
return NULL;
}
// If we're the host, then don't create the chunk, share data from the server's copy
#ifdef _LARGE_WORLDS
@ -303,4 +315,4 @@ void MultiPlayerChunkCache::dataReceived(int x, int z)
if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return;
int idx = ix * XZSIZE + iz;
hasData[idx] = true;
}
}

View file

@ -14,6 +14,7 @@
#include "..\Minecraft.World\net.minecraft.world.item.h"
#include "..\Minecraft.World\SharedConstants.h"
#include "Settings.h"
#include "Common\Network\NetworkPlayerInterface.h"
// #ifdef __PS3__
// #include "PS3\Network\NetworkPlayerSony.h"
// #endif
@ -21,7 +22,9 @@
Random *PendingConnection::random = new Random();
#ifdef _WINDOWS64
bool g_bRejectDuplicateNames = true;
// Windows64 LAN/minigame testing commonly uses repeated display names across clients.
// Keep joins permissive by default; duplicate names can still be rejected by toggling this.
bool g_bRejectDuplicateNames = false;
#endif
PendingConnection::PendingConnection(MinecraftServer *server, Socket *socket, const wstring& id)
@ -161,13 +164,51 @@ void PendingConnection::handleLogin(shared_ptr<LoginPacket> packet)
//if (true)// 4J removed !server->onlineMode)
bool sentDisconnect = false;
if (server->getPlayers()->isNameBanned(name))
{
app.DebugPrintf("Rejecting banned player name: %ls\n", name.c_str());
disconnect(DisconnectPacket::eDisconnect_Banned);
return;
}
if (server->getPlayers()->isWhitelistEnabled() && !server->getPlayers()->isWhiteListed(name))
{
app.DebugPrintf("Rejecting non-whitelisted player name: %ls\n", name.c_str());
disconnect(DisconnectPacket::eDisconnect_Kicked);
return;
}
PlayerUID onlineXuidForBanCheck = packet->m_onlineXuid;
#ifdef _WINDOWS64
BYTE onlineSmallIdForBanCheck = 255;
if (connection != NULL && connection->getSocket() != NULL)
{
INetworkPlayer *networkPlayer = connection->getSocket()->getPlayer();
if (networkPlayer != NULL)
{
onlineXuidForBanCheck = networkPlayer->GetUID();
onlineSmallIdForBanCheck = networkPlayer->GetSmallId();
}
}
#endif
bool rejectAsBanned = server->getPlayers()->isXuidBanned(onlineXuidForBanCheck);
#ifdef _WINDOWS64
if (rejectAsBanned)
{
// Windows64 stub player identity is slot-based, so suppress persistent ban rejections
// to avoid false "previously kicked" failures for new joiners.
app.DebugPrintf("PendingConnection::handleLogin - suppressed stale ban for %ls (smallId=%u)\n",
name.c_str(),
(unsigned int)onlineSmallIdForBanCheck);
rejectAsBanned = false;
}
#endif
if( sentDisconnect )
{
// Do nothing
}
else if( server->getPlayers()->isXuidBanned( packet->m_onlineXuid ) )
else if( rejectAsBanned )
{
app.DebugPrintf("Rejecting banned XUID for player: %ls\n", name.c_str());
disconnect(DisconnectPacket::eDisconnect_Banned);
}
#ifdef _WINDOWS64
@ -186,7 +227,8 @@ void PendingConnection::handleLogin(shared_ptr<LoginPacket> packet)
if (nameTaken)
{
app.DebugPrintf("Rejecting duplicate name: %ls\n", name.c_str());
disconnect(DisconnectPacket::eDisconnect_Banned);
// Don't map duplicate-name rejection to "banned by host".
disconnect(DisconnectPacket::eDisconnect_Kicked);
}
else
{
@ -294,4 +336,4 @@ wstring PendingConnection::getName()
bool PendingConnection::isServerPacketListener()
{
return true;
}
}

File diff suppressed because it is too large Load diff

View file

@ -24,6 +24,9 @@
#include "..\Minecraft.World\net.minecraft.world.level.storage.h"
#include "..\Minecraft.World\net.minecraft.world.level.saveddata.h"
#include "..\Minecraft.World\JavaMath.h"
#include <fstream>
#include <algorithm>
#include <cwctype>
#if defined(_XBOX) || defined(_WINDOWS64)
#include "Xbox\Network\NetworkPlayerXbox.h"
#elif defined(__PS3__) || defined(__ORBIS__)
@ -31,6 +34,68 @@
#endif
// 4J - this class is fairly substantially altered as there didn't seem any point in porting code for banning, whitelisting, ops etc.
namespace
{
static const wchar_t *kWhitelistFile = L"whitelist.txt";
static const wchar_t *kOpsFile = L"ops.txt";
static const wchar_t *kBansFile = L"banned-players.txt";
static wstring NormalizePlayerName(const wstring &name)
{
wstring out = name;
std::transform(out.begin(), out.end(), out.begin(), [](wchar_t c) { return (wchar_t)std::towlower(c); });
return out;
}
static void LoadNameSetFromFile(const wchar_t *fileName, set<wstring> &outSet)
{
outSet.clear();
std::wifstream in(fileName);
if (!in.good())
{
return;
}
wstring line;
while (std::getline(in, line))
{
// Strip comments.
size_t hashPos = line.find(L'#');
if (hashPos != wstring::npos)
{
line = line.substr(0, hashPos);
}
while (!line.empty() && iswspace(line.front()))
{
line.erase(line.begin());
}
while (!line.empty() && iswspace(line.back()))
{
line.pop_back();
}
if (!line.empty())
{
outSet.insert(NormalizePlayerName(line));
}
}
}
static void SaveNameSetToFile(const wchar_t *fileName, const set<wstring> &values)
{
std::wofstream out(fileName, std::ios::out | std::ios::trunc);
if (!out.good())
{
return;
}
for (AUTO_VAR(it, values.begin()); it != values.end(); ++it)
{
out << *it << L"\n";
}
}
}
PlayerList::PlayerList(MinecraftServer *server)
{
@ -58,6 +123,10 @@ PlayerList::PlayerList(MinecraftServer *server)
maxPlayers = server->settings->getInt(L"max-players", 20);
#endif
doWhiteList = false;
reloadWhitelist();
reloadOps();
reloadBans();
InitializeCriticalSection(&m_kickPlayersCS);
InitializeCriticalSection(&m_closePlayersCS);
@ -90,6 +159,12 @@ void PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer>
player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_HOST,1);
}
// Apply persisted operator status on join (dedicated and local-host modes).
if (isOp(player->name))
{
player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_Op, 1);
}
#if defined(__PS3__) || defined(__ORBIS__)
// PS3 networking library doesn't automatically assign PlayerUIDs to the network players for anything remote, so need to tell it what to set from the data in this packet now
if( !g_NetworkManager.IsLocalGame() )
@ -467,8 +542,64 @@ shared_ptr<ServerPlayer> PlayerList::getPlayerForLogin(PendingConnection *pendin
return shared_ptr<ServerPlayer>();
}
#endif
if (isNameBanned(userName))
{
pendingConnection->disconnect(DisconnectPacket::eDisconnect_Banned);
return shared_ptr<ServerPlayer>();
}
if (doWhiteList)
{
INetworkPlayer *joiningNetworkPlayer = NULL;
if (pendingConnection != NULL && pendingConnection->connection != NULL && pendingConnection->connection->getSocket() != NULL)
{
joiningNetworkPlayer = pendingConnection->connection->getSocket()->getPlayer();
}
if (joiningNetworkPlayer == NULL || !joiningNetworkPlayer->IsHost())
{
if (!isWhiteListed(userName))
{
app.DebugPrintf("PlayerList::getPlayerForLogin - rejecting non-whitelisted player %ls\n", userName.c_str());
pendingConnection->disconnect(DisconnectPacket::eDisconnect_Kicked);
return shared_ptr<ServerPlayer>();
}
}
}
shared_ptr<ServerPlayer> player = shared_ptr<ServerPlayer>(new ServerPlayer(server, server->getLevel(0), userName, new ServerPlayerGameMode(server->getLevel(0)) ));
wstring resolvedName = userName;
#ifdef _WINDOWS64
// Win64 testing often has multiple clients with the same OS username.
// Keep server-side player names unique to avoid legacy name-based collisions.
if (!resolvedName.empty())
{
const wstring baseName = resolvedName;
int suffix = 2;
bool unique = false;
while (!unique)
{
unique = true;
for (AUTO_VAR(it, players.begin()); it != players.end(); ++it)
{
shared_ptr<ServerPlayer> existing = *it;
if (existing != NULL && existing->name == resolvedName)
{
const int currentSuffix = suffix++;
wstring trimmedBase = baseName;
if (trimmedBase.length() > 56)
{
trimmedBase = trimmedBase.substr(0, 56);
}
resolvedName = trimmedBase + L"_" + to_wstring(currentSuffix);
unique = false;
break;
}
}
}
}
#endif
shared_ptr<ServerPlayer> player = shared_ptr<ServerPlayer>(new ServerPlayer(server, server->getLevel(0), resolvedName, new ServerPlayerGameMode(server->getLevel(0)) ));
player->gameMode->player = player; // 4J added as had to remove this assignment from ServerPlayer ctor
player->setXuid( xuid ); // 4J Added
player->setOnlineXuid( onlineXuid ); // 4J Added
@ -930,7 +1061,14 @@ void PlayerList::tick()
if (player != NULL)
{
#ifdef _WINDOWS64
// Keep kicks session-scoped on Windows64. The stub identity maps to slot ids, so
// persisting bans can incorrectly block later joiners that reuse a slot.
app.DebugPrintf("PlayerList::tick - kicking smallId=%u (no persistent ban on Windows64)\n",
(unsigned int)smallId);
#else
m_bannedXuids.push_back( player->getOnlineXuid() );
#endif
// 4J Stu - If we have kicked a player, make sure that they have no privileges if they later try to join the world when trust players is off
player->enableAllPlayerPrivileges( false );
player->connection->setWasKicked();
@ -1003,12 +1141,16 @@ wstring PlayerList::getPlayerNames()
bool PlayerList::isWhiteListed(const wstring& name)
{
return true;
if (!doWhiteList)
{
return true;
}
return (m_whitelistNames.find(NormalizePlayerName(name)) != m_whitelistNames.end());
}
bool PlayerList::isOp(const wstring& name)
{
return false;
return (m_operatorNames.find(NormalizePlayerName(name)) != m_operatorNames.end());
}
bool PlayerList::isOp(shared_ptr<ServerPlayer> player)
@ -1177,14 +1319,90 @@ void PlayerList::saveAll(ProgressListener *progressListener, bool bDeleteGuestMa
void PlayerList::whiteList(const wstring& playerName)
{
m_whitelistNames.insert(NormalizePlayerName(playerName));
SaveNameSetToFile(kWhitelistFile, m_whitelistNames);
}
void PlayerList::blackList(const wstring& playerName)
{
m_whitelistNames.erase(NormalizePlayerName(playerName));
SaveNameSetToFile(kWhitelistFile, m_whitelistNames);
}
void PlayerList::reloadWhitelist()
{
LoadNameSetFromFile(kWhitelistFile, m_whitelistNames);
}
void PlayerList::setWhitelistEnabled(bool enabled)
{
doWhiteList = enabled;
}
bool PlayerList::isWhitelistEnabled() const
{
return doWhiteList;
}
bool PlayerList::addOp(const wstring &playerName)
{
const size_t oldSize = m_operatorNames.size();
m_operatorNames.insert(NormalizePlayerName(playerName));
if (m_operatorNames.size() != oldSize)
{
SaveNameSetToFile(kOpsFile, m_operatorNames);
return true;
}
return false;
}
bool PlayerList::removeOp(const wstring &playerName)
{
const size_t erased = m_operatorNames.erase(NormalizePlayerName(playerName));
if (erased != 0)
{
SaveNameSetToFile(kOpsFile, m_operatorNames);
return true;
}
return false;
}
void PlayerList::reloadOps()
{
LoadNameSetFromFile(kOpsFile, m_operatorNames);
}
bool PlayerList::banName(const wstring &playerName)
{
const size_t oldSize = m_bannedNames.size();
m_bannedNames.insert(NormalizePlayerName(playerName));
if (m_bannedNames.size() != oldSize)
{
SaveNameSetToFile(kBansFile, m_bannedNames);
return true;
}
return false;
}
bool PlayerList::unbanName(const wstring &playerName)
{
const size_t erased = m_bannedNames.erase(NormalizePlayerName(playerName));
if (erased != 0)
{
SaveNameSetToFile(kBansFile, m_bannedNames);
return true;
}
return false;
}
void PlayerList::reloadBans()
{
LoadNameSetFromFile(kBansFile, m_bannedNames);
}
bool PlayerList::isNameBanned(const wstring &name) const
{
return (m_bannedNames.find(NormalizePlayerName(name)) != m_bannedNames.end());
}
void PlayerList::sendLevelInfo(shared_ptr<ServerPlayer> player, ServerLevel *level)

View file

@ -1,5 +1,6 @@
#pragma once
#include <deque>
#include <set>
#include "..\Minecraft.World\ArrayWithLength.h"
class ServerPlayer;
@ -34,6 +35,9 @@ private:
CRITICAL_SECTION m_kickPlayersCS;
deque<BYTE> m_smallIdsToClose;
CRITICAL_SECTION m_closePlayersCS;
set<wstring> m_whitelistNames;
set<wstring> m_operatorNames;
set<wstring> m_bannedNames;
/* 4J - removed
Set<String> bans = new HashSet<String>();
Set<String> ipBans = new HashSet<String>();
@ -99,10 +103,19 @@ public:
bool sendTo(const wstring& name, shared_ptr<Packet> packet);
// 4J Added ProgressListener *progressListener param and bDeleteGuestMaps param
void saveAll(ProgressListener *progressListener, bool bDeleteGuestMaps = false);
void whiteList(const wstring& playerName);
void whiteList(const wstring& playerName);
void blackList(const wstring& playerName);
// Set<String> getWhiteList(); / 4J removed
void reloadWhitelist();
void setWhitelistEnabled(bool enabled);
bool isWhitelistEnabled() const;
bool addOp(const wstring &playerName);
bool removeOp(const wstring &playerName);
void reloadOps();
bool banName(const wstring &playerName);
bool unbanName(const wstring &playerName);
void reloadBans();
bool isNameBanned(const wstring &name) const;
void sendLevelInfo(shared_ptr<ServerPlayer> player, ServerLevel *level);
void sendAllPlayerInfo(shared_ptr<ServerPlayer> player);
int getPlayerCount();

View file

@ -38,6 +38,11 @@ void Screen::keyPressed(wchar_t eventCharacter, int eventKey)
}
}
void Screen::HandleKeyPressed(wchar_t eventCharacter, int eventKey)
{
keyPressed(eventCharacter, eventKey);
}
wstring Screen::getClipboard()
{
// 4J - removed

View file

@ -28,6 +28,7 @@ protected:
public:
static wstring getClipboard();
static void setClipboard(const wstring& str);
void HandleKeyPressed(wchar_t eventCharacter, int eventKey);
private:
Button *clickedButton;
@ -51,4 +52,3 @@ public:
virtual void confirmResult(bool result, int id);
virtual void tabPressed();
};

View file

@ -8,6 +8,7 @@
#include "Settings.h"
#include "PlayerList.h"
#include "MultiPlayerLevel.h"
#include "TextEditScreen.h"
#include "..\Minecraft.World\Pos.h"
#include "..\Minecraft.World\net.minecraft.world.level.h"
#include "..\Minecraft.World\net.minecraft.world.level.storage.h"
@ -269,6 +270,24 @@ void ServerPlayer::flushEntitiesToRemove()
}
void ServerPlayer::openTextEdit(shared_ptr<SignTileEntity> sign)
{
if (sign == NULL || connection == NULL)
{
return;
}
if (connection->isLocal())
{
Minecraft *mc = Minecraft::GetInstance();
if (mc != NULL)
{
app.DebugPrintf("ServerPlayer::openTextEdit - opening TextEditScreen for local player");
mc->setScreen(new TextEditScreen(sign));
}
}
}
// 4J - have split doTick into 3 bits, so that we can call the doChunkSendingTick separately, but still do the equivalent of what calling a full doTick used to do, by calling this method
void ServerPlayer::doTick(bool sendChunks, bool dontDelayChunks/*=false*/, bool ignorePortal/*=false*/)
{
@ -445,7 +464,7 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks)
for (unsigned int i = 0; i < tes->size(); i++)
{
// 4J Stu - Added delay param to ensure that these arrive after the BRUPs from above
// Fix for #9169 - ART : Sign text is replaced with the words “Awaiting approval”.
// Fix for #9169 - ART : Sign text is replaced with the words ?Awaiting approval?.
broadcast(tes->at(i), !connection->isLocal() && !dontDelayChunks);
}
delete tes;

View file

@ -97,6 +97,7 @@ public:
virtual bool startCrafting(int x, int y, int z); // 4J added bool return
virtual bool startEnchanting(int x, int y, int z); // 4J added bool return
virtual bool startRepairing(int x, int y, int z); // 4J added bool return
virtual void openTextEdit(shared_ptr<SignTileEntity> sign);
virtual bool openContainer(shared_ptr<Container> container); // 4J added bool return
virtual bool openFurnace(shared_ptr<FurnaceTileEntity> furnace); // 4J added bool return
virtual bool openTrap(shared_ptr<DispenserTileEntity> trap); // 4J added bool return

View file

@ -62,6 +62,10 @@ void TextEditScreen::keyPressed(wchar_t ch, int eventKey)
if (eventKey == Keyboard::KEY_DOWN || eventKey == Keyboard::KEY_RETURN) line = (line + 1) & 3;
wstring temp=sign->GetMessage(line);
while (!temp.empty() && temp[temp.length() - 1] == L' ')
{
temp = temp.substr(0, temp.length() - 1);
}
if (eventKey == Keyboard::KEY_BACK && temp.length() > 0)
{
temp = temp.substr(0, temp.length() - 1);
@ -116,4 +120,4 @@ void TextEditScreen::render(int xm, int ym, float a)
Screen::render(xm, ym, a);
}
}

View file

@ -47,7 +47,28 @@ std::vector<BYTE> WinsockNetLayer::s_freeSmallIds;
bool g_Win64MultiplayerHost = false;
bool g_Win64MultiplayerJoin = false;
int g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT;
char g_Win64MultiplayerIP[256] = "127.0.0.1";
int g_Win64MultiplayerMaxPlayers = MINECRAFT_NET_MAX_PLAYERS;
char g_Win64MultiplayerIP[256] = "0.0.0.0";
BYTE WinsockNetLayer::s_maxPlayers = MINECRAFT_NET_MAX_PLAYERS;
static void ConfigureConnectedSocket(SOCKET sock)
{
if (sock == INVALID_SOCKET)
{
return;
}
int noDelay = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
int keepAlive = 1;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const char *)&keepAlive, sizeof(keepAlive));
int recvTimeoutMs = 30000;
int sendTimeoutMs = 30000;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&recvTimeoutMs, sizeof(recvTimeoutMs));
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (const char *)&sendTimeoutMs, sizeof(sendTimeoutMs));
}
bool WinsockNetLayer::Initialize()
{
@ -145,6 +166,14 @@ bool WinsockNetLayer::HostGame(int port)
s_hostSmallId = 0;
s_nextSmallId = 1;
s_hostGamePort = port;
if (g_Win64MultiplayerMaxPlayers >= 1 && g_Win64MultiplayerMaxPlayers <= MINECRAFT_NET_MAX_PLAYERS)
{
s_maxPlayers = (BYTE)g_Win64MultiplayerMaxPlayers;
}
else
{
s_maxPlayers = MINECRAFT_NET_MAX_PLAYERS;
}
EnterCriticalSection(&s_freeSmallIdLock);
s_freeSmallIds.clear();
@ -161,7 +190,15 @@ bool WinsockNetLayer::HostGame(int port)
char portStr[16];
sprintf_s(portStr, "%d", port);
int iResult = getaddrinfo(NULL, portStr, &hints, &result);
const char *bindIp = NULL;
if (g_Win64MultiplayerIP[0] != 0 &&
strcmp(g_Win64MultiplayerIP, "*") != 0 &&
strcmp(g_Win64MultiplayerIP, "0.0.0.0") != 0)
{
bindIp = g_Win64MultiplayerIP;
}
int iResult = getaddrinfo(bindIp, portStr, &hints, &result);
if (iResult != 0)
{
app.DebugPrintf("getaddrinfo failed: %d\n", iResult);
@ -189,7 +226,8 @@ bool WinsockNetLayer::HostGame(int port)
return false;
}
iResult = listen(s_listenSocket, SOMAXCONN);
int backlog = (s_maxPlayers > 1) ? (int)s_maxPlayers : 1;
iResult = listen(s_listenSocket, backlog);
if (iResult == SOCKET_ERROR)
{
app.DebugPrintf("listen() failed: %d\n", WSAGetLastError());
@ -203,7 +241,10 @@ bool WinsockNetLayer::HostGame(int port)
s_acceptThread = CreateThread(NULL, 0, AcceptThreadProc, NULL, 0, NULL);
app.DebugPrintf("Win64 LAN: Hosting on port %d\n", port);
app.DebugPrintf("Win64 LAN: Hosting on %s:%d (maxPlayers=%u)\n",
(bindIp != NULL) ? bindIp : "0.0.0.0",
port,
(unsigned int)s_maxPlayers);
return true;
}
@ -213,6 +254,14 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
s_isHost = false;
s_hostSmallId = 0;
s_connected = false;
s_active = false;
if (s_hostConnectionSocket != INVALID_SOCKET)
{
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
}
struct addrinfo hints = {};
struct addrinfo *result = NULL;
@ -231,37 +280,54 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
return false;
}
s_hostConnectionSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (s_hostConnectionSocket == INVALID_SOCKET)
bool connected = false;
BYTE assignedSmallId = 0;
const int maxAttempts = 12;
for (int attempt = 0; attempt < maxAttempts; ++attempt)
{
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
freeaddrinfo(result);
return false;
s_hostConnectionSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (s_hostConnectionSocket == INVALID_SOCKET)
{
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
break;
}
ConfigureConnectedSocket(s_hostConnectionSocket);
iResult = connect(s_hostConnectionSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR)
{
int err = WSAGetLastError();
app.DebugPrintf("connect() to %s:%d failed (attempt %d/%d): %d\n", ip, port, attempt + 1, maxAttempts, err);
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
Sleep(200);
continue;
}
BYTE assignBuf[1];
int bytesRecv = recv(s_hostConnectionSocket, (char *)assignBuf, 1, 0);
if (bytesRecv != 1)
{
app.DebugPrintf("Failed to receive small ID assignment from host (attempt %d/%d)\n", attempt + 1, maxAttempts);
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
Sleep(200);
continue;
}
assignedSmallId = assignBuf[0];
connected = true;
break;
}
int noDelay = 1;
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
iResult = connect(s_hostConnectionSocket, result->ai_addr, (int)result->ai_addrlen);
freeaddrinfo(result);
if (iResult == SOCKET_ERROR)
{
app.DebugPrintf("connect() to %s:%d failed: %d\n", ip, port, WSAGetLastError());
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
return false;
}
BYTE assignBuf[1];
int bytesRecv = recv(s_hostConnectionSocket, (char *)assignBuf, 1, 0);
if (bytesRecv != 1)
if (!connected)
{
app.DebugPrintf("Failed to receive small ID assignment from host\n");
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
return false;
}
s_localSmallId = assignBuf[0];
s_localSmallId = assignedSmallId;
app.DebugPrintf("Win64 LAN: Connected to %s:%d, assigned smallId=%d\n", ip, port, s_localSmallId);
@ -363,16 +429,22 @@ void WinsockNetLayer::HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsig
INetworkPlayer *pPlayerFrom = g_NetworkManager.GetPlayerBySmallId(fromSmallId);
INetworkPlayer *pPlayerTo = g_NetworkManager.GetPlayerBySmallId(toSmallId);
if (pPlayerFrom == NULL || pPlayerTo == NULL) return;
if (s_isHost)
{
if (pPlayerFrom == NULL)
{
return;
}
::Socket *pSocket = pPlayerFrom->GetSocket();
if (pSocket != NULL)
pSocket->pushDataToQueue(data, dataSize, false);
}
else
{
if (pPlayerTo == NULL)
{
return;
}
::Socket *pSocket = pPlayerTo->GetSocket();
if (pSocket != NULL)
pSocket->pushDataToQueue(data, dataSize, true);
@ -391,8 +463,7 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
break;
}
int noDelay = 1;
setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
ConfigureConnectedSocket(clientSocket);
extern QNET_STATE _iQNetStubState;
if (_iQNetStubState != QNET_STATE_GAME_PLAY)
@ -409,7 +480,7 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
assignedSmallId = s_freeSmallIds.back();
s_freeSmallIds.pop_back();
}
else if (s_nextSmallId < MINECRAFT_NET_MAX_PLAYERS)
else if (s_nextSmallId < s_maxPlayers)
{
assignedSmallId = s_nextSmallId++;
}
@ -479,7 +550,8 @@ DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param)
BYTE clientSmallId = s_connections[connIdx].smallId;
LeaveCriticalSection(&s_connectionsLock);
BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE];
std::vector<BYTE> recvBuf;
recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE);
while (s_active)
{
@ -492,23 +564,30 @@ DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param)
int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
if (packetSize <= 0 || packetSize > WIN64_NET_RECV_BUFFER_SIZE)
if (packetSize <= 0 || packetSize > WIN64_NET_MAX_PACKET_SIZE)
{
app.DebugPrintf("Win64 LAN: Invalid packet size %d from client smallId=%d\n", packetSize, clientSmallId);
app.DebugPrintf("Win64 LAN: Invalid packet size %d from client smallId=%d (max=%d)\n",
packetSize,
clientSmallId,
(int)WIN64_NET_MAX_PACKET_SIZE);
break;
}
if (!RecvExact(sock, recvBuf, packetSize))
if ((int)recvBuf.size() < packetSize)
{
recvBuf.resize(packetSize);
app.DebugPrintf("Win64 LAN: Resized host recv buffer to %d bytes for client smallId=%d\n", packetSize, clientSmallId);
}
if (!RecvExact(sock, &recvBuf[0], packetSize))
{
app.DebugPrintf("Win64 LAN: Client smallId=%d disconnected (body)\n", clientSmallId);
break;
}
HandleDataReceived(clientSmallId, s_hostSmallId, recvBuf, packetSize);
HandleDataReceived(clientSmallId, s_hostSmallId, &recvBuf[0], packetSize);
}
delete[] recvBuf;
EnterCriticalSection(&s_connectionsLock);
for (size_t i = 0; i < s_connections.size(); i++)
{
@ -552,7 +631,8 @@ void WinsockNetLayer::PushFreeSmallId(BYTE smallId)
DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param)
{
BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE];
std::vector<BYTE> recvBuf;
recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE);
while (s_active && s_hostConnectionSocket != INVALID_SOCKET)
{
@ -565,28 +645,34 @@ DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param)
int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
if (packetSize <= 0 || packetSize > WIN64_NET_RECV_BUFFER_SIZE)
if (packetSize <= 0 || packetSize > WIN64_NET_MAX_PACKET_SIZE)
{
app.DebugPrintf("Win64 LAN: Invalid packet size %d from host\n", packetSize);
app.DebugPrintf("Win64 LAN: Invalid packet size %d from host (max=%d)\n",
packetSize,
(int)WIN64_NET_MAX_PACKET_SIZE);
break;
}
if (!RecvExact(s_hostConnectionSocket, recvBuf, packetSize))
if ((int)recvBuf.size() < packetSize)
{
recvBuf.resize(packetSize);
app.DebugPrintf("Win64 LAN: Resized client recv buffer to %d bytes\n", packetSize);
}
if (!RecvExact(s_hostConnectionSocket, &recvBuf[0], packetSize))
{
app.DebugPrintf("Win64 LAN: Disconnected from host (body)\n");
break;
}
HandleDataReceived(s_hostSmallId, s_localSmallId, recvBuf, packetSize);
HandleDataReceived(s_hostSmallId, s_localSmallId, &recvBuf[0], packetSize);
}
delete[] recvBuf;
s_connected = false;
return 0;
}
bool WinsockNetLayer::StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer)
bool WinsockNetLayer::StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer, unsigned char maxPlayers)
{
if (s_advertising) return true;
if (!s_initialized) return false;
@ -598,7 +684,7 @@ bool WinsockNetLayer::StartAdvertising(int gamePort, const wchar_t *hostName, un
s_advertiseData.gamePort = (WORD)gamePort;
wcsncpy_s(s_advertiseData.hostName, 32, hostName, _TRUNCATE);
s_advertiseData.playerCount = 1;
s_advertiseData.maxPlayers = MINECRAFT_NET_MAX_PLAYERS;
s_advertiseData.maxPlayers = (maxPlayers > 0) ? maxPlayers : MINECRAFT_NET_MAX_PLAYERS;
s_advertiseData.gameHostSettings = gameSettings;
s_advertiseData.texturePackParentId = texPackId;
s_advertiseData.subTexturePackId = subTexId;
@ -648,6 +734,13 @@ void WinsockNetLayer::UpdateAdvertisePlayerCount(BYTE count)
LeaveCriticalSection(&s_advertiseLock);
}
void WinsockNetLayer::UpdateAdvertiseGameSettings(unsigned int gameSettings)
{
EnterCriticalSection(&s_advertiseLock);
s_advertiseData.gameHostSettings = gameSettings;
LeaveCriticalSection(&s_advertiseLock);
}
void WinsockNetLayer::UpdateAdvertiseJoinable(bool joinable)
{
EnterCriticalSection(&s_advertiseLock);

View file

@ -12,6 +12,7 @@
#define WIN64_NET_DEFAULT_PORT 25565
#define WIN64_NET_MAX_CLIENTS 7
#define WIN64_NET_RECV_BUFFER_SIZE 65536
#define WIN64_NET_MAX_PACKET_SIZE (4 * 1024 * 1024)
#define WIN64_LAN_DISCOVERY_PORT 25566
#define WIN64_LAN_BROADCAST_MAGIC 0x4D434C4E
@ -82,8 +83,9 @@ public:
static bool PopDisconnectedSmallId(BYTE *outSmallId);
static void PushFreeSmallId(BYTE smallId);
static bool StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer);
static bool StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer, unsigned char maxPlayers = MINECRAFT_NET_MAX_PLAYERS);
static void StopAdvertising();
static void UpdateAdvertiseGameSettings(unsigned int gameSettings);
static void UpdateAdvertisePlayerCount(BYTE count);
static void UpdateAdvertiseJoinable(bool joinable);
@ -92,6 +94,7 @@ public:
static std::vector<Win64LANSession> GetDiscoveredSessions();
static int GetHostPort() { return s_hostGamePort; }
static BYTE GetMaxPlayers() { return s_maxPlayers; }
private:
static DWORD WINAPI AcceptThreadProc(LPVOID param);
@ -125,6 +128,7 @@ private:
static Win64LANBroadcast s_advertiseData;
static CRITICAL_SECTION s_advertiseLock;
static int s_hostGamePort;
static BYTE s_maxPlayers;
static SOCKET s_discoverySock;
static HANDLE s_discoveryThread;
@ -142,6 +146,7 @@ private:
extern bool g_Win64MultiplayerHost;
extern bool g_Win64MultiplayerJoin;
extern int g_Win64MultiplayerPort;
extern int g_Win64MultiplayerMaxPlayers;
extern char g_Win64MultiplayerIP[256];
#endif

View file

@ -31,6 +31,7 @@ void CConsoleMinecraftApp::ExitGame()
}
void CConsoleMinecraftApp::FatalLoadError()
{
app.DebugPrintf("CConsoleMinecraftApp::FatalLoadError\n");
}
void CConsoleMinecraftApp::CaptureSaveThumbnail()

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
# LCE Dedicated Server Properties
dedicated=true
server-name=LCE Dedicated
world-name=LCE Dedicated Server
bind-address=0.0.0.0
server-port=25565
max-players=8
level-type=flat
save-world=false
whitelist=false

View file

@ -11,7 +11,21 @@ public:
T *data;
unsigned int length;
arrayWithLength() { data = NULL; length = 0; }
arrayWithLength(unsigned int elements, bool bClearArray=true) { assert(elements!=0); data = new T[elements]; if(bClearArray){ memset( data,0,sizeof(T)*elements); } this->length = elements; }
arrayWithLength(unsigned int elements, bool bClearArray=true)
{
if(elements == 0)
{
// Keep a valid pointer even for empty arrays to avoid null dereferences in
// legacy code paths that assume data is always non-null.
data = new T[1];
if(bClearArray){ memset(data,0,sizeof(T)); }
length = 0;
return;
}
data = new T[elements];
if(bClearArray){ memset( data,0,sizeof(T)*elements); }
this->length = elements;
}
// 4J Stu Added this ctor so I static init arrays in the Item derivation tree
arrayWithLength( T data[], unsigned int elements) { this->data = data; this->length = elements; }

View file

@ -182,7 +182,7 @@ public:
intArray getIntArray(wchar_t * name)
{
if (tags.find(name) == tags.end()) return intArray(0);
if (tags.find(name) == tags.end()) return intArray();
return ((IntArrayTag *) tags[name])->data;
}

View file

@ -421,26 +421,29 @@ void Packet::writeUtf(const wstring& value, DataOutputStream *dos) // throws IOE
wstring Packet::readUtf(DataInputStream *dis, int maxLength) // throws IOException TODO 4J JEV, should this declare a throws?
{
short stringLength = dis->readShort();
if (stringLength > maxLength)
{
wstringstream stream;
stream << L"Received string length longer than maximum allowed (" << stringLength << " > " << maxLength << ")";
assert(false);
// throw new IOException( stream.str() );
}
if (stringLength < 0)
{
assert(false);
// throw new IOException(L"Received string length is less than zero! Weird string!");
app.DebugPrintf("Packet::readUtf - invalid negative length %d (max=%d)\n", (int)stringLength, maxLength);
return L"";
}
const int sourceLength = (int)stringLength;
const int safeLength = sourceLength > maxLength ? maxLength : sourceLength;
if (sourceLength > maxLength)
{
app.DebugPrintf("Packet::readUtf - clamping overlong string (%d > %d)\n", sourceLength, maxLength);
}
wstring builder = L"";
for (int i = 0; i < stringLength; i++)
builder.reserve(safeLength);
for (int i = 0; i < sourceLength; i++)
{
wchar_t rc = dis->readChar();
builder.push_back( rc );
if (i < safeLength)
{
builder.push_back(rc);
}
}
return builder;

View file

@ -18,11 +18,20 @@ void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName )
info.szName = szThreadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
#if defined(_WINDOWS64)
// The 0x406D1388 thread-name exception is debugger-only metadata.
// Skip raising it when no debugger is attached to avoid standalone exits.
if (!IsDebuggerPresent())
{
return;
}
#endif
#if ( defined _WINDOWS64 | defined _DURANGO )
#if ( defined _WINDOWS64 || defined _DURANGO )
__try
{
RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR *)&info );
RaiseException( 0x406D1388, 0, 4, (ULONG_PTR *)&info );
}
__except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER )
{

View file

@ -68,7 +68,6 @@ Global
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.ContentPackage|Windows64.Build.0 = ContentPackage|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.ContentPackage|Xbox 360.ActiveCfg = ContentPackage|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Debug|Durango.ActiveCfg = Debug|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Debug|Durango.Build.0 = Debug|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Debug|ORBIS.ActiveCfg = Debug|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Debug|PS3.ActiveCfg = Debug|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Debug|PSVita.ActiveCfg = Debug|x64
@ -76,7 +75,6 @@ Global
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Debug|Windows64.Build.0 = Debug|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Debug|Xbox 360.ActiveCfg = Debug|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Release|Durango.ActiveCfg = Release|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Release|Durango.Build.0 = Release|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Release|ORBIS.ActiveCfg = Release|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Release|PS3.ActiveCfg = Release|x64
{F046C3CE-9749-4823-B32B-D9CC10B1A2C8}.Release|PSVita.ActiveCfg = Release|x64
@ -108,7 +106,6 @@ Global
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.ContentPackage|Windows64.ActiveCfg = ContentPackage|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.ContentPackage|Xbox 360.ActiveCfg = ContentPackage|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Debug|Durango.ActiveCfg = Debug|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Debug|Durango.Build.0 = Debug|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Debug|ORBIS.ActiveCfg = Debug|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Debug|PS3.ActiveCfg = Debug|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Debug|PSVita.ActiveCfg = Debug|x64
@ -116,7 +113,6 @@ Global
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Debug|Windows64.Build.0 = Debug|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Debug|Xbox 360.ActiveCfg = Debug|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Release|Durango.ActiveCfg = Release|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Release|Durango.Build.0 = Release|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Release|ORBIS.ActiveCfg = Release|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Release|PS3.ActiveCfg = Release|x64
{1B9A8C38-DD48-448C-AA24-E1A35E0089A3}.Release|PSVita.ActiveCfg = Release|x64

5
proxy-worlds.properties Normal file
View file

@ -0,0 +1,5 @@
# Bungee-like route table for /server and /send
# format: name=host:port|Display Name
hub=127.0.0.1:25565|Hub
bedwars=127.0.0.1:25566|Bedwars Match
practice=127.0.0.1:25567|Practice