logo
Main

Forums

Downloads

Unreal-Netiquette

Donate for Oldunreal:
Donate

borderline

Links to our wiki:
Wiki

Walkthrough

Links

Tutorials

Unreal Reference

Usermaps

borderline

Contact us:
Submit News
Page Index Toggle Pages: 1 Send TopicPrint
Hot Topic (More than 10 Replies) Real crouching bug: telefragging when getting up (Read 349 times)
Masterkent
Developer Team
Offline



Posts: 890
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Real crouching bug: telefragging when getting up
Dec 1st, 2017 at 11:49am
Print Post  
When restoring the original player's height, PlayerPawn.SetCrouch calls SetLocation(Location):

Code
Select All
// 227g real crouching mode implemention:
simulated final function SetCrouch( bool bCrouching )
{
	local float OldHeight,NewHeight;

	if( bIsReducedCrouch==bCrouching || CrouchCheckTime==Level.TimeSeconds )
		return; // No can do.
	CrouchCheckTime = Level.TimeSeconds; // Avoid any possible runaway loops.

	bIsReducedCrouch = bCrouching;

	if( bCrouching )
	{
		// Update collision size, prepivot height and location.
		OldHeight = CollisionHeight;
		SetCollisionSize(CollisionRadius,CollisionHeight*CrouchHeightPct);
		OldHeight = OldHeight-CollisionHeight;
		PrePivot.Z+=OldHeight;
		EyeHeight+=OldHeight;
		Move(vect(0,0,-1)*OldHeight);
	}
	else
	{
		// Reset collision size, prepivot height and location.
		OldHeight = CollisionHeight;
		NewHeight = CollisionHeight/CrouchHeightPct;
		OldHeight = NewHeight-OldHeight;
		PrePivot.Z-=OldHeight;
		OldHeight*=0.5f;
		EyeHeight-=OldHeight;
		Move(vect(0,0,2)*OldHeight);
		SetLocation(Location);
		SetCollisionSize(CollisionRadius,NewHeight);
	}
} 


If the player overlaps with other Pawn, the Pawn may be telefragged by the player. What is the purpose of calling SetLocation here?
  
Back to top
 
IP Logged
 
Smirftsch
Forum Administrator
*****
Offline



Posts: 7552
Location: at home
Joined: Apr 30th, 1998
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #1 - Dec 1st, 2017 at 1:17pm
Print Post  
dots made it back then, but iirc it is to avoid that the pawn is falling through (static) meshes when crouching on these. No idea if this is even necessary yet nowadays, since a lot of things changed since then.
  

Sometimes you have to lose a fight to win the war.
Back to top
WWWICQ  
IP Logged
 
medor
Senior Member
****
Offline


Oldunreal member

Posts: 250
Joined: May 17th, 2009
Re: Real crouching bug: telefragging when getting up
Reply #2 - Dec 3rd, 2017 at 9:44am
Print Post  
  
Back to top
 
IP Logged
 
Smirftsch
Forum Administrator
*****
Offline



Posts: 7552
Location: at home
Joined: Apr 30th, 1998
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #3 - Dec 3rd, 2017 at 5:23pm
Print Post  
since UT does not have static meshes (and other things) its maybe not comparable, but worth a look, thanks Smiley
  

Sometimes you have to lose a fight to win the war.
Back to top
WWWICQ  
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 890
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #4 - Dec 3rd, 2017 at 8:06pm
Print Post  
Smirftsch wrote on Dec 3rd, 2017 at 5:23pm:
since UT does not have static meshes (and other things) its maybe not comparable, but worth a look, thanks Smiley

That mod is bugged: it lets you fall through plain decorations (e.g. SteelBox or Barrel).

Do you have any map with static meshes for testing 227's implementation?
  
Back to top
 
IP Logged
 
Smirftsch
Forum Administrator
*****
Offline



Posts: 7552
Location: at home
Joined: Apr 30th, 1998
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #5 - Dec 4th, 2017 at 7:32am
Print Post  
Masterkent wrote on Dec 3rd, 2017 at 8:06pm:
That mod is bugged: it lets you fall through plain decorations (e.g. SteelBox or Barrel).

