From b132fd5fabe1bd9b94975fbf43ed92177d3ce38f Mon Sep 17 00:00:00 2001 From: Merval Date: Fri, 8 May 2026 13:35:35 -0700 Subject: [PATCH 1/3] Improve Windows client input and session handling --- .gitignore | 3 +- Minecraft.Client/Common/Consoles_App.cpp | 109 +++++- .../Common/Network/GameNetworkManager.cpp | 3 + .../Network/PlatformNetworkManagerStub.cpp | 20 +- .../UI/IUIScene_AbstractContainerMenu.cpp | 25 ++ .../Common/UI/UIControl_Slider.cpp | 14 + Minecraft.Client/Common/UI/UIControl_Slider.h | 1 + Minecraft.Client/Common/UI/UIController.cpp | 8 +- .../UI/UIScene_AbstractContainerMenu.cpp | 8 + .../Common/UI/UIScene_CraftingMenu.cpp | 325 ++++++++++++++++++ .../Common/UI/UIScene_CraftingMenu.h | 11 +- Minecraft.Client/Common/UI/UIScene_HUD.cpp | 4 +- .../Common/UI/UIScene_SettingsAudioMenu.cpp | 1 + .../Common/UI/UIScene_SettingsControlMenu.cpp | 1 + .../UI/UIScene_SettingsGraphicsMenu.cpp | 1 + .../Common/UI/UIScene_SettingsOptionsMenu.cpp | 1 + .../Common/UI/UIScene_SettingsUIMenu.cpp | 30 ++ Minecraft.Client/Minecraft.Client.vcxproj | 30 +- .../Minecraft.Client.vcxproj.filters | 47 ++- Minecraft.Client/Minecraft.cpp | 20 +- Minecraft.Client/PendingConnection.cpp | 14 +- .../Platform_Libs/Dev/Render/RendererCore.cpp | 57 ++- Minecraft.Client/ServerConnection.cpp | 5 +- .../Windows64/Network/WinsockNetLayer.cpp | 138 ++++---- .../Windows64/Network/WinsockNetLayer.h | 1 + Minecraft.Server | 2 +- Minecraft.World/Minecraft.World.vcxproj | 30 +- 27 files changed, 788 insertions(+), 121 deletions(-) diff --git a/.gitignore b/.gitignore index cd9fbc6..b254632 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ MinecraftConsoles.opensdf MinecraftConsoles.sdf server.properties +Agents.MD fix_include_case.ps1 @@ -299,4 +300,4 @@ Minecraft.Client/redist64/* # Required by Windows64 post-build copy step in Minecraft.Client.vcxproj !Minecraft.Client/Durango/Sound/ Minecraft.Client/Durango/Sound/* -!Minecraft.Client/Durango/Sound/Minecraft.msscmp \ No newline at end of file +!Minecraft.Client/Durango/Sound/Minecraft.msscmp diff --git a/Minecraft.Client/Common/Consoles_App.cpp b/Minecraft.Client/Common/Consoles_App.cpp index 0220201..50c2c20 100644 --- a/Minecraft.Client/Common/Consoles_App.cpp +++ b/Minecraft.Client/Common/Consoles_App.cpp @@ -78,6 +78,107 @@ unsigned int CMinecraftApp::m_uiLastSignInData = 0; const float CMinecraftApp::fSafeZoneX = 64.0f; // 5% of 1280 const float CMinecraftApp::fSafeZoneY = 36.0f; // 5% of 720 +#if defined(_WINDOWS64) && !defined(_FINAL_BUILD) +namespace +{ + FILE *g_clientLogFile = NULL; + CRITICAL_SECTION g_clientLogLock; + LONG g_clientLogInitState = 0; + + bool ClientLogHasContent(const char *buf) + { + for (const char *p = buf; *p; p++) + { + if (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' && *p != '=') + return true; + } + return false; + } + + void BuildClientLogFallbackPath(char *path, size_t pathSize) + { + path[0] = '\0'; + + char exePath[MAX_PATH]; + if (!GetModuleFileNameA(NULL, exePath, MAX_PATH)) + return; + + exePath[MAX_PATH - 1] = '\0'; + char *slash = strrchr(exePath, '\\'); + if (slash == NULL) + slash = strrchr(exePath, '/'); + if (slash == NULL) + return; + + slash[1] = '\0'; + _snprintf_s(path, pathSize, _TRUNCATE, "%sclient.log", exePath); + } + + void InitClientLog() + { + LONG state = InterlockedCompareExchange(&g_clientLogInitState, 1, 0); + if (state == 0) + { + InitializeCriticalSection(&g_clientLogLock); + + char logPath[MAX_PATH]; + _snprintf_s(logPath, MAX_PATH, _TRUNCATE, "client.log"); + fopen_s(&g_clientLogFile, logPath, "a"); + + if (g_clientLogFile == NULL) + { + BuildClientLogFallbackPath(logPath, MAX_PATH); + if (logPath[0] != '\0') + fopen_s(&g_clientLogFile, logPath, "a"); + } + + if (g_clientLogFile != NULL) + { + char msg[MAX_PATH + 64]; + _snprintf_s(msg, sizeof(msg), _TRUNCATE, "Client log: writing to %s\n", logPath); + OutputDebugStringA(msg); + } + else + { + OutputDebugStringA("Client log: failed to open client.log\n"); + } + + InterlockedExchange(&g_clientLogInitState, 2); + return; + } + + while (g_clientLogInitState == 1) + Sleep(0); + } + + void WriteClientLogLine(const char *buf) + { + if (buf == NULL || !ClientLogHasContent(buf)) + return; + + InitClientLog(); + if (g_clientLogFile == NULL) + return; + + char line[1024]; + strncpy_s(line, sizeof(line), buf, _TRUNCATE); + size_t len = strlen(line); + while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) + line[--len] = '\0'; + + time_t now = time(NULL); + struct tm t; + localtime_s(&t, &now); + + EnterCriticalSection(&g_clientLogLock); + fprintf(g_clientLogFile, "%04d-%02d-%02d %02d:%02d:%02d [INFO] %s\n", + t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, line); + fflush(g_clientLogFile); + LeaveCriticalSection(&g_clientLogLock); + } +} +#endif + int CMinecraftApp::s_iHTMLFontSizesA[eHTMLSize_COUNT] = { #ifdef _XBOX @@ -244,6 +345,9 @@ void CMinecraftApp::DebugPrintf(const char *szFormat, ...) vsnprintf(buf, sizeof(buf), szFormat, ap); va_end(ap); OutputDebugStringA(buf); +#ifdef _WINDOWS64 + WriteClientLogLine(buf); +#endif #ifdef WITH_SERVER_CODE bool hasContent = false; for (const char *p = buf; *p; p++) { @@ -313,6 +417,9 @@ void CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...) } #else OutputDebugStringA(buf); +#ifdef _WINDOWS64 + WriteClientLogLine(buf); +#endif #endif #ifndef _XBOX if(user == USER_UI) @@ -10360,4 +10467,4 @@ bool CMinecraftApp::HasReachedMainMenu() { return m_hasReachedMainMenu; } -#endif \ No newline at end of file +#endif diff --git a/Minecraft.Client/Common/Network/GameNetworkManager.cpp b/Minecraft.Client/Common/Network/GameNetworkManager.cpp index 717e6a5..6847ce6 100644 --- a/Minecraft.Client/Common/Network/GameNetworkManager.cpp +++ b/Minecraft.Client/Common/Network/GameNetworkManager.cpp @@ -1436,6 +1436,9 @@ void CGameNetworkManager::CreateSocket( INetworkPlayer *pNetworkPlayer, bool loc { socket = new Socket( pNetworkPlayer, g_NetworkManager.IsHost(), g_NetworkManager.IsHost() && localPlayer ); pNetworkPlayer->SetSocket( socket ); + app.DebugPrintf("CGameNetworkManager: Created socket for smallId=%d local=%d host=%d gameplay=%d\n", + pNetworkPlayer->GetSmallId(), localPlayer ? 1 : 0, g_NetworkManager.IsHost() ? 1 : 0, + g_NetworkManager.IsInGameplay() ? 1 : 0); // 4J Stu - May be other states we want to accept aswell // Add this user to the game server if the game is started already diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp index 9785cb9..1e8fc8a 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp @@ -296,11 +296,18 @@ void CPlatformNetworkManagerStub::DoWork() BYTE disconnectedSmallId; while (WinsockNetLayer::PopDisconnectedSmallId(&disconnectedSmallId)) { + app.DebugPrintf("PlatformNetworkManagerStub: Processing disconnect smallId=%d\n", disconnectedSmallId); if (disconnectedSmallId == 0) continue; - if (WinsockNetLayer::IsSmallIdConnected(disconnectedSmallId)) continue; + if (WinsockNetLayer::IsSmallIdConnected(disconnectedSmallId)) + { + app.DebugPrintf("PlatformNetworkManagerStub: smallId=%d is still connected, deferring cleanup\n", disconnectedSmallId); + continue; + } IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(disconnectedSmallId); if (qnetPlayer != NULL && qnetPlayer->m_smallId == disconnectedSmallId) { + app.DebugPrintf("PlatformNetworkManagerStub: Notifying leave for smallId=%d \"%ls\"\n", + disconnectedSmallId, qnetPlayer->GetGamertag()); NotifyPlayerLeaving(qnetPlayer); qnetPlayer->m_smallId = 0; qnetPlayer->m_isRemote = false; @@ -310,15 +317,25 @@ void CPlatformNetworkManagerStub::DoWork() WinsockNetLayer::PushFreeSmallId(disconnectedSmallId); if (IQNet::s_playerCount > 1) IQNet::s_playerCount--; + app.DebugPrintf("PlatformNetworkManagerStub: Cleaned up smallId=%d, playerCount=%d\n", + disconnectedSmallId, IQNet::s_playerCount); } } BYTE joinedSmallId; while (WinsockNetLayer::PopPendingJoinSmallId(&joinedSmallId)) { + app.DebugPrintf("PlatformNetworkManagerStub: Processing pending join smallId=%d\n", joinedSmallId); + if (!WinsockNetLayer::IsSmallIdConnected(joinedSmallId)) + { + app.DebugPrintf("PlatformNetworkManagerStub: Skipping stale pending join smallId=%d\n", joinedSmallId); + continue; + } IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(joinedSmallId); if (qnetPlayer != NULL && qnetPlayer->m_smallId == joinedSmallId) { + app.DebugPrintf("PlatformNetworkManagerStub: Notifying join for smallId=%d \"%ls\"\n", + joinedSmallId, qnetPlayer->GetGamertag()); NotifyPlayerJoined(qnetPlayer); } } @@ -333,6 +350,7 @@ void CPlatformNetworkManagerStub::DoWork() Socket *sock = np->GetSocket(); if (sock != NULL && sock->isClosing()) { + app.DebugPrintf("PlatformNetworkManagerStub: Socket closing for smallId=%d\n", (int)i); WinsockNetLayer::CloseConnectionBySmallId((BYTE)i); } } diff --git a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp index c59c227..d985ea3 100644 --- a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp +++ b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp @@ -1315,6 +1315,25 @@ bool IUIScene_AbstractContainerMenu::handleKeyDown(int iPad, int iAction, bool b } } +#ifdef _WINDOWS64 + if(iPad == 0 && iAction == ACTION_MENU_X && !bRepeat && g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_INVENTORY)) + { + ui.SetTooltips(iPad, -1); + + if(m_bNavigateBack) + { + ui.NavigateBack(iPad); + } + else + { + ui.CloseUIScenes(iPad); + } + + bHandled = true; + return S_OK; + } +#endif + #ifdef _XBOX ui.AnimateKeyPress(iPad, iAction); #else @@ -1350,6 +1369,12 @@ bool IUIScene_AbstractContainerMenu::handleKeyDown(int iPad, int iAction, bool b // Standard left click buttonNum = 0; quickKeyHeld = FALSE; +#ifdef _WINDOWS64 + if(g_KBMInput.IsKeyDown(VK_SHIFT) || g_KBMInput.IsKeyDown(VK_LSHIFT) || g_KBMInput.IsKeyDown(VK_RSHIFT)) + { + quickKeyHeld = TRUE; + } +#endif ui.PlayUISFX(eSFX_Press); } break; diff --git a/Minecraft.Client/Common/UI/UIControl_Slider.cpp b/Minecraft.Client/Common/UI/UIControl_Slider.cpp index bd3b1ad..be906a3 100644 --- a/Minecraft.Client/Common/UI/UIControl_Slider.cpp +++ b/Minecraft.Client/Common/UI/UIControl_Slider.cpp @@ -80,6 +80,20 @@ void UIControl_Slider::handleSliderMove(int newValue) } } +void UIControl_Slider::SetSliderValue(int newValue) +{ + if(newValue < m_min) newValue = m_min; + if(newValue > m_max) newValue = m_max; + + float fTouchPos = 0.0f; + if(m_max > m_min) + { + fTouchPos = (float)(newValue - m_min) / (float)(m_max - m_min); + } + + SetSliderTouchPos(fTouchPos); +} + void UIControl_Slider::SetSliderTouchPos(float fTouchPos) { IggyDataValue result; diff --git a/Minecraft.Client/Common/UI/UIControl_Slider.h b/Minecraft.Client/Common/UI/UIControl_Slider.h index 0b57c2f..a0d1f42 100644 --- a/Minecraft.Client/Common/UI/UIControl_Slider.h +++ b/Minecraft.Client/Common/UI/UIControl_Slider.h @@ -24,6 +24,7 @@ public: void init(const wstring &label, int id, int min, int max, int current); void handleSliderMove(int newValue); + void SetSliderValue(int newValue); void SetSliderTouchPos(float fTouchPos); virtual void setAllPossibleLabels(int labelCount, wchar_t labels[][256]); diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index 9f7a41e..05afd4e 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -1048,7 +1048,7 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key) case ACTION_MENU_DOWN: vk = VK_DOWN; break; case ACTION_MENU_LEFT: vk = VK_LEFT; break; case ACTION_MENU_RIGHT: vk = VK_RIGHT; break; - case ACTION_MENU_X: vk = 'E'; break; + case ACTION_MENU_X: vk = KeyboardMouseInput::KEY_INVENTORY; break; case ACTION_MENU_Y: vk = VK_TAB; break; case ACTION_MENU_LEFT_SCROLL: vk = 'Q'; break; case ACTION_MENU_RIGHT_SCROLL: vk = 'R'; break; @@ -1069,6 +1069,12 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key) if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_LEFT)) { released = true; down = false; } if (!pressed && !released && g_KBMInput.IsMouseButtonDown(KeyboardMouseInput::MOUSE_LEFT)) { down = true; } } + else if (!keyboardTextEntryActive && key == ACTION_MENU_X && !g_KBMInput.IsMouseGrabbed()) + { + if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT)) { pressed = true; down = true; } + if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_RIGHT)) { released = true; down = false; } + if (!pressed && !released && g_KBMInput.IsMouseButtonDown(KeyboardMouseInput::MOUSE_RIGHT)) { down = true; } + } // scroll if (!g_KBMInput.IsMouseGrabbed()) diff --git a/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp b/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp index f50de39..5779fbc 100644 --- a/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp @@ -288,6 +288,14 @@ void UIScene_AbstractContainerMenu::handleInput(int iPad, int key, bool repeat, //app.DebugPrintf("UIScene_InventoryMenu handling input for pad %d, key %d, down- %s, pressed- %s, released- %s\n", iPad, key, down?"TRUE":"FALSE", pressed?"TRUE":"FALSE", released?"TRUE":"FALSE"); ui.AnimateKeyPress(m_iPad, key, repeat, pressed, released); +#ifdef _WINDOWS64 + if(iPad == 0 && key == ACTION_MENU_A && !repeat && !g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT)) + { + handled = handleKeyDown(m_iPad, ACTION_MENU_X, false); + return; + } +#endif + if(pressed) { handled = handleKeyDown(m_iPad, key, repeat); diff --git a/Minecraft.Client/Common/UI/UIScene_CraftingMenu.cpp b/Minecraft.Client/Common/UI/UIScene_CraftingMenu.cpp index dfe9451..5a2dd7b 100644 --- a/Minecraft.Client/Common/UI/UIScene_CraftingMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_CraftingMenu.cpp @@ -5,6 +5,16 @@ #include "../../../Minecraft.World/net.minecraft.world.inventory.h" #include "UIScene_CraftingMenu.h" +#ifdef _WINDOWS64 +#include "../../KeyboardMouseInput.h" +extern HWND g_hWnd; + +static S32 RoundWindowsCraftingMetric(F32 value) +{ + return (S32)(value + 0.5f); +} +#endif + #ifdef __PSVITA__ #define GAME_CRAFTING_TOUCHUPDATE_TIMER_ID 0 #define GAME_CRAFTING_TOUCHUPDATE_TIMER_TIME 100 @@ -544,6 +554,302 @@ bool UIScene_CraftingMenu::allowRepeat(int key) return true; } +#ifdef _WINDOWS64 +bool UIScene_CraftingMenu::getWindowsMouseScenePos(S32 &x, S32 &y) +{ + if(!g_hWnd) + { + return false; + } + + RECT rc; + GetClientRect(g_hWnd, &rc); + int winW = rc.right - rc.left; + int winH = rc.bottom - rc.top; + if(winW <= 0 || winH <= 0) + { + return false; + } + + x = (S32)((F32)g_KBMInput.GetMouseX() * (ui.getScreenWidth() / (F32)winW)); + y = (S32)((F32)g_KBMInput.GetMouseY() * (ui.getScreenHeight() / (F32)winH)); + return true; +} + +bool UIScene_CraftingMenu::isPointInControl(S32 x, S32 y, UIControl &control, S32 offsetX, S32 offsetY) +{ + S32 cx = offsetX + control.getXPos(); + S32 cy = offsetY + control.getYPos(); + return x >= cx && x <= cx + control.getWidth() && y >= cy && y <= cy + control.getHeight(); +} + +bool UIScene_CraftingMenu::isPointInWindowsGroupTab(S32 mouseX, S32 mouseY, int group) +{ + const S32 smallTabOffsets[7] = { 0, 70, 139, 209, 279, 348, 418 }; + F32 scale = 1.0f; + S32 tabX = m_controlMainPanel.getXPos(); + S32 tabY = m_controlMainPanel.getYPos(); + S32 tabWidth = 72; + S32 tabHeight = 56; + + if(m_loadedResolution == eSceneResolution_720 || m_loadedResolution == eSceneResolution_1080) + { + scale = ui.getScreenHeight() / 720.0f; + if(scale <= 0.0f) + { + scale = 1.0f; + } + + tabWidth = RoundWindowsCraftingMetric(107.0f * scale); + tabHeight = RoundWindowsCraftingMetric(85.0f * scale); + tabX = m_controlMainPanel.getXPos() - RoundWindowsCraftingMetric(3.0f * scale) + RoundWindowsCraftingMetric((98.0f * scale) * group); + tabY = m_controlMainPanel.getYPos() - RoundWindowsCraftingMetric(5.0f * scale); + } + else + { + scale = ui.getScreenHeight() == 480.0f ? 1.0f : ui.getScreenHeight() / 360.0f; + if(scale <= 0.0f) + { + scale = 1.0f; + } + + tabWidth = RoundWindowsCraftingMetric(72.0f * scale); + tabHeight = RoundWindowsCraftingMetric(56.0f * scale); + tabX = m_controlMainPanel.getXPos() + RoundWindowsCraftingMetric(smallTabOffsets[group] * scale); + tabY = m_controlMainPanel.getYPos() - RoundWindowsCraftingMetric(2.0f * scale); + } + + return mouseX >= tabX && mouseX <= tabX + tabWidth && mouseY >= tabY && mouseY <= tabY + tabHeight; +} + +bool UIScene_CraftingMenu::setGroupFromWindowsMouse(S32 mouseX, S32 mouseY, bool &handled) +{ + int maxGroup = m_iContainerType == RECIPE_TYPE_3x3 ? m_iMaxGroup3x3 : m_iMaxGroup2x2; + S32 panelX = m_controlMainPanel.getXPos(); + S32 panelY = m_controlMainPanel.getYPos(); + + for(int group = 0; group < maxGroup; ++group) + { + if(isPointInWindowsGroupTab(mouseX, mouseY, group)) + { + if(group != m_iGroupIndex) + { + showTabHighlight(m_iGroupIndex, false); + m_iGroupIndex = group; + showTabHighlight(m_iGroupIndex, true); + } + + m_iCurrentSlotHIndex = 0; + m_iCurrentSlotVIndex = 1; + CheckRecipesAvailable(); + iVSlotIndexA[0] = CanBeMadeA[m_iCurrentSlotHIndex].iCount - 1; + iVSlotIndexA[1] = 0; + iVSlotIndexA[2] = 1; + UpdateVerticalSlots(); + UpdateHighlight(); + setGroupText(GetGroupNameText(m_pGroupA[m_iGroupIndex])); + ui.PlayUISFX(eSFX_Focus); + handled = true; + return true; + } + } + + return false; +} + +bool UIScene_CraftingMenu::handleWindowsMouseRecipeSelect(bool &handled) +{ + if(!g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) + { + return false; + } + + S32 mouseX = 0; + S32 mouseY = 0; + if(!getWindowsMouseScenePos(mouseX, mouseY)) + { + return false; + } + + S32 panelX = m_controlMainPanel.getXPos(); + S32 panelY = m_controlMainPanel.getYPos(); + + if(setGroupFromWindowsMouse(mouseX, mouseY, handled)) + { + return true; + } + + if(isPointInControl(mouseX, mouseY, m_slotListCraftingHSlots, panelX, panelY)) + { + S32 slotSize = m_slotListCraftingHSlots.getHeight(); + S32 slotX = m_slotListCraftingHSlots.getXPos(); + + if(slotSize <= 0) + { + slotSize = m_slotListCraftingHSlots.getWidth() / m_iCraftablesMaxHSlotC; + } + + if(slotSize > 0) + { + int newSlot = (mouseX - panelX - slotX) / slotSize; + if(newSlot >= 0 && newSlot < m_iCraftablesMaxHSlotC && CanBeMadeA[newSlot].iCount > 0) + { + int oldSlot = m_iCurrentSlotHIndex; + m_iCurrentSlotHIndex = newSlot; + m_iCurrentSlotVIndex = 1; + iVSlotIndexA[0] = CanBeMadeA[m_iCurrentSlotHIndex].iCount - 1; + iVSlotIndexA[1] = 0; + iVSlotIndexA[2] = 1; + + UpdateVerticalSlots(); + UpdateHighlight(); + if(CanBeMadeA[oldSlot].iCount > 0) + { + setShowCraftHSlot(oldSlot, true); + } + ui.PlayUISFX(eSFX_Focus); + handled = true; + return true; + } + } + } + + UIControl *activeSelector = NULL; + int activeSlotCount = 0; + int activeSlotIndices[3] = { 0, 1, 2 }; + + if(m_bSplitscreen ||(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen())) + { + activeSelector = &m_control1Selector; + activeSlotCount = 1; + activeSlotIndices[0] = 1; + } + else if(CanBeMadeA[m_iCurrentSlotHIndex].iCount <= 2) + { + activeSelector = &m_control2Selector; + activeSlotCount = 2; + activeSlotIndices[0] = 1; + activeSlotIndices[1] = 0; + } + else + { + activeSelector = &m_control3Selector; + activeSlotCount = 3; + } + + if(CanBeMadeA[m_iCurrentSlotHIndex].iCount > 1) + { + S32 slotSize = m_slotListCraftingHSlots.getHeight(); + if(slotSize <= 0 && m_iCraftablesMaxHSlotC > 0) + { + slotSize = m_slotListCraftingHSlots.getWidth() / m_iCraftablesMaxHSlotC; + } + + if(slotSize > 0 && activeSlotCount > 0) + { + S32 hSlotX = panelX + m_slotListCraftingHSlots.getXPos() + (m_iCurrentSlotHIndex * slotSize); + S32 hSlotY = panelY + m_slotListCraftingHSlots.getYPos(); + S32 hitLeft = hSlotX - (slotSize / 3); + S32 hitRight = hSlotX + slotSize + (slotSize / 3); + S32 hitTop = hSlotY; + + if(activeSlotCount > 1) + { + hitTop -= slotSize; + } + + if(mouseX >= hitLeft && mouseX <= hitRight && mouseY >= hitTop && mouseY <= hitTop + (slotSize * activeSlotCount)) + { + int row = (mouseY - hitTop) / slotSize; + if(row < 0) + { + row = 0; + } + else if(row >= activeSlotCount) + { + row = activeSlotCount - 1; + } + + m_iCurrentSlotVIndex = activeSlotIndices[row]; + UpdateHighlight(); + ui.PlayUISFX(eSFX_Focus); + handled = true; + return true; + } + } + } + + UIControl *selectors[3] = { &m_control3Selector, &m_control2Selector, &m_control1Selector }; + UIControl_SlotList *slots[3] = { &m_slotListCrafting3VSlots[0], &m_slotListCrafting3VSlots[1], &m_slotListCrafting3VSlots[2] }; + int slotIndices[3] = { 0, 1, 2 }; + + if(m_bSplitscreen ||(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen())) + { + selectors[0] = &m_control1Selector; + slots[0] = &m_slotListCrafting1VSlots; + slotIndices[0] = 1; + selectors[1] = NULL; + selectors[2] = NULL; + } + else if(CanBeMadeA[m_iCurrentSlotHIndex].iCount <= 2) + { + selectors[0] = &m_control2Selector; + slots[0] = &m_slotListCrafting2VSlots[0]; + slotIndices[0] = 1; + selectors[1] = &m_control2Selector; + slots[1] = &m_slotListCrafting2VSlots[1]; + slotIndices[1] = 0; + selectors[2] = NULL; + } + + for(int i = 0; i < 3; ++i) + { + if(selectors[i] == NULL || slots[i] == NULL) + { + continue; + } + + S32 selectorX = panelX + selectors[i]->getXPos(); + S32 selectorY = panelY + selectors[i]->getYPos(); + if(isPointInControl(mouseX, mouseY, *slots[i], selectorX, selectorY)) + { + m_iCurrentSlotVIndex = slotIndices[i]; + UpdateHighlight(); + ui.PlayUISFX(eSFX_Focus); + handled = true; + return true; + } + } + + if(activeSelector != NULL && activeSlotCount > 0 && isPointInControl(mouseX, mouseY, *activeSelector, panelX, panelY)) + { + S32 selectorTop = panelY + activeSelector->getYPos(); + S32 selectorHeight = activeSelector->getHeight(); + int row = 0; + if(selectorHeight > 0) + { + row = ((mouseY - selectorTop) * activeSlotCount) / selectorHeight; + } + if(row < 0) + { + row = 0; + } + else if(row >= activeSlotCount) + { + row = activeSlotCount - 1; + } + + m_iCurrentSlotVIndex = activeSlotIndices[row]; + UpdateHighlight(); + ui.PlayUISFX(eSFX_Focus); + handled = true; + return true; + } + + return false; +} +#endif + void UIScene_CraftingMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) { //app.DebugPrintf("UIScene_InventoryMenu handling input for pad %d, key %d, down- %s, pressed- %s, released- %s\n", iPad, key, down?"TRUE":"FALSE", pressed?"TRUE":"FALSE", released?"TRUE":"FALSE"); @@ -553,11 +859,30 @@ void UIScene_CraftingMenu::handleInput(int iPad, int key, bool repeat, bool pres { case ACTION_MENU_OTHER_STICK_UP: case ACTION_MENU_OTHER_STICK_DOWN: +#ifdef _WINDOWS64 + if(iPad == 0 && g_KBMInput.IsKBMActive() && !g_KBMInput.IsMouseGrabbed() && pressed) + { + handled = handleKeyDown(m_iPad, key == ACTION_MENU_OTHER_STICK_UP ? ACTION_MENU_UP : ACTION_MENU_DOWN, repeat); + break; + } +#endif sendInputToMovie(key,repeat,pressed,released); break; default: if(pressed) { +#ifdef _WINDOWS64 + if(iPad == 0 && key == ACTION_MENU_RIGHT_SCROLL && !repeat && g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING_ALT)) + { + handled = handleKeyDown(m_iPad, ACTION_MENU_B, false); + break; + } + + if(iPad == 0 && key == ACTION_MENU_A && handleWindowsMouseRecipeSelect(handled)) + { + break; + } +#endif handled = handleKeyDown(m_iPad, key, repeat); } break; diff --git a/Minecraft.Client/Common/UI/UIScene_CraftingMenu.h b/Minecraft.Client/Common/UI/UIScene_CraftingMenu.h index 44a39d6..a52b41f 100644 --- a/Minecraft.Client/Common/UI/UIScene_CraftingMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_CraftingMenu.h @@ -86,7 +86,6 @@ protected: IggyName m_funcMoveSelector, m_funcSelectVerticalItem, m_funcSetActiveTab; IggyName m_funcShowPanelDisplay, m_funcShowIngredientSlot; -#ifdef __PSVITA__ enum ETouchInput { ETouchInput_TouchPanel_0, @@ -100,6 +99,8 @@ protected: ETouchInput_Count, }; + +#ifdef __PSVITA__ UIControl_Touch m_TouchInput[ETouchInput_Count]; S32 m_iCraftingSlotTouchStartY; #endif @@ -177,6 +178,14 @@ protected: virtual bool allowRepeat(int key); void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); +#ifdef _WINDOWS64 + bool getWindowsMouseScenePos(S32 &x, S32 &y); + bool isPointInControl(S32 x, S32 y, UIControl &control, S32 offsetX = 0, S32 offsetY = 0); + bool handleWindowsMouseRecipeSelect(bool &handled); + bool setGroupFromWindowsMouse(S32 mouseX, S32 mouseY, bool &handled); + bool isPointInWindowsGroupTab(S32 mouseX, S32 mouseY, int group); +#endif + protected: virtual int getPad(); virtual void hideAllHSlots(); diff --git a/Minecraft.Client/Common/UI/UIScene_HUD.cpp b/Minecraft.Client/Common/UI/UIScene_HUD.cpp index 09cdf8a..4a4fa7d 100644 --- a/Minecraft.Client/Common/UI/UIScene_HUD.cpp +++ b/Minecraft.Client/Common/UI/UIScene_HUD.cpp @@ -18,7 +18,7 @@ UIScene_HUD::UIScene_HUD(int iPad, void *initData, UILayer *parentLayer) : UISce initialiseMovie(); m_lastActiveSlot = 0; - m_lastScale = 1; + m_lastScale = -1; m_bToolTipsVisible = true; m_lastExpProgress = 0.0f; m_lastExpLevel = 0; @@ -230,7 +230,7 @@ void UIScene_HUD::customDraw(IggyCustomDrawCallbackRegion *region) void UIScene_HUD::handleReload() { m_lastActiveSlot = 0; - m_lastScale = 1; + m_lastScale = -1; m_bToolTipsVisible = true; m_lastExpProgress = 0.0f; m_lastExpLevel = 0; diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsAudioMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SettingsAudioMenu.cpp index 6d892d7..70f0a72 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsAudioMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SettingsAudioMenu.cpp @@ -72,6 +72,7 @@ void UIScene_SettingsAudioMenu::handleInput(int iPad, int key, bool repeat, bool case ACTION_MENU_CANCEL: if(pressed) { + app.CheckGameSettingsChanged(true,m_iPad); navigateBack(); } break; diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsControlMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SettingsControlMenu.cpp index d5447f7..b6a0c35 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsControlMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SettingsControlMenu.cpp @@ -71,6 +71,7 @@ void UIScene_SettingsControlMenu::handleInput(int iPad, int key, bool repeat, bo case ACTION_MENU_CANCEL: if(pressed) { + app.CheckGameSettingsChanged(true,m_iPad); navigateBack(); handled = true; } diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp index 0ee21be..00a9426 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp @@ -130,6 +130,7 @@ void UIScene_SettingsGraphicsMenu::handleInput(int iPad, int key, bool repeat, b } } + app.CheckGameSettingsChanged(true,m_iPad); navigateBack(); handled = true; } diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsOptionsMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SettingsOptionsMenu.cpp index 72576de..1728079 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsOptionsMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SettingsOptionsMenu.cpp @@ -200,6 +200,7 @@ void UIScene_SettingsOptionsMenu::handleInput(int iPad, int key, bool repeat, bo // 4J-PB - don't action changes here or we might write to the profile on backing out here and then get a change in the settings all, and write again on backing out there //app.CheckGameSettingsChanged(true,pInputData->UserIndex); + app.CheckGameSettingsChanged(true,m_iPad); navigateBack(); } diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.cpp index 917012d..15e7c65 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.cpp @@ -110,6 +110,7 @@ void UIScene_SettingsUIMenu::handleInput(int iPad, int key, bool repeat, bool pr { // changed app.SetGameSettings(m_iPad,eGameSetting_SplitScreenVertical,m_checkboxSplitscreen.IsChecked()?1:0); + app.CheckGameSettingsChanged(true,m_iPad); // close the xui scenes, so we don't have the navigate backed to menu at the wrong place if(app.GetLocalPlayerCount()==2) @@ -123,6 +124,7 @@ void UIScene_SettingsUIMenu::handleInput(int iPad, int key, bool repeat, bool pr } else { + app.CheckGameSettingsChanged(true,m_iPad); navigateBack(); } handled = true; @@ -136,8 +138,34 @@ void UIScene_SettingsUIMenu::handleInput(int iPad, int key, bool repeat, bool pr break; case ACTION_MENU_UP: case ACTION_MENU_DOWN: + sendInputToMovie(key, repeat, pressed, released); + break; case ACTION_MENU_LEFT: case ACTION_MENU_RIGHT: + if(pressed && !repeat) + { + int direction = key == ACTION_MENU_RIGHT ? 1 : -1; + if(m_sliderUISize.hasFocus()) + { + int value = app.GetGameSettings(m_iPad,eGameSetting_UISize) + 1 + direction; + if(value < 1) value = 1; + if(value > 3) value = 3; + m_sliderUISize.SetSliderValue(value); + handleSliderMove(eControl_UISize, value); + handled = true; + break; + } + if(m_sliderUISizeSplitscreen.hasFocus()) + { + int value = app.GetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen) + 1 + direction; + if(value < 1) value = 1; + if(value > 3) value = 3; + m_sliderUISizeSplitscreen.SetSliderValue(value); + handleSliderMove(eControl_UISizeSplitscreen, value); + handled = true; + break; + } + } sendInputToMovie(key, repeat, pressed, released); break; } @@ -159,6 +187,7 @@ void UIScene_SettingsUIMenu::handleSliderMove(F64 sliderId, F64 currentValue) if(value != app.GetGameSettings(m_iPad,eGameSetting_UISize)+1) { app.SetGameSettings(m_iPad,eGameSetting_UISize,value-1); + app.CheckGameSettingsChanged(true,m_iPad); // Apply the changes to the selected text position ui.UpdateSelectedItemPos(m_iPad); } @@ -174,6 +203,7 @@ void UIScene_SettingsUIMenu::handleSliderMove(F64 sliderId, F64 currentValue) { // slider is 1 to 3 app.SetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen,value-1); + app.CheckGameSettingsChanged(true,m_iPad); // Apply the changes to the selected text position ui.UpdateSelectedItemPos(m_iPad); } diff --git a/Minecraft.Client/Minecraft.Client.vcxproj b/Minecraft.Client/Minecraft.Client.vcxproj index 54e3e23..28d92a4 100644 --- a/Minecraft.Client/Minecraft.Client.vcxproj +++ b/Minecraft.Client/Minecraft.Client.vcxproj @@ -233,34 +233,34 @@ Application MultiByte - v110 + v145 Application Unicode - v110 + v145 false Application MultiByte - v110 + v145 Application MultiByte - v110 + v145 Application Unicode - v110 + v145 true Application Unicode - v110 + v145 true @@ -336,49 +336,49 @@ Application MultiByte true - v110 + v145 Application MultiByte true - v110 + v145 Application MultiByte true - v110 + v145 Application MultiByte true - v110 + v145 Application Unicode true - v110 + v145 Application MultiByte true - v110 + v145 Application MultiByte true - v110 + v145 Application MultiByte true - v110 + v145 Application @@ -38423,4 +38423,4 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU - + \ No newline at end of file diff --git a/Minecraft.Client/Minecraft.Client.vcxproj.filters b/Minecraft.Client/Minecraft.Client.vcxproj.filters index 9f24100..a2d451c 100644 --- a/Minecraft.Client/Minecraft.Client.vcxproj.filters +++ b/Minecraft.Client/Minecraft.Client.vcxproj.filters @@ -3634,6 +3634,9 @@ Common\Source Files\UI\Scenes + + Header Files + @@ -5736,6 +5739,45 @@ Common\Source Files\UI\Scenes + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -6107,10 +6149,7 @@ PS3\SPUObjFiles\ContentPackage - - - - + \ No newline at end of file diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 69b4dcf..ed4908f 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -1621,8 +1621,24 @@ void Minecraft::run_middle() if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_INFO)) { +#ifdef _DEBUG_MENUS_ENABLED + if(i == ProfileManager.GetPrimaryPad()) + { + options->renderDebug = !options->renderDebug; + } +#else localplayers[i]->ullButtonsPressed|=1LL<ullButtonsPressed|=1LL<ullButtonsPressed|=1LL<renderDebug = !options->renderDebug; #ifdef _XBOX + options->renderDebug = !options->renderDebug; app.EnableDebugOverlay(options->renderDebug,iPad); #else // 4J Stu - The xbox uses a completely different way of navigating to this scene diff --git a/Minecraft.Client/PendingConnection.cpp b/Minecraft.Client/PendingConnection.cpp index ceea182..526d505 100644 --- a/Minecraft.Client/PendingConnection.cpp +++ b/Minecraft.Client/PendingConnection.cpp @@ -94,7 +94,8 @@ void PendingConnection::handlePreLogin(shared_ptr packet) return; } // printf("Server: handlePreLogin\n"); - app.DebugPrintf("PreLogin received from \"%ls\"\n", packet->loginKey.c_str()); + app.DebugPrintf("PreLogin received from \"%ls\" smallId=%d\n", + packet->loginKey.c_str(), connection && connection->getSocket() ? connection->getSocket()->getSmallId() : 0); name = packet->loginKey; // 4J Stu - Change from the login packet as we know better on client end during the pre-login packet sendPreLoginResponse(); } @@ -149,7 +150,8 @@ void PendingConnection::sendPreLoginResponse() void PendingConnection::handleLogin(shared_ptr packet) { - app.DebugPrintf("Login received from \"%ls\" (protocol %d)\n", name.c_str(), packet->clientVersion); + app.DebugPrintf("Login received from \"%ls\" (protocol %d) smallId=%d\n", + name.c_str(), packet->clientVersion, connection && connection->getSocket() ? connection->getSocket()->getSmallId() : 0); // printf("Server: handleLogin\n"); //name = packet->userName; if (packet->clientVersion != SharedConstants::NETWORK_PROTOCOL_VERSION) @@ -296,9 +298,15 @@ void PendingConnection::handleAcceptedLogin(shared_ptr packet) shared_ptr playerEntity = server->getPlayers()->getPlayerForLogin(this, name, playerXuid,packet->m_onlineXuid); if (playerEntity != NULL) { + app.DebugPrintf("PendingConnection: Placing \"%ls\" smallId=%d\n", + name.c_str(), connection && connection->getSocket() ? connection->getSocket()->getSmallId() : 0); server->getPlayers()->placeNewPlayer(connection, playerEntity, packet); connection = NULL; // We've moved responsibility for this over to the new PlayerConnection, NULL so we don't delete our reference to it here in our dtor } + else + { + app.DebugPrintf("PendingConnection: getPlayerForLogin returned NULL for \"%ls\"\n", name.c_str()); + } done = true; } @@ -348,4 +356,4 @@ wstring PendingConnection::getName() bool PendingConnection::isServerPacketListener() { return true; -} \ No newline at end of file +} diff --git a/Minecraft.Client/Platform_Libs/Dev/Render/RendererCore.cpp b/Minecraft.Client/Platform_Libs/Dev/Render/RendererCore.cpp index 5069422..c3e5289 100644 --- a/Minecraft.Client/Platform_Libs/Dev/Render/RendererCore.cpp +++ b/Minecraft.Client/Platform_Libs/Dev/Render/RendererCore.cpp @@ -621,16 +621,14 @@ void Renderer::Present() if (m_bShouldScreenGrabNextFrame) { PROFILER_SCOPE("Renderer::Present", "ScreenGrab", MP_MAGENTA) - - unsigned char *linearData = new unsigned char[kScreenGrabWidth * kScreenGrabHeight * 4]; ID3D11Texture2D *backBuffer = NULL; ID3D11Texture2D *stagingTexture = NULL; + D3D11_TEXTURE2D_DESC desc = {}; m_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)); if (backBuffer) { - D3D11_TEXTURE2D_DESC desc = {}; backBuffer->GetDesc(&desc); desc.Usage = D3D11_USAGE_STAGING; desc.BindFlags = 0; @@ -639,6 +637,11 @@ void Renderer::Present() m_pDevice->CreateTexture2D(&desc, NULL, &stagingTexture); } + const UINT screenGrabWidth = desc.Width ? desc.Width : kScreenGrabWidth; + const UINT screenGrabHeight = desc.Height ? desc.Height : kScreenGrabHeight; + unsigned char *linearData = new unsigned char[screenGrabWidth * screenGrabHeight * 4]; + memset(linearData, 0, screenGrabWidth * screenGrabHeight * 4); + if (stagingTexture && backBuffer) { PROFILER_SCOPE("Renderer::Present", "CopyResource", MP_MAGENTA) @@ -649,14 +652,29 @@ void Renderer::Present() { const unsigned char *src = reinterpret_cast(mapped.pData); - for (UINT y = 0; y < kScreenGrabHeight; ++y) + for (UINT y = 0; y < screenGrabHeight; ++y) { - unsigned char *dstRow = linearData + y * kScreenGrabWidth * 4; + unsigned char *dstRow = linearData + y * screenGrabWidth * 4; const unsigned char *srcRow = src + y * mapped.RowPitch; - memcpy(dstRow, srcRow, kScreenGrabWidth * 4); + if (desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) + { + for (UINT x = 0; x < screenGrabWidth; ++x) + { + const unsigned char *srcPixel = srcRow + x * 4; + unsigned char *dstPixel = dstRow + x * 4; + dstPixel[0] = srcPixel[2]; + dstPixel[1] = srcPixel[1]; + dstPixel[2] = srcPixel[0]; + dstPixel[3] = 0xFF; + } + } + else + { + memcpy(dstRow, srcRow, screenGrabWidth * 4); - for (UINT x = 0; x < kScreenGrabWidth; ++x) - dstRow[x * 4 + 3] = 0xFF; + for (UINT x = 0; x < screenGrabWidth; ++x) + dstRow[x * 4 + 3] = 0xFF; + } } m_pDeviceContext->Unmap(stagingTexture, 0); @@ -664,12 +682,27 @@ void Renderer::Present() } static int count = 0; - char fileName[304]; - sprintf_s(fileName, "d:\\screen%d.png", count++); + CreateDirectoryA("screenshots", NULL); + + SYSTEMTIME now; + GetLocalTime(&now); + + char fileName[MAX_PATH]; + sprintf_s( + fileName, + "screenshots\\screenshot_%04d%02d%02d_%02d%02d%02d_%03d_%03d.png", + now.wYear, + now.wMonth, + now.wDay, + now.wHour, + now.wMinute, + now.wSecond, + now.wMilliseconds, + count++); D3DXIMAGE_INFO info; - info.Width = kScreenGrabWidth; - info.Height = kScreenGrabHeight; + info.Width = screenGrabWidth; + info.Height = screenGrabHeight; SaveTextureData(fileName, &info, reinterpret_cast(linearData)); delete[] linearData; diff --git a/Minecraft.Client/ServerConnection.cpp b/Minecraft.Client/ServerConnection.cpp index 4a23e23..c095294 100644 --- a/Minecraft.Client/ServerConnection.cpp +++ b/Minecraft.Client/ServerConnection.cpp @@ -29,12 +29,15 @@ ServerConnection::~ServerConnection() // 4J - added to handle incoming connections, to replace thread that original used to have void ServerConnection::NewIncomingSocket(Socket *socket) { + app.DebugPrintf("ServerConnection: New incoming socket smallId=%d\n", socket ? socket->getSmallId() : 0); shared_ptr unconnectedClient = shared_ptr(new PendingConnection(server, socket, L"Connection #" + _toString(connectionCounter++))); handleConnection(unconnectedClient); } void ServerConnection::addPlayerConnection(shared_ptr uc) { + if (uc != NULL && uc->connection != NULL && uc->connection->getSocket() != NULL) + app.DebugPrintf("ServerConnection: Added player connection smallId=%d\n", uc->connection->getSocket()->getSmallId()); players.push_back(uc); } @@ -200,4 +203,4 @@ void ServerConnection::handleServerSettingsChanged(shared_ptrsetShowOnMaps(pMinecraft->options->GetGamertagSetting()); // } // } -} \ No newline at end of file +} diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp index 55a4dea..4900d7c 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp @@ -639,6 +639,8 @@ void WinsockNetLayer::HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsig EnterCriticalSection(&s_earlyDataLock); s_earlyDataBuffers[fromSmallId].insert( s_earlyDataBuffers[fromSmallId].end(), data, data + dataSize); + app.DebugPrintf("Win64 LAN: Buffered %u early bytes for smallId=%d (total=%d)\n", + dataSize, fromSmallId, (int)s_earlyDataBuffers[fromSmallId].size()); LeaveCriticalSection(&s_earlyDataLock); } return; @@ -654,6 +656,8 @@ void WinsockNetLayer::HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsig EnterCriticalSection(&s_earlyDataLock); s_earlyDataBuffers[fromSmallId].insert( s_earlyDataBuffers[fromSmallId].end(), data, data + dataSize); + app.DebugPrintf("Win64 LAN: Buffered %u bytes waiting for socket smallId=%d (total=%d)\n", + dataSize, fromSmallId, (int)s_earlyDataBuffers[fromSmallId].size()); LeaveCriticalSection(&s_earlyDataLock); } } @@ -678,6 +682,8 @@ void WinsockNetLayer::FlushPendingData() ::Socket *pSocket = pPlayer->GetSocket(); if (pSocket == NULL) continue; + app.DebugPrintf("Win64 LAN: Flushing %d early bytes for smallId=%d\n", + (int)s_earlyDataBuffers[i].size(), (int)i); pSocket->pushDataToQueue(s_earlyDataBuffers[i].data(), (DWORD)s_earlyDataBuffers[i].size(), false); s_earlyDataBuffers[i].clear(); @@ -740,15 +746,6 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param) continue; } - BYTE assignBuf[1] = { assignedSmallId }; - int sent = send(clientSocket, (const char *)assignBuf, 1, 0); - if (sent != 1) - { - app.DebugPrintf("Failed to send small ID to client\n"); - closesocket(clientSocket); - continue; - } - u_long nonBlocking = 1; ioctlsocket(clientSocket, FIONBIO, &nonBlocking); @@ -785,7 +782,17 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param) EnterCriticalSection(&s_pendingJoinLock); s_pendingJoinSmallIds.push_back(assignedSmallId); + app.DebugPrintf("Win64 LAN: Queued pending join for smallId=%d\n", assignedSmallId); LeaveCriticalSection(&s_pendingJoinLock); + + BYTE assignBuf[1] = { assignedSmallId }; + int sent = send(clientSocket, (const char *)assignBuf, 1, 0); + if (sent != 1) + { + app.DebugPrintf("Win64 LAN: Failed to send small ID to client smallId=%d\n", assignedSmallId); + MarkConnectionDisconnected(assignedSmallId); + continue; + } } return 0; } @@ -805,7 +812,7 @@ bool WinsockNetLayer::ProcessRecvData(Win64RemoteConnection &conn) if (packetSize <= 0 || (unsigned int)packetSize > WIN64_NET_MAX_PACKET_SIZE) { app.DebugPrintf("Win64 LAN: Invalid packet size %d from smallId=%d\n", packetSize, conn.smallId); - conn.active = false; + MarkConnectionDisconnected(conn.smallId); return false; } @@ -821,7 +828,8 @@ bool WinsockNetLayer::ProcessRecvData(Win64RemoteConnection &conn) BYTE *newBuf = (BYTE *)realloc(conn.recvBuffer, newSize); if (newBuf == NULL) { - conn.active = false; + app.DebugPrintf("Win64 LAN: Failed to grow receive buffer for smallId=%d\n", conn.smallId); + MarkConnectionDisconnected(conn.smallId); return false; } conn.recvBuffer = newBuf; @@ -842,6 +850,47 @@ bool WinsockNetLayer::ProcessRecvData(Win64RemoteConnection &conn) return (remaining >= 4); } +void WinsockNetLayer::MarkConnectionDisconnected(BYTE smallId) +{ + bool shouldNotify = false; + + EnterCriticalSection(&s_connectionsLock); + if ((size_t)smallId < s_connections.size()) + { + Win64RemoteConnection &conn = s_connections[smallId]; + shouldNotify = conn.active; + conn.active = false; + + if (conn.tcpSocket != INVALID_SOCKET) + { + closesocket(conn.tcpSocket); + conn.tcpSocket = INVALID_SOCKET; + } + + EnterCriticalSection(&conn.sendBufLock); + conn.sendBufferUsed = 0; + LeaveCriticalSection(&conn.sendBufLock); + + conn.recvBufferUsed = 0; + conn.currentPacketSize = 0; + conn.readingHeader = true; + } + LeaveCriticalSection(&s_connectionsLock); + + EnterCriticalSection(&s_earlyDataLock); + if ((size_t)smallId < s_earlyDataBuffers.size()) + s_earlyDataBuffers[smallId].clear(); + LeaveCriticalSection(&s_earlyDataLock); + + if (shouldNotify) + { + EnterCriticalSection(&s_disconnectLock); + s_disconnectedSmallIds.push_back(smallId); + LeaveCriticalSection(&s_disconnectLock); + app.DebugPrintf("Win64 LAN: Queued disconnect for smallId=%d\n", smallId); + } +} + DWORD WINAPI WinsockNetLayer::IOThreadProc(LPVOID param) { std::vector pollFds; @@ -886,13 +935,7 @@ DWORD WINAPI WinsockNetLayer::IOThreadProc(LPVOID param) if (pollFds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) { - conn.active = false; - closesocket(conn.tcpSocket); - conn.tcpSocket = INVALID_SOCKET; - - EnterCriticalSection(&s_disconnectLock); - s_disconnectedSmallIds.push_back(smallId); - LeaveCriticalSection(&s_disconnectLock); + MarkConnectionDisconnected(smallId); continue; } @@ -907,12 +950,7 @@ DWORD WINAPI WinsockNetLayer::IOThreadProc(LPVOID param) BYTE *newBuf = (BYTE *)realloc(conn.recvBuffer, newSize); if (newBuf == NULL) { - conn.active = false; - closesocket(conn.tcpSocket); - conn.tcpSocket = INVALID_SOCKET; - EnterCriticalSection(&s_disconnectLock); - s_disconnectedSmallIds.push_back(smallId); - LeaveCriticalSection(&s_disconnectLock); + MarkConnectionDisconnected(smallId); break; } conn.recvBuffer = newBuf; @@ -929,12 +967,7 @@ DWORD WINAPI WinsockNetLayer::IOThreadProc(LPVOID param) } else if (bytesRead == 0) { - conn.active = false; - closesocket(conn.tcpSocket); - conn.tcpSocket = INVALID_SOCKET; - EnterCriticalSection(&s_disconnectLock); - s_disconnectedSmallIds.push_back(smallId); - LeaveCriticalSection(&s_disconnectLock); + MarkConnectionDisconnected(smallId); break; } else @@ -942,12 +975,7 @@ DWORD WINAPI WinsockNetLayer::IOThreadProc(LPVOID param) int err = WSAGetLastError(); if (err == WSAEWOULDBLOCK) break; - conn.active = false; - closesocket(conn.tcpSocket); - conn.tcpSocket = INVALID_SOCKET; - EnterCriticalSection(&s_disconnectLock); - s_disconnectedSmallIds.push_back(smallId); - LeaveCriticalSection(&s_disconnectLock); + MarkConnectionDisconnected(smallId); break; } } @@ -968,6 +996,8 @@ bool WinsockNetLayer::PopDisconnectedSmallId(BYTE *outSmallId) found = true; } LeaveCriticalSection(&s_disconnectLock); + if (found) + app.DebugPrintf("Win64 LAN: Popped disconnect for smallId=%d\n", *outSmallId); return found; } @@ -976,6 +1006,7 @@ void WinsockNetLayer::PushFreeSmallId(BYTE smallId) EnterCriticalSection(&s_freeSmallIdLock); s_freeSmallIds.push_back(smallId); LeaveCriticalSection(&s_freeSmallIdLock); + app.DebugPrintf("Win64 LAN: Returned smallId=%d to free list\n", smallId); } bool WinsockNetLayer::PopPendingJoinSmallId(BYTE *outSmallId) @@ -989,6 +1020,8 @@ bool WinsockNetLayer::PopPendingJoinSmallId(BYTE *outSmallId) found = true; } LeaveCriticalSection(&s_pendingJoinLock); + if (found) + app.DebugPrintf("Win64 LAN: Popped pending join for smallId=%d\n", *outSmallId); return found; } @@ -1000,27 +1033,8 @@ bool WinsockNetLayer::IsSmallIdConnected(BYTE smallId) void WinsockNetLayer::CloseConnectionBySmallId(BYTE smallId) { - EnterCriticalSection(&s_connectionsLock); - if ((size_t)smallId < s_connections.size() && s_connections[smallId].active && s_connections[smallId].tcpSocket != INVALID_SOCKET) - { - s_connections[smallId].active = false; - closesocket(s_connections[smallId].tcpSocket); - s_connections[smallId].tcpSocket = INVALID_SOCKET; - app.DebugPrintf("Win64 LAN: Force-closed TCP connection for smallId=%d\n", smallId); - } - LeaveCriticalSection(&s_connectionsLock); - - if ((size_t)smallId < s_connections.size()) - { - EnterCriticalSection(&s_connections[smallId].sendBufLock); - s_connections[smallId].sendBufferUsed = 0; - LeaveCriticalSection(&s_connections[smallId].sendBufLock); - } - - EnterCriticalSection(&s_earlyDataLock); - if ((size_t)smallId < s_earlyDataBuffers.size()) - s_earlyDataBuffers[smallId].clear(); - LeaveCriticalSection(&s_earlyDataLock); + MarkConnectionDisconnected(smallId); + app.DebugPrintf("Win64 LAN: Force-closed TCP connection for smallId=%d\n", smallId); } void WinsockNetLayer::FlushSendBuffers() @@ -1031,6 +1045,7 @@ void WinsockNetLayer::FlushSendBuffers() { if (!s_connections[i].active) continue; + bool disconnectAfterSendError = false; EnterCriticalSection(&s_connections[i].sendBufLock); if (s_connections[i].sendBufferUsed > 0 && s_connections[i].tcpSocket != INVALID_SOCKET) { @@ -1045,10 +1060,8 @@ void WinsockNetLayer::FlushSendBuffers() int err = WSAGetLastError(); if (err == WSAEWOULDBLOCK) break; - s_connections[i].active = false; - EnterCriticalSection(&s_disconnectLock); - s_disconnectedSmallIds.push_back((BYTE)i); - LeaveCriticalSection(&s_disconnectLock); + app.DebugPrintf("Win64 LAN: Send failed for smallId=%d err=%d\n", (int)i, err); + disconnectAfterSendError = true; break; } if (sent == 0) break; @@ -1061,6 +1074,9 @@ void WinsockNetLayer::FlushSendBuffers() s_connections[i].sendBufferUsed = remaining; } LeaveCriticalSection(&s_connections[i].sendBufLock); + + if (disconnectAfterSendError) + MarkConnectionDisconnected((BYTE)i); } } diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h index 70a4c31..9d6e4ba 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h @@ -139,6 +139,7 @@ private: static DWORD WINAPI DiscoveryThreadProc(LPVOID param); static DWORD WINAPI AsyncJoinThreadProc(LPVOID param); static bool ProcessRecvData(Win64RemoteConnection &conn); + static void MarkConnectionDisconnected(BYTE smallId); static SOCKET s_listenSocket; static SOCKET s_hostConnectionSocket; diff --git a/Minecraft.Server b/Minecraft.Server index aad5c68..b0bbb51 160000 --- a/Minecraft.Server +++ b/Minecraft.Server @@ -1 +1 @@ -Subproject commit aad5c68b7eac04586d13241ea18e9bf6f7170185 +Subproject commit b0bbb51e8078b20b5add5f006dab2819ec31671c diff --git a/Minecraft.World/Minecraft.World.vcxproj b/Minecraft.World/Minecraft.World.vcxproj index ffa0622..b3aa438 100644 --- a/Minecraft.World/Minecraft.World.vcxproj +++ b/Minecraft.World/Minecraft.World.vcxproj @@ -231,32 +231,32 @@ StaticLibrary MultiByte - v110 + v145 StaticLibrary Unicode - v110 + v145 StaticLibrary MultiByte - v110 + v145 StaticLibrary MultiByte - v110 + v145 StaticLibrary Unicode - v110 + v145 StaticLibrary Unicode - v110 + v145 StaticLibrary @@ -319,42 +319,42 @@ StaticLibrary MultiByte - v110 + v145 StaticLibrary MultiByte - v110 + v145 StaticLibrary MultiByte - v110 + v145 StaticLibrary MultiByte - v110 + v145 StaticLibrary Unicode - v110 + v145 StaticLibrary MultiByte - v110 + v145 StaticLibrary MultiByte - v110 + v145 StaticLibrary MultiByte - v110 + v145 StaticLibrary @@ -3964,4 +3964,4 @@ - + \ No newline at end of file From 565aaa55f6c4331149b7e9366ef5c860280c36c0 Mon Sep 17 00:00:00 2001 From: Merval Date: Fri, 8 May 2026 14:13:13 -0700 Subject: [PATCH 2/3] Fix Windows settings slider mouse input --- Minecraft.Client/Common/UI/UIControl.cpp | 4 +-- Minecraft.Client/Common/UI/UIControl.h | 4 ++- Minecraft.Client/Common/UI/UIController.cpp | 26 ++++++++++++++----- Minecraft.Client/Common/UI/UIController.h | 1 + .../UI/UIScene_SettingsGraphicsMenu.cpp | 15 ++++++++--- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/Minecraft.Client/Common/UI/UIControl.cpp b/Minecraft.Client/Common/UI/UIControl.cpp index a32485a..830dfa3 100644 --- a/Minecraft.Client/Common/UI/UIControl.cpp +++ b/Minecraft.Client/Common/UI/UIControl.cpp @@ -42,7 +42,7 @@ bool UIControl::setupControl(UIScene *scene, IggyValuePath *parent, const string return res; } -#ifdef __PSVITA__ +#if defined(__PSVITA__) || defined(_WINDOWS64) void UIControl::UpdateControl() { F64 fx, fy, fwidth, fheight; @@ -55,7 +55,7 @@ void UIControl::UpdateControl() m_width = (S32)Math::round(fwidth); m_height = (S32)Math::round(fheight); } -#endif // __PSVITA__ +#endif // __PSVITA__ || _WINDOWS64 void UIControl::ReInit() { diff --git a/Minecraft.Client/Common/UI/UIControl.h b/Minecraft.Client/Common/UI/UIControl.h index 3b4ef05..466c141 100644 --- a/Minecraft.Client/Common/UI/UIControl.h +++ b/Minecraft.Client/Common/UI/UIControl.h @@ -60,8 +60,10 @@ public: UIControl(); virtual bool setupControl(UIScene *scene, IggyValuePath *parent, const string &controlName); -#ifdef __PSVITA__ +#if defined(__PSVITA__) || defined(_WINDOWS64) void UpdateControl(); +#endif +#ifdef __PSVITA__ void setHidden(bool bHidden) {m_bHidden=bHidden;} bool getHidden(void) {return m_bHidden;} #endif diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index 05afd4e..42e883d 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -217,6 +217,7 @@ UIController::UIController() m_winUserIndex = 0; m_accumulatedTicks = 0; m_windowsMouseWheelForMenu = 0; + m_windowsMouseSliderActive = false; InitializeCriticalSection(&m_navigationLock); InitializeCriticalSection(&m_registeredCallbackScenesCS); @@ -693,6 +694,7 @@ void UIController::tickInput() #endif { #ifdef _WINDOWS64 + m_windowsMouseSliderActive = false; if (!g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive()) { UIScene *pScene = NULL; @@ -755,24 +757,36 @@ void UIController::tickInput() vector *controls = pScene->GetControls(); if (controls) { + S32 mainPanelOffsetX = 0; + S32 mainPanelOffsetY = 0; + UIControl *mainPanel = pScene->GetMainPanel(); + if (mainPanel) + { + mainPanel->UpdateControl(); + mainPanelOffsetX = mainPanel->getXPos(); + mainPanelOffsetY = mainPanel->getYPos(); + } + for (size_t i = 0; i < controls->size(); i++) { UIControl *ctrl = (*controls)[i]; if (ctrl && ctrl->getControlType() == UIControl::eSlider && ctrl->getVisible()) { - S32 cx = ctrl->getXPos(); - S32 cy = ctrl->getYPos(); - S32 cw = ctrl->getWidth(); + ctrl->UpdateControl(); + UIControl_Slider *pSlider = (UIControl_Slider *)ctrl; + S32 cx = ctrl->getXPos() + mainPanelOffsetX; + S32 cy = ctrl->getYPos() + mainPanelOffsetY; + S32 cw = pSlider->GetRealWidth(); S32 ch = ctrl->getHeight(); if (mouseX >= cx && mouseX <= cx + cw && mouseY >= cy && mouseY <= cy + ch) { - UIControl_Slider *pSlider = (UIControl_Slider *)ctrl; - float fNewSliderPos = (mouseX - (float)cx) / (float)pSlider->GetRealWidth(); + float fNewSliderPos = (mouseX - (float)cx) / (float)cw; if (fNewSliderPos < 0.0f) fNewSliderPos = 0.0f; if (fNewSliderPos > 1.0f) fNewSliderPos = 1.0f; pSlider->SetSliderTouchPos(fNewSliderPos); + m_windowsMouseSliderActive = true; break; } } @@ -1063,7 +1077,7 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key) if (!pressed && !released && g_KBMInput.IsKeyDown(vk)) { down = true; } } - if (!keyboardTextEntryActive && (key == ACTION_MENU_OK || key == ACTION_MENU_A) && !g_KBMInput.IsMouseGrabbed()) + if (!keyboardTextEntryActive && (key == ACTION_MENU_OK || key == ACTION_MENU_A) && !g_KBMInput.IsMouseGrabbed() && !m_windowsMouseSliderActive) { if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) { pressed = true; down = true; } if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_LEFT)) { released = true; down = false; } diff --git a/Minecraft.Client/Common/UI/UIController.h b/Minecraft.Client/Common/UI/UIController.h index 9bb130b..923cabe 100644 --- a/Minecraft.Client/Common/UI/UIController.h +++ b/Minecraft.Client/Common/UI/UIController.h @@ -137,6 +137,7 @@ private: bool m_navigateToHomeOnReload; int m_accumulatedTicks; int m_windowsMouseWheelForMenu; + bool m_windowsMouseSliderActive; D3D11_RECT m_customRenderingClearRect; diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp index 00a9426..e91036f 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp @@ -3,6 +3,13 @@ #include "UIScene_SettingsGraphicsMenu.h" #include "../../Minecraft.h" #include "../../GameRenderer.h" + +namespace +{ + const int FOV_MIN = 40; + const int FOV_MAX = 120; +} + UIScene_SettingsGraphicsMenu::UIScene_SettingsGraphicsMenu(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer) { // Setup all the Iggy references we need for this scene @@ -28,7 +35,7 @@ UIScene_SettingsGraphicsMenu::UIScene_SettingsGraphicsMenu(int iPad, void *initD m_sliderInterfaceOpacity.init(TempString,eControl_InterfaceOpacity,0,100,app.GetGameSettings(m_iPad,eGameSetting_InterfaceOpacity)); swprintf( (WCHAR *)TempString, 256, L"FOV: %d", (int)pMinecraft->gameRenderer->GetFovVal()); - m_sliderFov.init(TempString,eControl_FOV,40,120,(int)pMinecraft->gameRenderer->GetFovVal()); + m_sliderFov.init(TempString,eControl_FOV,0,FOV_MAX - FOV_MIN,(int)pMinecraft->gameRenderer->GetFovVal() - FOV_MIN); doHorizontalResizeCheck(); @@ -174,11 +181,11 @@ void UIScene_SettingsGraphicsMenu::handleSliderMove(F64 sliderId, F64 currentVal break; case eControl_FOV: { - int fovValue = (int)currentValue; - m_sliderFov.handleSliderMove(fovValue); + int fovValue = (int)currentValue + FOV_MIN; + m_sliderFov.handleSliderMove((int)currentValue); Minecraft *pMinecraft = Minecraft::GetInstance(); - pMinecraft->gameRenderer->SetFovVal((float)currentValue); + pMinecraft->gameRenderer->SetFovVal((float)fovValue); WCHAR TempString[256]; swprintf( (WCHAR *)TempString, 256, L"FOV: %d", fovValue); From c35d23fe46564c9fe68b7e5053e75be899356ff4 Mon Sep 17 00:00:00 2001 From: Merval Date: Fri, 8 May 2026 14:24:59 -0700 Subject: [PATCH 3/3] Restore Linux server submodule reference --- Minecraft.Server | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Minecraft.Server b/Minecraft.Server index b0bbb51..aad5c68 160000 --- a/Minecraft.Server +++ b/Minecraft.Server @@ -1 +1 @@ -Subproject commit b0bbb51e8078b20b5add5f006dab2819ec31671c +Subproject commit aad5c68b7eac04586d13241ea18e9bf6f7170185