Merge branch 'smartcmd:main' into forked

This commit is contained in:
IsraelProyects 2026-03-05 06:04:23 -07:00 committed by GitHub
commit 956fee22e6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 184 additions and 174 deletions

View file

@ -89,13 +89,59 @@ target_link_libraries(MinecraftClient PRIVATE
>
)
add_custom_command(TARGET MinecraftClient POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-DPROJECT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
-DOUTPUT_DIR="$<TARGET_FILE_DIR:MinecraftClient>"
-DCONFIGURATION=$<CONFIG>
-P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CopyAssets.cmake"
VERBATIM
)
if(WIN32)
message(STATUS "Starting redist copy...")
execute_process(
COMMAND robocopy.exe
"${CMAKE_CURRENT_SOURCE_DIR}/x64/Release"
"${CMAKE_CURRENT_BINARY_DIR}"
/S /MT /R:0 /W:0 /NP
)
message(STATUS "Starting asset copy...")
execute_process(
COMMAND robocopy.exe
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client"
"${CMAKE_CURRENT_BINARY_DIR}"
/S /MT /R:0 /W:0 /NP
/XF "*.cpp" "*.c" "*.h" "*.hpp" "*.asm"
"*.xml" "*.lang" "*.vcxproj" "*.vcxproj.*" "*.sln"
"*.docx" "*.xls"
"*.bat" "*.cmd" "*.ps1" "*.py"
"*Test*"
/XD "Durango*" "Orbis*" "PS*" "Xbox"
)
message(STATUS "Patching Windows64Media...")
execute_process(
COMMAND robocopy.exe
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/DurangoMedia"
"${CMAKE_CURRENT_BINARY_DIR}/Windows64Media"
/S /MT /R:0 /W:0 /NP
/XF "*.h" "*.xml" "*.lang" "*.bat"
)
elseif(UNIX)
message(STATUS "Starting redist copy...")
execute_process(
COMMAND rsync -av "${CMAKE_CURRENT_SOURCE_DIR}/x64/Release/" "${CMAKE_CURRENT_BINARY_DIR}/"
)
message(STATUS "Starting asset copy...")
execute_process(
COMMAND rsync -av
"--exclude=*.cpp" "--exclude=*.c" "--exclude=*.h" "--exclude=*.hpp" "--exclude=*.asm"
"--exclude=*.xml" "--exclude=*.lang" "--exclude=*.vcxproj" "--exclude=*.vcxproj.*" "--exclude=*.sln"
"--exclude=*.docx" "--exclude=*.xls"
"--exclude=*.bat" "--exclude=*.cmd" "--exclude=*.ps1" "--exclude=*.py"
"--exclude=*Test*"
"--exclude=Durango*" "--exclude=Orbis*" "--exclude=PS*" "--exclude=Xbox"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/" "${CMAKE_CURRENT_BINARY_DIR}/"
)
message(STATUS "Patching Windows64Media...")
execute_process(
COMMAND rsync -av
"--exclude=*.h" "--exclude=*.xml" "--exclude=*.lang" "--exclude=*.bat"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/DurangoMedia/" "${CMAKE_CURRENT_BINARY_DIR}/Windows64Media/"
)
else()
message(FATAL_ERROR "Redist and asset copying is only supported on Windows (Robocopy) and Unix systems (rsync).")
endif()
set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT MinecraftClient)

View file

@ -2694,6 +2694,10 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
int oldDimension = minecraft->localplayers[m_userIndex]->dimension;
started = false;
// Stop any streaming music (e.g. jukebox) when changing dimensions
// so it doesn't leak into the new dimension
level->playStreamingMusic(L"", 0, 0, 0);
// Remove client connection from this level
level->removeClientConnection(this, false);

View file

@ -387,8 +387,10 @@ vector<HtmlString> *IUIScene_BeaconMenu::GetSectionHoverText(ESceneSection eSect
desc = new vector<HtmlString>();
HtmlString string( app.GetString(MobEffect::effects[effectId]->getDescriptionId()), eHTMLColor_White );
desc->push_back( string );
if (effectId < MobEffect::e_MobEffectIcon_COUNT && MobEffect::effects[effectId]) {
HtmlString string( app.GetString(MobEffect::effects[effectId]->getDescriptionId()), eHTMLColor_White );
desc->push_back( string );
}
}
break;
}

