mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/GabsPuNs-MinecraftConsoles.git
synced 2026-06-25 13:15:33 +00:00
Minecraft Consoles latest changes + Better shadow for water in Extra mode
Culling for water need more work in extra graphics mode.
This commit is contained in:
@@ -326,7 +326,10 @@ bool TileRenderer::tesselateInWorld( Tile* tt, int x, int y, int z, int forceDat
|
||||
retVal = tesselateQuartzInWorld(tt, x, y, z);
|
||||
break;
|
||||
case Tile::SHAPE_WATER:
|
||||
retVal = tesselateWaterInWorld( tt, x, y, z );
|
||||
if (Minecraft::GetInstance()->options->mipmapsBlend)
|
||||
retVal = tesselateWaterInWorldAO( tt, x, y, z );
|
||||
else
|
||||
retVal = tesselateWaterInWorld( tt, x, y, z );
|
||||
break;
|
||||
case Tile::SHAPE_CACTUS:
|
||||
retVal = tesselateCactusInWorld( tt, x, y, z );
|
||||
@@ -4755,6 +4758,209 @@ bool TileRenderer::tesselateWaterInWorld(Tile* tt, int x, int y, int z)
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool TileRenderer::tesselateWaterInWorldAO(Tile* tt, int x, int y, int z)
|
||||
{
|
||||
Tesselator* t = Tesselator::getInstance();
|
||||
|
||||
int col = tt->getColor(level, x, y, z);
|
||||
float r = ((col >> 16) & 0xff) / 255.0f;
|
||||
float g = ((col >> 8) & 0xff) / 255.0f;
|
||||
float b = (col & 0xff) / 255.0f;
|
||||
|
||||
bool up = tt->shouldRenderFace(level, x, y + 1, z, 1);
|
||||
bool down = tt->shouldRenderFace(level, x, y - 1, z, 0);
|
||||
bool dirs[4];
|
||||
|
||||
dirs[0] = tt->shouldRenderFace( level, x, y, z - 1, 2 );
|
||||
dirs[1] = tt->shouldRenderFace( level, x, y, z + 1, 3 );
|
||||
dirs[2] = tt->shouldRenderFace( level, x - 1, y, z, 4 );
|
||||
dirs[3] = tt->shouldRenderFace( level, x + 1, y, z, 5 );
|
||||
|
||||
if (!up && !down && !dirs[0] && !dirs[1] && !dirs[2] && !dirs[3])
|
||||
return false;
|
||||
|
||||
bool changed = false;
|
||||
Material* m = tt->material;
|
||||
int data = level->getData(x, y, z);
|
||||
|
||||
float h0 = getWaterHeight(x, y, z, m);
|
||||
float h1 = getWaterHeight(x, y, z + 1, m);
|
||||
float h2 = getWaterHeight(x + 1, y, z + 1, m);
|
||||
float h3 = getWaterHeight(x + 1, y, z, m);
|
||||
|
||||
float maxh = h0;
|
||||
if (h1 > maxh) maxh = h1;
|
||||
if (h2 > maxh) maxh = h2;
|
||||
if (h3 > maxh) maxh = h3;
|
||||
|
||||
// 4J - added. Farm tiles often found beside water, but they consider themselves non-solid as they only extend up to 15.0f / 16.0f.
|
||||
// If the max height of this water is below that level, don't bother rendering sides bordering onto farmland.
|
||||
if (maxh <= ( 15.0f / 16.0f ))
|
||||
{
|
||||
if (level->getTile(x, y, z - 1) == Tile::farmland_Id) dirs[0] = false;
|
||||
if (level->getTile(x, y, z + 1) == Tile::farmland_Id) dirs[1] = false;
|
||||
if (level->getTile(x - 1, y, z) == Tile::farmland_Id) dirs[2] = false;
|
||||
if (level->getTile(x + 1, y, z) == Tile::farmland_Id) dirs[3] = false;
|
||||
}
|
||||
|
||||
constexpr float EPS = 0.0001f;
|
||||
|
||||
if (noCulling || up)
|
||||
{
|
||||
changed = true;
|
||||
Icon* tex = getTexture(tt, 1, data);
|
||||
float angle = static_cast<float>(LiquidTile::getSlopeAngle(level, x, y, z, m));
|
||||
|
||||
if (angle > -999.0f) tex = getTexture(tt, 2, data);
|
||||
|
||||
h0 -= EPS; h1 -= EPS; h2 -= EPS; h3 -= EPS;
|
||||
|
||||
float u0, v0, u1, v1, u2, v2, u3, v3;
|
||||
|
||||
if (angle >= -999.0f)
|
||||
{
|
||||
float cc = 8.0f;
|
||||
float fsin = Mth::sin(angle) * 0.25f;
|
||||
float fcos = Mth::cos(angle) * 0.25f;
|
||||
u0 = tex->getU(cc + (-fcos - fsin) * SharedConstants::WORLD_RESOLUTION);
|
||||
v0 = tex->getV(cc + (fsin - fcos) * SharedConstants::WORLD_RESOLUTION);
|
||||
u1 = tex->getU(cc + (fsin - fcos) * SharedConstants::WORLD_RESOLUTION);
|
||||
v1 = tex->getV(cc + (fcos + fsin) * SharedConstants::WORLD_RESOLUTION);
|
||||
u2 = tex->getU(cc + (fcos + fsin) * SharedConstants::WORLD_RESOLUTION);
|
||||
v2 = tex->getV(cc + (fcos - fsin) * SharedConstants::WORLD_RESOLUTION);
|
||||
u3 = tex->getU(cc + (fcos - fsin) * SharedConstants::WORLD_RESOLUTION);
|
||||
v3 = tex->getV(cc + (-fcos - fsin) * SharedConstants::WORLD_RESOLUTION);
|
||||
}
|
||||
else
|
||||
{
|
||||
u0 = tex->getU(0.0f, true); v0 = tex->getV(0.0f, true);
|
||||
u1 = u0; v1 = tex->getV(SharedConstants::WORLD_RESOLUTION, true);
|
||||
u2 = tex->getU(SharedConstants::WORLD_RESOLUTION, true); v2 = v1;
|
||||
u3 = u2; v3 = v0;
|
||||
}
|
||||
|
||||
int pY = y + 1;
|
||||
int centerColor = tt->getLightColor(level, x, pY, z);
|
||||
float ll0Y0 = tt->getShadeBrightness(level, x, pY, z);
|
||||
|
||||
auto getWaterLight = [&](int sx, int sy, int sz) -> int {
|
||||
if (level->isSolidBlockingTile(sx, sy, sz)) return centerColor;
|
||||
return tt->getLightColor(level, sx, sy, sz);
|
||||
};
|
||||
|
||||
auto getWaterBr = [&](int sx, int sy, int sz) -> float {
|
||||
if (level->isSolidBlockingTile(sx, sy, sz)) return ll0Y0;
|
||||
return tt->getShadeBrightness(level, sx, sy, sz);
|
||||
};
|
||||
|
||||
int ccxY0 = getWaterLight(x - 1, pY, z);
|
||||
int ccXY0 = getWaterLight(x + 1, pY, z);
|
||||
int cc0Yz = getWaterLight(x, pY, z - 1);
|
||||
int cc0YZ = getWaterLight(x, pY, z + 1);
|
||||
|
||||
float llxY0 = getWaterBr(x - 1, pY, z);
|
||||
float llXY0 = getWaterBr(x + 1, pY, z);
|
||||
float ll0Yz = getWaterBr(x, pY, z - 1);
|
||||
float ll0YZ = getWaterBr(x, pY, z + 1);
|
||||
|
||||
float llxYz, llXYz, llxYZ, llXYZ;
|
||||
int ccxYz, ccXYz, ccxYZ, ccXYZ;
|
||||
|
||||
llxYz = getWaterBr(x - 1, pY, z - 1); ccxYz = getWaterLight(x - 1, pY, z - 1);
|
||||
llXYz = getWaterBr(x + 1, pY, z - 1); ccXYz = getWaterLight(x + 1, pY, z - 1);
|
||||
llxYZ = getWaterBr(x - 1, pY, z + 1); ccxYZ = getWaterLight(x - 1, pY, z + 1);
|
||||
llXYZ = getWaterBr(x + 1, pY, z + 1); ccXYZ = getWaterLight(x + 1, pY, z + 1);
|
||||
|
||||
float b0 = (llxY0 + llxYz + ll0Y0 + ll0Yz) / 4.0f;
|
||||
int c0 = blend(ccxY0, ccxYz, centerColor, cc0Yz);
|
||||
|
||||
float b1 = (llxYZ + llxY0 + ll0YZ + ll0Y0) / 4.0f;
|
||||
int c1 = blend(ccxYZ, ccxY0, cc0YZ, centerColor);
|
||||
|
||||
float b2 = (ll0YZ + ll0Y0 + llXYZ + llXY0) / 4.0f;
|
||||
int c2 = blend(cc0YZ, centerColor, ccXYZ, ccXY0);
|
||||
|
||||
float b3 = (ll0Y0 + ll0Yz + llXY0 + llXYz) / 4.0f;
|
||||
int c3 = blend(centerColor, cc0Yz, ccXY0, ccXYz);
|
||||
|
||||
t->tex2(c0); t->color(r * b0, g * b0, b * b0);
|
||||
t->vertexUV((float)x, (float)(y + h0), (float)z, u0, v0);
|
||||
|
||||
t->tex2(c1); t->color(r * b1, g * b1, b * b1);
|
||||
t->vertexUV((float)x, (float)(y + h1), (float)(z + 1), u1, v1);
|
||||
|
||||
t->tex2(c2); t->color(r * b2, g * b2, b * b2);
|
||||
t->vertexUV((float)(x + 1), (float)(y + h2), (float)(z + 1), u2, v2);
|
||||
|
||||
t->tex2(c3); t->color(r * b3, g * b3, b * b3);
|
||||
t->vertexUV((float)(x + 1), (float)(y + h3), (float)z, u3, v3);
|
||||
|
||||
if (static_cast<LiquidTile*>(tt)->LiquidTile::shouldRenderBackwardUpFace(level, x, y + 1, z))
|
||||
{
|
||||
t->tex2(c0); t->color(r * b0, g * b0, b * b0);
|
||||
t->vertexUV((float)x, (float)(y + h0), (float)z, u0, v0);
|
||||
t->tex2(c3); t->color(r * b3, g * b3, b * b3);
|
||||
t->vertexUV((float)(x + 1), (float)(y + h3), (float)z, u3, v3);
|
||||
t->tex2(c2); t->color(r * b2, g * b2, b * b2);
|
||||
t->vertexUV((float)(x + 1), (float)(y + h2), (float)(z + 1), u2, v2);
|
||||
t->tex2(c1); t->color(r * b1, g * b1, b * b1);
|
||||
t->vertexUV((float)x, (float)(y + h1), (float)(z + 1), u1, v1);
|
||||
}
|
||||
}
|
||||
|
||||
if (noCulling || down)
|
||||
{
|
||||
t->tex2(getLightColor(tt, level, x, y - 1, z));
|
||||
float bl = tt->getShadeBrightness(level, x, y - 1, z);
|
||||
t->color(r * 0.5f * bl, g * 0.5f * bl, b * 0.5f * bl);
|
||||
renderFaceDown(tt, x, y + EPS, z, getTexture(tt, 0));
|
||||
changed = true;
|
||||
}
|
||||
|
||||
for (int face = 0; face < 4; face++)
|
||||
{
|
||||
if (noCulling || dirs[face])
|
||||
{
|
||||
int xt = x, zt = z;
|
||||
float x0, z0, x1, z1, hh0, hh1;
|
||||
|
||||
if (face == 0) { zt--; x1 = x + 1.0f; z1 = z + EPS; x0 = x; z0 = z + EPS; hh0 = h0; hh1 = h3; }
|
||||
else if (face == 1) { zt++; x1 = x; z1 = z + 1.0f - EPS; x0 = x + 1.0f; z0 = z + 1.0f - EPS; hh0 = h2; hh1 = h1; }
|
||||
else if (face == 2) { xt--; x1 = x + EPS; z1 = z; x0 = x + EPS; z0 = z + 1.0f; hh0 = h1; hh1 = h0; }
|
||||
else { xt++; x0 = x + 1.0f - EPS; z1 = z + 1.0f; x1 = x + 1.0f - EPS; z0 = z; hh0 = h3; hh1 = h2; }
|
||||
|
||||
changed = true;
|
||||
Icon* tex = getTexture(tt, face + 2, data);
|
||||
float side_v_h0 = tex->getV((1.0f - hh0) * 8.0f);
|
||||
float side_v_h1 = tex->getV((1.0f - hh1) * 8.0f);
|
||||
float side_u0 = tex->getU(0.0f, true), side_u1 = tex->getU(8.0f, true), side_v1 = tex->getV(8.0f, true);
|
||||
|
||||
int lightTop = getLightColor(tt, level, xt, y + 1, zt);
|
||||
int lightBot = getLightColor(tt, level, xt, y, zt);
|
||||
float br = (face < 2) ? 0.8f : 0.6f;
|
||||
|
||||
t->tex2(lightTop); t->color(br * r, br * g, br * b);
|
||||
t->vertexUV(x0, y + hh0, z0, side_u0, side_v_h0);
|
||||
t->vertexUV(x1, y + hh1, z1, side_u1, side_v_h1);
|
||||
t->tex2(lightBot);
|
||||
t->vertexUV(x1, (float)y, z1, side_u1, side_v1);
|
||||
t->vertexUV(x0, (float)y, z0, side_u0, side_v1);
|
||||
|
||||
t->tex2(lightBot);
|
||||
t->vertexUV(x0, (float)y, z0, side_u0, side_v1);
|
||||
t->vertexUV(x1, (float)y, z1, side_u1, side_v1);
|
||||
t->tex2(lightTop);
|
||||
t->vertexUV(x1, y + hh1, z1, side_u1, side_v_h1);
|
||||
t->vertexUV(x0, y + hh0, z0, side_u0, side_v_h0);
|
||||
}
|
||||
}
|
||||
|
||||
tileShapeY0 = 0.0f;
|
||||
tileShapeY1 = 1.0f;
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
float TileRenderer::getWaterHeight( int x, int y, int z, Material* m )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
@@ -150,6 +150,7 @@ private:
|
||||
|
||||
void tesselateRowTexture( Tile* tt, int data, float x, float y, float z );
|
||||
bool tesselateWaterInWorld( Tile* tt, int x, int y, int z );
|
||||
bool tesselateWaterInWorldAO( Tile* tt, int x, int y, int z );
|
||||
private:
|
||||
float getWaterHeight( int x, int y, int z, Material* m );
|
||||
public:
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace ServerRuntime
|
||||
}
|
||||
|
||||
IServerCliCommand *command = m_registry->FindMutable(parsed.tokens[0]);
|
||||
if (command == NULL)
|
||||
if (command == nullptr)
|
||||
{
|
||||
LogWarn("Unknown command: " + parsed.tokens[0]);
|
||||
return false;
|
||||
@@ -170,7 +170,7 @@ namespace ServerRuntime
|
||||
|
||||
void ServerCliEngine::BuildCompletions(const std::string &line, std::vector<std::string> *out) const
|
||||
{
|
||||
if (out == NULL)
|
||||
if (out == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -211,7 +211,7 @@ namespace ServerRuntime
|
||||
else
|
||||
{
|
||||
const IServerCliCommand *command = m_registry->Find(commandToken);
|
||||
if (command != NULL)
|
||||
if (command != nullptr)
|
||||
{
|
||||
command->Complete(context, this, out);
|
||||
}
|
||||
@@ -254,13 +254,13 @@ namespace ServerRuntime
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
MinecraftServer *server = MinecraftServer::getInstance();
|
||||
if (server == NULL)
|
||||
if (server == nullptr)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
PlayerList *players = server->getPlayers();
|
||||
if (players == NULL)
|
||||
if (players == nullptr)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
@@ -268,7 +268,7 @@ namespace ServerRuntime
|
||||
for (size_t i = 0; i < players->players.size(); ++i)
|
||||
{
|
||||
std::shared_ptr<ServerPlayer> player = players->players[i];
|
||||
if (player != NULL)
|
||||
if (player != nullptr)
|
||||
{
|
||||
result.push_back(StringUtils::WideToUtf8(player->getName()));
|
||||
}
|
||||
@@ -280,13 +280,13 @@ namespace ServerRuntime
|
||||
std::shared_ptr<ServerPlayer> ServerCliEngine::FindPlayerByNameUtf8(const std::string &name) const
|
||||
{
|
||||
MinecraftServer *server = MinecraftServer::getInstance();
|
||||
if (server == NULL)
|
||||
if (server == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PlayerList *players = server->getPlayers();
|
||||
if (players == NULL)
|
||||
if (players == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -295,7 +295,7 @@ namespace ServerRuntime
|
||||
for (size_t i = 0; i < players->players.size(); ++i)
|
||||
{
|
||||
std::shared_ptr<ServerPlayer> player = players->players[i];
|
||||
if (player != NULL && equalsIgnoreCase(player->getName(), target))
|
||||
if (player != nullptr && equalsIgnoreCase(player->getName(), target))
|
||||
{
|
||||
return player;
|
||||
}
|
||||
@@ -345,28 +345,28 @@ namespace ServerRuntime
|
||||
return GameType::CREATIVE;
|
||||
}
|
||||
|
||||
char *end = NULL;
|
||||
char *end = nullptr;
|
||||
long id = strtol(lowered.c_str(), &end, 10);
|
||||
if (end != NULL && *end == 0)
|
||||
if (end != nullptr && *end == 0)
|
||||
{
|
||||
// Numeric fallback supports extended ids handled by level settings.
|
||||
return LevelSettings::validateGameType((int)id);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ServerCliEngine::DispatchWorldCommand(EGameCommand command, byteArray commandData, const std::shared_ptr<CommandSender> &sender) const
|
||||
{
|
||||
MinecraftServer *server = MinecraftServer::getInstance();
|
||||
if (server == NULL)
|
||||
if (server == nullptr)
|
||||
{
|
||||
LogWarn("MinecraftServer instance is not available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
CommandDispatcher *dispatcher = server->getCommandDispatcher();
|
||||
if (dispatcher == NULL)
|
||||
if (dispatcher == nullptr)
|
||||
{
|
||||
LogWarn("Command dispatcher is not available.");
|
||||
return false;
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace
|
||||
bool UseStreamInputMode()
|
||||
{
|
||||
const char *mode = getenv("SERVER_CLI_INPUT_MODE");
|
||||
if (mode != NULL)
|
||||
if (mode != nullptr)
|
||||
{
|
||||
return _stricmp(mode, "stream") == 0
|
||||
|| _stricmp(mode, "stdin") == 0;
|
||||
@@ -25,7 +25,7 @@ namespace
|
||||
|
||||
int WaitForStdinReadable(HANDLE stdinHandle, DWORD waitMs)
|
||||
{
|
||||
if (stdinHandle == NULL || stdinHandle == INVALID_HANDLE_VALUE)
|
||||
if (stdinHandle == nullptr || stdinHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -34,7 +34,7 @@ namespace
|
||||
if (fileType == FILE_TYPE_PIPE)
|
||||
{
|
||||
DWORD available = 0;
|
||||
if (!PeekNamedPipe(stdinHandle, NULL, 0, NULL, &available, NULL))
|
||||
if (!PeekNamedPipe(stdinHandle, nullptr, 0, nullptr, &available, nullptr))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -64,11 +64,11 @@ namespace
|
||||
namespace ServerRuntime
|
||||
{
|
||||
// C-style completion callback bridge requires a static instance pointer.
|
||||
ServerCliInput *ServerCliInput::s_instance = NULL;
|
||||
ServerCliInput *ServerCliInput::s_instance = nullptr;
|
||||
|
||||
ServerCliInput::ServerCliInput()
|
||||
: m_running(false)
|
||||
, m_engine(NULL)
|
||||
, m_engine(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace ServerRuntime
|
||||
|
||||
void ServerCliInput::Start(ServerCliEngine *engine)
|
||||
{
|
||||
if (engine == NULL || m_running.exchange(true))
|
||||
if (engine == nullptr || m_running.exchange(true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -107,14 +107,14 @@ namespace ServerRuntime
|
||||
CancelSynchronousIo((HANDLE)m_inputThread.native_handle());
|
||||
m_inputThread.join();
|
||||
}
|
||||
linenoiseSetCompletionCallback(NULL);
|
||||
linenoiseSetCompletionCallback(nullptr);
|
||||
|
||||
if (s_instance == this)
|
||||
{
|
||||
s_instance = NULL;
|
||||
s_instance = nullptr;
|
||||
}
|
||||
|
||||
m_engine = NULL;
|
||||
m_engine = nullptr;
|
||||
LogInfo("console", "CLI input thread stopped.");
|
||||
}
|
||||
|
||||
@@ -143,9 +143,9 @@ namespace ServerRuntime
|
||||
while (m_running)
|
||||
{
|
||||
char *line = linenoise("server> ");
|
||||
if (line == NULL)
|
||||
if (line == nullptr)
|
||||
{
|
||||
// NULL is expected on stop request (or Ctrl+C inside linenoise).
|
||||
// nullptr is expected on stop request (or Ctrl+C inside linenoise).
|
||||
if (!m_running)
|
||||
{
|
||||
break;
|
||||
@@ -166,7 +166,7 @@ namespace ServerRuntime
|
||||
void ServerCliInput::RunStreamInputLoop()
|
||||
{
|
||||
HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (stdinHandle == NULL || stdinHandle == INVALID_HANDLE_VALUE)
|
||||
if (stdinHandle == nullptr || stdinHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LogWarn("console", "stream input mode requested but STDIN handle is unavailable; falling back to linenoise.");
|
||||
RunLinenoiseLoop();
|
||||
@@ -190,7 +190,7 @@ namespace ServerRuntime
|
||||
|
||||
char ch = 0;
|
||||
DWORD bytesRead = 0;
|
||||
if (!ReadFile(stdinHandle, &ch, 1, &bytesRead, NULL) || bytesRead == 0)
|
||||
if (!ReadFile(stdinHandle, &ch, 1, &bytesRead, nullptr) || bytesRead == 0)
|
||||
{
|
||||
Sleep(10);
|
||||
continue;
|
||||
@@ -249,7 +249,7 @@ namespace ServerRuntime
|
||||
|
||||
void ServerCliInput::EnqueueLine(const char *line)
|
||||
{
|
||||
if (line == NULL || line[0] == 0 || m_engine == NULL)
|
||||
if (line == nullptr || line[0] == 0 || m_engine == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -262,7 +262,7 @@ namespace ServerRuntime
|
||||
void ServerCliInput::CompletionThunk(const char *line, linenoiseCompletions *completions)
|
||||
{
|
||||
// Static thunk forwards callback into instance state.
|
||||
if (s_instance != NULL)
|
||||
if (s_instance != nullptr)
|
||||
{
|
||||
s_instance->BuildCompletions(line, completions);
|
||||
}
|
||||
@@ -270,7 +270,7 @@ namespace ServerRuntime
|
||||
|
||||
void ServerCliInput::BuildCompletions(const char *line, linenoiseCompletions *completions)
|
||||
{
|
||||
if (line == NULL || completions == NULL || m_engine == NULL)
|
||||
if (line == nullptr || completions == nullptr || m_engine == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace ServerRuntime
|
||||
auto it = m_lookup.find(key);
|
||||
if (it == m_lookup.end())
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
@@ -63,7 +63,7 @@ namespace ServerRuntime
|
||||
auto it = m_lookup.find(key);
|
||||
if (it == m_lookup.end())
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace ServerRuntime
|
||||
|
||||
static void ResetConnectionLogEntry(ConnectionLogEntry *entry)
|
||||
{
|
||||
if (entry == NULL)
|
||||
if (entry == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -58,7 +58,7 @@ namespace ServerRuntime
|
||||
|
||||
static std::string NormalizeRemoteIp(const char *ip)
|
||||
{
|
||||
if (ip == NULL || ip[0] == 0)
|
||||
if (ip == nullptr || ip[0] == 0)
|
||||
{
|
||||
return std::string("unknown");
|
||||
}
|
||||
@@ -80,7 +80,7 @@ namespace ServerRuntime
|
||||
// Default to the main app channel when the caller does not provide a source tag.
|
||||
static const char *NormalizeClientLogSource(const char *source)
|
||||
{
|
||||
if (source == NULL || source[0] == 0)
|
||||
if (source == nullptr || source[0] == 0)
|
||||
{
|
||||
return "app";
|
||||
}
|
||||
@@ -101,7 +101,7 @@ namespace ServerRuntime
|
||||
// Split one debug payload into individual lines so each line becomes a prompt-safe server log entry.
|
||||
static void ForwardClientDebugMessage(const char *source, const char *message)
|
||||
{
|
||||
if (message == NULL || message[0] == 0)
|
||||
if (message == nullptr || message[0] == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -131,7 +131,7 @@ namespace ServerRuntime
|
||||
// Share the same formatting path for app, user, and legacy debug-spew forwards.
|
||||
static void ForwardFormattedClientDebugLogV(const char *source, const char *format, va_list args)
|
||||
{
|
||||
if (!IsDedicatedServerLoggingEnabled() || format == NULL || format[0] == 0)
|
||||
if (!IsDedicatedServerLoggingEnabled() || format == nullptr || format[0] == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -376,7 +376,7 @@ namespace ServerRuntime
|
||||
*/
|
||||
bool TryGetConnectionRemoteIp(unsigned char smallId, std::string *outIp)
|
||||
{
|
||||
if (!IsDedicatedServerLoggingEnabled() || outIp == NULL)
|
||||
if (!IsDedicatedServerLoggingEnabled() || outIp == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ static int ClampInt(int value, int minValue, int maxValue)
|
||||
|
||||
static bool TryParseBool(const std::string &value, bool *outValue)
|
||||
{
|
||||
if (outValue == NULL)
|
||||
if (outValue == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -138,7 +138,7 @@ static bool TryParseBool(const std::string &value, bool *outValue)
|
||||
|
||||
static bool TryParseInt(const std::string &value, int *outValue)
|
||||
{
|
||||
if (outValue == NULL)
|
||||
if (outValue == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -149,7 +149,7 @@ static bool TryParseInt(const std::string &value, int *outValue)
|
||||
return false;
|
||||
}
|
||||
|
||||
char *end = NULL;
|
||||
char *end = nullptr;
|
||||
long parsed = strtol(trimmed.c_str(), &end, 10);
|
||||
if (end == trimmed.c_str() || *end != 0)
|
||||
{
|
||||
@@ -162,7 +162,7 @@ static bool TryParseInt(const std::string &value, int *outValue)
|
||||
|
||||
static bool TryParseInt64(const std::string &value, __int64 *outValue)
|
||||
{
|
||||
if (outValue == NULL)
|
||||
if (outValue == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -173,7 +173,7 @@ static bool TryParseInt64(const std::string &value, __int64 *outValue)
|
||||
return false;
|
||||
}
|
||||
|
||||
char *end = NULL;
|
||||
char *end = nullptr;
|
||||
__int64 parsed = _strtoi64(trimmed.c_str(), &end, 10);
|
||||
if (end == trimmed.c_str() || *end != 0)
|
||||
{
|
||||
@@ -265,7 +265,7 @@ static std::string NormalizeSaveId(const std::string &source)
|
||||
|
||||
static void ApplyDefaultServerProperties(std::unordered_map<std::string, std::string> *properties)
|
||||
{
|
||||
if (properties == NULL)
|
||||
if (properties == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -288,13 +288,13 @@ static void ApplyDefaultServerProperties(std::unordered_map<std::string, std::st
|
||||
*/
|
||||
static bool ReadServerPropertiesFile(const char *filePath, std::unordered_map<std::string, std::string> *properties, int *outParsedCount)
|
||||
{
|
||||
if (properties == NULL)
|
||||
if (properties == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string text;
|
||||
if (filePath == NULL || !FileUtils::ReadTextFile(filePath, &text))
|
||||
if (filePath == nullptr || !FileUtils::ReadTextFile(filePath, &text))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -373,7 +373,7 @@ static bool ReadServerPropertiesFile(const char *filePath, std::unordered_map<st
|
||||
start = nextStart;
|
||||
}
|
||||
|
||||
if (outParsedCount != NULL)
|
||||
if (outParsedCount != nullptr)
|
||||
{
|
||||
*outParsedCount = parsedCount;
|
||||
}
|
||||
@@ -390,7 +390,7 @@ static bool ReadServerPropertiesFile(const char *filePath, std::unordered_map<st
|
||||
*/
|
||||
static bool WriteServerPropertiesFile(const char *filePath, const std::unordered_map<std::string, std::string> &properties)
|
||||
{
|
||||
if (filePath == NULL)
|
||||
if (filePath == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -428,7 +428,7 @@ static bool ReadNormalizedBoolProperty(
|
||||
if (raw != normalized)
|
||||
{
|
||||
(*properties)[key] = normalized;
|
||||
if (shouldWrite != NULL)
|
||||
if (shouldWrite != nullptr)
|
||||
{
|
||||
*shouldWrite = true;
|
||||
}
|
||||
@@ -457,7 +457,7 @@ static int ReadNormalizedIntProperty(
|
||||
if (raw != normalized)
|
||||
{
|
||||
(*properties)[key] = normalized;
|
||||
if (shouldWrite != NULL)
|
||||
if (shouldWrite != nullptr)
|
||||
{
|
||||
*shouldWrite = true;
|
||||
}
|
||||
@@ -486,7 +486,7 @@ static std::string ReadNormalizedStringProperty(
|
||||
if (value != (*properties)[key])
|
||||
{
|
||||
(*properties)[key] = value;
|
||||
if (shouldWrite != NULL)
|
||||
if (shouldWrite != nullptr)
|
||||
{
|
||||
*shouldWrite = true;
|
||||
}
|
||||
@@ -507,7 +507,7 @@ static bool ReadNormalizedOptionalInt64Property(
|
||||
if ((*properties)[key] != "")
|
||||
{
|
||||
(*properties)[key] = "";
|
||||
if (shouldWrite != NULL)
|
||||
if (shouldWrite != nullptr)
|
||||
{
|
||||
*shouldWrite = true;
|
||||
}
|
||||
@@ -519,7 +519,7 @@ static bool ReadNormalizedOptionalInt64Property(
|
||||
if (!TryParseInt64(raw, &parsed))
|
||||
{
|
||||
(*properties)[key] = "";
|
||||
if (shouldWrite != NULL)
|
||||
if (shouldWrite != nullptr)
|
||||
{
|
||||
*shouldWrite = true;
|
||||
}
|
||||
@@ -530,13 +530,13 @@ static bool ReadNormalizedOptionalInt64Property(
|
||||
if (raw != normalized)
|
||||
{
|
||||
(*properties)[key] = normalized;
|
||||
if (shouldWrite != NULL)
|
||||
if (shouldWrite != nullptr)
|
||||
{
|
||||
*shouldWrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (outValue != NULL)
|
||||
if (outValue != nullptr)
|
||||
{
|
||||
*outValue = parsed;
|
||||
}
|
||||
@@ -560,7 +560,7 @@ static EServerLogLevel ReadNormalizedLogLevelProperty(
|
||||
if (raw != normalized)
|
||||
{
|
||||
(*properties)[key] = normalized;
|
||||
if (shouldWrite != NULL)
|
||||
if (shouldWrite != nullptr)
|
||||
{
|
||||
*shouldWrite = true;
|
||||
}
|
||||
@@ -594,13 +594,13 @@ static std::string ReadNormalizedLevelTypeProperty(
|
||||
if (raw != normalized)
|
||||
{
|
||||
(*properties)[key] = normalized;
|
||||
if (shouldWrite != NULL)
|
||||
if (shouldWrite != nullptr)
|
||||
{
|
||||
*shouldWrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (outIsFlat != NULL)
|
||||
if (outIsFlat != nullptr)
|
||||
{
|
||||
*outIsFlat = isFlat;
|
||||
}
|
||||
@@ -658,7 +658,7 @@ static int WorldSizeToHellScale(int worldSize)
|
||||
|
||||
static bool TryParseWorldSize(const std::string &lowered, int *outWorldSize)
|
||||
{
|
||||
if (outWorldSize == NULL)
|
||||
if (outWorldSize == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -712,17 +712,17 @@ static int ReadNormalizedWorldSizeProperty(
|
||||
if (raw != normalized)
|
||||
{
|
||||
(*properties)[key] = normalized;
|
||||
if (shouldWrite != NULL)
|
||||
if (shouldWrite != nullptr)
|
||||
{
|
||||
*shouldWrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (outXzChunks != NULL)
|
||||
if (outXzChunks != nullptr)
|
||||
{
|
||||
*outXzChunks = WorldSizeToXzChunks(worldSize);
|
||||
}
|
||||
if (outHellScale != NULL)
|
||||
if (outHellScale != nullptr)
|
||||
{
|
||||
*outHellScale = WorldSizeToHellScale(worldSize);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "../../Minecraft.World/TilePos.h"
|
||||
#include "../../Minecraft.World/compression.h"
|
||||
#include "../../Minecraft.World/OldChunkStorage.h"
|
||||
#include "../../Minecraft.World/ConsoleSaveFileOriginal.h"
|
||||
#include "../../Minecraft.World/net.minecraft.world.level.tile.h"
|
||||
#include "../../Minecraft.World/Random.h"
|
||||
|
||||
@@ -183,10 +184,10 @@ using ServerRuntime::WorldBootstrapResult;
|
||||
|
||||
static bool ParseIntArg(const char *value, int *outValue)
|
||||
{
|
||||
if (value == NULL || *value == 0)
|
||||
if (value == nullptr || *value == 0)
|
||||
return false;
|
||||
|
||||
char *end = NULL;
|
||||
char *end = nullptr;
|
||||
long parsed = strtol(value, &end, 10);
|
||||
if (end == value || *end != 0)
|
||||
return false;
|
||||
@@ -197,10 +198,10 @@ static bool ParseIntArg(const char *value, int *outValue)
|
||||
|
||||
static bool ParseInt64Arg(const char *value, __int64 *outValue)
|
||||
{
|
||||
if (value == NULL || *value == 0)
|
||||
if (value == nullptr || *value == 0)
|
||||
return false;
|
||||
|
||||
char *end = NULL;
|
||||
char *end = nullptr;
|
||||
__int64 parsed = _strtoi64(value, &end, 10);
|
||||
if (end == value || *end != 0)
|
||||
return false;
|
||||
@@ -277,9 +278,9 @@ static bool ParseCommandLine(int argc, char **argv, DedicatedServerConfig *confi
|
||||
static void SetExeWorkingDirectory()
|
||||
{
|
||||
char exePath[MAX_PATH] = {};
|
||||
GetModuleFileNameA(NULL, exePath, MAX_PATH);
|
||||
GetModuleFileNameA(nullptr, exePath, MAX_PATH);
|
||||
char *slash = strrchr(exePath, '\\');
|
||||
if (slash != NULL)
|
||||
if (slash != nullptr)
|
||||
{
|
||||
*(slash + 1) = 0;
|
||||
SetCurrentDirectoryA(exePath);
|
||||
@@ -288,7 +289,7 @@ static void SetExeWorkingDirectory()
|
||||
|
||||
static void ApplyServerPropertiesToDedicatedConfig(const ServerPropertiesConfig &serverProperties, DedicatedServerConfig *config)
|
||||
{
|
||||
if (config == NULL)
|
||||
if (config == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -325,6 +326,7 @@ static void TickCoreSystems()
|
||||
g_NetworkManager.DoWork();
|
||||
ProfileManager.Tick();
|
||||
StorageManager.Tick();
|
||||
ConsoleSaveFileOriginal::flushPendingBackgroundSave();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,7 +422,7 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
|
||||
LogStartupStep("registering hidden window class");
|
||||
HINSTANCE hInstance = GetModuleHandle(NULL);
|
||||
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
||||
MyRegisterClass(hInstance);
|
||||
|
||||
LogStartupStep("creating hidden window");
|
||||
@@ -490,7 +492,7 @@ int main(int argc, char **argv)
|
||||
LogStartupStep("creating Minecraft singleton");
|
||||
Minecraft::main();
|
||||
Minecraft *minecraft = Minecraft::GetInstance();
|
||||
if (minecraft == NULL)
|
||||
if (minecraft == nullptr)
|
||||
{
|
||||
LogError("startup", "Minecraft initialization failed.");
|
||||
CleanupDevice();
|
||||
@@ -655,7 +657,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
if (autosaveRequested && app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle)
|
||||
if (autosaveRequested && app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle && !ConsoleSaveFileOriginal::hasPendingBackgroundSave())
|
||||
{
|
||||
LogWorldIO("autosave completed");
|
||||
autosaveRequested = false;
|
||||
@@ -669,7 +671,7 @@ int main(int argc, char **argv)
|
||||
DWORD now = GetTickCount();
|
||||
if ((LONG)(now - nextAutosaveTick) >= 0)
|
||||
{
|
||||
if (app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle)
|
||||
if (app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle && !ConsoleSaveFileOriginal::hasPendingBackgroundSave())
|
||||
{
|
||||
LogWorldIO("requesting autosave");
|
||||
app.SetXuiServerAction(kServerActionPad, eXuiServerAction_AutoSaveGame);
|
||||
@@ -685,25 +687,38 @@ int main(int argc, char **argv)
|
||||
|
||||
LogInfof("shutdown", "Dedicated server stopped");
|
||||
MinecraftServer *server = MinecraftServer::getInstance();
|
||||
if (server != NULL)
|
||||
if (server != nullptr && !ConsoleSaveFileOriginal::hasPendingBackgroundSave())
|
||||
{
|
||||
server->setSaveOnExit(true);
|
||||
}
|
||||
if (server != NULL)
|
||||
{
|
||||
LogWorldIO("requesting save before shutdown");
|
||||
LogWorldIO("using saveOnExit for shutdown");
|
||||
}
|
||||
|
||||
if (ConsoleSaveFileOriginal::hasPendingBackgroundSave())
|
||||
{
|
||||
LogWorldIO("Waiting for autosave to complete...");
|
||||
}
|
||||
|
||||
MinecraftServer::HaltServer();
|
||||
|
||||
if (g_NetworkManager.ServerStoppedValid())
|
||||
{
|
||||
C4JThread waitThread(&WaitForServerStoppedThreadProc, NULL, "WaitServerStopped");
|
||||
C4JThread waitThread(&WaitForServerStoppedThreadProc, nullptr, "WaitServerStopped");
|
||||
waitThread.Run();
|
||||
while (waitThread.isRunning())
|
||||
{
|
||||
TickCoreSystems();
|
||||
Sleep(10);
|
||||
}
|
||||
waitThread.WaitForCompletion(INFINITE);
|
||||
}
|
||||
|
||||
while (ConsoleSaveFileOriginal::hasPendingBackgroundSave())
|
||||
{
|
||||
TickCoreSystems();
|
||||
Sleep(10);
|
||||
}
|
||||
|
||||
LogInfof("shutdown", "Cleaning up and exiting.");
|
||||
WinsockNetLayer::Shutdown();
|
||||
LogDebugf("shutdown", "Network layer shutdown complete.");
|
||||
@@ -714,5 +729,4 @@ int main(int argc, char **argv)
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,7 +31,7 @@ struct SaveInfoQueryContext
|
||||
SaveInfoQueryContext()
|
||||
: done(false)
|
||||
, success(false)
|
||||
, details(NULL)
|
||||
, details(nullptr)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -75,7 +75,7 @@ static void SetStorageSaveUniqueFilename(const std::string &saveFilename)
|
||||
|
||||
static void LogSaveFilename(const char *prefix, const std::string &saveFilename)
|
||||
{
|
||||
LogInfof("world-io", "%s: %s", (prefix != NULL) ? prefix : "save-filename", saveFilename.c_str());
|
||||
LogInfof("world-io", "%s: %s", (prefix != nullptr) ? prefix : "save-filename", saveFilename.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,7 +86,7 @@ static void LogSaveFilename(const char *prefix, const std::string &saveFilename)
|
||||
*/
|
||||
static bool EnsureDirectoryExists(const std::wstring &directoryPath, bool *outCreated)
|
||||
{
|
||||
if (outCreated != NULL)
|
||||
if (outCreated != nullptr)
|
||||
{
|
||||
*outCreated = false;
|
||||
}
|
||||
@@ -107,9 +107,9 @@ static bool EnsureDirectoryExists(const std::wstring &directoryPath, bool *outCr
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CreateDirectoryW(directoryPath.c_str(), NULL))
|
||||
if (CreateDirectoryW(directoryPath.c_str(), nullptr))
|
||||
{
|
||||
if (outCreated != NULL)
|
||||
if (outCreated != nullptr)
|
||||
{
|
||||
*outCreated = true;
|
||||
}
|
||||
@@ -189,7 +189,7 @@ static void LogEnumeratedSaveInfo(int index, const SAVE_INFO &saveInfo)
|
||||
static int GetSavesInfoCallbackProc(LPVOID lpParam, SAVE_DETAILS *pSaveDetails, const bool bRes)
|
||||
{
|
||||
SaveInfoQueryContext *context = (SaveInfoQueryContext *)lpParam;
|
||||
if (context != NULL)
|
||||
if (context != nullptr)
|
||||
{
|
||||
context->details = pSaveDetails;
|
||||
context->success = bRes;
|
||||
@@ -207,7 +207,7 @@ static int GetSavesInfoCallbackProc(LPVOID lpParam, SAVE_DETAILS *pSaveDetails,
|
||||
static int LoadSaveDataCallbackProc(LPVOID lpParam, const bool bIsCorrupt, const bool bIsOwner)
|
||||
{
|
||||
SaveDataLoadContext *context = (SaveDataLoadContext *)lpParam;
|
||||
if (context != NULL)
|
||||
if (context != nullptr)
|
||||
{
|
||||
context->isCorrupt = bIsCorrupt;
|
||||
context->isOwner = bIsOwner;
|
||||
@@ -236,12 +236,12 @@ static bool WaitForSaveInfoResult(SaveInfoQueryContext *context, DWORD timeoutMs
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context->details == NULL)
|
||||
if (context->details == nullptr)
|
||||
{
|
||||
// Some implementations fill ReturnSavesInfo before the callback
|
||||
// Keep polling as a fallback instead of relying only on callback completion
|
||||
SAVE_DETAILS *details = StorageManager.ReturnSavesInfo();
|
||||
if (details != NULL)
|
||||
if (details != nullptr)
|
||||
{
|
||||
context->details = details;
|
||||
context->success = true;
|
||||
@@ -250,7 +250,7 @@ static bool WaitForSaveInfoResult(SaveInfoQueryContext *context, DWORD timeoutMs
|
||||
}
|
||||
}
|
||||
|
||||
if (tickProc != NULL)
|
||||
if (tickProc != nullptr)
|
||||
{
|
||||
tickProc();
|
||||
}
|
||||
@@ -278,7 +278,7 @@ static bool WaitForSaveLoadResult(SaveDataLoadContext *context, DWORD timeoutMs,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tickProc != NULL)
|
||||
if (tickProc != nullptr)
|
||||
{
|
||||
tickProc();
|
||||
}
|
||||
@@ -370,12 +370,12 @@ static EWorldSaveLoadResult PrepareWorldSaveData(
|
||||
LoadSaveDataThreadParam **outSaveData,
|
||||
std::string *outResolvedSaveFilename)
|
||||
{
|
||||
if (outSaveData == NULL)
|
||||
if (outSaveData == nullptr)
|
||||
{
|
||||
return eWorldSaveLoad_Failed;
|
||||
}
|
||||
*outSaveData = NULL;
|
||||
if (outResolvedSaveFilename != NULL)
|
||||
*outSaveData = nullptr;
|
||||
if (outResolvedSaveFilename != nullptr)
|
||||
{
|
||||
outResolvedSaveFilename->clear();
|
||||
}
|
||||
@@ -404,11 +404,11 @@ static EWorldSaveLoadResult PrepareWorldSaveData(
|
||||
return eWorldSaveLoad_Failed;
|
||||
}
|
||||
|
||||
if (infoContext.details == NULL)
|
||||
if (infoContext.details == nullptr)
|
||||
{
|
||||
infoContext.details = StorageManager.ReturnSavesInfo();
|
||||
}
|
||||
if (infoContext.details == NULL)
|
||||
if (infoContext.details == nullptr)
|
||||
{
|
||||
LogWorldIO("failed to retrieve save list");
|
||||
return eWorldSaveLoad_Failed;
|
||||
@@ -486,7 +486,7 @@ static EWorldSaveLoadResult PrepareWorldSaveData(
|
||||
resolvedSaveFilename = targetSaveFilename;
|
||||
}
|
||||
|
||||
if (outResolvedSaveFilename != NULL)
|
||||
if (outResolvedSaveFilename != nullptr)
|
||||
{
|
||||
*outResolvedSaveFilename = resolvedSaveFilename;
|
||||
}
|
||||
@@ -621,11 +621,11 @@ bool WaitForWorldActionIdle(
|
||||
{
|
||||
// Keep network and storage progressing while waiting
|
||||
// If this stops, save action itself may stall and time out
|
||||
if (tickProc != NULL)
|
||||
if (tickProc != nullptr)
|
||||
{
|
||||
tickProc();
|
||||
}
|
||||
if (handleActionsProc != NULL)
|
||||
if (handleActionsProc != nullptr)
|
||||
{
|
||||
handleActionsProc();
|
||||
}
|
||||
|
||||
@@ -496,6 +496,8 @@ set(_MINECRAFT_SERVER_COMMON_ROOT
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/iob_shim.asm"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/stdafx.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/stubs.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.World/ConsoleSaveFileOriginal.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.World/ConsoleSaveFileOriginal.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../include/lce_filesystem/lce_filesystem.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Console/ServerCliInput.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Console/ServerCliInput.h"
|
||||
|
||||
@@ -12,6 +12,25 @@
|
||||
#include "..\Minecraft.Client\Common\GameRules\LevelGenerationOptions.h"
|
||||
#include "..\Minecraft.World\net.minecraft.world.level.chunk.storage.h"
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
static std::atomic<bool> s_bgSaveActive{false};
|
||||
static std::mutex s_bgSaveMutex;
|
||||
|
||||
struct BackgroundSaveResult
|
||||
{
|
||||
ConsoleSaveFile *owner = nullptr;
|
||||
PBYTE thumbData = nullptr;
|
||||
DWORD thumbSize = 0;
|
||||
BYTE textMeta[88] = {};
|
||||
int textMetaBytes = 0;
|
||||
bool pending = false;
|
||||
};
|
||||
static BackgroundSaveResult s_bgResult;
|
||||
#endif
|
||||
|
||||
#ifdef _XBOX
|
||||
#define RESERVE_ALLOCATION MEM_RESERVE | MEM_LARGE_PAGES
|
||||
@@ -219,7 +238,7 @@ ConsoleSaveFileOriginal::~ConsoleSaveFileOriginal()
|
||||
pagesCommitted = 0;
|
||||
// Make sure we don't have any thumbnail data still waiting round - we can't need it now we've destroyed the save file anyway
|
||||
#if defined _XBOX
|
||||
app.GetSaveThumbnail(NULL,NULL);
|
||||
app.GetSaveThumbnail(nullptr,nullptr);
|
||||
#elif defined __PS3__
|
||||
app.GetSaveThumbnail(nullptr,nullptr, nullptr,nullptr);
|
||||
#endif
|
||||
@@ -478,7 +497,7 @@ void ConsoleSaveFileOriginal::finalizeWrite()
|
||||
{
|
||||
unsigned int pagesRequired = ( desiredSize + (CSF_PAGE_SIZE - 1 ) ) / CSF_PAGE_SIZE;
|
||||
void *pvRet = VirtualAlloc(pvHeap, pagesRequired * CSF_PAGE_SIZE, COMMIT_ALLOCATION, PAGE_READWRITE);
|
||||
if( pvRet == NULL )
|
||||
if( pvRet == nullptr )
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
@@ -678,6 +697,83 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail )
|
||||
|
||||
unsigned int fileSize = header.GetFileSize();
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
// on the server we dont want to block the tick thread doing compression!!!
|
||||
// sna[pshot pvSaveMem while we still hold the lock then hand it off to a background thread
|
||||
byte *snap = new (std::nothrow) byte[fileSize];
|
||||
if (snap)
|
||||
{
|
||||
// copy the save buffer while we still own the lock so nothing can write to it mid-copy
|
||||
QueryPerformanceCounter(&qwTime);
|
||||
memcpy(snap, pvSaveMem, fileSize);
|
||||
QueryPerformanceCounter(&qwNewTime);
|
||||
app.DebugPrintf("snapshot %u bytes in %.3f sec\n", fileSize,
|
||||
(qwNewTime.QuadPart - qwTime.QuadPart) * fSecsPerTick);
|
||||
|
||||
PBYTE thumb = nullptr;
|
||||
DWORD thumbSz = 0;
|
||||
app.GetSaveThumbnail(&thumb, &thumbSz);
|
||||
|
||||
BYTE meta[88];
|
||||
ZeroMemory(meta, 88);
|
||||
int64_t seed = 0;
|
||||
bool hasSeed = false;
|
||||
if (MinecraftServer *sv = MinecraftServer::getInstance(); sv && sv->levels[0])
|
||||
{
|
||||
seed = sv->levels[0]->getLevelData()->getSeed();
|
||||
hasSeed = true;
|
||||
}
|
||||
int metaLen = app.CreateImageTextData(meta, seed, hasSeed,
|
||||
app.GetGameHostOption(eGameHostOption_All), Minecraft::GetInstance()->getCurrentTexturePackId());
|
||||
|
||||
// telemetry
|
||||
INT uid = 0;
|
||||
StorageManager.GetSaveUniqueNumber(&uid);
|
||||
TelemetryManager->RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), uid, fileSize);
|
||||
|
||||
ReleaseSaveAccess();
|
||||
s_bgSaveActive.store(true, std::memory_order_release);
|
||||
|
||||
std::thread([snap, fileSize, thumb, thumbSz, meta, metaLen, this]() {
|
||||
unsigned int compLen = fileSize + 8;
|
||||
byte *buf = static_cast<byte *>(StorageManager.AllocateSaveData(compLen));
|
||||
if (!buf)
|
||||
{
|
||||
// FAIL!! attempt precalc
|
||||
compLen = 0;
|
||||
Compression::getCompression()->Compress(nullptr, &compLen, snap, fileSize);
|
||||
compLen += 8;
|
||||
buf = static_cast<byte *>(StorageManager.AllocateSaveData(compLen));
|
||||
}
|
||||
if (buf)
|
||||
{
|
||||
// COM,PRESS
|
||||
Compression::getCompression()->Compress(buf + 8, &compLen, snap, fileSize);
|
||||
ZeroMemory(buf, 8);
|
||||
memcpy(buf + 4, &fileSize, sizeof(fileSize));
|
||||
|
||||
// store the result so flushPendingBackgroundSave() can pick it up on the main thread next tick
|
||||
// StorageManager isnt thread safe so we cant call SetSaveImages or SaveSaveData from here. Bwoomp
|
||||
std::lock_guard<std::mutex> lk(s_bgSaveMutex);
|
||||
s_bgResult.owner = this;
|
||||
s_bgResult.thumbData = thumb;
|
||||
s_bgResult.thumbSize = thumbSz;
|
||||
memcpy(s_bgResult.textMeta, meta, sizeof(meta));
|
||||
s_bgResult.textMetaBytes = metaLen;
|
||||
s_bgResult.pending = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
app.DebugPrintf("save buf alloc failed\n");
|
||||
s_bgSaveActive.store(false, std::memory_order_release);
|
||||
}
|
||||
delete[] snap;
|
||||
}).detach();
|
||||
return;
|
||||
}
|
||||
app.DebugPrintf("snapshot alloc failed (%u bytes)\n", fileSize);
|
||||
#endif
|
||||
|
||||
// Assume that the compression will make it smaller so initially attempt to allocate the current file size
|
||||
// We add 4 bytes to the start so that we can signal compressed data
|
||||
// And another 4 bytes to store the decompressed data size
|
||||
@@ -843,6 +939,10 @@ int ConsoleSaveFileOriginal::SaveSaveDataCallback(LPVOID lpParam,bool bRes)
|
||||
{
|
||||
ConsoleSaveFile *pClass=static_cast<ConsoleSaveFile *>(lpParam);
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
s_bgSaveActive.store(false, std::memory_order_release);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1090,3 +1190,26 @@ void *ConsoleSaveFileOriginal::getWritePointer(FileEntry *file)
|
||||
{
|
||||
return static_cast<char *>(pvSaveMem) + file->currentFilePointer;;
|
||||
}
|
||||
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
void ConsoleSaveFileOriginal::flushPendingBackgroundSave()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(s_bgSaveMutex);
|
||||
if (!s_bgResult.pending)
|
||||
return;
|
||||
|
||||
StorageManager.SetSaveImages(
|
||||
s_bgResult.thumbData, s_bgResult.thumbSize,
|
||||
nullptr, 0, s_bgResult.textMeta, s_bgResult.textMetaBytes);
|
||||
StorageManager.SaveSaveData(&ConsoleSaveFileOriginal::SaveSaveDataCallback, s_bgResult.owner);
|
||||
|
||||
s_bgResult.pending = false;
|
||||
// the actual write isnt done until SaveSaveDataCallback fires
|
||||
}
|
||||
|
||||
bool ConsoleSaveFileOriginal::hasPendingBackgroundSave()
|
||||
{
|
||||
return s_bgSaveActive.load(std::memory_order_acquire);
|
||||
}
|
||||
#endif
|
||||
@@ -71,6 +71,11 @@ public:
|
||||
virtual vector<FileEntry *> *getValidPlayerDatFiles();
|
||||
#endif //__PS3__
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
static void flushPendingBackgroundSave();
|
||||
static bool hasPendingBackgroundSave();
|
||||
#endif
|
||||
|
||||
virtual int getSaveVersion();
|
||||
virtual int getOriginalSaveVersion();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user