Exemplo n.º 1
0
void CUnitHandler::DeleteUnitsNow()
{
	if (unitsToBeRemoved.empty())
		return;

	while (!unitsToBeRemoved.empty()) {
		DeleteUnitNow(unitsToBeRemoved.back());
		unitsToBeRemoved.pop_back();
	}
}
Exemplo n.º 2
0
void CUnitHandler::Update()
{
    auto UNIT_SANITY_CHECK = [](const CUnit* unit) {
        unit->pos.AssertNaNs();
        unit->midPos.AssertNaNs();
        unit->relMidPos.AssertNaNs();
        unit->speed.AssertNaNs();
        unit->deathSpeed.AssertNaNs();
        unit->rightdir.AssertNaNs();
        unit->updir.AssertNaNs();
        unit->frontdir.AssertNaNs();
        if (unit->unitDef->IsGroundUnit()) {
            assert(unit->pos.x >= -(float3::maxxpos * 16.0f));
            assert(unit->pos.x <=  (float3::maxxpos * 16.0f));
            assert(unit->pos.z >= -(float3::maxzpos * 16.0f));
            assert(unit->pos.z <=  (float3::maxzpos * 16.0f));
        }
    };

    {
        if (!unitsToBeRemoved.empty()) {
            eventHandler.DeleteSyncedUnits();
            while (!unitsToBeRemoved.empty()) {
                CUnit* delUnit = unitsToBeRemoved.back();
                unitsToBeRemoved.pop_back();
                DeleteUnitNow(delUnit);
            }
        }
    }

    {
        SCOPED_TIMER("Unit::MoveType::Update");

        for (CUnit* unit: activeUnits) {
            AMoveType* moveType = unit->moveType;

            UNIT_SANITY_CHECK(unit);

            if (moveType->Update()) {
                eventHandler.UnitMoved(unit);
            }
            if (!unit->pos.IsInBounds() && (unit->speed.w > MAX_UNIT_SPEED)) {
                // this unit is not coming back, kill it now without any death
                // sequence (so deathScriptFinished becomes true immediately)
                unit->KillUnit(NULL, false, true, false);
            }

            UNIT_SANITY_CHECK(unit);
        }
    }

    {
        // Delete dead units
        for (CUnit* unit: activeUnits) {
            if (!unit->deathScriptFinished)
                continue;

            // there are many ways to fiddle with "deathScriptFinished", so a unit may
            // arrive here without having been properly killed (and isDead still false),
            // which can result in MT deadlocking -- FIXME verify this
            // (KU returns early if isDead)
            unit->KillUnit(NULL, false, true);
            DeleteUnit(unit);
        }
    }

    {
        SCOPED_TIMER("Unit::UpdatePieceMatrices");

        for (CUnit* unit: activeUnits) {
            // UnitScript only applies piece-space transforms so
            // we apply the forward kinematics update separately
            // (only if we have any dirty pieces)
            unit->localModel->UpdatePieceMatrices();
        }
    }

    {
        SCOPED_TIMER("Unit::SlowUpdate");

        // reset the iterator every <UNIT_SLOWUPDATE_RATE> frames
        if ((gs->frameNum % UNIT_SLOWUPDATE_RATE) == 0) {
            activeSlowUpdateUnit = activeUnits.begin();
        }

        // stagger the SlowUpdate's
        unsigned int n = (activeUnits.size() / UNIT_SLOWUPDATE_RATE) + 1;

        for (; activeSlowUpdateUnit != activeUnits.end() && n != 0; ++activeSlowUpdateUnit) {
            CUnit* unit = *activeSlowUpdateUnit;

            UNIT_SANITY_CHECK(unit);
            unit->SlowUpdate();
            unit->SlowUpdateWeapons();
            UNIT_SANITY_CHECK(unit);

            n--;
        }
    }

    {
        SCOPED_TIMER("Unit::Update");

        for (CUnit* unit: activeUnits) {
            UNIT_SANITY_CHECK(unit);
            unit->Update();
            UNIT_SANITY_CHECK(unit);
        }
    }

    {
        SCOPED_TIMER("Unit::Weapon::Update");

        for (CUnit* unit: activeUnits) {
            if (unit->CanUpdateWeapons()) {
                for (CWeapon* w: unit->weapons) {
                    w->Update();
                }
            }
        }
    }
}
Exemplo n.º 3
0
void CUnitHandler::Update()
{
	{
		GML_STDMUTEX_LOCK(runit); // Update

		if (!unitsToBeRemoved.empty()) {
			GML_RECMUTEX_LOCK(obj); // Update

			while (!unitsToBeRemoved.empty()) {
				eventHandler.DeleteSyncedObjects(); // the unit destructor may invoke eventHandler, so we need to call these for every unit to clear invaild references from the batching systems

				GML_RECMUTEX_LOCK(unit); // Update

				eventHandler.DeleteSyncedUnits();

				GML_RECMUTEX_LOCK(proj); // Update - projectile drawing may access owner() and lead to crash
				GML_RECMUTEX_LOCK(sel);  // Update - unit is removed from selectedUnits in ~CObject, which is too late.
				GML_RECMUTEX_LOCK(quad); // Update - make sure unit does not get partially deleted before before being removed from the quadfield

				CUnit* delUnit = unitsToBeRemoved.back();
				unitsToBeRemoved.pop_back();

				DeleteUnitNow(delUnit);
			}
		}

		eventHandler.UpdateUnits();
	}

	GML::UpdateTicks();

	#define VECTOR_SANITY_CHECK(v)                              \
		assert(!math::isnan(v.x) && !math::isinf(v.x)); \
		assert(!math::isnan(v.y) && !math::isinf(v.y)); \
		assert(!math::isnan(v.z) && !math::isinf(v.z));
	#define MAPPOS_SANITY_CHECK(unit)                          \
		if (unit->unitDef->IsGroundUnit()) {                   \
			assert(unit->pos.x >= -(float3::maxxpos * 16.0f)); \
			assert(unit->pos.x <=  (float3::maxxpos * 16.0f)); \
			assert(unit->pos.z >= -(float3::maxzpos * 16.0f)); \
			assert(unit->pos.z <=  (float3::maxzpos * 16.0f)); \
		}
	#define UNIT_SANITY_CHECK(unit)                 \
		VECTOR_SANITY_CHECK(unit->pos);             \
		VECTOR_SANITY_CHECK(unit->midPos);          \
		VECTOR_SANITY_CHECK(unit->relMidPos);       \
		VECTOR_SANITY_CHECK(unit->speed);           \
		VECTOR_SANITY_CHECK(unit->deathSpeed);      \
		VECTOR_SANITY_CHECK(unit->residualImpulse); \
		VECTOR_SANITY_CHECK(unit->rightdir);        \
		VECTOR_SANITY_CHECK(unit->updir);           \
		VECTOR_SANITY_CHECK(unit->frontdir);        \
		MAPPOS_SANITY_CHECK(unit);

	{
		SCOPED_TIMER("Unit::MoveType::Update");
		std::list<CUnit*>::iterator usi;
		for (usi = activeUnits.begin(); usi != activeUnits.end(); ++usi) {
			CUnit* unit = *usi;
			AMoveType* moveType = unit->moveType;

			UNIT_SANITY_CHECK(unit);

			if (moveType->Update()) {
				eventHandler.UnitMoved(unit);
			}
			if (!unit->pos.IsInBounds() && (unit->speed.SqLength() > (MAX_UNIT_SPEED * MAX_UNIT_SPEED))) {
				// this unit is not coming back, kill it now without any death
				// sequence (so deathScriptFinished becomes true immediately)
				unit->KillUnit(NULL, false, true, false);
			}

			UNIT_SANITY_CHECK(unit);
			GML::GetTicks(unit->lastUnitUpdate);
		}
	}

	{
		SCOPED_TIMER("Unit::Update");
		std::list<CUnit*>::iterator usi;
		for (usi = activeUnits.begin(); usi != activeUnits.end(); ++usi) {
			CUnit* unit = *usi;

			UNIT_SANITY_CHECK(unit);

			if (unit->deathScriptFinished) {
				// there are many ways to fiddle with "deathScriptFinished", so a unit may
				// arrive here without having been properly killed (and isDead still false),
				// which can result in MT deadlocking -- FIXME verify this
				// (KU returns early if isDead)
				unit->KillUnit(NULL, false, true);

				DeleteUnit(unit);
			} else {
				unit->Update();
			}

			UNIT_SANITY_CHECK(unit);
		}
	}

	{
		SCOPED_TIMER("Unit::SlowUpdate");

		// reset the iterator every <UNIT_SLOWUPDATE_RATE> frames
		if ((gs->frameNum & (UNIT_SLOWUPDATE_RATE - 1)) == 0) {
			activeSlowUpdateUnit = activeUnits.begin();
		}

		// stagger the SlowUpdate's
		int n = (activeUnits.size() / UNIT_SLOWUPDATE_RATE) + 1;

		for (; activeSlowUpdateUnit != activeUnits.end() && n != 0; ++activeSlowUpdateUnit) {
			CUnit* unit = *activeSlowUpdateUnit;

			UNIT_SANITY_CHECK(unit);
			unit->SlowUpdate();
			UNIT_SANITY_CHECK(unit);

			n--;
		}
	}
}
Exemplo n.º 4
0
void CUnitHandler::Update()
{
	{
		if (!unitsToBeRemoved.empty()) {
			while (!unitsToBeRemoved.empty()) {
				eventHandler.DeleteSyncedObjects(); // the unit destructor may invoke eventHandler, so we need to call these for every unit to clear invaild references from the batching systems

				eventHandler.DeleteSyncedUnits();

				CUnit* delUnit = unitsToBeRemoved.back();
				unitsToBeRemoved.pop_back();

				DeleteUnitNow(delUnit);
			}
		}

		eventHandler.UpdateUnits();
	}

	#define MAPPOS_SANITY_CHECK(unit)                          \
		if (unit->unitDef->IsGroundUnit()) {                   \
			assert(unit->pos.x >= -(float3::maxxpos * 16.0f)); \
			assert(unit->pos.x <=  (float3::maxxpos * 16.0f)); \
			assert(unit->pos.z >= -(float3::maxzpos * 16.0f)); \
			assert(unit->pos.z <=  (float3::maxzpos * 16.0f)); \
		}
	#define UNIT_SANITY_CHECK(unit)         \
		unit->pos.AssertNaNs();             \
		unit->midPos.AssertNaNs();          \
		unit->relMidPos.AssertNaNs();       \
		unit->speed.AssertNaNs();           \
		unit->deathSpeed.AssertNaNs();      \
		unit->rightdir.AssertNaNs();        \
		unit->updir.AssertNaNs();           \
		unit->frontdir.AssertNaNs();        \
		MAPPOS_SANITY_CHECK(unit);

	{
		SCOPED_TIMER("Unit::MoveType::Update");

		for (auto usi = activeUnits.begin(); usi != activeUnits.end(); ++usi) {
			CUnit* unit = *usi;
			AMoveType* moveType = unit->moveType;

			UNIT_SANITY_CHECK(unit);

			if (moveType->Update()) {
				eventHandler.UnitMoved(unit);
			}
			if (!unit->pos.IsInBounds() && (Square(unit->speed.w) > (MAX_UNIT_SPEED * MAX_UNIT_SPEED))) {
				// this unit is not coming back, kill it now without any death
				// sequence (so deathScriptFinished becomes true immediately)
				unit->KillUnit(NULL, false, true, false);
			}

			UNIT_SANITY_CHECK(unit);
		}
	}

	{
		// Delete dead units
		for (auto usi = activeUnits.begin(); usi != activeUnits.end(); ++usi) {
			CUnit* unit = *usi;

			if (unit->deathScriptFinished) {
				// there are many ways to fiddle with "deathScriptFinished", so a unit may
				// arrive here without having been properly killed (and isDead still false),
				// which can result in MT deadlocking -- FIXME verify this
				// (KU returns early if isDead)
				unit->KillUnit(NULL, false, true);
				DeleteUnit(unit);
			}
		}
	}

	{
		SCOPED_TIMER("Unit::UpdatePieceMatrices");

		for (auto usi = activeUnits.begin(); usi != activeUnits.end(); ++usi) {
			// UnitScript only applies piece-space transforms so
			// we apply the forward kinematics update separately
			// (only if we have any dirty pieces)
			CUnit* unit = *usi;
			unit->localModel->UpdatePieceMatrices();
		}
	}

	{
		SCOPED_TIMER("Unit::Update");

		for (auto usi = activeUnits.begin(); usi != activeUnits.end(); ++usi) {
			CUnit* unit = *usi;
			UNIT_SANITY_CHECK(unit);
			unit->Update();
			UNIT_SANITY_CHECK(unit);
		}
	}

	{
		SCOPED_TIMER("Unit::SlowUpdate");

		// reset the iterator every <UNIT_SLOWUPDATE_RATE> frames
		if ((gs->frameNum & (UNIT_SLOWUPDATE_RATE - 1)) == 0) {
			activeSlowUpdateUnit = activeUnits.begin();
		}

		// stagger the SlowUpdate's
		unsigned int n = (activeUnits.size() / UNIT_SLOWUPDATE_RATE) + 1;

		for (; activeSlowUpdateUnit != activeUnits.end() && n != 0; ++activeSlowUpdateUnit) {
			CUnit* unit = *activeSlowUpdateUnit;

			UNIT_SANITY_CHECK(unit);
			unit->SlowUpdate();
			UNIT_SANITY_CHECK(unit);

			n--;
		}
	}
}