Skip to content

Commit

Permalink
Refactored cloud position calculation now to always work in single step
Browse files Browse the repository at this point in the history
Finally managed to write a test that shows that the cloud positioning
fails then there are more than 4 compound types

Fixed cloud positions not staying consistent. Now everything works

except phosphates are invisible
  • Loading branch information
hhyyrylainen committed Feb 15, 2019
1 parent 46d9232 commit 3647c1c
Show file tree
Hide file tree
Showing 8 changed files with 511 additions and 192 deletions.
2 changes: 1 addition & 1 deletion SetupThrive.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def parseExtraArgs
leviathan = Leviathan.new(
# Use this if you always want the latest commit
# version: "develop",
version: "ebaf03d6086c5cac39b66a54093e3926e1c0c359",
version: "28cd2c52dd583e9537f1df32cac91d9b4ed2da2d",
# Doesn't actually work, but leviathan doesn't install with sudo by
# default, or install at all for that matter
noInstallSudo: true
Expand Down
6 changes: 6 additions & 0 deletions src/ThriveGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ ThriveGame::ThriveGame()
StaticGame = this;
}

ThriveGame::ThriveGame(Leviathan::Engine* engine) :
Leviathan::ClientApplication(engine)
{
StaticGame = this;
}

ThriveGame::~ThriveGame()
{
StaticGame = nullptr;
Expand Down
4 changes: 4 additions & 0 deletions src/ThriveGame.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ class ThriveGame : public Leviathan::ClientApplication, public ThriveCommon {

public:
ThriveGame();

//! \brief Version for tests with incomplete engine instance
ThriveGame(Leviathan::Engine* engine);

virtual ~ThriveGame();

// ------------------------------------ //
Expand Down
228 changes: 147 additions & 81 deletions src/microbe_stage/compound_cloud_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,17 @@ std::tuple<float, float>
return std::make_tuple(localX, localY);
}

Float3
CompoundCloudSystem::calculateGridCenterForPlayerPos(const Float3& pos)
{
// The gaps between the positions is used for calculations here. Otherwise
// all clouds get moved when the player moves
return Float3(
static_cast<int>(std::round(pos.X / CLOUD_X_EXTENT)) * CLOUD_X_EXTENT,
0,
static_cast<int>(std::round(pos.Z / CLOUD_Y_EXTENT)) * CLOUD_Y_EXTENT);
}

// ------------------------------------ //
void
CompoundCloudSystem::Run(CellStageWorld& world)
Expand Down Expand Up @@ -713,121 +724,176 @@ void
((((m_cloudTypes.size() + 4 - 1) / 4 * 4) / 4) * 9),
"A CompoundCloud entity has mysteriously been destroyed");

const auto moved = playerPos - m_cloudGridCenter;
// Calculate what our center should be
const auto targetCenter = calculateGridCenterForPlayerPos(playerPos);

// TODO: because we no longer check if the player has moved at least a bit
// it is possible that this gets triggered very often if the player spins
// around a cloud edge, but hopefully there isn't a performance problem and
// that case can just be ignored.
// Z is used here because these are world coordinates
if(std::abs(moved.X) > CLOUD_WIDTH || std::abs(moved.Z) > CLOUD_HEIGHT) {

// Calculate the new center
if(moved.X < -CLOUD_WIDTH) {
m_cloudGridCenter -= Float3(CLOUD_WIDTH * 2, 0, 0);
} else if(moved.X > CLOUD_WIDTH) {
m_cloudGridCenter += Float3(CLOUD_WIDTH * 2, 0, 0);
}
// around a cloud edge.

if(moved.Z < -CLOUD_HEIGHT) {
m_cloudGridCenter -= Float3(0, 0, CLOUD_HEIGHT * 2);
} else if(moved.Z > CLOUD_HEIGHT) {
m_cloudGridCenter += Float3(0, 0, CLOUD_HEIGHT * 2);
}
// This needs an extra variable to track how much the player has moved
// auto moved = playerPos - m_cloudGridCenter;

// Calculate the new positions
const auto requiredCloudPositions{
calculateGridPositions(m_cloudGridCenter)};
if(m_cloudGridCenter != targetCenter) {

m_cloudGridCenter = targetCenter;
applyNewCloudPositioning();
}
}

