mirror of
https://github.com/neoStudiosLCE/neoLegacy.git
synced 2026-06-09 02:32:56 +00:00
feat: make F2 screenshot work in any context
Move screenshot capture from Minecraft::tick() (which requires an active player) to the Windows64 main loop alongside other global key handlers (F1/F3/F11). F2 now works from the main menu, pause menu, settings, inventory, crafting, and all other screens. Chat message still shown when in-game.
This commit is contained in:
parent
f2434a8ea8
commit
967adf1e54
|
|
@ -1554,9 +1554,6 @@ void Minecraft::run_middle()
|
|||
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_DEBUG;
|
||||
}
|
||||
|
||||
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_SCREENSHOT))
|
||||
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_SCREENSHOT;
|
||||
|
||||
// In flying mode, Shift held = sneak/descend
|
||||
if(g_KBMInput.IsKBMActive() && g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_SNEAK))
|
||||
{
|
||||
|
|
@ -3745,80 +3742,6 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
|
|||
//options->thirdPersonView = !options->thirdPersonView;
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
if(player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_SCREENSHOT))
|
||||
{
|
||||
extern ID3D11Device* g_pd3dDevice;
|
||||
extern ID3D11DeviceContext* g_pImmediateContext;
|
||||
extern IDXGISwapChain* g_pSwapChain;
|
||||
|
||||
ID3D11Texture2D* pBackBuffer = nullptr;
|
||||
HRESULT hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
pBackBuffer->GetDesc(&desc);
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture2D* pStaging = nullptr;
|
||||
hr = g_pd3dDevice->CreateTexture2D(&desc, nullptr, &pStaging);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
g_pImmediateContext->CopyResource(pStaging, pBackBuffer);
|
||||
|
||||
// Build path next to the executable
|
||||
wchar_t exePath[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, exePath, MAX_PATH);
|
||||
wchar_t* lastSlash = wcsrchr(exePath, L'\\');
|
||||
if (lastSlash) *(lastSlash + 1) = L'\0';
|
||||
wstring screenshotDirPath = wstring(exePath) + L"screenshots";
|
||||
CreateDirectoryW(screenshotDirPath.c_str(), NULL);
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
wchar_t filename[128];
|
||||
swprintf_s(filename, L"%04d-%02d-%02d_%02d.%02d.%02d.png",
|
||||
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
||||
wstring screenshotPath = screenshotDirPath + L"\\" + filename;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mapped;
|
||||
hr = g_pImmediateContext->Map(pStaging, 0, D3D11_MAP_READ, 0, &mapped);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Copy rows and force alpha to fully opaque
|
||||
unsigned char* rgba = new unsigned char[desc.Width * desc.Height * 4];
|
||||
for (UINT row = 0; row < desc.Height; row++)
|
||||
{
|
||||
unsigned char* src = (unsigned char*)mapped.pData + row * mapped.RowPitch;
|
||||
unsigned char* dst = rgba + row * desc.Width * 4;
|
||||
memcpy(dst, src, desc.Width * 4);
|
||||
for (UINT x = 0; x < desc.Width; x++)
|
||||
dst[x * 4 + 3] = 0xFF;
|
||||
}
|
||||
g_pImmediateContext->Unmap(pStaging, 0);
|
||||
|
||||
// Save PNG via stb_image_write
|
||||
string narrowPath(screenshotPath.begin(), screenshotPath.end());
|
||||
int writeResult = stbi_write_png(narrowPath.c_str(), desc.Width, desc.Height, 4, rgba, desc.Width * 4);
|
||||
delete[] rgba;
|
||||
|
||||
// Send local-only chat message on success
|
||||
if (writeResult)
|
||||
{
|
||||
wstring msg = L"Saved screenshot to " + wstring(filename);
|
||||
gui->addMessage(msg, iPad);
|
||||
}
|
||||
}
|
||||
pStaging->Release();
|
||||
}
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_GAME_INFO)) && gameMode->isInputAllowed(MINECRAFT_ACTION_GAME_INFO))
|
||||
{
|
||||
ui.NavigateToScene(iPad,eUIScene_InGameInfoMenu);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "Network\WinsockNetLayer.h"
|
||||
#include "Windows64_Xuid.h"
|
||||
#include "Common/UI/UI.h"
|
||||
#include "stb_image_write.h"
|
||||
|
||||
// Forward-declare the internal Renderer class and its global instance from 4J_Render_PC_d.lib.
|
||||
// C4JRender (RenderManager) is a stateless wrapper — all D3D state lives in InternalRenderManager.
|
||||
|
|
@ -474,6 +475,77 @@ static bool g_bTearingSupported = false;
|
|||
static bool g_bPendingExclusiveFullscreen = false;
|
||||
static bool g_bPendingExclusiveFullscreenValue = false;
|
||||
|
||||
// Captures the D3D11 back buffer and saves it as a PNG screenshot.
|
||||
// Returns true on success and sets outFilename to the saved filename.
|
||||
static bool TakeScreenshot(wstring& outFilename)
|
||||
{
|
||||
if (!g_pSwapChain || !g_pd3dDevice || !g_pImmediateContext)
|
||||
return false;
|
||||
|
||||
ID3D11Texture2D* pBackBuffer = nullptr;
|
||||
HRESULT hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
pBackBuffer->GetDesc(&desc);
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
bool success = false;
|
||||
ID3D11Texture2D* pStaging = nullptr;
|
||||
hr = g_pd3dDevice->CreateTexture2D(&desc, nullptr, &pStaging);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
g_pImmediateContext->CopyResource(pStaging, pBackBuffer);
|
||||
|
||||
wchar_t exePath[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, exePath, MAX_PATH);
|
||||
wchar_t* lastSlash = wcsrchr(exePath, L'\\');
|
||||
if (lastSlash) *(lastSlash + 1) = L'\0';
|
||||
wstring screenshotDirPath = wstring(exePath) + L"screenshots";
|
||||
CreateDirectoryW(screenshotDirPath.c_str(), NULL);
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
wchar_t filename[128];
|
||||
swprintf_s(filename, L"%04d-%02d-%02d_%02d.%02d.%02d.png",
|
||||
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
||||
wstring screenshotPath = screenshotDirPath + L"\\" + filename;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mapped;
|
||||
hr = g_pImmediateContext->Map(pStaging, 0, D3D11_MAP_READ, 0, &mapped);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
unsigned char* rgba = new unsigned char[desc.Width * desc.Height * 4];
|
||||
for (UINT row = 0; row < desc.Height; row++)
|
||||
{
|
||||
unsigned char* src = (unsigned char*)mapped.pData + row * mapped.RowPitch;
|
||||
unsigned char* dst = rgba + row * desc.Width * 4;
|
||||
memcpy(dst, src, desc.Width * 4);
|
||||
for (UINT x = 0; x < desc.Width; x++)
|
||||
dst[x * 4 + 3] = 0xFF;
|
||||
}
|
||||
g_pImmediateContext->Unmap(pStaging, 0);
|
||||
|
||||
string narrowPath(screenshotPath.begin(), screenshotPath.end());
|
||||
int writeResult = stbi_write_png(narrowPath.c_str(), desc.Width, desc.Height, 4, rgba, desc.Width * 4);
|
||||
delete[] rgba;
|
||||
|
||||
if (writeResult)
|
||||
{
|
||||
outFilename = filename;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
pStaging->Release();
|
||||
}
|
||||
pBackBuffer->Release();
|
||||
return success;
|
||||
}
|
||||
|
||||
// COM proxy for IDXGISwapChain — delegates all calls to the real swap chain,
|
||||
// but overrides Present() to set SyncInterval=1 when VSync is enabled.
|
||||
// Avoids vtable patching, which conflicts with the D3D11 debug layer.
|
||||
|
|
@ -1857,6 +1929,20 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||
}
|
||||
}
|
||||
|
||||
// F2 takes a screenshot (works in any context)
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_SCREENSHOT))
|
||||
{
|
||||
wstring filename;
|
||||
if (TakeScreenshot(filename))
|
||||
{
|
||||
if (pMinecraft->gui && pMinecraft->player)
|
||||
{
|
||||
wstring msg = L"Saved screenshot to " + filename;
|
||||
pMinecraft->gui->addMessage(msg, ProfileManager.GetPrimaryPad());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// F1 toggles the HUD
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_TOGGLE_HUD))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -148,9 +148,10 @@ Dedicated server releases support Hardcore Mode!
|
|||
- Dedicated Server (`LCREServerWindows64.zip`): download from the Nightly-Dedicated-Server release on GitHub
|
||||
- Docker: pull `ghcr.io/itsrevela/minecraft-lce-dedicated-server:nightly` for server container
|
||||
|
||||
In-game screenshot functionality with F2!
|
||||
Screenshot functionality with F2!
|
||||
- pressing F2 will save a screenshot to a `screenshots` folder in your root game directory
|
||||
- a local-only chat message is shown to the player notifying the screenshot filename that was saved
|
||||
- works in any context: main menu, pause menu, settings, inventory, crafting, and during gameplay
|
||||
- a local-only chat message is shown to the player when in-game
|
||||
|
||||
Proper implementation of Hardcore Mode in LCRE!
|
||||
- difficulty slider included in create world menu
|
||||
|
|
|
|||
Loading…
Reference in a new issue