From b319cb3cea6fe84141b63963919a2eaa3d3fcd0a Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Sat, 21 Mar 2026 20:29:13 -0500 Subject: [PATCH] TU19: merge Minecraft.Client/Level --- Minecraft.Client/Level/MultiPlayerLevel.cpp | 145 ++++--- Minecraft.Client/Level/MultiPlayerLevel.h | 27 +- Minecraft.Client/Level/ServerLevel.cpp | 362 ++++++++++++------ Minecraft.Client/Level/ServerLevel.h | 27 +- .../Level/ServerLevelListener.cpp | 22 +- Minecraft.Client/Level/ServerLevelListener.h | 9 +- 6 files changed, 417 insertions(+), 175 deletions(-) diff --git a/Minecraft.Client/Level/MultiPlayerLevel.cpp b/Minecraft.Client/Level/MultiPlayerLevel.cpp index 4f0055489..29a1e9617 100644 --- a/Minecraft.Client/Level/MultiPlayerLevel.cpp +++ b/Minecraft.Client/Level/MultiPlayerLevel.cpp @@ -9,9 +9,11 @@ #include "../MinecraftServer.h" #include "ServerLevel.h" #include "../Minecraft.h" +#include "../Rendering/Particles/FireworksParticles.h" #include "../../Minecraft.World/Entities/Mobs/PrimedTnt.h" #include "../../Minecraft.World/Blocks/Tile.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, int data) { @@ -53,10 +55,10 @@ MultiPlayerLevel::MultiPlayerLevel(ClientConnection* connection, // multiplayer, this should only be set by receiving a packet from the // server (which happens when a player logs in) // 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 (connection != NULL) { - this->savedDataStorage = connection->savedDataStorage; + savedDataStorage = connection->savedDataStorage; } unshareCheckX = 0; unshareCheckZ = 0; @@ -88,17 +90,30 @@ void MultiPlayerLevel::shareChunkAt(int x, int z) { void MultiPlayerLevel::tick() { 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 -int newDark = this->getSkyDarken(1); -if (newDark != skyDarken) + int newDark = this->getSkyDarken(1); + if (newDark != skyDarken) { skyDarken = newDark; for (unsigned int i = 0; i < listeners.size(); i++) - { - listeners[i]->skyColorChanged(); + { + listeners[i]->skyColorChanged(); } -}*/ + }*/ PIXEndNamedEvent(); PIXBeginNamedEvent(0, "Entity re-entry"); @@ -128,7 +143,8 @@ if (newDark != skyDarken) for (unsigned int i = 0; i < updatesToReset.size(); i++) { ResetInfo& r = updatesToReset[i]; 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); // updatesToReset.erase(updatesToReset.begin()+i); @@ -387,7 +403,7 @@ void MultiPlayerLevel::tickTiles() { int xo = cp.x * 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); } @@ -402,8 +418,8 @@ void MultiPlayerLevel::setChunkVisible(int x, int z, bool visible) { chunkCache->drop(x, z); } if (!visible) { - this->setTilesDirty(x * 16, 0, z * 16, x * 16 + 15, - Level::maxBuildHeight, z * 16 + 15); + setTilesDirty(x * 16, 0, z * 16, x * 16 + 15, Level::maxBuildHeight, + z * 16 + 15); } } @@ -456,7 +472,7 @@ void MultiPlayerLevel::putEntity(int id, std::shared_ptr e) { forced.insert(e); e->entityId = id; if (!addEntity(e)) { - this->reEntries.insert(e); + reEntries.insert(e); } entitiesById[id] = e; } @@ -498,14 +514,32 @@ void MultiPlayerLevel::removeEntities( Level::removeEntities(list); } -bool MultiPlayerLevel::setDataNoUpdate(int x, int y, int z, int data) { - int t = getTile(x, y, z); +bool MultiPlayerLevel::setData( + 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); + + 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 // server at this point 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, // t, d)); return true; @@ -515,8 +549,8 @@ bool MultiPlayerLevel::setDataNoUpdate(int x, int y, int z, int data) { return false; } -bool MultiPlayerLevel::setTileAndDataNoUpdate(int x, int y, int z, int tile, - int data) { +bool MultiPlayerLevel::setTileAndData(int x, int y, int z, int tile, int data, + int updateFlags) { // 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 @@ -539,24 +573,7 @@ bool MultiPlayerLevel::setTileAndDataNoUpdate(int x, int y, int z, int tile, // server at this point unshareChunkAt(x, z); - if (Level::setTileAndDataNoUpdate(x, y, z, tile, data)) { - // 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 (Level::setTileAndData(x, y, z, tile, data, updateFlags)) { // if(m_bEnableResetChanges) updatesToReset.push_back(ResetInfo(x, y, z, // t, d)); 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 // 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 - if ((Level::setTileAndData(x, y, z, tile, data) || + if ((Level::setTileAndData(x, y, z, tile, data, Tile::UPDATE_ALL) || g_NetworkManager.IsHost())) { if (g_NetworkManager.IsHost() && visuallyImportant) { // 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) { + return NULL; // new MinecartSoundUpdater(minecraft->soundEngine, minecart, + // minecraft->player); +} + void MultiPlayerLevel::tickWeather() { if (dimension->hasCeiling) return; - if (lightningTime > 0) { - lightningTime--; - } - oRainLevel = rainLevel; if (levelData->isRaining()) { rainLevel += 0.01; @@ -731,6 +750,7 @@ void MultiPlayerLevel::playSound(std::shared_ptr entity, int iSound, void MultiPlayerLevel::playLocalSound(double x, double y, double z, int iSound, float volume, float pitch, + bool distanceDelay /*= false */, float fClipSoundDist) { // float dd = 16; if (volume > 1) fClipSoundDist *= volume; @@ -747,11 +767,50 @@ void MultiPlayerLevel::playLocalSound(double x, double y, double z, int iSound, } if (minDistSq < fClipSoundDist * fClipSoundDist) { - minecraft->soundEngine->play(iSound, (float)x, (float)y, (float)z, - volume, pitch); + if (distanceDelay && minDistSq > 10 * 10) { + // 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( + 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() { // entities.removeAll(entitiesToRemove); diff --git a/Minecraft.Client/Level/MultiPlayerLevel.h b/Minecraft.Client/Level/MultiPlayerLevel.h index 0a02089d6..aeb70e2bc 100644 --- a/Minecraft.Client/Level/MultiPlayerLevel.h +++ b/Minecraft.Client/Level/MultiPlayerLevel.h @@ -18,9 +18,10 @@ private: ResetInfo(int x, int y, int z, int tile, int data); }; - std::vector updatesToReset; // 4J - was linked list but vector - // seems more appropriate - bool m_bEnableResetChanges; // 4J Added + std::vector + updatesToReset; // 4J - was linked list but std::vector seems more + // appropriate + bool m_bEnableResetChanges; // 4J Added public: void unshareChunkAt(int x, int z); // 4J - added void shareChunkAt(int x, int z); // 4J - added @@ -34,10 +35,11 @@ private: int compressCheckX; // 4J - added int compressCheckZ; // 4J - added std::vector - connections; // 4J Stu - Made this a vector as we can have more than - // one local connection + connections; // 4J Stu - Made this a std::vector as we can have more + // than one local connection MultiPlayerChunkCache* chunkCache; Minecraft* minecraft; + Scoreboard* scoreboard; public: MultiPlayerLevel(ClientConnection* connection, LevelSettings* levelSettings, @@ -79,15 +81,16 @@ public: std::shared_ptr removeEntity(int id); virtual void removeEntities( std::vector >* list); // 4J Added override - virtual bool setDataNoUpdate(int x, int y, int z, int data); - virtual bool setTileAndDataNoUpdate(int x, int y, int z, int tile, - int data); - virtual bool setTileNoUpdate(int x, int y, int z, int tile); + virtual bool setData(int x, int y, int z, int data, int updateFlags, + bool forceUpdate = false); + virtual bool setTileAndData(int x, int y, int z, int tile, int data, + int updateFlags); bool doSetTileAndData(int x, int y, int z, int tile, int data); virtual void disconnect(bool sendDisconnect = true); void animateTick(int xt, int yt, int zt); protected: + virtual Tickable* makeSoundUpdater(std::shared_ptr minecart); virtual void tickWeather(); static const int ANIMATE_TICK_MAX_PARTICLES = 500; @@ -104,8 +107,14 @@ public: virtual void playLocalSound(double x, double y, double z, int iSound, float volume, float pitch, + bool distanceDelay = false, 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 void addClientConnection(ClientConnection* c) { connections.push_back(c); } void removeClientConnection(ClientConnection* c, bool sendDisconnect); diff --git a/Minecraft.Client/Level/ServerLevel.cpp b/Minecraft.Client/Level/ServerLevel.cpp index 422c30a9f..ef6d203f2 100644 --- a/Minecraft.Client/Level/ServerLevel.cpp +++ b/Minecraft.Client/Level/ServerLevel.cpp @@ -6,33 +6,36 @@ #include "../Player/ServerPlayer.h" #include "../Network/PlayerConnection.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.level.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.item.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.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.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/Mobs/Arrow.h" #include "../../Minecraft.World/Entities/Mobs/PrimedTnt.h" #include "../../Minecraft.World/Blocks/FallingTile.h" #include "../../Minecraft.World/Headers/net.minecraft.network.packet.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 "ServerLevelListener.h" +#include "../Minecraft.Client/ServerLevelListener.h" #include "../../Minecraft.World/Util/WeighedTreasure.h" #include "../Textures/Packs/TexturePackRepository.h" #include "../Textures/Packs/DLCTexturePack.h" #include "../../Minecraft.World/Util/ProgressListener.h" -#include "../Platform/PS3/PS3Extras/ShutdownManager.h" +#include "PS3/PS3Extras/ShutdownManager.h" #include "../Network/PlayerChunkMap.h" 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[18] = new WeighedTreasure(Item::carrots_Id, 0, 1, 2, 3); 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, @@ -132,9 +135,25 @@ ServerLevel::ServerLevel(MinecraftServer* server, // of this ctor but setting up early here addListener(new ServerLevelListener(server, this)); - this->tracker = new EntityTracker(this); - this->chunkMap = new PlayerChunkMap( - this, dimension, server->getPlayers()->getViewDistance()); + tracker = new EntityTracker(this); + chunkMap = new PlayerChunkMap(this, dimension, + server->getPlayers()->getViewDistance()); + + mobSpawner = new MobSpawner(); + portalForcer = new PortalForcer(this); + scoreboard = new ServerScoreboard(server); + + // shared_ptr scoreboardSaveData = + // std::dynamic_pointer_cast( + // savedDataStorage->get(typeid(ScoreboardSaveData), + // ScoreboardSaveData::FILE_ID) ); if (scoreboardSaveData == NULL) + //{ + // scoreboardSaveData = shared_ptr( 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 // chunkSource is created. Call now if required. @@ -171,6 +190,9 @@ ServerLevel::ServerLevel(MinecraftServer* server, } ServerLevel::~ServerLevel() { + delete portalForcer; + delete mobSpawner; + EnterCriticalSection(&m_csQueueSendTileUpdates); for (AUTO_VAR(it, m_queuedSendTileUpdates.begin()); it != m_queuedSendTileUpdates.end(); ++it) { @@ -207,34 +229,47 @@ void ServerLevel::tick() { dimension->biomeSource->update(); if (allPlayersAreSleeping()) { - bool somebodyWokeUp = false; - if (spawnEnemies && difficulty >= Difficulty::EASY) { - } - - if (!somebodyWokeUp) { + if (getGameRules()->getBoolean(GameRules::RULE_DAYLIGHT)) { // 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 // tracking update code. // levelData->setTime(newTime - (newTime % TICKS_PER_DAY)); - setTime(newTime - (newTime % TICKS_PER_DAY)); - - awakenAllPlayers(); + setDayTime(newTime - (newTime % TICKS_PER_DAY)); } + awakenAllPlayers(); } PIXBeginNamedEvent(0, "Mob spawner tick"); // 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 // the original since we don't have chunk post-process spawning - MobSpawner::tick(this, spawnEnemies, - spawnFriendlies && (levelData->getTime() % 40) == 0); + if (getGameRules()->getBoolean(GameRules::RULE_DOMOBSPAWNING)) { + // 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(); PIXBeginNamedEvent(0, "Chunk source tick"); chunkSource->tick(); PIXEndNamedEvent(); - int newDark = this->getOldSkyDarken(1); + int newDark = getOldSkyDarken(1); if (newDark != skyDarken) { skyDarken = newDark; 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 // generally stutter quite a lot - __int64 time = levelData->getTime() + 1; -// 4J Stu - Putting this back in, but I have reduced the number of chunks that -// save when not forced + int64_t time = levelData->getGameTime() + 1; + // 4J Stu - Putting this back in, but I have reduced the number of chunks + // that save when not forced #ifdef _LARGE_WORLDS if (time % (saveInterval) == (dimension->id + 1)) #else @@ -274,7 +304,20 @@ void ServerLevel::tick() { // 4J : WESTY : Changed so that time update goes through stats tracking // update code. // 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"); // if (tickCount % 5 == 0) { @@ -296,8 +339,14 @@ void ServerLevel::tick() { // MemSect(0); PIXEndNamedEvent(); + PIXBeginNamedEvent(0, "Tick portal forcer"); + portalForcer->tick(getGameTime()); + PIXEndNamedEvent(); + // repeat after tile ticks + PIXBeginNamedEvent(0, "runTileEvents"); runTileEvents(); + PIXEndNamedEvent(); // 4J Added runQueuedSendTileUpdates(); @@ -318,8 +367,7 @@ void ServerLevel::updateSleepingPlayerList() { m_bAtLeastOnePlayerSleeping = false; AUTO_VAR(itEnd, players.end()); - for (std::vector >::iterator it = players.begin(); - it != itEnd; it++) { + for (AUTO_VAR(it, players.begin()); it != itEnd; it++) { if (!(*it)->isSleeping()) { allPlayersSleeping = false; // break; @@ -477,7 +525,7 @@ void ServerLevel::tickTiles() { m_updateChunkX[iLev][m_updateChunkCount[iLev]] = cp.x; 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); if (random->nextInt(prob) == 0 && isRaining() && isThundering()) { @@ -490,23 +538,21 @@ void ServerLevel::tickTiles() { if (isRainingAt(x, y, z)) { addGlobalEntity(std::shared_ptr( new LightningBolt(this, x, y, z))); - lightningTime = 2; } } // 4J - changes here brought forrward from 1.2.3 if (random->nextInt(16) == 0) { - // 4jcraft added cast to unsigned - randValue = (unsigned)randValue * 3 + (unsigned)addend; + randValue = randValue * 3 + addend; int val = (randValue >> 2); int x = (val & 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)) { - 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)) { - setTile(x + xo, yy, z + zo, Tile::topSnow_Id); + setTileAndUpdate(x + xo, yy, z + zo, Tile::topSnow_Id); } if (isRaining()) { Biome* b = getBiome(x + xo, z + zo); @@ -531,26 +577,42 @@ void ServerLevel::tickTiles() { 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, 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); TickNextTickData td = TickNextTickData(x, y, z, tileId); - int r = 8; - if (getInstaTick()) { - if (hasChunksAt(td.x - r, td.y - r, td.z - r, td.x + r, td.y + r, - td.z + r)) { - 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); + int r = 0; + if (getInstaTick() && tileId > 0) { + if (Tile::tiles[tileId]->canInstantlyTick()) { + r = 8; + if (hasChunksAt(td.x - r, td.y - r, td.z - r, td.x + r, td.y + r, + td.z + r)) { + 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 (tileId > 0) { - td.delay(tickDelay + levelData->getTime()); + td.delay(tickDelay + levelData->getGameTime()); + td.setPriorityTilt(priorityTilt); } EnterCriticalSection(&m_tickNextTickCS); 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, - int tickDelay) { + int tickDelay, int prioTilt) { TickNextTickData td = TickNextTickData(x, y, z, tileId); + td.setPriorityTilt(prioTilt); if (tileId > 0) { - td.delay(tickDelay + levelData->getTime()); + td.delay(tickDelay + levelData->getGameTime()); } EnterCriticalSection(&m_tickNextTickCS); if (tickNextTickSet.find(td) == tickNextTickSet.end()) { @@ -583,12 +646,14 @@ void ServerLevel::tickEntities() { return; } } else { - emptyTime = 0; + resetEmptyTime(); } Level::tickEntities(); } +void ServerLevel::resetEmptyTime() { emptyTime = 0; } + bool ServerLevel::tickPendingTicks(bool force) { EnterCriticalSection(&m_tickNextTickCS); int count = (int)tickNextTickList.size(); @@ -602,22 +667,33 @@ bool ServerLevel::tickPendingTicks(bool force) { AUTO_VAR(itTickList, tickNextTickList.begin()); for (int i = 0; i < count; i++) { TickNextTickData td = *(itTickList); - if (!force && td.m_delay > levelData->getTime()) { + if (!force && td.m_delay > levelData->getGameTime()) { break; } itTickList = tickNextTickList.erase(itTickList); 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, td.z + r)) { 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); } + } else { + addToTickNextTick(td.x, td.y, td.z, td.tileId, 0); } } + toBeTicked.clear(); + int count3 = (int)tickNextTickList.size(); int count4 = (int)tickNextTickSet.size(); @@ -640,20 +716,47 @@ std::vector* ServerLevel::fetchTicksInChunk(LevelChunk* chunk, int south = north + 16; delete pos; - for (AUTO_VAR(it, tickNextTickSet.begin()); it != tickNextTickSet.end();) { - TickNextTickData td = *it; + for (int i = 0; i < 2; i++) { + 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 (remove) { - tickNextTickList.erase(td); - it = tickNextTickSet.erase(it); - } else { - it++; + if (td.x >= xMin && td.x < xMax && td.z >= zMin && + td.z < zMax) { + if (remove) { + tickNextTickSet.erase(td); + it = tickNextTickList.erase(it); + } else { + it++; + } + + results->push_back(td); + } else { + it++; + } } - - results->push_back(td); } 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* ServerLevel::fetchTicksInChunk(LevelChunk* chunk, void ServerLevel::tick(std::shared_ptr e, bool actual) { if (!server->isAnimals() && - ((e->GetType() & eTYPE_ANIMAL) || (e->GetType() & eTYPE_WATERANIMAL))) { + (e->instanceof(eTYPE_ANIMAL) || e->instanceof(eTYPE_WATERANIMAL))) { e->remove(); } if (!server->isNpcsEnabled() && (std::dynamic_pointer_cast(e) != NULL)) { e->remove(); } - if (e->rider.lock() == NULL || - (std::dynamic_pointer_cast(e->rider.lock()) == - NULL)) // 4J - was !(e->rider instanceof Player) - { - Level::tick(e, actual); - } + Level::tick(e, actual); } void ServerLevel::forceTick(std::shared_ptr e, bool actual) { @@ -715,10 +813,7 @@ bool ServerLevel::mayInteract(std::shared_ptr player, int xt, int yt, return true; } else if (dimension->id == 0) // 4J Stu - Only limit this in the overworld { - int xd = (int)Mth::abs((float)(xt - levelData->getXSpawn())); - int zd = (int)Mth::abs((float)(zt - levelData->getZSpawn())); - if (xd > zd) zd = xd; - return (zd > 16 || server->getPlayers()->isOp(player->name)); + return !server->isUnderSpawnProtection(this, xt, yt, zt, player); } return true; } @@ -891,7 +986,7 @@ void ServerLevel::save(bool force, ProgressListener* progressListener, // if( force && !isClientSide ) //{ // if (progressListener != NULL) - //progressListener->progressStage(IDS_PROGRESS_SAVING_TO_DISC); + // progressListener->progressStage(IDS_PROGRESS_SAVING_TO_DISC); // levelStorage->flushSaveFile(); // } } @@ -1073,9 +1168,9 @@ void ServerLevel::runTileEvents() { bool ServerLevel::doTileEvent(TileEventData* te) { int t = getTile(te->getX(), te->getY(), te->getZ()); if (t == te->getTile()) { - Tile::tiles[t]->triggerEvent(this, te->getX(), te->getY(), te->getZ(), - te->getParamA(), te->getParamB()); - return true; + return Tile::tiles[t]->triggerEvent(this, te->getX(), te->getY(), + te->getZ(), te->getParamA(), + te->getParamB()); } return false; } @@ -1101,8 +1196,8 @@ MinecraftServer* ServerLevel::getServer() { return server; } EntityTracker* ServerLevel::getTracker() { return tracker; } -void ServerLevel::setTimeAndAdjustTileTicks(__int64 newTime) { - __int64 delta = newTime - levelData->getTime(); +void ServerLevel::setTimeAndAdjustTileTicks(int64_t newTime) { + int64_t delta = newTime - levelData->getGameTime(); // 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 // 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++) { tickNextTickList.insert(temp[i]); } - setTime(newTime); + setGameTime(newTime); } 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 = + std::shared_ptr(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 player = + std::dynamic_pointer_cast(*it); + player->connection->send(packet); + } +} + // 4J Stu - Sometimes we want to update tiles on the server from the main thread // (eg SignTileEntity when string verify returns) 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 bool ServerLevel::addEntity(std::shared_ptr e) { // If its an item entity, and we've got to our capacity, delete the oldest - if (std::dynamic_pointer_cast(e) != NULL) { + if (e->instanceof(eTYPE_ITEMENTITY)) { // printf("Adding item entity count //%d\n",m_itemEntities.size()); EnterCriticalSection(&m_limiterCS); @@ -1158,7 +1276,7 @@ bool ServerLevel::addEntity(std::shared_ptr e) { } // If its an hanging entity, and we've got to our capacity, delete the // oldest - else if (std::dynamic_pointer_cast(e) != NULL) { + else if (e->instanceof(eTYPE_HANGING_ENTITY)) { // printf("Adding item entity count //%d\n",m_itemEntities.size()); EnterCriticalSection(&m_limiterCS); @@ -1175,7 +1293,7 @@ bool ServerLevel::addEntity(std::shared_ptr e) { LeaveCriticalSection(&m_limiterCS); } // If its an arrow entity, and we've got to our capacity, delete the oldest - else if (std::dynamic_pointer_cast(e) != NULL) { + else if (e->instanceof(eTYPE_ARROW)) { // printf("Adding arrow entity count //%d\n",m_arrowEntities.size()); EnterCriticalSection(&m_limiterCS); @@ -1187,7 +1305,7 @@ bool ServerLevel::addEntity(std::shared_ptr e) { } // If its an experience orb entity, and we've got to our capacity, delete // the oldest - else if (std::dynamic_pointer_cast(e) != NULL) { + else if (e->instanceof(eTYPE_EXPERIENCEORB)) { // printf("Adding arrow entity count //%d\n",m_arrowEntities.size()); EnterCriticalSection(&m_limiterCS); @@ -1200,37 +1318,65 @@ bool ServerLevel::addEntity(std::shared_ptr 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 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 void ServerLevel::entityAddedExtra(std::shared_ptr e) { - if (std::dynamic_pointer_cast(e) != NULL) { + if (e->instanceof(eTYPE_ITEMENTITY)) { EnterCriticalSection(&m_limiterCS); m_itemEntities.push_back(e); // printf("entity added: item entity count now //%d\n",m_itemEntities.size()); LeaveCriticalSection(&m_limiterCS); - } else if (std::dynamic_pointer_cast(e) != NULL) { + } else if (e->instanceof(eTYPE_HANGING_ENTITY)) { EnterCriticalSection(&m_limiterCS); m_hangingEntities.push_back(e); // printf("entity added: item entity count now //%d\n",m_itemEntities.size()); LeaveCriticalSection(&m_limiterCS); - } else if (std::dynamic_pointer_cast(e) != NULL) { + } else if (e->instanceof(eTYPE_ARROW)) { EnterCriticalSection(&m_limiterCS); m_arrowEntities.push_back(e); // printf("entity added: arrow entity count now //%d\n",m_arrowEntities.size()); LeaveCriticalSection(&m_limiterCS); - } else if (std::dynamic_pointer_cast(e) != NULL) { + } else if (e->instanceof(eTYPE_EXPERIENCEORB)) { EnterCriticalSection(&m_limiterCS); m_experienceOrbEntities.push_back(e); // printf("entity added: experience orb entity count now //%d\n",m_arrowEntities.size()); LeaveCriticalSection(&m_limiterCS); - } else if (std::dynamic_pointer_cast(e) != NULL) { + } else if (e->instanceof(eTYPE_PRIMEDTNT)) { EnterCriticalSection(&m_limiterCS); m_primedTntCount++; LeaveCriticalSection(&m_limiterCS); - } else if (std::dynamic_pointer_cast(e) != NULL) { + } else if (e->instanceof(eTYPE_FALLINGTILE)) { EnterCriticalSection(&m_limiterCS); m_fallingTileCount++; LeaveCriticalSection(&m_limiterCS); @@ -1240,7 +1386,7 @@ void ServerLevel::entityAddedExtra(std::shared_ptr e) { // Maintain a cound of primed tnt & falling tiles in this level, and remove any // item entities from our list void ServerLevel::entityRemovedExtra(std::shared_ptr e) { - if (std::dynamic_pointer_cast(e) != NULL) { + if (e->instanceof(eTYPE_ITEMENTITY)) { EnterCriticalSection(&m_limiterCS); // printf("entity removed: item entity count //%d\n",m_itemEntities.size()); @@ -1252,7 +1398,7 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr e) { // printf("entity removed: item entity count now //%d\n",m_itemEntities.size()); LeaveCriticalSection(&m_limiterCS); - } else if (std::dynamic_pointer_cast(e) != NULL) { + } else if (e->instanceof(eTYPE_HANGING_ENTITY)) { EnterCriticalSection(&m_limiterCS); // printf("entity removed: item entity count //%d\n",m_itemEntities.size()); @@ -1265,7 +1411,7 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr e) { // printf("entity removed: item entity count now //%d\n",m_itemEntities.size()); LeaveCriticalSection(&m_limiterCS); - } else if (std::dynamic_pointer_cast(e) != NULL) { + } else if (e->instanceof(eTYPE_ARROW)) { EnterCriticalSection(&m_limiterCS); // printf("entity removed: arrow entity count //%d\n",m_arrowEntities.size()); @@ -1277,7 +1423,7 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr e) { // printf("entity removed: arrow entity count now //%d\n",m_arrowEntities.size()); LeaveCriticalSection(&m_limiterCS); - } else if (std::dynamic_pointer_cast(e) != NULL) { + } else if (e->instanceof(eTYPE_EXPERIENCEORB)) { EnterCriticalSection(&m_limiterCS); // printf("entity removed: experience orb entity count //%d\n",m_arrowEntities.size()); @@ -1290,11 +1436,11 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr e) { // printf("entity removed: experience orb entity count now //%d\n",m_arrowEntities.size()); LeaveCriticalSection(&m_limiterCS); - } else if (std::dynamic_pointer_cast(e) != NULL) { + } else if (e->instanceof(eTYPE_PRIMEDTNT)) { EnterCriticalSection(&m_limiterCS); m_primedTntCount--; LeaveCriticalSection(&m_limiterCS); - } else if (std::dynamic_pointer_cast(e) != NULL) { + } else if (e->instanceof(eTYPE_FALLINGTILE)) { EnterCriticalSection(&m_limiterCS); m_fallingTileCount--; LeaveCriticalSection(&m_limiterCS); @@ -1438,4 +1584,4 @@ void ServerLevel::flagEntitiesToBeRemoved(unsigned int* flags, if (chunkMap) { chunkMap->flagEntitiesToBeRemoved(flags, removedFound); } -} +} \ No newline at end of file diff --git a/Minecraft.Client/Level/ServerLevel.h b/Minecraft.Client/Level/ServerLevel.h index 56b0a9884..a704d6ed7 100644 --- a/Minecraft.Client/Level/ServerLevel.h +++ b/Minecraft.Client/Level/ServerLevel.h @@ -9,7 +9,8 @@ class PlayerChunkMap; class ServerLevel : public Level { 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; EntityTracker* tracker; @@ -35,6 +36,8 @@ public: private: bool allPlayersSleeping; + PortalForcer* portalForcer; + MobSpawner* mobSpawner; int emptyTime; bool m_bAtLeastOnePlayerSleeping; // 4J Added static WeighedTreasureArray @@ -68,10 +71,18 @@ public: protected: void tickTiles(); +private: + std::vector toBeTicked; + public: + bool isTileToBeTickedAt(int x, int y, int z, int tileId); 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 resetEmptyTime(); bool tickPendingTicks(bool force); std::vector* fetchTicksInChunk(LevelChunk* chunk, bool remove); @@ -89,7 +100,7 @@ public: std::vector >* getTileEntitiesInRegion( int x0, int y0, int z0, int x1, int y1, int z1); virtual bool mayInteract(std::shared_ptr player, int xt, int yt, - int zt, int id); + int zt, int content); protected: virtual void initializeLevel(LevelSettings* settings); @@ -141,8 +152,14 @@ protected: public: MinecraftServer* getServer(); EntityTracker* getTracker(); - void setTimeAndAdjustTileTicks(__int64 newTime); + void setTimeAndAdjustTileTicks(int64_t newTime); 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 private: @@ -170,6 +187,8 @@ public: void entityAddedExtra(std::shared_ptr e); void entityRemovedExtra(std::shared_ptr e); + bool atEntityLimit(std::shared_ptr e); // 4J: Added + virtual bool newPrimedTntAllowed(); virtual bool newFallingTileAllowed(); diff --git a/Minecraft.Client/Level/ServerLevelListener.cpp b/Minecraft.Client/Level/ServerLevelListener.cpp index 0440f6dbc..a421a76db 100644 --- a/Minecraft.Client/Level/ServerLevelListener.cpp +++ b/Minecraft.Client/Level/ServerLevelListener.cpp @@ -19,8 +19,8 @@ ServerLevelListener::ServerLevelListener(MinecraftServer* server, // 4J removed - /* -void ServerLevelListener::addParticle(const std::wstring& name, double x, double -y, double z, double xa, double ya, double za) +void ServerLevelListener::addParticle(const wstring& name, double x, double y, +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, int iSound, - double x, double y, double z, float volume, - float pitch, float fClipSoundDist) { +void ServerLevelListener::playSoundExceptPlayer(std::shared_ptr player, + int iSound, double x, double y, + double z, float volume, + float pitch, + float fSoundClipDist) { if (iSound < 0) { app.DebugPrintf( "ServerLevelListener received request for sound less than 0, so " @@ -79,8 +81,6 @@ void ServerLevelListener::playSound(std::shared_ptr entity, int iSound, // 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 // walking , and then I'll hear my footstep sound with a delay - std::shared_ptr player = - std::dynamic_pointer_cast(entity); server->getPlayers()->broadcast( player, x, y, z, volume > 1 ? 16 * volume : 16, level->dimension->id, @@ -108,7 +108,13 @@ void ServerLevelListener::levelEvent(std::shared_ptr source, int type, server->getPlayers()->broadcast( source, x, y, z, 64, level->dimension->id, std::shared_ptr( - 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( + new LevelEventPacket(type, sourceX, sourceY, sourceZ, data, true))); } void ServerLevelListener::destroyTileProgress(int id, int x, int y, int z, diff --git a/Minecraft.Client/Level/ServerLevelListener.h b/Minecraft.Client/Level/ServerLevelListener.h index 6212df1b1..dc313d558 100644 --- a/Minecraft.Client/Level/ServerLevelListener.h +++ b/Minecraft.Client/Level/ServerLevelListener.h @@ -27,9 +27,10 @@ public: // level's player array, not just the entity storage virtual void playSound(int iSound, double x, double y, double z, float volume, float pitch, float fClipSoundDist); - virtual void playSound(std::shared_ptr entity, int iSound, double x, - double y, double z, float volume, float pitch, - float fClipSoundDist); + virtual void playSoundExceptPlayer(std::shared_ptr player, + int iSound, double x, double y, double z, + float volume, float pitch, + float fSoundClipDist); virtual void setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1, Level* level); // 4J - added level param virtual void skyColorChanged(); @@ -39,5 +40,7 @@ public: int z); virtual void levelEvent(std::shared_ptr source, int type, int x, 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); };