ObjectFile.cpp #16

  • //
  • guest/
  • sam_stafford/
  • p4hl/
  • src/
  • dlls/
  • ObjectFile.cpp
  • View
  • Commits
  • Open Download .zip Download (9 KB)
// ObjectFile.cpp: implementation of the CObjectFile class.
//
//////////////////////////////////////////////////////////////////////

#include "p4objects.h"
#include "enginecallback.h"

LINK_ENTITY_TO_CLASS( object_file, CObjectFile)
#define FILE_HEIGHT 10.0
#define REV_HEIGHT 2.0

void CObjectFile::Spawn()
{
	intonotfrom = false;
	Precache( );

	switch (ftype)
	{
	default:
	case FTYPE_TEX:
		SET_MODEL( ENT(pev), "models/file/w_file.mdl" );
		break;
	case FTYPE_BIN:
		SET_MODEL( ENT(pev), "models/file/w_fileb.mdl" );
		break;
	case FTYPE_APP:
		SET_MODEL( ENT(pev), "models/file/w_filea.mdl" );
		break;
	case FTYPE_SYM:
		SET_MODEL( ENT(pev), "models/file/w_files.mdl" );
		break;
	}
	UTIL_SetOrigin( pev, pev->origin );
	target = (Vector)pev->origin;  //by default, we're already where we want to be.

	UTIL_SetSize( pev, Vector(-5, -15, 38), Vector( 5, 15, 86) );  //collision box!

	level = 0;

	pev->movetype = MOVETYPE_FLY;
//			pev->sequence = LookupActivity (ACT_IDLE);
//			pev->frame = 0;
//			pev->framerate = 1;
	pev->solid = SOLID_BBOX; 

	SetThink( Think );
	SetTouch( Touch );

	pev->nextthink = gpGlobals->time + 0.5;
}

void CObjectFile::Precache()
{
	PRECACHE_MODEL("models/file/w_file.mdl");
	PRECACHE_MODEL("models/file/w_fileb.mdl");
	PRECACHE_MODEL("models/file/w_filea.mdl");
	PRECACHE_MODEL("models/file/w_files.mdl");
}

