logo
Page Index Toggle Pages: 1 [2] 3  Send TopicPrint
Very Hot Topic (More than 25 Replies) bloblets etc (Read 9903 times)
Masterkent
Developer Team
Offline



Posts: 1345
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: bloblets etc
Reply #15 - Apr 5th, 2016 at 7:57pm
Print Post  
As far as I remember, there were some mods that changed blood effects. For people who have any such mods and j_34 I'd recommend to check if those mods still work correctly after the recent changes in 227j branch.
  
Back to top
 
IP Logged
 
Smirftsch
Forum Administrator
*****
Offline



Posts: 8100
Location: at home
Joined: Apr 30th, 1998
Gender: Male
Re: bloblets etc
Reply #16 - Apr 7th, 2016 at 5:33am
Print Post  
Masterkent wrote on Mar 19th, 2016 at 5:29pm:
A minor tweaking:

the following code should be inserted in UnrealShare.Blood2.PawnBleeding

Code
Select All
		if (Instigator == Instigator.LastDamageInstigator)
			Momentum *= 0.6; 


after

Code
Select All
	if (Instigator != none &&
		Instigator.LastDamageTime == Level.TimeSeconds &&
		!Instigator.bLastDamageSpawnedBlood)
	{
		Momentum = Instigator.LastDamageMomentum / FMax(Instigator.Mass, 1) * 3.0; 




added this code.
  

Sometimes you have to lose a fight to win the war.
Back to top
WWWICQ  
IP Logged
 
Shivaxi
The One Who Wanted To Have A Special Title In Forum
Betatester
****
Offline


Loving Pie

Posts: 2245
Location: BEHIND U!!!
Joined: Mar 8th, 2006
Gender: Male
Re: bloblets etc
Reply #17 - Dec 26th, 2016 at 3:17pm
Print Post  
Masterkent wrote on Feb 16th, 2016 at 6:13pm:
The only general resolution that comes to mind is a complete refactoring of the code responsible for bleeding and spawning blood decals.

While Pawn.TakeDamage has the direct access to essential values such as damage momentum, damage type, etc, it doesn't really know if/when a particular pawn is supposed to bleed and what blood color should be chosen for it (so it has to rely on the hardcoded check Pawn.IsA('ScriptedPawn') && ScriptedPawn(Pawn).bGreenBlood which does not cover non-ScriptedPawns).

Typically visual effects corresponding to a pawn damage are defined in PlayHit that may spawn blood effects (existing in pre-227 versions) or not. The majority of (if not all) such blood effects are implemented in UnrealShare.Blood2 (or its subclasses). The presence of an UnrealShare.Blood2 whose Instigator is the last damaged pawn is an evidence that the given pawn is bleeding, so we can relatively safely spawn UnrealShare.BloodSpray2 in such a case and avoid a situation when a pawn begins to bleed when it's not supposed to do so. UnrealShare.Blood2.PreBeginPlay could perform all necessary checks and possibly spawn UnrealShare.BloodSpray2 (which is directly responsible for spawning blood decals) as shown below:

Engine.LevelInfo:
Code
Select All
struct PawnDamageInfo
{
	var Pawn Victim;
	var Pawn Instigator;
	var vector HitLocation;
	var vector Momentum;
	var name DamageType;
	var float Time;
	var bool bSpawnedBlood;
};

var transient PawnDamageInfo LastPawnDamage; 


Engine.Pawn.TakeDamage:
Code
Select All
	if ( Level.Game!=None && Level.Game.GameRules!=None )
	{
		for ( GR=Level.Game.GameRules; GR!=None; GR=GR.NextRules )
			if ( GR.bModifyDamage )
				GR.ModifyDamage(Self,instigatedBy,Damage,hitlocation,damageType,momentum);
	}

	Level.LastPawnDamage.Victim = self;
	Level.LastPawnDamage.Instigator = instigatedBy;
	Level.LastPawnDamage.HitLocation = HitLocation;
	Level.LastPawnDamage.Momentum = momentum;
	Level.LastPawnDamage.DamageType = damageType;
	Level.LastPawnDamage.Time = Level.TimeSeconds;
	Level.LastPawnDamage.bSpawnedBlood = false; 


Code
Select All
	if (!bDeleteMe && actualdamage > 0 && DamageType != 'DROWNED')
	{
		Momentum2=Momentum*3.0;
		if (DamageType == 'SHREDDED')
			Momentum2 = vect(0,0,0);
		if (DamageType == 'SHOT')
			Momentum2 = Momentum2*2;

		RadNum = Rand(4);
		if (RadNum > 0)
		{
			if (Pawn_BloodsprayClass == None)
				Pawn_BloodsprayClass = class<actor>(DynamicLoadObject("UnrealShare.BloodSpray2",class'Class'));

			if (Pawn_BloodsprayClass != none)
			{
				for (i = 0; i< RadNum; i++)
				{
					b=Spawn(Pawn_BloodsprayClass,self,'',hitlocation,rotator(location-hitlocation));
					if (b != none)
						b.Velocity=Momentum2+Vrand()*100;
				}
			}
		}
		if ( Level.Game.bBleedingEnabled && FRand() < 0.5 ) // Start bleeding.
		{
			if (BleedingActor == None)
			{
				if (!bIsBleeding)
				{
					if(Pawn_BleedingClass == None)
						Pawn_BleedingClass = class<actor>(DynamicLoadObject("UnrealShare.Bleeding",class'Class'));
					 if (Pawn_BleedingClass != none)
						BleedingActor=Spawn(Pawn_BleedingClass,Self,'',hitlocation,rotator(location-hitlocation));
					if (BleedingActor != none)
					{
						bIsBleeding=True;
						BleedingActor.Instigator=InstigatedBy;
						BleedingActor.SetTimer(0.1,false);
					}
				}
			}
			else
			{
				bIsBleeding=True;
				BleedingActor.Instigator=InstigatedBy;
				BleedingActor.SetTimer(Level.TimeDilation + (Rand(3) / Level.TimeDilation), false);
			}
		}
	} 


UnrealShare.Blood2
Code
Select All
var array<BloodSpray2> BloodSprays;
var Bleeding PawnBleedingActor;

simulated function GreenBlood()
{
	Texture = texture'BloodSGrn';
	GreenBleeding();
}

function PreBeginPlay()
{
	PawnBleeding();
	if ( Level.Game!=None && Level.Game.bVeryLowGore )
		GreenBlood();
}

function PawnBleeding()
{
	local vector Momentum;
	local int i;
	local Actor b;

	if (Instigator != none &&
		Instigator == Level.LastPawnDamage.Victim &&
		Level.LastPawnDamage.Time == Level.TimeSeconds &&
		!Level.LastPawnDamage.bSpawnedBlood)
	{
		Momentum = Level.LastPawnDamage.Momentum / FMax(Instigator.Mass, 1) * 3.0;
		if (Level.LastPawnDamage.DamageType == 'SHREDDED')
			Momentum = vect(0,0,0);
		else if (Level.LastPawnDamage.DamageType == 'SHOT')
			Momentum *= 2;


		if (Instigator.Pawn_BloodsprayClass == None)
			Instigator.Pawn_BloodsprayClass = class'BloodSpray2';

		for (i = Rand(4); i > 0; --i)
		{
			b = Spawn(Instigator.Pawn_BloodsprayClass, Instigator, '', Location, rotator(Instigator.Location - Level.LastPawnDamage.HitLocation));
			if (b != none)
				b.Velocity = Momentum + VRand() * 100;
			if (BloodSpray2(b) != none)
				BloodSprays[Array_Size(BloodSprays)] = BloodSpray2(b);
		}

		if (Level.Game.bBleedingEnabled && FRand() < 0.5) // Start bleeding.
		{
			if (Instigator.Pawn_BleedingClass == none)
				Instigator.Pawn_BleedingClass = class'Bleeding';

			b = Spawn(Instigator.Pawn_BleedingClass, Instigator, '', Location, rotator(Instigator.Location - Level.LastPawnDamage.HitLocation));

			if (b != none)
			{
				if (Instigator.BleedingActor != none)
					Instigator.BleedingActor.Destroy();
				Instigator.BleedingActor = b;
				Instigator.bIsBleeding = true;
				Instigator.BleedingActor.Instigator = Level.LastPawnDamage.Instigator;
			}
			PawnBleedingActor = Bleeding(Instigator.BleedingActor);
		}

		Level.LastPawnDamage.bSpawnedBlood = true;
	}
}

function GreenBleeding()
{
	local int i;

	for (i = 0; i < Array_Size(BloodSprays); ++i)
		if (BloodSprays[i] != none && !BloodSprays[i].bDeleteMe)
		{
			BloodSprays[i].Green();
			if (ScriptedPawn(Instigator) == none)
				BloodSprays[i].RemoteRole = ROLE_None; // impossible to transfer color change to clients
		}
	if (PawnBleedingActor != none && !PawnBleedingActor.bDeleteMe)
		PawnBleedingActor.Green();
} 


(I also modified the implementation of postponed bleeding, since it doesn't seem to work as intended, namely, 227 code does not reset pawn's BleedingActor (UnrealShare.Bleeding) properly when its counter BleedAmount reaches zero, so once the pawn stops to bleed, further damage cannot make it bleed anymore. Was this functionality ever tested?)

It may be too late to make such changes without introducing a new config option, because some mods may rely on the existing implementation.



Yes, 2 of my mods relied on this sytem, RLCoop and BallisticBlood (BallisticBlood I haven't tested in J_35 yet to see how it is affected, but RLCoop is definitely broken), and now with the changes made in 227j_35, I have absolutely no idea how to get these working again, or if it's even possible to make it work with both 227j and 227i anymore without having to make 2 entirely separate mods.  Why didn't we just add some code to the Bloblet to tell it not to spawn any blood, period?  I may not be the greatest coder around, but wouldn't that have been easier?

Also this part:

Quote:
(I also modified the implementation of postponed bleeding, since it doesn't seem to work as intended, namely, 227 code does not reset pawn's BleedingActor (UnrealShare.Bleeding) properly when its counter BleedAmount reaches zero, so once the pawn stops to bleed, further damage cannot make it bleed anymore. Was this functionality ever tested?)


I coulda sworn this worked before, but I tested just now in 227j_27 (old code) and it seems I'm not able to bleed again after I stop bleeding the first time, which is strange though because you can in RLCoop which is basically subclassing off this system anyway, so I don't know what's happening there, but something that seems easily fixable in any case.
  

 
Back to top
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 1345
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: bloblets etc
Reply #18 - Dec 26th, 2016 at 7:30pm
Print Post  
Shivaxi wrote on Dec 26th, 2016 at 3:17pm:
Yes, 2 of my mods relied on this sytem, RLCoop and BallisticBlood (BallisticBlood I haven't tested in J_35 yet to see how it is affected, but RLCoop is definitely broken), and now with the changes made in 227j_35

Those changes were applied in j_34. It would be nice if beta testers checked updates a bit more frequently. It's much more easy to think about possible solutions with fresh memories about the relevant details.

Quote:
I have absolutely no idea how to get these working again

I can't suggest anything without seeing the relevant code that depends on the old implementation.

Quote:
it's even possible to make it work with both 227j and 227i anymore without having to make 2 entirely separate mods.

If a hypothetical 227j_34-compatible solution does not access new properties, then different implementations could be chosen based on either the value of Level.EngineSubVersion or the result of some feature test like (DynamicLoadObject("Engine.Pawn.LastDamageInstigator", class'Object', true) != none). Again, I cannot tell more without seeing your code.

Quote:
Why didn't we just add some code to the Bloblet to tell it not to spawn any blood, period?

Because the current fix is supposed to resolve the issue for all possible pawns (e.g. to prevent nonsense like bleeding automatic cannons). It also restricts damage types that may cause bleeding (pre-227 implementation made by Epic Games defines subsets of damage types that may cause appearance of blood).
  
Back to top
 
IP Logged
 
Leo T_C_K
Betatester
Offline



Posts: 1968
Joined: Aug 27th, 2005
Gender: Male
Re: bloblets etc
Reply #19 - Dec 27th, 2016 at 3:40am
Print Post  
I'm back to reply here and I agree with kent. I saw ridiculous stuff like the robot for unrealball or something similar bleeding, in a basketball game and similar things. This solution prevents that.

Imagine all mods in existence having to update just because you wanted an inherent change to 227 so you could make somethin easier.
  

People who accuse others of trolling are usually the biggest trolls themselves.
Back to top
YouTube  
IP Logged
 
Shivaxi
The One Who Wanted To Have A Special Title In Forum
Betatester
****
Offline


Loving Pie

Posts: 2245
Location: BEHIND U!!!
Joined: Mar 8th, 2006
Gender: Male
Re: bloblets etc
Reply #20 - Dec 28th, 2016 at 1:48am
Print Post  
Masterkent wrote on Dec 26th, 2016 at 7:30pm:
Shivaxi wrote on Dec 26th, 2016 at 3:17pm:
Yes, 2 of my mods relied on this sytem, RLCoop and BallisticBlood (BallisticBlood I haven't tested in J_35 yet to see how it is affected, but RLCoop is definitely broken), and now with the changes made in 227j_35

Those changes were applied in j_34. It would be nice if beta testers checked updates a bit more frequently. It's much more easy to think about possible solutions with fresh memories about the relevant details.

Quote:
I have absolutely no idea how to get these working again

I can't suggest anything without seeing the relevant code that depends on the old implementation.

Quote:
it's even possible to make it work with both 227j and 227i anymore without having to make 2 entirely separate mods.

If a hypothetical 227j_34-compatible solution does not access new properties, then different implementations could be chosen based on either the value of Level.EngineSubVersion or the result of some feature test like (DynamicLoadObject("Engine.Pawn.LastDamageInstigator", class'Object', true) != none). Again, I cannot tell more without seeing your code.

Quote:
Why didn't we just add some code to the Bloblet to tell it not to spawn any blood, period?

Because the current fix is supposed to resolve the issue for all possible pawns (e.g. to prevent nonsense like bleeding automatic cannons). It also restricts damage types that may cause bleeding (pre-227 implementation made by Epic Games defines subsets of damage types that may cause appearance of blood).


I haven't tested j34 either, I am still on j27, I just said j35 since it is the latest version right now.  But that's really besides the point  Tongue

Our code is relatively simple, Bleeder and I made our own Bleeding class, subclassing the normal Bleeding class, and then using a spawn notify to replace Bleeding with RLBleeding basically.  I'm not even sure why this does not still work, since the Bleeding class is still there, and does spawn as far as I know?  And I believe the replacer is working as well, since it compiles, and what happens in RLCoop is that you just don't lose any health at all now when bleeding, though I think the bleeding actor is being spawned.

Actually...now that I write this and think about it, I'm guessing the code in Bleeding itself was changed, and we may have to update our RLBleeding to get that to work so we lose health when in a bleeding state or whatever again.  The whole point of RLBleeding is because we wanted a sort of accumulative bleeding, where the more you get shot, the more and quicker you bleed out, which is how RLBleeding normally works.

Code (C++)
Select All
//=============================================================================
// RLBleedingNotify.
//=============================================================================
class RLBleedingNotify expands SpawnNotify;


simulated event Actor SpawnNotification(Actor A)
{
	local Pawn P;

	if(a.isa('Bleeding'))
	{
		P = Pawn(a.Owner);
		P.BleedingActor = Spawn(class'RLBleeding',a.Owner,,a.Owner.Location);
		if(P.BleedingActor != None)
		{
			A.Destroy();
			P.bIsBleeding=True;
			P.BleedingActor.Instigator=None;
			P.BleedingActor.SetTimer(0.1,false);
		}
	}

	return A;
}
 



Code (C++)
Select All
//=============================================================================
// RLBleeding.
//=============================================================================
class RLBleeding expands Bleeding;

var int BleedTimes;
var Pawn LastInstigator;

replication
{
	//unreliable if(bReplicateInstigator && (Role==ROLE_Authority) && (RemoteRole>=ROLE_SimulatedProxy))
	Reliable if(Role==ROLE_Authority)
		LastInstigator, BleedTimes;
}

function PostBeginPlay()
{
	//First time getting shot.
	Instigator = None;
	BleedTimes = 1;
	Super.PostBeginPlay();
}

function Timer()
{
	local Pawn P;

	//if(RL_Player(Owner)!=None) RL_Player(Owner).RepBleedAmount=BleedAmount;
	if(Pawn(Owner)!=None && !Owner.bDeleteMe)
	{
		P = Pawn(Owner);
		if((BleedAmount <= 0 || P.Health <= 0 ) || !P.bIsBleeding)
		{ BleedTimes = 0; P.bIsBleeding=false; /*RL_Player(Owner).RepBleedAmount=0;*/ Return; }
	}
	Else { Destroy(); Return; }

	if(Role == ROLE_Authority)
	{
		BleedAmount--;
		BleedTimes = Min(BleedTimes, BleedAmount);
		if(P.Health>0)
		{
			if(Level.Game.bBleedingDamageEnabled && P.ReducedDamageType!='All')
			{
				if(P.IsA('ScriptedPawn')) { if(ScriptedPawn(P).ReducedDamagePct<1.0) P.Health--; }
				else P.Health--;
			}
		}
		if(P.Health<=0)
		{
			P.bIsBleeding=False;
			if(LastInstigator!=None) P.Died(LastInstigator, 'bloodloss', Owner.Location);
			else P.Died(P, 'bloodloss', Owner.Location);
		}
		else if(P.bIsBleeding && P.Health<50 && FRand()<0.3)
		{
			if(P.bIsPlayer) P.PlayHit(1, P.Location, 'bloodloss', 0);
			else P.PlayHit(10, P.Location, 'bloodloss', 0);
		}
	}
	if(P != None)
	{
		if(!bGreen) Spawn(Class'RedBloodyDrip',Owner,'',Owner.Location+22*VRand());
		else Spawn(Class'GreenBloodyDrip',Owner,'',Owner.Location+22*VRand());
	}
	SetTimer((Level.TimeDilation + (Rand(3) / Level.TimeDilation))/float(BleedTimes),false);
}

function Tick(float DeltaTime)
{
	local Pawn P;

	//Got shot again? Up the bleeding.
	if(Instigator!=None)
	{
		if(BleedAmount==0) BleedTimes=0;
		else BleedTimes++;
		if (Level.Game.BleedingDamageMax != 0 && Level.Game.BleedingDamageMin != 0)
			BleedAmount += Max(Rand(Level.Game.BleedingDamageMax),Level.Game.BleedingDamageMin);
		else BleedAmount+=Rand(15);
		if(PlayerPawn(Instigator)!=None) LastInstigator = Instigator;
		Instigator = None;
		SetTimer((Level.TimeDilation + (Rand(3) / Level.TimeDilation))/float(BleedTimes),false);
	}

	if (Pawn(Owner) != None && !Owner.bDeleteMe)
		P = Pawn(Owner);
	if (P != None)
	{
		if (P.BleedingActor != Self)
		{
			P.BleedingActor.Destroy();
			P.BleedingActor = Self;
			P.bIsBleeding=True;
		}
		if ( P.Health <= 0 || BleedAmount <= 0 )
			P.bisBleeding = False;
	}
	else Destroy();
}
 





EDIT:



Just did a comparison, and only difference is these lines here:

227j 35:  Spawn(Class'RedBloodyDrip',Owner,'',Owner.Location+22*VRand(),rot(0,0,0));

227j 27:  Spawn(Class'RedBloodyDrip',Owner,'',Owner.Location+22*VRand());

I'm not a great coder or even good XD but as far as I can tell, that's not really gonna make a difference?  (Spoiler alert, Bleeder does most of the coding for RLCoop Tongue )



EDIT 2:



oh, you know what, I just realized...I think...probably...the way our RLBleeding is working, with the spawn notify replacing Bleeding and all, it's looking for owner, thinking the owner is the pawn, since originally the pawn spawned the bleeding, but taking a second look at the new code in j35 again, I realized and see now that it is Blood2 that spawns Bleeding (which makes sense actually, so I get it now, I didn't realize/process that before lol), so RLBleeding's owner is looking at the wrong thing, at Blood2, and not the pawn, which would make sense why it's not working.  I THINK this is what's happening, not 100% but seems to make the most sense, I'll bring this up with Bleeder, since he was looking for how Bleeding spawns now in j35 as well.
« Last Edit: Dec 28th, 2016 at 2:59am by Shivaxi »  

 
Back to top
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 1345
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: bloblets etc
Reply #21 - Dec 28th, 2016 at 1:28pm
Print Post  
The current implementation in 227j creates and initializes the Bleeding actor in a different way than 227i does.

Consider Engine.Pawn.TakeDamage from 227i:

Code
Select All
					if (Spray != none)
						BleedingActor=Spawn(Spray,Self,'',hitlocation,rotator(location-hitlocation));
					if (BleedingActor != none)
					{
						bIsBleeding=True;
						BleedingActor.Instigator=InstigatedBy;
						BleedingActor.SetTimer(0.1,false);
					} 


Your RLBleedingNotify.SpawnNotification creates an instance of RLBleeding, then assigns it to the victim's BleedingActor. Then RLBleedingNotify.SpawnNotification returns the original actor (which is under destruction after the call to Destroy) and the assignment

Code
Select All
BleedingActor=Spawn(Spray,Self,'',hitlocation,rotator(location-hitlocation)); 


immediately overwrites BleedingActor with the reference to that original actor. Then your RLBleeding.Tick notices that the owner's BleedingActor is not self, and assigns self to the owner's BleedingActor (so BleedingActor becomes referring to that newly created instance of RLBleeding actor again).

Now consider UnrealShare.Blood2.PawnBleeding from 227j_34/35:

Code
Select All
			b = Spawn(Instigator.Pawn_BleedingClass, Instigator, '', Location, rotator(Instigator.Location - Instigator.LastDamageHitLocation));

			if (b != none)
			{
				if (Instigator.BleedingActor != none)
					Instigator.BleedingActor.Destroy();
				Instigator.BleedingActor = b;
				Instigator.bIsBleeding = true;
				Instigator.BleedingActor.Instigator = Instigator.LastDamageInstigator;
			} 


Your RLBleedingNotify.SpawnNotification creates an instance of RLBleeding, then assigns it to the victim's BleedingActor. Then RLBleedingNotify.SpawnNotification returns the original actor (which is under destruction after the call to Destroy) and the assignment

Code
Select All
b = Spawn(Instigator.Pawn_BleedingClass, Instigator, '', Location, rotator(Instigator.Location - Instigator.LastDamageHitLocation)); 


makes b refer to that original actor. Despite the fact that the actor referred to by b is under destruction, the comparison b != none still results in true. Then

Code
Select All
				if (Instigator.BleedingActor != none)
					Instigator.BleedingActor.Destroy(); 


destroys the RLBleeding actor which you just created via RLBleedingNotify.SpawnNotification.

If I didn't overlook something, the following solution should work for both 227i and 227j_35 (preserving the original behavior):

In class RLBleedingNotify, define SpawnNotification as

Code
Select All
simulated event Actor SpawnNotification(Actor A)
{
	local Pawn P;
	local RLBleeding BleedingActor;

	if (A.IsA('Bleeding') && RLBleeding(A) == none && Pawn(A.Owner) != none)
	{
		P = Pawn(A.Owner);
		BleedingActor = RLBleeding(P.BleedingActor);
		if (BleedingActor != none)
		{
			A.Destroy();
			P.BleedingActor = none;
			return BleedingActor;
		}
		P.BleedingActor = Spawn(class'RLBleeding', P,, P.Location);
		if (P.BleedingActor != none)
		{
			A.Destroy();
			P.bIsBleeding = true;
			P.BleedingActor.Instigator = none;
			P.BleedingActor.SetTimer(0.1, false);
			return none;
		}
	}

	return A;
} 


(I preserved the simulated keyword, but I have no idea why you used it here).

In function RLBleeding.Tick, replace

Code
Select All
		if (P.BleedingActor != Self)
		{
			P.BleedingActor.Destroy(); 


with

Code
Select All
		if (P.BleedingActor != Self)
		{
			if (P.BleedingActor != none)
				P.BleedingActor.Destroy(); 


Shivaxi wrote on Dec 28th, 2016 at 1:48am:
the way our RLBleeding is working, with the spawn notify replacing Bleeding and all, it's looking for owner, thinking the owner is the pawn, since originally the pawn spawned the bleeding, but taking a second look at the new code in j35 again, I realized and see now that it is Blood2 that spawns Bleeding (which makes sense actually, so I get it now, I didn't realize/process that before lol), so RLBleeding's owner is looking at the wrong thing, at Blood2, and not the pawn, which would make sense why it's not working.

In both 227i and 227j_35, the owner of the created Bleeding actor is the victim pawn.
  
Back to top
 
IP Logged
 
Shivaxi
The One Who Wanted To Have A Special Title In Forum
Betatester
****
Offline


Loving Pie

Posts: 2245
Location: BEHIND U!!!
Joined: Mar 8th, 2006
Gender: Male
Re: bloblets etc
Reply #22 - Dec 28th, 2016 at 4:16pm
Print Post  
Ah okay.  Bleeder suggested changing Owner to Owner.Owner in the spawnnotify, which actually worked, however I think it is now spawning normal Bleeding instead of RLBleeding possibly, since bleeding does not accumulate anymore.

           P = Pawn(a.Owner);
           P.BleedingActor = Spawn(class'RLBleeding',a.Owner,,a.Owner.Location);

we changed to

           P = Pawn(a.Owner.Owner);
           P.BleedingActor = Spawn(class'RLBleeding',a.Owner.Owner,,a.Owner.Owner.Location);

Though based on what you said, I think it makes sense why that would be happening, so I'm gonna give your code a shot and report back to see what happens.

EDIT:

Oh, well, it crashes now XD.  Your code compiled all fine, I replaced it and the changes exactly as you said, and when testing it in game, as soon as I shot myself enough to spawn bleeding, game crashed with this error:

Critical: ULevel::SpawnActor
Critical: (Bleeding)
Critical: UObject:TonguerocessEvent
Critical: (BloodSpray2, PreBeginPlay)
Critical: ULevel::SpawnActor
Critical: (BloodSpray)
Critical: UObject:TonguerocessEvent
Critical: (DispersionAmmo1, HitWall)
Critical: AActor::physProjectile
Critical: AActor::performPhysics
Critical: AActor::Tick
Critical: TickAllActors
Critical: ULevel::Tick
Critical: (NetMode=0)
Critical: TickLevel
Critical: UGameEngine::Tick
Critical: UpdateWorld
Critical: MainLoop

Code (C++)
Select All
//=============================================================================
// RLBleeding.
//=============================================================================
class RLBleeding expands Bleeding;

var int BleedTimes;
var Pawn LastInstigator;

replication
{
	//unreliable if(bReplicateInstigator && (Role==ROLE_Authority) && (RemoteRole>=ROLE_SimulatedProxy))
	Reliable if(Role==ROLE_Authority)
		LastInstigator, BleedTimes;
}

function PostBeginPlay()
{
	//First time getting shot.
	Instigator = None;
	BleedTimes = 1;
	Super.PostBeginPlay();
}

function Timer()
{
	local Pawn P;

	//if(RL_Player(Owner)!=None) RL_Player(Owner).RepBleedAmount=BleedAmount;
	if(Pawn(Owner)!=None && !Owner.bDeleteMe)
	{
		P = Pawn(Owner);
		if((BleedAmount <= 0 || P.Health <= 0 ) || !P.bIsBleeding)
		{ BleedTimes = 0; P.bIsBleeding=false; /*RL_Player(Owner).RepBleedAmount=0;*/ Return; }
	}
	Else { Destroy(); Return; }

	if(Role == ROLE_Authority)
	{
		BleedAmount--;
		BleedTimes = Min(BleedTimes, BleedAmount);
		if(P.Health>0)
		{
			if(Level.Game.bBleedingDamageEnabled && P.ReducedDamageType!='All')
			{
				if(P.IsA('ScriptedPawn')) { if(ScriptedPawn(P).ReducedDamagePct<1.0) P.Health--; }
				else P.Health--;
			}
		}
		if(P.Health<=0)
		{
			P.bIsBleeding=False;
			if(LastInstigator!=None) P.Died(LastInstigator, 'bloodloss', Owner.Location);
			else P.Died(P, 'bloodloss', Owner.Location);
		}
		else if(P.bIsBleeding && P.Health<50 && FRand()<0.3)
		{
			if(P.bIsPlayer) P.PlayHit(1, P.Location, 'bloodloss', 0);
			else P.PlayHit(10, P.Location, 'bloodloss', 0);
		}
	}
	if(P != None)
	{
		if(!bGreen)
			Spawn(Class'RedBloodyDrip',Owner,'',Owner.Location+22*VRand(),rot(0,0,0));
		else
			Spawn(Class'GreenBloodyDrip',Owner,'',Owner.Location+22*VRand(),rot(0,0,0));
	}
	SetTimer((Level.TimeDilation + (Rand(3) / Level.TimeDilation))/float(BleedTimes),false);
}

function Tick(float DeltaTime)
{
	local Pawn P;

	//Got shot again? Up the bleeding.
	if(Instigator!=None)
	{
		if(BleedAmount==0) BleedTimes=0;
		else BleedTimes++;
		if (Level.Game.BleedingDamageMax != 0 && Level.Game.BleedingDamageMin != 0)
			BleedAmount += Max(Rand(Level.Game.BleedingDamageMax),Level.Game.BleedingDamageMin);
		else BleedAmount+=Rand(15);
		if(PlayerPawn(Instigator)!=None) LastInstigator = Instigator;
		Instigator = None;
		SetTimer((Level.TimeDilation + (Rand(3) / Level.TimeDilation))/float(BleedTimes),false);
	}

	if (Pawn(Owner) != None && !Owner.bDeleteMe)
		P = Pawn(Owner);
	if (P != None)
	{
		if (P.BleedingActor != Self)
		{
			if (P.BleedingActor != none)
				P.BleedingActor.Destroy();
			P.BleedingActor = Self;
			P.bIsBleeding=True;
		}
		if ( P.Health <= 0 || BleedAmount <= 0 )
			P.bisBleeding = False;
	}
	else Destroy();
}
 



Code (C++)
Select All
//=============================================================================
// RLBleedingNotify.
//=============================================================================
class RLBleedingNotify expands SpawnNotify;

simulated event Actor SpawnNotification(Actor A)
{
	local Pawn P;
	local RLBleeding BleedingActor;

	if (A.IsA('Bleeding') && RLBleeding(A) == none && Pawn(A.Owner) != none)
	{
		P = Pawn(A.Owner);
		BleedingActor = RLBleeding(P.BleedingActor);
		if (BleedingActor != none)
		{
			A.Destroy();
			P.BleedingActor = none;
			return BleedingActor;
		}
		P.BleedingActor = Spawn(class'RLBleeding', P,, P.Location);
		if (P.BleedingActor != none)
		{
			A.Destroy();
			P.bIsBleeding = true;
			P.BleedingActor.Instigator = none;
			P.BleedingActor.SetTimer(0.1, false);
			return none;
		}
	}

	return A;
}  

« Last Edit: Dec 28th, 2016 at 5:42pm by Shivaxi »  

 
Back to top
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 1345
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: bloblets etc
Reply #23 - Dec 28th, 2016 at 6:09pm
Print Post  
Shivaxi wrote on Dec 28th, 2016 at 4:16pm:
Oh, well, it crashes now XD.

Do you apply something like CheckReplacement to actors of type BloodSpray2?
  
Back to top
 
IP Logged
 
Shivaxi
The One Who Wanted To Have A Special Title In Forum
Betatester
****
Offline


Loving Pie

Posts: 2245
Location: BEHIND U!!!
Joined: Mar 8th, 2006
Gender: Male
Re: bloblets etc
Reply #24 - Dec 28th, 2016 at 8:12pm
Print Post  
Masterkent wrote on Dec 28th, 2016 at 6:09pm:
Shivaxi wrote on Dec 28th, 2016 at 4:16pm:
Oh, well, it crashes now XD.

Do you apply something like CheckReplacement to actors of type BloodSpray2?


All the code is above.  That's all that is happening.  It's the spawn notify that is causing it to crash somehow, since if I revert the code to what I previously had, it's fine and does not crash.
  

 
Back to top
IP Logged
 
Shivaxi
The One Who Wanted To Have A Special Title In Forum
Betatester
****
Offline


Loving Pie

Posts: 2245
Location: BEHIND U!!!
Joined: Mar 8th, 2006
Gender: Male
Re: bloblets etc
Reply #25 - Dec 28th, 2016 at 9:55pm
Print Post  
My best pal Bleeder just checked again and discovered this in Blood2.PawnBleeding():

Code (C++)
Select All
if (b != none)
			{
				if (Instigator.BleedingActor != none)
					Instigator.BleedingActor.Destroy();
				Instigator.BleedingActor = b;
				Instigator.bIsBleeding = true;
				Instigator.BleedingActor.Instigator = Instigator.LastDamageInstigator;
			} 


Doesn't that mean that Bleeding will reset everytime it is triggered? E.g. bleeding is set to 50-100, you get shot once and you start bleeding for 99. You get shot again and suddenly you bleed only 56?
PEACE
*drops mic*
ps bleeder is love, bleeder is life.
pps I'm a shivaxi

EDIT:

Bleeder is remote controlling my computer, he wrote that, not me lol  (we use teamviewer to collab on mods) but I s'pose he has a point and would explain why RLBleeding isn't working properly.
  

 
Back to top
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 1345
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: bloblets etc
Reply #26 - Dec 29th, 2016 at 10:20am
Print Post  
Shivaxi wrote on Dec 28th, 2016 at 8:12pm:
It's the spawn notify that is causing it to crash somehow

Yes, it happens due to a bug in the native SpawnNotify implementation. When there are two or more SpawnNotify actors, the implementation does not check if the current SpawnNotify actor returned none before switching to the next SpawnNotify actor, and then an attempt to use the next SpawnNotify actor for the previously returned none results in crash.

You can try to return the actor under destruction instead (as you did before):

Code
Select All
event Actor SpawnNotification(Actor A)
{
	local Pawn P;
	local RLBleeding BleedingActor;

	if (A.IsA('Bleeding') && RLBleeding(A) == none && Pawn(A.Owner) != none)
	{
		P = Pawn(A.Owner);
		BleedingActor = RLBleeding(P.BleedingActor);
		if (BleedingActor != none)
		{
			A.Destroy();
			P.BleedingActor = none;
			return BleedingActor;
		}
		BleedingActor = Spawn(class'RLBleeding', P,, P.Location);
		if (BleedingActor != none)
		{
			A.Destroy();
			P.bIsBleeding = true;
			BleedingActor.Instigator = none;
			BleedingActor.SetTimer(0.1, false);
			return A;
		}
	}

	return A;
} 


Shivaxi wrote on Dec 28th, 2016 at 9:55pm:
Doesn't that mean that Bleeding will reset everytime it is triggered? E.g. bleeding is set to 50-100, you get shot once and you start bleeding for 99. You get shot again and suddenly you bleed only 56?

That is correct, in case of using UnrealShare.Bleeding, shots may delay postponed bleeding for an indefinite time. You're free to suggest an alternative implementation for the next revision of 227j.

Quote:
but I s'pose he has a point and would explain why RLBleeding isn't working properly.

I explained why it's not working a few messages above. Note that this breaking change is not related to the fix for bloblets. Your code stopped to work after an attempt to fix the broken reference implementation of postponed bleeding. Anyway, I doubt that there is a way to implement a fix without accumulation of BleedAmount such that it wouldn't break your implementation of RLBleeding which does use accumulation of BleedAmount.
  
Back to top
 
IP Logged
 
[]KAOS[]Casey
Developer Team
Betatester
Offline


nedm

Posts: 3214
Joined: Aug 7th, 2011
Gender: Male
Re: bloblets etc
Reply #27 - Dec 29th, 2016 at 7:27pm
Print Post  
Quote:
Note that this breaking change is not related to the fix for bloblets.


Wish I could say I haven't heard anything like this before...
  
Back to top
 
IP Logged
 
Shivaxi
The One Who Wanted To Have A Special Title In Forum
Betatester
****
Offline


Loving Pie

Posts: 2245
Location: BEHIND U!!!
Joined: Mar 8th, 2006
Gender: Male
Re: bloblets etc
Reply #28 - Dec 29th, 2016 at 9:06pm
Print Post  
Masterkent wrote on Dec 29th, 2016 at 10:20am:
Shivaxi wrote on Dec 28th, 2016 at 8:12pm:
It's the spawn notify that is causing it to crash somehow

Yes, it happens due to a bug in the native SpawnNotify implementation. When there are two or more SpawnNotify actors, the implementation does not check if the current SpawnNotify actor returned none before switching to the next SpawnNotify actor, and then an attempt to use the next SpawnNotify actor for the previously returned none results in crash.


That's strange, because I have several other mods that all use/spawn multiple spawn notify issues with no problems or crashing, and all spawn notifies working as intended.  RLCoop used to use 2, and Ballistic Blood alone spawns and uses 3 spawn notify actors.  Maybe I am misunderstanding.

Masterkent wrote on Dec 29th, 2016 at 10:20am:
You can try to return the actor under destruction instead (as you did before):

Code
Select All
event Actor SpawnNotification(Actor A)
{
	local Pawn P;
	local RLBleeding BleedingActor;

	if (A.IsA('Bleeding') && RLBleeding(A) == none && Pawn(A.Owner) != none)
	{
		P = Pawn(A.Owner);
		BleedingActor = RLBleeding(P.BleedingActor);
		if (BleedingActor != none)
		{
			A.Destroy();
			P.BleedingActor = none;
			return BleedingActor;
		}
		BleedingActor = Spawn(class'RLBleeding', P,, P.Location);
		if (BleedingActor != none)
		{
			A.Destroy();
			P.bIsBleeding = true;
			BleedingActor.Instigator = none;
			BleedingActor.SetTimer(0.1, false);
			return A;
		}
	}

	return A;
} 



We ended up rewriting RLBleeding entirely anyway, so that it doesn't use or reference 227 Bleeding at all and we have more control over it, so I guess the issue is resolved now.

Masterkent wrote on Dec 29th, 2016 at 10:20am:
Shivaxi wrote on Dec 28th, 2016 at 9:55pm:
Doesn't that mean that Bleeding will reset everytime it is triggered? E.g. bleeding is set to 50-100, you get shot once and you start bleeding for 99. You get shot again and suddenly you bleed only 56?

That is correct, in case of using UnrealShare.Bleeding, shots may delay postponed bleeding for an indefinite time. You're free to suggest an alternative implementation for the next revision of 227j.


Well Bleeder could probably tell you how to code it, but I can suggest HOW I think it should work.  Instead of getting shot again triggering a new bleed actor and resetting bleed amount, why not wait until current bleed actor to finish bleeding, kill actor, and then it would allow a new one to spawn should pawn get shot again.  I think this was initially how it was supposed to work, no?  Though of course it was bugged, and after a pawn bled once, it could not bleed again.

I mean alternately you can checkout how Bleeder and I's new bleeding system works  Tongue   Though it's a lot of changes, wouldn't want to break any more compatibility with any other mods that rely on the system.  I tested Ballistic Blood in 227j_35 btw and all seems fine fortunately.

Masterkent wrote on Dec 29th, 2016 at 10:20am:
Quote:
but I s'pose he has a point and would explain why RLBleeding isn't working properly.

I explained why it's not working a few messages above. Note that this breaking change is not related to the fix for bloblets. Your code stopped to work after an attempt to fix the broken reference implementation of postponed bleeding. Anyway, I doubt that there is a way to implement a fix without accumulation of BleedAmount such that it wouldn't break your implementation of RLBleeding which does use accumulation of BleedAmount.


I meant why accumulating didn't work, once we had it working with the previous method of owner.owner
  

 
Back to top
IP Logged
 
Masterkent
Developer Team
Offline



Posts: 1345
Location: Russia
Joined: Apr 5th, 2013
Gender: Male
Re: bloblets etc
Reply #29 - Jan 3rd, 2017 at 7:58pm
Print Post  
Shivaxi wrote on Dec 29th, 2016 at 9:06pm:
That's strange, because I have several other mods that all use/spawn multiple spawn notify issues with no problems or crashing, and all spawn notifies working as intended.  RLCoop used to use 2, and Ballistic Blood alone spawns and uses 3 spawn notify actors.  Maybe I am misunderstanding.

Game crashes when SpawnNotification returns none and the SpawnNotify actor for which this SpawnNotification is called is not the last in the chain. As long as your implementation does not imply that this condition may hold, it should work without producing such crashes.

Quote:
Well Bleeder could probably tell you how to code it, but I can suggest HOW I think it should work.  Instead of getting shot again triggering a new bleed actor and resetting bleed amount, why not wait until current bleed actor to finish bleeding, kill actor, and then it would allow a new one to spawn should pawn get shot again.

Then we ignore all hits between the first hit that initiates postponed bleeding and the moment when the Bleeding actor finishes its job. I found this model less intuitively "realistic", although it probably can be implemented so that the implied changes would not break implementations like yours. In my imagination, a more "realistic" behavior could be achieved with updating BleedAmount on subsequent hits as indicated below:

in class Bleeding:

Code
Select All
function Trigger(Actor A, Pawn DamageInstigator)
{
	local Pawn P;
	local int BleedingDamageMin, BleedingDamageMax;

	P = Pawn(Owner);
	if (P == none || P.bDeleteMe || P.Health <= 0)
		return;

	Instigator = DamageInstigator;
	P.bIsBleeding = true;

	if (Level.Game.BleedingDamageMin > 0 && Level.Game.BleedingDamageMax >= Level.Game.BleedingDamageMin)
	{
		BleedingDamageMin = Level.Game.BleedingDamageMin;
		BleedingDamageMax = Level.Game.BleedingDamageMax;
	}
	else
	{
		BleedingDamageMin = 1;
		BleedingDamageMax = 15;
	}
	BleedAmount = Min(
		BleedingDamageMax,
		Max(0, BleedAmount) + BleedingDamageMin + Rand(BleedingDamageMax - BleedingDamageMin + 1));

	if (TimerRate == 0)
		SetTimer(BleedingTimeInterval(), false);
}

function float BleedingTimeInterval()
{
	return 1 + Rand(3);
} 


in class Blood2:
Code
Select All
		if (Level.Game.bBleedingEnabled && !Instigator.bDeleteMe && Instigator.Health >= 0) // Start bleeding
		{
			if (Instigator.Pawn_BleedingClass == none)
				Instigator.Pawn_BleedingClass = class'Bleeding';

			if (Instigator.BleedingActor != none && !Instigator.BleedingActor.bDeleteMe)
				Instigator.BleedingActor.Trigger(self, Instigator.LastDamageInstigator);
			else
			{
				b = Spawn(Instigator.Pawn_BleedingClass, Instigator, '', Location, rotator(Instigator.Location - Instigator.LastDamageHitLocation));

				if (b != none && !b.bDeleteMe)
				{
					b.Trigger(self, Instigator.LastDamageInstigator);
					Instigator.BleedingActor = b;
				}
			}
			PawnBleedingActor = Bleeding(Instigator.BleedingActor);
		} 


I'll describe this in detail later. This change also may break implementations like yours (and, like before, your implementation can be tweaked to be compatible with both 227i and this variant).

Quote:
I think this was initially how it was supposed to work, no?

I dunno.

Quote:
I mean alternately you can checkout how Bleeder and I's new bleeding system works  Tongue

I never needed such a thing (postponed bleeding), so I'd rather prefer to fix the existing implementation in a relatively simple way and forget about it.

Quote:
I tested Ballistic Blood in 227j_35 btw and all seems fine fortunately.

Good to hear that.
  
Back to top
 
IP Logged
 
Page Index Toggle Pages: 1 [2] 3 
Send TopicPrint
Bookmarks: del.icio.us Digg Facebook Google Google+ Linked in reddit StumbleUpon Twitter Yahoo