4jcraft/Minecraft.Client/Player/EntityTracker.cpp
MatthewBeshay a0fdc643d1 Merge branch 'upstream-dev' into cleanup/nullptr-replacement
# Conflicts:
#	Minecraft.Client/Network/PlayerChunkMap.cpp
#	Minecraft.Client/Network/PlayerList.cpp
#	Minecraft.Client/Network/ServerChunkCache.cpp
#	Minecraft.Client/Platform/Common/Consoles_App.cpp
#	Minecraft.Client/Platform/Common/DLC/DLCManager.cpp
#	Minecraft.Client/Platform/Common/GameRules/LevelGenerationOptions.cpp
#	Minecraft.Client/Platform/Common/GameRules/LevelRuleset.cpp
#	Minecraft.Client/Platform/Common/Tutorial/Tutorial.cpp
#	Minecraft.Client/Platform/Common/Tutorial/TutorialTask.cpp
#	Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.cpp
#	Minecraft.Client/Platform/Common/UI/UIComponent_Panorama.cpp
#	Minecraft.Client/Platform/Common/UI/UIController.cpp
#	Minecraft.Client/Platform/Common/UI/UIController.h
#	Minecraft.Client/Platform/Extrax64Stubs.cpp
#	Minecraft.Client/Platform/Windows64/4JLibs/inc/4J_Input.h
#	Minecraft.Client/Platform/Windows64/4JLibs/inc/4J_Storage.h
#	Minecraft.Client/Player/EntityTracker.cpp
#	Minecraft.Client/Player/ServerPlayer.cpp
#	Minecraft.Client/Rendering/EntityRenderers/PlayerRenderer.cpp
#	Minecraft.Client/Textures/Packs/DLCTexturePack.cpp
#	Minecraft.Client/Textures/Stitching/StitchedTexture.cpp
#	Minecraft.Client/Textures/Stitching/TextureMap.cpp
#	Minecraft.Client/Textures/Textures.cpp
#	Minecraft.World/Blocks/NotGateTile.cpp
#	Minecraft.World/Blocks/PressurePlateTile.cpp
#	Minecraft.World/Blocks/TileEntities/PotionBrewing.cpp
#	Minecraft.World/Enchantments/EnchantmentHelper.cpp
#	Minecraft.World/Entities/HangingEntity.cpp
#	Minecraft.World/Entities/LeashFenceKnotEntity.cpp
#	Minecraft.World/Entities/LivingEntity.cpp
#	Minecraft.World/Entities/Mobs/Boat.cpp
#	Minecraft.World/Entities/Mobs/Minecart.cpp
#	Minecraft.World/Entities/Mobs/Witch.cpp
#	Minecraft.World/Entities/SyncedEntityData.cpp
#	Minecraft.World/Items/LeashItem.cpp
#	Minecraft.World/Items/PotionItem.cpp
#	Minecraft.World/Level/BaseMobSpawner.cpp
#	Minecraft.World/Level/CustomLevelSource.cpp
#	Minecraft.World/Level/Level.cpp
#	Minecraft.World/Level/Storage/DirectoryLevelStorage.cpp
#	Minecraft.World/Level/Storage/McRegionLevelStorage.cpp
#	Minecraft.World/Level/Storage/RegionFileCache.cpp
#	Minecraft.World/Player/Player.cpp
#	Minecraft.World/WorldGen/Biomes/BiomeCache.cpp
#	Minecraft.World/WorldGen/Features/RandomScatteredLargeFeature.cpp
#	Minecraft.World/WorldGen/Layers/BiomeOverrideLayer.cpp
2026-03-30 16:28:40 +11:00

253 lines
9.9 KiB
C++