View file

@ -6,35 +6,33 @@
// 4J - added
void CreeperModel::_init(float g)
{
int yo = 4;
head = new ModelPart(this, 0, 0);
head->addBox(-4, - 8, -4, 8, 8, 8, g); // Head
head->setPos(0, (float)(yo), 0);
head->setPos(0, 6, 0);
hair = new ModelPart(this, 32, 0);
hair->addBox(-4, -8, -4, 8, 8, 8, g + 0.5f); // Head
hair->setPos(0, (float)(yo), 0);
hair->setPos(0, 6, 0);
body = new ModelPart(this, 16, 16);
body->addBox(-4, 0, -2, 8, 12, 4, g); // Body
body->setPos(0, (float)(yo), 0);
body->setPos(0, 6, 0);
leg0 = new ModelPart(this, 0, 16);
leg0->addBox(-2, 0, -2, 4, 6, 4, g); // Leg0
leg0->setPos(-2, (float)(12 + yo), 4);
leg0->setPos(-2, 18, 4);
leg1 = new ModelPart(this, 0, 16);
leg1->addBox(-2, 0, -2, 4, 6, 4, g); // Leg1
leg1->setPos(2, (float)(12 + yo), 4);
leg1->setPos(2, 18, 4);
leg2 = new ModelPart(this, 0, 16);
leg2->addBox(-2, 0, -2, 4, 6, 4, g); // Leg2
leg2->setPos(-2, (float)(12 + yo), -4);
leg2->setPos(-2, 18, -4);
leg3 = new ModelPart(this, 0, 16);
leg3->addBox(-2, 0, -2, 4, 6, 4, g); // Leg3
leg3->setPos(2, (float)(12 + yo), -4);
leg3->setPos(2, 18, -4);
// 4J added - compile now to avoid random performance hit first time cubes are rendered
head->compile(1.0f/16.0f);

View file

@ -54,13 +54,13 @@ void EntityTracker::addEntity(shared_ptr<Entity> e)
else if (e->instanceof(eTYPE_THROWNEXPBOTTLE)) addEntity(e, 16 * 4, 10, true);
else if (e->instanceof(eTYPE_FIREWORKS_ROCKET)) addEntity(e, 16 * 4, 10, true);
else if (e->instanceof(eTYPE_ITEMENTITY)) addEntity(e, 16 * 4, 20, true);
else if (e->instanceof(eTYPE_MINECART)) addEntity(e, 16 * 5, 3, true);
else if (e->instanceof(eTYPE_BOAT)) addEntity(e, 16 * 5, 3, true);
else if (e->instanceof(eTYPE_SQUID)) addEntity(e, 16 * 4, 3, true);
else if (e->instanceof(eTYPE_WITHERBOSS)) addEntity(e, 16 * 5, 3, false);
else if (e->instanceof(eTYPE_BAT)) addEntity(e, 16 * 5, 3, false);
else if (dynamic_pointer_cast<Creature>(e)!=NULL) addEntity(e, 16 * 5, 3, true);
else if (e->instanceof(eTYPE_ENDERDRAGON)) addEntity(e, 16 * 10, 3, true);
else if (e->instanceof(eTYPE_MINECART)) addEntity(e, 16 * 5, 1, true);
else if (e->instanceof(eTYPE_BOAT)) addEntity(e, 16 * 5, 1, true);
else if (e->instanceof(eTYPE_SQUID)) addEntity(e, 16 * 4, 1, true);
else if (e->instanceof(eTYPE_WITHERBOSS)) addEntity(e, 16 * 5, 1, false);
else if (e->instanceof(eTYPE_BAT)) addEntity(e, 16 * 5, 1, false);
else if (dynamic_pointer_cast<Creature>(e)!=NULL) addEntity(e, 16 * 5, 1, true);
else if (e->instanceof(eTYPE_ENDERDRAGON)) addEntity(e, 16 * 10, 1, true);
else if (e->instanceof(eTYPE_PRIMEDTNT)) addEntity(e, 16 * 10, 10, true);
else if (e->instanceof(eTYPE_FALLINGTILE)) addEntity(e, 16 * 10, 20, true);
else if (e->instanceof(eTYPE_HANGING_ENTITY)) addEntity(e, 16 * 10, INT_MAX, false);
@ -245,4 +245,4 @@ shared_ptr<TrackedEntity> EntityTracker::getTracker(shared_ptr<Entity> e)
return it->second;
}
return nullptr;
}
}

