Jump to content

  • Log In with Google      Sign In   
  • Create Account

deleting code at run time?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
19 replies to this topic

#1 sobeit   Members   -  Reputation: 433

Like
0Likes
Like

Posted 20 July 2013 - 05:58 PM

Hi there, 

 

I'm not sure if this is actually possible to do, deleting some portion of code at run time.

What I want to do is to create a achievement system for my game. Let's say, the player will get an achievement when she kills the first enemy. In this case I need to do an "if test" if(enemyNumber == 1) {.....}. However this portion is completely useless for the rest of the game after she earns this achievement. And I need to do as many this kind of tests as the number of achievements in the game. I wonder if there is a way to deal with such problem, deleting code or changing code at run time? How do you guys normally handle it?

 

thanks in advance.


Edited by sobeit, 20 July 2013 - 05:59 PM.


Sponsor:

#2 JTippetts   Moderators   -  Reputation: 8498

Like
8Likes
Like

Posted 20 July 2013 - 06:14 PM

Typically, you want to remove your achievements from the actual guts of your game, since acheesements don't really have anything to do with your gameplay. They're just frosting. So your gameplay shouldn't ever be doing anything like "if (achievement criteria==true) then do achievement end" because it just doesn't belong in your gameplay code. Instead, your achievement system should "hook" into your gameplay code and observe things as they happen, siphoning off the events that it cares about. For example:

 

Every time an enemy is killed, the gameplay system will send some kind of "Enemy Killed" event. This event can be listened for by various subsystems in your game to handle the various things that should happen when an enemy is killed. One of the subsystems that might listen for this event would be the Statistics subsystem, which keeps a count of all enemies killed so that the player can know how awesome she is. Another subsystem listening for that event would be the Achievements subsystem, which would handle that event by passing it on to the various achievements who sign up to listen for it. One of these listening achievements would be the First Kill Achievement which would fire off its payload upon the receipt of an EnemyKilled event, then disable itself (to prevent subsequent events from repeating the payload). This way nothing has to actively poll to see if the achievement should fire, it happens instead by passively listening and you don't waste CPU time in a huge nest of if conditionals.

 

Of course, this does require that the heart of your gameplay system be event-based, but that's a pretty good idea anyway.


Edited by JTippetts, 20 July 2013 - 06:14 PM.


#3 SiCrane   Moderators   -  Reputation: 9599

Like
1Likes
Like

Posted 20 July 2013 - 07:20 PM

Note that changing code at run time is generally possible, but the ease/difficulty of doing so depends on what programming language you are using. For dynamic languages like Ruby replacing function definitions at run time is essentially trivial. For compiled languages, you have to do evil things like disabling data execution protection and rewriting code pages. 



#4 sobeit   Members   -  Reputation: 433

Like
0Likes
Like

Posted 21 July 2013 - 12:03 AM


Of course, this does require that the heart of your gameplay system be event-based, but that's a pretty good idea anyway.

 

thank you, do you know where I can find some example or tutorial on this kind of game design?



#5 markr   Crossbones+   -  Reputation: 1653

Like
0Likes
Like

Posted 21 July 2013 - 03:49 PM

What you're proposing sounds like a premature (and probably unnecessary) optimisation.

 

However, I agree with the spirit of JTippetts response - that you might want to make some sort of declarative or script-based system for handling "achievements" especially if there are a great many of them.



#6 Pink Horror   Members   -  Reputation: 1204

Like
0Likes
Like

Posted 21 July 2013 - 09:48 PM

Hi there, 

 

I'm not sure if this is actually possible to do, deleting some portion of code at run time.

 

Use Lisp.

 

Or, come back when your game is too slow, and the people here will help you sort it out. Until then, don't think about the cost of your if statements. The event-driven system with listeners would give you something like what you want, but it probably wouldn't be an optimization in any way - a hard-coded string of if statements is much easier to compute than iterating over some list of objects with virtual functions to call.

 

If there was a speed improvement once you managed to remove enough listeners from the list, it's not a worst-case optimization. It's more like a best case optimization. Best case optimizations are the worst kind - they only help when your game needs the least amount of help. Your game will start out with all the achievements, and so you won't get any savings until the user is deep into the game. If you have performance problems from your achievements, you cannot expect your user to achieve some to help speed up the game for you.

 

A data-driven system would help you organize your code, so it's worth it for that. I wouldn't want you to not implement something useful like that due to worrying about the cost. I just don't want you to prematurely over-engineer your game either.