sounds familiar somehow. Very much assume its the same problem.

Masterkent wrote on Dec 3rd, 2017 at 8:06pm:
Do you have any map with static meshes for testing 227's implementation?

nope, but just build a 256 cube or something and convert to static mesh, should be sufficient.
  

Sometimes you have to lose a fight to win the war.
Back to top
WWWICQ  
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 890
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #6 - Dec 4th, 2017 at 8:14pm
Print Post  
I checked static meshes on SP-DontShootTheChest1. That code works well with and without calling SetLocation. Perhaps, SetLocation is used to force touching between the player and other actors (e.g. triggers). The mentioned bug is easy to fix, but I found many other disadvantages in the current implementation, so I gonna write up a technical report with possible fixes a bit later.
  
Back to top
 
IP Logged
 
Krull0r
Global Moderator
Betatester
Developer Team
*****
Offline


227 Emitter Expert

Posts: 302
Location: Germany
Joined: Jul 1st, 2007
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #7 - Dec 4th, 2017 at 8:46pm
Print Post  
If you touch real crouching I like to request that the crouching camera height should be the same like the standard crouching.
  

Back to top
 
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 890
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #8 - Dec 4th, 2017 at 9:14pm
Print Post  
Krull0r wrote on Dec 4th, 2017 at 8:46pm:
If you touch real crouching I like to request that the crouching camera height should be the same like the standard crouching.

I already implemented a fix for 3d person view. If you mean something else, could you clarify what else should be changed?
  
Back to top
 
IP Logged
 
Krull0r
Global Moderator
Betatester
Developer Team
*****
Offline


227 Emitter Expert

Posts: 302
Location: Germany
Joined: Jul 1st, 2007
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #9 - Dec 5th, 2017 at 12:15am
Print Post  
When using real crouching the first person camera is way to close to the ground. It is more like laying on the ground.

I made an example video which shows the difference between normal crouching and real crouching.

normal crouching vs real crouching





I think it's important that the player do not notice that real crouching is active. It should be the same eye height like normal crouching.
  

Back to top
 
IP Logged
 
[]KAOS[]Casey
Developer Team
Betatester
Offline


nedm

Posts: 3082
Joined: Aug 7th, 2011
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #10 - Dec 5th, 2017 at 3:38am
Print Post  
I have my own implementation of crouch code in a pawn i made that doesnt use setlocation. Only SetCollisionSize and MoveSmooth, but it does have eyeheight/camera problems as I recall.
  
Back to top
 
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 890
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #11 - Dec 6th, 2017 at 9:12pm
Print Post  
Krull0r wrote on Dec 5th, 2017 at 12:15am:
When using real crouching the first person camera is way to close to the ground. It is more like laying on the ground.

Indeed, I forgot about that issue, although I noticed it before.

Quote:
I think it's important that the player do not notice that real crouching is active. It should be the same eye height like normal crouching.

I think, that would make sense only for a particular crouch height factor, namely

CrouchHeightPct = 1 - default.BaseEyeHeight / (2 * default.CollisionHeight)

For standard Humans that would be equal to 1 - 23.0 / (2 * 39.0), that is, approximately 0.7051282.

The default value of PlayerPawn.CrouchHeightPct is 0.55, which is noticeably less than the above. Assuming that for normal crouch the distance between the camera and the ground is 39 uu (CollisionHeight + EyeHeight where CollisionHeight is 39 and EyeHeight is 0), maintaining the same distance for the case of reduced collision height would imply that the distance between the camera and the top of the player's collision cylinder would be equal to 39.0 * 0.55 - 39.0 = 3.9 uu. When the player is standing, the distance between the camera and the top is 39.0 - 23.0 = 16.0 uu. A transition from 16.0 uu to 3.9 uu would imply a serious deformation of the head :=)