View file

@ -548,7 +548,7 @@ void ItemInHandRenderer::render(float a)
glPushMatrix();
float d = 0.8f;
#if defined __ORBIS__ || defined __PS3__
#if defined __ORBIS__ || defined __PS3__ || defined _WINDOWS64
static const float swingPowFactor = 1.0f;
#else
static const float swingPowFactor = 4.0f; // 4J added, to slow the swing down when nearest the player for avoiding luminance flash issues

View file

@ -1485,7 +1485,7 @@ void Minecraft::run_middle()
}
// Utility keys always work regardless of KBM active state
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_PAUSE) && !ui.IsTutorialVisible(i))
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_PAUSE) && !ui.IsTutorialVisible(i) && !ui.GetMenuDisplayed(i))
{
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_PAUSEMENU;
app.DebugPrintf("PAUSE PRESSED (keyboard) - ipad = %d\n",i);
@ -1494,9 +1494,9 @@ void Minecraft::run_middle()
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_THIRD_PERSON))
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON;
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_INFO))
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_MENU))
{
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_GAME_INFO;
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_DEBUG;
}
// In flying mode, Shift held = sneak/descend

View file

@ -90,7 +90,6 @@ bool MultiPlayerGameMode::destroyBlock(int x, int y, int z, int face)
if (g_NetworkManager.IsHost())
{
level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, x, y, z, oldTile->id + (level->getData(x, y, z) << Tile::TILE_NUM_SHIFT));
return true;
}
#endif

View file