#7 Norman Barrows   Crossbones+   -  Reputation: 2138

Like
1Likes
Like

Posted 21 July 2013 - 11:18 PM


However this portion is completely useless for the rest of the game after she earns this achievement. And I need to do as many this kind of tests as the number of achievements in the game. I wonder if there is a way to deal with such problem

 

in the big picture, its only a problem if your code exceeds ram.   you'll want to go with the implementation that gets the job done with the least amount of effort. building games is a big job. you want to work smart, not hard.

 

the last time i had to seriously engineer around something like that was about 1982 when i was writing my first game, a text mode D&D rpg clone on a Sperry Rand 8088 PC, dos 2.11,  and MS Basic. the PC only had 64K of RAM, so you had to use overlay files (modules that paged in and out of memory automatically, with about a 1 second delay). nowadays, windows pages ram as needed, so you have lots of ram, up to the limits of physical ram + max page file size (typically 10% of hard drive? maybe less with today's huge drives).

 

usually its horrendously huge data structures, not code, that makes you run out of ram.

 

i've done games as big as 100,000+ lines of code with no problems.

 

my current main project is at 70,000+ lines of code, and i don't even BEGIN to think about the size of my code segment. OTOH, i HAVE declared data structures that result in "error: program too big to compile", or "data segment exceeds addressable ram", or some such thing. that's when i go for paging strategies.

 

dynamic allocation exceeding available ram can be an issue.

 

"code segment too big" almost never is these days.


Norm Barrows

Rockland Software Productions

"Building PC games since 1988"

 

rocklandsoftware.net

 


#8 sobeit   Members   -  Reputation: 433

Like
0Likes
Like

Posted 22 July 2013 - 01:14 AM


in the big picture, its only a problem if your code exceeds ram.

thank you for the reply, but I don't really worry about "code exceeding ram"(sorry, I didn't state my question clearly enough). my problem is that I need to do many if statement to test whether the player has completed certain achievements, which is unnecessary after the player has completed those achievements. for example

if(KilledTheFirstEnemy == true)

{........}

if(FinishLevelWithin3Munites)

{........}

if(GetANewCostume)

{........}

if(.....)

{........}

the problem is that a player would complete "KilledTheFirstenemy" in the very early stage of the game, but the if test still needs to be executed through out the whole game which is kinda wasting in terms of computation.


Edited by sobeit, 22 July 2013 - 01:17 AM.


#9 sobeit   Members   -  Reputation: 433

Like
0Likes
Like

Posted 22 July 2013 - 01:21 AM


A data-driven system would help you organize your code, so it's worth it for that. I wouldn't want you to not implement something useful like that due to worrying about the cost. I just don't want you to prematurely over-engineer your game either.

thank you for your suggest, I would look into these design patterns. 



#10 Pink Horror   Members   -  Reputation: 1204

Like
0Likes
Like

Posted 22 July 2013 - 06:12 PM


the problem is that a player would complete "KilledTheFirstenemy" in the very early stage of the game, but the if test still needs to be executed through out the whole game which is kinda wasting in terms of computation.

 

When your player starts the game, you're going to have all the checks in there, right? So, if these checks have some cost (though I don't really think you have to worry about it), that cost will be in full effect at the beginning of your game. I would not attempt any optimization that does not help this worst-case scenario, a scenario that everyone who plays the game will have to experience. If you run into a problem with your achievements, which is possible depending on how you check each of the various ifs (for example, going to a database for each check), you will need to come up with a solution that helps the performance right at the beginning of the game.

 

My career has been optimization for games. Often, I see other people make optimizations hoping for best-case scenarios. They think, maybe if the player doesn't turn, I don't need to redo this vision check here, so I can skip this, etc. They focus on whatever is easiest to compute, and then let the frame rate suffer when the camera is turning, or when the scene is transitioning, or when there are just too many things happening at once. I really believe it's better to get straight after the worst part, and make sure that works fast enough, before going after any easy targets of opportunity. You should really be focused on how to make sure you can process your maximum number of achievement events quickly enough, instead of thinking about what would be wasted when the number of possible achievements gets smaller over time.



#11 BGB   Crossbones+   -  Reputation: 1554

Like
0Likes
Like

Posted 23 July 2013 - 12:02 PM

Note that changing code at run time is generally possible, but the ease/difficulty of doing so depends on what programming language you are using. For dynamic languages like Ruby replacing function definitions at run time is essentially trivial. For compiled languages, you have to do evil things like disabling data execution protection and rewriting code pages. 

 

 