I have no idea why 0.55 has been chosen as the default value of CrouchHeightPct, but it's too late to change it now. Some maps may really need a crouch height factor that would be less than 0.7051282. F.e., on Jones-06-Vandora a player needs to reduce his collision height by at least ~1/0.65 times in order to reach health vials in the box beyond the last arena (1/0.66 or below is not sufficient). Currently mappers have no any standard means to declare what crouch height factor would be desirable for their maps - they can only change LevelInfo's bSupportsRealCrouching. Managing CrouchHeightPct is possible only via scripting, but many mappers don't have a sufficient knowledge in this area. So, we can expect that the majority of maps using this feature rely on the current default, that is 0.55.

If we assume that the distance between the camera and the top of the collision cylinder should be constant, then we can expect that such a low crouch height factor would imply a noticeably lower camera position than in case of normal crouch: 26.9 uu against 39.0 uu from the ground. The current implementation makes it more low (21.45 uu instead of 26.9 uu), so a slight improvement is possible nevertheless.

[]KAOS[]Casey wrote on Dec 5th, 2017 at 3:38am:
I have my own implementation of crouch code in a pawn i made that doesnt use setlocation.

ATM, I'm trying to modify Engine.PlayerPawn in order to achieve a satisfactory behavior in various scenarios. Although I decided to avoid using SetLocation for PlayerPawn directly, I had to call SetLocation during speculative evaluations that are supposed to determine if the player can leave the crouching state. My current implementation is rather complicated:

Code (Javascript)
Select All
simulated final function SetCrouch(bool bCrouching)
{
	local float OldHeight, NewHeight, VerticalOffset;
	local bool bOldCollideActors, bOldBlockActors, bOldBlockPlayers, bOldCollideWorld;

	if (bIsReducedCrouch == bCrouching || CrouchCheckTime == Level.TimeSeconds)
		return; // No can do.
	CrouchCheckTime = Level.TimeSeconds; // Avoid any possible runaway loops.

	bIsReducedCrouch = bCrouching;

	if (bCrouching)
	{
		// Update collision size, prepivot height and location.
		OldHeight = CollisionHeight;
		SetCollisionSize(CollisionRadius,CollisionHeight*CrouchHeightPct);
		VerticalOffset = OldHeight - CollisionHeight;
		PrePivot.Z += VerticalOffset;
		EyeHeight += VerticalOffset;
		Move(vect(0, 0, -1) * VerticalOffset);
	}
	else
	{
		// Reset collision size, prepivot height and location.
		OldHeight = CollisionHeight;
		NewHeight = CollisionHeight/CrouchHeightPct;
		VerticalOffset = NewHeight - OldHeight;
		PrePivot.Z -= VerticalOffset;
		EyeHeight -= VerticalOffset;

		bOldCollideActors = bCollideActors;
		bOldBlockActors = bBlockActors;
		bOldBlockPlayers = bBlockPlayers;
		bOldCollideWorld = bCollideWorld;

		SetCollision(false, false, false); // actors should not be touched during the next move operation
		bCollideWorld = false;
		SetCollisionSize(CollisionRadius, NewHeight); // calling before Move to prevent calls to UnTouch
		Move(vect(0, 0, -1) * VerticalOffset); // move the pawn so that its upper bound remains on the same level

		SetCollision(bOldCollideActors, false, false); // enable calls to Touch
		Move(vect(0, 0, 2) * VerticalOffset); // move to the destination location,
		SetCollision(bOldCollideActors, bOldBlockActors, bOldBlockPlayers);
		bCollideWorld = bOldCollideWorld;
	}
}
simulated final function bool TryToDuck(bool bCrouching)
{
	if (!Level.bSupportsRealCrouching || bIsReducedCrouch == bCrouching)
		return true;
	if (bCrouching)
	{
		SetCrouch(true);
		return true;
	}
	// Make sure theres space to get up.
	if (!class'RealCrouchSpaceChecker'.static.CanStand(self, CollisionHeight/CrouchHeightPct))
		return false; // Wasnt enough space to uncrouch.
	SetCrouch(false);
	return true;
} 


Code (Javascript)
Select All
class RealCrouchSpaceChecker expands Info;

var private bool bIsBlocked;

