diff options
| author | Loki Rautio <lokirautio@gmail.com> | 2026-03-04 03:56:03 -0600 |
|---|---|---|
| committer | Loki Rautio <lokirautio@gmail.com> | 2026-03-04 03:56:03 -0600 |
| commit | 42aec6dac53dffa6afe072560a7e1d4986112538 (patch) | |
| tree | 0836426857391df1b6a83f6368a183f83ec9b104 /Minecraft.World/MobSpawner.cpp | |
| parent | c9d58eeac7c72f0b3038e084667b4d89a6249fce (diff) | |
| parent | ef9b6fd500dfabd9463267b0dd9e29577eea8a2b (diff) | |
Merge branch 'main' into pr/win64-world-saves
# Conflicts:
# Minecraft.Client/MinecraftServer.cpp
# README.md
Diffstat (limited to 'Minecraft.World/MobSpawner.cpp')
| -rw-r--r-- | Minecraft.World/MobSpawner.cpp | 191 |
1 files changed, 18 insertions, 173 deletions
diff --git a/Minecraft.World/MobSpawner.cpp b/Minecraft.World/MobSpawner.cpp index d2b4f6fd..8cd60e92 100644 --- a/Minecraft.World/MobSpawner.cpp +++ b/Minecraft.World/MobSpawner.cpp @@ -39,7 +39,7 @@ TilePos MobSpawner::getRandomPosWithin(Level *level, int cx, int cz) unordered_map<ChunkPos,bool,ChunkPosKeyHash,ChunkPosKeyEq> MobSpawner::chunksToPoll; #endif -const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies) +const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies, bool spawnPersistent) { #ifndef _CONTENT_PACKAGE @@ -94,7 +94,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie #endif #endif - if (!spawnEnemies && !spawnFriendlies) + if (!spawnEnemies && !spawnFriendlies && !spawnPersistent) { return 0; } @@ -193,15 +193,24 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie MemSect(31); Pos *spawnPos = level->getSharedSpawnPos(); MemSect(0); - + for (unsigned int i = 0; i < MobCategory::values.length; i++) { MobCategory *mobCategory = MobCategory::values[i]; - if ((mobCategory->isFriendly() && !spawnFriendlies) || (!mobCategory->isFriendly() && !spawnEnemies)) + if ((mobCategory->isFriendly() && !spawnFriendlies) || (!mobCategory->isFriendly() && !spawnEnemies) || (mobCategory->isPersistent() && !spawnPersistent)) { continue; } + // 4J - early out for non-main dimensions, if spawning anything friendly + if( mobCategory->isFriendly() ) + { + if( level->dimension->id != 0 ) + { + continue; + } + } + // 4J - this is now quite different to the java version. We just have global max counts for the level whereas the original has a max per chunk that // scales with the number of chunks to be polled. int categoryCount = level->countInstanceOf( mobCategory->getEnumBaseClass(), mobCategory->isSingleType()); @@ -221,8 +230,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie #endif if( it->second ) { - // don't add mobs to edge chunks, to prevent adding mobs - // "outside" of the active playground + // don't add mobs to edge chunks, to prevent adding mobs "outside" of the active playground continue; } ChunkPos *cp = (ChunkPos *) (&it->first); @@ -247,6 +255,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie int ss = 6; Biome::MobSpawnerData *currentMobType = NULL; + MobGroupData *groupData = NULL; for (int ll = 0; ll < 4; ll++) { @@ -349,8 +358,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie categoryCount++; mob->setDespawnProtected(); // 4J added - default to protected against despawning level->addEntity(mob); - finalizeMobSettings(mob, level, xx, yy, zz); - mob->finalizeMobSpawn(); + groupData = mob->finalizeMobSpawn(groupData); // 4J - change here so that we can't ever make more than the desired amount of entities in each priority. In the original java version // depending on the random spawn positions being considered the only limit as to the number of entities created per category is the number // of chunks to poll. @@ -420,171 +428,7 @@ bool MobSpawner::isSpawnPositionOk(MobCategory *category, Level *level, int x, i int tt = level->getTile(x, y - 1, z); return tt != Tile::unbreakable_Id && !level->isSolidBlockingTile(x, y, z) && !level->getMaterial(x, y, z)->isLiquid() && !level->isSolidBlockingTile(x, y + 1, z); } -} - - -void MobSpawner::finalizeMobSettings(shared_ptr<Mob> mob, Level *level, float xx, float yy, float zz) -{ - if (dynamic_pointer_cast<Spider>( mob ) != NULL && level->random->nextInt(100) == 0) - { - shared_ptr<Skeleton> skeleton = shared_ptr<Skeleton>( new Skeleton(level) ); - skeleton->moveTo(xx, yy, zz, mob->yRot, 0); - level->addEntity(skeleton); - skeleton->ride(mob); - } - else if (dynamic_pointer_cast<Sheep >( mob ) != NULL) - { - (dynamic_pointer_cast<Sheep>( mob ))->setColor(Sheep::getSheepColor(level->random)); - } - else if (dynamic_pointer_cast<Ozelot >( mob ) != NULL) - { - if (level->random->nextInt(7) == 0) - { - for (int kitten = 0; kitten < 2; kitten++) - { - shared_ptr<Ozelot> ozelot = shared_ptr<Ozelot>(new Ozelot(level)); - ozelot->moveTo(xx, yy, zz, mob->yRot, 0); - ozelot->setAge(-20 * 60 * 20); - level->addEntity(ozelot); - } - } - } -} - - -// 4J Stu TODO This was an array of Class type. I haven't made a base Class type yet, but don't need to -// as this can be an array of Mob type? -eINSTANCEOF MobSpawner::bedEnemies[bedEnemyCount] = { - eTYPE_SPIDER, eTYPE_ZOMBIE, eTYPE_SKELETON -}; - - -bool MobSpawner::attackSleepingPlayers(Level *level, vector<shared_ptr<Player> > *players) -{ - - bool somebodyWokeUp = false; - - PathFinder finder = PathFinder(level, true, false, false, true); - - AUTO_VAR(itEnd, players->end()); - for (AUTO_VAR(it, players->begin()); it != itEnd; it++) - { - shared_ptr<Player> player = (*it); - - bool nextPlayer = false; - - for (int attemptCount = 0; attemptCount < 20 && !nextPlayer; attemptCount++)\ - { - - - // limit position within the range of the player - int x = Mth::floor(player->x) + level->random->nextInt(32) - level->random->nextInt(32); - int z = Mth::floor(player->z) + level->random->nextInt(32) - level->random->nextInt(32); - int yStart = Mth::floor(player->y) + level->random->nextInt(16) - level->random->nextInt(16); - if (yStart < 1) - { - yStart = 1; - } - else if (yStart > Level::maxBuildHeight) - { - yStart = Level::maxBuildHeight; - } - - { - int type = level->random->nextInt(bedEnemyCount); - int y = yStart; - - while (y > 2 && !level->isTopSolidBlocking(x, y - 1, z)) - { - y--; - } - - while (!isSpawnPositionOk( (MobCategory *) MobCategory::monster, level, x, y, z) && y < (yStart + 16) && y < Level::maxBuildHeight) - { - y++; - } - if (y >= (yStart + 16) || y >= Level::maxBuildHeight) - { - y = yStart; - continue; } - else - { - float xx = x + 0.5f; - float yy = (float) y; - float zz = z + 0.5f; - - shared_ptr<Mob> mob; -// 4J - removed try/catch -// try -// { - //mob = classes[type].getConstructor(Level.class).newInstance(level); - // 4J - there was a classes array here which duplicated the bedEnemies array but have removed it - mob = dynamic_pointer_cast<Mob>(EntityIO::newByEnumType(bedEnemies[type], level )); -// } -// catch (exception e) -// { -// // TODO 4J Stu - We can't print a stack trace, and newInstance doesn't currently throw an exception anyway -// //e.printStackTrace(); -// return somebodyWokeUp; -// } - - // System.out.println("Placing night mob"); - mob->moveTo(xx, yy, zz, level->random->nextFloat() * 360, 0); - // check if the mob can spawn at this location - if (!mob->canSpawn()) - { - continue; - } - Pos *bedPos = BedTile::findStandUpPosition(level, Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z), 1); - if (bedPos == NULL) - { - // an unlikely case where the bed is - // completely blocked - bedPos = new Pos(x, y + 1, z); - } - - // 4J Stu - TU-1 hotfix - // Fix for #13152 - If the player sleeps in a bed next to a wall in an enclosed, well lit area they will be awoken by a monster - // The pathfinder should attempt to get close to the position that we will move the mob to, - // instead of the player who could be next to a wall. Otherwise the paths gets to the other - // side of the the wall, then moves the mob inside the building - //Path *findPath = finder.findPath(mob.get(), player.get(), 32.0f); - Path *findPath = finder.findPath(mob.get(), bedPos->x, bedPos->y, bedPos->z, 32.0f); - if (findPath != NULL && findPath->getSize() > 1) - { - Node *last = findPath->last(); - - if (abs(last->x - bedPos->x) < 1.5 && abs(last->z - bedPos->z) < 1.5 && abs(last->y - bedPos->y) < 1.5) - { - // System.out.println("Found path!"); - - mob->moveTo(bedPos->x + 0.5f, bedPos->y, bedPos->z + 0.5f, 0, 0); - // the mob would maybe not be able to - // spawn here, but we ignore that now (we assume - // it walked here) - { - level->addEntity(mob); - finalizeMobSettings(mob, level, bedPos->x + 0.5f, (float) bedPos->y, bedPos->z + 0.5f); - mob->finalizeMobSpawn(); - player->stopSleepInBed(true, false, false); - // play a sound effect to scare the player - mob->playAmbientSound(); - somebodyWokeUp = true; - nextPlayer = true; - } - } - delete findPath; - } - delete bedPos; - } - } - } - } - - - return somebodyWokeUp; -} void MobSpawner::postProcessSpawnMobs(Level *level, Biome *biome, int xo, int zo, int cellWidth, int cellHeight, Random *random) { @@ -599,6 +443,7 @@ void MobSpawner::postProcessSpawnMobs(Level *level, Biome *biome, int xo, int zo while (random->nextFloat() < biome->getCreatureProbability()) { Biome::MobSpawnerData *type = (Biome::MobSpawnerData *) WeighedRandom::getRandomItem(level->random, ((vector<WeighedRandomItem *> *)mobs)); + MobGroupData *groupData = NULL; int count = type->minCount + random->nextInt(1 + type->maxCount - type->minCount); int x = xo + random->nextInt(cellWidth); @@ -633,7 +478,7 @@ void MobSpawner::postProcessSpawnMobs(Level *level, Biome *biome, int xo, int zo mob->setDespawnProtected(); level->addEntity(mob); - finalizeMobSettings(mob, level, xx, yy, zz); + groupData = mob->finalizeMobSpawn(groupData); success = true; } |
