Spawning Grenade causes ammo count to reset to default values

I just don’t know what to use as the transform I am clueless on that. I don’t want to use a method that I don’t understand. I didn’t think that having to just get rid of a grenade ammo count would be this difficult. I would even try just reattaching the grenade to the socket but for some reason that wouldn’t work. The only reason why I would consider this method of reattaching the grenade to the socket is to avoid spawning the grenade as to avoid the ammo count resetting. Even then for some reason the grenade would not reattach to the socket regardless even though I have the collision and the simulate physics set correctly this is incredibly frustrating.

I am sorry if I seem irate I have been going at this issue for awhile and I am tired.

Thank you for your help so far you are giving me good ideas. I am just trying to grasp them to the best of my abilities.

Could you give an example of what deferred spawning and finish spawning looks like in code?
If possible.

I see the dilemma, you have no location because you don’t specify the location on its SpawnActor. Possibly you spawn it at 0,0,0 then immediately attach it to the Players Grenade socket. Given that, you can continue to do that by using 0,0,0 in the FTransform(FVector(0.f,0.f,0.f)) so the FinishSpawning would look like

MyNewGrenade->SpawnActor(…);
MyNewGrenade->AmmoCount=MyRealAmmoCount;
MyNewGrenade->FinishSpawning(FTransform(FVector(0.f,0.f,0.f)));
… attach MyNewGrenade to grenade socket here …

Normally you would have a location that you are spawning something and specify it on the SpawnActor statement. I didn’t realize that you didn’t but were spawning with a default location and then immediately attaching it.

Here is an example of how I use deferred spawning (I have a macro that does the SpawnActor so SpawnBPDeferred is just a macro that sets the spawn params and launches the spawn). In this I spawn, set lots of parameters and even call a function within the not-yet-spawned Weapon to do some initialization. Then I complete the spawn with FinishSpawning. Until that FinishSpawning statement, the weapon doesn’t exist in the world, but I can manipulate stuff within it.

AUsableItem* AMyCharacter::SpawnWeapon(int32 wi,FVector SpawnAtLoc) {
AUsableItem* TempWeapon = SpawnBPDeferred(GetWorld(), GI->TheLS->WeaponInventory[wi].WeaponObject, SpawnAtLoc, FRotator(0.0f,0.0f,0.0f));
AWeapon* NewWeapon = Cast(TempWeapon);
NewWeapon->WeaponExisted=true; //probably coming out of inventory and was initialized with unique stuff prior to this
NewWeapon->Description=GI->TheLS->WeaponInventory[wi].WeaponDescription;
NewWeapon->Barrel=GI->TheLS->WeaponInventory[wi].Barrel;
NewWeapon->Stock=GI->TheLS->WeaponInventory[wi].Stock;
NewWeapon->Clip=GI->TheLS->WeaponInventory[wi].Clip;
NewWeapon->Scope=GI->TheLS->WeaponInventory[wi].Scope;
NewWeapon->BaseUniqueID=GI->TheLS->WeaponInventory[wi].BaseUniqueID;
NewWeapon->Favorite=GI->TheLS->WeaponInventory[wi].Favorite;
UE_LOG(LogTemp,Warning,TEXT(“LS GetNextWeapon: We selected %s as next weapon with base id as %s”),*NewWeapon->Description,*NewWeapon->BaseUniqueID);
NewWeapon->WeaponDetail=GI->TheLS->WeaponInventory[wi].WeaponDetail;
NewWeapon->AlternateFireDetail=GI->TheLS->WeaponInventory[wi].AlternateFireDetail;
// BARREL
if(NewWeapon->Barrel != nullptr) NewWeapon->PreloadValues1=GI->TheLS->WeaponInventory[wi].AttachmentDetail1;
// STOCK
if(NewWeapon->Stock != nullptr) NewWeapon->PreloadValues2=GI->TheLS->WeaponInventory[wi].AttachmentDetail2;
// CLIP
if(NewWeapon->Clip != nullptr) NewWeapon->PreloadValues3=GI->TheLS->WeaponInventory[wi].AttachmentDetail3;
// SCOPE
if(NewWeapon->Scope) NewWeapon->PreloadValues4=GI->TheLS->WeaponInventory[wi].AttachmentDetail4;
NewWeapon->PreProcessSetup();
//we are using a default transform because this weapon will be placed in the characters hands after this
NewWeapon->FinishSpawning(FTransform(FVector(SpawnAtLoc)));
GI->TheLS->PlayerSettings.BaseUniqueID=NewWeapon->BaseUniqueID;
return TempWeapon;
}

