diff --git a/Minecraft.Client/BeaconRenderer.cpp b/Minecraft.Client/BeaconRenderer.cpp index 959df6a8..a884a059 100644 --- a/Minecraft.Client/BeaconRenderer.cpp +++ b/Minecraft.Client/BeaconRenderer.cpp @@ -23,116 +23,129 @@ void BeaconRenderer::render(shared_ptr _beacon, double x, double y, //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glDisable(GL_LIGHTING); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthMask(true); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - - float tt = beacon->getLevel()->getGameTime() + a; - float texVOff = -tt * .20f - floor(-tt * .10f); + float ca = .125f; + int yb = 0; + for (unsigned int i = 0; i < beacon->beamSections.size(); i++) { - int r = 1; + BeaconTileEntity::BeaconBeamSection& section = beacon->beamSections.at(i); + int sectionTop = yb + section.getHeight(); - double rot = tt * .025 * (1 - (r & 1) * 2.5); + glDisable(GL_LIGHTING); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthMask(true); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); - t->begin(); - t->color(255, 255, 255, 32); + float tt = beacon->getLevel()->getGameTime() + a; + float texVOff = -tt * .20f - floor(-tt * .10f); - double rr1 = r * 0.2; + { + int r = 1; - double wnx = .5 + cos(rot + PI * .75) * rr1; - double wnz = .5 + sin(rot + PI * .75) * rr1; - double enx = .5 + cos(rot + PI * .25) * rr1; - double enz = .5 + sin(rot + PI * .25) * rr1; + double rot = tt * .025 * (1 - (r & 1) * 2.5); - double wsx = .5 + cos(rot + PI * 1.25) * rr1; - double wsz = .5 + sin(rot + PI * 1.25) * rr1; - double esx = .5 + cos(rot + PI * 1.75) * rr1; - double esz = .5 + sin(rot + PI * 1.75) * rr1; + t->begin(); + t->color(section.getColor()[0], section.getColor()[1], section.getColor()[2], ca); - double top = 256 * scale; + double rr1 = r * 0.2; - double uu1 = 0; - double uu2 = 1; - double vv2 = -1 + texVOff; - double vv1 = 256 * scale * (.5 / rr1) + vv2; + double wnx = .5 + cos(rot + PI * .75) * rr1; + double wnz = .5 + sin(rot + PI * .75) * rr1; + double enx = .5 + cos(rot + PI * .25) * rr1; + double enz = .5 + sin(rot + PI * .25) * rr1; - t->vertexUV(x + wnx, y + top, z + wnz, uu2, vv1); - t->vertexUV(x + wnx, y, z + wnz, uu2, vv2); - t->vertexUV(x + enx, y, z + enz, uu1, vv2); - t->vertexUV(x + enx, y + top, z + enz, uu1, vv1); + double wsx = .5 + cos(rot + PI * 1.25) * rr1; + double wsz = .5 + sin(rot + PI * 1.25) * rr1; + double esx = .5 + cos(rot + PI * 1.75) * rr1; + double esz = .5 + sin(rot + PI * 1.75) * rr1; - t->vertexUV(x + esx, y + top, z + esz, uu2, vv1); - t->vertexUV(x + esx, y, z + esz, uu2, vv2); - t->vertexUV(x + wsx, y, z + wsz, uu1, vv2); - t->vertexUV(x + wsx, y + top, z + wsz, uu1, vv1); + double bot = y + yb; + double top = y + sectionTop * scale; - t->vertexUV(x + enx, y + top, z + enz, uu2, vv1); - t->vertexUV(x + enx, y, z + enz, uu2, vv2); - t->vertexUV(x + esx, y, z + esz, uu1, vv2); - t->vertexUV(x + esx, y + top, z + esz, uu1, vv1); - - t->vertexUV(x + wsx, y + top, z + wsz, uu2, vv1); - t->vertexUV(x + wsx, y, z + wsz, uu2, vv2); - t->vertexUV(x + wnx, y, z + wnz, uu1, vv2); - t->vertexUV(x + wnx, y + top, z + wnz, uu1, vv1); - - t->end(); + double uu1 = 0; + double uu2 = 1; + double vv2 = -1 + texVOff; + double vv1 = section.getHeight() * scale * 2.5 + vv2; + + t->vertexUV(x + wnx, top, z + wnz, uu2, vv1); + t->vertexUV(x + wnx, bot, z + wnz, uu2, vv2); + t->vertexUV(x + enx, bot, z + enz, uu1, vv2); + t->vertexUV(x + enx, top, z + enz, uu1, vv1); + + t->vertexUV(x + enx, top, z + enz, uu2, vv1); + t->vertexUV(x + enx, bot, z + enz, uu2, vv2); + t->vertexUV(x + esx, bot, z + esz, uu1, vv2); + t->vertexUV(x + esx, top, z + esz, uu1, vv1); + + t->vertexUV(x + esx, top, z + esz, uu2, vv1); + t->vertexUV(x + esx, bot, z + esz, uu2, vv2); + t->vertexUV(x + wsx, bot, z + wsz, uu1, vv2); + t->vertexUV(x + wsx, top, z + wsz, uu1, vv1); + + t->vertexUV(x + wsx, top, z + wsz, uu2, vv1); + t->vertexUV(x + wsx, bot, z + wsz, uu2, vv2); + t->vertexUV(x + wnx, bot, z + wnz, uu1, vv2); + t->vertexUV(x + wnx, top, z + wnz, uu1, vv1); + + t->end(); + } + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(false); + + { + t->begin(); + t->color(section.getColor()[0], section.getColor()[1], section.getColor()[2], ca); + + double wnx = .2; + double wnz = .2; + double enx = .8; + double enz = .2; + + double wsx = .2; + double wsz = .8; + double esx = .8; + double esz = .8; + + double top = y + sectionTop * scale; + double bot = y + yb; + + double uu1 = 0; + double uu2 = 1; + double vv2 = -1 + texVOff; + double vv1 = section.getHeight() * scale + vv2; + + t->vertexUV(x + wnx, top, z + wnz, uu2, vv1); + t->vertexUV(x + wnx, bot, z + wnz, uu2, vv2); + t->vertexUV(x + enx, bot, z + enz, uu1, vv2); + t->vertexUV(x + enx, top, z + enz, uu1, vv1); + + t->vertexUV(x + enx, top, z + enz, uu2, vv1); + t->vertexUV(x + enx, bot, z + enz, uu2, vv2); + t->vertexUV(x + esx, bot, z + esz, uu1, vv2); + t->vertexUV(x + esx, top, z + esz, uu1, vv1); + + t->vertexUV(x + esx, top, z + esz, uu2, vv1); + t->vertexUV(x + esx, bot, z + esz, uu2, vv2); + t->vertexUV(x + wsx, bot, z + wsz, uu1, vv2); + t->vertexUV(x + wsx, top, z + wsz, uu1, vv1); + + t->vertexUV(x + wsx, top, z + wsz, uu2, vv1); + t->vertexUV(x + wsx, bot, z + wsz, uu2, vv2); + t->vertexUV(x + wnx, bot, z + wnz, uu1, vv2); + t->vertexUV(x + wnx, top, z + wnz, uu1, vv1); + + t->end(); + } + + glEnable(GL_LIGHTING); + glEnable(GL_TEXTURE_2D); + + glDepthMask(true); + + yb = sectionTop; } - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthMask(false); - - { - t->begin(); - t->color(255, 255, 255, 32); - - double wnx = .2; - double wnz = .2; - double enx = .8; - double enz = .2; - - double wsx = .2; - double wsz = .8; - double esx = .8; - double esz = .8; - - double top = 256 * scale; - - double uu1 = 0; - double uu2 = 1; - double vv2 = -1 + texVOff; - double vv1 = 256 * scale + vv2; - - t->vertexUV(x + wnx, y + top, z + wnz, uu2, vv1); - t->vertexUV(x + wnx, y, z + wnz, uu2, vv2); - t->vertexUV(x + enx, y, z + enz, uu1, vv2); - t->vertexUV(x + enx, y + top, z + enz, uu1, vv1); - - t->vertexUV(x + esx, y + top, z + esz, uu2, vv1); - t->vertexUV(x + esx, y, z + esz, uu2, vv2); - t->vertexUV(x + wsx, y, z + wsz, uu1, vv2); - t->vertexUV(x + wsx, y + top, z + wsz, uu1, vv1); - - t->vertexUV(x + enx, y + top, z + enz, uu2, vv1); - t->vertexUV(x + enx, y, z + enz, uu2, vv2); - t->vertexUV(x + esx, y, z + esz, uu1, vv2); - t->vertexUV(x + esx, y + top, z + esz, uu1, vv1); - - t->vertexUV(x + wsx, y + top, z + wsz, uu2, vv1); - t->vertexUV(x + wsx, y, z + wsz, uu2, vv2); - t->vertexUV(x + wnx, y, z + wnz, uu1, vv2); - t->vertexUV(x + wnx, y + top, z + wnz, uu1, vv1); - - t->end(); - } - - glEnable(GL_LIGHTING); - glEnable(GL_TEXTURE_2D); - - glDepthMask(true); } } \ No newline at end of file diff --git a/Minecraft.Client/Common/Media/Keyboard720.swf b/Minecraft.Client/Common/Media/Keyboard720.swf new file mode 100644 index 00000000..e9b6107e Binary files /dev/null and b/Minecraft.Client/Common/Media/Keyboard720.swf differ diff --git a/Minecraft.Client/Common/Media/KeyboardSplit720.swf b/Minecraft.Client/Common/Media/KeyboardSplit720.swf new file mode 100644 index 00000000..fdeea502 Binary files /dev/null and b/Minecraft.Client/Common/Media/KeyboardSplit720.swf differ diff --git a/Minecraft.Client/Common/Media/MediaWindows64.arc b/Minecraft.Client/Common/Media/MediaWindows64.arc index 1cb4d064..edfe5a7a 100644 Binary files a/Minecraft.Client/Common/Media/MediaWindows64.arc and b/Minecraft.Client/Common/Media/MediaWindows64.arc differ diff --git a/Minecraft.Client/Common/Network/GameNetworkManager.h b/Minecraft.Client/Common/Network/GameNetworkManager.h index 3357b3cd..22d58807 100644 --- a/Minecraft.Client/Common/Network/GameNetworkManager.h +++ b/Minecraft.Client/Common/Network/GameNetworkManager.h @@ -47,7 +47,8 @@ public: { JOINGAME_SUCCESS, JOINGAME_FAIL_GENERAL, - JOINGAME_FAIL_SERVER_FULL + JOINGAME_FAIL_SERVER_FULL, + JOINGAME_PENDING } eJoinGameResult; void Initialise(); diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp index 1e625098..430f2c11 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp @@ -173,6 +173,11 @@ bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkMa m_bSearchPending = false; m_bIsOfflineGame = false; +#ifdef _WINDOWS64 + m_bJoinPending = false; + m_joinLocalUsersMask = 0; + m_joinHostName[0] = 0; +#endif m_pSearchParam = nullptr; m_SessionsUpdatedCallback = nullptr; @@ -282,6 +287,38 @@ void CPlatformNetworkManagerStub::DoWork() m_bLeaveGameOnTick = false; } } + + if (m_bJoinPending) + { + WinsockNetLayer::eJoinState state = WinsockNetLayer::GetJoinState(); + if (state == WinsockNetLayer::eJoinState_Success) + { + WinsockNetLayer::FinalizeJoin(); + + BYTE localSmallId = WinsockNetLayer::GetLocalSmallId(); + + IQNet::m_player[localSmallId].m_smallId = localSmallId; + IQNet::m_player[localSmallId].m_isRemote = false; + IQNet::m_player[localSmallId].m_isHostPlayer = false; + IQNet::m_player[localSmallId].m_resolvedXuid = Win64Xuid::ResolvePersistentXuid(); + + Minecraft* pMinecraft = Minecraft::GetInstance(); + wcscpy_s(IQNet::m_player[localSmallId].m_gamertag, 32, pMinecraft->user->name.c_str()); + IQNet::s_playerCount = localSmallId + 1; + + NotifyPlayerJoined(&IQNet::m_player[0]); + NotifyPlayerJoined(&IQNet::m_player[localSmallId]); + + m_pGameNetworkManager->StateChange_AnyToStarting(); + m_bJoinPending = false; + } + else if (state == WinsockNetLayer::eJoinState_Failed || + state == WinsockNetLayer::eJoinState_Rejected || + state == WinsockNetLayer::eJoinState_Cancelled) + { + m_bJoinPending = false; + } + } #endif } @@ -511,36 +548,22 @@ int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo* searchResult, int l IQNet::m_player[0].m_smallId = 0; IQNet::m_player[0].m_isRemote = true; IQNet::m_player[0].m_isHostPlayer = true; - // Remote host still maps to legacy host XUID in mixed old/new sessions. IQNet::m_player[0].m_resolvedXuid = Win64Xuid::GetLegacyEmbeddedHostXuid(); wcsncpy_s(IQNet::m_player[0].m_gamertag, 32, searchResult->data.hostName, _TRUNCATE); WinsockNetLayer::StopDiscovery(); - if (!WinsockNetLayer::JoinGame(hostIP, hostPort)) + wcsncpy_s(m_joinHostName, 32, searchResult->data.hostName, _TRUNCATE); + m_joinLocalUsersMask = localUsersMask; + + if (!WinsockNetLayer::BeginJoinGame(hostIP, hostPort)) { app.DebugPrintf("Win64 LAN: Failed to connect to %s:%d\n", hostIP, hostPort); return CGameNetworkManager::JOINGAME_FAIL_GENERAL; } - BYTE localSmallId = WinsockNetLayer::GetLocalSmallId(); - - IQNet::m_player[localSmallId].m_smallId = localSmallId; - IQNet::m_player[localSmallId].m_isRemote = false; - IQNet::m_player[localSmallId].m_isHostPlayer = false; - // Local non-host identity is the persistent uid.dat XUID. - IQNet::m_player[localSmallId].m_resolvedXuid = Win64Xuid::ResolvePersistentXuid(); - - Minecraft* pMinecraft = Minecraft::GetInstance(); - wcscpy_s(IQNet::m_player[localSmallId].m_gamertag, 32, pMinecraft->user->name.c_str()); - IQNet::s_playerCount = localSmallId + 1; - - NotifyPlayerJoined(&IQNet::m_player[0]); - NotifyPlayerJoined(&IQNet::m_player[localSmallId]); - - m_pGameNetworkManager->StateChange_AnyToStarting(); - - return CGameNetworkManager::JOINGAME_SUCCESS; + m_bJoinPending = true; + return CGameNetworkManager::JOINGAME_PENDING; #else return CGameNetworkManager::JOINGAME_SUCCESS; #endif diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h index 4a3f4068..dffa3953 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h @@ -77,6 +77,12 @@ private: bool m_bIsPrivateGame; int m_flagIndexSize; +#ifdef _WINDOWS64 + bool m_bJoinPending; + int m_joinLocalUsersMask; + wchar_t m_joinHostName[32]; +#endif + // This is only maintained by the host, and is not valid on client machines GameSessionData m_hostGameSessionData; CGameNetworkManager *m_pGameNetworkManager; diff --git a/Minecraft.Client/Common/UI/UIControl_Slider.cpp b/Minecraft.Client/Common/UI/UIControl_Slider.cpp index c9b773a7..a53d8575 100644 --- a/Minecraft.Client/Common/UI/UIControl_Slider.cpp +++ b/Minecraft.Client/Common/UI/UIControl_Slider.cpp @@ -78,6 +78,20 @@ bool IsUsingKeyboardMouse() #endif } +void UIControl_Slider::setFocus(bool hasFocus) +{ + if (m_hasFocus != hasFocus) + { + m_hasFocus = hasFocus; + + IggyDataValue result; + IggyDataValue value[1]; + value[0].type = IGGY_DATATYPE_number; + value[0].number = hasFocus ? 0.0f : 1.0f; + IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath() , m_funcSetGreyedOut , 1 , value ); + } +} + void UIControl_Slider::handleSliderMove(int newValue) { if (m_current!=newValue) @@ -119,7 +133,47 @@ void UIControl_Slider::SetSliderTouchPos(float fTouchPos) value[0].type = IGGY_DATATYPE_number; value[0].number = fTouchPos; IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath() , m_funcSetRelativeSliderPos , 1 , value ); - } +} + +void UIControl_Slider::SetSliderValue(int iValue) +{ + IggyDataValue result; + IggyDataValue value[1]; + value[0].type = IGGY_DATATYPE_number; + value[0].number = iValue; + IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath() , m_funcSetRelativeSliderPos , 1 , value ); +} + +void UIControl_Slider::MoveSliderValue(int delta) +{ + int newValue = m_current + delta; + if(newValue >= m_max) + newValue = m_max; + if(m_min > newValue) + newValue = m_min; + + IggyDataValue result; + IggyDataValue value[1]; + value[0].type = IGGY_DATATYPE_number; + value[0].number = newValue; + IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath() , m_funcSetRelativeSliderPos , 1 , value ); + + if(m_current != newValue) + { + ui.PlayUISFX(eSFX_Scroll); + m_current = newValue; + + if(newValue < m_allPossibleLabels.size()) + { + setLabel(m_allPossibleLabels[newValue]); + } + } +} + +int UIControl_Slider::getCurrentValue() +{ + return m_current; +} S32 UIControl_Slider::GetRealWidth() { diff --git a/Minecraft.Client/Common/UI/UIControl_Slider.h b/Minecraft.Client/Common/UI/UIControl_Slider.h index 505f6dd2..2b076c64 100644 --- a/Minecraft.Client/Common/UI/UIControl_Slider.h +++ b/Minecraft.Client/Common/UI/UIControl_Slider.h @@ -9,12 +9,14 @@ private: int m_min; int m_max; int m_current; + bool m_hasFocus; vector m_allPossibleLabels; // 4J-TomK - function for setting slider position on touch IggyName m_funcSetRelativeSliderPos; IggyName m_funcGetRealWidth; + IggyName m_funcSetGreyedOut; public: UIControl_Slider(); @@ -23,10 +25,16 @@ public: void init(UIString label, int id, int min, int max, int current); + void setFocus(bool hasFocus); + virtual bool hasFocus() { return m_hasFocus; } void handleSliderMove(int newValue); void SetSliderTouchPos(float fTouchPos); + virtual void SetSliderValue(int value); virtual void setAllPossibleLabels(int labelCount, wchar_t labels[][256]); + void MoveSliderValue(int delta); + int getCurrentValue(); + S32 GetRealWidth(); virtual void ReInit(); }; diff --git a/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.cpp b/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.cpp index e10a5a62..a28b9d45 100644 --- a/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.cpp +++ b/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.cpp @@ -2,6 +2,16 @@ #include "UI.h" #include "UIScene_ConnectingProgress.h" #include "..\..\Minecraft.h" +#ifdef _WINDOWS64 +#include "..\..\Windows64\Network\WinsockNetLayer.h" +#include "..\..\..\Minecraft.World\DisconnectPacket.h" + +static int ConnectingProgress_OnRejectedDialogOK(LPVOID, int iPad, const C4JStorage::EMessageResult) +{ + ui.NavigateBack(iPad); + return 0; +} +#endif UIScene_ConnectingProgress::UIScene_ConnectingProgress(int iPad, void *_initData, UILayer *parentLayer) : UIScene(iPad, parentLayer) { @@ -43,6 +53,12 @@ UIScene_ConnectingProgress::UIScene_ConnectingProgress(int iPad, void *_initData m_cancelFuncParam = param->cancelFuncParam; m_removeLocalPlayer = false; m_showingButton = false; + +#ifdef _WINDOWS64 + WinsockNetLayer::eJoinState initState = WinsockNetLayer::GetJoinState(); + m_asyncJoinActive = (initState != WinsockNetLayer::eJoinState_Idle && initState != WinsockNetLayer::eJoinState_Cancelled); + m_asyncJoinFailed = false; +#endif } UIScene_ConnectingProgress::~UIScene_ConnectingProgress() @@ -53,6 +69,19 @@ UIScene_ConnectingProgress::~UIScene_ConnectingProgress() void UIScene_ConnectingProgress::updateTooltips() { +#ifdef _WINDOWS64 + if (m_asyncJoinActive) + { + ui.SetTooltips( m_iPad, -1, IDS_TOOLTIPS_BACK); + return; + } + if (m_asyncJoinFailed) + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT, -1); + return; + } +#endif + // 4J-PB - removing the option of cancel join, since it didn't work anyway //ui.SetTooltips( m_iPad, -1, m_showTooltips?IDS_TOOLTIPS_CANCEL_JOIN:-1); ui.SetTooltips( m_iPad, -1, -1); @@ -62,6 +91,85 @@ void UIScene_ConnectingProgress::tick() { UIScene::tick(); +#ifdef _WINDOWS64 + if (m_asyncJoinActive) + { + WinsockNetLayer::eJoinState state = WinsockNetLayer::GetJoinState(); + if (state == WinsockNetLayer::eJoinState_Connecting) + { + // connecting............. + int attempt = WinsockNetLayer::GetJoinAttempt(); + int maxAttempts = WinsockNetLayer::GetJoinMaxAttempts(); + char buf[128]; + if (attempt <= 1) + sprintf_s(buf, "Connecting..."); + else + sprintf_s(buf, "Connecting failed, trying again (%d/%d)", attempt, maxAttempts); + wchar_t wbuf[128]; + mbstowcs(wbuf, buf, 128); + m_labelTitle.setLabel(wstring(wbuf)); + } + else if (state == WinsockNetLayer::eJoinState_Success) + { + m_asyncJoinActive = false; + // go go go + } + else if (state == WinsockNetLayer::eJoinState_Cancelled) + { + // cancel + m_asyncJoinActive = false; + navigateBack(); + } + else if (state == WinsockNetLayer::eJoinState_Rejected) + { + // server full and banned are passed differently compared to other disconnects it seems + m_asyncJoinActive = false; + DisconnectPacket::eDisconnectReason reason = WinsockNetLayer::GetJoinRejectReason(); + int exitReasonStringId; + switch (reason) + { + case DisconnectPacket::eDisconnect_ServerFull: + exitReasonStringId = IDS_DISCONNECTED_SERVER_FULL; + break; + case DisconnectPacket::eDisconnect_Banned: + exitReasonStringId = IDS_DISCONNECTED_KICKED; + break; + default: + exitReasonStringId = IDS_CONNECTION_LOST_SERVER; + break; + } + UINT uiIDA[1]; + uiIDA[0] = IDS_CONFIRM_OK; + ui.RequestErrorMessage(IDS_CONNECTION_FAILED, exitReasonStringId, uiIDA, 1, ProfileManager.GetPrimaryPad(), ConnectingProgress_OnRejectedDialogOK, nullptr, nullptr); + } + else if (state == WinsockNetLayer::eJoinState_Failed) + { + // FAIL + m_asyncJoinActive = false; + m_asyncJoinFailed = true; + + int maxAttempts = WinsockNetLayer::GetJoinMaxAttempts(); + char buf[256]; + sprintf_s(buf, "Failed to connect after %d attempts. The server may be unavailable.", maxAttempts); + wchar_t wbuf[256]; + mbstowcs(wbuf, buf, 256); + + // TIL that these exist + // not going to use a actual popup due to it requiring messing with strings which can really mess things up + // i dont trust myself with that + // these need to be touched up later as teh button is a bit offset + m_labelTitle.setLabel(L"Unable to connect to server"); + m_progressBar.setLabel(wstring(wbuf)); + m_progressBar.showBar(false); + m_progressBar.setVisible(true); + m_buttonConfirm.setVisible(true); + m_showingButton = true; + m_controlTimer.setVisible(false); + } + return; + } +#endif + if( m_removeLocalPlayer ) { m_removeLocalPlayer = false; @@ -94,6 +202,8 @@ void UIScene_ConnectingProgress::handleGainFocus(bool navBack) void UIScene_ConnectingProgress::handleLoseFocus() { + if (!m_runFailTimer) return; + int millisecsLeft = getTimer(0)->targetTime - System::currentTimeMillis(); int millisecsTaken = getTimer(0)->duration - millisecsLeft; app.DebugPrintf("\n"); @@ -208,6 +318,17 @@ void UIScene_ConnectingProgress::handleInput(int iPad, int key, bool repeat, boo switch(key) { // 4J-PB - Removed the option to cancel join - it didn't work anyway +#ifdef _WINDOWS64 + case ACTION_MENU_CANCEL: + if (pressed && m_asyncJoinActive) + { + m_asyncJoinActive = false; + WinsockNetLayer::CancelJoinGame(); + navigateBack(); + handled = true; + } + break; +#endif // case ACTION_MENU_CANCEL: // { // if(m_cancelFunc != nullptr) @@ -250,6 +371,13 @@ void UIScene_ConnectingProgress::handlePress(F64 controlId, F64 childId) case eControl_Confirm: if(m_showingButton) { +#ifdef _WINDOWS64 + if (m_asyncJoinFailed) + { + navigateBack(); + } + else +#endif if( m_iPad != ProfileManager.GetPrimaryPad() && g_NetworkManager.IsInSession() ) { // The connection failed if we see the button, so the temp player should be removed and the viewports updated again diff --git a/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.h b/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.h index 2c52284c..eaaea7f6 100644 --- a/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.h +++ b/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.h @@ -13,6 +13,11 @@ private: void (*m_cancelFunc)(LPVOID param); LPVOID m_cancelFuncParam; +#ifdef _WINDOWS64 + bool m_asyncJoinActive; + bool m_asyncJoinFailed; +#endif + enum EControls { eControl_Confirm diff --git a/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp index 417c1700..5b83ea7c 100644 --- a/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp @@ -583,6 +583,24 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) // Alert the app the we no longer want to be informed of ethernet connections app.SetLiveLinkRequired( false ); +#ifdef _WINDOWS64 + if (result == CGameNetworkManager::JOINGAME_PENDING) + { + pClass->m_bIgnoreInput = false; + + ConnectionProgressParams *param = new ConnectionProgressParams(); + param->iPad = ProfileManager.GetPrimaryPad(); + param->stringId = -1; + param->showTooltips = true; + param->setFailTimer = false; + param->timerTime = 0; + param->cancelFunc = nullptr; + param->cancelFuncParam = nullptr; + ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_ConnectingProgress, param); + return; + } +#endif + if( result != CGameNetworkManager::JOINGAME_SUCCESS ) { int exitReasonStringId = -1; diff --git a/Minecraft.Client/Common/UI/UIScene_LoadMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LoadMenu.cpp index 84f5a5c1..07483b6e 100644 --- a/Minecraft.Client/Common/UI/UIScene_LoadMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_LoadMenu.cpp @@ -528,13 +528,11 @@ void UIScene_LoadMenu::tick() m_bGameModeCreative=true; m_iGameModeId = GameType::CREATIVE->getId(); break; -#ifdef _ADVENTURE_MODE_ENABLED case 2: // Adventure m_buttonGamemode.setLabel(app.GetString(IDS_GAMEMODE_ADVENTURE)); m_bGameModeCreative=false; m_iGameModeId = GameType::ADVENTURE->getId(); break; -#endif case 0: // Survival default: m_buttonGamemode.setLabel(app.GetString(IDS_GAMEMODE_SURVIVAL)); @@ -709,13 +707,11 @@ void UIScene_LoadMenu::handlePress(F64 controlId, F64 childId) m_bGameModeCreative = true; break; case 1: // Creative -#ifdef _ADVENTURE_MODE_ENABLED m_buttonGamemode.setLabel(app.GetString(IDS_GAMEMODE_ADVENTURE)); m_iGameModeId = GameType::ADVENTURE->getId(); m_bGameModeCreative = false; break; case 2: // Adventure -#endif m_buttonGamemode.setLabel(app.GetString(IDS_GAMEMODE_SURVIVAL)); m_iGameModeId = GameType::SURVIVAL->getId(); m_bGameModeCreative = false; diff --git a/Minecraft.Client/ItemInHandRenderer.cpp b/Minecraft.Client/ItemInHandRenderer.cpp index a5006609..3cbe1ed1 100644 --- a/Minecraft.Client/ItemInHandRenderer.cpp +++ b/Minecraft.Client/ItemInHandRenderer.cpp @@ -243,7 +243,10 @@ void ItemInHandRenderer::renderItem(shared_ptr mob, shared_ptrtextures->bindTexture(minecraft->textures->getTextureLocation(Icon::TYPE_TERRAIN)); MemSect(0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); tileRenderer->renderTile(Tile::tiles[item->id], item->getAuxValue(), SharedConstants::TEXTURE_LIGHTING ? 1.0f : mob->getBrightness(1)); // 4J - change brought forward from 1.8.2 + glDisable(GL_BLEND); } else { diff --git a/Minecraft.Client/MultiPlayerChunkCache.cpp b/Minecraft.Client/MultiPlayerChunkCache.cpp index 62361ce3..03c47fcc 100644 --- a/Minecraft.Client/MultiPlayerChunkCache.cpp +++ b/Minecraft.Client/MultiPlayerChunkCache.cpp @@ -139,19 +139,26 @@ bool MultiPlayerChunkCache::reallyHasChunk(int x, int z) return hasData[idx]; } -void MultiPlayerChunkCache::drop(int x, int z) +void MultiPlayerChunkCache::drop(const int x, const int z) { - // 4J Stu - We do want to drop any entities in the chunks, especially for the case when a player is dead as they will - // not get the RemoveEntity packet if an entity is removed. - LevelChunk *chunk = getChunk(x, z); - if (!chunk->isEmpty()) + const int ix = x + XZOFFSET; + const int iz = z + XZOFFSET; + if ((ix < 0) || (ix >= XZSIZE)) return; + if ((iz < 0) || (iz >= XZSIZE)) return; + const int idx = ix * XZSIZE + iz; + LevelChunk* chunk = cache[idx]; + + if (chunk != nullptr && !chunk->isEmpty()) { - // Added parameter here specifies that we don't want to delete tile entities, as they won't get recreated unless they've got update packets - // The tile entities are in general only created on the client by virtue of the chunk rebuild + // Unload chunk but keep tile entities chunk->unload(false); - // 4J - We just want to clear out the entities in the chunk, but everything else should be valid - chunk->loaded = true; + const auto it = std::find(loadedChunkList.begin(), loadedChunkList.end(), chunk); + if (it != loadedChunkList.end()) loadedChunkList.erase(it); + + cache[idx] = nullptr; + hasData[idx] = false; + chunk->loaded = false; } } diff --git a/Minecraft.Client/PlayerChunkMap.cpp b/Minecraft.Client/PlayerChunkMap.cpp index bcc3f6ba..ddf2bae2 100644 --- a/Minecraft.Client/PlayerChunkMap.cpp +++ b/Minecraft.Client/PlayerChunkMap.cpp @@ -792,6 +792,14 @@ void PlayerChunkMap::setRadius(int newRadius) int xc = static_cast(player->x) >> 4; int zc = static_cast(player->z) >> 4; + for (auto it = addRequests.begin(); it != addRequests.end(); ) + { + if (it->player == player) + it = addRequests.erase(it); + else + ++it; + } + for (int x = xc - newRadius; x <= xc + newRadius; x++) for (int z = zc - newRadius; z <= zc + newRadius; z++) { @@ -801,9 +809,26 @@ void PlayerChunkMap::setRadius(int newRadius) getChunkAndAddPlayer(x, z, player); } } + + // Remove chunks that are outside the new radius + for (int x = xc - radius; x <= xc + radius; x++) + { + for (int z = zc - radius; z <= zc + radius; z++) + { + if (x < xc - newRadius || x > xc + newRadius || z < zc - newRadius || z > zc + newRadius) + { + getChunkAndRemovePlayer(x, z, player); + } + } + } } } + if (newRadius < radius) + { + level->cache->dropAll(); + } + assert(radius <= MAX_VIEW_DISTANCE); assert(radius >= MIN_VIEW_DISTANCE); this->radius = newRadius; diff --git a/Minecraft.Client/PlayerList.cpp b/Minecraft.Client/PlayerList.cpp index ba82ec6a..331539cb 100644 --- a/Minecraft.Client/PlayerList.cpp +++ b/Minecraft.Client/PlayerList.cpp @@ -1690,7 +1690,16 @@ bool PlayerList::isXuidBanned(PlayerUID xuid) } // AP added for Vita so the range can be increased once the level starts -void PlayerList::setViewDistance(int newViewDistance) +void PlayerList::setViewDistance(const int newViewDistance) { viewDistance = newViewDistance; + + for (size_t i = 0; i < server->levels.length; i++) + { + ServerLevel* level = server->levels[i]; + if (level != nullptr) + { + level->getChunkMap()->setRadius(newViewDistance); + } + } } diff --git a/Minecraft.Client/ServerChunkCache.cpp b/Minecraft.Client/ServerChunkCache.cpp index c7d70c7d..54312ffa 100644 --- a/Minecraft.Client/ServerChunkCache.cpp +++ b/Minecraft.Client/ServerChunkCache.cpp @@ -80,54 +80,31 @@ vector *ServerChunkCache::getLoadedChunkList() return &m_loadedChunkList; } -void ServerChunkCache::drop(int x, int z) +void ServerChunkCache::drop(const int x, const int z) { - // 4J - we're not dropping things anymore now that we have a fixed sized cache -#ifdef _LARGE_WORLDS + const int ix = x + XZOFFSET; + const int iz = z + XZOFFSET; + if ((ix < 0) || (ix >= XZSIZE)) return; + if ((iz < 0) || (iz >= XZSIZE)) return; + const int idx = ix * XZSIZE + iz; + LevelChunk* chunk = cache[idx]; - bool canDrop = false; -// if (level->dimension->mayRespawn()) -// { -// Pos *spawnPos = level->getSharedSpawnPos(); -// int xd = x * 16 + 8 - spawnPos->x; -// int zd = z * 16 + 8 - spawnPos->z; -// delete spawnPos; -// int r = 128; -// if (xd < -r || xd > r || zd < -r || zd > r) -// { -// canDrop = true; -//} -// } -// else + if (chunk != nullptr) { - canDrop = true; - } - if(canDrop) - { - int ix = x + XZOFFSET; - int iz = z + XZOFFSET; - // Check we're in range of the stored level - if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return; - if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return; - int idx = ix * XZSIZE + iz; - LevelChunk *chunk = cache[idx]; + const auto it = std::find(m_loadedChunkList.begin(), m_loadedChunkList.end(), chunk); + if (it != m_loadedChunkList.end()) m_loadedChunkList.erase(it); - if(chunk) - { - m_toDrop.push_back(chunk); - } + cache[idx] = nullptr; + chunk->loaded = false; } -#endif } void ServerChunkCache::dropAll() { -#ifdef _LARGE_WORLDS for (LevelChunk *chunk : m_loadedChunkList) { drop(chunk->x, chunk->z); -} -#endif + } } // 4J - this is the original (and virtual) interface to create @@ -957,6 +934,10 @@ bool ServerChunkCache::tick() m_unloadedCache[idx] = chunk; cache[idx] = nullptr; } + else + { + continue; + } } m_toDrop.pop_front(); } diff --git a/Minecraft.Client/TileRenderer.cpp b/Minecraft.Client/TileRenderer.cpp index d66b4c91..fdda6fae 100644 --- a/Minecraft.Client/TileRenderer.cpp +++ b/Minecraft.Client/TileRenderer.cpp @@ -8505,6 +8505,44 @@ void TileRenderer::renderTile( Tile* tile, int data, float brightness, float fAl tesselateHopperInWorld(tile, 0, 0, 0, 0, true); glTranslatef(0.5f, 0.5f, 0.5f); } + else if (shape == Tile::SHAPE_THIN_PANE) + { + setShape(7.0f / 16.0f, 0, 0, 9.0f / 16.0f, 1.0f, 1.0f); + + glTranslatef(-0.5f, -0.5f, -0.5f); + t->begin(); + t->normal(0, -1, 0); + renderFaceDown(tile, 0, 0, 0, getTexture(tile, 0, data)); + t->end(); + + t->begin(); + t->normal(0, 1, 0); + renderFaceUp(tile, 0, 0, 0, getTexture(tile, 1, data)); + t->end(); + + t->begin(); + t->normal(0, 0, -1); + renderNorth(tile, 0, 0, 0, getTexture(tile, 2, data)); + t->end(); + + t->begin(); + t->normal(0, 0, 1); + renderSouth(tile, 0, 0, 0, getTexture(tile, 3, data)); + t->end(); + + t->begin(); + t->normal(-1, 0, 0); + renderWest(tile, 0, 0, 0, getTexture(tile, 4, data)); + t->end(); + + t->begin(); + t->normal(1, 0, 0); + renderEast(tile, 0, 0, 0, getTexture(tile, 5, data)); + t->end(); + + glTranslatef(0.5f, 0.5f, 0.5f); + setShape(0, 0, 0, 1, 1, 1); + } t->setMipmapEnable( true ); // 4J added } @@ -8525,6 +8563,8 @@ bool TileRenderer::canRender( int renderShape ) if ( renderShape == Tile::SHAPE_WALL) return true; if ( renderShape == Tile::SHAPE_BEACON) return true; if ( renderShape == Tile::SHAPE_ANVIL) return true; + if ( renderShape == Tile::SHAPE_THIN_PANE ) return true; + if ( renderShape == Tile::SHAPE_WATER ) return true; return false; } diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp index 981ab3ab..acc043e5 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp @@ -67,6 +67,16 @@ SOCKET WinsockNetLayer::s_splitScreenSocket[XUSER_MAX_COUNT] = { INVALID_SOCKET, BYTE WinsockNetLayer::s_splitScreenSmallId[XUSER_MAX_COUNT] = { 0xFF, 0xFF, 0xFF, 0xFF }; HANDLE WinsockNetLayer::s_splitScreenRecvThread[XUSER_MAX_COUNT] = {nullptr, nullptr, nullptr, nullptr}; +// async stuff +HANDLE WinsockNetLayer::s_joinThread = nullptr; +volatile WinsockNetLayer::eJoinState WinsockNetLayer::s_joinState = WinsockNetLayer::eJoinState_Idle; +volatile int WinsockNetLayer::s_joinAttempt = 0; +volatile bool WinsockNetLayer::s_joinCancel = false; +char WinsockNetLayer::s_joinIP[256] = {}; +int WinsockNetLayer::s_joinPort = 0; +BYTE WinsockNetLayer::s_joinAssignedSmallId = 0; +DisconnectPacket::eDisconnectReason WinsockNetLayer::s_joinRejectReason = DisconnectPacket::eDisconnect_Quitting; + bool g_Win64MultiplayerHost = false; bool g_Win64MultiplayerJoin = false; int g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT; @@ -114,6 +124,15 @@ void WinsockNetLayer::Shutdown() StopAdvertising(); StopDiscovery(); + s_joinCancel = true; + if (s_joinThread != nullptr) + { + WaitForSingleObject(s_joinThread, 5000); + CloseHandle(s_joinThread); + s_joinThread = nullptr; + } + s_joinState = eJoinState_Idle; + s_active = false; s_connected = false; @@ -421,6 +440,215 @@ bool WinsockNetLayer::JoinGame(const char* ip, int port) return true; } +bool WinsockNetLayer::BeginJoinGame(const char* ip, int port) +{ + if (!s_initialized && !Initialize()) return false; + + // if there isnt any cleanup it sometime caused issues. Oops + CancelJoinGame(); + if (s_joinThread != nullptr) + { + WaitForSingleObject(s_joinThread, 5000); + CloseHandle(s_joinThread); + s_joinThread = nullptr; + } + + s_isHost = false; + s_hostSmallId = 0; + s_connected = false; + s_active = false; + + if (s_hostConnectionSocket != INVALID_SOCKET) + { + closesocket(s_hostConnectionSocket); + s_hostConnectionSocket = INVALID_SOCKET; + } + + if (s_clientRecvThread != nullptr) + { + WaitForSingleObject(s_clientRecvThread, 5000); + CloseHandle(s_clientRecvThread); + s_clientRecvThread = nullptr; + } + + strncpy_s(s_joinIP, sizeof(s_joinIP), ip, _TRUNCATE); + s_joinPort = port; + s_joinAttempt = 0; + s_joinCancel = false; + s_joinAssignedSmallId = 0; + s_joinRejectReason = DisconnectPacket::eDisconnect_Quitting; + s_joinState = eJoinState_Connecting; + + s_joinThread = CreateThread(nullptr, 0, JoinThreadProc, nullptr, 0, nullptr); + if (s_joinThread == nullptr) + { + s_joinState = eJoinState_Failed; + return false; + } + return true; +} + +DWORD WINAPI WinsockNetLayer::JoinThreadProc(LPVOID param) +{ + struct addrinfo hints = {}; + struct addrinfo* result = nullptr; + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + char portStr[16]; + sprintf_s(portStr, "%d", s_joinPort); + + int iResult = getaddrinfo(s_joinIP, portStr, &hints, &result); + if (iResult != 0) + { + app.DebugPrintf("getaddrinfo failed for %s:%d - %d\n", s_joinIP, s_joinPort, iResult); + s_joinState = eJoinState_Failed; + return 0; + } + + bool connected = false; + BYTE assignedSmallId = 0; + SOCKET sock = INVALID_SOCKET; + + for (int attempt = 0; attempt < JOIN_MAX_ATTEMPTS; ++attempt) + { + if (s_joinCancel) + { + freeaddrinfo(result); + s_joinState = eJoinState_Cancelled; + return 0; + } + + s_joinAttempt = attempt + 1; + + sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol); + if (sock == INVALID_SOCKET) + { + app.DebugPrintf("socket() failed: %d\n", WSAGetLastError()); + break; + } + + int noDelay = 1; + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&noDelay, sizeof(noDelay)); + + iResult = connect(sock, result->ai_addr, static_cast(result->ai_addrlen)); + if (iResult == SOCKET_ERROR) + { + int err = WSAGetLastError(); + app.DebugPrintf("connect() to %s:%d failed (attempt %d/%d): %d\n", s_joinIP, s_joinPort, attempt + 1, JOIN_MAX_ATTEMPTS, err); + closesocket(sock); + sock = INVALID_SOCKET; + for (int w = 0; w < 4 && !s_joinCancel; w++) + Sleep(50); + continue; + } + + BYTE assignBuf[1]; + int bytesRecv = recv(sock, (char*)assignBuf, 1, 0); + if (bytesRecv != 1) + { + app.DebugPrintf("failed to receive small id assignment from host (attempt %d/%d)\n", attempt + 1, JOIN_MAX_ATTEMPTS); + closesocket(sock); + sock = INVALID_SOCKET; + for (int w = 0; w < 4 && !s_joinCancel; w++) + Sleep(50); + continue; + } + + if (assignBuf[0] == WIN64_SMALLID_REJECT) + { + BYTE rejectBuf[5]; + if (!RecvExact(sock, rejectBuf, 5)) + { + app.DebugPrintf("failed to receive reject reason from host (?)\n"); + closesocket(sock); + sock = INVALID_SOCKET; + for (int w = 0; w < 4 && !s_joinCancel; w++) + Sleep(50); + continue; + } + int reason = ((rejectBuf[1] & 0xff) << 24) | ((rejectBuf[2] & 0xff) << 16) | + ((rejectBuf[3] & 0xff) << 8) | (rejectBuf[4] & 0xff); + s_joinRejectReason = (DisconnectPacket::eDisconnectReason)reason; + closesocket(sock); + freeaddrinfo(result); + s_joinState = eJoinState_Rejected; + return 0; + } + + assignedSmallId = assignBuf[0]; + connected = true; + break; + } + freeaddrinfo(result); + + if (s_joinCancel) + { + if (sock != INVALID_SOCKET) closesocket(sock); + s_joinState = eJoinState_Cancelled; + return 0; + } + + if (!connected) + { + s_joinState = eJoinState_Failed; + return 0; + } + + s_hostConnectionSocket = sock; + s_joinAssignedSmallId = assignedSmallId; + s_joinState = eJoinState_Success; + return 0; +} + +void WinsockNetLayer::CancelJoinGame() +{ + if (s_joinState == eJoinState_Connecting) + { + s_joinCancel = true; + } + else if (s_joinState == eJoinState_Success) + { + // fix a race cond + if (s_hostConnectionSocket != INVALID_SOCKET) + { + closesocket(s_hostConnectionSocket); + s_hostConnectionSocket = INVALID_SOCKET; + } + s_joinState = eJoinState_Cancelled; + } +} + +bool WinsockNetLayer::FinalizeJoin() +{ + if (s_joinState != eJoinState_Success) + return false; + + s_localSmallId = s_joinAssignedSmallId; + + strncpy_s(g_Win64MultiplayerIP, sizeof(g_Win64MultiplayerIP), s_joinIP, _TRUNCATE); + g_Win64MultiplayerPort = s_joinPort; + + app.DebugPrintf("connected to %s:%d, assigned smallId=%d\n", s_joinIP, s_joinPort, s_localSmallId); + + s_active = true; + s_connected = true; + + s_clientRecvThread = CreateThread(nullptr, 0, ClientRecvThreadProc, nullptr, 0, nullptr); + + if (s_joinThread != nullptr) + { + WaitForSingleObject(s_joinThread, 2000); + CloseHandle(s_joinThread); + s_joinThread = nullptr; + } + + s_joinState = eJoinState_Idle; + return true; +} + bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void* data, int dataSize) { if (sock == INVALID_SOCKET || dataSize <= 0 || dataSize > WIN64_NET_MAX_PACKET_SIZE) return false; @@ -1334,4 +1562,25 @@ DWORD WINAPI WinsockNetLayer::DiscoveryThreadProc(LPVOID param) return 0; } +// some lazy helper funcs +WinsockNetLayer::eJoinState WinsockNetLayer::GetJoinState() +{ + return s_joinState; +} + +int WinsockNetLayer::GetJoinAttempt() +{ + return s_joinAttempt; +} + +int WinsockNetLayer::GetJoinMaxAttempts() +{ + return JOIN_MAX_ATTEMPTS; +} + +DisconnectPacket::eDisconnectReason WinsockNetLayer::GetJoinRejectReason() +{ + return s_joinRejectReason; +} + #endif diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h index afccbd66..8a11e391 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h @@ -21,6 +21,8 @@ class Socket; +#include "..\..\..\Minecraft.World\DisconnectPacket.h" + #pragma pack(push, 1) struct Win64LANBroadcast { @@ -69,6 +71,23 @@ public: static bool HostGame(int port, const char* bindIp = nullptr); static bool JoinGame(const char* ip, int port); + enum eJoinState + { + eJoinState_Idle, + eJoinState_Connecting, + eJoinState_Success, + eJoinState_Failed, + eJoinState_Rejected, + eJoinState_Cancelled + }; + static bool BeginJoinGame(const char* ip, int port); + static void CancelJoinGame(); + static eJoinState GetJoinState(); + static int GetJoinAttempt(); + static int GetJoinMaxAttempts(); + static DisconnectPacket::eDisconnectReason GetJoinRejectReason(); + static bool FinalizeJoin(); + static bool SendToSmallId(BYTE targetSmallId, const void* data, int dataSize); static bool SendOnSocket(SOCKET sock, const void* data, int dataSize); @@ -112,6 +131,17 @@ private: static DWORD WINAPI SplitScreenRecvThreadProc(LPVOID param); static DWORD WINAPI AdvertiseThreadProc(LPVOID param); static DWORD WINAPI DiscoveryThreadProc(LPVOID param); + static DWORD WINAPI JoinThreadProc(LPVOID param); + + static HANDLE s_joinThread; + static volatile eJoinState s_joinState; + static volatile int s_joinAttempt; + static volatile bool s_joinCancel; + static char s_joinIP[256]; + static int s_joinPort; + static BYTE s_joinAssignedSmallId; + static DisconnectPacket::eDisconnectReason s_joinRejectReason; + static const int JOIN_MAX_ATTEMPTS = 4; static SOCKET s_listenSocket; static SOCKET s_hostConnectionSocket; diff --git a/Minecraft.World/BeaconTileEntity.cpp b/Minecraft.World/BeaconTileEntity.cpp index 633930f4..db35df42 100644 --- a/Minecraft.World/BeaconTileEntity.cpp +++ b/Minecraft.World/BeaconTileEntity.cpp @@ -2,6 +2,7 @@ #include "net.minecraft.network.packet.h" #include "net.minecraft.world.effect.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.animal.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" @@ -105,6 +106,8 @@ void BeaconTileEntity::applyEffects() void BeaconTileEntity::updateShape() { + beamSections.clear(); + beamSections.push_back(BeaconBeamSection(1.0f, 1.0f, 1.0f)); if (!level->canSeeSky(x, y + 1, z)) { @@ -115,6 +118,58 @@ void BeaconTileEntity::updateShape() { isActive = true; + int ly = y + 1; + bool first = true; + + int height = level->getHeight(); + while (ly < height) + { + int t = level->getTile(x, ly, z); + if (t == Tile::stained_glass_Id || t == Tile::stained_glass_pane_Id) + { + int data = level->getData(x, ly, z); + BeaconBeamSection& last = beamSections.back(); + + float nr = Sheep::COLOR[data][0]; + float ng = Sheep::COLOR[data][1]; + float nb = Sheep::COLOR[data][2]; + + if (first) + { + if (nr != last.color[0] || ng != last.color[1] || nb != last.color[2]) + { + beamSections.push_back(BeaconBeamSection(nr, ng, nb)); + } + else + { + last.increaseHeight(); + } + first = false; + } + else + { + float r = (last.color[0] + nr) * 0.5f; + float g = (last.color[1] + ng) * 0.5f; + float b = (last.color[2] + nb) * 0.5f; + + if (r != last.color[0] || g != last.color[1] || b != last.color[2]) + { + beamSections.push_back(BeaconBeamSection(r, g, b)); + } + else + { + last.increaseHeight(); + } + } + } + else + { + beamSections.back().increaseHeight(); + } + + ly++; + } + levels = 0; for (int step = 1; step <= 4; step++) { diff --git a/Minecraft.World/BeaconTileEntity.h b/Minecraft.World/BeaconTileEntity.h index eaf3847e..275edb5d 100644 --- a/Minecraft.World/BeaconTileEntity.h +++ b/Minecraft.World/BeaconTileEntity.h @@ -4,6 +4,32 @@ class BeaconTileEntity : public TileEntity, public Container { +public: + struct BeaconBeamSection + { + float color[3]; + int height; + + BeaconBeamSection(float r, float g, float b, int h = 1) { + color[0] = r; + color[1] = g; + color[2] = b; + height = h; + } + + void increaseHeight() { + height++; + } + + float *getColor() { + return color; + } + + int getHeight() { + return height; + } + }; + public: eINSTANCEOF GetType() { return eTYPE_BEACONTILEENTITY; } static TileEntity *create() { return new BeaconTileEntity(); } @@ -20,6 +46,8 @@ public: static void staticCtor(); + vector beamSections; + private: int64_t clientSideRenderTick; float clientSideRenderScale; diff --git a/Minecraft.World/ItemDispenseBehaviors.cpp b/Minecraft.World/ItemDispenseBehaviors.cpp index 8758dcfb..b43c599c 100644 --- a/Minecraft.World/ItemDispenseBehaviors.cpp +++ b/Minecraft.World/ItemDispenseBehaviors.cpp @@ -270,6 +270,15 @@ void BoatDispenseBehavior::playSound(BlockSource *source, eOUTCOME outcome) /* FilledBucket */ +FilledBucketDispenseBehavior::FilledBucketDispenseBehavior() : DefaultDispenseItemBehavior() +{ + defaultDispenseItemBehavior = new DefaultDispenseItemBehavior(); +} + +FilledBucketDispenseBehavior::~FilledBucketDispenseBehavior() +{ + delete defaultDispenseItemBehavior; +} shared_ptr FilledBucketDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) { @@ -288,8 +297,7 @@ shared_ptr FilledBucketDispenseBehavior::execute(BlockSource *sour return dispensed; } - outcome = LEFT_ITEM; - return dispensed; + return defaultDispenseItemBehavior->dispense(source, dispensed); } /* EmptyBucket */ @@ -335,7 +343,6 @@ shared_ptr EmptyBucketDispenseBehavior::execute(BlockSource *sourc return dispensed; } - /* Flint and Steel */ shared_ptr FlintAndSteelDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) diff --git a/Minecraft.World/ItemDispenseBehaviors.h b/Minecraft.World/ItemDispenseBehaviors.h index 4635c8a4..a2c43623 100644 --- a/Minecraft.World/ItemDispenseBehaviors.h +++ b/Minecraft.World/ItemDispenseBehaviors.h @@ -83,7 +83,11 @@ private: class FilledBucketDispenseBehavior : public DefaultDispenseItemBehavior { public: + FilledBucketDispenseBehavior(); + virtual ~FilledBucketDispenseBehavior(); virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); +private: + DefaultDispenseItemBehavior *defaultDispenseItemBehavior; }; class EmptyBucketDispenseBehavior : public DefaultDispenseItemBehavior diff --git a/Minecraft.World/LevelSettings.h b/Minecraft.World/LevelSettings.h index 73f588f6..dd50e02c 100644 --- a/Minecraft.World/LevelSettings.h +++ b/Minecraft.World/LevelSettings.h @@ -4,8 +4,6 @@ class LevelType; class Abilities; class LevelData; -#define _ADVENTURE_MODE_ENABLED - // 4J Stu - Was Java enum class class GameType {