void CObjectFile :: Think( void )
{
	if (!IsInWorld())
	{
		parent->disown( this );
		UTIL_Remove( this );
		return;
	}
	if (UTIL_VecUpdate( &(pev->origin), target )) {
		pev->nextthink = gpGlobals->time + 0.05;
		UTIL_SetSize( pev, Vector(-5, -15, 38), Vector( 5, 15, 86) );  //collision box!
	}
	else
	{
		pev->nextthink = gpGlobals->time + 1.5;
	}
	if (cache)
	{
		if (alldone)
		{
			/* now that they've all been spawned we can run around setting up pointers */
			ListNode* scan = revs.head;
			CObjectRev* obj;
			FileRevArrow* arrow;
			while (scan != NULL)
			{
				obj = (CObjectRev*) scan->ent;
				if (obj == NULL) break;
				arrow = obj->revobj->fromarrows;
				while (arrow)
				{
					if (arrow->ptr->ent) 
					{
						obj->AddArrow((CObjectRev*)arrow->ptr->ent, arrow->type, arrow->contrib);
					}
					arrow = arrow->next;
				}
				scan = scan->next;
			}
			delete cache;
			cache = NULL;
			pev->nextthink = gpGlobals->time + 0.1;
			return;
		}
		if (revsmade > MAXRESULTS)
		{
			alldone = true;
			pev->nextthink = gpGlobals->time;
			return;
		}
		if (hwork == cache->main)
		{
			if (rwork != NULL)
			{
				CObjectRev* orev = GetClassPtr( (CObjectRev *) NULL);
				revsmade++;
				orev->type = rwork->type;
				revs.Append(orev);
				rwork->ent = orev;
				orev->revobj = rwork;
				int xcoord = cache->changes->GetPos(rwork->change);
				orev->pev->classname = MAKE_STRING("object_rev");
				orev->Spawn();
				orev->pev->origin = pev->origin + Vector(-xcoord, 0, 0);
				orev->target = target - Vector(0,0,100);
				orev->target.x -= xcoord*15;
				orev->target.z += (FILE_HEIGHT - 5.0);
				orev->ismain = 127;
				orev->istext = rwork->istext;
				orev->filerev = hwork->name;
				orev->filerev.Append("#");
				orev->filerev.Append(&(rwork->rev));
				orev->parent = this;
				orev->pev->nextthink = gpGlobals->time;
				rwork = rwork->next;
				pev->nextthink = gpGlobals->time + 0.1;
				return;
			} 
			else //start on the "from" list
			{
				hwork = cache->from;
				if (hwork) rwork = hwork->head;
				ycoord = 1;
				intonotfrom = false;
				pev->nextthink = gpGlobals->time;
				return;
			}
		}
		else
		{
			if (!intonotfrom)
			{
				if (hwork)
				{
					if (rwork != NULL)
					{
						CObjectRev* orev = GetClassPtr( (CObjectRev *) NULL);
						revsmade++;
						orev->type = rwork->type;
						revs.Append(orev);
						rwork->ent = orev;
						orev->revobj = rwork;
						int xcoord = cache->changes->GetPos(rwork->change);
						orev->pev->classname = MAKE_STRING("object_rev");
						orev->Spawn();
						orev->pev->origin = pev->origin + Vector(-xcoord, ycoord, 0);
						orev->target = target - Vector(0,0,100);
						orev->target.x -= xcoord*15;
						orev->target.y += ycoord*20;
						orev->target.z += (zcoord - RANDOM_FLOAT(0.0, REV_HEIGHT));
						orev->ismain = 0;
						orev->istext = rwork->istext;
						orev->filerev = hwork->name;
						orev->filerev.Append("#");
						orev->filerev.Append(&(rwork->rev));
						orev->parent = this;
						orev->pev->nextthink = gpGlobals->time;
						rwork = rwork->next;
						pev->nextthink = gpGlobals->time + 0.1;
						return;
					} 
					else //next FileHead
					{
						hwork = hwork->next;
						ycoord++;
						if (hwork) rwork = hwork->head;
						zcoord = RANDOM_FLOAT(-5.0, FILE_HEIGHT - 5.0);
						pev->nextthink = gpGlobals->time;
						return;
					}
				}
				else //on to the intos
				{
					hwork = cache->into;
					intonotfrom = true;
					if (hwork) rwork = hwork->head;
					ycoord = 1;
					pev->nextthink = gpGlobals->time;
					return;
				}
			}
			else //are we on the intos?
			{
				if (hwork)
				{
					if (rwork != NULL)
					{
						CObjectRev* orev = GetClassPtr( (CObjectRev *) NULL);
						revsmade++;
						orev->type = rwork->type;
						revs.Append(orev);
						rwork->ent = orev;
						orev->revobj = rwork;
						int xcoord = cache->changes->GetPos(rwork->change);
						orev->pev->classname = MAKE_STRING("object_rev");
						orev->Spawn();
						orev->pev->origin = pev->origin + Vector(-xcoord, ycoord, 0);
						orev->target = target - Vector(0,0,100);
						orev->target.x -= xcoord*15;
						orev->target.y -= ycoord*20;
						orev->target.z += (zcoord - RANDOM_FLOAT(0.0, REV_HEIGHT));
						orev->ismain = 0;
						orev->istext = rwork->istext;
						orev->filerev = hwork->name;
						orev->filerev.Append("#");
						orev->filerev.Append(&(rwork->rev));
						orev->parent = this;
						orev->pev->nextthink = gpGlobals->time;
						rwork = rwork->next;
						pev->nextthink = gpGlobals->time + 0.1;
						return;
					} 
					else //next FileHead
					{
						hwork = hwork->next;
						ycoord++;
						if (hwork) rwork = hwork->head;
						else alldone = true;
						zcoord = RANDOM_FLOAT(-5.0, FILE_HEIGHT - 5.0);
						pev->nextthink = gpGlobals->time;
						return;
					}
				}
				else //No "into" files?
				{
					alldone = true;
					return;
				}
			}
		}
	}
}