void
CompoundCloudSystem::applyNewCloudPositioning()
{
// Calculate the new positions
const auto requiredCloudPositions{
calculateGridPositions(m_cloudGridCenter)};

// Reposition clouds according to the origin
// The max amount of clouds is that all need to be moved
const size_t MAX_FAR_CLOUDS = m_managedClouds.size();
// Reposition clouds according to the origin
// The max amount of clouds is that all need to be moved
const size_t MAX_FAR_CLOUDS = m_managedClouds.size();

// According to spec this check is superfluous, but it makes me feel
// better
if(m_tooFarAwayClouds.size() != MAX_FAR_CLOUDS)
m_tooFarAwayClouds.resize(MAX_FAR_CLOUDS);
// According to spec this check is superfluous, but it makes me feel
// better
if(m_tooFarAwayClouds.size() != MAX_FAR_CLOUDS)
m_tooFarAwayClouds.resize(MAX_FAR_CLOUDS);

size_t farAwayIndex = 0;
size_t farAwayIndex = 0;

// All clouds that aren't at one of the requiredCloudPositions needs to
// be moved
for(auto iter = m_managedClouds.begin(); iter != m_managedClouds.end();
++iter) {
// All clouds that aren't at one of the requiredCloudPositions needs to
// be moved. Also only one from each cloud group needs to be at each
// position
for(auto iter = m_managedClouds.begin(); iter != m_managedClouds.end();
++iter) {

const auto pos = iter->second->m_position;
const auto pos = iter->second->m_position;

bool matched = false;
bool matched = false;

// Check if it is at any of the valid positions
for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) {
// Check if it is at any of the valid positions
for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) {

const auto& requiredPos = requiredCloudPositions[i];
const auto& requiredPos = requiredCloudPositions[i];

// An exact check might work but just to be safe slight
// inaccuracy is allowed here
if((pos - requiredPos).HAddAbs() < Leviathan::EPSILON) {
// An exact check might work but just to be safe slight
// inaccuracy is allowed here
if((pos - requiredPos).HAddAbs() < Leviathan::EPSILON) {

matched = true;
break;
}
}
// TODO: this is probably not needed and can be removed
// // It also has to be the only cloud with the first
// // compound id that it has (this is used to filter out
// // multiple clouds of a group being at some position)
// bool duplicate = false;

if(!matched) {
// const auto toCheckID = iter->second->getCompoundId1();

if(farAwayIndex >= MAX_FAR_CLOUDS) {
// for(auto iter2 = m_managedClouds.begin();
// iter2 != m_managedClouds.end(); ++iter2) {

LOG_FATAL("CompoundCloudSystem: Logic error in calculating "
"far away clouds that need to move");
break;
}
// if(iter == iter2)
// continue;

// if(toCheckID == iter2->second->getCompoundId1()) {
// duplicate = true;
// break;
// }
// }

m_tooFarAwayClouds[farAwayIndex++] = iter->second;
// if(!duplicate) {
matched = true;
break;
//}
}
}

// Move clouds that are too far away
// We check through each position that should have a cloud and move one
// where there isn't one
size_t farAwayRepositionedIndex = 0;

// Loop through the cloud groups
for(size_t c = 0; c < m_cloudTypes.size(); c += CLOUDS_IN_ONE) {
// Loop for moving clouds to all needed positions for each group
for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) {
bool hasCloud = false;
const auto& requiredPos = requiredCloudPositions[i];
for(auto iter = m_managedClouds.begin();
iter != m_managedClouds.end(); ++iter) {
const auto pos = iter->second->m_position;
// An exact check might work but just to be safe slight
// inaccuracy is allowed here
if(((pos - requiredPos).HAddAbs() < Leviathan::EPSILON) &&
(m_cloudTypes[c].id ==
iter->second->getCompoundId1())) {
if(!matched) {

if(farAwayIndex >= MAX_FAR_CLOUDS) {

LOG_FATAL("CompoundCloudSystem: Logic error in calculating "
"far away clouds that need to move");
break;
}

m_tooFarAwayClouds[farAwayIndex++] = iter->second;
}
}

// Move clouds that are too far away
// We check through each position that should have a cloud and move one
// where there isn't one. This also needs to take into account the cloud
// groups

// Loop through the cloud groups
for(size_t c = 0; c < m_cloudTypes.size(); c += CLOUDS_IN_ONE) {

const CompoundId groupType = m_cloudTypes[c].id;

// Loop for moving clouds to all needed positions for each group
for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) {

bool hasCloud = false;

const auto& requiredPos = requiredCloudPositions[i];

for(auto iter = m_managedClouds.begin();
iter != m_managedClouds.end(); ++iter) {

const auto pos = iter->second->m_position;
// An exact check might work but just to be safe slight
// inaccuracy is allowed here
if(((pos - requiredPos).HAddAbs() < Leviathan::EPSILON)) {

// Check that the group of the cloud is correct
if(groupType == iter->second->getCompoundId1()) {
hasCloud = true;
break;
}
}
}

if(hasCloud)
continue;

bool filled = false;

// We need to find a cloud from the right group
for(size_t checkReposition = 0; checkReposition < farAwayIndex;
++checkReposition) {

if(hasCloud)
continue;
if(m_tooFarAwayClouds[checkReposition] &&
m_tooFarAwayClouds[checkReposition]->getCompoundId1() ==
groupType) {

if(farAwayRepositionedIndex >= farAwayIndex) {
LOG_FATAL("CompoundCloudSystem: Logic error in moving far "
"clouds (ran out), total to reposition: " +
std::to_string(farAwayIndex + 1) +
", current index: " +
std::to_string(farAwayRepositionedIndex) +
", position grid index: " + std::to_string(i));
// Found a candidate
m_tooFarAwayClouds[checkReposition]->recycleToPosition(
requiredPos);

// Set to null to skip on next scan
m_tooFarAwayClouds[checkReposition] = nullptr;

filled = true;
break;
}
}

m_tooFarAwayClouds[farAwayRepositionedIndex++]
->recycleToPosition(requiredPos);
if(!filled) {
LOG_FATAL("CompoundCloudSystem: Logic error in moving far "
"clouds, didn't find any to use for needed pos");
break;
}
}
}

// TODO: this can be removed once this has been fully confirmed to work fine
// Errors about clouds that should have been moved but haven't been
for(size_t checkReposition = 0; checkReposition < farAwayIndex;
++checkReposition) {
if(m_tooFarAwayClouds[checkReposition]) {
LOG_FATAL(
"CompoundCloudSystem: Logic error in moving far "
"clouds, a cloud that should have been moved wasn't moved");
}
}
}

void
Expand Down
12 changes: 12 additions & 0 deletions src/microbe_stage/compound_cloud_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -479,16 +479,28 @@ class CompoundCloudSystem {
};
}

static Float3
calculateGridCenterForPlayerPos(const Float3& pos);

protected:
//! \brief Removes deleted clouds from m_managedClouds
void
cloudReportDestroyed(CompoundCloudComponent* cloud);

private:
//! \brief Spawns and despawns the cloud entities around the player
//! \todo This should check if the player has moved at least 10 units to
//! avoid excessive recalculations if the player goes in a circle around a
//! cloud boundary
void
doSpawnCycle(CellStageWorld& world, const Float3& playerPos);

//! \brief This method handles moving the clouds
//!
//! This has been separated from doSpawnCycle to be more manageable
void
applyNewCloudPositioning();

void
_spawnCloud(CellStageWorld& world,
const Float3& pos,
Expand Down
Loading

0 comments on commit 3647c1c

Please sign in to comment.