#include "../Platform/stdafx.h"
#include "EntityTracker.h"
#include "../MinecraftServer.h"
#include "../Network/PlayerList.h"
#include "TrackedEntity.h"
#include "ServerPlayer.h"
#include "../Level/ServerLevel.h"
#include "../../Minecraft.World/Util/Mth.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.item.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.monster.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.player.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.animal.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.global.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.projectile.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.boss.enderdragon.h"
#include "../../Minecraft.World/Headers/net.minecraft.network.packet.h"
#include "../../Minecraft.World/Headers/net.minecraft.network.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.dimension.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.chunk.h"
#include "../Network/PlayerConnection.h"
EntityTracker::EntityTracker(ServerLevel* level) {
this->level = level;
maxRange = level->getServer()->getPlayers()->getMaxRange();
}
void EntityTracker::addEntity(std::shared_ptr<Entity> e) {
if (e->instanceof(eTYPE_SERVERPLAYER)) {
addEntity(e, 32 * 16, 2);
std::shared_ptr<ServerPlayer> player =
std::dynamic_pointer_cast<ServerPlayer>(e);
for (auto it = entities.begin(); it != entities.end(); it++) {
if ((*it)->e != player) {
(*it)->updatePlayer(this, player);
}
}
} else if (e->instanceof(eTYPE_FISHINGHOOK))
addEntity(e, 16 * 4, 5, true);
else if (e->instanceof(eTYPE_SMALL_FIREBALL))
addEntity(e, 16 * 4, 10, false);
else if (e->instanceof(eTYPE_DRAGON_FIREBALL))
addEntity(e, 16 * 4, 10, false); // 4J Added TU9
else if (e->instanceof(eTYPE_ARROW))
addEntity(e, 16 * 4, 20, false);
else if (e->instanceof(eTYPE_FIREBALL))
addEntity(e, 16 * 4, 10, false);
else if (e->instanceof(eTYPE_SNOWBALL))
addEntity(e, 16 * 4, 10, true);
else if (e->instanceof(eTYPE_THROWNENDERPEARL))
addEntity(e, 16 * 4, 10, true);
else if (e->instanceof(eTYPE_EYEOFENDERSIGNAL))
addEntity(e, 16 * 4, 4, true);
else if (e->instanceof(eTYPE_THROWNEGG))
addEntity(e, 16 * 4, 10, true);
else if (e->instanceof(eTYPE_THROWNPOTION))
addEntity(e, 16 * 4, 10, true);
else if (e->instanceof(eTYPE_THROWNEXPBOTTLE))
addEntity(e, 16 * 4, 10, true);
else if (e->instanceof(eTYPE_FIREWORKS_ROCKET))
addEntity(e, 16 * 4, 10, true);
else if (e->instanceof(eTYPE_ITEMENTITY))
addEntity(e, 16 * 4, 20, true);
else if (e->instanceof(eTYPE_MINECART))
addEntity(e, 16 * 5, 3, true);
else if (e->instanceof(eTYPE_BOAT))
addEntity(e, 16 * 5, 3, true);
else if (e->instanceof(eTYPE_SQUID))
addEntity(e, 16 * 4, 3, true);
else if (e->instanceof(eTYPE_WITHERBOSS))
addEntity(e, 16 * 5, 3, false);
else if (e->instanceof(eTYPE_BAT))
addEntity(e, 16 * 5, 3, false);
else if (std::dynamic_pointer_cast<Creature>(e) != nullptr)
addEntity(e, 16 * 5, 3, true);
else if (e->instanceof(eTYPE_ENDERDRAGON))
addEntity(e, 16 * 10, 3, true);
else if (e->instanceof(eTYPE_PRIMEDTNT))
addEntity(e, 16 * 10, 10, true);
else if (e->instanceof(eTYPE_FALLINGTILE))
addEntity(e, 16 * 10, 20, true);
else if (e->instanceof(eTYPE_HANGING_ENTITY))
addEntity(e, 16 * 10, INT_MAX, false);
else if (e->instanceof(eTYPE_EXPERIENCEORB))
addEntity(e, 16 * 10, 20, true);
else if (e->instanceof(eTYPE_ENDER_CRYSTAL))
addEntity(e, 16 * 16, INT_MAX, false);
else if (e->instanceof(eTYPE_ITEM_FRAME))
addEntity(e, 16 * 10, INT_MAX, false);
}
void EntityTracker::addEntity(std::shared_ptr<Entity> e, int range,
int updateInterval) {
addEntity(e, range, updateInterval, false);
}
void EntityTracker::addEntity(std::shared_ptr<Entity> e, int range,
int updateInterval, bool trackDeltas) {
if (range > maxRange) range = maxRange;
if (entityMap.find(e->entityId) != entityMap.end()) {
assert(false); // Entity already tracked
}
if (e->entityId >= 2048) {
__debugbreak();
}
std::shared_ptr<TrackedEntity> te = std::shared_ptr<TrackedEntity>(
new TrackedEntity(e, range, updateInterval, trackDeltas));
entities.insert(te);
entityMap[e->entityId] = te;
te->updatePlayers(this, &level->players);
}
// 4J - have split removeEntity into two bits - it used to do the equivalent of
// EntityTracker::removePlayer followed by EntityTracker::removeEntity. This is
// to allow us to now choose to remove the player as a "seenBy" only when the
// player has actually been removed from the level's own player array
void EntityTracker::removeEntity(std::shared_ptr<Entity> e) {
auto it = entityMap.find(e->entityId);
if (it != entityMap.end()) {
std::shared_ptr<TrackedEntity> te = it->second;
entityMap.erase(it);
entities.erase(te);
te->broadcastRemoved();
}
}
void EntityTracker::removePlayer(std::shared_ptr<Entity> e) {
if (e->GetType() == eTYPE_SERVERPLAYER) {
std::shared_ptr<ServerPlayer> player =
std::dynamic_pointer_cast<ServerPlayer>(e);
for (auto it = entities.begin(); it != entities.end(); it++) {
(*it)->removePlayer(player);
}
// 4J: Flush now to ensure remove packets are sent before player
// respawns and add entity packets are sent
player->flushEntitiesToRemove();
}
}
void EntityTracker::tick() {
std::vector<std::shared_ptr<ServerPlayer> > movedPlayers;
for (auto it = entities.begin(); it != entities.end(); it++) {
std::shared_ptr<TrackedEntity> te = *it;
te->tick(this, &level->players);
if (te->moved && te->e->GetType() == eTYPE_SERVERPLAYER) {
movedPlayers.push_back(
std::dynamic_pointer_cast<ServerPlayer>(te->e));
}
}
// 4J Stu - If one player on a system is updated, then make sure they all
// are as they all have their range extended to include entities visible by
// any other player on the system Fix for #11194 - Gameplay: Host player and
// their split-screen avatars can become invisible and invulnerable to
// client.
MinecraftServer* server = MinecraftServer::getInstance();
for (unsigned int i = 0; i < server->getPlayers()->players.size(); i++) {
std::shared_ptr<ServerPlayer> ep = server->getPlayers()->players[i];
if (ep->dimension != level->dimension->id) continue;
if (ep->connection == nullptr) continue;
INetworkPlayer* thisPlayer = ep->connection->getNetworkPlayer();
if (thisPlayer == nullptr) continue;
bool addPlayer = false;
for (unsigned int j = 0; j < movedPlayers.size(); j++) {
std::shared_ptr<ServerPlayer> sp = movedPlayers[j];
if (sp == ep) break;
if (sp->connection == nullptr) continue;
INetworkPlayer* otherPlayer = sp->connection->getNetworkPlayer();
if (otherPlayer != nullptr && thisPlayer->IsSameSystem(otherPlayer)) {
addPlayer = true;
break;
}
}
if (addPlayer) movedPlayers.push_back(ep);
}
for (unsigned int i = 0; i < movedPlayers.size(); i++) {
std::shared_ptr<ServerPlayer> player = movedPlayers[i];
if (player->connection == nullptr) continue;
for (auto it = entities.begin(); it != entities.end(); it++) {
std::shared_ptr<TrackedEntity> te = *it;
if (te->e != player) {
te->updatePlayer(this, player);
}
}
}
// 4J Stu - We want to do this for dead players as they don't tick normally
for (auto it = level->players.begin(); it != level->players.end();
++it) {
std::shared_ptr<ServerPlayer> player =
std::dynamic_pointer_cast<ServerPlayer>(*it);
if (!player->isAlive()) {
player->flushEntitiesToRemove();
}
}
}
void EntityTracker::broadcast(std::shared_ptr<Entity> e,
std::shared_ptr<Packet> packet) {
auto it = entityMap.find(e->entityId);
if (it != entityMap.end()) {
std::shared_ptr<TrackedEntity> te = it->second;
te->broadcast(packet);
}
}
void EntityTracker::broadcastAndSend(std::shared_ptr<Entity> e,
std::shared_ptr<Packet> packet) {
auto it = entityMap.find(e->entityId);
if (it != entityMap.end()) {
std::shared_ptr<TrackedEntity> te = it->second;
te->broadcastAndSend(packet);
}
}
void EntityTracker::clear(std::shared_ptr<ServerPlayer> serverPlayer) {
for (auto it = entities.begin(); it != entities.end(); it++) {
std::shared_ptr<TrackedEntity> te = *it;
te->clear(serverPlayer);
}
}
void EntityTracker::playerLoadedChunk(std::shared_ptr<ServerPlayer> player,
LevelChunk* chunk) {
for (auto it = entities.begin(); it != entities.end(); ++it) {
std::shared_ptr<TrackedEntity> te = *it;
if (te->e != player && te->e->xChunk == chunk->x &&
te->e->zChunk == chunk->z) {
te->updatePlayer(this, player);
}
}
}
// AP added for Vita so the range can be increased once the level starts
void EntityTracker::updateMaxRange() {
maxRange = level->getServer()->getPlayers()->getMaxRange();
}
std::shared_ptr<TrackedEntity> EntityTracker::getTracker(
std::shared_ptr<Entity> e) {
auto it = entityMap.find(e->entityId);
if (it != entityMap.end()) {
return it->second;
}
return nullptr;
}