FWIW, there is a "slightly less evil" strategy of making use of function pointers.

 

the basic idea being that the logic is mostly broken down into pieces ("basic operations"), and then structs and function pointers are used to glue everything together. as things change around, then the various structures and function pointers can be changed around, ...

 

when executed, the logic can jump fairly directly from one operation to the next and essentially walk the structure.

 

if done well, this can be fairly flexible and actually a fair bit faster than the "general purpose" logic (lots of complex branching if/else chains or switches).

the drawback, however, is that it is typically much more bulky and nasty-looking, and potentially difficult to understand and debug.

 

generally, I think reorganizing code where possible is preferable to resorting to something like this.

 

 

generally, in my case, it is mostly confined to use in my scripting VM and dynamic type-system and object-system facilities (*1).

 

I had a few times tried using it in image codecs, but typically it is faster/easier just to write special-case versions of functions (say: "hey, we are using 4:2:0 subsampling and YCbCr and an RGBA image buffer" -> use a special version of the logic specifically for this case, falling back to the general case when encountering an unexpected combination of parameters).

 

the tradeoff is that specialized versions of code can also contribute a fair bit of bulk, and are inherently "not really all that flexible" since each only addresses a few specific parameters (say, if we had 3 subsampling modes, 4 color-space transforms, and 4 image-buffer layouts, naively this would mean 48 versions of the image-transform, which is impractical, so usually only 2 or 3 "very common" cases get special handling).

 

sometimes a "mix and match" compromise is possible, with some special-casing of the logic, mixed with the use of function-pointers in other places.

 

 

going beyond this, there is crafting specialized machine-code sequences at run-time, which can execute faster, but opens up a lot of issues (namely portability and complexity). however, machine-code can accomplish a few things which function-pointers can't (it is free from the constraints of the language and ABI, ...).

 

direct self-modifying code and writing into compiler-generated code generally seems like a bad idea IMO.

 

 

*1: actually, they tend to use a mixture of structs and function pointers, and directly-generated native code.

 

in some tests (for script code), using a straight-C route I have gotten within about 10x of native, and about 2x-3x of native C for cases where typically a form of "call-threaded code" is used (the native code = sequence of calls to C functions implementing the logic), with occasional operations being generated directly as machine code (typically things like variable loads/stores and arithmetic operations and similar).

 

typically, this is good enough.

 

a much more "advanced" strategy is to use (or implement) a full compiler, but, this is another level of pain, and adds its own costs.

 

 

using such a code generator for the original problem though would likely be severely overkill.

 

 

or such...



#12 Waterlimon   Crossbones+   -  Reputation: 2565

Like
3Likes
Like

Posted 23 July 2013 - 12:36 PM

You might not have to check all the achievements from the beginning, which makes optimizing this not pointless.

The achievement "Killed second enemy" would be added after the first one is completed. Same with other things that have some preconditions.

I would make a container of achievement objects that check their condition when told to do so. They can then be removed and new ones can be added as the player progresses.

Polymorphism would be used.


Edited by Waterlimon, 24 July 2013 - 02:10 PM.

o3o


#13 Norman Barrows   Crossbones+   -  Reputation: 2138

Like
1Likes
Like

Posted 24 July 2013 - 08:15 AM


thank you for the reply, but I don't really worry about "code exceeding ram"(sorry, I didn't state my question clearly enough). my problem is that I need to do many if statement to test whether the player has completed certain achievements, which is unnecessary after the player has completed those achievements.

 

that's nothing to worry about! <g>.

 

just code it. it'll run plenty fast. even if you do a couple hundred checks per frame.

 

you can nest the checks to make it run faster:

 

if (first opponent killed)

    {

     // run second opponent dead check

    }

 

 

in general, the code will probably take the form of:

 

if (achievement A not awarded)

    {

    check for achievement A completion

    }

else 

    {

    check achievements that require A to be completed first

    }

 

 

for example, you only check for kill #2 once kill #1 is competed.

 

if you have achievements for the first 10 kills, at first it just does it does one if (is A done already?), then does the check for achievement A. only at the end does it do 9 if's (A through I completed) and then check for achievement J.

 

you make be able to implement this in a generic manner, with flags for each achievement saying if they're completed. you might also use flags for stuff like "all 10 first kill achievements done".  you'd check this before checking for kills. once the player had 10 kills, the code would just do that one check per frame.

 

