Announcing Section #2 for Survival Game - Weapons & Interaction

Thank you so much ZioYuri78!, very friendly for the help, I’m going to see it. :slight_smile:

tyvm for this series, I had a request if it wouldn’t be much of an inconvenience; is it possible to implement a simple damage type that does something unique like lets say impulse damage or poison.

ty

I might introduce something for DamageTypes by implementing headshot damage as that is very fitting to the theme of zombie hunting too. :slight_smile: Will have to see if I can fit that into one of the sections.

Hey Tom :slight_smile:

I’m catching up on your series. Today I noticed a change in ASBombActor constructor that is:


	SetRemoteRoleForBackwardsCompat(ROLE_SimulatedProxy);

Can you explain what this does and why it’s necessary?
I’m curious because, thanks to it’s name, it seems to be for “Backwards Comparibility”. I don’t really understand the the purpose of it and the documents lack information about it.

Also (which might be helpful), I found this:
AActor::SetRemoteRoleForBackwardsCompat | Unreal Engine Documentation (Little information here)

And:

Which… Seems to be an (updated? fixed?) version of


	SetRemoteRoleForBackwardsCompat(ROLE_SimulatedProxy);
	bReplicates = true;
	bReplicateMovement = true;


Thank you again for your time, support and excellent tutorial! :smiley:

Hi Zoc!

Excellent question! I had a dive into the source and it turns out that SetReplicates sets both bReplicates and the RemoteRole. I noticed some replication issues w/o setting the remote role so I added that function call. I replaced all of that with a single call to SetReplicates(true) now though that will make it into Section 4.

I don’t understand how that remote role works, but since it’s a backwards compatibility function, I guess it’s not worth to look into it, right ? :slight_smile:
Glad I could contribute by noticing this :slight_smile:

Do you mind if I keep asking questions ? There’s some stuff I still don’t understand how it’s linked (and I feel bad overlooking stuff, since it usually leads to taboos and other “it works, don’t touch it” issues).

How is the Respawn handled ?
I don’t know if this was changed in section 3 or 4 (I’m trying to understand how things works in section 2 for now, yet.)

I see a Die() function in the character. (I don’t see a reason for it to return a bool value, but I guess this is something that was planned for some future feature, right?)
It sets the killer, and call OnDeath() function, that:

  1. Apply the last tick of damage
  2. Apply momentum based on last shot (that for some reason I couldn’t figure out yet, makes the character get launched to the air, vertically o.O)
  3. Destroys the items contained in the inventory
  4. Removes control from the player, by un-possessing the pawn ( DetachFromControllerPendingDestroy() )
  5. Stop/Reset animations
  6. Handle collisions (I have a question about this below)
  7. Setup the Ragdoll by a custom function

Okay. This is how the player dies. How does it respawn?
I see a AHavenPlayerController::UnFreeze() function in there, but I don’t see it being called anywhere.
By inspecting PlayerController.h, I see this:


	/** Timer used by RoundEnded and Inactive states to accept player input again */
	virtual void UnFreeze();

I also noticed that it’s an empty function, so there’s no point in calling Super::UnFreeze() here.
I tried to dive a bit into the code, but… I think I got lost :frowning:
I currently have no idea what causes the player to respawn, and I also have no idea what to do if I wanted to modify this behavior, e.g.:

  • Delay the respawn by 5 seconds;
  • Make players respawn in waves;
  • Make a queue so a “new dead player” will only respawn after everyone in queue respawned - an item of this queue would be processed every 10 secs.

One thing that I noticed while I was writing the previous question is that you first disable the capsule collision then later you enable the actor collision inside OnDeath() function. Why this?
Initially I thought it was to avoid players from having fun shooting flying ragdolls, but collisions get re-enabled right after. I don’t get it.

Thank you again for your time and patience answering all these (odd?) doubts! :smiley:

Questions is what this thread is for! :wink:

UnFreeze() is called internally, it’s definitely very obfuscated and something I don’t like. It’s slightly changing in Section 4, so you will get to see an example of a delayed respawn. I believe there are some changes coming to how respawn and all that is handled in the engine itself, so don’t strain yourself too much till it gets a proper cleanup pass :smiley:

As for the collision, I’d have to check, but a quick look at the code tells me I could omit the call to disable collision and only keep the call to ignore all channels. So yes, there is no particular reason to disable it and then re-enable it, while the re-enable has virtually no effect since we ignore ALL collision channels for the capsule, so the call only affects enabling collision on our ragdol. :slight_smile:

Hope that makes sense!

  • Tom

I’ve been reading the UE4 docs about networking and one thing it says is to not use property replication on properties that don’t change very often. It seems to indicate this is the “old” way of doing it, and you should now use RPC’s instead for infrequent changes.

