2024-01-20 22:54:30 +02:00
|
|
|
/*
|
|
|
|
* ObjectGraph.h, part of VCMI engine
|
|
|
|
*
|
|
|
|
* Authors: listed in file AUTHORS in main folder
|
|
|
|
*
|
|
|
|
* License: GNU General Public License v2.0 or later
|
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "AINodeStorage.h"
|
|
|
|
#include "../AIUtility.h"
|
|
|
|
|
|
|
|
namespace NKAI
|
|
|
|
{
|
|
|
|
|
|
|
|
class Nullkiller;
|
|
|
|
|
|
|
|
struct ObjectLink
|
|
|
|
{
|
|
|
|
float cost = 100000; // some big number
|
|
|
|
uint64_t danger = 0;
|
|
|
|
|
2024-02-03 12:20:59 +02:00
|
|
|
bool update(float newCost, uint64_t newDanger)
|
2024-01-20 22:54:30 +02:00
|
|
|
{
|
|
|
|
if(cost > newCost)
|
|
|
|
{
|
|
|
|
cost = newCost;
|
|
|
|
danger = newDanger;
|
2024-02-03 12:20:59 +02:00
|
|
|
|
|
|
|
return true;
|
2024-01-20 22:54:30 +02:00
|
|
|
}
|
2024-02-03 12:20:59 +02:00
|
|
|
|
|
|
|
return false;
|
2024-01-20 22:54:30 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ObjectNode
|
|
|
|
{
|
|
|
|
ObjectInstanceID objID;
|
2024-02-03 12:20:59 +02:00
|
|
|
MapObjectID objTypeID;
|
2024-01-20 22:54:30 +02:00
|
|
|
bool objectExists;
|
|
|
|
std::unordered_map<int3, ObjectLink> connections;
|
|
|
|
|
|
|
|
void init(const CGObjectInstance * obj)
|
|
|
|
{
|
|
|
|
objectExists = true;
|
|
|
|
objID = obj->id;
|
2024-02-03 12:20:59 +02:00
|
|
|
objTypeID = obj->ID;
|
2024-01-20 22:54:30 +02:00
|
|
|
}
|
2024-03-17 09:34:54 +02:00
|
|
|
|
|
|
|
void initJunction()
|
|
|
|
{
|
|
|
|
objectExists = false;
|
|
|
|
objID = ObjectInstanceID();
|
|
|
|
objTypeID = Obj();
|
|
|
|
}
|
2024-01-20 22:54:30 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class ObjectGraph
|
|
|
|
{
|
|
|
|
std::unordered_map<int3, ObjectNode> nodes;
|
|
|
|
|
|
|
|
public:
|
|
|
|
void updateGraph(const Nullkiller * ai);
|
|
|
|
void addObject(const CGObjectInstance * obj);
|
2024-03-17 09:34:54 +02:00
|
|
|
void registerJunction(const int3 & pos);
|
2024-01-20 22:54:30 +02:00
|
|
|
void connectHeroes(const Nullkiller * ai);
|
2024-02-11 15:27:56 +02:00
|
|
|
void removeObject(const CGObjectInstance * obj);
|
2024-03-17 09:34:54 +02:00
|
|
|
bool tryAddConnection(const int3 & from, const int3 & to, float cost, uint64_t danger);
|
|
|
|
void removeConnection(const int3 & from, const int3 & to);
|
2024-02-03 12:20:59 +02:00
|
|
|
void dumpToLog(std::string visualKey) const;
|
2024-01-20 22:54:30 +02:00
|
|
|
|
2024-03-24 09:32:29 +02:00
|
|
|
void copyFrom(const ObjectGraph & other)
|
|
|
|
{
|
|
|
|
nodes = other.nodes;
|
|
|
|
}
|
|
|
|
|
2024-01-20 22:54:30 +02:00
|
|
|
template<typename Func>
|
|
|
|
void iterateConnections(const int3 & pos, Func fn)
|
|
|
|
{
|
2024-02-03 12:20:59 +02:00
|
|
|
for(auto & connection : nodes.at(pos).connections)
|
2024-01-20 22:54:30 +02:00
|
|
|
{
|
|
|
|
fn(connection.first, connection.second);
|
|
|
|
}
|
|
|
|
}
|
2024-02-03 12:20:59 +02:00
|
|
|
|
|
|
|
const ObjectNode & getNode(int3 tile) const
|
|
|
|
{
|
|
|
|
return nodes.at(tile);
|
|
|
|
}
|
2024-03-09 16:20:00 +02:00
|
|
|
|
2024-03-17 09:34:54 +02:00
|
|
|
bool hasNodeAt(const int3 & tile) const
|
|
|
|
{
|
|
|
|
return vstd::contains(nodes, tile);
|
|
|
|
}
|
2024-01-20 22:54:30 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct GraphPathNode;
|
|
|
|
|
2024-01-27 22:19:27 +02:00
|
|
|
enum GrapthPathNodeType
|
|
|
|
{
|
|
|
|
NORMAL,
|
|
|
|
|
|
|
|
BATTLE,
|
|
|
|
|
|
|
|
LAST
|
|
|
|
};
|
|
|
|
|
|
|
|
struct GraphPathNodePointer
|
|
|
|
{
|
|
|
|
int3 coord = int3(-1);
|
|
|
|
GrapthPathNodeType nodeType = GrapthPathNodeType::NORMAL;
|
|
|
|
|
|
|
|
GraphPathNodePointer() = default;
|
|
|
|
|
|
|
|
GraphPathNodePointer(int3 coord, GrapthPathNodeType type)
|
|
|
|
:coord(coord), nodeType(type)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
bool valid() const
|
|
|
|
{
|
|
|
|
return coord.valid();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::unordered_map<int3, GraphPathNode[GrapthPathNodeType::LAST]> GraphNodeStorage;
|
|
|
|
|
2024-01-20 22:54:30 +02:00
|
|
|
class GraphNodeComparer
|
|
|
|
{
|
2024-01-27 22:19:27 +02:00
|
|
|
const GraphNodeStorage & pathNodes;
|
2024-01-20 22:54:30 +02:00
|
|
|
|
|
|
|
public:
|
2024-01-27 22:19:27 +02:00
|
|
|
GraphNodeComparer(const GraphNodeStorage & pathNodes)
|
2024-01-20 22:54:30 +02:00
|
|
|
:pathNodes(pathNodes)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-01-27 22:19:27 +02:00
|
|
|
bool operator()(const GraphPathNodePointer & lhs, const GraphPathNodePointer & rhs) const;
|
2024-01-20 22:54:30 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct GraphPathNode
|
|
|
|
{
|
|
|
|
const float BAD_COST = 100000;
|
|
|
|
|
2024-01-27 22:19:27 +02:00
|
|
|
GrapthPathNodeType nodeType = GrapthPathNodeType::NORMAL;
|
|
|
|
GraphPathNodePointer previous;
|
2024-01-20 22:54:30 +02:00
|
|
|
float cost = BAD_COST;
|
|
|
|
uint64_t danger = 0;
|
2024-03-17 09:34:54 +02:00
|
|
|
const CGObjectInstance * obj = nullptr;
|
|
|
|
std::shared_ptr<SpecialAction> specialAction;
|
2024-01-20 22:54:30 +02:00
|
|
|
|
2024-01-27 22:19:27 +02:00
|
|
|
using TFibHeap = boost::heap::fibonacci_heap<GraphPathNodePointer, boost::heap::compare<GraphNodeComparer>>;
|
2024-01-20 22:54:30 +02:00
|
|
|
|
|
|
|
TFibHeap::handle_type handle;
|
|
|
|
bool isInQueue = false;
|
|
|
|
|
|
|
|
bool reachable() const
|
|
|
|
{
|
|
|
|
return cost < BAD_COST;
|
|
|
|
}
|
|
|
|
|
2024-01-27 22:19:27 +02:00
|
|
|
bool tryUpdate(const GraphPathNodePointer & pos, const GraphPathNode & prev, const ObjectLink & link);
|
2024-01-20 22:54:30 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class GraphPaths
|
|
|
|
{
|
|
|
|
ObjectGraph graph;
|
2024-01-27 22:19:27 +02:00
|
|
|
GraphNodeStorage pathNodes;
|
2024-02-03 12:20:59 +02:00
|
|
|
std::string visualKey;
|
2024-01-20 22:54:30 +02:00
|
|
|
|
|
|
|
public:
|
2024-03-24 09:32:29 +02:00
|
|
|
GraphPaths();
|
2024-01-20 22:54:30 +02:00
|
|
|
void calculatePaths(const CGHeroInstance * targetHero, const Nullkiller * ai);
|
|
|
|
void addChainInfo(std::vector<AIPath> & paths, int3 tile, const CGHeroInstance * hero, const Nullkiller * ai) const;
|
2024-03-24 09:32:29 +02:00
|
|
|
void quickAddChainInfoWithBlocker(std::vector<AIPath> & paths, int3 tile, const CGHeroInstance * hero, const Nullkiller * ai) const;
|
2024-01-20 22:54:30 +02:00
|
|
|
void dumpToLog() const;
|
2024-01-27 22:19:27 +02:00
|
|
|
|
|
|
|
private:
|
2024-03-17 09:34:54 +02:00
|
|
|
GraphPathNode & getOrCreateNode(const GraphPathNodePointer & pos)
|
2024-01-27 22:19:27 +02:00
|
|
|
{
|
2024-02-03 12:20:59 +02:00
|
|
|
auto & node = pathNodes[pos.coord][pos.nodeType];
|
|
|
|
|
|
|
|
node.nodeType = pos.nodeType;
|
|
|
|
|
|
|
|
return node;
|
2024-01-27 22:19:27 +02:00
|
|
|
}
|
2024-03-17 09:34:54 +02:00
|
|
|
|
|
|
|
const GraphPathNode & getNode(const GraphPathNodePointer & pos) const
|
|
|
|
{
|
|
|
|
auto & node = pathNodes.at(pos.coord)[pos.nodeType];
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
2024-01-20 22:54:30 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|