mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-05-06 13:59:45 +00:00
374 lines
11 KiB
C++
374 lines
11 KiB
C++
#include "stdafx.h"
|
|
#include "../Common/Consoles_App.h"
|
|
#include "../User.h"
|
|
#include "../../Minecraft.Client/Minecraft.h"
|
|
#include "../../Minecraft.Client/MinecraftServer.h"
|
|
#include "../../Minecraft.Client/PlayerList.h"
|
|
#include "../../Minecraft.Client/ServerPlayer.h"
|
|
#include "../../Minecraft.World/Level.h"
|
|
#include "../../Minecraft.World/LevelSettings.h"
|
|
#include "../../Minecraft.World/BiomeSource.h"
|
|
#include "../../Minecraft.World/LevelType.h"
|
|
|
|
CConsoleMinecraftApp app;
|
|
|
|
CConsoleMinecraftApp::CConsoleMinecraftApp() : CMinecraftApp()
|
|
{
|
|
m_bShutdown = false;
|
|
}
|
|
|
|
void CConsoleMinecraftApp::SetRichPresenceContext(int iPad, int contextId)
|
|
{
|
|
ProfileManager.SetRichPresenceContextValue(iPad,CONTEXT_GAME_STATE,contextId);
|
|
}
|
|
|
|
void CConsoleMinecraftApp::StoreLaunchData()
|
|
{
|
|
}
|
|
void CConsoleMinecraftApp::ExitGame()
|
|
{
|
|
m_bShutdown = true;
|
|
}
|
|
void CConsoleMinecraftApp::FatalLoadError()
|
|
{
|
|
}
|
|
|
|
void CConsoleMinecraftApp::CaptureSaveThumbnail()
|
|
{
|
|
RenderManager.CaptureThumbnail(&m_ThumbnailBuffer);
|
|
|
|
// CaptureThumbnail in the render lib doesn't produce data on Win64,
|
|
// so grab the back buffer via D3D11 and encode a PNG manually
|
|
if (!m_ThumbnailBuffer.Allocated())
|
|
{
|
|
extern ID3D11Device* g_pd3dDevice;
|
|
extern ID3D11DeviceContext* g_pImmediateContext;
|
|
extern IDXGISwapChain* g_pSwapChain;
|
|
|
|
if (!g_pd3dDevice || !g_pImmediateContext || !g_pSwapChain)
|
|
return;
|
|
|
|
ID3D11Texture2D* pBackBuffer = nullptr;
|
|
HRESULT hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
|
|
if (FAILED(hr) || !pBackBuffer)
|
|
return;
|
|
|
|
D3D11_TEXTURE2D_DESC bbDesc;
|
|
pBackBuffer->GetDesc(&bbDesc);
|
|
|
|
// 64x64 to match other platforms
|
|
const int THUMB_W = 64;
|
|
const int THUMB_H = 64;
|
|
|
|
// staging texture for CPU readback
|
|
D3D11_TEXTURE2D_DESC stagingDesc = {};
|
|
stagingDesc.Width = bbDesc.Width;
|
|
stagingDesc.Height = bbDesc.Height;
|
|
stagingDesc.MipLevels = 1;
|
|
stagingDesc.ArraySize = 1;
|
|
stagingDesc.Format = bbDesc.Format;
|
|
stagingDesc.SampleDesc.Count = 1;
|
|
stagingDesc.Usage = D3D11_USAGE_STAGING;
|
|
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
|
|
|
ID3D11Texture2D* pStaging = nullptr;
|
|
|
|
// resolve MSAA if needed
|
|
if (bbDesc.SampleDesc.Count > 1)
|
|
{
|
|
D3D11_TEXTURE2D_DESC resolveDesc = bbDesc;
|
|
resolveDesc.SampleDesc.Count = 1;
|
|
resolveDesc.SampleDesc.Quality = 0;
|
|
resolveDesc.Usage = D3D11_USAGE_DEFAULT;
|
|
resolveDesc.BindFlags = 0;
|
|
resolveDesc.CPUAccessFlags = 0;
|
|
|
|
ID3D11Texture2D* pResolved = nullptr;
|
|
hr = g_pd3dDevice->CreateTexture2D(&resolveDesc, nullptr, &pResolved);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
g_pImmediateContext->ResolveSubresource(pResolved, 0, pBackBuffer, 0, bbDesc.Format);
|
|
hr = g_pd3dDevice->CreateTexture2D(&stagingDesc, nullptr, &pStaging);
|
|
if (SUCCEEDED(hr))
|
|
g_pImmediateContext->CopyResource(pStaging, pResolved);
|
|
pResolved->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = g_pd3dDevice->CreateTexture2D(&stagingDesc, nullptr, &pStaging);
|
|
if (SUCCEEDED(hr))
|
|
g_pImmediateContext->CopyResource(pStaging, pBackBuffer);
|
|
}
|
|
pBackBuffer->Release();
|
|
|
|
if (!pStaging)
|
|
return;
|
|
|
|
D3D11_MAPPED_SUBRESOURCE mapped;
|
|
hr = g_pImmediateContext->Map(pStaging, 0, D3D11_MAP_READ, 0, &mapped);
|
|
if (FAILED(hr))
|
|
{
|
|
pStaging->Release();
|
|
return;
|
|
}
|
|
|
|
// nearest-neighbor downsample to 64x64
|
|
BYTE* thumbPixels = new BYTE[THUMB_W * THUMB_H * 4];
|
|
for (int y = 0; y < THUMB_H; y++)
|
|
{
|
|
int srcY = y * (int)bbDesc.Height / THUMB_H;
|
|
BYTE* srcRow = (BYTE*)mapped.pData + srcY * mapped.RowPitch;
|
|
for (int x = 0; x < THUMB_W; x++)
|
|
{
|
|
int srcX = x * (int)bbDesc.Width / THUMB_W;
|
|
BYTE* src = srcRow + srcX * 4; // assumes BGRA/RGBA 32bpp
|
|
BYTE* dst = thumbPixels + (y * THUMB_W + x) * 4;
|
|
dst[0] = src[2]; // R (from B in BGRA)
|
|
dst[1] = src[1]; // G
|
|
dst[2] = src[0]; // B (from R in BGRA)
|
|
dst[3] = 255; // A
|
|
}
|
|
}
|
|
|
|
g_pImmediateContext->Unmap(pStaging, 0);
|
|
pStaging->Release();
|
|
|
|
// encode uncompressed PNG (IHDR + stored IDAT + IEND)
|
|
int rawRowSize = 1 + THUMB_W * 3; // filter byte + RGB
|
|
int rawSize = rawRowSize * THUMB_H;
|
|
|
|
// single stored deflate block (rawSize fits in 16 bits)
|
|
int deflateSize = 5 + rawSize; // 5-byte block header + data
|
|
if (rawSize > 65535)
|
|
{
|
|
// shouldn't happen at 64x64 but bail just in case
|
|
delete[] thumbPixels;
|
|
return;
|
|
}
|
|
|
|
int idatDataSize = 2 + deflateSize + 4; // zlib header(2) + deflate + adler32(4)
|
|
int pngSize = 8 + (12 + 13) + (12 + idatDataSize) + 12; // sig + IHDR + IDAT + IEND
|
|
|
|
BYTE* png = (BYTE*)malloc(pngSize);
|
|
if (!png)
|
|
{
|
|
delete[] thumbPixels;
|
|
return;
|
|
}
|
|
int pos = 0;
|
|
|
|
// PNG signature
|
|
static const BYTE sig[8] = {0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A};
|
|
memcpy(png + pos, sig, 8); pos += 8;
|
|
|
|
// big-endian write helper
|
|
auto writeBE32 = [&](int offset, unsigned int val) {
|
|
png[offset+0] = (val >> 24) & 0xFF;
|
|
png[offset+1] = (val >> 16) & 0xFF;
|
|
png[offset+2] = (val >> 8) & 0xFF;
|
|
png[offset+3] = (val ) & 0xFF;
|
|
};
|
|
|
|
// CRC32 for PNG chunks
|
|
static unsigned int crcTable[256];
|
|
static bool crcInit = false;
|
|
if (!crcInit)
|
|
{
|
|
for (int n = 0; n < 256; n++)
|
|
{
|
|
unsigned int c = n;
|
|
for (int k = 0; k < 8; k++)
|
|
c = (c & 1) ? 0xEDB88320 ^ (c >> 1) : c >> 1;
|
|
crcTable[n] = c;
|
|
}
|
|
crcInit = true;
|
|
}
|
|
auto crc32 = [&](BYTE* data, int len) -> unsigned int {
|
|
unsigned int c = 0xFFFFFFFF;
|
|
for (int i = 0; i < len; i++)
|
|
c = crcTable[(c ^ data[i]) & 0xFF] ^ (c >> 8);
|
|
return c ^ 0xFFFFFFFF;
|
|
};
|
|
|
|
// IHDR chunk
|
|
writeBE32(pos, 13); pos += 4; // length
|
|
int ihdrStart = pos;
|
|
png[pos++]='I'; png[pos++]='H'; png[pos++]='D'; png[pos++]='R';
|
|
writeBE32(pos, THUMB_W); pos += 4;
|
|
writeBE32(pos, THUMB_H); pos += 4;
|
|
png[pos++] = 8; // bit depth
|
|
png[pos++] = 2; // color type RGB
|
|
png[pos++] = 0; // compression
|
|
png[pos++] = 0; // filter
|
|
png[pos++] = 0; // interlace
|
|
writeBE32(pos, crc32(png + ihdrStart, 17)); pos += 4;
|
|
|
|
// IDAT chunk
|
|
writeBE32(pos, idatDataSize); pos += 4;
|
|
int idatStart = pos;
|
|
png[pos++]='I'; png[pos++]='D'; png[pos++]='A'; png[pos++]='T';
|
|
|
|
// zlib header (no compression)
|
|
png[pos++] = 0x78; png[pos++] = 0x01;
|
|
|
|
// Deflate stored block (final)
|
|
png[pos++] = 0x01; // final block, stored
|
|
png[pos++] = (rawSize ) & 0xFF;
|
|
png[pos++] = (rawSize >> 8) & 0xFF;
|
|
png[pos++] = ~rawSize & 0xFF;
|
|
png[pos++] = (~rawSize >> 8) & 0xFF;
|
|
|
|
// Raw PNG data (filter=None for each row, RGB)
|
|
unsigned int adlerA = 1, adlerB = 0;
|
|
for (int y = 0; y < THUMB_H; y++)
|
|
{
|
|
png[pos++] = 0; // filter byte = None
|
|
adlerA = (adlerA + 0) % 65521;
|
|
adlerB = (adlerB + adlerA) % 65521;
|
|
for (int x = 0; x < THUMB_W; x++)
|
|
{
|
|
BYTE* px = thumbPixels + (y * THUMB_W + x) * 4;
|
|
for (int c = 0; c < 3; c++)
|
|
{
|
|
png[pos++] = px[c];
|
|
adlerA = (adlerA + px[c]) % 65521;
|
|
adlerB = (adlerB + adlerA) % 65521;
|
|
}
|
|
}
|
|
}
|
|
// Adler32
|
|
unsigned int adler = (adlerB << 16) | adlerA;
|
|
writeBE32(pos, adler); pos += 4;
|
|
// IDAT CRC
|
|
writeBE32(pos, crc32(png + idatStart, 4 + idatDataSize)); pos += 4;
|
|
|
|
// IEND chunk
|
|
writeBE32(pos, 0); pos += 4;
|
|
int iendStart = pos;
|
|
png[pos++]='I'; png[pos++]='E'; png[pos++]='N'; png[pos++]='D';
|
|
writeBE32(pos, crc32(png + iendStart, 4)); pos += 4;
|
|
|
|
delete[] thumbPixels;
|
|
|
|
m_ThumbnailBuffer.m_type = ImageFileBuffer::e_typePNG;
|
|
m_ThumbnailBuffer.m_pBuffer = png;
|
|
m_ThumbnailBuffer.m_bufferSize = pos;
|
|
}
|
|
}
|
|
void CConsoleMinecraftApp::GetSaveThumbnail(PBYTE *pbData,DWORD *pdwSize)
|
|
{
|
|
// On a save caused by a create world, the thumbnail capture won't have happened
|
|
if (m_ThumbnailBuffer.Allocated())
|
|
{
|
|
if (pbData)
|
|
{
|
|
*pbData = new BYTE[m_ThumbnailBuffer.GetBufferSize()];
|
|
*pdwSize = m_ThumbnailBuffer.GetBufferSize();
|
|
memcpy(*pbData, m_ThumbnailBuffer.GetBufferPointer(), *pdwSize);
|
|
}
|
|
m_ThumbnailBuffer.Release();
|
|
}
|
|
else
|
|
{
|
|
// No capture happened (e.g. first save on world creation) leave thumbnail as nullptr
|
|
if (pbData) *pbData = nullptr;
|
|
if (pdwSize) *pdwSize = 0;
|
|
}
|
|
}
|
|
void CConsoleMinecraftApp::ReleaseSaveThumbnail()
|
|
{
|
|
}
|
|
|
|
void CConsoleMinecraftApp::GetScreenshot(int iPad,PBYTE *pbData,DWORD *pdwSize)
|
|
{
|
|
}
|
|
|
|
void CConsoleMinecraftApp::TemporaryCreateGameStart()
|
|
{
|
|
////////////////////////////////////////////////////////////////////////////////////////////// From CScene_Main::OnInit
|
|
|
|
app.setLevelGenerationOptions(nullptr);
|
|
|
|
// From CScene_Main::RunPlayGame
|
|
Minecraft *pMinecraft=Minecraft::GetInstance();
|
|
app.ReleaseSaveThumbnail();
|
|
ProfileManager.SetLockedProfile(0);
|
|
extern wchar_t g_Win64UsernameW[17];
|
|
pMinecraft->user->name = g_Win64UsernameW;
|
|
app.ApplyGameSettingsChanged(0);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////// From CScene_MultiGameJoinLoad::OnInit
|
|
MinecraftServer::resetFlags();
|
|
|
|
// From CScene_MultiGameJoinLoad::OnNotifyPressEx
|
|
app.SetTutorialMode( false );
|
|
app.SetCorruptSaveDeleted(false);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////// From CScene_MultiGameCreate::CreateGame
|
|
|
|
app.ClearTerrainFeaturePosition();
|
|
wstring wWorldName = L"TestWorld";
|
|
|
|
StorageManager.ResetSaveData();
|
|
StorageManager.SetSaveTitle(wWorldName.c_str());
|
|
|
|
bool isFlat = false;
|
|
int64_t seedValue = 0; // BiomeSource::findSeed(isFlat?LevelType::lvl_flat:LevelType::lvl_normal); // 4J - was (new Random())->nextLong() - now trying to actually find a seed to suit our requirements
|
|
|
|
NetworkGameInitData *param = new NetworkGameInitData();
|
|
param->seed = seedValue;
|
|
param->saveData = nullptr;
|
|
|
|
app.SetGameHostOption(eGameHostOption_Difficulty,0);
|
|
app.SetGameHostOption(eGameHostOption_FriendsOfFriends,0);
|
|
app.SetGameHostOption(eGameHostOption_Gamertags,1);
|
|
app.SetGameHostOption(eGameHostOption_BedrockFog,1);
|
|
|
|
app.SetGameHostOption(eGameHostOption_GameType,GameType::CREATIVE->getId() ); // LevelSettings::GAMETYPE_SURVIVAL
|
|
app.SetGameHostOption(eGameHostOption_LevelType, 0 );
|
|
app.SetGameHostOption(eGameHostOption_Structures, 1 );
|
|
app.SetGameHostOption(eGameHostOption_BonusChest, 0 );
|
|
|
|
app.SetGameHostOption(eGameHostOption_PvP, 1);
|
|
app.SetGameHostOption(eGameHostOption_TrustPlayers, 1 );
|
|
app.SetGameHostOption(eGameHostOption_FireSpreads, 1 );
|
|
app.SetGameHostOption(eGameHostOption_TNT, 1 );
|
|
app.SetGameHostOption(eGameHostOption_HostCanFly, 1);
|
|
app.SetGameHostOption(eGameHostOption_HostCanChangeHunger, 1);
|
|
app.SetGameHostOption(eGameHostOption_HostCanBeInvisible, 1 );
|
|
|
|
param->settings = app.GetGameHostOption( eGameHostOption_All );
|
|
|
|
g_NetworkManager.FakeLocalPlayerJoined();
|
|
|
|
LoadingInputParams *loadingParams = new LoadingInputParams();
|
|
loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc;
|
|
loadingParams->lpParam = static_cast<LPVOID>(param);
|
|
|
|
// Reset the autosave time
|
|
app.SetAutosaveTimerTime();
|
|
|
|
C4JThread* thread = new C4JThread(loadingParams->func, loadingParams->lpParam, "RunNetworkGame");
|
|
thread->Run();
|
|
}
|
|
|
|
int CConsoleMinecraftApp::GetLocalTMSFileIndex(WCHAR *wchTMSFile,bool bFilenameIncludesExtension,eFileExtensionType eEXT)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int CConsoleMinecraftApp::LoadLocalTMSFile(WCHAR *wchTMSFile)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int CConsoleMinecraftApp::LoadLocalTMSFile(WCHAR *wchTMSFile, eFileExtensionType eExt)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
void CConsoleMinecraftApp::FreeLocalTMSFiles(eTMSFileType eType)
|
|
{
|
|
}
|