New unit cache.

This commit is contained in:
nobody_ 2004-01-15 15:15:09 +00:00
parent 4a4b5c6f3a
commit 991579cd81
8 changed files with 270 additions and 19 deletions

View file

@ -51,7 +51,7 @@ OBJDIR=@OBJDIR@
IFLAGS= -I$(TOPDIR)/src/include $(XIFLAGS) -I$(TOPDIR)/src/movie/vp31/include
CFLAGS=@PROFILE_CFLAGS@ @DEBUG_CFLAGS@ $(IFLAGS) \
-DUNIT_ON_MAP -DUSE_LIBMODPLUG -DUSE_HP_FOR_XP -DMAP_REGIONS\
-DUSE_LIBMODPLUG -DUSE_HP_FOR_XP -DMAP_REGIONS \
@PROFILE_CFLAGS@ @DEBUG_CFLAGS@ @VIDEO_CFLAGS@ @BZ2_CFLAGS@ \
@OGG_CFLAGS@ @MAD_CFLAGS@ @FLAC_CFLAGS@ @CDAUDIO_CFLAGS@ \
@LUA_CFLAGS@ $(CCL) $(VERSION) $(COMP_CFLAGS) @SOUND_CFLAGS@ @PLATFORM@ \

View file

@ -80,6 +80,9 @@ global void HandleActionDie(Unit* unit)
MapUnmarkUnitSight(unit);
unit->State = unit->Type->CorpseScript;
DebugCheck(unit->Type->TileWidth != unit->Type->CorpseType->TileWidth ||
unit->Type->TileHeight != unit->Type->CorpseType->TileHeight);
unit->Type = unit->Type->CorpseType;
CommandStopUnit(unit); // This clears all order queues

View file

@ -77,6 +77,9 @@ global void HandleActionUpgradeTo(Unit* unit)
unit->HP += stats->HitPoints - unit->Type->Stats[player->Player].HitPoints;
// don't have such unit now
player->UnitTypesCount[unit->Type->Type]--;
DebugCheck(unit->Type->TileWidth != type->TileWidth ||
unit->Type->TileHeight != type->TileHeight);
unit->Type = type;
unit->Stats = (UnitStats*)stats;
// and we have new one...

View file