i was thinking you might be able to write a slick generic routine that used the completed flags, dependency info (what achievements are prerequisites for which other achievements), and the various achievement checks to process any and all achievements.  but that would require some sort of check function as a variable. granted you could possibly do function variables for each achievement check. i use this in CAVEMAN. one of the fields in an actions database record is a function variable that contains the address of the action handler code. another common way to implement this is with a big switch() statement. if i did it again, i'd just use a big switch:

 

 

int achievement_done(int achievement _num)

switch(achievement_num)

    {

   case 0:

                 // code to check completion of achievement #0 goes here

                return(result)

   case 1:

                 // code to check completion of achievement #1 goes here

                return(result)

   // add additional checks here

   }


Norm Barrows

Rockland Software Productions

"Building PC games since 1988"

 

rocklandsoftware.net

 


#14 tool_2046   Members   -  Reputation: 1064

Like
0Likes
Like

Posted 24 July 2013 - 12:27 PM

You could maintain a list of achievements you iterate over. When one has been completed remove it from the list to check. No need to hard code each achievement in a giant if/else or case statement. 



#15 sobeit   Members   -  Reputation: 433

Like
0Likes
Like

Posted 24 July 2013 - 01:17 PM

thank you guys! your replies really helped me a lot. I think I've got the basic idea on how to do this.



#16 BGB   Crossbones+   -  Reputation: 1554

Like
0Likes
Like

Posted 24 July 2013 - 01:24 PM

You could maintain a list of achievements you iterate over. When one has been completed remove it from the list to check. No need to hard code each achievement in a giant if/else or case statement. 

 

agreed.

 

using a list of objects of some sort would probably be better than hard-coding it, with a class method or similar to determine when the achievement has been completed.



#17 sobeit   Members   -  Reputation: 433

Like
0Likes
Like

Posted 24 July 2013 - 01:30 PM


 if i did it again, i'd just use a big switch:

 

thank you for your advice. I will try it out.


Edited by sobeit, 24 July 2013 - 01:34 PM.


#18 Paradigm Shifter   Crossbones+   -  Reputation: 5374

Like
0Likes
Like

Posted 24 July 2013 - 03:06 PM

Assuming C++/Java/C#:

 

I'll second the have some kind of container (vector, list) of objects which are derived from a base class which has a pure virtual

 

bool SatisfiedAchievement()

 

method which returns true if the achievement is satisfied, so it can be removed from the container after it has been completed.

 

But what you don't want is each achievement to be a separate class derived from the base class - most achievements are similar (kill enemy X, collect X items, kill X enemies of type Y, etc.), so you want to have the different types of achievements as classes which take parameters on construction (or a separate initialisation step) which provides the details.

 

You can still have really complicated achievement types to have a class of their own, but these should be an exception rather than the norm. Also consider compound achievements which can have several subtasks (such as kill X goblins and collect Y golden nostrils), you can have a compound achievement class which checks for both (so will contain 2 or more instances of concrete achievement classes as members) which only returns true from SatisifiedAchievement when both tasks are complete.

 

 

If you are using C, you can do the same with function pointers.


Edited by Paradigm Shifter, 24 July 2013 - 03:07 PM.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#19 sobeit   Members   -  Reputation: 433

Like
0Likes
Like

Posted 26 July 2013 - 01:28 AM


You could maintain a list of achievements you iterate over. When one has been completed remove it from the list to check. No need to hard code each achievement in a giant if/else or case statement. 

This way, I need to do all the checks in one place which means I need to keep some static variables or database for those events that will trigger achievements, right?



#20 Norman Barrows   Crossbones+   -  Reputation: 2138

Like
1Likes
Like

Posted 26 July 2013 - 05:37 PM

generally speaking when an event occurs (such as player making 1st kill), you can process it immediately, or you must store the event (somehow - perhaps with an event_X_occurred flag) for later processing.

 

this is one of the design options i tend to ponder over with every game i do. should i process events immediately, or store them for later processing? 

 

processing them immediately means i don't have the extra complexity of storing events which are pending processing. 

 

storing them for later processing means i can process all at once, which may be more efficient and/or a more modular design.

 

but usually, storing them for later processing is more work and complexity, and less efficient as well. its not necessarily overhead that a game can't handle, but essentially, its more work to code, and runs slower, just for the benefit of a more modular design.

 

so i usually process events immediately "and be done with it".


Norm Barrows

Rockland Software Productions

"Building PC games since 1988"

 

rocklandsoftware.net

 





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS