mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
TBB for battle AI spellcast an fixes
This commit is contained in:
parent
274bf739b8
commit
03395a3d8a
@ -132,7 +132,12 @@ int64_t AttackPossibility::calculateDamageReduce(
|
|||||||
{
|
{
|
||||||
auto ourUnits = state->battleGetUnitsIf([&](const battle::Unit * u) -> bool
|
auto ourUnits = state->battleGetUnitsIf([&](const battle::Unit * u) -> bool
|
||||||
{
|
{
|
||||||
return u->unitSide() != defender->unitSide() && !u->isTurret();
|
return u->unitSide() != defender->unitSide()
|
||||||
|
&& !u->isTurret()
|
||||||
|
&& u->creatureId() != CreatureID::CATAPULT
|
||||||
|
&& u->creatureId() != CreatureID::BALLISTA
|
||||||
|
&& u->creatureId() != CreatureID::FIRST_AID_TENT
|
||||||
|
&& u->getCount();
|
||||||
});
|
});
|
||||||
|
|
||||||
if(ourUnits.empty())
|
if(ourUnits.empty())
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "StackWithBonuses.h"
|
#include "StackWithBonuses.h"
|
||||||
#include "EnemyInfo.h"
|
#include "EnemyInfo.h"
|
||||||
|
#include "tbb/parallel_for.h"
|
||||||
#include "../../lib/CStopWatch.h"
|
#include "../../lib/CStopWatch.h"
|
||||||
#include "../../lib/CThreadHelper.h"
|
#include "../../lib/CThreadHelper.h"
|
||||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||||
@ -704,96 +705,70 @@ void BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ScriptsCache
|
|
||||||
{
|
|
||||||
//todo: re-implement scripts context cache
|
|
||||||
};
|
|
||||||
|
|
||||||
auto evaluateSpellcast = [&] (PossibleSpellcast * ps, std::shared_ptr<ScriptsCache>)
|
|
||||||
{
|
|
||||||
auto state = std::make_shared<HypotheticBattle>(env.get(), cb);
|
|
||||||
|
|
||||||
spells::BattleCast cast(state.get(), hero, spells::Mode::HERO, ps->spell);
|
|
||||||
cast.castEval(state->getServerCallback(), ps->dest);
|
|
||||||
|
|
||||||
auto allUnits = state->battleGetUnitsIf([](const battle::Unit * u) -> bool{ return true; });
|
|
||||||
|
|
||||||
auto needFullEval = vstd::contains_if(allUnits, [&](const battle::Unit * u) -> bool
|
|
||||||
{
|
|
||||||
auto original = cb->battleGetUnitByID(u->unitId());
|
|
||||||
return !original || u->speed() != original->speed();
|
|
||||||
});
|
|
||||||
|
|
||||||
DamageCache innerCache(&damageCache);
|
|
||||||
innerCache.buildDamageCache(state, side);
|
|
||||||
|
|
||||||
if(needFullEval || !cachedAttack)
|
|
||||||
{
|
|
||||||
PotentialTargets innerTargets(activeStack, damageCache, state);
|
|
||||||
BattleExchangeEvaluator innerEvaluator(state, env);
|
|
||||||
|
|
||||||
if(!innerTargets.possibleAttacks.empty())
|
|
||||||
{
|
|
||||||
innerEvaluator.updateReachabilityMap(state);
|
|
||||||
|
|
||||||
auto newStackAction = innerEvaluator.findBestTarget(activeStack, innerTargets, innerCache, state);
|
|
||||||
|
|
||||||
ps->value = newStackAction.score;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ps->value = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ps->value = scoreEvaluator.calculateExchange(*cachedAttack, *targets, innerCache, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto unit : allUnits)
|
|
||||||
{
|
|
||||||
auto newHealth = unit->getAvailableHealth();
|
|
||||||
auto oldHealth = healthOfStack[unit->unitId()];
|
|
||||||
|
|
||||||
if(oldHealth != newHealth)
|
|
||||||
{
|
|
||||||
auto damage = std::abs(oldHealth - newHealth);
|
|
||||||
auto originalDefender = cb->battleGetUnitByID(unit->unitId());
|
|
||||||
auto dpsReduce = AttackPossibility::calculateDamageReduce(nullptr, originalDefender ? originalDefender : unit, damage, innerCache, state);
|
|
||||||
auto ourUnit = unit->unitSide() == side ? 1 : -1;
|
|
||||||
auto goodEffect = newHealth > oldHealth ? 1 : -1;
|
|
||||||
|
|
||||||
ps->value += ourUnit * goodEffect * dpsReduce;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using EvalRunner = ThreadPool<ScriptsCache>;
|
|
||||||
|
|
||||||
EvalRunner::Tasks tasks;
|
|
||||||
|
|
||||||
for(PossibleSpellcast & psc : possibleCasts)
|
|
||||||
tasks.push_back(std::bind(evaluateSpellcast, &psc, _1));
|
|
||||||
|
|
||||||
uint32_t threadCount = boost::thread::hardware_concurrency();
|
|
||||||
|
|
||||||
if(threadCount == 0)
|
|
||||||
{
|
|
||||||
logGlobal->warn("No information of CPU cores available");
|
|
||||||
threadCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
CStopWatch timer;
|
CStopWatch timer;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<ScriptsCache>> scriptsPool;
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, possibleCasts.size()), [&](const tbb::blocked_range<size_t> & r)
|
||||||
|
{
|
||||||
|
for(auto i = r.begin(); i != r.end(); i++)
|
||||||
|
{
|
||||||
|
auto & ps = possibleCasts[i];
|
||||||
|
auto state = std::make_shared<HypotheticBattle>(env.get(), cb);
|
||||||
|
|
||||||
for(uint32_t idx = 0; idx < threadCount; idx++)
|
spells::BattleCast cast(state.get(), hero, spells::Mode::HERO, ps.spell);
|
||||||
{
|
cast.castEval(state->getServerCallback(), ps.dest);
|
||||||
scriptsPool.emplace_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
EvalRunner runner(&tasks, scriptsPool);
|
auto allUnits = state->battleGetUnitsIf([](const battle::Unit * u) -> bool { return true; });
|
||||||
runner.run();
|
|
||||||
|
auto needFullEval = vstd::contains_if(allUnits, [&](const battle::Unit * u) -> bool
|
||||||
|
{
|
||||||
|
auto original = cb->battleGetUnitByID(u->unitId());
|
||||||
|
return !original || u->speed() != original->speed();
|
||||||
|
});
|
||||||
|
|
||||||
|
DamageCache innerCache(&damageCache);
|
||||||
|
innerCache.buildDamageCache(state, side);
|
||||||
|
|
||||||
|
if(needFullEval || !cachedAttack)
|
||||||
|
{
|
||||||
|
PotentialTargets innerTargets(activeStack, damageCache, state);
|
||||||
|
BattleExchangeEvaluator innerEvaluator(state, env);
|
||||||
|
|
||||||
|
if(!innerTargets.possibleAttacks.empty())
|
||||||
|
{
|
||||||
|
innerEvaluator.updateReachabilityMap(state);
|
||||||
|
|
||||||
|
auto newStackAction = innerEvaluator.findBestTarget(activeStack, innerTargets, innerCache, state);
|
||||||
|
|
||||||
|
ps.value = newStackAction.score;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ps.value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ps.value = scoreEvaluator.calculateExchange(*cachedAttack, *targets, innerCache, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto unit : allUnits)
|
||||||
|
{
|
||||||
|
auto newHealth = unit->getAvailableHealth();
|
||||||
|
auto oldHealth = healthOfStack[unit->unitId()];
|
||||||
|
|
||||||
|
if(oldHealth != newHealth)
|
||||||
|
{
|
||||||
|
auto damage = std::abs(oldHealth - newHealth);
|
||||||
|
auto originalDefender = cb->battleGetUnitByID(unit->unitId());
|
||||||
|
auto dpsReduce = AttackPossibility::calculateDamageReduce(nullptr, originalDefender ? originalDefender : unit, damage, innerCache, state);
|
||||||
|
auto ourUnit = unit->unitSide() == side ? 1 : -1;
|
||||||
|
auto goodEffect = newHealth > oldHealth ? 1 : -1;
|
||||||
|
|
||||||
|
ps.value += ourUnit * goodEffect * dpsReduce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
LOGFL("Evaluation took %d ms", timer.getDiff());
|
LOGFL("Evaluation took %d ms", timer.getDiff());
|
||||||
|
|
||||||
|
@ -37,7 +37,11 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(BattleAI PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(BattleAI PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_link_libraries(BattleAI PRIVATE ${VCMI_LIB_TARGET})
|
target_link_libraries(BattleAI PRIVATE ${VCMI_LIB_TARGET} TBB::tbb)
|
||||||
|
|
||||||
vcmi_set_output_dir(BattleAI "AI")
|
vcmi_set_output_dir(BattleAI "AI")
|
||||||
enable_pch(BattleAI)
|
enable_pch(BattleAI)
|
||||||
|
|
||||||
|
if(APPLE_IOS AND NOT USING_CONAN)
|
||||||
|
install(IMPORTED_RUNTIME_ARTIFACTS TBB::tbb LIBRARY DESTINATION ${LIB_DIR}) # CMake 3.21+
|
||||||
|
endif()
|
||||||
|
@ -52,6 +52,23 @@ StackWithBonuses::StackWithBonuses(const HypotheticBattle * Owner, const battle:
|
|||||||
battle::CUnitState::operator=(*Stack);
|
battle::CUnitState::operator=(*Stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StackWithBonuses::StackWithBonuses(const HypotheticBattle * Owner, const battle::Unit * Stack)
|
||||||
|
: battle::CUnitState(),
|
||||||
|
origBearer(Stack->getBonusBearer()),
|
||||||
|
owner(Owner),
|
||||||
|
type(Stack->unitType()),
|
||||||
|
baseAmount(Stack->unitBaseAmount()),
|
||||||
|
id(Stack->unitId()),
|
||||||
|
side(Stack->unitSide()),
|
||||||
|
player(Stack->unitOwner()),
|
||||||
|
slot(Stack->unitSlot())
|
||||||
|
{
|
||||||
|
localInit(Owner);
|
||||||
|
|
||||||
|
auto state = Stack->acquireState();
|
||||||
|
battle::CUnitState::operator=(*state);
|
||||||
|
}
|
||||||
|
|
||||||
StackWithBonuses::StackWithBonuses(const HypotheticBattle * Owner, const battle::UnitInfo & info)
|
StackWithBonuses::StackWithBonuses(const HypotheticBattle * Owner, const battle::UnitInfo & info)
|
||||||
: battle::CUnitState(),
|
: battle::CUnitState(),
|
||||||
origBearer(nullptr),
|
origBearer(nullptr),
|
||||||
@ -265,7 +282,7 @@ std::shared_ptr<StackWithBonuses> HypotheticBattle::getForUpdate(uint32_t id)
|
|||||||
|
|
||||||
if(iter == stackStates.end())
|
if(iter == stackStates.end())
|
||||||
{
|
{
|
||||||
const CStack * s = subject->battleGetStackByID(id, false);
|
const battle::Unit * s = subject->battleGetUnitByID(id);
|
||||||
|
|
||||||
auto ret = std::make_shared<StackWithBonuses>(this, s);
|
auto ret = std::make_shared<StackWithBonuses>(this, s);
|
||||||
stackStates[id] = ret;
|
stackStates[id] = ret;
|
||||||
|
@ -51,6 +51,8 @@ public:
|
|||||||
|
|
||||||
StackWithBonuses(const HypotheticBattle * Owner, const battle::CUnitState * Stack);
|
StackWithBonuses(const HypotheticBattle * Owner, const battle::CUnitState * Stack);
|
||||||
|
|
||||||
|
StackWithBonuses(const HypotheticBattle * Owner, const battle::Unit * Stack);
|
||||||
|
|
||||||
StackWithBonuses(const HypotheticBattle * Owner, const battle::UnitInfo & info);
|
StackWithBonuses(const HypotheticBattle * Owner, const battle::UnitInfo & info);
|
||||||
|
|
||||||
virtual ~StackWithBonuses();
|
virtual ~StackWithBonuses();
|
||||||
|
Loading…
Reference in New Issue
Block a user