@ -973,6 +973,9 @@ void gdraw_D3D1X_(SetRendertargetSize)(S32 w, S32 h)
void gdraw_D3D1X_(SetTileOrigin)(ID3D1X(RenderTargetView) *main_rt, ID3D1X(DepthStencilView) *main_ds, ID3D1X(ShaderResourceView) *non_msaa_rt, S32 x, S32 y)
{
if (!gdraw) return; // AAR - saftey check because windows calls resize early
D3D1X_(RENDER_TARGET_VIEW_DESC) desc;
if (gdraw->frame_done) {

View file

@ -30,6 +30,7 @@ public:
static const int KEY_PAUSE = VK_ESCAPE;
static const int KEY_THIRD_PERSON = VK_F5;
static const int KEY_DEBUG_INFO = VK_F3;
static const int KEY_DEBUG_MENU = VK_F4;
void Init();
void Tick();

View file

@ -88,8 +88,7 @@ BOOL g_bWidescreen = TRUE;
int g_iScreenWidth = 1920;
int g_iScreenHeight = 1080;
UINT g_ScreenWidth = 1920;
UINT g_ScreenHeight = 1080;
float g_iAspectRatio = static_cast<float>(g_iScreenWidth) / g_iScreenHeight;
char g_Win64Username[17] = { 0 };
wchar_t g_Win64UsernameW[17] = { 0 };
@ -98,6 +97,14 @@ wchar_t g_Win64UsernameW[17] = { 0 };
static bool g_isFullscreen = false;
static WINDOWPLACEMENT g_wpPrev = { sizeof(g_wpPrev) };
//--------------------------------------------------------------------------------------
// Update the Aspect Ratio to support Any Aspect Ratio
//--------------------------------------------------------------------------------------
void UpdateAspectRatio(int width, int height)
{
g_iAspectRatio = static_cast<float>(width) / height;
}
struct Win64LaunchOptions
{
int screenMode;
@ -117,6 +124,50 @@ static void CopyWideArgToAnsi(LPCWSTR source, char* dest, size_t destSize)
dest[destSize - 1] = 0;
}
// ---------- Persistent options (options.txt next to exe) ----------
static void GetOptionsFilePath(char *out, size_t outSize)
{
GetModuleFileNameA(NULL, out, (DWORD)outSize);
char *p = strrchr(out, '\\');
if (p) *(p + 1) = '\0';
strncat_s(out, outSize, "options.txt", _TRUNCATE);
}
static void SaveFullscreenOption(bool fullscreen)
{
char path[MAX_PATH];
GetOptionsFilePath(path, sizeof(path));
FILE *f = nullptr;
if (fopen_s(&f, path, "w") == 0 && f)
{
fprintf(f, "fullscreen=%d\n", fullscreen ? 1 : 0);
fclose(f);
}
}
static bool LoadFullscreenOption()
{
char path[MAX_PATH];
GetOptionsFilePath(path, sizeof(path));
FILE *f = nullptr;
if (fopen_s(&f, path, "r") == 0 && f)
{
char line[256];
while (fgets(line, sizeof(line), f))
{
int val = 0;
if (sscanf_s(line, "fullscreen=%d", &val) == 1)
{
fclose(f);
return val != 0;
}
}
fclose(f);
}
return false;
}
// ------------------------------------------------------------------
static void ApplyScreenMode(int screenMode)
{
switch (screenMode)
@ -468,6 +519,7 @@ ID3D11Texture2D* g_pDepthStencilBuffer = NULL;
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
// WM_SIZE - handle resizing logic to support Any Aspect Ratio
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
@ -585,6 +637,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
}
break;
case WM_SIZE:
{
UpdateAspectRatio(LOWORD(lParam), HIWORD(lParam));
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
@ -651,7 +708,7 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
return FALSE;
}
ShowWindow(g_hWnd, nCmdShow);
ShowWindow(g_hWnd, (nCmdShow != SW_HIDE) ? SW_SHOWMAXIMIZED : nCmdShow);
UpdateWindow(g_hWnd);
return TRUE;
@ -719,7 +776,7 @@ HRESULT InitDevice()
//app.DebugPrintf("width: %d, height: %d\n", width, height);
width = g_iScreenWidth;
height = g_iScreenHeight;
app.DebugPrintf("width: %d, height: %d\n", width, height);
//app.DebugPrintf("width: %d, height: %d\n", width, height);
UINT createDeviceFlags = 0;
#ifdef _DEBUG
@ -860,6 +917,7 @@ void ToggleFullscreen()
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
g_isFullscreen = !g_isFullscreen;
SaveFullscreenOption(g_isFullscreen);
if (g_KBMInput.IsWindowFocused())
g_KBMInput.SetWindowFocused(true);
@ -1180,6 +1238,12 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
return 0;
}
// Restore fullscreen state from previous session
if (LoadFullscreenOption() && !g_isFullscreen)
{
ToggleFullscreen();
}
if (launchOptions.serverMode)
{
int serverResult = RunHeadlessServer();
@ -1505,19 +1569,6 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
}
#ifdef _DEBUG_MENUS_ENABLED
// F4 Open debug overlay
if (g_KBMInput.IsKeyPressed(VK_F4))
{
if (Minecraft *pMinecraft = Minecraft::GetInstance())
{
if (pMinecraft->options &&
app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
{
ui.NavigateToScene(0, eUIScene_DebugOverlay, NULL, eUILayer_Debug);
}
}
}
// F6 Open debug console
if (g_KBMInput.IsKeyPressed(VK_F6))
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View file

@ -48,13 +48,11 @@ void glLoadIdentity()
RenderManager.MatrixSetIdentity();
}
extern int g_iScreenWidth;
extern int g_iScreenHeight;
// AAR - Use calculated aspect ratio to support dynamic resizing
extern float g_iAspectRatio;
void gluPerspective(float fovy, float aspect, float zNear, float zFar)
{
float dynamicAspect = (float)g_iScreenWidth / (float)g_iScreenHeight;
RenderManager.MatrixPerspective(fovy, dynamicAspect, zNear, zFar);
RenderManager.MatrixPerspective(fovy, g_iAspectRatio, zNear, zFar);
}
void glOrtho(float left,float right,float bottom,float top,float zNear,float zFar)

View file

@ -288,10 +288,10 @@ shared_ptr<ItemInstance> FilledBucketDispenseBehavior::execute(BlockSource *sour
return dispensed;
}
return DefaultDispenseItemBehavior::dispense(source, dispensed);
outcome = LEFT_ITEM;
return dispensed;
}
/* EmptyBucket */
shared_ptr<ItemInstance> EmptyBucketDispenseBehavior::execute(BlockSource *source, shared_ptr<ItemInstance> dispensed, eOUTCOME &outcome)
@ -454,4 +454,4 @@ shared_ptr<ItemInstance> TntDispenseBehavior::execute(BlockSource *source, share
outcome = LEFT_ITEM;
}
return dispensed;
}
}

View file

@ -10,17 +10,24 @@ PanicGoal::PanicGoal(PathfinderMob *mob, double speedModifier)
{
this->mob = mob;
this->speedModifier = speedModifier;
setRequiredControlFlags(Control::MoveControlFlag);
Goal::setRequiredControlFlags(Control::MoveControlFlag);
}
bool PanicGoal::canUse()
{
if (mob->getLastHurtByMob() == NULL && !mob->isOnFire()) return false;
Vec3 *pos = RandomPos::getPos(dynamic_pointer_cast<PathfinderMob>(mob->shared_from_this()), 5, 4);
if (pos == NULL) return false;
if (mob->getLastHurtByMob() == nullptr && !mob->isOnFire()) return false;
const int hurtTimeout = mob->getLastHurtByMobTimestamp();
if (hurtTimeout == 0) return false;
static thread_local std::mt19937 rng(std::random_device{}());
std::uniform_int_distribution<int> dist(60, 100);
const int panicDuration = dist(rng);
if (mob->tickCount - hurtTimeout > panicDuration) return false;
const Vec3* pos = RandomPos::getPos(dynamic_pointer_cast<PathfinderMob>(mob->shared_from_this()), 5, 4);
if (pos == nullptr) return false;
posX = pos->x;
posY = pos->y;
posZ = pos->z;
return true;
}
@ -31,5 +38,6 @@ void PanicGoal::start()
bool PanicGoal::canContinueToUse()
{
if (mob->getLastHurtByMob() == nullptr && !mob->isOnFire()) return false;
return !mob->getNavigation()->isDone();
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "Goal.h"
#include <random>
class PathfinderMob;

View file

@ -166,9 +166,15 @@ void SignTileEntity::setChanged()
void SignTileEntity::SetMessage(int iIndex,wstring &wsText)
{
{
if (wsText.length() > MAX_LINE_LENGTH) // MAX_LINE_LENGTH == 15
{
wsText = wsText.substr(0, MAX_LINE_LENGTH);
#ifdef _DEBUG
OutputDebugStringW(L"Sign text truncated to 15 characters\n");
#endif
}
m_wsmessages[iIndex]=wsText;
}
// 4J-PB - added for string verification

View file

@ -535,7 +535,7 @@ void WitherBoss::registerAttributes()
getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.6f);
// 4J Stu - Don't make it so far!
//getAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->setBaseValue(40);
getAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->setBaseValue(40);
}
float WitherBoss::getHeadYRot(int i)
@ -581,4 +581,4 @@ MobType WitherBoss::getMobType()
void WitherBoss::ride(shared_ptr<Entity> e)
{
riding = nullptr;
}
}

View file

@ -56,7 +56,7 @@ void Zombie::registerAttributes()
Monster::registerAttributes();
// 4J Stu - Don't make it so far!
//getAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->setBaseValue(40);
getAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->setBaseValue(40);
getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.23f);
getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(3);
@ -490,4 +490,4 @@ Zombie::ZombieGroupData::ZombieGroupData(bool baby, bool villager)
{
isBaby = baby;
isVillager = villager;
}
}

View file

@ -1,107 +0,0 @@
if(NOT DEFINED PROJECT_SOURCE_DIR OR NOT DEFINED OUTPUT_DIR OR NOT DEFINED CONFIGURATION)
message(FATAL_ERROR "CopyAssets.cmake requires PROJECT_SOURCE_DIR, OUTPUT_DIR, and CONFIGURATION.")
endif()
# Some generators may pass quoted values (e.g. "Debug"); normalize that.
string(REPLACE "\"" "" PROJECT_SOURCE_DIR "${PROJECT_SOURCE_DIR}")
string(REPLACE "\"" "" OUTPUT_DIR "${OUTPUT_DIR}")
string(REPLACE "\"" "" CONFIGURATION "${CONFIGURATION}")
set(_project_dir "${PROJECT_SOURCE_DIR}/Minecraft.Client")
function(copy_tree_if_exists src_rel dst_rel)
set(_src "${_project_dir}/${src_rel}")
set(_dst "${OUTPUT_DIR}/${dst_rel}")
if(EXISTS "${_src}")
file(MAKE_DIRECTORY "${_dst}")
file(GLOB_RECURSE _files RELATIVE "${_src}" "${_src}/*")
foreach(_file IN LISTS _files) # if not a source file
if(NOT _file MATCHES "\\.(cpp|c|h|hpp|xml|lang)$")
set(_full_src "${_src}/${_file}")
set(_full_dst "${_dst}/${_file}")
if(IS_DIRECTORY "${_full_src}")
file(MAKE_DIRECTORY "${_full_dst}")
else()
get_filename_component(_dst_dir "${_full_dst}" DIRECTORY)
file(MAKE_DIRECTORY "${_dst_dir}")
execute_process(
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${_full_src}" "${_full_dst}"
)
endif()
endif()
endforeach()
endif()
endfunction()
function(ensure_dir rel_path)
file(MAKE_DIRECTORY "${OUTPUT_DIR}/${rel_path}")
endfunction()
function(copy_file_if_exists src_rel dst_rel)
set(_src "${PROJECT_SOURCE_DIR}/${src_rel}")
set(_dst "${OUTPUT_DIR}/${dst_rel}")
get_filename_component(_dst_dir "${_dst}" DIRECTORY)
file(MAKE_DIRECTORY "${_dst_dir}")
if(EXISTS "${_src}")
execute_process(
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${_src}" "${_dst}"
)
endif()
endfunction()
function(copy_first_existing dst_rel)
set(_copied FALSE)
foreach(_candidate IN LISTS ARGN)
if(EXISTS "${PROJECT_SOURCE_DIR}/${_candidate}")
copy_file_if_exists("${_candidate}" "${dst_rel}")
set(_copied TRUE)
break()
endif()
endforeach()
if(NOT _copied)
message(WARNING "Runtime file not found for ${dst_rel}. Checked: ${ARGN}")
endif()
endfunction()
function(remove_directory_if_exists rel_path)
set(_dir "${OUTPUT_DIR}/${rel_path}")
if(EXISTS "${_dir}")
file(REMOVE_RECURSE "${_dir}")
endif()
endfunction()
copy_tree_if_exists("Durango/Sound" "Windows64/Sound")
copy_tree_if_exists("music" "music")
copy_tree_if_exists("Windows64/GameHDD" "Windows64/GameHDD")
copy_file_if_exists("Minecraft.Client/Common/Media/MediaWindows64.arc" "Common/Media/MediaWindows64.arc")
copy_tree_if_exists("Common/res" "Common/res")
copy_tree_if_exists("Common/Trial" "Common/Trial")
copy_tree_if_exists("Common/Tutorial" "Common/Tutorial")
copy_tree_if_exists("DurangoMedia" "Windows64Media")
copy_tree_if_exists("Windows64Media" "Windows64Media")
remove_directory_if_exists("Windows64Media/Layout")
# Some runtime code asserts if this directory tree is missing.
ensure_dir("Windows64/GameHDD")
# Keep legacy runtime redistributables in a familiar location.
copy_tree_if_exists("Windows64/Miles/lib/redist64" "redist64")
copy_tree_if_exists("Windows64/Iggy/lib/redist64" "redist64")
# Runtime DLLs required at launch.
copy_first_existing("iggy_w64.dll"
"Minecraft.Client/Windows64/Iggy/lib/redist64/iggy_w64.dll"
"x64/${CONFIGURATION}/iggy_w64.dll"
)
copy_first_existing("mss64.dll"
"Minecraft.Client/Windows64/Miles/lib/redist64/mss64.dll"
"x64/${CONFIGURATION}/mss64.dll"
)