void CObjectFile :: Touch( CBaseEntity* Thing )
{ 
	CBasePlayer *pl;
	CBaseEntity *be = CBaseEntity::Instance(Thing->pev->owner);

	if (Thing->IsPlayer()) pl = (CBasePlayer*) Thing;
	else if (be->IsPlayer()) pl = (CBasePlayer*) be;
	else return;
	if (pl->m_flNextP4Time > gpGlobals->time) return;
	pl->m_flNextP4Time = gpGlobals->time + 0.5;

	if (Thing->IsExpand()) {
		Expand( pl );
		return;
	}

	if (Thing->IsLong()) {
		Long( pl );
		return;
	}
	pl->m_flNextP4Time = gpGlobals->time + 0.2;
	UTIL_PrintHud(pl, path.Text());
}

void CObjectFile::Long( CBasePlayer* pl )
{
	ClientFileUser ui;
	ui.logflag = TRUE;
	ClientApi client;
	if (P4PORT.Length()) client.SetPort(P4PORT.Text());
	Error e;
	StrBuf msg = StrBuf();

	client.Init( &e );
	if (e.GetSeverity()) {
		e.Fmt(&msg);
		UTIL_FatalHud(pl, msg.Text());
		pl->m_flNextP4Time = gpGlobals->time + 20.0; //20 second delay on connect error
		return;
	}
	
	char* args[1];
	args[0] = path.Text();

	client.SetArgv(1, args);
	client.Run( "filelog", &ui );

	client.Final( &e );
	if (e.GetSeverity()) {
		e.Fmt(&msg);
		UTIL_WarningHud(pl, msg.Text());
	}

	UTIL_PrintHud( pl, ui.filelog.Text());
}

void CObjectFile::Expand( CBasePlayer* pl )
{
	if (level == 1) return;
	StrBuf hudmsg = StrBuf();
	hudmsg.Append("Displaying history of ");
	hudmsg.Append(path.Text());
	hudmsg.Append("...");
	UTIL_PrintHud( pl, hudmsg.Text());
	//killKids(this);

	newLevel(1);
	parent->killKids(this);

	ClientApi client;
	Error e;
	if (P4PORT.Length()) client.SetPort(P4PORT.Text());
	cache = new FileLogCache(path, &client, &e);
	if (e.IsFatal())
	{
		StrBuf msg;
		e.Fmt(&msg);
		UTIL_FatalHud(pl, msg.Text());
		pl->m_flNextP4Time = gpGlobals->time + 20.0;
		delete cache;
		cache = NULL;
		return;
	}

	/* create an entity for each one - don't set up "from" pointers yet*/
	if (cache->main == NULL) return;
	hwork = cache->main;
	rwork = hwork->head;
	alldone = false;
	pev->nextthink = gpGlobals->time;
	/* From here the "Think" function will take care of everything. */
}

void CObjectFile :: newLevel( short newlev )
{
	if (newlev > 0)
	{
		Vector parvec = parent->targvec();
		target.x = parvec.x;
		target.y = parvec.y;
	}
	target.z += (newlev - level)*100;
	level = newlev;
	parent->newLevel(level+1);
}

void CObjectFile :: disown ( CBaseEntity *Target ) //this does the OPPOSITE of killKids!!!
{
	revs.EKill(Target);
}

void CObjectFile :: killKids( CBaseEntity *Caller )
{
	bool callerFlag = false;
	CBaseEntity* kid = revs.EPop();
	while (kid != NULL)
	{
		if (kid == Caller) 
		{
			callerFlag = TRUE;
			kid = revs.EPop();
			continue;
		}
		kid -> killKids(this);
		UTIL_Remove(kid);
		kid = revs.EPop();
	}
	if (callerFlag) revs.Append(Caller);
}

CObjectFile::CObjectFile()
{

}

/*
CObjectFile::~CObjectFile()
{

}
*/
# Change User Description Committed
#17 1689 Sam Stafford Integrate 02.1 API and code cleanup to P4HL.
 Lots of work.  Phew.
#16 1521 Sam Stafford Integrated change 1520 to P4HL.
 Updated CObjectFile::Expand() to use
the new variable name.

Infrastructure change.
#15 1450 Sam Stafford Major performance improvement - use one ClientApi connection for all
filelogs.
Improves querying time about tenfold on large requests!

