project-navigation
Personal tools

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - yobbo

Pages: [1]
1
Coding / Re: the AI discussion
« on: July 07, 2013, 07:08:54 am »
Sooo, after three failures that really should have worked, and now that i've cooled down from the resulting tantrum, i figure i'll just post what i wanted to do and hope someone can point out the best way to actually do it.

Here is some code that does not work for various reasons.

Code: [Select]
typedef struct enemy_distance_s {
/* Approximate distance in TUs to the nearest enemy (capped at 255) */
byte distance[PATHFINDING_HEIGHT][PATHFINDING_WIDTH][PATHFINDING_WIDTH];

inline byte getDist(const pos3_t pos) const {
return distance[pos[2]][pos[1]][pos[0]];
}
inline void setDist(const int x, const int y, const int z, const byte val) {
distance[z][y][x] = val;
}
inline void setDist(const pos3_t pos, const byte val) {
setDist(pos[0], pos[1], pos[2], val);
}
} enemy_distance_t;

/**
 * @brief Calculate the distance to the nearest enemy for every point on the map.
 * @param[in] routing The routing map (either server or client map).
 * @param[out] enemy_dist The map of nearest-enemy distances.
 * @param[in] team The AI team we're calculating this for.
 */
void CalcEnemyDistances(const Routing &routing, enemy_distance_t *enemy_dist, const int team)
{
/* Clear the distance grid: set all distances to max.
* (this is probably about 512KiB of data to maxify) */
for (int z = 0; z < PATHFINDING_HEIGHT; z++) {
for (int y = 0; y < PATHFINDING_WIDTH; y++) {
for (int x = 0; x < PATHFINDING_WIDTH; x++) {
enemy_dist->setDist(x, y, z, (byte)(-1));
}
}
}

/* Maintain a list of cells to be checked. */
std::list<pos3_t> cells_to_check;

/* Start with distance 0 at all enemy positions. */
edict_t *ent = nullptr;
while ((ent = G_EdictsGetNextLivingActor(ent))) {
/* Assume we are hostile to members of all other teams.
* (ReactionFire::isEnemy seems to work this way also) */
if (ent->team == team) {
continue;
}
enemy_dist->setDist(ent->pos, 0);
cells_to_check.push_back(ent->pos);
}

int updatedCells = 0;

/* Check the surroundings of each cell,
* to see if we found a shorter path.
* If so, update the distance map, and recurse. */
while (!cells_to_check.empty()) {

std::list<pos3_t>::iterator cell;
for (cell = cells_to_check.begin(); cell != cells_to_check.end(); cell++) {
int dist = enemy_dist->getDist(*cell);

for (int dir = 0; dir < PATHFINDING_DIRECTIONS; dir++) {
/* Get the cell leading to this cell in this direction. */
pos3_t from_cell;
int crouching = 0;
VectorCopy(*cell, from_cell);
PosSubDV(from_cell, crouching, dir);

/* Is it connected?
* For now don't take into account size etc,
* just if there is a grid connection. */
if (!routing.getConn(ACTOR_SIZE_NORMAL, from_cell, dir)) {
continue;
}

/* How many TUs does it take to move from there to here? */
int tustep = Grid_GetTUsForDirection(dir, 0);

/* Have we found a shorter distance? */
if (tustep + dist < enemy_dist->getDist(from_cell)) {
enemy_dist->setDist(from_cell, tustep + dist);
/* Add to the list to be checked next cycle. */
cells_to_check.push_front(from_cell);
updatedCells++;
}
}

cell = cells_to_check.erase(cell);
}
}
}

The most obvious reason this does not work, is that std::list doesn't know how to deal with a pos3_t. That's easily solved by defining a new 3-pos struct to use here and converting to and fro, but it's not the main problem.

The main problem is that it seems this combination of things i want to do is unable to be called together from anywhere in the codebase. Specifically G_EdictsGetNextLivingActor and Grid_GetTUsForDirection. In grid.cpp it can't call the G_ function, and in g_ai.cpp it can't call the Grid_ function.

Maybe i'm wrong about that, and there's some way i can easily do this, but in the end i still have no idea where this function should go.

Probably it wants to be called from G_ClientEndRound? And the enemy_distance_t must be made accessible to the AI somehow. The routing table needs to be accessible to whatever is calling this function, and enemy_distance_t needs to be declared somewhere everyone can see it.

It's possible there's a better way to organize things, but i've already tried integrating this in three different places unsuccessfuly, so i really hope someone can look at this and tell me where and how it can fit in.

2
Coding / Re: the AI discussion
« on: June 27, 2013, 08:37:25 am »
I couldn't find any previous discussion of using the routing info to solve this. If you could find a link for me that would be helpful.

So far it looks like this solution is complicated by movement depending on the actor doing the moving. It looks like the code can handle things such as smller actors moving thru smaller holes while larger ones can't.

That and the routing code is doing my head in.

Particularly
Code: [Select]
/**
 * @sa G_RecalcRouting
 */
void G_CompleteRecalcRouting (void)
{
Edict *ent = nullptr;

while ((ent = G_EdictsGetNextInUse(ent)))
if (IS_BMODEL(ent))
G_RecalcRouting(ent->model, GridBox::EMPTY);
}
Why is the routing info recaculated for every entity in use? Shouldn't there be just one routing table? Why does it relate to specific game entities at all? Am i misunderstanding?