static function bool CanStand(PlayerPawn Player, float StandingCollisionHeight)
{
	local RealCrouchSpaceChecker Checker;
	local vector Offset;
	local bool bResult;

	if (!Player.bCollideActors && !Player.bCollideWorld)
		return true;

	Offset = vect(0, 0, 1) * (StandingCollisionHeight - Player.CollisionHeight);
	Checker = Player.Spawn(class'RealCrouchSpaceChecker',,, Player.Location - Offset);
	if (Checker == none) // Abnormal case
		return true;     // Prevent permanent crouching

	if (Player.bCollideActors)
	{
		Checker.SetCollision(true, false, false);
		Checker.SetCollisionSize(Player.CollisionRadius, StandingCollisionHeight);
		Checker.Move(2 * Offset); // Checking if the player would touch blocking actors

		if (Checker.bIsBlocked)
			return Checker.CanStandResult(false);
	}

	if (!Player.bCollideWorld)
		return Checker.CanStandResult(true);

	Checker.SetCollision(false, false, false);
	Checker.SetCollisionSize(Player.CollisionRadius, Player.CollisionHeight);
	Checker.SetLocation(Player.Location);
	Checker.bCollideWorld = true;

	Checker.Move(2 * Offset); // Checking if the player would hit the level geometry

	if (Checker.Location == Player.Location + 2 * Offset)
		return Checker.CanStandResult(true);

	// Sometimes the engine allows a small overlapping with level geometry as a result of player movement;
	// Trying to simulate such a movement
	Checker.SetCollisionSize(Player.CollisionRadius, StandingCollisionHeight);
	return Checker.CanStandResult(Checker.SetLocation(Checker.Location - Offset) && Checker.SetLocation(Player.Location + Offset));
}

function bool CanStandResult(bool bResult)
{
	Destroy();
	return bResult;
}

event Touch(Actor A)
{
	// see AActor::IsBlockedBy
	if (bIsBlocked || !A.bBlockPlayers)
		return;
	if (PlayerPawn(A) != none)
	{
		if (Instigator.bBlockPlayers)
			bIsBlocked = true;
	}
	else if (Instigator.bBlockActors)
		bIsBlocked = true;
}

event FellOutOfWorld();

defaultproperties
{
	RemoteRole=ROLE_None
} 


and it's still imperfect. Probably, a perfect implementation is not possible without special C++ functions.

Quote:
but it does have eyeheight/camera problems as I recall.

I doubt that a non-intrusive mod (that would not subclass PlayerPawn) can change EyeHeight/BaseEyeHeight properly.
« Last Edit: Dec 7th, 2017 at 2:08pm by Masterkent »  
Back to top
 
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 890
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #12 - Dec 7th, 2017 at 10:24am
Print Post  
Smirftsch wrote on Dec 1st, 2017 at 1:17pm:
but iirc it is to avoid that the pawn is falling through (static) meshes when crouching on these. No idea if this is even necessary yet nowadays, since a lot of things changed since then.

The reason why players can fall through meshes on 227i is wrong move offset in PlayerPawn.SetCrouch:

Code
Select All
		// Reset collision size, prepivot height and location.
		OldHeight = CollisionHeight;
		NewHeight = CollisionHeight/CrouchHeightPct;
		OldHeight = NewHeight-OldHeight;
		PrePivot.Z-=OldHeight;
		OldHeight*=0.5f;
		EyeHeight-=OldHeight;
		MoveSmooth(vect(0,0,1)*OldHeight);
		SetCollisionSize(CollisionRadius,NewHeight); 


I don't see any reasons to use the multiplier 0.5f here - neither for the purposes of changing the value of EyeHeight nor for the move operation. The player must be moved upwards by (CollisionHeight/CrouchHeightPct - CollisionHeight) uu. When the offset is less than this value, the bottom bound of the player is placed below the initial height due to change of the CollisionHeight, this is why the PlayerPawn may fall through the actor below.

In 227j, the move operation was fixed to use the correct offset:

