TU19: merge Minecraft.Client/Level

This commit is contained in:
Tropical 2026-03-21 20:29:13 -05:00
parent 1c12bedc86
commit b319cb3cea
6 changed files with 417 additions and 175 deletions

View file

@ -9,9 +9,11 @@
#include "../MinecraftServer.h" #include "../MinecraftServer.h"
#include "ServerLevel.h" #include "ServerLevel.h"
#include "../Minecraft.h" #include "../Minecraft.h"
#include "../Rendering/Particles/FireworksParticles.h"
#include "../../Minecraft.World/Entities/Mobs/PrimedTnt.h" #include "../../Minecraft.World/Entities/Mobs/PrimedTnt.h"
#include "../../Minecraft.World/Blocks/Tile.h" #include "../../Minecraft.World/Blocks/Tile.h"
#include "../../Minecraft.World/Blocks/TileEntities/TileEntity.h" #include "../../Minecraft.World/Blocks/TileEntities/TileEntity.h"
#include "../../Minecraft.World/Util/JavaMath.h"
MultiPlayerLevel::ResetInfo::ResetInfo(int x, int y, int z, int tile, MultiPlayerLevel::ResetInfo::ResetInfo(int x, int y, int z, int tile,
int data) { int data) {
@ -53,10 +55,10 @@ MultiPlayerLevel::MultiPlayerLevel(ClientConnection* connection,
// multiplayer, this should only be set by receiving a packet from the // multiplayer, this should only be set by receiving a packet from the
// server (which happens when a player logs in) // server (which happens when a player logs in)
// setSpawnPos(new Pos(8, 64, 8)); // setSpawnPos(new Pos(8, 64, 8));
// The base ctor already has made some storage, so need to delete that // The base ctor already has made some storage, so need to delete that
if (this->savedDataStorage) delete savedDataStorage; if (this->savedDataStorage) delete savedDataStorage;
if (connection != NULL) { if (connection != NULL) {
this->savedDataStorage = connection->savedDataStorage; savedDataStorage = connection->savedDataStorage;
} }
unshareCheckX = 0; unshareCheckX = 0;
unshareCheckZ = 0; unshareCheckZ = 0;
@ -88,17 +90,30 @@ void MultiPlayerLevel::shareChunkAt(int x, int z) {
void MultiPlayerLevel::tick() { void MultiPlayerLevel::tick() {
PIXBeginNamedEvent(0, "Sky color changing"); PIXBeginNamedEvent(0, "Sky color changing");
setTime(getTime() + 1); setGameTime(getGameTime() + 1);
if (getGameRules()->getBoolean(GameRules::RULE_DAYLIGHT)) {
// 4J: Debug setting added to keep it at day time
#ifndef _FINAL_BUILD
bool freezeTime =
app.DebugSettingsOn() &&
app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) &
(1L << eDebugSetting_FreezeTime);
if (!freezeTime)
#endif
{
setDayTime(getDayTime() + 1);
}
}
/* 4J - change brought forward from 1.8.2 /* 4J - change brought forward from 1.8.2
int newDark = this->getSkyDarken(1); int newDark = this->getSkyDarken(1);
if (newDark != skyDarken) if (newDark != skyDarken)
{ {
skyDarken = newDark; skyDarken = newDark;
for (unsigned int i = 0; i < listeners.size(); i++) for (unsigned int i = 0; i < listeners.size(); i++)
{ {
listeners[i]->skyColorChanged(); listeners[i]->skyColorChanged();
} }
}*/ }*/
PIXEndNamedEvent(); PIXEndNamedEvent();
PIXBeginNamedEvent(0, "Entity re-entry"); PIXBeginNamedEvent(0, "Entity re-entry");
@ -128,7 +143,8 @@ if (newDark != skyDarken)
for (unsigned int i = 0; i < updatesToReset.size(); i++) { for (unsigned int i = 0; i < updatesToReset.size(); i++) {
ResetInfo& r = updatesToReset[i]; ResetInfo& r = updatesToReset[i];
if (--r.ticks == 0) { if (--r.ticks == 0) {
Level::setTileAndDataNoUpdate(r.x, r.y, r.z, r.tile, r.data); Level::setTileAndData(r.x, r.y, r.z, r.tile, r.data,
Tile::UPDATE_ALL);
Level::sendTileUpdated(r.x, r.y, r.z); Level::sendTileUpdated(r.x, r.y, r.z);
// updatesToReset.erase(updatesToReset.begin()+i); // updatesToReset.erase(updatesToReset.begin()+i);
@ -387,7 +403,7 @@ void MultiPlayerLevel::tickTiles() {
int xo = cp.x * 16; int xo = cp.x * 16;
int zo = cp.z * 16; int zo = cp.z * 16;
LevelChunk* lc = this->getChunk(cp.x, cp.z); LevelChunk* lc = getChunk(cp.x, cp.z);
tickClientSideTiles(xo, zo, lc); tickClientSideTiles(xo, zo, lc);
} }
@ -402,8 +418,8 @@ void MultiPlayerLevel::setChunkVisible(int x, int z, bool visible) {
chunkCache->drop(x, z); chunkCache->drop(x, z);
} }
if (!visible) { if (!visible) {
this->setTilesDirty(x * 16, 0, z * 16, x * 16 + 15, setTilesDirty(x * 16, 0, z * 16, x * 16 + 15, Level::maxBuildHeight,
Level::maxBuildHeight, z * 16 + 15); z * 16 + 15);
} }
} }
@ -456,7 +472,7 @@ void MultiPlayerLevel::putEntity(int id, std::shared_ptr<Entity> e) {
forced.insert(e); forced.insert(e);
e->entityId = id; e->entityId = id;
if (!addEntity(e)) { if (!addEntity(e)) {
this->reEntries.insert(e); reEntries.insert(e);
} }
entitiesById[id] = e; entitiesById[id] = e;
} }
@ -498,14 +514,32 @@ void MultiPlayerLevel::removeEntities(
Level::removeEntities(list); Level::removeEntities(list);
} }
bool MultiPlayerLevel::setDataNoUpdate(int x, int y, int z, int data) { bool MultiPlayerLevel::setData(
int t = getTile(x, y, z); int x, int y, int z, int data, int updateFlags,
bool forceUpdate /*=false*/) // 4J added forceUpdate)
{
// First check if this isn't going to do anything, because if it isn't then
// the next stage (of unsharing data) is really quite expensive so far
// better to early out here
int d = getData(x, y, z); int d = getData(x, y, z);
if ((d == data)) {
// If we early-out, its important that we still do a checkLight here
// (which would otherwise have happened as part of
// Level::setTileAndDataNoUpdate) This is because since we are
// potentially sharing tile/data but not lighting data, it is possible
// that the server might tell a client of a lighting update that doesn't
// need actioned on the client just because the chunk's data was being
// shared with the server when it was set. However, the lighting data
// will potentially now be out of sync on the client.
checkLight(x, y, z);
return false;
}
// 4J - added - if this is the host, then stop sharing block data with the // 4J - added - if this is the host, then stop sharing block data with the
// server at this point // server at this point
unshareChunkAt(x, z); unshareChunkAt(x, z);
if (Level::setDataNoUpdate(x, y, z, data)) { if (Level::setData(x, y, z, data, updateFlags, forceUpdate)) {
// if(m_bEnableResetChanges) updatesToReset.push_back(ResetInfo(x, y, z, // if(m_bEnableResetChanges) updatesToReset.push_back(ResetInfo(x, y, z,
// t, d)); // t, d));
return true; return true;
@ -515,8 +549,8 @@ bool MultiPlayerLevel::setDataNoUpdate(int x, int y, int z, int data) {
return false; return false;
} }
bool MultiPlayerLevel::setTileAndDataNoUpdate(int x, int y, int z, int tile, bool MultiPlayerLevel::setTileAndData(int x, int y, int z, int tile, int data,
int data) { int updateFlags) {
// First check if this isn't going to do anything, because if it isn't then // First check if this isn't going to do anything, because if it isn't then
// the next stage (of unsharing data) is really quite expensive so far // the next stage (of unsharing data) is really quite expensive so far
// better to early out here // better to early out here
@ -539,24 +573,7 @@ bool MultiPlayerLevel::setTileAndDataNoUpdate(int x, int y, int z, int tile,
// server at this point // server at this point
unshareChunkAt(x, z); unshareChunkAt(x, z);
if (Level::setTileAndDataNoUpdate(x, y, z, tile, data)) { if (Level::setTileAndData(x, y, z, tile, data, updateFlags)) {
// if(m_bEnableResetChanges) updatesToReset.push_back(ResetInfo(x, y, z,
// t, d));
return true;
}
// Didn't actually need to stop sharing
shareChunkAt(x, z);
return false;
}
bool MultiPlayerLevel::setTileNoUpdate(int x, int y, int z, int tile) {
int t = getTile(x, y, z);
int d = getData(x, y, z);
// 4J - added - if this is the host, then stop sharing block data with the
// server at this point
unshareChunkAt(x, z);
if (Level::setTileNoUpdate(x, y, z, tile)) {
// if(m_bEnableResetChanges) updatesToReset.push_back(ResetInfo(x, y, z, // if(m_bEnableResetChanges) updatesToReset.push_back(ResetInfo(x, y, z,
// t, d)); // t, d));
return true; return true;
@ -585,7 +602,7 @@ bool MultiPlayerLevel::doSetTileAndData(int x, int y, int z, int tile,
// If we're the host, need to tell the renderer for updates even if they // If we're the host, need to tell the renderer for updates even if they
// don't change things as the host might have been sharing data and so set // don't change things as the host might have been sharing data and so set
// it already, but the renderer won't know to update // it already, but the renderer won't know to update
if ((Level::setTileAndData(x, y, z, tile, data) || if ((Level::setTileAndData(x, y, z, tile, data, Tile::UPDATE_ALL) ||
g_NetworkManager.IsHost())) { g_NetworkManager.IsHost())) {
if (g_NetworkManager.IsHost() && visuallyImportant) { if (g_NetworkManager.IsHost() && visuallyImportant) {
// 4J Stu - This got removed from the tileUpdated function in TU14. // 4J Stu - This got removed from the tileUpdated function in TU14.
@ -613,13 +630,15 @@ void MultiPlayerLevel::disconnect(bool sendDisconnect /*= true*/) {
} }
} }
Tickable* MultiPlayerLevel::makeSoundUpdater(
std::shared_ptr<Minecart> minecart) {
return NULL; // new MinecartSoundUpdater(minecraft->soundEngine, minecart,
// minecraft->player);
}
void MultiPlayerLevel::tickWeather() { void MultiPlayerLevel::tickWeather() {
if (dimension->hasCeiling) return; if (dimension->hasCeiling) return;
if (lightningTime > 0) {
lightningTime--;
}
oRainLevel = rainLevel; oRainLevel = rainLevel;
if (levelData->isRaining()) { if (levelData->isRaining()) {
rainLevel += 0.01; rainLevel += 0.01;
@ -731,6 +750,7 @@ void MultiPlayerLevel::playSound(std::shared_ptr<Entity> entity, int iSound,
void MultiPlayerLevel::playLocalSound(double x, double y, double z, int iSound, void MultiPlayerLevel::playLocalSound(double x, double y, double z, int iSound,
float volume, float pitch, float volume, float pitch,
bool distanceDelay /*= false */,
float fClipSoundDist) { float fClipSoundDist) {
// float dd = 16; // float dd = 16;
if (volume > 1) fClipSoundDist *= volume; if (volume > 1) fClipSoundDist *= volume;
@ -747,11 +767,50 @@ void MultiPlayerLevel::playLocalSound(double x, double y, double z, int iSound,
} }
if (minDistSq < fClipSoundDist * fClipSoundDist) { if (minDistSq < fClipSoundDist * fClipSoundDist) {
minecraft->soundEngine->play(iSound, (float)x, (float)y, (float)z, if (distanceDelay && minDistSq > 10 * 10) {
volume, pitch); // exhaggerate sound speed effect by making speed of sound ~=
// 40 m/s instead of 300 m/s
double delayInSeconds = sqrt(minDistSq) / 40.0;
minecraft->soundEngine->schedule(
iSound, (float)x, (float)y, (float)z, volume, pitch,
(int)Math::round(delayInSeconds *
SharedConstants::TICKS_PER_SECOND));
} else {
minecraft->soundEngine->play(iSound, (float)x, (float)y, (float)z,
volume, pitch);
}
} }
} }
void MultiPlayerLevel::createFireworks(double x, double y, double z, double xd,
double yd, double zd,
CompoundTag* infoTag) {
minecraft->particleEngine->add(
std::shared_ptr<FireworksParticles::FireworksStarter>(
new FireworksParticles::FireworksStarter(this, x, y, z, xd, yd, zd,
minecraft->particleEngine,
infoTag)));
}
void MultiPlayerLevel::setScoreboard(Scoreboard* scoreboard) {
this->scoreboard = scoreboard;
}
void MultiPlayerLevel::setDayTime(int64_t newTime) {
// 4J: We send daylight cycle rule with host options so don't need this
/*if (newTime < 0)
{
newTime = -newTime;
getGameRules()->set(GameRules::RULE_DAYLIGHT, L"false");
}
else
{
getGameRules()->set(GameRules::RULE_DAYLIGHT, L"true");
}*/
Level::setDayTime(newTime);
}
void MultiPlayerLevel::removeAllPendingEntityRemovals() { void MultiPlayerLevel::removeAllPendingEntityRemovals() {
// entities.removeAll(entitiesToRemove); // entities.removeAll(entitiesToRemove);

View file

@ -18,9 +18,10 @@ private:
ResetInfo(int x, int y, int z, int tile, int data); ResetInfo(int x, int y, int z, int tile, int data);
}; };
std::vector<ResetInfo> updatesToReset; // 4J - was linked list but vector std::vector<ResetInfo>
// seems more appropriate updatesToReset; // 4J - was linked list but std::vector seems more
bool m_bEnableResetChanges; // 4J Added // appropriate
bool m_bEnableResetChanges; // 4J Added
public: public:
void unshareChunkAt(int x, int z); // 4J - added void unshareChunkAt(int x, int z); // 4J - added
void shareChunkAt(int x, int z); // 4J - added void shareChunkAt(int x, int z); // 4J - added
@ -34,10 +35,11 @@ private:
int compressCheckX; // 4J - added int compressCheckX; // 4J - added
int compressCheckZ; // 4J - added int compressCheckZ; // 4J - added
std::vector<ClientConnection*> std::vector<ClientConnection*>
connections; // 4J Stu - Made this a vector as we can have more than connections; // 4J Stu - Made this a std::vector as we can have more
// one local connection // than one local connection
MultiPlayerChunkCache* chunkCache; MultiPlayerChunkCache* chunkCache;
Minecraft* minecraft; Minecraft* minecraft;
Scoreboard* scoreboard;
public: public:
MultiPlayerLevel(ClientConnection* connection, LevelSettings* levelSettings, MultiPlayerLevel(ClientConnection* connection, LevelSettings* levelSettings,
@ -79,15 +81,16 @@ public:
std::shared_ptr<Entity> removeEntity(int id); std::shared_ptr<Entity> removeEntity(int id);
virtual void removeEntities( virtual void removeEntities(
std::vector<std::shared_ptr<Entity> >* list); // 4J Added override std::vector<std::shared_ptr<Entity> >* list); // 4J Added override
virtual bool setDataNoUpdate(int x, int y, int z, int data); virtual bool setData(int x, int y, int z, int data, int updateFlags,
virtual bool setTileAndDataNoUpdate(int x, int y, int z, int tile, bool forceUpdate = false);
int data); virtual bool setTileAndData(int x, int y, int z, int tile, int data,
virtual bool setTileNoUpdate(int x, int y, int z, int tile); int updateFlags);
bool doSetTileAndData(int x, int y, int z, int tile, int data); bool doSetTileAndData(int x, int y, int z, int tile, int data);
virtual void disconnect(bool sendDisconnect = true); virtual void disconnect(bool sendDisconnect = true);
void animateTick(int xt, int yt, int zt); void animateTick(int xt, int yt, int zt);
protected: protected:
virtual Tickable* makeSoundUpdater(std::shared_ptr<Minecart> minecart);
virtual void tickWeather(); virtual void tickWeather();
static const int ANIMATE_TICK_MAX_PARTICLES = 500; static const int ANIMATE_TICK_MAX_PARTICLES = 500;
@ -104,8 +107,14 @@ public:
virtual void playLocalSound(double x, double y, double z, int iSound, virtual void playLocalSound(double x, double y, double z, int iSound,
float volume, float pitch, float volume, float pitch,
bool distanceDelay = false,
float fClipSoundDist = 16.0f); float fClipSoundDist = 16.0f);
virtual void createFireworks(double x, double y, double z, double xd,
double yd, double zd, CompoundTag* infoTag);
virtual void setScoreboard(Scoreboard* scoreboard);
virtual void setDayTime(int64_t newTime);
// 4J Stu - Added so we can have multiple local connections // 4J Stu - Added so we can have multiple local connections
void addClientConnection(ClientConnection* c) { connections.push_back(c); } void addClientConnection(ClientConnection* c) { connections.push_back(c); }
void removeClientConnection(ClientConnection* c, bool sendDisconnect); void removeClientConnection(ClientConnection* c, bool sendDisconnect);

View file

@ -6,33 +6,36 @@
#include "../Player/ServerPlayer.h" #include "../Player/ServerPlayer.h"
#include "../Network/PlayerConnection.h" #include "../Network/PlayerConnection.h"
#include "../Player/EntityTracker.h" #include "../Player/EntityTracker.h"
#include "../Network/ServerScoreboard.h"
#include "../../Minecraft.World/Scores/ScoreboardSaveData.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.h" #include "../../Minecraft.World/Headers/net.minecraft.world.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.h" #include "../../Minecraft.World/Headers/net.minecraft.world.item.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.dimension.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.storage.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.chunk.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.tile.entity.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.biome.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.h" #include "../../Minecraft.World/Headers/net.minecraft.world.entity.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.ai.village.h" #include "../../Minecraft.World/Headers/net.minecraft.world.entity.ai.village.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.player.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.npc.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.global.h" #include "../../Minecraft.World/Headers/net.minecraft.world.entity.global.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.npc.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.player.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.biome.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.chunk.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.dimension.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.levelgen.feature.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.storage.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.tile.entity.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.scores.h"
#include "../../Minecraft.World/Entities/ItemEntity.h" #include "../../Minecraft.World/Entities/ItemEntity.h"
#include "../../Minecraft.World/Entities/Mobs/Arrow.h" #include "../../Minecraft.World/Entities/Mobs/Arrow.h"
#include "../../Minecraft.World/Entities/Mobs/PrimedTnt.h" #include "../../Minecraft.World/Entities/Mobs/PrimedTnt.h"
#include "../../Minecraft.World/Blocks/FallingTile.h" #include "../../Minecraft.World/Blocks/FallingTile.h"
#include "../../Minecraft.World/Headers/net.minecraft.network.packet.h" #include "../../Minecraft.World/Headers/net.minecraft.network.packet.h"
#include "../../Minecraft.World/Util/Mth.h" #include "../../Minecraft.World/Util/Mth.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.levelgen.feature.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.item.h"
#include "../../Minecraft.World/WorldGen/Structures/StructurePiece.h" #include "../../Minecraft.World/WorldGen/Structures/StructurePiece.h"
#include "ServerLevelListener.h" #include "../Minecraft.Client/ServerLevelListener.h"
#include "../../Minecraft.World/Util/WeighedTreasure.h" #include "../../Minecraft.World/Util/WeighedTreasure.h"
#include "../Textures/Packs/TexturePackRepository.h" #include "../Textures/Packs/TexturePackRepository.h"
#include "../Textures/Packs/DLCTexturePack.h" #include "../Textures/Packs/DLCTexturePack.h"
#include "../../Minecraft.World/Util/ProgressListener.h" #include "../../Minecraft.World/Util/ProgressListener.h"
#include "../Platform/PS3/PS3Extras/ShutdownManager.h" #include "PS3/PS3Extras/ShutdownManager.h"
#include "../Network/PlayerChunkMap.h" #include "../Network/PlayerChunkMap.h"
WeighedTreasureArray ServerLevel::RANDOM_BONUS_ITEMS; WeighedTreasureArray ServerLevel::RANDOM_BONUS_ITEMS;
@ -100,7 +103,7 @@ void ServerLevel::staticCtor() {
RANDOM_BONUS_ITEMS[17] = new WeighedTreasure(Item::potato_Id, 0, 1, 2, 3); RANDOM_BONUS_ITEMS[17] = new WeighedTreasure(Item::potato_Id, 0, 1, 2, 3);
RANDOM_BONUS_ITEMS[18] = new WeighedTreasure(Item::carrots_Id, 0, 1, 2, 3); RANDOM_BONUS_ITEMS[18] = new WeighedTreasure(Item::carrots_Id, 0, 1, 2, 3);
RANDOM_BONUS_ITEMS[19] = RANDOM_BONUS_ITEMS[19] =
new WeighedTreasure(Tile::mushroom1_Id, 0, 1, 2, 2); new WeighedTreasure(Tile::mushroom_brown_Id, 0, 1, 2, 2);
}; };
ServerLevel::ServerLevel(MinecraftServer* server, ServerLevel::ServerLevel(MinecraftServer* server,
@ -132,9 +135,25 @@ ServerLevel::ServerLevel(MinecraftServer* server,
// of this ctor but setting up early here // of this ctor but setting up early here
addListener(new ServerLevelListener(server, this)); addListener(new ServerLevelListener(server, this));
this->tracker = new EntityTracker(this); tracker = new EntityTracker(this);
this->chunkMap = new PlayerChunkMap( chunkMap = new PlayerChunkMap(this, dimension,
this, dimension, server->getPlayers()->getViewDistance()); server->getPlayers()->getViewDistance());
mobSpawner = new MobSpawner();
portalForcer = new PortalForcer(this);
scoreboard = new ServerScoreboard(server);
// shared_ptr<ScoreboardSaveData> scoreboardSaveData =
// std::dynamic_pointer_cast<ScoreboardSaveData>(
// savedDataStorage->get(typeid(ScoreboardSaveData),
// ScoreboardSaveData::FILE_ID) ); if (scoreboardSaveData == NULL)
//{
// scoreboardSaveData = shared_ptr<ScoreboardSaveData>( new
// ScoreboardSaveData() );
// savedDataStorage->set(ScoreboardSaveData::FILE_ID, scoreboardSaveData);
// }
// scoreboardSaveData->setScoreboard(scoreboard);
//((ServerScoreboard *) scoreboard)->setSaveData(scoreboardSaveData);
// This also used to be called in parent ctor, but can't be called until // This also used to be called in parent ctor, but can't be called until
// chunkSource is created. Call now if required. // chunkSource is created. Call now if required.
@ -171,6 +190,9 @@ ServerLevel::ServerLevel(MinecraftServer* server,
} }
ServerLevel::~ServerLevel() { ServerLevel::~ServerLevel() {
delete portalForcer;
delete mobSpawner;
EnterCriticalSection(&m_csQueueSendTileUpdates); EnterCriticalSection(&m_csQueueSendTileUpdates);
for (AUTO_VAR(it, m_queuedSendTileUpdates.begin()); for (AUTO_VAR(it, m_queuedSendTileUpdates.begin());
it != m_queuedSendTileUpdates.end(); ++it) { it != m_queuedSendTileUpdates.end(); ++it) {
@ -207,34 +229,47 @@ void ServerLevel::tick() {
dimension->biomeSource->update(); dimension->biomeSource->update();
if (allPlayersAreSleeping()) { if (allPlayersAreSleeping()) {
bool somebodyWokeUp = false; if (getGameRules()->getBoolean(GameRules::RULE_DAYLIGHT)) {
if (spawnEnemies && difficulty >= Difficulty::EASY) {
}
if (!somebodyWokeUp) {
// skip time until new day // skip time until new day
__int64 newTime = levelData->getTime() + TICKS_PER_DAY; int64_t newTime = levelData->getDayTime() + TICKS_PER_DAY;
// 4J : WESTY : Changed so that time update goes through stats // 4J : WESTY : Changed so that time update goes through stats
// tracking update code. // tracking update code.
// levelData->setTime(newTime - (newTime % TICKS_PER_DAY)); // levelData->setTime(newTime - (newTime % TICKS_PER_DAY));
setTime(newTime - (newTime % TICKS_PER_DAY)); setDayTime(newTime - (newTime % TICKS_PER_DAY));
awakenAllPlayers();
} }
awakenAllPlayers();
} }
PIXBeginNamedEvent(0, "Mob spawner tick"); PIXBeginNamedEvent(0, "Mob spawner tick");
// for Minecraft 1.8, spawn friendlies really rarely - 4J - altered // for Minecraft 1.8, spawn friendlies really rarely - 4J - altered
// from once every 400 ticks to 40 ticks as we depend on this a more than // from once every 400 ticks to 40 ticks as we depend on this a more than
// the original since we don't have chunk post-process spawning // the original since we don't have chunk post-process spawning
MobSpawner::tick(this, spawnEnemies, if (getGameRules()->getBoolean(GameRules::RULE_DOMOBSPAWNING)) {
spawnFriendlies && (levelData->getTime() % 40) == 0); // Note - these flags are used logically in an inverted way. Mob
// spawning is not performed if: (1) finalSpawnEnemies isn't set, and
// mob category isn't friendly (2) finalSpawnFriendlies isn't set, and
// mob category is friendly (3) finalSpawnPersistent isn't set, and mob
// category is persistent
bool finalSpawnEnemies =
spawnEnemies && ((levelData->getGameTime() % 2) ==
0); // Spawn enemies every other tick
bool finalSpawnFriendlies =
spawnFriendlies && ((levelData->getGameTime() % 40) ==
0); // Spawn friendlies once per 40 ticks
bool finalSpawnPersistent =
finalSpawnFriendlies &&
((levelData->getGameTime() % 80) ==
0); // All persistents are also friendly - do them once every
// other friendly spawning, ie once per 80 ticks
mobSpawner->tick(this, finalSpawnEnemies, finalSpawnFriendlies,
finalSpawnPersistent);
}
PIXEndNamedEvent(); PIXEndNamedEvent();
PIXBeginNamedEvent(0, "Chunk source tick"); PIXBeginNamedEvent(0, "Chunk source tick");
chunkSource->tick(); chunkSource->tick();
PIXEndNamedEvent(); PIXEndNamedEvent();
int newDark = this->getOldSkyDarken(1); int newDark = getOldSkyDarken(1);
if (newDark != skyDarken) { if (newDark != skyDarken) {
skyDarken = newDark; skyDarken = newDark;
if (!SharedConstants::TEXTURE_LIGHTING) // 4J - change brought forward if (!SharedConstants::TEXTURE_LIGHTING) // 4J - change brought forward
@ -247,17 +282,12 @@ void ServerLevel::tick() {
} }
} }
PIXBeginNamedEvent(0, "runTileEvents");
// run after entity updates
runTileEvents();
PIXEndNamedEvent();
// 4J - temporarily disabling saves as they are causing gameplay to // 4J - temporarily disabling saves as they are causing gameplay to
// generally stutter quite a lot // generally stutter quite a lot
__int64 time = levelData->getTime() + 1; int64_t time = levelData->getGameTime() + 1;
// 4J Stu - Putting this back in, but I have reduced the number of chunks that // 4J Stu - Putting this back in, but I have reduced the number of chunks
// save when not forced // that save when not forced
#ifdef _LARGE_WORLDS #ifdef _LARGE_WORLDS
if (time % (saveInterval) == (dimension->id + 1)) if (time % (saveInterval) == (dimension->id + 1))
#else #else
@ -274,7 +304,20 @@ void ServerLevel::tick() {
// 4J : WESTY : Changed so that time update goes through stats tracking // 4J : WESTY : Changed so that time update goes through stats tracking
// update code. // update code.
// levelData->setTime(time); // levelData->setTime(time);
setTime(time); setGameTime(levelData->getGameTime() + 1);
if (getGameRules()->getBoolean(GameRules::RULE_DAYLIGHT)) {
// 4J: Debug setting added to keep it at day time
#ifndef _FINAL_BUILD
bool freezeTime =
app.DebugSettingsOn() &&
app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) &
(1L << eDebugSetting_FreezeTime);
if (!freezeTime)
#endif
{
setDayTime(levelData->getDayTime() + 1);
}
}
PIXBeginNamedEvent(0, "Tick pending ticks"); PIXBeginNamedEvent(0, "Tick pending ticks");
// if (tickCount % 5 == 0) { // if (tickCount % 5 == 0) {
@ -296,8 +339,14 @@ void ServerLevel::tick() {
// MemSect(0); // MemSect(0);
PIXEndNamedEvent(); PIXEndNamedEvent();
PIXBeginNamedEvent(0, "Tick portal forcer");
portalForcer->tick(getGameTime());
PIXEndNamedEvent();
// repeat after tile ticks // repeat after tile ticks
PIXBeginNamedEvent(0, "runTileEvents");
runTileEvents(); runTileEvents();
PIXEndNamedEvent();
// 4J Added // 4J Added
runQueuedSendTileUpdates(); runQueuedSendTileUpdates();
@ -318,8 +367,7 @@ void ServerLevel::updateSleepingPlayerList() {
m_bAtLeastOnePlayerSleeping = false; m_bAtLeastOnePlayerSleeping = false;
AUTO_VAR(itEnd, players.end()); AUTO_VAR(itEnd, players.end());
for (std::vector<std::shared_ptr<Player> >::iterator it = players.begin(); for (AUTO_VAR(it, players.begin()); it != itEnd; it++) {
it != itEnd; it++) {
if (!(*it)->isSleeping()) { if (!(*it)->isSleeping()) {
allPlayersSleeping = false; allPlayersSleeping = false;
// break; // break;
@ -477,7 +525,7 @@ void ServerLevel::tickTiles() {
m_updateChunkX[iLev][m_updateChunkCount[iLev]] = cp.x; m_updateChunkX[iLev][m_updateChunkCount[iLev]] = cp.x;
m_updateChunkZ[iLev][m_updateChunkCount[iLev]++] = cp.z; m_updateChunkZ[iLev][m_updateChunkCount[iLev]++] = cp.z;
LevelChunk* lc = this->getChunk(cp.x, cp.z); LevelChunk* lc = getChunk(cp.x, cp.z);
tickClientSideTiles(xo, zo, lc); tickClientSideTiles(xo, zo, lc);
if (random->nextInt(prob) == 0 && isRaining() && isThundering()) { if (random->nextInt(prob) == 0 && isRaining() && isThundering()) {
@ -490,23 +538,21 @@ void ServerLevel::tickTiles() {
if (isRainingAt(x, y, z)) { if (isRainingAt(x, y, z)) {
addGlobalEntity(std::shared_ptr<LightningBolt>( addGlobalEntity(std::shared_ptr<LightningBolt>(
new LightningBolt(this, x, y, z))); new LightningBolt(this, x, y, z)));
lightningTime = 2;
} }
} }
// 4J - changes here brought forrward from 1.2.3 // 4J - changes here brought forrward from 1.2.3
if (random->nextInt(16) == 0) { if (random->nextInt(16) == 0) {
// 4jcraft added cast to unsigned randValue = randValue * 3 + addend;
randValue = (unsigned)randValue * 3 + (unsigned)addend;
int val = (randValue >> 2); int val = (randValue >> 2);
int x = (val & 15); int x = (val & 15);
int z = ((val >> 8) & 15); int z = ((val >> 8) & 15);
int yy = this->getTopRainBlock(x + xo, z + zo); int yy = getTopRainBlock(x + xo, z + zo);
if (shouldFreeze(x + xo, yy - 1, z + zo)) { if (shouldFreeze(x + xo, yy - 1, z + zo)) {
setTile(x + xo, yy - 1, z + zo, Tile::ice_Id); setTileAndUpdate(x + xo, yy - 1, z + zo, Tile::ice_Id);
} }
if (isRaining() && shouldSnow(x + xo, yy, z + zo)) { if (isRaining() && shouldSnow(x + xo, yy, z + zo)) {
setTile(x + xo, yy, z + zo, Tile::topSnow_Id); setTileAndUpdate(x + xo, yy, z + zo, Tile::topSnow_Id);
} }
if (isRaining()) { if (isRaining()) {
Biome* b = getBiome(x + xo, z + zo); Biome* b = getBiome(x + xo, z + zo);
@ -531,26 +577,42 @@ void ServerLevel::tickTiles() {
m_updateTrigger->Set(iLev); m_updateTrigger->Set(iLev);
} }
bool ServerLevel::isTileToBeTickedAt(int x, int y, int z, int tileId) {
TickNextTickData td = TickNextTickData(x, y, z, tileId);
return find(toBeTicked.begin(), toBeTicked.end(), td) != toBeTicked.end();
}
void ServerLevel::addToTickNextTick(int x, int y, int z, int tileId, void ServerLevel::addToTickNextTick(int x, int y, int z, int tileId,
int tickDelay) { int tickDelay) {
addToTickNextTick(x, y, z, tileId, tickDelay, 0);
}
void ServerLevel::addToTickNextTick(int x, int y, int z, int tileId,
int tickDelay, int priorityTilt) {
MemSect(27); MemSect(27);
TickNextTickData td = TickNextTickData(x, y, z, tileId); TickNextTickData td = TickNextTickData(x, y, z, tileId);
int r = 8; int r = 0;
if (getInstaTick()) { if (getInstaTick() && tileId > 0) {
if (hasChunksAt(td.x - r, td.y - r, td.z - r, td.x + r, td.y + r, if (Tile::tiles[tileId]->canInstantlyTick()) {
td.z + r)) { r = 8;
int id = getTile(td.x, td.y, td.z); if (hasChunksAt(td.x - r, td.y - r, td.z - r, td.x + r, td.y + r,
if (id == td.tileId && id > 0) { td.z + r)) {
Tile::tiles[id]->tick(this, td.x, td.y, td.z, random); int id = getTile(td.x, td.y, td.z);
if (id == td.tileId && id > 0) {
Tile::tiles[id]->tick(this, td.x, td.y, td.z, random);
}
} }
MemSect(0);
return;
} else {
tickDelay = 1;
} }
MemSect(0);
return;
} }
if (hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r)) { if (hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r)) {
if (tileId > 0) { if (tileId > 0) {
td.delay(tickDelay + levelData->getTime()); td.delay(tickDelay + levelData->getGameTime());
td.setPriorityTilt(priorityTilt);
} }
EnterCriticalSection(&m_tickNextTickCS); EnterCriticalSection(&m_tickNextTickCS);
if (tickNextTickSet.find(td) == tickNextTickSet.end()) { if (tickNextTickSet.find(td) == tickNextTickSet.end()) {
@ -563,11 +625,12 @@ void ServerLevel::addToTickNextTick(int x, int y, int z, int tileId,
} }
void ServerLevel::forceAddTileTick(int x, int y, int z, int tileId, void ServerLevel::forceAddTileTick(int x, int y, int z, int tileId,
int tickDelay) { int tickDelay, int prioTilt) {
TickNextTickData td = TickNextTickData(x, y, z, tileId); TickNextTickData td = TickNextTickData(x, y, z, tileId);
td.setPriorityTilt(prioTilt);
if (tileId > 0) { if (tileId > 0) {
td.delay(tickDelay + levelData->getTime()); td.delay(tickDelay + levelData->getGameTime());
} }
EnterCriticalSection(&m_tickNextTickCS); EnterCriticalSection(&m_tickNextTickCS);
if (tickNextTickSet.find(td) == tickNextTickSet.end()) { if (tickNextTickSet.find(td) == tickNextTickSet.end()) {
@ -583,12 +646,14 @@ void ServerLevel::tickEntities() {
return; return;
} }
} else { } else {
emptyTime = 0; resetEmptyTime();
} }
Level::tickEntities(); Level::tickEntities();
} }
void ServerLevel::resetEmptyTime() { emptyTime = 0; }
bool ServerLevel::tickPendingTicks(bool force) { bool ServerLevel::tickPendingTicks(bool force) {
EnterCriticalSection(&m_tickNextTickCS); EnterCriticalSection(&m_tickNextTickCS);
int count = (int)tickNextTickList.size(); int count = (int)tickNextTickList.size();
@ -602,22 +667,33 @@ bool ServerLevel::tickPendingTicks(bool force) {
AUTO_VAR(itTickList, tickNextTickList.begin()); AUTO_VAR(itTickList, tickNextTickList.begin());
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
TickNextTickData td = *(itTickList); TickNextTickData td = *(itTickList);
if (!force && td.m_delay > levelData->getTime()) { if (!force && td.m_delay > levelData->getGameTime()) {
break; break;
} }
itTickList = tickNextTickList.erase(itTickList); itTickList = tickNextTickList.erase(itTickList);
tickNextTickSet.erase(td); tickNextTickSet.erase(td);
int r = 8; toBeTicked.push_back(td);
}
for (AUTO_VAR(it, toBeTicked.begin()); it != toBeTicked.end();) {
TickNextTickData td = *it;
it = toBeTicked.erase(it);
int r = 0;
if (hasChunksAt(td.x - r, td.y - r, td.z - r, td.x + r, td.y + r, if (hasChunksAt(td.x - r, td.y - r, td.z - r, td.x + r, td.y + r,
td.z + r)) { td.z + r)) {
int id = getTile(td.x, td.y, td.z); int id = getTile(td.x, td.y, td.z);
if (id == td.tileId && id > 0) { if (id > 0 && Tile::isMatching(id, td.tileId)) {
Tile::tiles[id]->tick(this, td.x, td.y, td.z, random); Tile::tiles[id]->tick(this, td.x, td.y, td.z, random);
} }
} else {
addToTickNextTick(td.x, td.y, td.z, td.tileId, 0);
} }
} }
toBeTicked.clear();
int count3 = (int)tickNextTickList.size(); int count3 = (int)tickNextTickList.size();
int count4 = (int)tickNextTickSet.size(); int count4 = (int)tickNextTickSet.size();
@ -640,20 +716,47 @@ std::vector<TickNextTickData>* ServerLevel::fetchTicksInChunk(LevelChunk* chunk,
int south = north + 16; int south = north + 16;
delete pos; delete pos;
for (AUTO_VAR(it, tickNextTickSet.begin()); it != tickNextTickSet.end();) { for (int i = 0; i < 2; i++) {
TickNextTickData td = *it; if (i == 0) {
for (AUTO_VAR(it, tickNextTickList.begin());
it != tickNextTickList.end();) {
TickNextTickData td = *it;
if (td.x >= west && td.x < east && td.z >= north && td.z < south) { if (td.x >= xMin && td.x < xMax && td.z >= zMin &&
if (remove) { td.z < zMax) {
tickNextTickList.erase(td); if (remove) {
it = tickNextTickSet.erase(it); tickNextTickSet.erase(td);
} else { it = tickNextTickList.erase(it);
it++; } else {
it++;
}
results->push_back(td);
} else {
it++;
}
} }
results->push_back(td);
} else { } else {
it++; if (!toBeTicked.empty()) {
app.DebugPrintf("To be ticked size: %d\n", toBeTicked.size());
}
for (AUTO_VAR(it, toBeTicked.begin()); it != toBeTicked.end();) {
TickNextTickData td = *it;
if (td.x >= xMin && td.x < xMax && td.z >= zMin &&
td.z < zMax) {
if (remove) {
tickNextTickList.erase(td);
it = toBeTicked.erase(it);
} else {
it++;
}
results->push_back(td);
} else {
it++;
}
}
} }
} }
@ -663,19 +766,14 @@ std::vector<TickNextTickData>* ServerLevel::fetchTicksInChunk(LevelChunk* chunk,
void ServerLevel::tick(std::shared_ptr<Entity> e, bool actual) { void ServerLevel::tick(std::shared_ptr<Entity> e, bool actual) {
if (!server->isAnimals() && if (!server->isAnimals() &&
((e->GetType() & eTYPE_ANIMAL) || (e->GetType() & eTYPE_WATERANIMAL))) { (e->instanceof(eTYPE_ANIMAL) || e->instanceof(eTYPE_WATERANIMAL))) {
e->remove(); e->remove();
} }
if (!server->isNpcsEnabled() && if (!server->isNpcsEnabled() &&
(std::dynamic_pointer_cast<Npc>(e) != NULL)) { (std::dynamic_pointer_cast<Npc>(e) != NULL)) {
e->remove(); e->remove();
} }
if (e->rider.lock() == NULL || Level::tick(e, actual);
(std::dynamic_pointer_cast<Player>(e->rider.lock()) ==
NULL)) // 4J - was !(e->rider instanceof Player)
{
Level::tick(e, actual);
}
} }
void ServerLevel::forceTick(std::shared_ptr<Entity> e, bool actual) { void ServerLevel::forceTick(std::shared_ptr<Entity> e, bool actual) {
@ -715,10 +813,7 @@ bool ServerLevel::mayInteract(std::shared_ptr<Player> player, int xt, int yt,
return true; return true;
} else if (dimension->id == 0) // 4J Stu - Only limit this in the overworld } else if (dimension->id == 0) // 4J Stu - Only limit this in the overworld
{ {
int xd = (int)Mth::abs((float)(xt - levelData->getXSpawn())); return !server->isUnderSpawnProtection(this, xt, yt, zt, player);
int zd = (int)Mth::abs((float)(zt - levelData->getZSpawn()));
if (xd > zd) zd = xd;
return (zd > 16 || server->getPlayers()->isOp(player->name));
} }
return true; return true;
} }
@ -891,7 +986,7 @@ void ServerLevel::save(bool force, ProgressListener* progressListener,
// if( force && !isClientSide ) // if( force && !isClientSide )
//{ //{
// if (progressListener != NULL) // if (progressListener != NULL)
//progressListener->progressStage(IDS_PROGRESS_SAVING_TO_DISC); // progressListener->progressStage(IDS_PROGRESS_SAVING_TO_DISC);
// levelStorage->flushSaveFile(); // levelStorage->flushSaveFile();
// } // }
} }
@ -1073,9 +1168,9 @@ void ServerLevel::runTileEvents() {
bool ServerLevel::doTileEvent(TileEventData* te) { bool ServerLevel::doTileEvent(TileEventData* te) {
int t = getTile(te->getX(), te->getY(), te->getZ()); int t = getTile(te->getX(), te->getY(), te->getZ());
if (t == te->getTile()) { if (t == te->getTile()) {
Tile::tiles[t]->triggerEvent(this, te->getX(), te->getY(), te->getZ(), return Tile::tiles[t]->triggerEvent(this, te->getX(), te->getY(),
te->getParamA(), te->getParamB()); te->getZ(), te->getParamA(),
return true; te->getParamB());
} }
return false; return false;
} }
@ -1101,8 +1196,8 @@ MinecraftServer* ServerLevel::getServer() { return server; }
EntityTracker* ServerLevel::getTracker() { return tracker; } EntityTracker* ServerLevel::getTracker() { return tracker; }
void ServerLevel::setTimeAndAdjustTileTicks(__int64 newTime) { void ServerLevel::setTimeAndAdjustTileTicks(int64_t newTime) {
__int64 delta = newTime - levelData->getTime(); int64_t delta = newTime - levelData->getGameTime();
// 4J - can't directly adjust m_delay in a set as it has a const interator, // 4J - can't directly adjust m_delay in a set as it has a const interator,
// since changing values in here might change the ordering of the elements // since changing values in here might change the ordering of the elements
// in the set. Instead move to a vector, do the adjustment, put back in the // in the set. Instead move to a vector, do the adjustment, put back in the
@ -1117,11 +1212,34 @@ void ServerLevel::setTimeAndAdjustTileTicks(__int64 newTime) {
for (unsigned int i = 0; i < temp.size(); i++) { for (unsigned int i = 0; i < temp.size(); i++) {
tickNextTickList.insert(temp[i]); tickNextTickList.insert(temp[i]);
} }
setTime(newTime); setGameTime(newTime);
} }
PlayerChunkMap* ServerLevel::getChunkMap() { return chunkMap; } PlayerChunkMap* ServerLevel::getChunkMap() { return chunkMap; }
PortalForcer* ServerLevel::getPortalForcer() { return portalForcer; }
void ServerLevel::sendParticles(const std::wstring& name, double x, double y,
double z, int count) {
sendParticles(name, x + 0.5f, y + 0.5f, z + 0.5f, count, 0.5f, 0.5f, 0.5f,
0.02f);
}
void ServerLevel::sendParticles(const std::wstring& name, double x, double y,
double z, int count, double xDist, double yDist,
double zDist, double speed) {
std::shared_ptr<Packet> packet =
std::shared_ptr<LevelParticlesPacket>(new LevelParticlesPacket(
name, (float)x, (float)y, (float)z, (float)xDist, (float)yDist,
(float)zDist, (float)speed, count));
for (AUTO_VAR(it, players.begin()); it != players.end(); ++it) {
std::shared_ptr<ServerPlayer> player =
std::dynamic_pointer_cast<ServerPlayer>(*it);
player->connection->send(packet);
}
}
// 4J Stu - Sometimes we want to update tiles on the server from the main thread // 4J Stu - Sometimes we want to update tiles on the server from the main thread
// (eg SignTileEntity when string verify returns) // (eg SignTileEntity when string verify returns)
void ServerLevel::queueSendTileUpdate(int x, int y, int z) { void ServerLevel::queueSendTileUpdate(int x, int y, int z) {
@ -1146,7 +1264,7 @@ void ServerLevel::runQueuedSendTileUpdates() {
// removed and added so we can limit the number of itementities created // removed and added so we can limit the number of itementities created
bool ServerLevel::addEntity(std::shared_ptr<Entity> e) { bool ServerLevel::addEntity(std::shared_ptr<Entity> e) {
// If its an item entity, and we've got to our capacity, delete the oldest // If its an item entity, and we've got to our capacity, delete the oldest
if (std::dynamic_pointer_cast<ItemEntity>(e) != NULL) { if (e->instanceof(eTYPE_ITEMENTITY)) {
// printf("Adding item entity count // printf("Adding item entity count
//%d\n",m_itemEntities.size()); //%d\n",m_itemEntities.size());
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
@ -1158,7 +1276,7 @@ bool ServerLevel::addEntity(std::shared_ptr<Entity> e) {
} }
// If its an hanging entity, and we've got to our capacity, delete the // If its an hanging entity, and we've got to our capacity, delete the
// oldest // oldest
else if (std::dynamic_pointer_cast<HangingEntity>(e) != NULL) { else if (e->instanceof(eTYPE_HANGING_ENTITY)) {
// printf("Adding item entity count // printf("Adding item entity count
//%d\n",m_itemEntities.size()); //%d\n",m_itemEntities.size());
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
@ -1175,7 +1293,7 @@ bool ServerLevel::addEntity(std::shared_ptr<Entity> e) {
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} }
// If its an arrow entity, and we've got to our capacity, delete the oldest // If its an arrow entity, and we've got to our capacity, delete the oldest
else if (std::dynamic_pointer_cast<Arrow>(e) != NULL) { else if (e->instanceof(eTYPE_ARROW)) {
// printf("Adding arrow entity count // printf("Adding arrow entity count
//%d\n",m_arrowEntities.size()); //%d\n",m_arrowEntities.size());
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
@ -1187,7 +1305,7 @@ bool ServerLevel::addEntity(std::shared_ptr<Entity> e) {
} }
// If its an experience orb entity, and we've got to our capacity, delete // If its an experience orb entity, and we've got to our capacity, delete
// the oldest // the oldest
else if (std::dynamic_pointer_cast<ExperienceOrb>(e) != NULL) { else if (e->instanceof(eTYPE_EXPERIENCEORB)) {
// printf("Adding arrow entity count // printf("Adding arrow entity count
//%d\n",m_arrowEntities.size()); //%d\n",m_arrowEntities.size());
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
@ -1200,37 +1318,65 @@ bool ServerLevel::addEntity(std::shared_ptr<Entity> e) {
return Level::addEntity(e); return Level::addEntity(e);
} }
// 4J: Returns true if the level is at its limit for this type of entity (only
// checks arrows, hanging, item and experience orbs)
bool ServerLevel::atEntityLimit(std::shared_ptr<Entity> e) {
// TODO: This duplicates code from addEntity above, fix
bool atLimit = false;
if (e->instanceof(eTYPE_ITEMENTITY)) {
EnterCriticalSection(&m_limiterCS);
atLimit = m_itemEntities.size() >= MAX_ITEM_ENTITIES;
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_HANGING_ENTITY)) {
EnterCriticalSection(&m_limiterCS);
atLimit = m_hangingEntities.size() >= MAX_HANGING_ENTITIES;
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_ARROW)) {
EnterCriticalSection(&m_limiterCS);
atLimit = m_arrowEntities.size() >= MAX_ARROW_ENTITIES;
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_EXPERIENCEORB)) {
EnterCriticalSection(&m_limiterCS);
atLimit = m_experienceOrbEntities.size() >= MAX_EXPERIENCEORB_ENTITIES;
LeaveCriticalSection(&m_limiterCS);
}
return atLimit;
}
// Maintain a cound of primed tnt & falling tiles in this level // Maintain a cound of primed tnt & falling tiles in this level
void ServerLevel::entityAddedExtra(std::shared_ptr<Entity> e) { void ServerLevel::entityAddedExtra(std::shared_ptr<Entity> e) {
if (std::dynamic_pointer_cast<ItemEntity>(e) != NULL) { if (e->instanceof(eTYPE_ITEMENTITY)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
m_itemEntities.push_back(e); m_itemEntities.push_back(e);
// printf("entity added: item entity count now // printf("entity added: item entity count now
//%d\n",m_itemEntities.size()); //%d\n",m_itemEntities.size());
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} else if (std::dynamic_pointer_cast<HangingEntity>(e) != NULL) { } else if (e->instanceof(eTYPE_HANGING_ENTITY)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
m_hangingEntities.push_back(e); m_hangingEntities.push_back(e);
// printf("entity added: item entity count now // printf("entity added: item entity count now
//%d\n",m_itemEntities.size()); //%d\n",m_itemEntities.size());
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} else if (std::dynamic_pointer_cast<Arrow>(e) != NULL) { } else if (e->instanceof(eTYPE_ARROW)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
m_arrowEntities.push_back(e); m_arrowEntities.push_back(e);
// printf("entity added: arrow entity count now // printf("entity added: arrow entity count now
//%d\n",m_arrowEntities.size()); //%d\n",m_arrowEntities.size());
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} else if (std::dynamic_pointer_cast<ExperienceOrb>(e) != NULL) { } else if (e->instanceof(eTYPE_EXPERIENCEORB)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
m_experienceOrbEntities.push_back(e); m_experienceOrbEntities.push_back(e);
// printf("entity added: experience orb entity count now // printf("entity added: experience orb entity count now
//%d\n",m_arrowEntities.size()); //%d\n",m_arrowEntities.size());
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} else if (std::dynamic_pointer_cast<PrimedTnt>(e) != NULL) { } else if (e->instanceof(eTYPE_PRIMEDTNT)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
m_primedTntCount++; m_primedTntCount++;
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} else if (std::dynamic_pointer_cast<FallingTile>(e) != NULL) { } else if (e->instanceof(eTYPE_FALLINGTILE)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
m_fallingTileCount++; m_fallingTileCount++;
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
@ -1240,7 +1386,7 @@ void ServerLevel::entityAddedExtra(std::shared_ptr<Entity> e) {
// Maintain a cound of primed tnt & falling tiles in this level, and remove any // Maintain a cound of primed tnt & falling tiles in this level, and remove any
// item entities from our list // item entities from our list
void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) { void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) {
if (std::dynamic_pointer_cast<ItemEntity>(e) != NULL) { if (e->instanceof(eTYPE_ITEMENTITY)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
// printf("entity removed: item entity count // printf("entity removed: item entity count
//%d\n",m_itemEntities.size()); //%d\n",m_itemEntities.size());
@ -1252,7 +1398,7 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) {
// printf("entity removed: item entity count now // printf("entity removed: item entity count now
//%d\n",m_itemEntities.size()); //%d\n",m_itemEntities.size());
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} else if (std::dynamic_pointer_cast<HangingEntity>(e) != NULL) { } else if (e->instanceof(eTYPE_HANGING_ENTITY)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
// printf("entity removed: item entity count // printf("entity removed: item entity count
//%d\n",m_itemEntities.size()); //%d\n",m_itemEntities.size());
@ -1265,7 +1411,7 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) {
// printf("entity removed: item entity count now // printf("entity removed: item entity count now
//%d\n",m_itemEntities.size()); //%d\n",m_itemEntities.size());
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} else if (std::dynamic_pointer_cast<Arrow>(e) != NULL) { } else if (e->instanceof(eTYPE_ARROW)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
// printf("entity removed: arrow entity count // printf("entity removed: arrow entity count
//%d\n",m_arrowEntities.size()); //%d\n",m_arrowEntities.size());
@ -1277,7 +1423,7 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) {
// printf("entity removed: arrow entity count now // printf("entity removed: arrow entity count now
//%d\n",m_arrowEntities.size()); //%d\n",m_arrowEntities.size());
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} else if (std::dynamic_pointer_cast<ExperienceOrb>(e) != NULL) { } else if (e->instanceof(eTYPE_EXPERIENCEORB)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
// printf("entity removed: experience orb entity count // printf("entity removed: experience orb entity count
//%d\n",m_arrowEntities.size()); //%d\n",m_arrowEntities.size());
@ -1290,11 +1436,11 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) {
// printf("entity removed: experience orb entity count now // printf("entity removed: experience orb entity count now
//%d\n",m_arrowEntities.size()); //%d\n",m_arrowEntities.size());
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} else if (std::dynamic_pointer_cast<PrimedTnt>(e) != NULL) { } else if (e->instanceof(eTYPE_PRIMEDTNT)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
m_primedTntCount--; m_primedTntCount--;
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
} else if (std::dynamic_pointer_cast<FallingTile>(e) != NULL) { } else if (e->instanceof(eTYPE_FALLINGTILE)) {
EnterCriticalSection(&m_limiterCS); EnterCriticalSection(&m_limiterCS);
m_fallingTileCount--; m_fallingTileCount--;
LeaveCriticalSection(&m_limiterCS); LeaveCriticalSection(&m_limiterCS);
@ -1438,4 +1584,4 @@ void ServerLevel::flagEntitiesToBeRemoved(unsigned int* flags,
if (chunkMap) { if (chunkMap) {
chunkMap->flagEntitiesToBeRemoved(flags, removedFound); chunkMap->flagEntitiesToBeRemoved(flags, removedFound);
} }
} }

View file

@ -9,7 +9,8 @@ class PlayerChunkMap;
class ServerLevel : public Level { class ServerLevel : public Level {
private: private:
static const int EMPTY_TIME_NO_TICK = SharedConstants::TICKS_PER_SECOND * 3; static const int EMPTY_TIME_NO_TICK =
SharedConstants::TICKS_PER_SECOND * 60;
MinecraftServer* server; MinecraftServer* server;
EntityTracker* tracker; EntityTracker* tracker;
@ -35,6 +36,8 @@ public:
private: private:
bool allPlayersSleeping; bool allPlayersSleeping;
PortalForcer* portalForcer;
MobSpawner* mobSpawner;
int emptyTime; int emptyTime;
bool m_bAtLeastOnePlayerSleeping; // 4J Added bool m_bAtLeastOnePlayerSleeping; // 4J Added
static WeighedTreasureArray static WeighedTreasureArray
@ -68,10 +71,18 @@ public:
protected: protected:
void tickTiles(); void tickTiles();
private:
std::vector<TickNextTickData> toBeTicked;
public: public:
bool isTileToBeTickedAt(int x, int y, int z, int tileId);
void addToTickNextTick(int x, int y, int z, int tileId, int tickDelay); void addToTickNextTick(int x, int y, int z, int tileId, int tickDelay);
void forceAddTileTick(int x, int y, int z, int tileId, int tickDelay); void addToTickNextTick(int x, int y, int z, int tileId, int tickDelay,
int priorityTilt);
void forceAddTileTick(int x, int y, int z, int tileId, int tickDelay,
int prioTilt);
void tickEntities(); void tickEntities();
void resetEmptyTime();
bool tickPendingTicks(bool force); bool tickPendingTicks(bool force);
std::vector<TickNextTickData>* fetchTicksInChunk(LevelChunk* chunk, std::vector<TickNextTickData>* fetchTicksInChunk(LevelChunk* chunk,
bool remove); bool remove);
@ -89,7 +100,7 @@ public:
std::vector<std::shared_ptr<TileEntity> >* getTileEntitiesInRegion( std::vector<std::shared_ptr<TileEntity> >* getTileEntitiesInRegion(
int x0, int y0, int z0, int x1, int y1, int z1); int x0, int y0, int z0, int x1, int y1, int z1);
virtual bool mayInteract(std::shared_ptr<Player> player, int xt, int yt, virtual bool mayInteract(std::shared_ptr<Player> player, int xt, int yt,
int zt, int id); int zt, int content);
protected: protected:
virtual void initializeLevel(LevelSettings* settings); virtual void initializeLevel(LevelSettings* settings);
@ -141,8 +152,14 @@ protected:
public: public:
MinecraftServer* getServer(); MinecraftServer* getServer();
EntityTracker* getTracker(); EntityTracker* getTracker();
void setTimeAndAdjustTileTicks(__int64 newTime); void setTimeAndAdjustTileTicks(int64_t newTime);
PlayerChunkMap* getChunkMap(); PlayerChunkMap* getChunkMap();
PortalForcer* getPortalForcer();
void sendParticles(const std::wstring& name, double x, double y, double z,
int count);
void sendParticles(const std::wstring& name, double x, double y, double z,
int count, double xDist, double yDist, double zDist,
double speed);
void queueSendTileUpdate(int x, int y, int z); // 4J Added void queueSendTileUpdate(int x, int y, int z); // 4J Added
private: private:
@ -170,6 +187,8 @@ public:
void entityAddedExtra(std::shared_ptr<Entity> e); void entityAddedExtra(std::shared_ptr<Entity> e);
void entityRemovedExtra(std::shared_ptr<Entity> e); void entityRemovedExtra(std::shared_ptr<Entity> e);
bool atEntityLimit(std::shared_ptr<Entity> e); // 4J: Added
virtual bool newPrimedTntAllowed(); virtual bool newPrimedTntAllowed();
virtual bool newFallingTileAllowed(); virtual bool newFallingTileAllowed();

View file

@ -19,8 +19,8 @@ ServerLevelListener::ServerLevelListener(MinecraftServer* server,
// 4J removed - // 4J removed -
/* /*
void ServerLevelListener::addParticle(const std::wstring& name, double x, double void ServerLevelListener::addParticle(const wstring& name, double x, double y,
y, double z, double xa, double ya, double za) double z, double xa, double ya, double za)
{ {
} }
*/ */
@ -67,9 +67,11 @@ void ServerLevelListener::playSound(int iSound, double x, double y, double z,
} }
} }
void ServerLevelListener::playSound(std::shared_ptr<Entity> entity, int iSound, void ServerLevelListener::playSoundExceptPlayer(std::shared_ptr<Player> player,
double x, double y, double z, float volume, int iSound, double x, double y,
float pitch, float fClipSoundDist) { double z, float volume,
float pitch,
float fSoundClipDist) {
if (iSound < 0) { if (iSound < 0) {
app.DebugPrintf( app.DebugPrintf(
"ServerLevelListener received request for sound less than 0, so " "ServerLevelListener received request for sound less than 0, so "
@ -79,8 +81,6 @@ void ServerLevelListener::playSound(std::shared_ptr<Entity> entity, int iSound,
// since we're already playing these in the LevelRenderer::playSound. // since we're already playing these in the LevelRenderer::playSound.
// The PC version does seem to do this and the result is I can stop // The PC version does seem to do this and the result is I can stop
// walking , and then I'll hear my footstep sound with a delay // walking , and then I'll hear my footstep sound with a delay
std::shared_ptr<Player> player =
std::dynamic_pointer_cast<Player>(entity);
server->getPlayers()->broadcast( server->getPlayers()->broadcast(
player, x, y, z, volume > 1 ? 16 * volume : 16, player, x, y, z, volume > 1 ? 16 * volume : 16,
level->dimension->id, level->dimension->id,
@ -108,7 +108,13 @@ void ServerLevelListener::levelEvent(std::shared_ptr<Player> source, int type,
server->getPlayers()->broadcast( server->getPlayers()->broadcast(
source, x, y, z, 64, level->dimension->id, source, x, y, z, 64, level->dimension->id,
std::shared_ptr<LevelEventPacket>( std::shared_ptr<LevelEventPacket>(
new LevelEventPacket(type, x, y, z, data))); new LevelEventPacket(type, x, y, z, data, false)));
}
void ServerLevelListener::globalLevelEvent(int type, int sourceX, int sourceY,
int sourceZ, int data) {
server->getPlayers()->broadcastAll(std::shared_ptr<LevelEventPacket>(
new LevelEventPacket(type, sourceX, sourceY, sourceZ, data, true)));
} }
void ServerLevelListener::destroyTileProgress(int id, int x, int y, int z, void ServerLevelListener::destroyTileProgress(int id, int x, int y, int z,

View file

@ -27,9 +27,10 @@ public:
// level's player array, not just the entity storage // level's player array, not just the entity storage
virtual void playSound(int iSound, double x, double y, double z, virtual void playSound(int iSound, double x, double y, double z,
float volume, float pitch, float fClipSoundDist); float volume, float pitch, float fClipSoundDist);
virtual void playSound(std::shared_ptr<Entity> entity, int iSound, double x, virtual void playSoundExceptPlayer(std::shared_ptr<Player> player,
double y, double z, float volume, float pitch, int iSound, double x, double y, double z,
float fClipSoundDist); float volume, float pitch,
float fSoundClipDist);
virtual void setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1, virtual void setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1,
Level* level); // 4J - added level param Level* level); // 4J - added level param
virtual void skyColorChanged(); virtual void skyColorChanged();
@ -39,5 +40,7 @@ public:
int z); int z);
virtual void levelEvent(std::shared_ptr<Player> source, int type, int x, virtual void levelEvent(std::shared_ptr<Player> source, int type, int x,
int y, int z, int data); int y, int z, int data);
virtual void globalLevelEvent(int type, int sourceX, int sourceY,
int sourceZ, int data);
virtual void destroyTileProgress(int id, int x, int y, int z, int progress); virtual void destroyTileProgress(int id, int x, int y, int z, int progress);
}; };