@ -217,6 +217,9 @@ typedef struct _map_field_ {
#ifdef UNIT_ON_MAP
Unit* UnitCache; /// An unit on the map field
#endif
#ifdef NEW_UNIT_CACHE
UnitListItem* UnitCache; /// An unit on the map field
#endif
#ifdef HIERARCHIC_PATHFINDER
unsigned short RegId; /// Region to which the field belongs
// FIXME: Johns: this values can't be placed in the map field,

View file

@ -37,6 +37,12 @@
== Config definitions
============================================================================*/
// Unit On Map cache
#define UNIT_ON_MAP
// New unit cache
// #define NEW_UNIT_CACHE
//
// Default speed for many things, set it higher for faster actions.
//

View file

@ -391,7 +391,6 @@
typedef struct _unit_ Unit; /// unit itself
typedef enum _unit_action_ UnitAction; /// all possible unit actions
struct _spell_type_; /// base structure of a spell type
/**
@ -490,6 +489,15 @@ enum _directions_ {
LookingNW =7*32, /// Unit looking north west
};
/// A linked list element.
typedef struct _unit_list_item_ UnitListItem;
struct _unit_list_item_ {
Unit* Unit; /// Points to the unit it links
UnitListItem* Prev; /// Previous item.
UnitListItem* Next; /// Next item.
};
#define NextDirection 32 /// Next direction N->NE->E...
#define UnitNotSeen 0x7fffffff /// Unit not seen, used by Unit::SeenFrame
@ -498,16 +506,20 @@ struct _unit_ {
// NOTE: int is faster than shorts
int Refs; /// Reference counter
int Slot; /// Assigned slot number
Unit** UnitSlot; /// Slot pointer of Units
Unit** PlayerSlot; /// Slot pointer of Player->Units
Unit** UnitSlot; /// Slot pointer of Units
Unit** PlayerSlot; /// Slot pointer of Player->Units
Unit* Next; /// Generic link pointer (on map)
Unit* Next; /// Generic link pointer (on map)
#ifdef NEW_UNIT_CACHE
UnitListItem* CacheLinks; /// Link nodes for unit cache
unsigned CacheLock : 1; /// Used to lock unit out of the cache.
#endif
int InsideCount; /// Number of units inside.
Unit* UnitInside; /// Pointer to one of the units inside.
Unit* Container; /// Pointer to the unit containing it (or 0)
Unit* NextContained; /// Next unit in the container.
Unit* PrevContained; /// Previous unit in the container.
Unit* UnitInside; /// Pointer to one of the units inside.
Unit* Container; /// Pointer to the unit containing it (or 0)
Unit* NextContained; /// Next unit in the container.
Unit* PrevContained; /// Previous unit in the container.
int X; /// Map position X
int Y; /// Map position Y

View file

@ -280,6 +280,12 @@ local Unit *AllocUnit(void)
*/
global void InitUnit(Unit* unit, UnitType* type)
{
#ifdef NEW_UNIT_CACHE
int i;
#endif
DebugCheck(!type);
// Refs need to be *increased* by 1, not *set* to 1, because if InitUnit()
// is called from game loading code, Refs can already have a nonzero
// value (thanks to forward references in the save file). Incrementing
@ -300,6 +306,14 @@ global void InitUnit(Unit* unit, UnitType* type)
// Initialise unit structure (must be zero filled!)
//
unit->Type = type;
#ifdef NEW_UNIT_CACHE
unit->CacheLinks = (UnitListItem *)malloc(type->TileWidth * type->TileHeight * sizeof(UnitListItem));
for (i = 0; i < type->TileWidth * type->TileHeight; ++i) {
unit->CacheLinks[i].Prev = unit->CacheLinks[i].Next = 0;
unit->CacheLinks[i].Unit = unit;
}
#endif
unit->Seen.Frame = UnitNotSeen; // Unit isn't yet seen
unit->Frame = unit->Type->Animations->Still[0].Frame +
@ -2843,6 +2857,8 @@ global void LetUnitDie(Unit* unit)
if (type->CorpseType) {
unit->State = unit->Type->CorpseScript;
DebugCheck(type->TileWidth != type->CorpseType->TileWidth ||
type->TileHeight != type->CorpseType->TileHeight);
type = unit->Type = type->CorpseType;
unit->IX = (type->Width - VideoGraphicWidth(type->Sprite)) / 2;

View file

@ -43,19 +43,10 @@
#include <string.h>
#include "stratagus.h"
#ifdef UNIT_ON_MAP
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "unit.h"
#include "map.h"
//*****************************************************************************
// Convert calls to internal
//****************************************************************************/
#ifdef UNIT_ON_MAP
/**
** Insert new unit into cache.
@ -236,3 +227,220 @@ global void InitUnitCache(void)
}
#endif // } UNIT_ON_MAP
#ifdef NEW_UNIT_CACHE
/**
** Insert new unit into cache.
**
** @param unit Unit pointer to place in cache.
*/
global void UnitCacheInsert(Unit* unit)
{
int i;
int j;
MapField* mf;
UnitListItem* listitem;
DebugLevel3Fn("%d,%d %d %s\n" _C_ unit->X _C_ unit->Y _C_ unit->Slot _C_ unit->Type->Name);
for (i = 0; i < unit->Type->TileHeight; ++i) {
for (j = 0; j < unit->Type->TileWidth; ++j) {
mf = TheMap.Fields + (i + unit->Y) * TheMap.Width + j + unit->X;
listitem = unit->CacheLinks + i * unit->Type->TileWidth + j;
// Always add at the start of the list.
listitem->Next = mf->UnitCache;
listitem->Prev = 0;
// update Prev link if cache on tile is no empty
if (mf->UnitCache) {
mf->UnitCache->Prev = listitem;
}
mf->UnitCache = listitem;
}
}
}
/**
** Remove unit from cache.
**
** @param unit Unit pointer to remove from cache.
*/
global void UnitCacheRemove(Unit* unit)
{
int i;
int j;
MapField* mf;
UnitListItem* listitem;
DebugLevel3Fn("%d,%d %d %s\n" _C_ unit->X _C_ unit->Y _C_ unit->Slot _C_ unit->Type->Name);
for (i = 0; i < unit->Type->TileHeight; ++i) {
for (j = 0; j < unit->Type->TileWidth; ++j) {
mf = TheMap.Fields + (i + unit->Y) * TheMap.Width + j + unit->X;
listitem = unit->CacheLinks + i * unit->Type->TileWidth + j;
if (listitem->Next) {
listitem->Next->Prev = listitem->Prev;
}
if (listitem->Prev) {
listitem->Prev->Next = listitem->Next;
} else {
if (mf->UnitCache != listitem) {
DebugLevel0Fn("Try to remove unit not in cache. It's ok, mostly.\n");
}
// item is head of the list.
mf->UnitCache = listitem->Next;
DebugCheck(mf->UnitCache && mf->UnitCache->Prev);
}
listitem->Next = listitem->Prev = 0;
}
}
}
/**
** Change unit in cache.
** FIXME: optimize, add destination to parameters
**
** @param unit Unit pointer to change in cache.
*/
global void UnitCacheChange(Unit* unit)
{
UnitCacheRemove(unit);
UnitCacheInsert(unit);
}
/**
** Select units in rectangle range.
**
** @param x1 Left column of selection rectangle
** @param y1 Top row of selection rectangle
** @param x2 Right column of selection rectangle
** @param y2 Bottom row of selection rectangle
** @param table All units in the selection rectangle
**
** @return Returns the number of units found
*/
global int UnitCacheSelect(int x1, int y1, int x2, int y2, Unit** table)
{
int i;
int j;
int n;
UnitListItem* listitem;
//
// Reduce to map limits. FIXME: should the caller check?
//
if (x1 < 0) {
x1 = 0;
}
if (y1 < 0) {
y1 = 0;
}
if (x2 > TheMap.Width) {
x2 = TheMap.Width;
}
if (y2 > TheMap.Height) {
y2 = TheMap.Height;
}
DebugLevel3Fn("%d,%d %d,%d\n" _C_ x1 _C_ y1 _C_ x2 _C_ y2);
n = 0;
for (i = y1; i < y2; ++i) {
for (j = x1; j < x2; ++j) {
listitem = TheMap.Fields[i * TheMap.Width + j].UnitCache;
for (; listitem; listitem = listitem->Next) {
//
// To avoid getting an unit in multiple times we use a cache lock.
// It should only be used in here, unless you somehow want the unit
// to be out of cache.
//
if (!listitem->Unit->CacheLock) {
listitem->Unit->CacheLock = 1;
table[n++] = listitem->Unit;
}
}
}
}
//
// Clean the cache locks, restore to original situation.
//
for (i = 0; i < n; ++i) {
table[i]->CacheLock = 0;
}
return n;
}
/**
** Select units on map tile.
**
** @param x Map X tile position
** @param y Map Y tile position
** @param table All units in the selection rectangle
**
** @return Returns the number of units found
*/
global int UnitCacheOnTile(int x, int y, Unit** table)
{
UnitListItem* listitem;
int n;
//
// Unlike in UnitCacheSelect, there's no way an unit can show up twice,
// so there is no need for Cache Locks.
//
n = 0;
listitem = TheMap.Fields[y * TheMap.Width + x].UnitCache;
for (; listitem; listitem = listitem->Next) {
if (!listitem->Unit->CacheLock) {
table[n++] = listitem->Unit;
}
}
return n;
}
/**
** Select unit on X,Y of type naval,fly,land.
**
** @param x Map X tile position.
** @param y Map Y tile position.
** @param type UnitType::UnitType, naval,fly,land.
**
** @return Unit, if an unit of correct type is on the field.
*/
global Unit* UnitCacheOnXY(int x, int y, unsigned type)
{
Unit* table[UnitMax];
int n;
n = UnitCacheOnTile(x, y, table);
while (n--) {
if ((unsigned)table[n]->Type->UnitType == type) {
break;
}
}
if (n > -1) {
return table[n];
} else {
return NoUnitP;
}
}
/**
** Print unit-cache statistic.
*/
global void UnitCacheStatistic(void)
{
// FIXME: stats about query sizes.. you can get the rest by profiling.
}
/**
** Initialize unit-cache.
*/
global void InitUnitCache(void)
{
}
#endif // } NEW_UNIT_CACHE