- removed deprecated 'fast' pathfinder that wasn't fast enough and is not going to be used

This commit is contained in:
Mark Vejvoda 2012-09-22 21:05:06 +00:00
parent d91e72a825
commit 871b6c4a6e
8 changed files with 5 additions and 3013 deletions

View File

@ -1,403 +0,0 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2012 Mark Vejvoda
//
// You can redistribute this code and/or modify it under
// the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef __INTRUSIVE_HASH_SET_HPP__
#define __INTRUSIVE_HASH_SET_HPP__
#ifndef WIN32
#include <inttypes.h>
#endif
#include <memory.h>
/*
This is base class for values that can be
stored in intrusive hashset.
*/
struct IntrHashSetNodeBase{
IntrHashSetNodeBase* ihsNextNode;
};
/*
Values must be allocated in (some kind of) a heap.
Not stack.
Values are also nodes in a hash table,
so deleting values that is in hash is bad thing to do.
*/
/*
class TRAITS MUST implement following static members:
bool TRAITS::isEqual(const T* a,const T* b);
uint32_t TRAITS::getHashCode(const T* a);
*/
template <class T,class TRAITS>
class IntrHashSet{
protected:
typedef T Node;
// copy constructor is protected
// values CANNOT be copied since
// they are allocated outside of this container!
IntrHashSet(const IntrHashSet&);
public:
// default constructor
// preAlloc values CANNOT be zero!
IntrHashSet(int preAlloc=128)
{
hash=new Node*[preAlloc];
memset(hash,0,sizeof(Node*)*preAlloc);
hashSize=preAlloc;
collisionsCount=0;
}
//destructor
~IntrHashSet()
{
if(hash)
{
delete [] hash;
}
}
//just empties container without deleting values!
void Clear()
{
collisionsCount=0;
memset(hash,0,sizeof(Node*)*hashSize);
}
//insert allocated value
void Insert(T* value)
{
if(collisionsCount>hashSize/2)
{
Rehash();
}
uint32_t hidx=getIndex(value);
Node*& nodePtr=hash[hidx];
collisionsCount+=nodePtr!=0?1:0;
value->ihsNextNode=nodePtr;
nodePtr=value;
}
//iterator
//can be used to iterate over all values of hash
//and also returned by find method and can be
//use to delete value from hash faster
class ConstIterator{
public:
ConstIterator(const IntrHashSet* argHash):node(0),parent(0),index(0),hash(argHash){}
ConstIterator(const IntrHashSet& argHash):node(0),parent(0),index(0),hash(&argHash){}
const T* Get()const
{
return node;
}
bool Found()const
{
return node!=0;
}
void Rewind()
{
index=0;
node=0;
parent=0;
}
bool Next()
{
if(index>=hash->hashSize)
{
return false;
}
if(index==0 && node==0 && parent==0)
{
parent=&hash->hash;
node=*parent;
if(node)
{
return true;
}
}
while(node==0)
{
index++;
if(index>=hash->hashSize)
{
return false;
}
parent=hash->hash+index;
node=*parent;
if(node)
{
return true;
}
}
if(*parent!=node)
{
parent=(Node**)&(*parent)->ihsNextNode;
}
node=(Node*)node->ihsNextNode;
if(node)
{
return true;
}
return Next();
}
protected:
ConstIterator(const IntrHashSet* argHash,uint32_t argIndex,const Node* argNode,const Node*const* argParent):
node(argNode),parent(argParent),index(argIndex),hash(argHash){}
const Node* node;
const Node*const* parent;
uint32_t index;
const IntrHashSet* hash;
friend class IntrHashSet;
};
//mutable version of iterator
//however it's not good idea to modify key part of stored value
class Iterator{
public:
Iterator(IntrHashSet* argHash):node(0),parent(0),index(0),hash(argHash){}
Iterator(IntrHashSet& argHash):node(0),parent(0),index(0),hash(&argHash){}
T* Get()
{
return node;
}
bool Found()const
{
return node!=0;
}
void Rewind()
{
index=0;
node=0;
parent=0;
}
bool Next()
{
if(index>=hash->hashSize)
{
return false;
}
if(index==0 && node==0 && parent==0)
{
parent=hash->hash;
node=*parent;
if(node)
{
return true;
}
}
while(node==0)
{
index++;
if(index>=hash->hashSize)
{
return false;
}
parent=hash->hash+index;
node=*parent;
if(node)
{
return true;
}
}
if(*parent!=node)
{
parent=(Node**)&(*parent)->ihsNextNode;
}
node=(Node*)node->ihsNextNode;
if(node)
{
return true;
}
return Next();
}
protected:
Iterator(IntrHashSet* argHash,uint32_t argIndex,Node* argNode,Node** argParent):
node(argNode),parent(argParent),index(argIndex),hash(argHash){}
Node* node;
Node** parent;
uint32_t index;
IntrHashSet* hash;
friend class IntrHashSet;
};
//constant version of find
//returned iterator can be used to obtain found value
//or delete it from hashet
ConstIterator Find(const T& value)const
{
uint32_t hidx=getIndex(&value);
Node*const* nodePtr=&hash[hidx];
if(!*nodePtr)return ConstIterator(0);
if(TRAITS::isEqual((*nodePtr),&value))
{
return ConstIterator(this,hidx,*nodePtr,nodePtr);
}
Node*const* parentPtr=nodePtr;
Node* node=(Node*)(*nodePtr)->ihsNextNode;
while(node)
{
if(TRAITS::isEqual(node,&value))
{
return ConstIterator(this,hidx,node,parentPtr);
}
parentPtr=nodePtr;
nodePtr=(Node**)&node->ihsNextNode;
node=(Node*)node->ihsNextNode;
}
return ConstIterator(0);
}
//non constant version of find
Iterator Find(const T& value)
{
uint32_t hidx=getIndex(&value);
Node** nodePtr=&hash[hidx];
if(!*nodePtr)return Iterator(0);
if(TRAITS::isEqual((*nodePtr),&value))
{
return Iterator(this,hidx,*nodePtr,nodePtr);
}
Node** parentPtr=nodePtr;
Node* node=(Node*)(*nodePtr)->ihsNextNode;
while(node)
{
if(TRAITS::isEqual(node,&value))
{
return Iterator(this,hidx,node,parentPtr);
}
parentPtr=nodePtr;
nodePtr=(Node**)&node->ihsNextNode;
node=(Node*)node->ihsNextNode;
}
return Iterator(0);
}
//delete element from hashset 'by value'
//actual value IS NOT DEALLOCATED
//and should be deallocated separately
void Delete(const T& value)
{
uint32_t hidx=getIndex(&value);
Node** nodePtr=hash+hidx;
if(TRAITS::isEqual((*nodePtr),&value))
{
Node* node=*nodePtr;
*nodePtr=(Node*)node->ihsNextNode;
if(*nodePtr)
{
collisionsCount--;
}
return;
}
Node* parentPtr=*nodePtr;
Node* node=(Node*)(*nodePtr)->ihsNextNode;
while(node)
{
if(TRAITS::isEqual(node,&value))
{
parentPtr->ihsNextNode=node->ihsNextNode;
return;
}
parentPtr=node;
node=(Node*)node->ihsNextNode;
}
}
//delete element by iterator returned from Find
//or used for iteration.
//iterator used for Delete is no longer valid
//for iteration, however element it refer to
//is still here and Get is still valid after Delete.
//actuall value also IS NOT DEALLOCATED!
void Delete(const Iterator& hi)
{
Node** parentPtr=(Node**)hi.parent;
Node* node=(Node*)hi.node;
if(!node)
{
return;
}
if(*parentPtr==node)
{
*parentPtr=(Node*)node->ihsNextNode;
}else
{
(*parentPtr)->ihsNextNode=node->ihsNextNode;
}
if(*parentPtr)
{
collisionsCount--;
}
}
protected:
// get index of a bucket in a hash table
uint32_t getIndex(const T* value)const
{
uint32_t hashCode=TRAITS::getHashCode(value);
return hashCode%hashSize;
}
// increase hash table size if there are
// too much collisions
void Rehash()
{
Node** oldHash=hash;
Node** oldHashEnd=hash+hashSize;
hashSize*=2;
hash=new Node*[hashSize];
memset(hash,0,sizeof(Node*)*hashSize);
collisionsCount=0;
for(Node** it=oldHash;it!=oldHashEnd;it++)
{
Node* node=*it;
Node* nextNode;
while(node)
{
uint32_t hidx=getIndex(node);
Node** nodePtr=hash+hidx;
if(*nodePtr)
{
collisionsCount++;
}
nextNode=(Node*)node->ihsNextNode;
node->ihsNextNode=*nodePtr;
*nodePtr=node;
node=nextNode;
}
}
}
// hash table itself
Node** hash;
// size of hash table
size_t hashSize;
// number of collisions
int collisionsCount;
};
#endif

