PDA

View Full Version : Code review: Mines



Higor
05-11-2012, 03:35 PM
Hope this is the right section, it is discussion after all, in a technical way...

Been talking to ChanClan about posting technical reviews, gonna start here.
Optimizing code and reducing processing time, starting with mines.

====
First of all, we have the mine Timer:

simulated event Timer()
{
local Pawn p;
Super.Timer();


if ( SCount > 0 || Role != ROLE_Authority )
return;

foreach RadiusActors(class'Pawn', p, 75)
if ( p.bIsPlayer && p.Health > 0 &&
p.PlayerReplicationInfo != None &&
p.PlayerReplicationInfo.Team != Team && !p.PlayerReplicationInfo.bIsSpectator || ScriptedPawn(p) != None )
if (p != None && !bDisabledByEMP)
Damage();
}
There is also a RadiusActors iteration, this checks the entire actor list, besides, the iterator doesn't include a break so the Damage() function can be called multiple times lagging even more the server or making the mine deal over 500 damage on lower levels.
Also, bDisabledByEMP is a global conditional, check it outside of the iterator and to sum up, ForEach iterators ALWAYS return a valid actor, otherwise the code isn't even called, so we don't need to check for (p != none).

Suggested code:

simulated event Timer()
{
local Pawn p;
Super.Timer();


if ( SCount > 0 || bDisabledByEMP || Role != ROLE_Authority) //EMP check prevents iterations
return;

ForEach VisibleCollidingActors (class'Pawn', p, 75,,true) //This true makes the iterator ignore actors with bHidden=true property
if ( p.bIsPlayer && p.Health > 0 &&
p.PlayerReplicationInfo != None &&
p.PlayerReplicationInfo.Team != Team && !p.PlayerReplicationInfo.bIsSpectator || ScriptedPawn(p) != None )
{
Damage();
return; //Prevent multiple detonation on same frame
}
}
VisibleCollidingActors is faster, it checks the collision hash for colliding actors instead of the entire actor list, is faster when used with small radius (< 300).
- It checks if the actors have a valid collision (players have, spectators don't so it works)
- It checks if they are in sight so there is no need to call FastTrace on them
- Checks visibility if specified (bHidden).


Next function: Damage

function Damage()
{
local int i;
local Pawn p;
local Pawn pAward;

local vector dir;
local int x;
local int y;
local int z;
local string sMessage;
local string sName;

Self.PlaySound(Sound'SharpExplosion',, 4.0);

pAward = GetAwardedPlayer();

for ( i = 0; i <= Grade; i++ )
{
dir.x = Rand(80)-40;
dir.y = Rand(80)-40;
dir.z = Rand(80)-40;
spawn(class'MineExplosion',,,Location + dir);
foreach RadiusActors(class'Pawn', p, 75+(i*25))
if (p != None)
if (ShouldAttack(p))
{
dir = Location - p.Location;
dir = normal(dir);
if (p.Health>0)
{
p.TakeDamage((Grade+1) * 15, instigator, 0.5 * (p.CollisionHeight + p.CollisionRadius)*dir, vect(0,0,0), 'mine');
sgPRI(pAward.PlayerReplicationInfo).AddRU((Grade+1 ) * 4);
}
}
}

sgPRI(pAward.PlayerReplicationInfo).AddRU(50);

Destroy();

}

Ok, we have here: unneeded variables, slow iterators inside fast iterators and sets of functions that can be replaced with faster stuff.
- Calling a function in unrealscript is VERY EXPENSIVE, unrealscript functions are 40 times slower than their c++ counterparts, so we should focus on reducing the unrealscript function calls even if some functionality is wasted...
- Look how I generate a random dir: (dir = VRand() * 40), 3 functions total: equal, VRand() and *. If i do this without storing the variable, it will only be 2 functions total.
- How it's done in the main code: (dir.x = Rand(80)-40; 3 times) 12 functions total: equal, dot (accessing X in vector struct), Rand(), - (minus), 3 times a row.
- Second, no need to check (p != none) this always returns true here.
PD: Why call SELF.Function if you can simply call function?

Suggested code:

function Damage()
{
local int i;
local Pawn p, pAward;

PlaySound(Sound'SharpExplosion',, 4.0);
pAward = GetAwardedPlayer();

for ( i = 0; i <= Grade; i++ )
{
Spawn (class'MineExplosion',,, Location + VRand() * 40);
ForEach VisibleCollidingActors (class'Pawn', p, 75+(i*25),,true)
{
if ( (p.Health > 0) && ShouldAttack(P) ) //Health check first, faster
{
p.TakeDamage((Grade+1) * 15, instigator, normal( Location - p.Location) * 0.5 * (p.CollisionHeight + p.CollisionRadius), vect(0,0,0), 'mine');
sgPRI(pAward.PlayerReplicationInfo).AddRU((Grade+1 ) * 4);
}
}
}

sgPRI(pAward.PlayerReplicationInfo).AddRU(50);

Destroy();
}

Here we call a collision hash iterator *grade* times, we also removed a lot of unused variables and reduced the amount of function calls.


Next function: ShouldAttack

function bool ShouldAttack(Pawn enemy)
{
if ( ScriptedPawn(enemy) != None )
return true;
if ( enemy == None )
return false;
if ( !FastTrace(enemy.Location) )
return false;
if ( sgBuilding(enemy) != None )
{
if ( sgBuilding(enemy).Team == Team || sgBuilding(enemy).Energy < 0 )
return false;
}
else if ( enemy.PlayerReplicationInfo == None ||
enemy.PlayerReplicationInfo.Team == Team ||
!enemy.bProjTarget )
return false;
return true;
}
This one is simple, we remove the most expensive function here: FastTrace.
Why? VisibleCollidingActors already performs this check.
We also remove the (enemy == none) check, seeing the context this function is called, enemy ALWAYS exists so this check will always return FALSE.

Suggested code:

function bool ShouldAttack(Pawn enemy)
{
if ( ScriptedPawn(enemy) != None )
return true;
if ( sgBuilding(enemy) != None )
{
if ( sgBuilding(enemy).Team == Team || sgBuilding(enemy).Energy < 0 )
return false;
}
else if ( enemy.PlayerReplicationInfo == None ||
enemy.PlayerReplicationInfo.Team == Team ||
!enemy.bProjTarget )
return false;
return true;
}

Supermine optimization in next post...

Higor
05-11-2012, 03:53 PM
Now we deal with the SuperMine subclass:

Function: Timer
We replace the timer as well, with the difference that radius is greater and that supermine is allowed to detonate multiple times.
For that we remove the break inside the iterator.
Suggested code:

event Timer()
{
local Pawn p;
Super.Timer();


if ( SCount > 0 || bDisabledByEMP) //EMP check prevents iterations
return;

ForEach VisibleCollidingActors (class'Pawn', p, 100,,true) //This true makes the iterator ignore actors with bHidden=true property
if ( p.bIsPlayer && p.Health > 0 &&
p.PlayerReplicationInfo != None &&
p.PlayerReplicationInfo.Team != Team && !p.PlayerReplicationInfo.bIsSpectator ) //Original supermine didn't check for monsters, so we do the same?
Damage();
}


Function: Damage
Same logic here, we just modify it with the supermine parameters.

function Damage()
{
local int i;
local Pawn p, pAward;

PlaySound(Sound'SharpExplosion',, 4.0);
pAward = GetAwardedPlayer();

for ( i = 0; i <= Grade; i++ )
{
Spawn (class'MineExplosion',,, Location + VRand() * 40);
ForEach VisibleCollidingActors (class'Pawn', p, 100+(i*35),,true)
{
if ( (p.Health > 0) && ShouldAttack(P) ) //Health check first, faster
{
p.TakeDamage((Grade+1) * 15, instigator, normal( Location - p.Location) * 0.5 * (p.CollisionHeight + p.CollisionRadius), vect(0,0,0), 'supermine');
sgPRI(pAward.PlayerReplicationInfo).AddRU((Grade+1 ) * 4);
}
}
}

sgPRI(pAward.PlayerReplicationInfo).AddRU(50);

Energy -= 200;
if ( Energy <= 0 )
Destruct();
}

Since we use the new iterators here, the ShouldAttack function defined in Mine will work as well here.

The code does EXACTLY THE SAME as before, except that it solves a rare case of normal mines detonating multiple times if more than one player approached it at the same time, not to mention the reduced overhead in the timer and the detonation.

SAM
05-11-2012, 04:56 PM
Thanks very much for taking your time to make such an informative post here Higor. I do believe it is SW's intention to optimise Siege however his time constraints with University is proving a challenge.

I'm sure he will take your comments into account. Please continue posting. I'd love to see just where siege is going wrong and I already know it is all the timer functions as well as actors...

SilverWing
05-11-2012, 04:59 PM
Wow... kk... if u got anymore fixes plz post... and ill add them in if it works...

Im deving Siege right now ( hopefully not for long xD)... and im only able to fix few bugs here and there... so any help i can get would be amazing

do u have xfire/msn ?

audiosonic
05-11-2012, 06:02 PM
so any help i can get would be amazing

UNIVERSITY MATERIAL RIGHT THERE

SilverWing
05-11-2012, 06:15 PM
FIXED :D

|uK|Cube
05-11-2012, 06:50 PM
Things like this u should pm me about (SW)

Moskva
05-11-2012, 06:52 PM
Things like this u should pm me about(SW)

DONT EDIT MY POSTS SILVERPRICK

.seVered.][
05-11-2012, 09:20 PM
Please, let keep these posts semi-public... some of us would like to see these discussion's about the code.

Feralidragon
05-12-2012, 12:01 PM
Great review Higor, but I want to point a very few things up as part of this discussion:



'Simulated' keyword to prevent the event from even being processed and removing the conditional (Role != ROLE_Authority) since removing 'Simulated' already makes this one useless (returns TRUE always on server).
In this case you're absolutely right, but for the sake of SW or other devs not starting to modify that wherever they see this kind of code:
- if your function "Supers" it's counterpart in the superclass (not the case here), keep it simulated and with that check, because if the upper super function needs to be simulated, making it not simulated in your subclass will break the "simulation" chain (since non-simulated only call functions server side, no matter if they are simulated or not, there are just a few exceptions to this rule though).
Only if you're absolutely sure that "Super." doesn't call any simulated function in the chain, then you can discard the "simulated" and the check.




VisibleCollidingActors is faster, it checks the collision hash for colliding actors instead of the entire actor list, is faster when used with small radius (< 300).
I believe that limit is way higher, up to 2000 VCA is faster than RA, from there RA is faster. But that's debatable.




- Calling a function in unrealscript is VERY EXPENSIVE, unrealscript functions are 40 times slower than their c++ counterparts, so we should focus on reducing the unrealscript function calls even if some functionality is wasted...
Sorry, but I cannot agree with that at all. Yes, function calls shouldn't be excessively used (the time taken as to do with the needed instructions to even initialize it, specially with arguments and returns, thus is one of the slowest instructions you can give), however avoiding them at all costs is not the solution either and I think that's an over-dramatization of it.

If we go that way we start to have redundant code, which is very bad programming practice, for example:

a = b + c;
If that is only once or at max twice in your code, just do it that way, but if you use the exact same expression over and over (let's say 5x or more), the best thing to do is:

function doMyThang(){
a = b + c;
}

And call doMyThang() where needed. It has the overhead of the function call, and yes it would be faster to just repeat "a = b + c;", but that's plain wrong in good programming practices, as if you have to update the algorithm, good luck, if you have a problem related to it, good luck again.

So here's the summary:
- don't use functions if there's already something that does the same thing (like Higor rightfully pointed out);
- however, every time you have a repeatable pattern of instructions, don't just copy and paste them to not create functions, create a function for them and reuse that function whenever it's needed (and if your function becomes too big, it's also acceptable and sometimes encouraged to split it into smaller functions as smaller steps of the same algorithm).

Also, 40x slower than C++? That's nothing to worry about, C++ is absurdly fast, and languages like javascript and php are way slower than uScript specially since they're interpreted languages (whereas uscript is byte code like java), and I sure you what you will find there the most are functions, classes and instances (way heavier than functions), in the case of javascript you can even store functions in variables, yet your browser runs them just fine, servers use it, etc, and php for instance was made in C++ and, again, is interpreted (much worse than byte-code in most occasions).
It's not function calls by themselves that will endanger your code into running considerably slower, there are way more weighting problems for drops in performance such as:
- Usage of heavy functions (not the call itself);
- Instantiation of classes (objects): spawns and "new something"
- Graphical processing (which in UT is mostly done in CPU and not GPU);
- Squared and cubic algorithms (cicles within cicles).


Also, there's a better way than that "VisibleCollidingActors" of making the awareness of the mines if we are heading for absolute optimization: in my mod (purely as a practical example), I spawn a custom built "trigger" actor that once touched, it triggers the mine.
Why spawn a seperate trigger and not use the mine itself? For 2 reasons:
- Mine collision to be destroyed (which differs from the sensing);
- Translocator doesn't like any actor other than triggers, inventory and a few others (as for it "touching" other actors is the same as hitting a wall, not sure why they did this, but it's the way it is).

That way instead of relying in a timed iterator, you use once-triggered events, if they aren't triggered, they're just occupying memory space and not processing time.

Just my 2 cents, as for everything else, really nice and I agree.

Higor
05-12-2012, 02:39 PM
It's really unfortunate unrealscript doesn't have inlining though I don't have a problem with that.

But you're right here because Siege is more like a group project, or at least many developers coded it...
I'll try and make a more readable version of both things.

PD: Siege server suffers from heavy lag and increased ping on crowded games, and clearly needs to run as fast as possible, so I may have gone overboard with the gotos.

nOs*Wildcard
05-12-2012, 05:15 PM
Great review Higor, but I want to point a very few things up as part of this discussion:



In this case you're absolutely right, but for the sake of SW or other devs not starting to modify that wherever they see this kind of code:
- if your function "Supers" it's counterpart in the superclass (not the case here), keep it simulated and with that check, because if the upper super function needs to be simulated, making it not simulated in your subclass will break the "simulation" chain (since non-simulated only call functions server side, no matter if they are simulated or not, there are just a few exceptions to this rule though).
Only if you're absolutely sure that "Super." doesn't call any simulated function in the chain, then you can discard the "simulated" and the check.



I believe that limit is way higher, up to 2000 VCA is faster than RA, from there RA is faster. But that's debatable.



Sorry, but I cannot agree with that at all. Yes, function calls shouldn't be excessively used (the time taken as to do with the needed instructions to even initialize it, specially with arguments and returns, thus is one of the slowest instructions you can give), however avoiding them at all costs is not the solution either and I think that's an over-dramatization of it.

If we go that way we start to have redundant code, which is very bad programming practice, for example:

a = b + c;
If that is only once or at max twice in your code, just do it that way, but if you use the exact same expression over and over (let's say 5x or more), the best thing to do is:

function doMyThang(){
a = b + c;
}

And call doMyThang() where needed. It has the overhead of the function call, and yes it would be faster to just repeat "a = b + c;", but that's plain wrong in good programming practices, as if you have to update the algorithm, good luck, if you have a problem related to it, good luck again.

So here's the summary:
- don't use functions if there's already something that does the same thing (like Higor rightfully pointed out);
- however, every time you have a repeatable pattern of instructions, don't just copy and paste them to not create functions, create a function for them and reuse that function whenever it's needed (and if your function becomes too big, it's also acceptable and sometimes encouraged to split it into smaller functions as smaller steps of the same algorithm).

Also, 40x slower than C++? That's nothing to worry about, C++ is absurdly fast, and languages like javascript and php are way slower than uScript specially since they're interpreted languages (whereas uscript is byte code like java), and I sure you what you will find there the most are functions, classes and instances (way heavier than functions), in the case of javascript you can even store functions in variables, yet your browser runs them just fine, servers use it, etc, and php for instance was made in C++ and, again, is interpreted (much worse than byte-code in most occasions).
It's not function calls by themselves that will endanger your code into running considerably slower, there are way more weighting problems for drops in performance such as:
- Usage of heavy functions (not the call itself);
- Instantiation of classes (objects): spawns and "new something"
- Graphical processing (which in UT is mostly done in CPU and not GPU);
- Squared and cubic algorithms (cicles within cicles).


Also, there's a better way than that "VisibleCollidingActors" of making the awareness of the mines if we are heading for absolute optimization: in my mod (purely as a practical example), I spawn a custom built "trigger" actor that once touched, it triggers the mine.
Why spawn a seperate trigger and not use the mine itself? For 2 reasons:
- Mine collision to be destroyed (which differs from the sensing);
- Translocator doesn't like any actor other than triggers, inventory and a few others (as for it "touching" other actors is the same as hitting a wall, not sure why they did this, but it's the way it is).

That way instead of relying in a timed iterator, you use once-triggered events, if they aren't triggered, they're just occupying memory space and not processing time.

Just my 2 cents, as for everything else, really nice and I agree.

Using the actor classes built in Touch() event, Now that's thinking smarter not harder :) Nice. If I were to make a guess on how you made your new NW3 VX Cybot pull things in did you use a clideing actors itterator? Just curious, forgive me if this is a little off topic. Reading these optimizations has stired me up in seeing whats up :calm:

Higor
05-12-2012, 05:35 PM
Could be applied if the mines didn't use trace checks, otherwise, I'd be the first you see on the server detonating them unharmed to clear a path.

Feralidragon
05-12-2012, 07:33 PM
Using the actor classes built in Touch() event, Now that's thinking smarter not harder :) Nice. If I were to make a guess on how you made your new NW3 VX Cybot pull things in did you use a clideing actors itterator? Just curious, forgive me if this is a little off topic. Reading these optimizations has stired me up in seeing whats up :calm:
In the NW3 VX cybot I used the VisibleCollidingActors way, I tried to get a faster way, but given that the pulling radius is very limited and I have to update pawn to "orbit" it instead of getting sucked right away (so he/she/it has a chance to get out), I didn't find any better option.



Could be applied if the mines didn't use trace checks, otherwise, I'd be the first you see on the server detonating them unharmed to clear a path.
Inside of the Touch event/function you can do anything, including trace checks to the touched actor, so what's the problem? :)

PS: You don't need goto's to optimize the code, at all, and I think you know it, but I already covered that up in the other topic.

Higor
05-12-2012, 11:31 PM
When you enter a the touch radius, the event is called, if you're out of sight, mine won't detonate.
You can walk safe then.

Now if you enable a constant check (timer or tick) after the Touch event happens to check that the toucher actor (TouchingActors or VisibleCollidingActors) enters line of sight mine will detonate as soon as enemy enters sight, and check will disable itself when no more players in sight and radius.
Unless...

I take a couple of seconds to enter the trigger out of the visibility zone and then confuse it into thinking that nothing is touching it.
I can still walk past it.

If you take out the visibility check, then I'll be having a field day with carefully placed supermines as I used to do with HE grenades on CS 1.6... that will certainly ruin the gameplay to lots of attackers.
My code might be horrible but I think ahead of engine exploits.

And doesn't the engine somehow check the collision hash to check when actors touch? It's the almost same thing if we used VisibleCollidingActors, excepting for that trace check if something is found, which we actually need in this case.
It's a real damn shame UT doesn't have CollidingActors method, Siege could really use this for Containers.


Gonna fix the timer, didn't realize that the Superclass function does have clientside code.

Feralidragon
05-13-2012, 06:45 AM
I also do my best to think ahead of engine exploits (it doesn't mean I always succeed, so this kind of discussion is good for both sides, so don't think for one second you're the only one thinking or try to think ahead, you're not the only coder or developer in this community), thus that's still no excuse to not improve the way your code is structured so it can be as correct as possible (and you should work that out imo, you obviously have solid knowledge in several languages and very good rational thinking, but it seems to me you're not willing to get better, which is unfortunate).
No one is perfect (like I said, my code isn't perfect either and I try to improve my ways as well) and there's no justification to not (at least try) write "good code" and gather some knowledge how to (what are the bad practices, the good ones, etc, they're not just theoretic, they have a solid reason to be called that way and to be respected by actual professional coders in the business).

Anyway I'm glad you got that far on your thinking about the mines, but instead of thinking "there's an exploit -> quit going that way" you should think "there's an exploit, what's the best way to avoid it but still keep the code optimized?". You're looking too much into micro-optimization, and you're literally discarding any further thinking in what can be severally optimized at some spots.

For instance, I thought ahead of all of that myself when I developed my own mines in a mod yet to be released, so I am perfectly aware of all that *so far*, so what I do is to save the toucher in a custom var in the sensing actor (the trigger) and I don't rely on iterators, instead I have my own function to check if the player is still touching (the collision is an unmovable and non-rotating cylinder, so it's easy to build the algorithm to check if a point is inside this cylinder volume of if another cylinder is touching it, and I built code for that just to keep the code optimized and yet with those exploits covered up), through a timer that is enabled or disabled at will.

Atm I just store the first valid pawn that touched it, so I am aware if 2 enter it and none of them is visually valid from the mine standpoint of view at first, one of them will be able to pass safely, but given the mines sensing is very short in radius and such teamwork is rare, I am not very worried. On the other side, just to cover that one up I might convert this var into an array to list a set of actors anyway (perhaps 4 or 8, more than that would be too much), just to close that exploit possibility.

And no, doing a VisibleCollidingActors check at uscript level or let the engine handle that natively through touch events is not the same thing. You said it yourself: uScript function calls are 40x slower than the c++ ones, plus no one really knows how the engine does this internally on touch unless you have the source code (and I only know 1 guy who has it), but even assuming it does almost the same, it's something handled and optimized at C++ level and which runs once, while you would have the extra overhead by doing it again for *each* mine (and in a match you can have several mines placed around for a long time).

So, in the end, what other exploits do you see here with this way?

.seVered.][
05-13-2012, 01:56 PM
When you enter a the touch radius, the event is called, if you're out of sight, mine won't detonate.
You can walk safe then.

It used to be (2g and Extreme) if you were quick enough on the dodge you could avoid the detonation( by moving away from the direction the mine was built-like backwards). Seems the code for this item has become TOO optimized. Maybe if the mine would change color for a split second, say like .30(which happen's to be the default dodge tick), THEN detonate, but detonate with a larger damage radius (or in one direction if it was a claymore).




Atm I just store the first valid pawn that touched it, so I am aware if 2 enter it and none of them is visually valid from the mine standpoint of view at first, one of them will be able to pass safely, but given the mines sensing is very short in radius and such teamwork is rare, I am not very worried. On the other side, just to cover that one up I might convert this var into an array to list a set of actors anyway (perhaps 4 or 8, more than that would be too much), just to close that exploit possibility.

This would be an excellent implement, however... even with using that tactic (more than one actor) IT DOESN"T WORK (probably due to other optimizations that have improved performace), the timer's are too fast. Let's say, 2 people both with shield belt's on hit the super mine, consecutive. The second player SHOULD make it through with at least half of his health remaining or AT LEAST destroy the mine. ATM, NO ONE CAN, all you can do is use the minigun approach IF the mine is even able to be hit by the minigun (not behind a minishield or container), or nuke the mines.




Gonna fix the timer, didn't realize that the Superclass function does have clientside code.

I would examine ALL clientside superclass functions...

and I are... gunna.... *wink (<redneck humor)

In the words of a once famous singer, ... Walk this way... <;-)~

Higor
05-13-2012, 02:19 PM
Exploit in Touch() method (needs trace checks).

Extra info:
Touching array can be searched even quicklier using TouchingActors iterator, but this is optional.
Touch also takes into account player's collision.

Let's first assume that:
- You have a Touch() event. If in sight detonate, else start Touching (array) checks on Timer or Tick.
- Timer or Tick will check that this new touching player enters line of sight to detonate.
- If this (or all) player leaves touching zone, the Timer or Tick checks will be disabled.

Method:
- Approach the triggered mine's collision box and enter it while out of sight (so FastTrace fails).
- Grab the Flak Cannon or the BioRifle and fire at least 4 projectiles into the trigger's collision box.
- If done correctly, you will remove yourself from the trigger's touching array, disabling the temporary periodic checks.

The only way I see to deal with this is to either remove trace checks, or check for VisibleCollidingActors all the time as it's doing now.

Feralidragon
05-13-2012, 05:14 PM
Sorry, but... you either didn't read my post through, or you didn't understand what I wrote at all.

Either ways, allow me to quote myself from my previous post:


[...]what I do is to save the toucher in a custom var in the sensing actor (the trigger) and I don't rely on iterators, instead I have my own function to check if the player is still touching (the collision is an unmovable and non-rotating cylinder, so it's easy to build the algorithm to check if a point is inside this cylinder volume of if another cylinder is touching it, and I built code for that just to keep the code optimized and yet with those exploits covered up)[...]

And:


Atm I just store the first valid pawn that touched it, so I am aware if 2 enter it and none of them is visually valid from the mine standpoint of view at first, one of them will be able to pass safely, but given the mines sensing is very short in radius and such teamwork is rare, I am not very worried. On the other side, just to cover that one up I might convert this var into an array to list a set of actors anyway (perhaps 4 or 8, more than that would be too much), just to close that exploit possibility.

Summary: I do NOT use the Touching array at all, exactly because of that: the array holds up to 4 actor references, and once 1 more enters it, the older gets replaced, and on.
Instead, I have:
- My own variable that stores the first player that touched it (but as stated above I might convert it to a list instead);
- In that variable only possible valid actors that can make the mine explode are the ones considered, everything else is ignored (that includes most projectiles);
- To know if the player is still in it without using touching nor relying on "untouch" (since the latter is also unreliable), I have a function of my own that pretty much checks if actor A is touching actor B (in this case a player relative the mine sensor), and I can guarantee it's 100% accurate (and it considers both collisions exactly like the real Touch or touching would do), but it's me who manage this with custom code, and it's super fast and doesn't need visiblecollidingactors nor any other iterator at all.

So I already have that exploit covered up as I stated 1 post ago, so I ask again:
is there any exploit you still see with this method?

Higor
05-13-2012, 09:06 PM
Dang, I didn't even see your post, nor severed's.

That is a good way to cover that exploit, and I'd make that array 4 elements long, playing today just saw 2 ppl group on the other side of a supermine's corner and a third one crossing.
I would make the CollisonHeight 20 or 30 units smaller than the radius, players have greater height after all.

Unfortunately I won't be here till next week so I won't be able to post or read anything.

.seVered.][
05-21-2012, 09:36 PM
Let's get this MINE discussion going again... I think it's a valid point and someone else should comment on it.