Merge upstream/main into main

This commit is contained in:
Revela
2026-03-15 23:38:41 -05:00
19 changed files with 546 additions and 639 deletions

View File

@@ -658,7 +658,7 @@ bool MinecraftServer::initServer(int64_t seed, NetworkGameInitData *initData, DW
setFlightAllowed(GetDedicatedServerBool(settings, L"allow-flight", true));
// 4J Stu - Enabling flight to stop it kicking us when we use it
#ifdef _DEBUG_MENUS_ENABLED
#if (defined _DEBUG_MENUS_ENABLED && defined _DEBUG)
setFlightAllowed(true);
#endif
@@ -1725,330 +1725,345 @@ void MinecraftServer::setPlayerIdleTimeout(int playerIdleTimeout)
extern int c0a, c0b, c1a, c1b, c1c, c2a, c2b;
void MinecraftServer::run(int64_t seed, void *lpParameter)
{
NetworkGameInitData *initData = nullptr;
DWORD initSettings = 0;
bool findSeed = false;
NetworkGameInitData *initData = nullptr;
DWORD initSettings = 0;
bool findSeed = false;
if(lpParameter != nullptr)
{
initData = static_cast<NetworkGameInitData *>(lpParameter);
initSettings = app.GetGameHostOption(eGameHostOption_All);
findSeed = initData->findSeed;
m_texturePackId = initData->texturePackId;
}
// try { // 4J - removed try/catch/finally
bool didInit = false;
{
initData = static_cast<NetworkGameInitData *>(lpParameter);
initSettings = app.GetGameHostOption(eGameHostOption_All);
findSeed = initData->findSeed;
m_texturePackId = initData->texturePackId;
}
// try { // 4J - removed try/catch/finally
bool didInit = false;
if (initServer(seed, initData, initSettings,findSeed))
{
didInit = true;
ServerLevel *levelNormalDimension = levels[0];
// 4J-PB - Set the Stronghold position in the leveldata if there isn't one in there
Minecraft *pMinecraft = Minecraft::GetInstance();
{
didInit = true;
ServerLevel *levelNormalDimension = levels[0];
// 4J-PB - Set the Stronghold position in the leveldata if there isn't one in there
Minecraft *pMinecraft = Minecraft::GetInstance();
LevelData *pLevelData=levelNormalDimension->getLevelData();
if(pLevelData && pLevelData->getHasStronghold()==false)
{
{
int x,z;
if(app.GetTerrainFeaturePosition(eTerrainFeature_Stronghold,&x,&z))
{
pLevelData->setXStronghold(x);
pLevelData->setZStronghold(z);
pLevelData->setHasStronghold();
}
}
{
pLevelData->setXStronghold(x);
pLevelData->setZStronghold(z);
pLevelData->setHasStronghold();
}
}
int64_t lastTime = getCurrentTimeMillis();
int64_t unprocessedTime = 0;
while (running && !s_bServerHalted)
{
int64_t now = getCurrentTimeMillis();
int64_t lastTime = getCurrentTimeMillis();
int64_t unprocessedTime = 0;
while (running && !s_bServerHalted)
{
int64_t now = getCurrentTimeMillis();
// 4J Stu - When we pause the server, we don't want to count that as time passed
// 4J Stu - TU-1 hotifx - Remove this line. We want to make sure that we tick connections at the proper rate when paused
// 4J Stu - When we pause the server, we don't want to count that as time passed
// 4J Stu - TU-1 hotifx - Remove this line. We want to make sure that we tick connections at the proper rate when paused
//Fix for #13191 - The host of a game can get a message informing them that the connection to the server has been lost
//if(m_isServerPaused) lastTime = now;
int64_t passedTime = now - lastTime;
if (passedTime > MS_PER_TICK * 40)
{
// logger.warning("Can't keep up! Did the system time change, or is the server overloaded?");
passedTime = MS_PER_TICK * 40;
}
if (passedTime < 0)
{
// logger.warning("Time ran backwards! Did the system time change?");
passedTime = 0;
}
unprocessedTime += passedTime;
lastTime = now;
int64_t passedTime = now - lastTime;
if (passedTime > MS_PER_TICK * 40)
{
// logger.warning("Can't keep up! Did the system time change, or is the server overloaded?");
passedTime = MS_PER_TICK * 40;
}
if (passedTime < 0)
{
// logger.warning("Time ran backwards! Did the system time change?");
passedTime = 0;
}
unprocessedTime += passedTime;
lastTime = now;
// 4J Added ability to pause the server
// 4J Added ability to pause the server
if( !m_isServerPaused )
{
bool didTick = false;
if (levels[0]->allPlayersAreSleeping())
{
tick();
unprocessedTime = 0;
}
else
{
// int tickcount = 0;
// int64_t beforeall = System::currentTimeMillis();
while (unprocessedTime > MS_PER_TICK)
{
unprocessedTime -= MS_PER_TICK;
chunkPacketManagement_PreTick();
// int64_t before = System::currentTimeMillis();
tick();
// int64_t after = System::currentTimeMillis();
// PIXReportCounter(L"Server time",(float)(after-before));
{
bool didTick = false;
if (levels[0]->allPlayersAreSleeping())
{
tick();
unprocessedTime = 0;
}
else
{
// int tickcount = 0;
// int64_t beforeall = System::currentTimeMillis();
while (unprocessedTime > MS_PER_TICK)
{
unprocessedTime -= MS_PER_TICK;
chunkPacketManagement_PreTick();
// int64_t before = System::currentTimeMillis();
tick();
// int64_t after = System::currentTimeMillis();
// PIXReportCounter(L"Server time",(float)(after-before));
chunkPacketManagement_PostTick();
}
// int64_t afterall = System::currentTimeMillis();
// PIXReportCounter(L"Server time all",(float)(afterall-beforeall));
// PIXReportCounter(L"Server ticks",(float)tickcount);
}
}
else
{
// 4J Stu - TU1-hotfix
chunkPacketManagement_PostTick();
}
// int64_t afterall = System::currentTimeMillis();
// PIXReportCounter(L"Server time all",(float)(afterall-beforeall));
// PIXReportCounter(L"Server ticks",(float)tickcount);
}
}
else
{
// 4J Stu - TU1-hotfix
//Fix for #13191 - The host of a game can get a message informing them that the connection to the server has been lost
// The connections should tick at the same frequency even when paused
while (unprocessedTime > MS_PER_TICK)
{
unprocessedTime -= MS_PER_TICK;
// Keep ticking the connections to stop them timing out
connection->tick();
}
}
// The connections should tick at the same frequency even when paused
while (unprocessedTime > MS_PER_TICK)
{
unprocessedTime -= MS_PER_TICK;
// Keep ticking the connections to stop them timing out
connection->tick();
}
}
if(MinecraftServer::setTimeAtEndOfTick)
{
MinecraftServer::setTimeAtEndOfTick = false;
for (unsigned int i = 0; i < levels.length; i++)
{
// if (i == 0 || settings->getBoolean(L"allow-nether", true)) // 4J removed - we always have nether
{
ServerLevel *level = levels[i];
{
MinecraftServer::setTimeAtEndOfTick = false;
for (unsigned int i = 0; i < levels.length; i++)
{
// if (i == 0 || settings->getBoolean(L"allow-nether", true)) // 4J removed - we always have nether
{
ServerLevel *level = levels[i];
level->setGameTime( MinecraftServer::setTime );
}
}
}
}
}
}
if(MinecraftServer::setTimeOfDayAtEndOfTick)
{
MinecraftServer::setTimeOfDayAtEndOfTick = false;
for (unsigned int i = 0; i < levels.length; i++)
{
if (i == 0 || GetDedicatedServerBool(settings, L"allow-nether", true))
{
ServerLevel *level = levels[i];
{
MinecraftServer::setTimeOfDayAtEndOfTick = false;
for (unsigned int i = 0; i < levels.length; i++)
{
if (i == 0 || GetDedicatedServerBool(settings, L"allow-nether", true))
{
ServerLevel *level = levels[i];
level->setDayTime( MinecraftServer::setTimeOfDay );
}
}
}
}
}
}
// Process delayed actions
eXuiServerAction eAction;
LPVOID param;
// Process delayed actions
eXuiServerAction eAction;
LPVOID param;
for(int i=0;i<XUSER_MAX_COUNT;i++)
{
eAction = app.GetXuiServerAction(i);
param = app.GetXuiServerActionParam(i);
{
eAction = app.GetXuiServerAction(i);
param = app.GetXuiServerActionParam(i);
switch(eAction)
{
case eXuiServerAction_AutoSaveGame:
{
case eXuiServerAction_AutoSaveGame:
#if defined(_XBOX_ONE) || defined(__ORBIS__) || defined(MINECRAFT_SERVER_BUILD)
{
#if defined(_XBOX_ONE) || defined(__ORBIS__)
{
PIXBeginNamedEvent(0,"Autosave");
PIXBeginNamedEvent(0, "Autosave");
// Get the frequency of the timer
LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime;
float fElapsedTime = 0.0f;
QueryPerformanceFrequency( &qwTicksPerSec );
float fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart;
// Get the frequency of the timer
LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime;
float fElapsedTime = 0.0f;
QueryPerformanceFrequency(&qwTicksPerSec);
float fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart;
// Save the start time
QueryPerformanceCounter( &qwTime );
if (players != nullptr)
{
players->saveAll(nullptr);
}
for (unsigned int j = 0; j < levels.length; j++)
{
if( s_bServerHalted ) break;
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
// with the data from the nethers leveldata.
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
ServerLevel *level = levels[levels.length - 1 - j];
PIXBeginNamedEvent(0, "Saving level %d",levels.length - 1 - j);
level->save(false, nullptr, true);
PIXEndNamedEvent();
}
if( !s_bServerHalted )
{
PIXBeginNamedEvent(0,"Saving game rules");
saveGameRules();
PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Save to disc");
levels[0]->saveToDisc(Minecraft::GetInstance()->progressRenderer, true);
PIXEndNamedEvent();
}
PIXEndNamedEvent();
QueryPerformanceCounter( &qwNewTime );
qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart;
fElapsedTime = fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart));
app.DebugPrintf("Autosave: Elapsed time %f\n", fElapsedTime);
}
break;
// Save the start time
QueryPerformanceCounter(&qwTime);
#endif
case eXuiServerAction_SaveGame:
app.EnterSaveNotificationSection();
if (players != nullptr)
{
players->saveAll(Minecraft::GetInstance()->progressRenderer);
}
players->broadcastAll(std::make_shared<UpdateProgressPacket>(20));
if (players != nullptr)
{
players->saveAll(nullptr);
}
for (unsigned int j = 0; j < levels.length; j++)
{
for (unsigned int j = 0; j < levels.length; j++)
{
if( s_bServerHalted ) break;
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
// with the data from the nethers leveldata.
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
ServerLevel *level = levels[levels.length - 1 - j];
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXBeginNamedEvent(0, "Saving level %d", levels.length - 1 - j);
#endif
level->save(false, nullptr, true);
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXEndNamedEvent();
#endif
}
if (!s_bServerHalted)
{
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXBeginNamedEvent(0, "Saving game rules");
#endif
saveGameRules();
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXEndNamedEvent();
PIXBeginNamedEvent(0, "Save to disc");
#endif
levels[0]->saveToDisc(Minecraft::GetInstance()->progressRenderer, true);
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXEndNamedEvent();
#endif
}
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXEndNamedEvent();
QueryPerformanceCounter(&qwNewTime);
qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart;
fElapsedTime = fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart));
app.DebugPrintf("Autosave: Elapsed time %f\n", fElapsedTime);
#endif
}
break;
#endif
case eXuiServerAction_SaveGame:
app.EnterSaveNotificationSection();
if (players != nullptr)
{
players->saveAll(Minecraft::GetInstance()->progressRenderer);
}
players->broadcastAll(std::make_shared<UpdateProgressPacket>(20));
for (unsigned int j = 0; j < levels.length; j++)
{
if( s_bServerHalted ) break;
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
// with the data from the nethers leveldata.
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
ServerLevel *level = levels[levels.length - 1 - j];
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
// with the data from the nethers leveldata.
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
ServerLevel *level = levels[levels.length - 1 - j];
level->save(true, Minecraft::GetInstance()->progressRenderer, (eAction==eXuiServerAction_AutoSaveGame));
players->broadcastAll(std::make_shared<UpdateProgressPacket>(33 + (j * 33)));
}
players->broadcastAll(std::make_shared<UpdateProgressPacket>(33 + (j * 33)));
}
if( !s_bServerHalted )
{
saveGameRules();
{
saveGameRules();
levels[0]->saveToDisc(Minecraft::GetInstance()->progressRenderer, (eAction==eXuiServerAction_AutoSaveGame));
}
app.LeaveSaveNotificationSection();
break;
case eXuiServerAction_DropItem:
// Find the player, and drop the id at their feet
{
shared_ptr<ServerPlayer> player = players->players.at(0);
}
app.LeaveSaveNotificationSection();
break;
case eXuiServerAction_DropItem:
// Find the player, and drop the id at their feet
{
shared_ptr<ServerPlayer> player = players->players.at(0);
size_t id = (size_t) param;
player->drop(std::make_shared<ItemInstance>(id, 1, 0));
}
break;
case eXuiServerAction_SpawnMob:
{
shared_ptr<ServerPlayer> player = players->players.at(0);
eINSTANCEOF factory = static_cast<eINSTANCEOF>((size_t)param);
player->drop(std::make_shared<ItemInstance>(id, 1, 0));
}
break;
case eXuiServerAction_SpawnMob:
{
shared_ptr<ServerPlayer> player = players->players.at(0);
eINSTANCEOF factory = static_cast<eINSTANCEOF>((size_t)param);
shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(EntityIO::newByEnumType(factory,player->level ));
mob->moveTo(player->x+1, player->y, player->z+1, player->level->random->nextFloat() * 360, 0);
mob->setDespawnProtected(); // 4J added, default to being protected against despawning (has to be done after initial position is set)
player->level->addEntity(mob);
}
break;
case eXuiServerAction_PauseServer:
player->level->addEntity(mob);
}
break;
case eXuiServerAction_PauseServer:
m_isServerPaused = ( (size_t) param == TRUE );
if( m_isServerPaused )
{
m_serverPausedEvent->Set();
}
break;
case eXuiServerAction_ToggleRain:
{
bool isRaining = levels[0]->getLevelData()->isRaining();
levels[0]->getLevelData()->setRaining(!isRaining);
levels[0]->getLevelData()->setRainTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
}
break;
case eXuiServerAction_ToggleThunder:
{
bool isThundering = levels[0]->getLevelData()->isThundering();
levels[0]->getLevelData()->setThundering(!isThundering);
levels[0]->getLevelData()->setThunderTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
}
break;
case eXuiServerAction_ServerSettingChanged_Gamertags:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_OPTIONS, app.GetGameHostOption(eGameHostOption_Gamertags)));
break;
case eXuiServerAction_ServerSettingChanged_BedrockFog:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_IN_GAME_SETTINGS, app.GetGameHostOption(eGameHostOption_All)));
break;
{
m_serverPausedEvent->Set();
}
break;
case eXuiServerAction_ToggleRain:
{
bool isRaining = levels[0]->getLevelData()->isRaining();
levels[0]->getLevelData()->setRaining(!isRaining);
levels[0]->getLevelData()->setRainTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
}
break;
case eXuiServerAction_ToggleThunder:
{
bool isThundering = levels[0]->getLevelData()->isThundering();
levels[0]->getLevelData()->setThundering(!isThundering);
levels[0]->getLevelData()->setThunderTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
}
break;
case eXuiServerAction_ServerSettingChanged_Gamertags:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_OPTIONS, app.GetGameHostOption(eGameHostOption_Gamertags)));
break;
case eXuiServerAction_ServerSettingChanged_BedrockFog:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_IN_GAME_SETTINGS, app.GetGameHostOption(eGameHostOption_All)));
break;
case eXuiServerAction_ServerSettingChanged_Difficulty:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_DIFFICULTY, Minecraft::GetInstance()->options->difficulty));
break;
case eXuiServerAction_ExportSchematic:
case eXuiServerAction_ServerSettingChanged_Difficulty:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_DIFFICULTY, Minecraft::GetInstance()->options->difficulty));
break;
case eXuiServerAction_ExportSchematic:
#ifndef _CONTENT_PACKAGE
app.EnterSaveNotificationSection();
app.EnterSaveNotificationSection();
//players->broadcastAll( shared_ptr<UpdateProgressPacket>( new UpdateProgressPacket(20) ) );
if( !s_bServerHalted )
{
ConsoleSchematicFile::XboxSchematicInitParam *initData = static_cast<ConsoleSchematicFile::XboxSchematicInitParam *>(param);
{
ConsoleSchematicFile::XboxSchematicInitParam *initData = static_cast<ConsoleSchematicFile::XboxSchematicInitParam *>(param);
#ifdef _XBOX
File targetFileDir(File::pathRoot + File::pathSeparator + L"Schematics");
File targetFileDir(File::pathRoot + File::pathSeparator + L"Schematics");
#else
File targetFileDir(L"Schematics");
File targetFileDir(L"Schematics");
#endif
if(!targetFileDir.exists()) targetFileDir.mkdir();
wchar_t filename[128];
wchar_t filename[128];
swprintf(filename,128,L"%ls%dx%dx%d.sch",initData->name,(initData->endX - initData->startX + 1), (initData->endY - initData->startY + 1), (initData->endZ - initData->startZ + 1));
File dataFile = File( targetFileDir, wstring(filename) );
if(dataFile.exists()) dataFile._delete();
FileOutputStream fos = FileOutputStream(dataFile);
DataOutputStream dos = DataOutputStream(&fos);
ConsoleSchematicFile::generateSchematicFile(&dos, levels[0], initData->startX, initData->startY, initData->startZ, initData->endX, initData->endY, initData->endZ, initData->bSaveMobs, initData->compressionType);
dos.close();
FileOutputStream fos = FileOutputStream(dataFile);
DataOutputStream dos = DataOutputStream(&fos);
ConsoleSchematicFile::generateSchematicFile(&dos, levels[0], initData->startX, initData->startY, initData->startZ, initData->endX, initData->endY, initData->endZ, initData->bSaveMobs, initData->compressionType);
dos.close();
delete initData;
}
app.LeaveSaveNotificationSection();
delete initData;
}
app.LeaveSaveNotificationSection();
#endif
break;
case eXuiServerAction_SetCameraLocation:
break;
case eXuiServerAction_SetCameraLocation:
#ifndef _CONTENT_PACKAGE
{
DebugSetCameraPosition *pos = static_cast<DebugSetCameraPosition *>(param);
{
DebugSetCameraPosition *pos = static_cast<DebugSetCameraPosition *>(param);
app.DebugPrintf( "DEBUG: Player=%i\n", pos->player );
app.DebugPrintf( "DEBUG: Teleporting to pos=(%f.2, %f.2, %f.2), looking at=(%f.2,%f.2)\n",
pos->m_camX, pos->m_camY, pos->m_camZ,
pos->m_camX, pos->m_camY, pos->m_camZ,
pos->m_yRot, pos->m_elev
);
shared_ptr<ServerPlayer> player = players->players.at(pos->player);
shared_ptr<ServerPlayer> player = players->players.at(pos->player);
player->debug_setPosition( pos->m_camX, pos->m_camY, pos->m_camZ,
pos->m_yRot, pos->m_elev );
// Doesn't work
// Doesn't work
//player->setYHeadRot(pos->m_yRot);
//player->absMoveTo(pos->m_camX, pos->m_camY, pos->m_camZ, pos->m_yRot, pos->m_elev);
}
}
#endif
break;
}
break;
}
app.SetXuiServerAction(i,eXuiServerAction_Idle);
}
}
Sleep(1);
}
}
Sleep(1);
}
}
//else
//{
//{
// while (running)
// {
// {
// handleConsoleInputs();
// Sleep(10);
// Sleep(10);
// }
//}
#if 0
@@ -2075,9 +2090,9 @@ void MinecraftServer::run(int64_t seed, void *lpParameter)
}
#endif
// 4J Stu - Stop the server when the loops complete, as the finally would do
stopServer(didInit);
stopped = true;
// 4J Stu - Stop the server when the loops complete, as the finally would do
stopServer(didInit);
stopped = true;
}
void MinecraftServer::broadcastStartSavingPacket()
@@ -2385,6 +2400,9 @@ bool MinecraftServer::chunkPacketManagement_CanSendTo(INetworkPlayer *player)
{
if( player == nullptr ) return false;
#ifdef MINECRAFT_SERVER_BUILD
return true;
#else
int time = GetTickCount();
DWORD currentPlayerCount = g_NetworkManager.GetPlayerCount();
if( currentPlayerCount == 0 ) return false;
@@ -2396,6 +2414,7 @@ bool MinecraftServer::chunkPacketManagement_CanSendTo(INetworkPlayer *player)
}
return false;
#endif
}
void MinecraftServer::chunkPacketManagement_DidSendTo(INetworkPlayer *player)