3
Coding / Re: the AI discussion
« on: June 26, 2013, 07:17:51 am »
So, it's been really bugging me that the aliens clump up in places where they can't actually reach the player's soldiers.

It seems their positioning heuristic takes into account the absolute distance to the nearest soldier, so failing to find anything better to do, they minimize absolute distance, thus standing in corners "close" to the soldiers, and hovering above or below them on the wrong floor.

I have a proposed fix for this, but I haven't looked at the code yet, so I'm not sure if it makes sense.

My proposal is to calculate (once per turn, after the player has finished moving) the distance to the nearest soldier for every point on the map. I assume there must be some data structure in place already representing the movable area of the map, so this could be walked over for each soldier. Not too much of a computational burden as it's only done once per turn.

Thus in stead of taking into account absolute distance to soldiers, the aliens could take into account the actual movable distance, based on this calculated distance map.

It can be explained by saying the aliens can "smell" the soldiers ;).

In terms of the AI, I assume this is a fairly simple fix. Just change the distance metric to instead use the actual calculated walking-distance.

So I have two (and a half) questions, answers would help if anyone knows off the top of their head:

1a) Is there a movement grid structure I can easily walk over with a simple distance calulating routine?
1b) Where is the best place to store the resulting distance data? It needs to be recalculated each turn, and accessable by the alien AI.

2) Where do aliens decide that "closer is better"?

I can probably find the answers to these questions myself, but it will take some time to familiarize myself with the code. I figured I'd post my proposal and ask my questions while I do so.

4
Linux / Re: compiling 2.5 from git source
« on: June 24, 2013, 05:00:18 pm »
I believe this has been fixed already, try pulling again :).

5
Coding / Re: Git Bundle
« on: June 19, 2013, 07:27:28 am »
Hi, thanks for your quick reply :).

Yes that is the idea, but I think bundling only the master branch is easiest. Probably most of the data is in there, and that way it could be used for those who just want the master branch, as well as those who want to clone the whole repo.

I've never used git bundles before either, so I did some research (and some testing on one of my other repos), and came up with the following process.



TO CREATE A BUNDLE

As long as it contains most of the data, that's good enough, so it can probably just be of the master branch:

Code: [Select]
git bundle create ufoai.bundle master
This will create a bundle containing all the commits in the master branch. It can be updated if a lot of data gets added, but as long as it has the bulk of the repo that's probably fine.



TO USE THE BUNDLE TO CLONE THE GIT REPO (summary at the bottom)

Assuming you have the ufoai.bundle file in your current directory:

Code: [Select]
git init ufoai
cd ufoai
git pull ../ufoai.bundle master

This will pull all the commits up until whenever the bundle was created, and put them in the 'master' branch of the new repo.

Now we want to link to the actual repo, and bring our copy up-to-date with it.

If all we want is the master branch, we can do

Code: [Select]
git remote add origin git://git.code.sf.net/p/ufoai/code --track master
git pull

but if we want to be able to track all the branches, it's better to do

Code: [Select]
git remote add origin git://git.code.sf.net/p/ufoai/code
git fetch
git merge origin/master

and then to set the default upstream for pulling and pushing.

Code: [Select]
git branch --set-upstream-to origin/master


At this point you can see all the remote branches with

Code: [Select]
git branch -r
unless you used '--track master', in which case you have to manually add any branches you want to see with

Code: [Select]
git remote set-branches --add origin <branchname(s)>
git fetch

now assuming 'git branch -r' shows everything you want, and has exactly one branch with the name you want to work on, you can switch to and track any of the existing remote branches with 'git checkout'. For example

Code: [Select]
git checkout renderer_work
would be shorthand for 'git checkout -b renderer_work --track origin/renderer_work'



SO TO SUMMARIZE:


OPTION A: MASTER ONLY

Code: [Select]
git init ufoai
cd ufoai
git pull ../ufoai.bundle master
git remote add origin git://git.code.sf.net/p/ufoai/code --track master
git pull

-> should be up-to-date and tracking master, patch away


OPTION B: WHOLE REPO

Code: [Select]
git init ufoai
cd ufoai
git pull ../ufoai.bundle master
git remote add origin git://git.code.sf.net/p/ufoai/code
git fetch
git merge origin/master
git branch --set-upstream-to origin/master

-> up-to-date, tracking master, and can check out and work on other branches.



For reference, another project which uses a git bundle for their data is FlightGear: http://wiki.flightgear.org/Git

6
Coding / Git Bundle
« on: June 18, 2013, 11:43:42 am »
Would it be possible to provide a git bundle for those who want to clone the git repository?

It is a very large download, and it seems that git cannot resume if it fails. After four hours and 1.4GB of data, my internet connection gave in, and there was no way to resume. If there were a git bundle to some recent point (say the 2.4 version), then that could be downloaded via normal means (such as http download or torrent), and used to clone the repository, then one could update it from there.

EDIT: Bundle added, thanks H-Hour :)

simple instructions for using it are: (replace '../ufoai-master-01d1bbf-2013-06-17.bundle' with wherever the bundle is and whatever it's called, i ran this from where the bundle was):

Code: [Select]
git init ufoai
cd ufoai
git pull ../ufoai-master-01d1bbf-2013-06-17.bundle master
git remote add origin git://git.code.sf.net/p/ufoai/code --track master
git pull

This will track the master branch. After that you can update whenever you like with

Code: [Select]
git pull

Pages: [1]