feat: TU19 (Dec 2014) Features & Content (#155)

* try to resolve merge conflict

* feat: TU19 (Dec 2014) Features & Content (#32)

* December 2014 files

* Working release build

* Fix compilation issues

* Add sound to Windows64Media

* Add DLC content and force Tutorial DLC

* Revert "Add DLC content and force Tutorial DLC"

This reverts commit 97a4399472.

* Disable broken light packing

* Disable breakpoint during DLC texture map load

Allows DLC loading but the DLC textures are still broken

* Fix post build not working

* ...

* fix vs2022 build

* fix cmake build

---------

Co-authored-by: Loki <lokirautio@gmail.com>
This commit is contained in:
daoge
2026-03-03 03:04:10 +08:00
committed by GitHub
parent 84c31a2331
commit b3feddfef3
2069 changed files with 264842 additions and 139522 deletions

View File

@@ -6,6 +6,7 @@
#include "..\..\..\Minecraft.World\ThreadName.h"
#include "..\..\..\Minecraft.World\Entity.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.h"
#include "..\..\..\Minecraft.World\FireworksRecipe.h"
#include "..\..\ClientConnection.h"
#include "..\..\Minecraft.h"
#include "..\..\User.h"
@@ -30,7 +31,7 @@
#ifdef _XBOX
#include "Common\XUI\XUI_PauseMenu.h"
#elif !(defined __PSVITA__)
#else
#include "Common\UI\UI.h"
#include "Common\UI\UIScene_PauseMenu.h"
#include "..\..\Xbox\Network\NetworkPlayerXbox.h"
@@ -204,7 +205,79 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame
}
else
{
param->seed = seed = app.getLevelGenerationOptions()->getLevelSeed();
param->seed = seed = app.getLevelGenerationOptions()->getLevelSeed();
if(param->levelGen->isTutorial())
{
// Load the tutorial save data here
if(param->levelGen->requiresBaseSave() && !param->levelGen->getBaseSavePath().empty() )
{
#ifdef _XBOX
#ifdef _TU_BUILD
wstring fileRoot = L"UPDATE:\\res\\GameRules\\" + param->levelGen->getBaseSavePath();
#else
wstring fileRoot = L"GAME:\\res\\TitleUpdate\\GameRules\\" + param->levelGen->getBaseSavePath();
#endif
#else
#ifdef _WINDOWS64
wstring fileRoot = L"Windows64Media\\Tutorial\\" + param->levelGen->getBaseSavePath();
File root(fileRoot);
if(!root.exists()) fileRoot = L"Windows64\\Tutorial\\" + param->levelGen->getBaseSavePath();
#elif defined(__ORBIS__)
wstring fileRoot = L"/app0/orbis/Tutorial/" + param->levelGen->getBaseSavePath();
#elif defined(__PSVITA__)
wstring fileRoot = L"PSVita/Tutorial/" + param->levelGen->getBaseSavePath();
#elif defined(__PS3__)
wstring fileRoot = L"PS3/Tutorial/" + param->levelGen->getBaseSavePath();
#else
wstring fileRoot = L"Tutorial\\" + param->levelGen->getBaseSavePath();
#endif
#endif
File grf(fileRoot);
if (grf.exists())
{
#ifdef _UNICODE
wstring path = grf.getPath();
const WCHAR *pchFilename=path.c_str();
HANDLE fileHandle = CreateFile(
pchFilename, // file name
GENERIC_READ, // access mode
0, // share mode // TODO 4J Stu - Will we need to share file? Probably not but...
NULL, // Unused
OPEN_EXISTING , // how to create // TODO 4J Stu - Assuming that the file already exists if we are opening to read from it
FILE_FLAG_SEQUENTIAL_SCAN, // file attributes
NULL // Unsupported
);
#else
const char *pchFilename=wstringtofilename(grf.getPath());
HANDLE fileHandle = CreateFile(
pchFilename, // file name
GENERIC_READ, // access mode
0, // share mode // TODO 4J Stu - Will we need to share file? Probably not but...
NULL, // Unused
OPEN_EXISTING , // how to create // TODO 4J Stu - Assuming that the file already exists if we are opening to read from it
FILE_FLAG_SEQUENTIAL_SCAN, // file attributes
NULL // Unsupported
);
#endif
if( fileHandle != INVALID_HANDLE_VALUE )
{
DWORD bytesRead,dwFileSize = GetFileSize(fileHandle,NULL);
PBYTE pbData = (PBYTE) new BYTE[dwFileSize];
BOOL bSuccess = ReadFile(fileHandle,pbData,dwFileSize,&bytesRead,NULL);
if(bSuccess==FALSE)
{
app.FatalLoadError();
}
CloseHandle(fileHandle);
// 4J-PB - is it possible that we can get here after a read fail and it's not an error?
param->levelGen->setBaseSaveData(pbData, dwFileSize);
}
}
}
}
}
}
}
@@ -694,7 +767,7 @@ int CGameNetworkManager::JoinFromInvite_SignInReturned(void *pParam,bool bContin
{
UINT uiIDA[1];
uiIDA[0] = IDS_OK;
ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, iPad, NULL, NULL, app.GetStringTable());
ui.RequestErrorMessage(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, iPad);
return 0;
}
@@ -738,7 +811,7 @@ int CGameNetworkManager::JoinFromInvite_SignInReturned(void *pParam,bool bContin
{
UINT uiIDA[1];
uiIDA[0]=IDS_CONFIRM_OK;
ui.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable());
ui.RequestErrorMessage( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad());
}
else
{
@@ -856,6 +929,16 @@ int CGameNetworkManager::ServerThreadProc( void* lpParameter )
NetworkGameInitData *param = (NetworkGameInitData *)lpParameter;
seed = param->seed;
app.SetGameHostOption(eGameHostOption_All,param->settings);
// 4J Stu - If we are loading a DLC save that's separate from the texture pack, load
if( param->levelGen != NULL && (param->texturePackId == 0 || param->levelGen->getRequiredTexturePackId() != param->texturePackId) )
{
while((Minecraft::GetInstance()->skins->needsUIUpdate() || ui.IsReloadingSkin()))
{
Sleep(1);
}
param->levelGen->loadBaseSaveData();
}
}
SetThreadName(-1, "Minecraft Server thread");
@@ -867,6 +950,7 @@ int CGameNetworkManager::ServerThreadProc( void* lpParameter )
Entity::useSmallIds();
Level::enableLightingCache();
Tile::CreateNewThreadStorage();
FireworksRecipe::CreateNewThreadStorage();
MinecraftServer::main(seed, lpParameter); //saveData, app.GetGameHostOption(eGameHostOption_All));
@@ -889,10 +973,7 @@ int CGameNetworkManager::ExitAndJoinFromInviteThreadProc( void* lpParam )
Compression::UseDefaultThreadStorage();
//app.SetGameStarted(false);
#ifndef __PSVITA__
UIScene_PauseMenu::_ExitWorld(NULL);
#endif
while( g_NetworkManager.IsInSession() )
{
@@ -900,7 +981,7 @@ int CGameNetworkManager::ExitAndJoinFromInviteThreadProc( void* lpParam )
}
// Xbox should always be online when receiving invites - on PS3 we need to check & ask the user to sign in
#ifndef __PS3__
#if !defined(__PS3__) && !defined(__PSVITA__)
JoinFromInviteData *inviteData = (JoinFromInviteData *)lpParam;
app.SetAction(inviteData->dwUserIndex, eAppAction_JoinFromInvite, lpParam);
#else
@@ -914,7 +995,7 @@ int CGameNetworkManager::ExitAndJoinFromInviteThreadProc( void* lpParam )
UINT uiIDA[2];
uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT;
uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE;
ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CGameNetworkManager::MustSignInReturned_0,lpParam, app.GetStringTable());
ui.RequestErrorMessage(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CGameNetworkManager::MustSignInReturned_0,lpParam);
}
#endif
@@ -1053,16 +1134,16 @@ int CGameNetworkManager::ChangeSessionTypeThreadProc( void* lpParam )
{
if(g_NetworkManager.m_bSignedOutofPSN)
{
C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME, IDS_ERROR_PSN_SIGN_OUT, uiIDA,1,ProfileManager.GetPrimaryPad());
C4JStorage::EMessageResult result = ui.RequestErrorMessage( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME, IDS_ERROR_PSN_SIGN_OUT, uiIDA,1,ProfileManager.GetPrimaryPad());
}
else
{
C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME, uiIDA,1,ProfileManager.GetPrimaryPad());
C4JStorage::EMessageResult result = ui.RequestErrorMessage( IDS_ERROR_NETWORK_TITLE, IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME, uiIDA,1,ProfileManager.GetPrimaryPad());
}
}
else
{
C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_CONNECTION_LOST, g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE_NO_EXIT), uiIDA,1,ProfileManager.GetPrimaryPad());
C4JStorage::EMessageResult result = ui.RequestErrorMessage( IDS_CONNECTION_LOST, g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE_NO_EXIT), uiIDA,1,ProfileManager.GetPrimaryPad());
}
// Swap these two messages around as one is too long to display at 480
@@ -1073,7 +1154,7 @@ int CGameNetworkManager::ChangeSessionTypeThreadProc( void* lpParam )
{
UINT uiIDA[1];
uiIDA[0]=IDS_CONFIRM_OK;
C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME, IDS_IN_PARTY_SESSION_FULL, uiIDA,1,ProfileManager.GetPrimaryPad());
C4JStorage::EMessageResult result = ui.RequestErrorMessage( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME, IDS_IN_PARTY_SESSION_FULL, uiIDA,1,ProfileManager.GetPrimaryPad());
pMinecraft->progressRenderer->progressStartNoAbort( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME );
pMinecraft->progressRenderer->progressStage( -1 );
}
@@ -1215,6 +1296,13 @@ int CGameNetworkManager::ChangeSessionTypeThreadProc( void* lpParam )
// Update the network player
pMinecraft->m_pendingLocalConnections[index]->getConnection()->getSocket()->setPlayer(g_NetworkManager.GetLocalPlayerByUserIndex(index));
}
else if ( pMinecraft->m_connectionFailed[index] && (pMinecraft->m_connectionFailedReason[index] == DisconnectPacket::eDisconnect_ConnectionCreationFailed) )
{
pMinecraft->removeLocalPlayerIdx(index);
#ifdef _XBOX_ONE
ProfileManager.RemoveGamepadFromGame(index);
#endif
}
}
}
}
@@ -1572,7 +1660,7 @@ void CGameNetworkManager::GameInviteReceived( int userIndex, const INVITE_INFO *
// 4J Stu - This is a bit messy and is due to the library incorrectly returning false for IsSignedInLive if the npAvailability isn't SCE_OK
UINT uiIDA[1];
uiIDA[0]=IDS_OK;
ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, iPadNotSignedInLive, NULL, NULL, app.GetStringTable());
ui.RequestErrorMessage(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, iPadNotSignedInLive);
}
else if (ProfileManager.isSignedInPSN(iPadNotSignedInLive))
{
@@ -1581,60 +1669,39 @@ void CGameNetworkManager::GameInviteReceived( int userIndex, const INVITE_INFO *
UINT uiIDA[1];
uiIDA[0] = IDS_OK;
ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, iPadNotSignedInLive, NULL, NULL, app.GetStringTable());
ui.RequestErrorMessage( IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, iPadNotSignedInLive);
}
else
{
// Not signed in to PSN
UINT uiIDA[1];
uiIDA[0] = IDS_PRO_NOTONLINE_ACCEPT;
ui.RequestMessageBox( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, iPadNotSignedInLive, &CGameNetworkManager::MustSignInReturned_1, (void *)pInviteInfo, app.GetStringTable(), NULL, 0, false);
ui.RequestAlertMessage( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, iPadNotSignedInLive, &CGameNetworkManager::MustSignInReturned_1, (void *)pInviteInfo);
}
return;
}
// 4J-JEV: Check that all players are authorised for PsPlus, present upsell to players that aren't and try again.
for (unsigned int index = 0; index < XUSER_MAX_COUNT; index++)
// if this is the trial game, we'll check and send the user to unlock the game later, in HandleInviteWhenInMenus
if(ProfileManager.IsFullVersion())
{
if ( ProfileManager.IsSignedIn(index)
&& !ProfileManager.HasPlayStationPlus(userIndex) )
// 4J-JEV: Check that all players are authorised for PsPlus, present upsell to players that aren't and try again.
for (unsigned int index = 0; index < XUSER_MAX_COUNT; index++)
{
m_pInviteInfo = (INVITE_INFO *) pInviteInfo;
m_iPlayerInvited = userIndex;
if ( ProfileManager.IsSignedIn(index)
&& !ProfileManager.HasPlayStationPlus(userIndex) )
{
m_pInviteInfo = (INVITE_INFO *) pInviteInfo;
m_iPlayerInvited = userIndex;
m_pUpsell = new PsPlusUpsellWrapper(index);
m_pUpsell->displayUpsell();
m_pUpsell = new PsPlusUpsellWrapper(index);
m_pUpsell->displayUpsell();
return;
return;
}
}
}
#endif
#ifdef __PSVITA__
// Need to check we're signed in to PSN
bool isSignedInLive = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad());
if (!isSignedInLive)
{
// Determine why they're not "signed in live"
// MGH - we need to add a new message at some point for connecting when already signed in
// if (ProfileManager.IsSignedInPSN(ProfileManager.GetPrimaryPad()))
// {
// // Signed in to PSN but not connected (no internet access)
// UINT uiIDA[1];
// uiIDA[0] = IDS_OK;
// ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL, app.GetStringTable());
// }
// else
{
// Not signed in to PSN
UINT uiIDA[1];
uiIDA[0] = IDS_PRO_NOTONLINE_ACCEPT;
ui.RequestMessageBox( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, ProfileManager.GetPrimaryPad(), &CGameNetworkManager::MustSignInReturned_1, (void *)pInviteInfo, app.GetStringTable(), NULL, 0, false);
}
return;
}
#endif
int localUsersMask = 0;
Minecraft *pMinecraft = Minecraft::GetInstance();
@@ -1675,17 +1742,22 @@ void CGameNetworkManager::GameInviteReceived( int userIndex, const INVITE_INFO *
uiIDA[0]=IDS_CONFIRM_OK;
// 4J-PB - it's possible there is no primary pad here, when accepting an invite from the dashboard
ui.RequestMessageBox( IDS_CONNECTION_FAILED, IDS_CONNECTION_FAILED_NO_SD_SPLITSCREEN, uiIDA,1,XUSER_INDEX_ANY,NULL,NULL, app.GetStringTable());
ui.RequestErrorMessage( IDS_CONNECTION_FAILED, IDS_CONNECTION_FAILED_NO_SD_SPLITSCREEN, uiIDA,1,XUSER_INDEX_ANY);
}
else
#endif
if( noUGC )
{
#ifdef __PSVITA__
// showing the system message for chat restriction here instead now, to fix FQA bug report
ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, ProfileManager.GetPrimaryPad() );
#else
int messageText = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL;
if(joiningUsers > 1) messageText = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL;
ui.RequestUGCMessageBox(IDS_CONNECTION_FAILED, messageText, XUSER_INDEX_ANY);
#endif
}
#if defined(__PS3__) || defined __PSVITA__
else if(bContentRestricted)
@@ -1703,7 +1775,7 @@ void CGameNetworkManager::GameInviteReceived( int userIndex, const INVITE_INFO *
// 4J-PB - it's possible there is no primary pad here, when accepting an invite from the dashboard
//StorageManager.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable());
ui.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,XUSER_INDEX_ANY,NULL,NULL, app.GetStringTable());
ui.RequestErrorMessage( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,XUSER_INDEX_ANY);
}
else
{
@@ -1717,10 +1789,11 @@ void CGameNetworkManager::GameInviteReceived( int userIndex, const INVITE_INFO *
#endif
if( !g_NetworkManager.IsInSession() )
{
#ifndef __PS3__
HandleInviteWhenInMenus(userIndex, pInviteInfo);
#else
#if defined (__PS3__) || defined (__PSVITA__)
// PS3 is more complicated here - we need to make sure that the player is online. If they are then we can do the same as the xbox, if not we need to try and get them online and then, if they do sign in, go down the same path
// Determine why they're not "signed in live"
// MGH - On Vita we need to add a new message at some point for connecting when already signed in
if(ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()))
{
HandleInviteWhenInMenus(userIndex, pInviteInfo);
@@ -1730,8 +1803,12 @@ void CGameNetworkManager::GameInviteReceived( int userIndex, const INVITE_INFO *
UINT uiIDA[2];
uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT;
uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE;
ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CGameNetworkManager::MustSignInReturned_1,(void *)pInviteInfo, app.GetStringTable());
ui.RequestErrorMessage(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CGameNetworkManager::MustSignInReturned_1,(void *)pInviteInfo);
}
#else
HandleInviteWhenInMenus(userIndex, pInviteInfo);
#endif
}
else
@@ -1777,7 +1854,9 @@ void CGameNetworkManager::HandleInviteWhenInMenus( int userIndex, const INVITE_I
}
else
{
#ifndef _XBOX_ONE
ProfileManager.SetPrimaryPad(userIndex);
#endif
// 4J Stu - If we accept an invite from the main menu before going to play game we need to load the DLC
// These checks are done within the StartInstallDLCProcess - (!app.DLCInstallProcessCompleted() && !app.DLCInstallPending()) app.StartInstallDLCProcess(dwUserIndex);
@@ -1787,7 +1866,11 @@ void CGameNetworkManager::HandleInviteWhenInMenus( int userIndex, const INVITE_I
// The locked profile should not be changed if we are in menus as the main player might sign out in the sign-in ui
//ProfileManager.SetLockedProfile(-1);
#ifdef _XBOX_ONE
if((!app.IsLocalMultiplayerAvailable())&&InputManager.IsPadLocked(userIndex))
#else
if(!app.IsLocalMultiplayerAvailable())
#endif
{
bool noPrivileges=!ProfileManager.AllowedToPlayMultiplayer(userIndex);
@@ -1795,7 +1878,7 @@ void CGameNetworkManager::HandleInviteWhenInMenus( int userIndex, const INVITE_I
{
UINT uiIDA[1];
uiIDA[0]=IDS_CONFIRM_OK;
ui.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable());
ui.RequestErrorMessage( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad());
}
else
{

View File

@@ -22,6 +22,7 @@ using namespace std;
class ClientConnection;
class Minecraft;
const int NON_QNET_SENDDATA_ACK_REQUIRED = 1;
// This class implements the game-side interface to the networking system. As such, it is platform independent and may contain bits of game-side code where appropriate.
// It shouldn't ever reference any platform specifics of the network implementation (eg QNET), rather it should interface with an implementation of PlatformNetworkManager to

View File

@@ -9,8 +9,9 @@ class INetworkPlayer
public:
virtual ~INetworkPlayer() {}
virtual unsigned char GetSmallId() = 0;
virtual void SendData(INetworkPlayer *player, const void *pvData, int dataSize, bool lowPriority) = 0;
virtual void SendData(INetworkPlayer *player, const void *pvData, int dataSize, bool lowPriority, bool ack) = 0;
virtual bool IsSameSystem(INetworkPlayer *player) = 0;
virtual int GetOutstandingAckCount() = 0;
virtual int GetSendQueueSizeBytes( INetworkPlayer *player, bool lowPriority ) = 0;
virtual int GetSendQueueSizeMessages( INetworkPlayer *player, bool lowPriority ) = 0;
virtual int GetCurrentRtt() = 0;
@@ -28,4 +29,6 @@ public:
virtual const wchar_t *GetOnlineName() = 0;
virtual wstring GetDisplayName() = 0;
virtual PlayerUID GetUID() = 0;
virtual void SentChunkPacket() = 0;
virtual int GetTimeSinceLastChunkPacket_ms() = 0;
};

View File

@@ -5,6 +5,7 @@ NetworkPlayerSony::NetworkPlayerSony(SQRNetworkPlayer *qnetPlayer)
{
m_sqrPlayer = qnetPlayer;
m_pSocket = NULL;
m_lastChunkPacketTime = 0;
}
unsigned char NetworkPlayerSony::GetSmallId()
@@ -12,10 +13,10 @@ unsigned char NetworkPlayerSony::GetSmallId()
return m_sqrPlayer->GetSmallId();
}
void NetworkPlayerSony::SendData(INetworkPlayer *player, const void *pvData, int dataSize, bool lowPriority)
void NetworkPlayerSony::SendData(INetworkPlayer *player, const void *pvData, int dataSize, bool lowPriority, bool ack)
{
// TODO - handle priority
m_sqrPlayer->SendData( ((NetworkPlayerSony *)player)->m_sqrPlayer, pvData, dataSize );
m_sqrPlayer->SendData( ((NetworkPlayerSony *)player)->m_sqrPlayer, pvData, dataSize, ack );
}
bool NetworkPlayerSony::IsSameSystem(INetworkPlayer *player)
@@ -23,14 +24,19 @@ bool NetworkPlayerSony::IsSameSystem(INetworkPlayer *player)
return m_sqrPlayer->IsSameSystem(((NetworkPlayerSony *)player)->m_sqrPlayer);
}
int NetworkPlayerSony::GetOutstandingAckCount()
{
return m_sqrPlayer->GetOutstandingAckCount();
}
int NetworkPlayerSony::GetSendQueueSizeBytes( INetworkPlayer *player, bool lowPriority )
{
return 0; // TODO
return m_sqrPlayer->GetSendQueueSizeBytes();
}
int NetworkPlayerSony::GetSendQueueSizeMessages( INetworkPlayer *player, bool lowPriority )
{
return 0; // TODO
return m_sqrPlayer->GetSendQueueSizeMessages();
}
int NetworkPlayerSony::GetCurrentRtt()
@@ -112,3 +118,20 @@ void NetworkPlayerSony::SetUID(PlayerUID UID)
{
m_sqrPlayer->SetUID(UID);
}
void NetworkPlayerSony::SentChunkPacket()
{
m_lastChunkPacketTime = System::currentTimeMillis();
}
int NetworkPlayerSony::GetTimeSinceLastChunkPacket_ms()
{
// If we haven't ever sent a packet, return maximum
if( m_lastChunkPacketTime == 0 )
{
return INT_MAX;
}
__int64 currentTime = System::currentTimeMillis();
return (int)( currentTime - m_lastChunkPacketTime );
}

View File

@@ -11,8 +11,9 @@ public:
// Common player interface
NetworkPlayerSony(SQRNetworkPlayer *sqrPlayer);
virtual unsigned char GetSmallId();
virtual void SendData(INetworkPlayer *player, const void *pvData, int dataSize, bool lowPriority);
virtual void SendData(INetworkPlayer *player, const void *pvData, int dataSize, bool lowPriority, bool ack);
virtual bool IsSameSystem(INetworkPlayer *player);
virtual int GetOutstandingAckCount();
virtual int GetSendQueueSizeBytes( INetworkPlayer *player, bool lowPriority );
virtual int GetSendQueueSizeMessages( INetworkPlayer *player, bool lowPriority );
virtual int GetCurrentRtt();
@@ -33,7 +34,10 @@ public:
void SetUID(PlayerUID UID);
virtual void SentChunkPacket();
virtual int GetTimeSinceLastChunkPacket_ms();
private:
SQRNetworkPlayer *m_sqrPlayer;
Socket *m_pSocket;
__int64 m_lastChunkPacketTime;
};

View File

@@ -54,10 +54,8 @@ void CPlatformNetworkManagerSony::HandleStateChange(SQRNetworkManager::eSQRNetwo
else if( newState == SQRNetworkManager::SNM_STATE_JOINING )
{
// 4J Stu - We may be accepting an invite from the DLC menu, so hide the icon
#ifdef __ORBIS__
sceNpCommerceHidePsStoreIcon();
#elif defined __PSVITA__
sceNpCommerce2HidePsStoreIcon();
#if defined __ORBIS__ || defined __PSVITA__
app.GetCommerce()->HidePsStoreIcon();
#endif
m_bLeavingGame = false;
m_bLeaveGameOnTick = false;
@@ -459,16 +457,16 @@ int CPlatformNetworkManagerSony::CorrectErrorIDS(int IDS)
// Determine if we'd prefer to present errors as a signing out issue, rather than a network issue, based on whether we have a network connection at all or not
bool preferSignoutError = false;
int state;
#ifdef __PS3__
#if defined __PSVITA__ // MGH - to fix devtrack #6258
if(!ProfileManager.IsSignedInPSN(ProfileManager.GetPrimaryPad()))
preferSignoutError = true;
#elif defined __ORBIS__
if(!ProfileManager.isSignedInPSN(ProfileManager.GetPrimaryPad()))
preferSignoutError = true;
#elif defined __PS3__
int ret = cellNetCtlGetState( &state );
int IPObtainedState = CELL_NET_CTL_STATE_IPObtained;
#elif defined __ORBIS__
int ret = sceNetCtlGetState( &state );
int IPObtainedState = SCE_NET_CTL_STATE_IPOBTAINED;
#elif defined __PSVITA__
int ret = sceNetCtlInetGetState( &state );
int IPObtainedState = SCE_NET_CTL_STATE_IPOBTAINED;
#endif
if( ret == 0 )
{
if( state == IPObtainedState )
@@ -476,6 +474,7 @@ int CPlatformNetworkManagerSony::CorrectErrorIDS(int IDS)
preferSignoutError = true;
}
}
#endif
#ifdef __PSVITA__
// If we're in ad-hoc mode this problem definitely wasn't PSN related
@@ -1446,7 +1445,8 @@ void CPlatformNetworkManagerSony::startAdhocMatching( )
bool CPlatformNetworkManagerSony::checkValidInviteData(const INVITE_INFO* pInviteInfo)
{
if(((SQRNetworkManager_Vita*)m_pSQRNet_Vita)->GetHostUID() == pInviteInfo->hostPlayerUID)
SQRNetworkManager_Vita* pSQR = (SQRNetworkManager_Vita*)m_pSQRNet_Vita;
if(pSQR->IsOnlineGame() && !pSQR->IsHost()&& (pSQR->GetHostUID() == pInviteInfo->hostPlayerUID))
{
// we're trying to join a game we're already in, so we just ignore this
return false;

View File

@@ -8,3 +8,76 @@ void SQRNetworkManager::SafeToRespondToGameBootInvite()
{
s_safeToRespondToGameBootInvite = true;
}
int SQRNetworkManager::GetSendQueueSizeBytes()
{
int queueSize = 0;
int playerCount = GetPlayerCount();
for(int i = 0; i < playerCount; ++i)
{
SQRNetworkPlayer *player = GetPlayerByIndex( i );
if( player != NULL )
{
queueSize += player->GetTotalSendQueueBytes();
}
}
return queueSize;
}
int SQRNetworkManager::GetSendQueueSizeMessages()
{
int queueSize = 0;
int playerCount = GetPlayerCount();
for(int i = 0; i < playerCount; ++i)
{
SQRNetworkPlayer *player = GetPlayerByIndex( i );
if( player != NULL )
{
queueSize += player->GetTotalSendQueueMessages();
}
}
return queueSize;
}
int SQRNetworkManager::GetOutstandingAckCount(SQRNetworkPlayer *pSQRPlayer)
{
int ackCount = 0;
int playerCount = GetPlayerCount();
for(int i = 0; i < playerCount; ++i)
{
SQRNetworkPlayer *pSQRPlayer2 = GetPlayerByIndex( i );
if( pSQRPlayer2 )
{
if( ( pSQRPlayer == pSQRPlayer2 ) || (pSQRPlayer->IsSameSystem(pSQRPlayer2) ) )
{
ackCount += pSQRPlayer2->m_acksOutstanding;
}
}
}
return ackCount;
}
void SQRNetworkManager::RequestWriteAck(int smallId)
{
EnterCriticalSection(&m_csAckQueue);
m_queuedAckRequests.push(smallId);
LeaveCriticalSection(&m_csAckQueue);
}
void SQRNetworkManager::TickWriteAcks()
{
EnterCriticalSection(&m_csAckQueue);
while(m_queuedAckRequests.size() > 0)
{
int smallId = m_queuedAckRequests.front();
m_queuedAckRequests.pop();
SQRNetworkPlayer *player = GetPlayerBySmallId(smallId);
if( player )
{
LeaveCriticalSection(&m_csAckQueue);
player->WriteAck();
EnterCriticalSection(&m_csAckQueue);
}
}
LeaveCriticalSection(&m_csAckQueue);
}

View File

@@ -11,6 +11,9 @@
#include <queue>
#include <unordered_map>
#if defined __PSVITA__
#include "..\..\Minecraft.Client\PSVita\4JLibs\inc\4J_Profile.h"
#endif
class SQRNetworkPlayer;
class ISQRNetworkManagerListener;
@@ -30,7 +33,9 @@ public:
protected:
friend class SQRNetworkPlayer;
friend class SonyVoiceChat;
#ifdef __PSVITA__
friend class HelloSyncInfo;
#endif
static const int MAX_FRIENDS = 100;
#ifdef __PS3__
@@ -231,6 +236,8 @@ protected:
std::queue<StateChangeInfo> m_stateChangeQueue;
CRITICAL_SECTION m_csStateChangeQueue;
CRITICAL_SECTION m_csMatching;
CRITICAL_SECTION m_csAckQueue;
std::queue<int> m_queuedAckRequests;
typedef enum
{
@@ -295,6 +302,13 @@ public:
static void SafeToRespondToGameBootInvite();
int GetOutstandingAckCount(SQRNetworkPlayer *pSonyPlayer);
int GetSendQueueSizeBytes();
int GetSendQueueSizeMessages();
void RequestWriteAck(int smallId);
void TickWriteAcks();
};

View File

@@ -16,6 +16,15 @@
#endif
//#define PRINT_ACK_STATS
#ifdef __PS3__
static const int sc_wouldBlockFlag = CELL_RUDP_ERROR_WOULDBLOCK;
#else // __ORBIS__
static const int sc_wouldBlockFlag = SCE_RUDP_ERROR_WOULDBLOCK;
#endif
static const bool sc_verbose = false;
@@ -84,6 +93,8 @@ SQRNetworkPlayer::SQRNetworkPlayer(SQRNetworkManager *manager, eSQRNetworkPlayer
m_host = onHost;
m_manager = manager;
m_customData = 0;
m_acksOutstanding = 0;
m_totalBytesInSendQueue = 0;
if( pUID )
{
memcpy(&m_ISD.m_UID,pUID,sizeof(PlayerUID));
@@ -102,6 +113,7 @@ SQRNetworkPlayer::SQRNetworkPlayer(SQRNetworkManager *manager, eSQRNetworkPlayer
}
SetNameFromUID();
InitializeCriticalSection(&m_csQueue);
InitializeCriticalSection(&m_csAcks);
#ifdef __ORBIS__
if(IsLocal())
{
@@ -109,6 +121,14 @@ SQRNetworkPlayer::SQRNetworkPlayer(SQRNetworkManager *manager, eSQRNetworkPlayer
}
#endif
#ifndef _CONTENT_PACKAGE
m_minAckTime = INT_MAX;
m_maxAckTime = 0;
m_totalAcks = 0;
m_totalAckTime = 0;
m_averageAckTime = 0;
#endif
}
SQRNetworkPlayer::~SQRNetworkPlayer()
@@ -190,13 +210,8 @@ bool SQRNetworkPlayer::HasSmallIdConfirmed()
// To confirm to the host that we are ready, send a single byte with our small id.
void SQRNetworkPlayer::ConfirmReady()
{
#ifdef __PS3__
int ret = cellRudpWrite( m_rudpCtx, &m_ISD, sizeof(InitSendData), CELL_RUDP_MSG_LATENCY_CRITICAL );
#else //__ORBIS__
int ret = sceRudpWrite( m_rudpCtx, &m_ISD, sizeof(InitSendData), SCE_RUDP_MSG_LATENCY_CRITICAL );
#endif
// TODO - error handling here?
assert ( ret == sizeof(InitSendData) );
SendInternal(&m_ISD, sizeof(InitSendData), e_flag_AckNotRequested);
// Final flag for a local player on the client, as we are now safe to send data on to the host
m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:");
app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Small ID confirmed\n");
@@ -205,8 +220,9 @@ void SQRNetworkPlayer::ConfirmReady()
// Attempt to send data, of any size, from this player to that specified by pPlayerTarget. This may not be possible depending on the two players, due to
// our star shaped network connectivity. Data may be any size, and is copied so on returning from this method it does not need to be preserved.
void SQRNetworkPlayer::SendData( SQRNetworkPlayer *pPlayerTarget, const void *data, unsigned int dataSize )
void SQRNetworkPlayer::SendData( SQRNetworkPlayer *pPlayerTarget, const void *data, unsigned int dataSize, bool ack )
{
AckFlags ackFlags = ack ? e_flag_AckRequested : e_flag_AckNotRequested;
// Our network is connected as a star. If we are the host, then we can send to any remote player. If we're a client, we can send only to the host.
// The host can also send to other local players, but this doesn't need to go through Rudp.
if( m_host )
@@ -224,7 +240,7 @@ void SQRNetworkPlayer::SendData( SQRNetworkPlayer *pPlayerTarget, const void *da
else if( ( m_type == SNP_TYPE_HOST ) && ( pPlayerTarget->m_type == SNP_TYPE_REMOTE ) )
{
// Rudp communication from host to remote player - handled by remote player instance
pPlayerTarget->SendInternal(data,dataSize);
pPlayerTarget->SendInternal(data,dataSize, ackFlags);
}
else
{
@@ -237,7 +253,7 @@ void SQRNetworkPlayer::SendData( SQRNetworkPlayer *pPlayerTarget, const void *da
if( ( m_type == SNP_TYPE_LOCAL ) && ( pPlayerTarget->m_type == SNP_TYPE_HOST ) )
{
// Rudp communication from client to host - handled by this player instace
SendInternal(data, dataSize);
SendInternal(data, dataSize, ackFlags);
}
else
{
@@ -250,15 +266,30 @@ void SQRNetworkPlayer::SendData( SQRNetworkPlayer *pPlayerTarget, const void *da
// Internal send function - to simplify the number of mechanisms we have for sending data, this method just adds the data to be send to the player's internal queue,
// and then calls SendMoreInternal. This method can take any size of data, which it will split up into payload size chunks before sending. All input data is copied
// into internal buffers.
void SQRNetworkPlayer::SendInternal(const void *data, unsigned int dataSize)
void SQRNetworkPlayer::SendInternal(const void *data, unsigned int dataSize, AckFlags ackFlags)
{
EnterCriticalSection(&m_csQueue);
bool bOutstandingPackets = (m_sendQueue.size() > 0); // check if there are still packets in the queue, we won't be calling SendMoreInternal here if there are
QueuedSendBlock sendBlock;
unsigned char *dataCurrent = (unsigned char *)data;
unsigned int dataRemaining = dataSize;
if(ackFlags == e_flag_AckReturning)
{
// no data, just the flag
assert(dataSize == 0);
assert(data == NULL);
int dataSize = dataRemaining;
if( dataSize > SNP_MAX_PAYLOAD ) dataSize = SNP_MAX_PAYLOAD;
sendBlock.start = NULL;
sendBlock.end = NULL;
sendBlock.current = NULL;
sendBlock.ack = ackFlags;
m_sendQueue.push(sendBlock);
}
else
{
while( dataRemaining )
{
int dataSize = dataRemaining;
@@ -266,19 +297,203 @@ void SQRNetworkPlayer::SendInternal(const void *data, unsigned int dataSize)
sendBlock.start = new unsigned char [dataSize];
sendBlock.end = sendBlock.start + dataSize;
sendBlock.current = sendBlock.start;
sendBlock.ack = ackFlags;
memcpy( sendBlock.start, dataCurrent, dataSize);
m_sendQueue.push(sendBlock);
dataRemaining -= dataSize;
dataCurrent += dataSize;
}
// Now try and send as much as we can
SendMoreInternal();
}
m_totalBytesInSendQueue += dataSize;
// if the queue had something in it already, then the UDP callback will fire and call SendMoreInternal
// so we don't call it here, to avoid a deadlock
if(!bOutstandingPackets)
{
// Now try and send as much as we can
SendMoreInternal();
}
LeaveCriticalSection(&m_csQueue);
}
int SQRNetworkPlayer::WriteDataPacket(const void* data, int dataSize, AckFlags ackFlags)
{
DataPacketHeader header(dataSize, ackFlags);
int headerSize = sizeof(header);
int packetSize = dataSize+headerSize;
unsigned char* packetData = new unsigned char[packetSize];
*((DataPacketHeader*)packetData) = header;
memcpy(&packetData[headerSize], data, dataSize);
#ifndef _CONTENT_PACKAGE
if(ackFlags == e_flag_AckRequested)
m_ackStats.push_back(System::currentTimeMillis());
#endif
#ifdef __PS3__
int ret = cellRudpWrite( m_rudpCtx, packetData, packetSize, 0);//CELL_RUDP_MSG_LATENCY_CRITICAL );
#else // __ORBIS__ && __PSVITA__
int ret = sceRudpWrite( m_rudpCtx, packetData, packetSize, 0);//SCE_RUDP_MSG_LATENCY_CRITICAL );
#endif
if(ret == sc_wouldBlockFlag)
{
// nothing was sent!
}
else
{
assert(ret==packetSize || ret > headerSize); // we must make sure we've sent the entire packet or the header and some data at least
ret -= headerSize;
if(ackFlags == e_flag_AckRequested)
{
EnterCriticalSection(&m_csAcks);
m_acksOutstanding++;
LeaveCriticalSection(&m_csAcks);
}
}
delete packetData;
return ret;
}
int SQRNetworkPlayer::GetPacketDataSize()
{
unsigned int ackFlag;
int headerSize = sizeof(ackFlag);
#ifdef __PS3__
unsigned int packetSize = cellRudpGetSizeReadable(m_rudpCtx);
#else
unsigned int packetSize = sceRudpGetSizeReadable(m_rudpCtx);
#endif
if(packetSize == 0)
return 0;
unsigned int dataSize = packetSize - headerSize;
assert(dataSize >= 0);
if(dataSize == 0)
{
// header only, must just be an ack returning
ReadAck();
}
return dataSize;
}
int SQRNetworkPlayer::ReadDataPacket(void* data, int dataSize)
{
int headerSize = sizeof(DataPacketHeader);
int packetSize = dataSize+headerSize;
unsigned char* packetData = new unsigned char[packetSize];
#ifdef __PS3__
int bytesRead = cellRudpRead( m_rudpCtx, packetData, packetSize, 0, NULL );
#else // __ORBIS__ && __PSVITA__
int bytesRead = sceRudpRead( m_rudpCtx, packetData, packetSize, 0, NULL );
#endif
if(bytesRead == sc_wouldBlockFlag)
{
delete packetData;
return 0;
}
// check the header, and see if we need to send back an ack
DataPacketHeader header = *((DataPacketHeader*)packetData);
if(header.GetAckFlags() == e_flag_AckRequested)
{
// Don't send the ack back directly from here, as this is called from a rudp event callback, and we end up in a thread lock situation between the lock librudp uses
// internally (which is locked already here since we are being called in the event handler), and our own lock that we do for processing our write queue
m_manager->RequestWriteAck(GetSmallId());
}
else
{
assert(header.GetAckFlags() == e_flag_AckNotRequested);
}
if(bytesRead > 0)
{
bytesRead -= headerSize;
memcpy(data, &packetData[headerSize], bytesRead);
}
assert(header.GetDataSize() == bytesRead);
delete packetData;
return bytesRead;
}
void SQRNetworkPlayer::ReadAck()
{
DataPacketHeader header;
#ifdef __PS3__
int bytesRead = cellRudpRead( m_rudpCtx, &header, sizeof(header), 0, NULL );
#else // __ORBIS__ && __PSVITA__
int bytesRead = sceRudpRead( m_rudpCtx, &header, sizeof(header), 0, NULL );
#endif
if(bytesRead == sc_wouldBlockFlag)
{
return;
}
assert(header.GetAckFlags() == e_flag_AckReturning);
EnterCriticalSection(&m_csAcks);
m_acksOutstanding--;
assert(m_acksOutstanding >=0);
LeaveCriticalSection(&m_csAcks);
#ifndef _CONTENT_PACKAGE
#ifdef PRINT_ACK_STATS
__int64 timeTaken = System::currentTimeMillis() - m_ackStats[0];
if(timeTaken < m_minAckTime)
m_minAckTime = timeTaken;
if(timeTaken > m_maxAckTime)
m_maxAckTime = timeTaken;
m_totalAcks++;
m_totalAckTime += timeTaken;
m_averageAckTime = m_totalAckTime / m_totalAcks;
app.DebugPrintf("RUDP ctx : %d : Time taken for ack - %4d ms : min - %4d : max %4d : avg %4d\n", m_rudpCtx, timeTaken, m_minAckTime, m_maxAckTime, m_averageAckTime);
m_ackStats.erase(m_ackStats.begin());
#endif
#endif
}
void SQRNetworkPlayer::WriteAck()
{
SendInternal(NULL, 0, e_flag_AckReturning);
}
int SQRNetworkPlayer::GetOutstandingAckCount()
{
return m_manager->GetOutstandingAckCount(this);
}
int SQRNetworkPlayer::GetTotalOutstandingAckCount()
{
return m_acksOutstanding;
}
int SQRNetworkPlayer::GetTotalSendQueueBytes()
{
return m_totalBytesInSendQueue;
}
int SQRNetworkPlayer::GetTotalSendQueueMessages()
{
CriticalSectionScopeLock lock(&m_csQueue);
return m_sendQueue.size();
}
int SQRNetworkPlayer::GetSendQueueSizeBytes()
{
return m_manager->GetSendQueueSizeBytes();
}
int SQRNetworkPlayer::GetSendQueueSizeMessages()
{
return m_manager->GetSendQueueSizeMessages();
}
// Internal send function. This attempts to send as many elements in the queue as possible until the write function tells us that we can't send any more. This way,
@@ -287,6 +502,8 @@ void SQRNetworkPlayer::SendInternal(const void *data, unsigned int dataSize)
void SQRNetworkPlayer::SendMoreInternal()
{
EnterCriticalSection(&m_csQueue);
assert(m_sendQueue.size() > 0); // this should never be called with an empty queue.
bool keepSending;
do
{
@@ -296,17 +513,12 @@ void SQRNetworkPlayer::SendMoreInternal()
// Attempt to send the full data in the first element in our queue
unsigned char *data= m_sendQueue.front().current;
int dataSize = m_sendQueue.front().end - m_sendQueue.front().current;
#ifdef __PS3__
int ret = cellRudpWrite( m_rudpCtx, data, dataSize, 0);//CELL_RUDP_MSG_LATENCY_CRITICAL );
int wouldBlockFlag = CELL_RUDP_ERROR_WOULDBLOCK;
int ret = WriteDataPacket(data, dataSize, m_sendQueue.front().ack);
#else // __ORBIS__
int ret = sceRudpWrite( m_rudpCtx, data, dataSize, 0);//CELL_RUDP_MSG_LATENCY_CRITICAL );
int wouldBlockFlag = SCE_RUDP_ERROR_WOULDBLOCK;
#endif
if( ret == dataSize )
{
// Fully sent, remove from queue - will loop in the while loop to see if there's anything else in the queue we could send
m_totalBytesInSendQueue -= ret;
delete [] m_sendQueue.front().start;
m_sendQueue.pop();
if( m_sendQueue.size() )
@@ -314,15 +526,15 @@ void SQRNetworkPlayer::SendMoreInternal()
keepSending = true;
}
}
else if( ( ret >= 0 ) || ( ret == wouldBlockFlag ) )
else if( ( ret >= 0 ) || ( ret == sc_wouldBlockFlag ) )
{
// Things left to send - adjust this element in the queue
int remainingBytes;
if( ret >= 0 )
{
// Only ret bytes sent so far
m_totalBytesInSendQueue -= ret;
remainingBytes = dataSize - ret;
assert(remainingBytes > 0 );
}

View File

@@ -48,12 +48,41 @@ class SQRNetworkPlayer
SNP_TYPE_REMOTE, // On host - this player's m_rupdCtx can be used to communicate from between the host and this player. On clients - this is a remote player that cannot be communicated with
} eSQRNetworkPlayerType;
enum AckFlags
{
e_flag_AckUnknown,
e_flag_AckNotRequested,
e_flag_AckRequested,
e_flag_AckReturning
};
class DataPacketHeader
{
unsigned short m_dataSize;
unsigned short m_ackFlags;
public:
DataPacketHeader() : m_dataSize(0), m_ackFlags(e_flag_AckUnknown) {}
DataPacketHeader(int dataSize, AckFlags ackFlags) : m_dataSize(dataSize), m_ackFlags(ackFlags) { }
AckFlags GetAckFlags() { return (AckFlags)m_ackFlags;}
int GetDataSize() { return m_dataSize; }
};
#ifndef _CONTENT_PACKAGE
std::vector<__int64> m_ackStats;
int m_minAckTime;
int m_maxAckTime;
int m_totalAcks;
__int64 m_totalAckTime;
int m_averageAckTime;
#endif
class QueuedSendBlock
{
public:
unsigned char *start;
unsigned char *end;
unsigned char *current;
AckFlags ack;
};
class InitSendData
@@ -75,11 +104,26 @@ class SQRNetworkPlayer
void InitialDataReceived(InitSendData *ISD); // Only for remote players as viewed from the host, this is set when the host has received confirmation that the client has received the small id for this player, ie it is now safe to send data to
bool HasSmallIdConfirmed();
void SendData( SQRNetworkPlayer *pPlayerTarget, const void *data, unsigned int dataSize );
void SendData( SQRNetworkPlayer *pPlayerTarget, const void *data, unsigned int dataSize, bool ack );
void ConfirmReady();
void SendInternal(const void *data, unsigned int dataSize);
void SendInternal(const void *data, unsigned int dataSize, AckFlags ackFlags);
void SendMoreInternal();
int GetPacketDataSize();
int ReadDataPacket(void* data, int dataSize);
int WriteDataPacket(const void* data, int dataSize, AckFlags ackFlags);
void ReadAck();
void WriteAck();
int GetOutstandingAckCount();
int GetSendQueueSizeBytes();
int GetSendQueueSizeMessages();
int GetTotalOutstandingAckCount();
int GetTotalSendQueueBytes();
int GetTotalSendQueueMessages();
#ifdef __PSVITA__
void SendInternal_VitaAdhoc(const void *data, unsigned int dataSize, EAdhocDataTag tag = e_dataTag_Normal);
void SendMoreInternal_VitaAdhoc();
@@ -99,5 +143,9 @@ class SQRNetworkPlayer
wchar_t m_name[21];
uintptr_t m_customData;
CRITICAL_SECTION m_csQueue;
CRITICAL_SECTION m_csAcks;
std::queue<QueuedSendBlock> m_sendQueue;
int m_totalBytesInSendQueue;
int m_acksOutstanding;
};

View File

@@ -170,4 +170,8 @@ public:
virtual void CheckForTrialUpgradeKey() = 0;
virtual bool LicenseChecked() = 0;
#if defined __ORBIS__ || defined __PSVITA__
virtual void ShowPsStoreIcon() = 0;
virtual void HidePsStoreIcon() = 0;
#endif
};

View File

@@ -36,6 +36,37 @@ static SceRemoteStorageStatus statParams;
void SonyRemoteStorage::SetRetrievedDescData()
{
DescriptionData* pDescDataTest = (DescriptionData*)m_remoteFileInfo->fileDescription;
ESavePlatform testPlatform = (ESavePlatform)MAKE_FOURCC(pDescDataTest->m_platform[0], pDescDataTest->m_platform[1], pDescDataTest->m_platform[2], pDescDataTest->m_platform[3]);
if(testPlatform == SAVE_FILE_PLATFORM_NONE)
{
// new version of the descData
DescriptionData_V2* pDescData2 = (DescriptionData_V2*)m_remoteFileInfo->fileDescription;
m_retrievedDescData.m_descDataVersion = GetU32FromHexBytes(pDescData2->m_descDataVersion);
m_retrievedDescData.m_savePlatform = (ESavePlatform)MAKE_FOURCC(pDescData2->m_platform[0], pDescData2->m_platform[1], pDescData2->m_platform[2], pDescData2->m_platform[3]);
m_retrievedDescData.m_seed = GetU64FromHexBytes(pDescData2->m_seed);
m_retrievedDescData.m_hostOptions = GetU32FromHexBytes(pDescData2->m_hostOptions);
m_retrievedDescData.m_texturePack = GetU32FromHexBytes(pDescData2->m_texturePack);
m_retrievedDescData.m_saveVersion = GetU32FromHexBytes(pDescData2->m_saveVersion);
memcpy(m_retrievedDescData.m_saveNameUTF8, pDescData2->m_saveNameUTF8, sizeof(pDescData2->m_saveNameUTF8));
assert(m_retrievedDescData.m_descDataVersion > 1 && m_retrievedDescData.m_descDataVersion <= sc_CurrentDescDataVersion);
}
else
{
// old version,copy the data across to the new version
DescriptionData* pDescData = (DescriptionData*)m_remoteFileInfo->fileDescription;
m_retrievedDescData.m_descDataVersion = 1;
m_retrievedDescData.m_savePlatform = (ESavePlatform)MAKE_FOURCC(pDescData->m_platform[0], pDescData->m_platform[1], pDescData->m_platform[2], pDescData->m_platform[3]);
m_retrievedDescData.m_seed = GetU64FromHexBytes(pDescData->m_seed);
m_retrievedDescData.m_hostOptions = GetU32FromHexBytes(pDescData->m_hostOptions);
m_retrievedDescData.m_texturePack = GetU32FromHexBytes(pDescData->m_texturePack);
m_retrievedDescData.m_saveVersion = SAVE_FILE_VERSION_COMPRESSED_CHUNK_STORAGE; // the last save version before we added it to this data
memcpy(m_retrievedDescData.m_saveNameUTF8, pDescData->m_saveNameUTF8, sizeof(pDescData->m_saveNameUTF8));
}
}
@@ -51,8 +82,9 @@ void getSaveInfoReturnCallback(LPVOID lpParam, SonyRemoteStorage::Status s, int
if(strcmp(statParams.data[i].fileName, sc_remoteSaveFilename) == 0)
{
// found the file we need in the cloud
pRemoteStorage->m_getInfoStatus = SonyRemoteStorage::e_infoFound;
pRemoteStorage->m_remoteFileInfo = &statParams.data[i];
pRemoteStorage->SetRetrievedDescData();
pRemoteStorage->m_getInfoStatus = SonyRemoteStorage::e_infoFound;
}
}
}
@@ -104,7 +136,7 @@ void SonyRemoteStorage::getSaveInfo()
bool SonyRemoteStorage::getSaveData( const char* localDirname, CallbackFunc cb, LPVOID lpParam )
{
m_startTime = System::currentTimeMillis();
m_dataProgress = 0;
m_dataProgress = -1;
return getData(sc_remoteSaveFilename, localDirname, cb, lpParam);
}
@@ -131,7 +163,9 @@ bool SonyRemoteStorage::setSaveData(PSAVE_INFO info, CallbackFunc cb, void* lpPa
m_setDataStatus = e_settingData;
m_initCallbackFunc = cb;
m_initCallbackParam = lpParam;
m_dataProgress = 0;
m_dataProgress = -1;
m_uploadSaveSize = 0;
m_startTime = System::currentTimeMillis();
bool bOK = init(setSaveDataInitCallback, this);
if(!bOK)
m_setDataStatus = e_settingDataFailed;
@@ -148,16 +182,14 @@ const char* SonyRemoteStorage::getSaveNameUTF8()
{
if(m_getInfoStatus != e_infoFound)
return NULL;
DescriptionData* pDescData = (DescriptionData*)m_remoteFileInfo->fileDescription;
return pDescData->m_saveNameUTF8;
return m_retrievedDescData.m_saveNameUTF8;
}
ESavePlatform SonyRemoteStorage::getSavePlatform()
{
if(m_getInfoStatus != e_infoFound)
return SAVE_FILE_PLATFORM_NONE;
DescriptionData* pDescData = (DescriptionData*)m_remoteFileInfo->fileDescription;
return (ESavePlatform)MAKE_FOURCC(pDescData->m_platform[0], pDescData->m_platform[1], pDescData->m_platform[2], pDescData->m_platform[3]);
return m_retrievedDescData.m_savePlatform;
}
@@ -165,51 +197,23 @@ __int64 SonyRemoteStorage::getSaveSeed()
{
if(m_getInfoStatus != e_infoFound)
return 0;
DescriptionData* pDescData = (DescriptionData*)m_remoteFileInfo->fileDescription;
char seedString[17];
ZeroMemory(seedString,17);
memcpy(seedString, pDescData->m_seed,16);
__uint64 seed = 0;
std::stringstream ss;
ss << seedString;
ss >> std::hex >> seed;
return seed;
return m_retrievedDescData.m_seed;
}
unsigned int SonyRemoteStorage::getSaveHostOptions()
{
if(m_getInfoStatus != e_infoFound)
return 0;
DescriptionData* pDescData = (DescriptionData*)m_remoteFileInfo->fileDescription;
char optionsString[9];
ZeroMemory(optionsString,9);
memcpy(optionsString, pDescData->m_hostOptions,8);
unsigned int uiHostOptions = 0;
std::stringstream ss;
ss << optionsString;
ss >> std::hex >> uiHostOptions;
return uiHostOptions;
return m_retrievedDescData.m_hostOptions;
}
unsigned int SonyRemoteStorage::getSaveTexturePack()
{
if(m_getInfoStatus != e_infoFound)
return 0;
DescriptionData* pDescData = (DescriptionData*)m_remoteFileInfo->fileDescription;
char textureString[9];
ZeroMemory(textureString,9);
memcpy(textureString, pDescData->m_texturePack,8);
unsigned int uiTexturePack = 0;
std::stringstream ss;
ss << textureString;
ss >> std::hex >> uiTexturePack;
return uiTexturePack;
return m_retrievedDescData.m_texturePack;
}
const char* SonyRemoteStorage::getRemoteSaveFilename()
@@ -292,14 +296,41 @@ bool SonyRemoteStorage::saveIsAvailable()
#endif
}
bool SonyRemoteStorage::saveVersionSupported()
{
return (m_retrievedDescData.m_saveVersion <= SAVE_FILE_VERSION_NUMBER);
}
int SonyRemoteStorage::getDataProgress()
{
if(m_dataProgress < 0)
return 0;
int chunkSize = 1024*1024; // 1mb chunks when downloading
int totalSize = getSaveFilesize();
int transferRatePerSec = 300*1024; // a pessimistic download transfer rate
if(getStatus() == e_setDataInProgress)
{
chunkSize = 5 * 1024 * 1024; // 5mb chunks when uploading
totalSize = m_uploadSaveSize;
transferRatePerSec = 20*1024; // a pessimistic upload transfer rate
}
int sizeTransferred = (totalSize * m_dataProgress) / 100;
int nextChunk = ((sizeTransferred + chunkSize) * 100) / totalSize;
__int64 time = System::currentTimeMillis();
int elapsedSecs = (time - m_startTime) / 1000;
int progVal = m_dataProgress + (elapsedSecs/3);
if(progVal > 95)
float estimatedTransfered = float(elapsedSecs * transferRatePerSec);
int progVal = m_dataProgress + (estimatedTransfered / float(totalSize)) * 100;
if(progVal > nextChunk)
return nextChunk;
if(progVal > 99)
{
return m_dataProgress;
if(m_dataProgress > 99)
return m_dataProgress;
return 99;
}
return progVal;
}
@@ -338,3 +369,139 @@ void SonyRemoteStorage::waitForStorageManagerIdle()
storageState = StorageManager.GetSaveState();
}
}
void SonyRemoteStorage::GetDescriptionData(char* descData)
{
switch(sc_CurrentDescDataVersion)
{
case 1:
{
DescriptionData descData_V1;
GetDescriptionData(descData_V1);
memcpy(descData, &descData_V1, sizeof(descData_V1));
}
break;
case 2:
{
DescriptionData_V2 descData_V2;
GetDescriptionData(descData_V2);
memcpy(descData, &descData_V2, sizeof(descData_V2));
}
break;
default:
assert(0);
break;
}
}
void SonyRemoteStorage::GetDescriptionData( DescriptionData& descData)
{
ZeroMemory(&descData, sizeof(DescriptionData));
descData.m_platform[0] = SAVE_FILE_PLATFORM_LOCAL & 0xff;
descData.m_platform[1] = (SAVE_FILE_PLATFORM_LOCAL >> 8) & 0xff;
descData.m_platform[2] = (SAVE_FILE_PLATFORM_LOCAL >> 16) & 0xff;
descData.m_platform[3] = (SAVE_FILE_PLATFORM_LOCAL >> 24)& 0xff;
if(m_thumbnailData)
{
unsigned int uiHostOptions;
bool bHostOptionsRead;
DWORD uiTexturePack;
char seed[22];
app.GetImageTextData(m_thumbnailData, m_thumbnailDataSize,(unsigned char *)seed, uiHostOptions, bHostOptionsRead, uiTexturePack);
__int64 iSeed = strtoll(seed,NULL,10);
SetU64HexBytes(descData.m_seed, iSeed);
// Save the host options that this world was last played with
SetU32HexBytes(descData.m_hostOptions, uiHostOptions);
// Save the texture pack id
SetU32HexBytes(descData.m_texturePack, uiTexturePack);
}
memcpy(descData.m_saveNameUTF8, m_saveFileDesc, strlen(m_saveFileDesc));
}
void SonyRemoteStorage::GetDescriptionData( DescriptionData_V2& descData)
{
ZeroMemory(&descData, sizeof(DescriptionData_V2));
descData.m_platformNone[0] = SAVE_FILE_PLATFORM_NONE & 0xff;
descData.m_platformNone[1] = (SAVE_FILE_PLATFORM_NONE >> 8) & 0xff;
descData.m_platformNone[2] = (SAVE_FILE_PLATFORM_NONE >> 16) & 0xff;
descData.m_platformNone[3] = (SAVE_FILE_PLATFORM_NONE >> 24)& 0xff;
// Save descData version
char descDataVersion[9];
sprintf(descDataVersion,"%08x",sc_CurrentDescDataVersion);
memcpy(descData.m_descDataVersion,descDataVersion,8); // Don't copy null
descData.m_platform[0] = SAVE_FILE_PLATFORM_LOCAL & 0xff;
descData.m_platform[1] = (SAVE_FILE_PLATFORM_LOCAL >> 8) & 0xff;
descData.m_platform[2] = (SAVE_FILE_PLATFORM_LOCAL >> 16) & 0xff;
descData.m_platform[3] = (SAVE_FILE_PLATFORM_LOCAL >> 24)& 0xff;
if(m_thumbnailData)
{
unsigned int uiHostOptions;
bool bHostOptionsRead;
DWORD uiTexturePack;
char seed[22];
app.GetImageTextData(m_thumbnailData, m_thumbnailDataSize,(unsigned char *)seed, uiHostOptions, bHostOptionsRead, uiTexturePack);
__int64 iSeed = strtoll(seed,NULL,10);
SetU64HexBytes(descData.m_seed, iSeed);
// Save the host options that this world was last played with
SetU32HexBytes(descData.m_hostOptions, uiHostOptions);
// Save the texture pack id
SetU32HexBytes(descData.m_texturePack, uiTexturePack);
// Save the savefile version
SetU32HexBytes(descData.m_saveVersion, SAVE_FILE_VERSION_NUMBER);
// clear out the future data with underscores
memset(descData.m_futureData, '_', sizeof(descData.m_futureData));
}
memcpy(descData.m_saveNameUTF8, m_saveFileDesc, strlen(m_saveFileDesc));
}
uint32_t SonyRemoteStorage::GetU32FromHexBytes(char* hexBytes)
{
char hexString[9];
ZeroMemory(hexString,9);
memcpy(hexString, hexBytes,8);
uint32_t u32Val = 0;
std::stringstream ss;
ss << hexString;
ss >> std::hex >> u32Val;
return u32Val;
}
uint64_t SonyRemoteStorage::GetU64FromHexBytes(char* hexBytes)
{
char hexString[17];
ZeroMemory(hexString,17);
memcpy(hexString, hexBytes,16);
uint64_t u64Val = 0;
std::stringstream ss;
ss << hexString;
ss >> std::hex >> u64Val;
return u64Val;
}
void SonyRemoteStorage::SetU32HexBytes(char* hexBytes, uint32_t u32)
{
char hexString[9];
sprintf(hexString,"%08x",u32);
memcpy(hexBytes,hexString,8); // Don't copy null
}
void SonyRemoteStorage::SetU64HexBytes(char* hexBytes, uint64_t u64)
{
char hexString[17];
sprintf(hexString,"%016llx",u64);
memcpy(hexBytes,hexString,16); // Don't copy null
}

View File

@@ -40,6 +40,7 @@ public:
PSAVE_INFO m_setSaveDataInfo;
SceRemoteStorageData* m_remoteFileInfo;
char m_saveFileDesc[128];
class DescriptionData
{
@@ -52,6 +53,47 @@ public:
char m_saveNameUTF8[128];
};
class DescriptionData_V2
{
// this stuff is read from a JSON query, so it all has to be text based, max 256 bytes
public:
char m_platformNone[4]; // set to no platform, to indicate we're using the newer version of the data
char m_descDataVersion[8]; // 4 bytes as hex - version number will be 2 in this case
char m_platform[4];
char m_seed[16]; // 8 bytes as hex
char m_hostOptions[8]; // 4 bytes as hex
char m_texturePack[8]; // 4 bytes as hex
char m_saveVersion[8]; // 4 bytes as hex
char m_futureData[64]; // some space for future data in case we need to expand this at all
char m_saveNameUTF8[128];
};
class DescriptionDataParsed
{
public:
int m_descDataVersion;
ESavePlatform m_savePlatform;
__int64 m_seed;
uint32_t m_hostOptions;
uint32_t m_texturePack;
uint32_t m_saveVersion;
char m_saveNameUTF8[128];
};
static const int sc_CurrentDescDataVersion = 2;
void GetDescriptionData(char* descData);
void GetDescriptionData(DescriptionData& descData);
void GetDescriptionData(DescriptionData_V2& descData);
uint32_t GetU32FromHexBytes(char* hexBytes);
uint64_t GetU64FromHexBytes(char* hexBytes);
void SetU32HexBytes(char* hexBytes, uint32_t u32);
void SetU64HexBytes(char* hexBytes, uint64_t u64);
DescriptionDataParsed m_retrievedDescData;
void SetRetrievedDescData();
CallbackFunc m_callbackFunc;
void* m_callbackParam;
@@ -62,6 +104,7 @@ public:
void getSaveInfo();
bool waitingForSaveInfo() { return (m_getInfoStatus == e_gettingInfo); }
bool saveIsAvailable();
bool saveVersionSupported();
int getSaveFilesize();
bool getSaveData(const char* localDirname, CallbackFunc cb, LPVOID lpParam);
@@ -115,6 +158,6 @@ protected:
bool m_bAborting;
bool m_bTransferStarted;
int m_uploadSaveSize;
};