total newb looking for some help with modding

Chat about various topics.

Re: total newb looking for some help with modding

Postby Gary on Wed Nov 23, 2011 12:36 pm

You could also throw a DevMsg("The game should of just wrote to the file/n"); in there just to be sure you are placing the code in the right place.

The function DevMsg writes to the console when the ConVar developer is set to 1.
Have a question related to modding or something I posted? Something that needs staff attention? I haven't been active lately, but feel free to PM me or message me on Steam(link below)

User avatar
Gary
Interlopers Staff
Interlopers Staff
 
Joined: Wed Dec 16, 2009 12:40 am
Location: USA, FL

Re: total newb looking for some help with modding

Postby PsychoJim on Wed Nov 23, 2011 5:39 pm

I don't think that could be the problem, after all in C++ if you try to open a file that doesn't exist then it creates that file, e.g. using the following code:
// basic file operations
#include <iostream>
#include <fstream>
using namespace std;

int main () {
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
return 0;
}

If the file example.txt did not exist, then this would create it.

But I tried your suggestion out anyway. I created the file, in the same folder as player.cpp, which calls the function OnTakeDamage where my code was inserted. But nothing was written to this file after my player took damage. So that doesn't seem like it's the problem.

I'm really stuck in a dead in with this. I'm sure I can't be the first person to want to create a .txt file to record some in-game data. Surely someone must know how to do this?

If I could just even get the basics of this, that would be something. Let's say, I run my mod from Visual C++, I load my map, I click new game. How can I get the game to create a .txt file that says "You started a new game"? Does anyone have any idea of how to do this?
PsychoJim
Member
Member
 
Joined: Tue Aug 23, 2011 12:58 pm

Re: total newb looking for some help with modding

Postby PsychoJim on Wed Nov 23, 2011 7:50 pm

Thanks for your suggestion Gary.
So I tried including both:
Msg("The player has just been damaged/n");
DevMsg("The player has just been damaged/n");
I placed these in the file player.cpp, at just after line 1011:
int CBasePlayer::OnTakeDamage( const CTakeDamageInfo &inputInfo )
and after line 1566):
int CBasePlayer::OnTakeDamage_Alive( const CTakeDamageInfo &info )
These were the only points in the source code that includes CBasePlayer::OnTakeDamage.
I then ran debug, started a new game, and damaged myself using the rpg.
But nothing came up on the console.
So clearly my code is in the wrong place.

Basically then, my real problem comes down to not knowing where in the source code that certain events are triggered from. The problem is, I don't know how to find this out either. I have been looking through the VDC, but I can't find anything that tells me "when the player is damaged this corresponds to line(s) XXXX in the files XXX.cpp or XXX.h". I thought that by searching within the source code for the term OnTakeDamage, I could find the correct spot for when the player gets damaged. Ditto for OnPlayerPickup. But despite my efforts, I'm not getting any response to either receiving damage or picking up an object or weapon.

Ok, so I'm just going to try to get right back to square 1 and forget about .txt files for the moment.
Let's say I take the line DevMsg("The game has just started/n");
Where should I place this line in the source code so that "The game has just started" appears in the console when I start a new game?
PsychoJim
Member
Member
 
Joined: Tue Aug 23, 2011 12:58 pm

Re: total newb looking for some help with modding

Postby zombie@computer on Wed Nov 23, 2011 9:11 pm

ok, here goes, basic class and interitance in c++:

Lets say we have two classes in c++ GenericEntity and AwesomeEntity.
Code: Select all
class GenericEntity
{
   Spawn();
   TakeDamage();
   Die();
   FancyStuff();
}
class AwesomeEntity
{
   Spawn();
   TakeDamage();
   Die();
   FancyStuff();
}

GenericEntity can be damaged and killed, as can AwesomeEntity. The only difference is that AwesomeEntity blows up when its damaged.
Ok, so instead of writing all the damaging and killing code twice, we can make AwesomeEntity derive (or inherit) from GenericEntity. This basically means: AwesomeEntity has all code from GenericEntity. E.g.
Code: Select all
class GenericEntity
{
   Spawn();
   TakeDamage();
   Die();
   FancyStuff();
}
class AwesomeEntity : public GenericEntity
{
}

Is the same as the example above. You can Spawn(), TakeDamage(), Die() and FancyStuff() AwesomeEntity like before, even though the code for all of that is described in another class.
We didnt want the same entity tho, it required a slight different code. Remember, AwesomeEntity had to explode?
Now comes the fun part of c++: we can mark a piece of code in such a way that it can be overridden.
Code: Select all
class GenericEntity
{
   Spawn();
   TakeDamage();
   virtual Die();
   FancyStuff();
}
class AwesomeEntity : public GenericEntity
{
     virtual Die();
     Explode();
}

The keyword here is 'virtual'. Now, when some piece of code kills AwesomeEntity, it will trigger AwesomeEntity's Die() code, instead of GenericEntity's DIe() code. AwesomeEntity's Die code is the following:
Code: Select all
     Die()
     {
          Explode();
          GenericEntity::Die();
     }

