| 2374 | } |
| 2375 | |
| 2376 | Vec2F WorldServer::findPlayerStart(Maybe<Vec2F> firstTry) { |
| 2377 | Vec2F spawnRectSize = jsonToVec2F(m_serverConfig.get("playerStartRegionSize")); |
| 2378 | auto maximumVerticalSearch = m_serverConfig.getInt("playerStartRegionMaximumVerticalSearch"); |
| 2379 | auto maximumTries = m_serverConfig.getInt("playerStartRegionMaximumTries"); |
| 2380 | |
| 2381 | static const Set<DungeonId> allowedSpawnDungeonIds = {NoDungeonId, SpawnDungeonId, ConstructionDungeonId, DestroyedBlockDungeonId}; |
| 2382 | |
| 2383 | Vec2F pos; |
| 2384 | if (firstTry) |
| 2385 | pos = *firstTry; |
| 2386 | else |
| 2387 | pos = Vec2F(m_worldTemplate->findSensiblePlayerStart().value(Vec2I(0, m_worldTemplate->surfaceLevel()))); |
| 2388 | |
| 2389 | CollisionSet collideWithAnything{CollisionKind::Null, CollisionKind::Block, CollisionKind::Dynamic, CollisionKind::Platform, CollisionKind::Slippery}; |
| 2390 | for (int t = 0; t < maximumTries; ++t) { |
| 2391 | bool foundGround = false; |
| 2392 | // First go downward until we collide with terrain |
| 2393 | for (int i = 0; i < maximumVerticalSearch; ++i) { |
| 2394 | RectF spawnRect = RectF(pos[0] - spawnRectSize[0] / 2, pos[1], pos[0] + spawnRectSize[0] / 2, pos[1] + spawnRectSize[1]); |
| 2395 | generateRegion(RectI::integral(spawnRect)); |
| 2396 | if (rectTileCollision(RectI::integral(spawnRect), collideWithAnything)) { |
| 2397 | foundGround = true; |
| 2398 | break; |
| 2399 | } |
| 2400 | --pos[1]; |
| 2401 | } |
| 2402 | |
| 2403 | if (foundGround) { |
| 2404 | // Then go up until our spawn region is no longer in the terrain, but bail |
| 2405 | // out and try again if we can't signal the region or we are stuck in a |
| 2406 | // dungeon. |
| 2407 | for (int i = 0; i < maximumVerticalSearch; ++i) { |
| 2408 | if (m_tileArray->tile(Vec2I::floor(pos)).liquid.liquid != EmptyLiquidId) |
| 2409 | break; |
| 2410 | |
| 2411 | RectF spawnRect = RectF(pos[0] - spawnRectSize[0] / 2, pos[1], pos[0] + spawnRectSize[0] / 2, pos[1] + spawnRectSize[1]); |
| 2412 | |
| 2413 | generateRegion(RectI::integral(spawnRect)); |
| 2414 | |
| 2415 | auto tileDungeonId = getServerTile(Vec2I::floor(pos)).dungeonId; |
| 2416 | |
| 2417 | if (!allowedSpawnDungeonIds.contains(tileDungeonId)) |
| 2418 | break; |
| 2419 | |
| 2420 | if (!rectTileCollision(RectI::integral(spawnRect), collideWithAnything) && spawnRect.yMax() < m_geometry.height()) |
| 2421 | return pos; |
| 2422 | |
| 2423 | ++pos[1]; |
| 2424 | } |
| 2425 | } |
| 2426 | |
| 2427 | pos = Vec2F(m_worldTemplate->findSensiblePlayerStart().value(Vec2I(0, m_worldTemplate->surfaceLevel()))); |
| 2428 | } |
| 2429 | |
| 2430 | return pos; |
| 2431 | } |
| 2432 | |
| 2433 | Vec2F WorldServer::findPlayerSpaceStart(float targetX) { |
nothing calls this directly
no test coverage detected