View File

@ -1,546 +0,0 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2012 Mark Vejvoda
//
// You can redistribute this code and/or modify it under
// the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef __INTRUSIVE_HEAP_HASH_SET_HPP__
#define __INTRUSIVE_HEAP_HASH_SET_HPP__
#ifndef WIN32
#include <inttypes.h>
#endif
#include <vector>
#include "IntrHashSet.hpp"
/*
Here is temlate class Intrusive Heap/HashSet.
Actuall values are stored in this container,
no copying is performed, so all values should
be allocated in a heap or in a storage with
lifetime as long as lifetime of container.
Values are also used as nodes of container,
so no value can be stored in two containers
of this kind simultaneously.
*/
/*
This is what should be done with duplicate
from hash point of view values.
*/
enum HHDuplicatePolicy{
hhdpReplaceOld, //replace old value. old values is not deallocated!
hhdpKeepOld, //container is not modified in this case.
hhdpInsertDuplicate //duplicates are stored in container
};
/*
TRAITS class MUST implement following static members:
for heap - this is something like operator< or operator>
bool TRAITS::Compare(const T* a,const T* b);
for hash
bool TRAITS::isEqual(const T* a,const T* b);
uint32_t TRAITS::getHashCode(const T& a);
*/
/*
This is base class for values stored in a intrusive heap hash
*/
struct IntrHeapHashNodeBase:public IntrHashSetNodeBase{
int ihhNodeIndex;
};
template <class T,class TRAITS,HHDuplicatePolicy policy=hhdpReplaceOld>
class IntrHeapHash{
public:
//default constructor
//preAlloc value cannot be 0!
IntrHeapHash(int preAlloc=128)
{
hash=new Node*[preAlloc];
memset(hash,0,preAlloc*sizeof(Node*));
hashSize=preAlloc;
heap=new Node*[preAlloc];
memset(heap,0,preAlloc*sizeof(Node*));
heapSize=0;
heapAlloc=preAlloc;
collisionsCount=0;
}
//guess what? destructor!
~IntrHeapHash()
{
delete [] hash;
delete [] heap;
}
// clear content container
// values are not deallocated!
void Clear()
{
memset(hash,0,hashSize*sizeof(Node*));
heapSize=0;
collisionsCount=0;
}
//insert new value into container
//return value is equal to inserted value for all policies if no duplicate detected
//in case of duplicate for keep old policy 0 is returned
//in case of duplicate for replace old policy old value is returned
T* Insert(T* value)
{
if(collisionsCount>hashSize/2)
{
Rehash();
}
uint32_t hidx=getIndex(value);
Node*& node=hash[hidx];
T* rv=value;
if(policy==hhdpReplaceOld || policy==hhdpKeepOld)
{
Node* ptr=FindHashNode(node,*value);
if(ptr)
{
if(policy==hhdpKeepOld)
{
return 0;
}
DeleteHashNode(hash+hidx,ptr);
rv=ptr;
}
}
value->ihhNodeIndex=heapSize;
if(node)
{
collisionsCount++;
}
value->ihsNextNode=node;
node=value;
if(heapSize==heapAlloc)
{
heapAlloc*=2;
Node** newHeap=new Node*[heapAlloc];
memcpy(newHeap,heap,heapSize*sizeof(Node*));
delete [] heap;
heap=newHeap;
}
heap[heapSize++]=value;
HeapPush();
return rv;
}
// value at the head of heap
const T* getHead()const
{
return *heap;
}
// same as previous but non const
T* getHead()
{
return **heap;
}
// get and remove head value of heap
T* Pop()
{
T* rv=*heap;
uint32_t hidx=getIndex(rv);
DeleteHashNode(&hash[hidx],rv);
HeapSwap(heap,heap+heapSize-1);
heapSize--;
HeapPop();
return rv;
}
//find value in hash
//const version
const T* Find(const T& value)const
{
uint32_t hidx=getIndex(&value);
Node* ptr=hash[hidx];
while(ptr)
{
if(TRAITS::isEqual(ptr,&value))
{
return ptr;
}
ptr=(Node*)ptr->ihsNextNode;
}
return 0;
}
//find value in hash
//non const version
//it's not good idea to modify key value of hash or key value of heap however
T* Find(const T& value)
{
uint32_t hidx=getIndex(&value);
Node* ptr=hash[hidx];
while(ptr)
{
if(TRAITS::isEqual(ptr,&value))
{
return ptr;
}
ptr=(Node*)ptr->ihsNextNode;
}
return 0;
}
//get from hash all values equal to given
void GetAll(const T& value,std::vector<T*>& values)const
{
uint32_t hidx=getIndex(&value);
Node* ptr=hash[hidx];
while(ptr)
{
if(TRAITS::isEqual(ptr,&value))
{
values.push_back(ptr);
}
ptr=(Node*)ptr->ihsNextNode;
}
}
//delete value from hash
//deleted object returned
T* Delete(const T& value)
{
uint32_t hidx=getIndex(&value);
int idx=DeleteHashNode(hash+hidx,value);
if(idx==-1)
{
return 0;
}
if(idx==heapSize-1)
{
heapSize--;
return heap[heapSize];
}
HeapSwap(heap+idx,heap+heapSize-1);
heapSize--;
HeapFix(idx);
return heap[heapSize];
}
//delete all values equal to given
void DeleteAll(const T& value)
{
uint32_t hidx=getIndex(&value);
Node** nodePtr=hash+hidx;
while(*nodePtr)
{
int idx=DeleteHashNode(nodePtr,value);
if(idx==-1)
{
return;
}
if(idx==heapSize-1)
{
heapSize--;
continue;
}
HeapSwap(heap+idx,heap+heapSize-1);
heapSize--;
HeapFix(idx);
}
}
//get number of elements in container
size_t getSize()const
{
return heapSize;
}
//check if container is empty
bool isEmpty()const
{
return heapSize==0;
}
//iterator
//can/should be used like this:
//for(IHHTypeDef::Iterator it(ihh);it.Next();)
//{
// dosomething(it.Get())
//}
class Iterator{
public:
Iterator(const IntrHeapHash& argHH)
{
begin=argHH.heap;
current=0;
end=argHH.heap+argHH.heapSize;
}
bool Next()
{
if(current==0)
{
current=begin;
}else
{
current++;
}
return current!=end;
}
T* Get()
{
if(current)
{
return *current;
}
return 0;
}
void Rewind()
{
current=begin;
}
protected:
typename IntrHeapHash::Node **begin,**current,**end;
};
protected:
//protected copy constructor
//values cannot be copied as well as container
IntrHeapHash(const IntrHeapHash&);
//typedef for convenience
typedef T Node;
//heap array
Node** heap;
//hash table
Node** hash;
//size of hash table
size_t hashSize;
//used size of heap
size_t heapSize;
//allocated size of heap
size_t heapAlloc;
//count of collisions in hash
int collisionsCount;
//get index of value in hash table
uint32_t getIndex(const T* value)const
{
uint32_t hashCode=TRAITS::getHashCode(value);
return hashCode%hashSize;
}
//resize hash table when
//collisions count is too big
void Rehash()
{
Node** oldHash=hash;
Node** oldHashEnd=oldHash+hashSize;
hashSize*=2;
hash=new Node*[hashSize];
memset(hash,0,hashSize*sizeof(Node*));
collisionsCount=0;
for(Node** it=oldHash;it!=oldHashEnd;it++)
{
Node* nodePtr=*it;
while(nodePtr)
{
uint32_t hidx=getIndex(nodePtr);
Node*& hnode=hash[hidx];
if(hnode)
{
collisionsCount++;
}
Node* next=(Node*)nodePtr->ihsNextNode;
nodePtr->ihsNextNode=hnode;
hnode=nodePtr;
nodePtr=next;
}
}
}
//find and delete hash node from bucket by ptr
void DeleteHashNode(Node** nodeBasePtr,Node* nodePtr)
{
if(*nodeBasePtr==nodePtr)
{
*nodeBasePtr=(Node*)nodePtr->ihsNextNode;
if(*nodeBasePtr)
{
collisionsCount--;
}
return;
}
Node* parentPtr=*nodeBasePtr;
Node* iterPtr=(Node*)parentPtr->ihsNextNode;
while(iterPtr)
{
if(iterPtr==nodePtr)
{
parentPtr->ihsNextNode=nodePtr->ihsNextNode;
collisionsCount--;
return;
}
parentPtr=iterPtr;
iterPtr=(Node*)iterPtr->ihsNextNode;
}
}
//find and delete hash node from bucked by value
//heap index returned
int DeleteHashNode(Node** nodePtr,const T& data)
{
if(!*nodePtr)return -1;
if(TRAITS::isEqual(*nodePtr,&data))
{
int rv=(*nodePtr)->ihhNodeIndex;
*nodePtr=(Node*)(*nodePtr)->ihsNextNode;
if(*nodePtr)
{
collisionsCount--;
}
return rv;
}
Node* parentPtr=*nodePtr;
Node* node=(Node*)(*nodePtr)->ihsNextNode;
while(node)
{
if(TRAITS::isEqual(node,&data))
{
parentPtr->ihsNextNode=node->ihsNextNode;
collisionsCount--;
return node->ihhNodeIndex;
}
parentPtr=node;
node=(Node*)node->ihsNextNode;
}
return -1;
}
//find hash node in a bucked by value
Node* FindHashNode(Node* nodePtr,const T& data)
{
while(nodePtr)
{
if(TRAITS::isEqual(nodePtr,&data))
{
return nodePtr;
}
nodePtr=(Node*)nodePtr->ihsNextNode;
}
return 0;
}
//float up tail element
void HeapPush(int didx=-1)
{
int idx=didx==-1?heapSize-1:didx;
int pidx;
Node** b=heap;
Node** i=b+idx;
Node** pi;
Node* ptr=*i;
while(idx)
{
pidx=(idx-1)/2;
pi=b+pidx;
if(TRAITS::Compare(ptr,(*pi)))
{
*i=*pi;
(*i)->ihhNodeIndex=idx;
i=pi;
idx=pidx;
}else
{
break;
}
}
*i=ptr;
ptr->ihhNodeIndex=idx;
}
//drow down element from head
void HeapPop(int idx=0)
{
if(heapSize<=1)
{
return;
}
Node **i,**b,**i1,**i2;
int cidx1,cidx2;
b=heap;
i=b+idx;
Node* ptr=*i;
while(idx<heapSize)
{
cidx1=idx*2+1;
cidx2=idx*2+2;
if(cidx1>=heapSize)
{
break;
}
i1=b+cidx1;
i2=b+cidx2;
if(cidx2>=heapSize || TRAITS::Compare((*i1),(*i2)))
{
if(!TRAITS::Compare(ptr,(*i1)))
{
*i=*i1;
(*i)->ihhNodeIndex=idx;
idx=cidx1;
i=i1;
}else
{
break;
}
}else
{
if(!TRAITS::Compare(ptr,(*i2)))
{
*i=*i2;
(*i)->ihhNodeIndex=idx;
idx=cidx2;
i=i2;
}else
{
break;
}
}
}
*i=ptr;
ptr->ihhNodeIndex=idx;
}
//either drow down or float up element at middle
void HeapFix(int idx)
{
int pidx=(idx-1)/2;
if(TRAITS::Compare(heap[idx],heap[pidx]))
{
HeapPush(idx);
}else
{
HeapPop(idx);
}
}
//swap two element fixing indeces
void HeapSwap(Node** i1,Node** i2)
{
int idx1=(*i1)->ihhNodeIndex;
int idx2=(*i2)->ihhNodeIndex;
Node* ptr=*i1;
*i1=*i2;
(*i1)->ihhNodeIndex=idx1;
(*i2)=ptr;
(*i2)->ihhNodeIndex=idx2;
}
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,155 +0,0 @@
/*!
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2012 Mark Vejvoda
//
// You can redistribute this code and/or modify it under
// the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches)
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliff@infiniplex.net
A* Algorithm Implementation using STL is
Copyright (C)2001-2005 Justin Heyes-Jones
FixedSizeAllocator class
Copyright 2001 Justin Heyes-Jones
This class is a constant time O(1) memory manager for objects of
a specified type. The type is specified using a template class.
Memory is allocated from a fixed size buffer which you can specify in the
class constructor or use the default.
Using GetFirst and GetNext it is possible to iterate through the elements
one by one, and this would be the most common use for the class.
I would suggest using this class when you want O(1) add and delete
and you don't do much searching, which would be O(n). Structures such as binary
trees can be used instead to get O(logn) access time.
**
** The MIT license:
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is furnished
** to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in all
** copies or substantial portions of the Software.
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef FAST_ASTAR_H
#define FAST_ASTAR_H
//*** IMPORTANT : READ ME FIRST !!
//***
//*** This source code simply provides a C++ wrapper for the AStar Algorithm Implementation in STL written by Justin Heyes-Jones
//*** There is nothing wrong with Justin's code in any way, except that he uses templates. My personal programming style is
//*** to use virtual interfaces and the PIMPLE paradigm to hide the details of the implementation.
//***
//*** To use my wrapper you simply have your own path node inherit the pure virtual interface 'AI_Node' and implement the
//*** following four methods.
//***
//***
//** virtual float getDistance(const AI_Node *node) = 0; // Return the distance between two nodes
//** virtual float getCost(void) = 0; // return the relative 'cost' of a node. Default should be 1.
//** virtual unsigned int getEdgeCount(void) const = 0; // Return the number of edges in a node.
//** virtual AI_Node * getEdge(int index) const = 0; // Return a pointer to the node a particular edge is connected to.
//**
//** That's all there is to it.
//**
//** Here is an example usage:
//**
//** FastAstar *fa = createFastAstar();
//** astarStartSearch(fq,fromNode,toNode);
//** for (int i=0; i<10000; i++)
//** {
//** bool finished = astarSearchStep(fa);
//** if ( finished ) break;
//** }
//**
//** unsigned int count;
//** AI_Node **solution = getSolution(fa,count);
//**
//** ... do something you want with the answer
//**
//** releaseFastAstar(fa);
//**
//*******************************
#include "data_types.h"
using namespace Shared::Platform;
class AI_Node
{
public:
virtual float getDistance(const AI_Node *node,void *userData) = 0;
virtual float getCost(void *userData) = 0;
virtual unsigned int getEdgeCount(void *userData) const = 0;
virtual AI_Node * getEdge(int index,void *userData) const = 0;
virtual int32 getHashCode() const = 0;
virtual ~AI_Node() {}
};
enum SearchState {
SEARCH_STATE_NOT_INITIALISED,
SEARCH_STATE_SEARCHING,
SEARCH_STATE_SUCCEEDED,
SEARCH_STATE_FAILED,
SEARCH_STATE_OUT_OF_MEMORY,
SEARCH_STATE_INVALID
};
class FastAstar;
FastAstar * createFastAstar(void); // Create an instance of the FastAstar utility.
void astarStartSearch(FastAstar *astar,AI_Node *from,AI_Node *to, void *userData); // start a search.
bool astarSearchStep(FastAstar *astar,unsigned int &searchCount); // step the A star algorithm one time. Return true if the search is completed.
SearchState getLastSearchState(FastAstar *astar);
AI_Node ** getSolution(FastAstar *astar,unsigned int &count); // retrieve the solution. If this returns a null pointer and count of zero, it means no solution could be found.
void releaseFastAstar(FastAstar *astar); // Release the intance of the FastAstar utility.
#endif

View File

@ -21,7 +21,6 @@
#include "command.h"
#include "faction.h"
#include "randomgen.h"
#include "fast_path_finder.h"
#include "leak_dumper.h"
using namespace std;
@ -87,9 +86,6 @@ void PathFinder::init(const Map *map) {
PathFinder::~PathFinder() {
for(int i = 0; i < GameConstants::maxPlayers; ++i) {
factions[i].nodePool.clear();
releaseFastAstar(factions[i].fa);
factions[i].fa = NULL;
}
factions.clear();
map=NULL;
@ -229,18 +225,9 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu
uint32 searched_node_count = 0;
minorDebugPathfinder = false;
//bool enableFastPathfinder = Config::getInstance().getBool("EnableFastPathFinder","false");
bool enableFastPathfinder = false;
if(enableFastPathfinder == true) {
if(minorDebugPathfinder) printf("Fast Pathfind Unit [%d - %s] from = %s to = %s frameIndex = %d\n",unit->getId(),unit->getType()->getName().c_str(),unit->getPos().getString().c_str(),finalPos.getString().c_str(),frameIndex);
if(minorDebugPathfinder) printf("Legacy Pathfind Unit [%d - %s] from = %s to = %s frameIndex = %d\n",unit->getId(),unit->getType()->getName().c_str(),unit->getPos().getString().c_str(),finalPos.getString().c_str(),frameIndex);
ts = aStarFast(unit, finalPos, false, frameIndex, maxNodeCount,&searched_node_count);
}
else {
if(minorDebugPathfinder) printf("Legacy Pathfind Unit [%d - %s] from = %s to = %s frameIndex = %d\n",unit->getId(),unit->getType()->getName().c_str(),unit->getPos().getString().c_str(),finalPos.getString().c_str(),frameIndex);
ts = aStar(unit, finalPos, false, frameIndex, maxNodeCount,&searched_node_count);
}
ts = aStar(unit, finalPos, false, frameIndex, maxNodeCount,&searched_node_count);
//post actions
switch(ts) {
@ -317,12 +304,7 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu
int maxBailoutNodeCount = (PathFinder::pathFindBailoutRadius * 2);
if(enableFastPathfinder == true) {
ts= aStarFast(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count);
}
else {
ts= aStar(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count);
}
ts= aStar(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count);
}
}
}
@ -344,12 +326,7 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu
//printf("$$$$ Unit BAILOUT(1) ASTAR ATTEMPT for [%d - %s] newFinalPos = [%s]\n",unit->getId(),unit->getFullName().c_str(),newFinalPos.getString().c_str());
int maxBailoutNodeCount = (PathFinder::pathFindBailoutRadius * 2);
if(enableFastPathfinder == true) {
ts= aStarFast(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count);
}
else {
ts= aStar(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count);
}
ts= aStar(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count);
}
}
}
@ -428,7 +405,6 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu
break;
}
//if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() >= 1) printf("In [%s::%s Line: %d] fastastar took [%lld] msecs, ts = %d nodeSearchCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),ts,nodeSearchCount);
if(minorDebugPathfinderPerformance && chrono.getMillis() >= 1) printf("Unit [%d - %s] astar took [%lld] msecs, ts = %d searched_node_count = %d.\n",unit->getId(),unit->getType()->getName().c_str(),(long long int)chrono.getMillis(),ts,searched_node_count);
return ts;
@ -436,511 +412,6 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu
// ==================== PRIVATE ====================
TravelState PathFinder::aStarFast(Unit *unit, Vec2i finalPos, bool inBailout, int frameIndex, int maxNodeCount,uint32 *searched_node_count) {
TravelState ts = tsImpossible;
Chrono chrono;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
if(maxNodeCount < 0) {
maxNodeCount = factions[unit->getFactionIndex()].useMaxNodeCount;
//printf("AStar set maxNodeCount = %d\n",maxNodeCount);
}
if(maxNodeCount >= 1 && unit->getPathfindFailedConsecutiveFrameCount() >= 3) {
//int orgmaxNodeCount = maxNodeCount;
maxNodeCount = 200;
//printf("AStar maxpath cut for unit [%d - %s] to %d [orig: %d] [unit->getPathfindFailedConsecutiveFrameCount(): %d]\n",unit->getId(),unit->getFullName().c_str(), maxNodeCount,orgmaxNodeCount,unit->getPathfindFailedConsecutiveFrameCount());
}
UnitPathInterface *path= unit->getPath();
int unitFactionIndex = unit->getFactionIndex();
//factions[unitFactionIndex].nodePoolCount= 0;
//factions[unitFactionIndex].openNodesList.clear();
//factions[unitFactionIndex].openPosList.clear();
//factions[unitFactionIndex].closedNodesList.clear();
if(frameIndex >= 0) {
clearUnitPrecache(unit);
}
// check the pre-cache to see if we can re-use a cached path
if(frameIndex < 0) {
if(factions[unitFactionIndex].precachedTravelState.find(unit->getId()) != factions[unitFactionIndex].precachedTravelState.end()) {
if(factions[unitFactionIndex].precachedTravelState[unit->getId()] == tsMoving) {
bool canMoveToCells = true;
Vec2i lastPos = unit->getPos();
for(int i=0; i < factions[unitFactionIndex].precachedPath[unit->getId()].size(); i++) {
Vec2i nodePos = factions[unitFactionIndex].precachedPath[unit->getId()][i];
if(map->isInside(nodePos) == false || map->isInsideSurface(map->toSurfCoords(nodePos)) == false) {
throw megaglest_runtime_error("Pathfinder invalid node path position = " + nodePos.getString() + " i = " + intToStr(i));
}
//if(i < pathFindRefresh ||
if(i < unit->getPathFindRefreshCellCount() ||
(factions[unitFactionIndex].precachedPath[unit->getId()].size() >= pathFindExtendRefreshForNodeCount &&
i < getPathFindExtendRefreshNodeCount(unitFactionIndex))) {
//!!! Test MV
if(canUnitMoveSoon(unit, lastPos, nodePos) == false) {
canMoveToCells = false;
break;
}
lastPos = nodePos;
}
else {
break;
}
}
if(canMoveToCells == true) {
path->clear();
UnitPathBasic *basicPathFinder = dynamic_cast<UnitPathBasic *>(path);
for(int i=0; i < factions[unitFactionIndex].precachedPath[unit->getId()].size(); i++) {
Vec2i nodePos = factions[unitFactionIndex].precachedPath[unit->getId()][i];
if(map->isInside(nodePos) == false || map->isInsideSurface(map->toSurfCoords(nodePos)) == false) {
throw megaglest_runtime_error("Pathfinder invalid node path position = " + nodePos.getString() + " i = " + intToStr(i));
}
//if(i < pathFindRefresh ||
if(i < unit->getPathFindRefreshCellCount() ||
(factions[unitFactionIndex].precachedPath[unit->getId()].size() >= pathFindExtendRefreshForNodeCount &&
i < getPathFindExtendRefreshNodeCount(unitFactionIndex))) {
path->add(nodePos);
}
//else if(tryLastPathCache == false) {
// break;
//}
//if(tryLastPathCache == true && basicPathFinder) {
if(basicPathFinder) {
basicPathFinder->addToLastPathCache(nodePos);
}
}
unit->setUsePathfinderExtendedMaxNodes(false);
return factions[unitFactionIndex].precachedTravelState[unit->getId()];
}
else {
clearUnitPrecache(unit);
}
}
else if(factions[unitFactionIndex].precachedTravelState[unit->getId()] == tsBlocked) {
path->incBlockCount();
unit->setUsePathfinderExtendedMaxNodes(false);
return factions[unitFactionIndex].precachedTravelState[unit->getId()];
}
}
}
else {
clearUnitPrecache(unit);
}
const Vec2i unitPos = unit->getPos();
finalPos= computeNearestFreePos(unit, finalPos);
float dist= unitPos.dist(finalPos);
factions[unitFactionIndex].useMaxNodeCount = PathFinder::pathFindNodesMax;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
// Check the previous path find cache for the unit to see if its good to
// use
const bool showConsoleDebugInfo = Config::getInstance().getBool("EnablePathfinderDistanceOutput","false");
const bool tryLastPathCache = Config::getInstance().getBool("EnablePathfinderCache","false");
if(showConsoleDebugInfo || tryLastPathCache) {
if(showConsoleDebugInfo && dist > 60) printf("Distance from [%d - %s] to destination is %.2f tryLastPathCache = %d\n",unit->getId(),unit->getFullName().c_str(), dist,tryLastPathCache);
if(tryLastPathCache == true && path != NULL) {
UnitPathBasic *basicPathFinder = dynamic_cast<UnitPathBasic *>(path);
if(basicPathFinder != NULL && basicPathFinder->getLastPathCacheQueueCount() > 0) {
vector<Vec2i> cachedPath= basicPathFinder->getLastPathCacheQueue();
for(int i = 0; i < cachedPath.size(); ++i) {
Vec2i &pos1 = cachedPath[i];
// Looking to find if the unit is in one of the cells in the cached path
if(unitPos == pos1) {
// Now see if we can re-use this path to get to the final destination
for(int j = i+1; j < cachedPath.size(); ++j) {
Vec2i &pos2 = cachedPath[j];
bool canUnitMoveToCell = map->aproxCanMove(unit, pos1, pos2);
if(canUnitMoveToCell == true) {
if(pos2 == finalPos) {
//on the way
ts= tsMoving;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
//store path
if(frameIndex < 0) {
basicPathFinder->clear();
}
int pathCount=0;
for(int k=i+1; k <= j; k++) {
if(k >= cachedPath.size()) {
throw megaglest_runtime_error("k >= cachedPath.size() k = " + intToStr(k) + " cachedPath.size() = " + intToStr(cachedPath.size()));
}
if(frameIndex >= 0) {
factions[unitFactionIndex].precachedPath[unit->getId()].push_back(cachedPath[k]);
}
else {
//if(pathCount < pathFindRefresh) {
if(pathCount < unit->getPathFindRefreshCellCount()) {
basicPathFinder->add(cachedPath[k]);
}
basicPathFinder->addToLastPathCache(cachedPath[k]);
}
pathCount++;
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
char szBuf[4096]="";
sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] inBailout [%d] ts [%d]",
factions[unitFactionIndex].openNodesList.size(),factions[unitFactionIndex].openPosList.size(),finalPos.getString().c_str(),inBailout,ts);
unit->logSynchData(__FILE__,__LINE__,szBuf);
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) {
string commandDesc = "none";
Command *command= unit->getCurrCommand();
if(command != NULL && command->getCommandType() != NULL) {
commandDesc = command->getCommandType()->toString();
}
char szBuf[1024]="";
sprintf(szBuf,"State: moving, cmd [%s] pos: %s Queue= %d",commandDesc.c_str(),unit->getPos().getString().c_str(), path->getQueueCount());
unit->setCurrentUnitTitle(szBuf);
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
unit->setUsePathfinderExtendedMaxNodes(false);
return ts;
}
//else if(j - i > pathFindRefresh) {
else if(j - i > unit->getPathFindRefreshCellCount()) {
//on the way
ts= tsMoving;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
//store path
if(frameIndex < 0) {
basicPathFinder->clear();
}
int pathCount=0;
for(int k=i+1; k < cachedPath.size(); k++) {
if(k >= cachedPath.size()) {
throw megaglest_runtime_error("#2 k >= cachedPath.size() k = " + intToStr(k) + " cachedPath.size() = " + intToStr(cachedPath.size()));
}
if(frameIndex >= 0) {
factions[unitFactionIndex].precachedPath[unit->getId()].push_back(cachedPath[k]);
}
else {
//if(pathCount < pathFindRefresh) {
if(pathCount < unit->getPathFindRefreshCellCount()) {
basicPathFinder->add(cachedPath[k]);
}
basicPathFinder->addToLastPathCache(cachedPath[k]);
}
pathCount++;
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
char szBuf[4096]="";
sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] inBailout [%d] ts [%d]",
factions[unitFactionIndex].openNodesList.size(),factions[unitFactionIndex].openPosList.size(),finalPos.getString().c_str(),inBailout,ts);
unit->logSynchData(__FILE__,__LINE__,szBuf);
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) {
string commandDesc = "none";
Command *command= unit->getCurrCommand();
if(command != NULL && command->getCommandType() != NULL) {
commandDesc = command->getCommandType()->toString();
}
char szBuf[1024]="";
sprintf(szBuf,"State: moving, cmd [%s] pos: %s Queue= %d",commandDesc.c_str(),unit->getPos().getString().c_str(), path->getQueueCount());
unit->setCurrentUnitTitle(szBuf);
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
unit->setUsePathfinderExtendedMaxNodes(false);
return ts;
}
}
pos1 = pos2;
}
break;
}
}
}
}
}
//path find algorithm
//b) loop
bool pathFound = true;
bool nodeLimitReached = false;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
// First check if unit currently blocked all around them, if so don't try to pathfind
if(inBailout == false && unitPos != finalPos) {
int failureCount = 0;
int cellCount = 0;
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
Vec2i pos = unitPos + Vec2i(i, j);
if(pos != unitPos) {
//!!! Test MV
bool canUnitMoveToCell = canUnitMoveSoon(unit, unitPos, pos);
if(canUnitMoveToCell == false) {
failureCount++;
}
cellCount++;
}
}
}
nodeLimitReached = (failureCount == cellCount);
pathFound = !nodeLimitReached;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] **Check if dest blocked, distance for unit [%d - %s] from [%s] to [%s] is %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d\n",__FILE__,__FUNCTION__,__LINE__,unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount);
if(showConsoleDebugInfo && nodeLimitReached) {
printf("**Check if src blocked [%d - %d], unit [%d - %s] from [%s] to [%s] distance %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d [%d]\n",
nodeLimitReached, inBailout, unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount,cellCount);
}
if(nodeLimitReached == false) {
// First check if final destination blocked
failureCount = 0;
cellCount = 0;
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
Vec2i pos = finalPos + Vec2i(i, j);
if(pos != finalPos) {
//!!! Test MV
bool canUnitMoveToCell = canUnitMoveSoon(unit, pos, finalPos);
if(canUnitMoveToCell == false) {
failureCount++;
}
cellCount++;
}
}
}
nodeLimitReached = (failureCount == cellCount);
pathFound = !nodeLimitReached;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] **Check if dest blocked, distance for unit [%d - %s] from [%s] to [%s] is %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d\n",__FILE__,__FUNCTION__,__LINE__,unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount);
if(showConsoleDebugInfo && nodeLimitReached) {
printf("**Check if dest blocked [%d - %d], unit [%d - %s] from [%s] to [%s] distance %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d [%d]\n",
nodeLimitReached, inBailout, unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount,cellCount);
}
}
}
//
//finalPos= computeNearestFreePos(unit, finalPos);
FastAINodeCache nodeCache(unit);
// Start of New Fast AStar
FastAINode *fromNode = map->getCellNode(unit->getPos());
FastAINode *toNode = map->getCellNode(finalPos);
//FastAstar *fa = createFastAstar();
FastAstar *fa = factions[unitFactionIndex].fa;
astarStartSearch(fa,fromNode,toNode, &nodeCache);
pathFound = false;
unsigned int nodeSearchCount=0;
unsigned int count=0;
AI_Node **solution = NULL;
if(nodeLimitReached == false) {
for(nodeSearchCount=0; pathFound == false && nodeSearchCount < maxNodeCount; ++nodeSearchCount) {
unsigned int search_count=0;
pathFound = astarSearchStep(fa,search_count);
//printf("Fast Pathfind Unit [%d - %s] finished = %d search_count = %d i = %d\n",unit->getId(),unit->getType()->getName().c_str(),finished,search_count,i);
}
solution = getSolution(fa,count);
}
if(searched_node_count != NULL) {
*searched_node_count = nodeSearchCount;
}
if(count <= 1 || getLastSearchState(fa) != SEARCH_STATE_SUCCEEDED) {
if(minorDebugPathfinder) printf("Fast Pathfind Unit [%d - %s] NOT FOUND PATH frameIndex = %d nodeSearchCount = %d\n",unit->getId(),unit->getType()->getName().c_str(),frameIndex,nodeSearchCount);
//blocked
if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) {
string commandDesc = "none";
Command *command= unit->getCurrCommand();
if(command != NULL && command->getCommandType() != NULL) {
commandDesc = command->getCommandType()->toString();
}
std::pair<Vec2i,int> lastHarvest = unit->getLastHarvestResourceTarget();
char szBuf[4096]="";
sprintf(szBuf,"State: blocked, cmd [%s] pos: [%s], lastHarvest = [%s - %d], reason C= %d, D= %d, F = %d",
commandDesc.c_str(),unit->getPos().getString().c_str(), lastHarvest.first.getString().c_str(),lastHarvest.second, path->getBlockCount(), path->isBlocked(), path->isStuck());
unit->setCurrentUnitTitle(szBuf);
}
if(frameIndex < 0) {
unit->setUsePathfinderExtendedMaxNodes(false);
}
ts= tsBlocked;
if(frameIndex < 0) {
path->incBlockCount();
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
char szBuf[4096]="";
sprintf(szBuf,"[path for unit BLOCKED] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] ts [%d]",
factions[unitFactionIndex].openNodesList.size(),factions[unitFactionIndex].openPosList.size(),finalPos.getString().c_str(),ts);
unit->logSynchData(__FILE__,__LINE__,szBuf);
}
//if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
unit->setLastStuckFrameToCurrentFrame();
unit->setLastStuckPos(finalPos);
// Now see if the unit is eligble for pathfind max nodes boost?
if(nodeSearchCount >= maxNodeCount) {
unit->incrementPathfindFailedConsecutiveFrameCount();
}
else {
unit->resetPathfindFailedConsecutiveFrameCount();
}
}
else {
if(minorDebugPathfinder) printf("Fast Pathfind Unit [%d - %s] FOUND PATH count = %d frameIndex = %d nodeSearchCount = %d\n",unit->getId(),unit->getType()->getName().c_str(),count,frameIndex,nodeSearchCount);
ts= tsMoving;
UnitPathInterface *path= unit->getPath();
//if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
if(frameIndex < 0) {
if(maxNodeCount == pathFindNodesAbsoluteMax) {
unit->setUsePathfinderExtendedMaxNodes(true);
}
else {
unit->setUsePathfinderExtendedMaxNodes(false);
}
}
//store path
if(frameIndex < 0) {
path->clear();
}
UnitPathBasic *basicPathFinder = dynamic_cast<UnitPathBasic *>(path);
for(int i=0; i < count; ++i) {
FastAINode *node = dynamic_cast<FastAINode *>(solution[i]);
const Vec2i &nodePos = node->getPos();
if(nodePos != unit->getPos()) {
if(map->isInside(nodePos) == false || map->isInsideSurface(map->toSurfCoords(nodePos)) == false) {
throw megaglest_runtime_error("Pathfinder invalid node path position = " + nodePos.getString() + " i = " + intToStr(i));
}
//if(minorDebugPathfinder) printf("nodePos [%s]\n",nodePos.getString().c_str());
if(frameIndex >= 0) {
factions[unitFactionIndex].precachedPath[unit->getId()].push_back(nodePos);
}
else {
//if(i < pathFindRefresh ||
if(i < unit->getPathFindRefreshCellCount() ||
(nodeSearchCount >= pathFindExtendRefreshForNodeCount &&
i < getPathFindExtendRefreshNodeCount(unitFactionIndex))) {
path->add(nodePos);
}
else if(tryLastPathCache == false) {
break;
}
//if(tryLastPathCache == true && basicPathFinder) {
if(basicPathFinder) {
basicPathFinder->addToLastPathCache(nodePos);
}
}
}
}
//if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
char szBuf[4096]="";
sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] ts [%d]",
factions[unitFactionIndex].openNodesList.size(),factions[unitFactionIndex].openPosList.size(),finalPos.getString().c_str(),ts);
unit->logSynchData(__FILE__,__LINE__,szBuf);
string pathToTake = "";
for(int i = 0; i < path->getQueueCount(); ++i) {
Vec2i &pos = path->getQueue()[i];
if(pathToTake != "") {
pathToTake += ", ";
}
pathToTake += pos.getString();
}
unit->logSynchData(__FILE__,__LINE__,szBuf);
sprintf(szBuf,"Path for unit to take = %s",pathToTake.c_str());
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) {
string commandDesc = "none";
Command *command= unit->getCurrCommand();
if(command != NULL && command->getCommandType() != NULL) {
commandDesc = command->getCommandType()->toString();
}
char szBuf[1024]="";
sprintf(szBuf,"State: moving, cmd [%s] pos: %s, Queue= %d",commandDesc.c_str(),unit->getPos().getString().c_str(), path->getQueueCount());
unit->setCurrentUnitTitle(szBuf);
}
//if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
}
//releaseFastAstar(fa);
// End of New Fast AStar
//factions[unitFactionIndex].openNodesList.clear();
//factions[unitFactionIndex].openPosList.clear();
//factions[unitFactionIndex].closedNodesList.clear();
//if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
if(frameIndex >= 0) {
factions[unitFactionIndex].precachedTravelState[unit->getId()] = ts;
}
//else {
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() >= 1) printf("In [%s::%s Line: %d] fastastar took [%lld] msecs, ts = %d nodeSearchCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),ts,nodeSearchCount);
//if(chrono.getMillis() >= 1) printf("In [%s::%s Line: %d] fastastar took [%lld] msecs, ts = %d nodeSearchCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),ts,nodeSearchCount);
//}
return ts;
}
bool PathFinder::addToOpenSet(Unit *unit, Node *node,const Vec2i finalPos, Vec2i sucPos, bool &nodeLimitReached,int maxNodeCount,Node **newNodeAdded, bool bypassChecks) {
bool result = false;

View File

@ -24,7 +24,7 @@
#include "skill_type.h"
#include "map.h"
#include "unit.h"
#include "fast_path_finder.h"
//#include <tr1/unordered_map>
//using namespace std::tr1;
@ -114,8 +114,6 @@ public:
//mapFromToNodeList.clear();
//lastFromToNodeListFrame = -100;
badCellList.clear();
fa = createFastAstar();
}
~FactionState() {
//fa = NULL;
@ -135,8 +133,6 @@ public:
//std::map<int, std::map<Vec2i,std::map<Vec2i, bool> > > mapFromToNodeList;
std::map<int,std::map<Field,BadUnitNodeList> > badCellList;
FastAstar *fa;
};
typedef vector<FactionState> FactionStateList;
@ -173,7 +169,6 @@ public:
void loadGame(const XmlNode *rootNode);
private:
TravelState aStarFast(Unit *unit, Vec2i finalPos, bool inBailout, int frameIndex, int maxNodeCount=-1,uint32 *searched_node_count=NULL);
TravelState aStar(Unit *unit, const Vec2i &finalPos, bool inBailout, int frameIndex, int maxNodeCount=-1,uint32 *searched_node_count=NULL);
//Node *newNode(FactionState &faction,int maxNodeCount);
inline static Node *newNode(FactionState &faction, int maxNodeCount) {

View File

@ -279,142 +279,6 @@ void SurfaceCell::loadGame(const XmlNode *rootNode, int index, World *world) {
// class Map
// =====================================================
FastAINode * FastAINode::getNodeForEdgeIndex(int index,void *userData) const {
FastAINode *resultNode = NULL;
switch(index) {
case 0: // north
resultNode = map->getCellNode(pos.x,pos.y-1,false);
break;
case 1: // north east
resultNode = map->getCellNode(pos.x+1,pos.y-1,false);
break;
case 2: // east
resultNode = map->getCellNode(pos.x+1,pos.y,false);
break;
case 3: // south east
resultNode = map->getCellNode(pos.x+1,pos.y+1,false);
break;
case 4: // south
resultNode = map->getCellNode(pos.x,pos.y+1,false);
break;
case 5: // south west
resultNode = map->getCellNode(pos.x-1,pos.y+1,false);
break;
case 6: // west
resultNode = map->getCellNode(pos.x-1,pos.y,false);
break;
case 7: // north west
resultNode = map->getCellNode(pos.x-1,pos.y-1,false);
break;
}
bool checkCellObjects = true;
if(checkCellObjects == true && resultNode != NULL) {
FastAINodeCache *nodeCache = (FastAINodeCache *)userData;
std::map<Vec2i,std::map<Vec2i,bool> >::const_iterator iterFind = nodeCache->cachedCanMoveSoonList.find(pos);
if(iterFind != nodeCache->cachedCanMoveSoonList.end() &&
iterFind->second.find(resultNode->getPos()) != iterFind->second.end()) {
const std::map<Vec2i,bool> &mapCache2 = iterFind->second;
std::map<Vec2i,bool>::const_iterator iterFind2 = mapCache2.find(resultNode->getPos());
if(iterFind2->second == false) {
resultNode = NULL;
}
}
else {
const Vec2i &nodePos = resultNode->getPos();
if(resultNode->getPos() != nodeCache->unit->getCurrentPathFinderDesiredFinalPos()) {
if(map->aproxCanMoveSoon(nodeCache->unit, pos, resultNode->getPos()) == false) {
resultNode = NULL;
}
}
nodeCache->cachedCanMoveSoonList[pos][nodePos] = (resultNode != NULL);
}
}
return resultNode;
}
float FastAINode::getDistance(const AI_Node *node,void *userData) {
return pos.dist(dynamic_cast<const FastAINode *>(node)->pos);
}
float FastAINode::getCost(void *userData) {
float result = 1.0f;
// FastAINodeCache *nodeCache = (FastAINodeCache *)userData;
// if(map->aproxCanMoveSoon(nodeCache->unit, pos, pos) == false) {
// result = 100000;
// }
// bool checkCellObjects = true;
// if(checkCellObjects == true) {
// FastAINode *resultNode = map->getCellNode(pos,false);
// if(resultNode != NULL) {
// FastAINodeCache *nodeCache = (FastAINodeCache *)userData;
// std::map<Vec2i,std::map<Vec2i,bool> >::const_iterator iterFind = nodeCache->cachedCanMoveSoonList.find(pos);
// if(iterFind != nodeCache->cachedCanMoveSoonList.end() &&
// iterFind->second.find(resultNode->getPos()) != iterFind->second.end()) {
// const std::map<Vec2i,bool> &mapCache2 = iterFind->second;
// std::map<Vec2i,bool>::const_iterator iterFind2 = mapCache2.find(resultNode->getPos());
//
// if(iterFind2->second == false) {
// resultNode = NULL;
// result = 9999999;
// }
// }
// else {
// const Vec2i &nodePos = resultNode->getPos();
//
// if(resultNode->getPos() != nodeCache->unit->getCurrentPathFinderDesiredFinalPos()) {
// if(map->aproxCanMoveSoon(nodeCache->unit, pos, resultNode->getPos()) == false) {
// resultNode = NULL;
// result = 9999999;
// }
// }
//
// nodeCache->cachedCanMoveSoonList[pos][nodePos] = (resultNode != NULL);
// }
// }
// }
return result;
}
unsigned int FastAINode::getEdgeCount(void *userData) const {
unsigned int result = 0;
for(unsigned int index = 0; index < NODE_EDGE_COUNT; ++index) {
FastAINode *resultNode = getNodeForEdgeIndex(index,userData);
if(resultNode != NULL) {
result++;
}
}
return result;
}
AI_Node * FastAINode::getEdge(int index,void *userData) const {
FastAINode *result = NULL;
unsigned int edgeCount = getEdgeCount(userData);
if(edgeCount < NODE_EDGE_COUNT) {
int edgeIndex = -1;
for(unsigned int index2 = 0; index2 < NODE_EDGE_COUNT; ++index2) {
result = getNodeForEdgeIndex(index2,userData);
if(result != NULL) {
edgeIndex++;
if(edgeIndex == index) {
return result;
}
}
result = NULL;
}
return result;
}
result = getNodeForEdgeIndex(index,userData);
return result;
};
// ===================== PUBLIC ========================
const int Map::cellScale= 2;
@ -423,7 +287,6 @@ const int Map::mapScale= 2;
Map::Map() {
cells= NULL;
surfaceCells= NULL;
cellNodes=NULL;
startLocations= NULL;
title="";
@ -446,8 +309,6 @@ Map::~Map() {
cells = NULL;
delete [] surfaceCells;
surfaceCells = NULL;
delete [] cellNodes;
cellNodes = NULL;
delete [] startLocations;
startLocations = NULL;
}
@ -545,14 +406,6 @@ Checksum Map::load(const string &path, TechTree *techTree, Tileset *tileset) {
//cells
cells= new Cell[getCellArraySize()];
cellNodes = new FastAINode[getCellArraySize()];
for(unsigned int x = 0; x < w; ++x) {
for(unsigned int y = 0; y < h; ++y) {
int arrayIndex = y * w + x;
FastAINode &cellNode = cellNodes[arrayIndex];
cellNode.setData(Vec2i(x,y),this);
}
}
surfaceCells= new SurfaceCell[getSurfaceCellArraySize()];
//read heightmap

View File

@ -26,7 +26,6 @@
#include "selection.h"
#include <cassert>
#include "unit_type.h"
#include "fast_path_finder.h"
#include "command.h"
#include "checksum.h"
#include "leak_dumper.h"
@ -204,47 +203,6 @@ public:
std::map<Vec2i,std::map<Vec2i,bool> > cachedCanMoveSoonList;
};
class FastAINode : public AI_Node {
protected:
Vec2i pos;
const Map *map;
int32 hashCode;
static const int NODE_EDGE_COUNT = 8;
FastAINode * getNodeForEdgeIndex(int index,void *userData) const;
public:
FastAINode() {
this->map = NULL;
hashCode=0;
}
FastAINode(Vec2i &pos,const Map *map) {
this->pos = pos;
this->map = map;
Checksum result;
result.addInt(pos.x);
result.addInt(pos.y);
hashCode = result.getSum();
}
virtual ~FastAINode() {}
void setData(Vec2i pos, const Map *map) {
this->pos = pos;
this->map = map;
Checksum result;
result.addInt(pos.x);
result.addInt(pos.y);
hashCode = result.getSum();
}
inline const Vec2i & getPos() const { return pos; }
virtual float getDistance(const AI_Node *node, void *userData);
virtual float getCost(void *userData);
virtual unsigned int getEdgeCount(void *userData) const;
virtual AI_Node * getEdge(int index, void *userData) const;
inline virtual int32 getHashCode() const { return hashCode; }
};
class Map {
public:
static const int cellScale; //number of cells per surfaceCell
@ -263,7 +221,6 @@ private:
int maxPlayers;
Cell *cells;
SurfaceCell *surfaceCells;
FastAINode *cellNodes;
Vec2i *startLocations;
Checksum checksumValue;
float maxMapHeight;
@ -306,30 +263,6 @@ public:
return getCell(pos.x, pos.y);
}
//get
inline FastAINode *getCellNode(Vec2i pos, bool errorOnInvalid=true) const {
return getCellNode(pos.x, pos.y, errorOnInvalid);
}
inline FastAINode *getCellNode(int x, int y, bool errorOnInvalid=true) const {
int arrayIndex = y * w + x;
if(arrayIndex < 0 || arrayIndex >= getCellArraySize()) {
if(errorOnInvalid == false) {
return NULL;
}
//abort();
throw megaglest_runtime_error("arrayIndex >= getCellArraySize(), arrayIndex = " + intToStr(arrayIndex) + " w = " + intToStr(w) + " h = " + intToStr(h));
}
else if(cellNodes == NULL) {
if(errorOnInvalid == false) {
return NULL;
}
throw megaglest_runtime_error("cellNodes == NULL");
}
return &cellNodes[arrayIndex];
}
inline int getCellArraySize() const {
return (w * h);
}