Code
Select All
		// Reset collision size, prepivot height and location.
		OldHeight = CollisionHeight;
		NewHeight = CollisionHeight/CrouchHeightPct;
		OldHeight = NewHeight-OldHeight;
		PrePivot.Z-=OldHeight;
		OldHeight*=0.5f;
		EyeHeight-=OldHeight;
		Move(vect(0,0,2)*OldHeight);
		SetLocation(Location);
		SetCollisionSize(CollisionRadius,NewHeight); 


The role of SetLocation called prior to SetCollisionSize is still unclear for me. It doesn't make any sense for establishing new touches between actors or for adjusting the location of the PlayerPawn actor, because it might make sense only if it was called _after_ setting CollisionHeight to the target value. A move operation (via Move/MoveSmooth) may result in touching other actors anyway, while expansion of an actor by means of SetCollisionSize never adds new actors to the touch list (as far as I can see).

There is an alternative way to prevent skipping touches due to expansion: the player can be moved in the opposite direction and then back, so during the last move operation the upper bound of the player could cross all actors above on the way to its target height. This is an example of how it can be implemented:

Code
Select All
		// Reset collision size, prepivot height and location.
		OldHeight = CollisionHeight;
		NewHeight = CollisionHeight/CrouchHeightPct;
		VerticalOffset = NewHeight - OldHeight;
		PrePivot.Z -= VerticalOffset;
		EyeHeight -= VerticalOffset;

		bOldCollideActors = bCollideActors;
		bOldBlockActors = bBlockActors;
		bOldBlockPlayers = bBlockPlayers;
		bOldCollideWorld = bCollideWorld;

1		SetCollision(false, false, false); // actors should not be touched during the next move operation
1		bCollideWorld = false;
2		SetCollisionSize(CollisionRadius, NewHeight); // calling before Move to prevent calls to UnTouch
3		Move(vect(0, 0, -1) * VerticalOffset); // move the pawn so that its upper bound remains on the same level

4		SetCollision(bOldCollideActors, false, false); // enable calls to Touch
5		Move(vect(0, 0, 2) * VerticalOffset); // move to the destination location,
6		SetCollision(bOldCollideActors, bOldBlockActors, bOldBlockPlayers);
6		bCollideWorld = bOldCollideWorld; 


At (1) we disable any collision, so the player can be later moved down without interaction with any actors or level geometry.

At (2) we set the target value of collision height, so moving the player would not cause untouching for the actors that are currently touching the player.

At (3) we move the player down so that player's upper bound is placed on the same level as it was before step (2).

At (4) we conditionally enable weak interaction with other actors (if player's bCollideActors was true before step (1)), that is, we permit touching with other actors on the next move operation. However, we do not let other actors block the player.

At (5) we move the PlayerPawn to the location where the player is finally supposed to be when standing. In some specific cases, the player may eventually overlap with the ceiling, but falling through floor or actors below should be excluded. How often overlapping with ceiling is possible depends on the quality of the method that determines whether the player can stand up. SetCrouch(false) should not be called without ensuring that standing up is possible.

At (6) we restore the original collision properties.

A few notes about why a correct registering of touches is important. Imagine a map where a player should crouch in order to move under some lethal trigger (which might represent something like an electric fence). If you stand up and touch the trigger, you're supposed to die. The problem with naive implementations of "real crouch" is that you can easily miss the trigger if the upper bound of your collision cylinder is moved across the lower bound of the trigger only by means of SetCollisionSize (which does not register touches) and there is nothing that would force calling Touch on the trigger.
  
Back to top
 
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 890
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: Real crouching bug: telefragging when getting up
Reply #13 - Dec 8th, 2017 at 8:09pm
Print Post  
On the other hand, this "double-move" method may cause inappropriate (Foot/Head)ZoneChange or ZoneInfo.ActorEntered/ActorLeaving calls. So, it looks like SetLocation would give the best approximation to the ideal...
  
Back to top
 
IP Logged
 
Page Index Toggle Pages: 1
Send TopicPrint
Bookmarks: del.icio.us Digg Facebook Google Google+ Linked in reddit StumbleUpon Twitter Yahoo