I just realized something that may be confusing. Just ignore the NewWeapon vs TempWeapon. It is just that our Weapons are a separate subclass for inventory, sales and pickup purposes called AUsableItem but then have to be referred to as the subclass AWeapon for access to the real detail weapon parameters. Not important.

1 Like

Could you just get the socket transform instead?

Thank you for being so patient with me.

I don’t recall if you can get that in world space which is what it would require. You also might have a collision problem since collision would still be on at the time of the spawn. You turn it off at the attachment code right now which is important.

So you are saying to manipulate the variables before FinishSpawning()? I looked up to the other post and that is what you mean sorry.

Yes that is the idea. If for example, you have a default ammo count in the blueprint you are spawning but don’t want that value in this instance of the actor, you can change it very reliably at this time. Then your BeginPlay in the actor will start with the altered values. It can be extremely useful anytime you want to fiddle with parameters prior to the BeginPlay running and creates real flexibility in how the spawn object launches.

1 Like

Good to know. So even if I spawn the actor at a different location I can then still attach it to the mesh and modify the variables before the spawning.

Here is what i have so far using your method which works when spawning using the socket. When I switch weapons and the the weapon spawns it still resets the values for some reason…

if (Player->CurrentWeapon->CurrentMagazineAmmo == 0)
{		
UE_LOG(LogTemp, Warning, TEXT("CurrentGrenadeAmmo: %d"), CurrentMagazineAmmo);
FActorSpawnParameters SpawnParams;
SpawnParams.bDeferConstruction = true;
Player->CurrentWeapon->CurrentMagazineAmmo = 0;
CurrentMagazineAmmo = 0;
Player->bIsThrowing = false;
UE_LOG(LogTemp, Warning, TEXT("SpawnwdAndAttachedGrenade"));
Player->CurrentWeapon->GetWeaponMesh()->SetHiddenInGame(true);
}
if (Player->CurrentWeapon->CurrentMagazineAmmo == 2)
{
FActorSpawnParameters SpawnParams;
SpawnParams.bDeferConstruction = true;
Player->CurrentWeapon->GetWeaponMesh()->SetSimulatePhysics(true);
Player->bIsThrowing = false;
UE_LOG(LogTemp, Warning, TEXT("SpawnwdAndAttachedGrenade"));
Player->CurrentWeapon = GetWorld()->SpawnActorDeferred<AGrenade>(Player->ThirdWeaponClass, Player->GetMesh()->GetSocketTransform("GrenadeSocket"));
Player->CurrentWeapon->GetWeaponMesh()->SetSimulatePhysics(false);
CurrentMagazineAmmo = 2;
Player->CurrentWeapon->CurrentMagazineAmmo = 2;
Player->CurrentWeapon->FinishSpawning(Player->GetMesh()->GetSocketTransform("GrenadeSocket"));
UE_LOG(LogTemp, Warning, TEXT("CurrentGrenadeAmmo: %d"), CurrentMagazineAmmo);
Player->CurrentWeapon->AttachToComponent(Player->GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName("GrenadeSocket"));		Player->CurrentWeapon->GetWeaponMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
else if (Player->CurrentWeapon->CurrentMagazineAmmo == 1)
{
			
FActorSpawnParameters SpawnParams;
SpawnParams.bDeferConstruction = true;
Player->bIsThrowing = false;
Player->CurrentWeapon->GetWeaponMesh()->SetSimulatePhysics(true);
UE_LOG(LogTemp, Warning, TEXT("SpawnwdAndAttachedGrenade"));
Player->CurrentWeapon = GetWorld()->SpawnActorDeferred<AGrenade>(Player->ThirdWeaponClass, Player->GetMesh()->GetSocketTransform("GrenadeSocket"));
Player->CurrentWeapon->GetWeaponMesh()->SetSimulatePhysics(false);
CurrentMagazineAmmo = 1;
Player->CurrentWeapon->CurrentMagazineAmmo = 1;		Player->CurrentWeapon->FinishSpawning(Player->GetMesh()->GetSocketTransform("GrenadeSocket"));
UE_LOG(LogTemp, Warning, TEXT("CurrentGrenadeAmmo: %d"), CurrentMagazineAmmo);
Player->CurrentWeapon->AttachToComponent(Player->GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName("GrenadeSocket"));		Player->CurrentWeapon->GetWeaponMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
			}

Won’t be able to look at this tonight, but what class is this code in?

1 Like

The grenade actor class.

It would concern me that this code is wiping out the pointer to itself. I’ve had trouble with garbage collection when losing the last pointer to an actor. Does this code represent what you are doing. It should be the same (minus the bIsThrowing which I don’t understand) but simpler which I find leads to understanding where my issues lie. It still wipes out the pointer in Player to itself, so presumably death or something should occur immediately after.

if(CurrentMagazineAmmo < 1) // No More Grenades, just die?
{
	this->GetWeaponMesh()->SetHiddenInGame(true);
} 
else // More Grenades Available, spawn another in players hand
{
	GetWeaponMesh()->SetSimulatePhysics(true);
	AGrenade* NewGrenade = GetWorld()->SpawnActorDeferred<AGrenade>(
		Player->ThirdWeaponClass, 
		Player->GetMesh()->GetSocketTransform("GrenadeSocket")
		);
	NewGrenade->CurrentMagazineAmmo = --CurrentMagazineAmmo;
	NewGrenade->FinishSpawning(Player->GetMesh()->GetSocketTransform("GrenadeSocket"));
	AttachToComponent(Player->GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName("GrenadeSocket"));
        this->GetWeaponMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
        Player->CurrentWeapon = NewGrenade;
        NewGrenade=nullptr;
}

I doubt this helps but I just don’t know everything that is going on in your classes.

1 Like

I could give it a shot thank you eagletree.

Any form of new ideas for me help I thank you for that.

bIsThrowing is for the anim graph in order to allow the player to initiate the animation to throw.

I tried what you did and still for some reason the weapon swap still causes the ammo count to reset. I came up with an alternative. To just reattach the grenade after it explodes. Because for some reason just spawning the grenade again causes the ammo count to reset no matter what.

WeaponBaseMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
WeaponBaseMesh->SetSimulatePhysics(false);
WeaponBaseMesh->AttachToComponent(Player->GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName("GrenadeSocket"));

I will mention one more thing. If you remove the ammo count completely from the grenade class and put it in possibly the player class, that would be a more traditional approach. In my way of thinking about it, the grenade is nothing but a projectile (even if it is not a projectile class per se), and if you imagine a gun, you would not keep its ammo count in one of its projectiles. You would probably keep it in its weapon class which is going to be persistent.

The grenade is a little different because it doesn’t have a weapon class in between in the way you’ve set it up. But if not, I’d just let the Player Character take on that function. The anim notify can tell it when the grenade is being tossed (though I assume it already knows). And at the same time, I wouldn’t have the grenade spawning its follow-on grenade. This again could be handled by the Player Character class.

I think it is a bit dicey to have short lived actors managing data that is supposed to be persistent. Your player character is one of the classes you have at your disposal that is probably persistent and would work okay.

1 Like