I notice in the ASBombActor you use the bExploded property to inform clients that a bomb has exploded. Shouldn’t this be an RPC instead (that the server calls, but runs on the clients, or perhaps a multicast so a listen server can simulate as well) to trigger the bomb exploding on the clients. This seems to be a good example where an RPC would be better than a replicated property (as the docs point out). What do you think Tom?

Edit: Just started watching the networking video tutorials. Check from the 30 sec mark in this video. He defines when to use variable replication and when to use an RPC… the funny thing is he even uses triggering an explosion as an example of when to use an RPC. :smiley:

That’s a good point. I’ll revisit that in the current section 5 as the docs will be about replication mostly.

Update: I’ve updated SBombActor to use NetMulticast instead of RepNotify and it works great! This approach is definitely easier to grasp when looking at the code, so I think it’s a good change.

That’s great. Look forward to seeing section 5 when I get there.

I have a strictly C++ question, why sometime you use a forward declaration and sometime not?

I will take a snip from SCharacter.h code as an example



void SetCurrentWeapon(class ASWeapon* newWeapon, class ASWeapon* LastWeapon = nullptr);

	void EquipWeapon(ASWeapon* Weapon);

	UFUNCTION(Reliable, Server, WithValidation)
	void ServerEquipWeapon(ASWeapon* Weapon);

	void ServerEquipWeapon_Implementation(ASWeapon* Weapon);

	bool ServerEquipWeapon_Validate(ASWeapon* Weapon);

	/* OnRep functions can use a parameter to hold the previous value of the variable. Very useful when you need to handle UnEquip etc. */
	UFUNCTION()
	void OnRep_CurrentWeapon(ASWeapon* LastWeapon);

	void AddWeapon(class ASWeapon* Weapon);

	void RemoveWeapon(class ASWeapon* Weapon, bool bDestroy);

	UPROPERTY(Transient, ReplicatedUsing = OnRep_CurrentWeapon)
	class ASWeapon* CurrentWeapon;

	class ASWeapon* PreviousWeapon;

	/* The default weapons to spawn with */
	UPROPERTY(EditDefaultsOnly, Category = Inventory)
	TArray<TSubclassOf<class ASWeapon>> DefaultInventoryClasses;



In the example sometime you use void MyFunction(ASWeapon* Weapon) declaration and sometime void MyFunction(class ASWeapon* Weapon) and i don’t understand when is the case to use first example and when the second. Same for some variable declaration.

I now forward declaration is for when the compilers don’t know yet the type of parameters but in this case you don’t have to use “class” everytime you use ASWeapon as a parameter or variable?

That must have slipped in, I think you can remove the ‘class’ prefix in those cases since it can recognize the value w/o. I find the whole structure of forward declaration to be odd and unfortunate.

If it fails to find it, it should fail everytime in that file, so I was being inconsistent.

Thank you Tom :slight_smile:

hi, my English is a little immature. Please understand…
I got questions than read this section sample code.
How to Create ‘STypes.h’ file? (Only Header file & While exist inside include STypes.generate.h)
I look forward to a good answer.
Thank you… :slight_smile:

Hi! That’s an excellent question. Up to this point I have done it in either of two ways (both a little hacky) the first is copy/pasting it from the original project. The other way is simply creating a new file in Explorer, name is STypes.h and start adding your content to the header.

The STypes.generated.h does NOT need to be created by you, that is all handled by Unreal Header Tool.

HI, what do “bChartDistanceFactor and bReceivesDecals” mean in “ASweapon”?:confused:

There isn’t much info on bChartDistanceFactor actually, it’s adding some GPU rendering optimization.

As for bReceivesDecals, turning that off disables decals to appear on the mesh (eg. weapon impact FX) this is turned off for the player mesh too, because it won’t look good on the animated mesh.

Hi Tom … Thanks for your great Series i love this tutorial.

currently I’m on section 2 and i have a question on STypes.h
as you said before in other post , I made this in visual studio not in engine but I don’t know how i can tell the engine and compiler to read this file … when i include this file in SCharacter.h it’s said there is no such file or directory.
I’m using 4.9 and i put this file in both Source and Source/SurvivalGame forlder

thanks

I think i found my mistake.
I created STypes.h by right click on SurvivalGame folder in VS solution explorer and Add Item .
This time i create a .txt file in windows explorer and change name and format to STypes.h and every things is OK and project compiled successful but there is a problem inside STypes.h there is no


 #include "STypes.generated.h"

Why engine didn’t add this line ?

without that line GENERATED_USTRUCT_BODY() not working… and compiler give errors.

and another question is what is difference between these two type of pointer ? both compile fine in STypes.h


TWeakObjectPtr<class ASCharacter> PawnInstigator;
class ASCharacter* PawnInstigator;