Had to move client->Final() to the constructor to ensure that
connection is cleaned up promptly and doesn't hang things up.
#14 1433 Sam Stafford Integ display: if you see one of a file's revisions, you see them all.
Previously, your view was limited to those revisions which were
directly
related to the file you asked about.  However, if you asked about a
file branched from the mainline, this meant that you couldn't see
mainline changes that weren't yet integrated into your branch, and
that's
not terribly useful.
#13 1422 Sam Stafford Fixed a major crashing bug related to trying to draw relationships to
filerevs that weren't being drawn themselves (access violation).  Three
line fix for a problem that took three days to find.  *facepalm*
#12 1405 Sam Stafford Phew - this was a big one!

New functionality:
    The rare case in which a revision has multiple parents, due to
    multiple resolves before submit, is now handled properly.  There
    is no limit on the number of "parents" a revision may have.

    Integration lines are now always "weighted" to indicate whether
    they contributed all, some, or none to the target.  For example,
    a "branch" line will be very solid and wide, whereas an "ignore"
    will be thin and faint.

Rearchitecture:
    Now using low-cost structs to keep track of integration information.
    Also being just a little more efficient with scanning through large
    data structures.  Quite a bit of general code bloat trimmed off now
    that some of the kludges are gone.

Possible problems:
    Not sure yet, but it might happen that "duplicate" integration
    pointers will be created, now that it's not a single variable which
    would get overwritten in the event of a duplicate.

to-do:
    Trim off obsolete member variables.  Use more enums and fewer #defs.
#11 1047 Sam Stafford Ensure that the pointer-setting step is carried out even if the "into"
section in the cache is empty.  (Bug introduced by change 1024.)
#10 1024 Sam Stafford Reworked entity creation in most cases - it's done one at a time now rather
than all at once.  This allows us to have more entities than the previous limit
of 130, and also looks a little nicer.

Folders and files now pop into existence instantly instead of sliding - makes
navigation easier.  Depots still slide because there typically aren't as many
of them (okay, I might eventually make them pop too, but I'm tired now).
Revisions slide because it looks really cool - like a waterfall pouring out of
the file.

The upper limit to entities is now due to the "visible entity packet" thing,
which I'm certain I have no control over - it's as high as it can possibly be
right now.
#9 1008 Sam Stafford Fixed a bug with the whole "istext" thing - wasn't setting the bit on
CObjectRevs other than "main", so they'd all default to false.  Now it
seems to be better.  Also cleaned up the style a little bit by including
istext in the constructors, rather than setting it after construction.
#8 1007 Sam Stafford A stab at making P4HL a bit more accessible to Perforce novices.
During the Precache() phase of the P4HL objects, a "p4 info" is
executed.  If this returns any errors, odds are there's no server
there (I can't think of what other error "p4 info" would return).
If this happens, use "public.perforce.com:1666" as the new port
value for all future Perforce transactions during this session,
and send a message to the console explaining this.
#7 1006 Sam Stafford Lower the height of the "main" revision list so it doesn't look
quite so weird.  Delete a few unnecessary WAD files.
#6 1004 Sam Stafford Different file types are now treated differently - the ObjectFiles
have different skins depending on file type of the head rev, and
non-text revisions will not attempt to display their contents when
expanded.

Possible bug: old-style filetypes might be detected wrong (ie "ktext"
instead of "text+k").  I'd have to put in some pretty complex logic to
make it completely foolproof and backwards-compatible.  Right now it just errs
on the side of thinking a file is text if there's any confusion.
#5 1003 Sam Stafford Different file types now displayed differently.
 Also flipped
around the file model so that its text doesn't look backwards
any more.
#4 993 Sam Stafford Improvements to integ pointer display :
1) Integ pointers not drawn until both revs have stopped moving.
2) "Branch" type pointers always drawn if target is a "branch" rev.
#3 991 Sam Stafford Tweaks to display of ObjectRevs:
    1) Random variation in their height.  This is intended to make
    overlapping lasers less common.
    2) The "main" revisions are now connected by brighter white beams   
    in order to make it obvious which file is the one we asked about.
#2 957 Sam Stafford Make CObjectFile::Expand ignore FileRevs that don't have
"fromcheck" or "intocheck" flagged.
#1 937 Sam Stafford Renaming my guest directory to the more conventional
sam_stafford.
//guest/samwise/p4hl/src/dlls/ObjectFile.cpp
#1 936 Sam Stafford Adding P4HL to the public depot.
 See relnotes.txt for
installation instructions; all relevant files are under
p4hl/dist.

Source code is under p4hl/src in the form of a VC++ project.