This code triggers the Explosion() code, and finally GenericEntity's Die() code (we still want to remove the entity from the game, after all).
Note that valve usually uses BaseClass::Die(), where BaseClass is a reference to the class we derived from (it's actually a typedef).

Ok, now things become more difficult. The above example had two classes, but in c++ you can derive from derived classes (ad infinitam)
So you can have for instance
Code: Select all
class GenericEntity
{
   Spawn();
   TakeDamage();
   virtual Die();
   FancyStuff();
}
class AwesomeEntity : public GenericEntity
{
     virtual Die();
     Explode();
}
class SuperAwesomeEntity : public AwesomeEntity
{
     virtual Die() { GenericEntity::Die();  };
}
class ExtremelySuperAwesomeEntity: public SuperAwesomeEntity
{

}
etc

Note SuperAwesomeEntity's Die() code. It overrides the die code, and triggers GenericEntity's Die() code. It doesn't explode, because it doesn't trigger AwesomeEntity's Die() code.

Ok, your situation:
It seems you are fiddling with a piece of code like this Die() code. If the class ingame is actually ExtremelySuperAwesomeEntity or AwesomeEntity, the Die() code of AwesomeEntity will be triggered, and any changes you make there will show. However, if the class ingame is SuperAwesomeEntity, a class that derives from the class you are editing, changes will do diddly squat.

I hope you get where the problem lies now, so we can move on to the solution:
1) google. Esp the valve dev wiki.
2) rightclick on your function, find all references, usually yields possible other places you needed to edit instead. You can even use Visual studio's builtin search box.
3) if you run the game from visual studio (see debuggin in valve dev wiki) you can set breakpoints and see what variables look like when playing the game. It should help you bigtime.

In your specific case, there is no single player class specifying all players code. Theres HL2_Player which derives from CBasePlayer which derives from CBaseCombatCharacter which derives from CBaseFlex which derives from CBaseAnimatingOverlay which derives from CBaseAnimating which derives from CBaseEntity which derives from IServerEntity or IClientEntity depending on context which derives from IUnknown which derives from IHandleEntity. Any of these classes (well, to be exact, those 'below' CBaseEntity) can have the code you need to alter. Get it? You need to find the 'lowest' class that has the code triggered you need to alter.
When you are up to your neck in shit, keep your head up high
zombie@computer
Forum Goer Elite™
Forum Goer Elite™
 
Joined: Fri Dec 31, 2004 5:58 pm
Location: Lent, Netherlands

Re: total newb looking for some help with modding

Postby PsychoJim on Tue Nov 29, 2011 6:56 pm

Wow! Thanks for such a detailed reply zombie.

Sure, I understand the basics of class and inheritance, I've programmed experiments with python before so I'm not a total newb to programming, just to C++ syntax and the half-life 2 source code. But it was helpful to have it explained it in the context of game entities, so many thanks for that.

I understand what you're getting at by saying that I need to find the lowest class that triggers the code that I wish to record. So I approached the problem by searching through the source code for terms that might be useful. I am using Visual Studio, so as you suggest, I used the built in search function to look for the code that might relate to what I’m interested in.

The problem is, that I’m still a bit in the dark in terms of exactly what to look for in the source code and where to look for it. Going back to my earlier example of wanting to record when a player gets damaged, the obvious thing to look for in the source code is “damage”. That returns 6685 matching lines. Obviously then I need to filter my results somewhat. Instead then I tried “TakeDamage”, which returned 1713 results, still too many to trawl through, The term “OnTakeDamage” returned 284 results, that’s a a bit more manageable. So now it’s just a question of going through each of these lines to see which one might be lowest class. But still, it’s basically going to be just guesswork and trial-and-error as to which of these results will actually correspond to the player sustaining damage in the game. Is there a way in which I can make my approach a bit more educated and less of a fumble in the dark?

Anyway, I looked up Damage, TakeDamage and OnTakeDamage in the VDC, and came across a tutorial for regenerating health. I think this might be useful in trying to understand the best way to implement a solution to my problem, so I’m going to see how I get on with that.

Thanks again for all the help and advice.
PsychoJim
Member
Member
 
Joined: Tue Aug 23, 2011 12:58 pm

Re: total newb looking for some help with modding

Postby PsychoJim on Thu Jan 05, 2012 5:30 pm

Finally, I have managed to implement some sort of data logging system. I will post details a little later.

However for the moment, I have one small sticking problem. I’m using the output functions of various entities to trigger my own custom logging entity. This works fine for nearly every action in the game; OnPlayerPickup, OnTakeDamage, OnBreak, etc. However, I also would like to record whenever a weapon, e.g. shotgun, is fired. I thought I would be able to do this with the output OnPlayerUse, however it seems that this doesn’t apply to when the weapon is actually fired, but when the weapon is picked up and thrown instead.

Can anyone give me a little advice about the best way to make it so that firing a weapon then fires an output? Will I have to make a custom output for the weapon? Or can I bind an output to the +attack command in the .cfg file? Any advice on this one would as always be appreciated.
PsychoJim
Member
Member
 
Joined: Tue Aug 23, 2011 12:58 pm
Previous

Return to General Discussion

Who is online

Users browsing this forum: No registered users

cron