#multiplayer
1 messages ยท Page 42 of 1
and I wanted to check how it all looked in ue5-main, got surprised to see a new CVAR that happened to fix the notify issue
a bit unconvenient that it is a CVAR ๐ฆ
but anyways... this is also set in Lyra's engine config
Maybe it was planned? Weird. I'd imagine it should be on by default and should be optional to be off.
yeah
Helloo!
Currently using UE5, just loaded a new third person tenplate, attempted to use split screen using "Create Local Player" this doesn't seem to get any input from my second xbox controller. Both controllers work in the editor allowing me to move around. But it doesn't seem that a player controller for my second controller is being used/detected. Any help will be very appreciated ๐
Mmm any reason a server-executed multicast is only being fired on server (and not clients?)
I can ensure it is being called on the server
Clients aren't relevant
mmm this class is marked as always relevant
or it's a server only class like gamemode
it's basically RPCing some stuff to its client clones
mmm
The class itself is created on the server, but since it is marked as replicated, shouldn't it exist also on clients?
What are we talking about? Gamemode, player state, a custom actor?
A custom actor which acts as a helper so a subsystem can do networking stuff basically
This is part of some "old" code that I ported from 4.27 (a prototype I made) and it used to work there, so my bet is that something in the creation/spawning process is not correct and therefore is not existing on clients or smth
post code if you want more help
yeah I'll do, thanks
Just a quick question, when i am hosting a lan server , it takes like 30 seconds to join as client 2, any way to speed that up ?
oh wow thank you! @thin stratus will this help you too?
Yes, thanks for the ping
@pallid mesa Also I read all your articles yesterday, they are amazing! Thank you for writing them. I have a question about your "A non-destructive and better synced network clock" - have you tested whether the slight difference in synced time between client and server would cause net corrections if gameplay mechanics were dependent on this time? E.g Reducing cooldown timers for GAS abilities by the RTT up to a certain ping?
I have an issue with my vehicle replication, I'm working on a client authoritative mode but for some reason when I'm playing in a listen server it's state doesn't get replicated to clients (client to server and to other clients works)
Probably an oversight in the implementation
UFUNCTION()
void OnRep_ReplicatedState();
UPROPERTY(ReplicatedUsing=OnRep_ReplicatedState)
FReplicatedState ReplicatedState;
UFUNCTION(Server, Unreliable)
void Server_ReplicateState(FReplicatedState NewReplicatedState);
void URacingTankMovementComp::OnRep_ReplicatedState()
{
TankBody->SetWorldLocation(ReplicatedState.Location);
TankBody->SetWorldRotation(ReplicatedState.Rotation);
TankBody->SetPhysicsLinearVelocity(ReplicatedState.LinearVelocity);
TankBody->SetPhysicsAngularVelocityInRadians(ReplicatedState.AngularVelocity);
}
void URacingTankMovementComp::Server_ReplicateState_Implementation(FReplicatedState NewReplicatedState)
{
ReplicatedState = NewReplicatedState;
OnRep_ReplicatedState();
}
OnTick :
if (OwnerTank && OwnerTank->IsLocallyControlled())
{
ReplicatedState.Location = TankBody->GetComponentLocation();
ReplicatedState.Rotation = TankBody->GetComponentRotation();
ReplicatedState.AngularVelocity = TankBody->GetPhysicsAngularVelocityInRadians();
ReplicatedState.LinearVelocity = TankBody->GetPhysicsLinearVelocity();
if (!OwnerTank->HasAuthority())
{
Server_ReplicateState(ReplicatedState);
}
this is what I'm doing
oh and
DOREPLIFETIME_CONDITION(URacingTankMovementComp, ReplicatedState, COND_SkipOwner);
{```
I'm using this
Listen server does have authority
yeah but modifying the ReplicatedState struct should be enough to make it replicate no?
Oh NVM, you are setting it
the Server_ReplicateState just sends it to set it yeah
yeah that's also on purpose
Ok
calling OnRep on server makes it reset the location and velocity every tick
I ma personally against calling OnReps for server as it makes actual replication harder to debug - but yeah presumably you need to apply it
Also, I assume you have disabled replicated movement on the owner?
yup
Realistically, you shouldn't need any of this btw - you can just set the owning actors' replicated movement data (which contains physics state)
Which will also be cheaper - component replication/RPC's have additional overhead
Not usually anything to worry about, but becomes a factor at scale or when properties are updating a lot
but that makes it server authoritative no?
Not necessarily, just ignore the updates on the receiving client
I.e. in OnRep_Movement guard against IsLocallyControlled or auto proxy or w/e
I'm making a racing game and I want to let the player do whatever they want (cheating protection isn't required)
All he's suggesting is to use the already replicating movement
And instead of applying it locally, you filter the call
In fact, Skeletal Meshes even have a flag that does that automatically for the purpose of vehicles
Exactly what it's meant for
Why it lives on USkeletalMeshComponent and not USceneComponent or w/e is anyone's guess though. 10/10 API decisions.
how would I change the behaviour of movement replication though?
overriding OnRep_Movement?
If it's a physics simulating skeletal mesh, you don't even have to do that
Just uncheck "Replicate Physics To Autonomous Proxy" on the mesh
damn
It's a stupid fortnite API thing that ended up in vanilla engine
Because apparently nobody would ever make a physics-simulating static mesh vehicle
Genius
btw I'm in class (granted, it's a Shader Programming class) but teacher was like "you should use a multicast"
:thonk:
no
:D why does that sound like you need that to exist for StaticMeshes for your pet project
bad teacher
I don't luckily ๐
I know I was like no as well but he got on my pc and started doing it
Interesting - do you just do what the OnRep would do, but by hand?
Just such a dumb decision to put it there IMO
this is our best programming teacher btw
If server + client have to execute it, I make another func and have the OnRep call that
quit school tbh
we have a "physics engine" and "network programming" teacher that never opened unreal
I kid
MP is hard, you need actual experience to teach it properly. No offence to the teachers.
he was like "I'm sure Blueprints can be more performant than C++"
no but like
he doesn't know shit it made me depressed
I went through all stages of grief on the first week of class with him
we had like 22hours of class where all he did was talk about politics and open youtube tutorials about how to make a blueprint
๐
what kind of politics
Interesting. Seems a long-winded way of doing:
Speed = 30;
if (GetNetMode() < NM_Client)
{
OnRep_Speed();
}
It's the same at the end of the day, no? Or is there something that happened specifically that caused you to adopt your stance?
french politics
he was like "it's going to get bloody very soon"
(I'm in france btw, despite my strong wish to not be here)
The problem for me is when I put a breakpoint in an OnRep function - I expect that breakpoint to only ever be hit on a client. It makes it harder to debug if the server is calling what is really client code
he told us things would change radically in the next two weeks like a month and a half ago
and now this week he was like "it's gonna happen first weeks of january"
๐
Fair - I guess it depends on how you use OnReps. I design 'em where they're not only meant for client code personally.
motherfucker needs to focus on his work
ikr, he's a politician actually
idk why they brought him here
school gave him like 100 hours of teaching
prolly 5000โฌ
I would bet my ass he didn't teach jack shit to anyone
5000โฌ down the drain
Just tell him to rethink both of his careerpaths
unless it's some kind of money laundering scheme ๐ฌ
Complain, tell the school he has no idea what he's doing.
Just make sure to leave emotion out of it. Just lay out clean clear facts.
my not so well informed opinion is if you actually want to learn something properly and you don't need a degree or some kind of qualification for your career path, best to just find resources yourself than pay for college
@rocky topaz This has some extra "guff" from my implementation but hopefully it demonstrates the approach
Main point of note, is that when an RPC is received it's applied at the beginning of the frame. I had better/smoother results by applying client changes after the current physics tick - hence all the intermediatte data
"I learned more from some guy from the UK on Discord in 5 Minutes than from that guy in a school during the last 2 weeks."
2 months*
Notice my incredible anti-cheat protection:
// TODO: Time / Cheat Verification
True opinion. The issue is that HR in most companies don't care how much you know. They're not wasting their time on your interview without some form of say so that you 'might' know what you're doing. College degrees aren't about learning, they're about getting your foot in the door.
best to just find resources yourself than pay for college
Small note: It's probably best to pay a tutor for that
Solid
EAC got nuttin on dis
It depends on your logic and timing tolerances... ofc the synced clock will give you a closer view in both ends
I learned more from some guy from the UK on Discord in 5 Minute
To be fair - it is James and he is friggin' sweet ๐ .
he's the teacher for a ton of programming classes not just physics and networking
but yeah we did and he's getting fired next trimester afaik
Get a refund.
yeah definitely agreed, but I need a degree and I'm not paying this school
I was in an apprenticeship first year which paid for the school through a gov grant
You only need a degree if you're looking to join an existing company ๐
I have a static mesh and I found it too
ah nvm I misunderstood what you said
yeah as a broke man from a third world country (Africa)
Honestly, I got a Bachelor in Applied Science, Math and IT, and even though I did end up founding my own company, I wouldn't say this was wasted.
I'm on 5.0.3 and I have it too
I'm just trying to justify my life choices ๐ญ
it's hard to start a company
Yeah must have been recent, I recall it only being in skeletal mesh for no reason whatsoever
sad beep
well this is weird
I removed all my replication stuff
and my server's state is still not replicating to the clients
SetReplicateMovement(true);
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
SetRootComponent(Mesh);
Mesh->SetSimulatePhysics(true);
Mesh->bReplicatePhysicsToAutonomousProxy = false;
Ok, so after debugging a bit I am still clueless so, here's my code:
In my subsystem, the helper replicated actor is created:
// MySubsystem.h
UPROPERTY()
AReplicationHelper* MyHelper;
// MySubsystem.cpp
void UMySubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
if (GEngine->GetNetMode(GetWorld()) != NM_Client)
{
MyHelper = GetWorld()->SpawnActor<AReplicationHelper>(AReplicationHelper::StaticClass());
}
}
Then, in AReplicationHelper constructor I set bReplicates and bAlwaysRelevant to true.
The function that is multicasted from the server:
// .h
UFUNCTION(NetMulticast, Unreliable)
void NetCastLocations(const TArray<FUnitLocationNetUpdate>& UnitLocations, int32 ServerStepNumber);
void AReplicationHelper::NetCastLocations_Implementation(const TArray<FUnitLocationNetUpdate>& UnitLocations,
int32 ServerStepNumber)
{
// only server reaches this code
if (GetNetMode() != NM_Client)
{
return;
}
// do my client-side logic
}
@prisma snow I think I know. U ready for dis?
yes
It's unsafe to access ENetMode in A world subsystems initialize
I had to jump through repeated hoops for this
MMM
Wait - it is? I think I might be doing that ๐
Some really obscure UWorld lifetimes in PIE make it a PITA
this is soo weird
So it's possible that both server + client are spawning their own
why would the server's state not replicate to clients
that would make prefect sense
You can get around it, 1 sec
This is how I'm doing my server only subsystem ๐
if (!Super::ShouldCreateSubsystem(Outer))
{
return false;
}
UWorld* World = Cast<UWorld>(Outer);
return World->GetNetMode() < NM_Client;
This is the dumb code I had to use:
{
const UWorld* lWorld = OverrideWorld ? OverrideWorld : GetWorld();
check(lWorld);
OutMode = lWorld->GetNetMode();
#if WITH_EDITOR
// PIE creates some obscure UWorld lifetimes that makes NetMode access more difficult.
// See https://udn.unrealengine.com/s/question/0D54z00007DW1CQCA1/why-are-uworldsubsystems-initialized-before-uworld-is-initialized
if (lWorld->IsPlayInEditor())
{
UEditorEngine* const EditorEngine = CastChecked<UEditorEngine>(GEngine);
const UPackage* Package = Cast<UPackage>(lWorld->GetOuter());
if (!Package || Package->GetPIEInstanceID() == INDEX_NONE)
{
// This is a Transient UPackage used for PIE Client worlds.
OutMode = ENetMode::NM_MAX;
return false;
}
else
{
// We can get the UGameInstance/UNetDriver from here, *before* the UWorld properties are set
const FWorldContext* PIEWC = EditorEngine->GetWorldContextFromPIEInstance(Package->GetPIEInstanceID());
if (ensureAlways(PIEWC))
{
if (!PIEWC->PendingNetGame)
{
OutMode = PIEWC->RunAsDedicated ? ENetMode::NM_DedicatedServer : ENetMode::NM_Standalone;
}
else if (ensureAlways(PIEWC->PendingNetGame->NetDriver))
{
OutMode = PIEWC->PendingNetGame->NetDriver->GetNetMode();
}
}
}
}
#endif
return true;
}```
Also then - I recommend moving the actor spawn to some post-world-initialized function
The problem is that subsystems are initialized before the world is actually initialied, but the order varies between editor vs packaged
{
Super::Initialize(Collection);
const UWorld* lWorld = GetWorld();
check(lWorld && lWorld->IsGameWorld() && lWorld->PersistentLevel != nullptr);
/* Can't actually do proper initialization until much later... */
PostInitWorldDelegateHandle = FCoreUObjectDelegates::PostLoadMapWithWorld.AddUObject(this, &UHT_WorldManager::PostInitWorldInternal);
#if WITH_EDITOR
/* Editor environment is even more fucking annoying */
PostInitWorldPIEDelegateHandle = FEditorDelegates::PostPIEStarted.AddUObject(this, &UHT_WorldManager::PostInitWorldPIEInternal);
#endif
}
void UHT_WorldManager::Deinitialize()
{
ManagerTickFunction.UnRegisterTickFunction();
FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(PostInitWorldDelegateHandle);
#if WITH_EDITOR
FEditorDelegates::PostPIEStarted.Remove(PostInitWorldPIEDelegateHandle);
#endif
Super::Deinitialize();
}
void UHT_WorldManager::PostInitWorldInternal(UWorld* NewWorld)
{
const UWorld* lWorld = GetWorld();
if (lWorld && lWorld == NewWorld && !bHasPostWorldInitialized)
{
bHasPostWorldInitialized = true;
FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(PostInitWorldDelegateHandle);
#if WITH_EDITOR
FEditorDelegates::PostPIEStarted.Remove(PostInitWorldPIEDelegateHandle);
#endif
// Handle Tick Registration now.
if (!ManagerTickFunction.IsTickFunctionRegistered() && ManagerTickFunction.bCanEverTick)
{
ManagerTickFunction.Target = this;
ManagerTickFunction.SetTickFunctionEnable(ManagerTickFunction.bStartWithTickEnabled || ManagerTickFunction.IsTickFunctionEnabled());
ManagerTickFunction.RegisterTickFunction(lWorld->PersistentLevel);
}
OnWorldInitialized();
}
}
#if WITH_EDITOR
void UHT_WorldManager::PostInitWorldPIEInternal(bool bSimulating)
{
PostInitWorldInternal(GetWorld());
}
#endif```
What fun.
Sorry for wall of text
I see, so basically I should use that special function + initialize a bit later
what a mess Epic games xD
@hollow eagle Tagging you about this reply because I am using some code that you suggested ๐ . Figured you might be interested.
I wanted to onbly have certain subsystems initialized on server for e.g.
lemme put my messages back together
So had to do this shiz
{
if (Super::ShouldCreateSubsystem(InOuter))
{
const UWorld* lWorld = Cast<UWorld>(InOuter);
if (lWorld && lWorld->IsGameWorld())
{
#if WITH_EDITOR
// PIE creates temporary worlds for Net Clients which should never initialize subsystems.
if (lWorld->IsPlayInEditor())
{
const UPackage* OuterPackage = CastChecked<UPackage>(lWorld->GetOuter());
if (!OuterPackage || OuterPackage->GetPIEInstanceID() == INDEX_NONE)
{
return false;
}
}
#endif
if (CheckNetMode(lWorld) && CheckLevelName(lWorld))
{
return true;
}
}
}
return false;
}```
lol
so I just set replicates movement and unchecked autonomous proxy replication but it's not working as it was with my implementation
(it wasn't replicating earlier because the blueprint kept replicating movement unchecked ๐คฆ๐ปโโ๏ธ )
the movement isn't going from autonomous proxy to the authority like, I flipped a car in the server and it started moving upside down when I was moving in autonomous proxy
Maybe i should just dump the whole class on git
maybe we should set on fire the person(s) that did this to subsystems
tbh I think this is mostly PIE shennanigans and the hax it creates
The way the world is duplicated by editor GI is wierd
thanks; the blog needs some love... there are loads of info being lost in discord, god bless the chat history... but discord in a way... killed the forums and dev-blogposts
Ah thank you. Are you saying there a way to have a timing tolerance before a net correction? Kind of like the distance tolerance threshold in GetPredictionData_Client()? Or am I way off?
MutableThis->ClientPredictionData->MaxSmoothNetUpdateDist = 92.f;
MutableThis->ClientPredictionData->NoSmoothNetUpdateDist = 140.f;```
/* Editor environment is even more fucking annoying */
๐
So true, we need Chat GPT to index the discord into blog posts lol
Not exactly, it is implementation dependent... but in this case a synced clock can help you with rewindings
So for example... I've shot my weapon at this angle at 10.33
The server will receive this information, and since clocks are synced, it will be able to rewind the victim's capsule to that point in time
meaning that you can trust that your 10.33 are equivalent to the 10.33 in the server
welp I have no clue what's wrong with the default move replication and I don't have time to dive into it I guess I'll just go back to my old issue
when a struct field that's marked as replicated is modified on the server it's replicated to all clients right?
you need to replicate the whole struct
and mark the fileds u don't wish to replicate as NotReplicated
so this is my struct ```h
USTRUCT()
struct FReplicatedState
{
GENERATED_BODY()
UPROPERTY()
FVector Location;
UPROPERTY()
FRotator Rotation;
UPROPERTY()
FVector LinearVelocity;
UPROPERTY()
FVector AngularVelocity;
};
I have this in my header : ```h
UFUNCTION()
void OnRep_ReplicatedState();
UPROPERTY(ReplicatedUsing=OnRep_ReplicatedState)
FReplicatedState ReplicatedState;
UFUNCTION(Server, Unreliable)
void Server_ReplicateState(FReplicatedState NewReplicatedState);
void URacingTankMovementComp::OnRep_ReplicatedState()
{
TankBody->SetWorldLocation(ReplicatedState.Location);
TankBody->SetWorldRotation(ReplicatedState.Rotation);
TankBody->SetPhysicsLinearVelocity(ReplicatedState.LinearVelocity);
TankBody->SetPhysicsAngularVelocityInRadians(ReplicatedState.AngularVelocity);
}
void URacingTankMovementComp::Server_ReplicateState_Implementation(FReplicatedState NewReplicatedState)
{
ReplicatedState = NewReplicatedState;
OnRep_ReplicatedState();
}
void OnTick...
if (OwnerTank && OwnerTank->IsLocallyControlled())
{
ReplicatedState.Location = TankBody->GetComponentLocation();
ReplicatedState.Rotation = TankBody->GetComponentRotation();
ReplicatedState.AngularVelocity = TankBody->GetPhysicsAngularVelocityInRadians();
ReplicatedState.LinearVelocity = TankBody->GetPhysicsLinearVelocity();
if (!OwnerTank->HasAuthority())
{
Server_ReplicateState(ReplicatedState);
}
}```
and this is the body
my issue is that the Server's state isn't being replicated to clients
Ahh yess for server side rewinding. I've implemented that before from stephen's course, it's very handy and syncing time is a great use case for that (and a day night cycle across servers). I was curious more about client side prediction cooldown timers for GAS abilities. The idea Eki was talking about where you minus the RTT from the server's cooldown. Some people said it wouldn't work because you can't get frame perfect time sync between client and server. Where you get a result that's accurate +/- 5 ms, but that difference is the difference of a few frames. And just being off by one frame can cause a net correction. Curious if you have insight on that?
I really don't get it as there should be no reason the ReplicatedState of the pawn of my ListenServer wouldn't get replicated to clients
ur phys state only replicates to sim proxies?
it's getting modified in the server itself so it should call the RepNotify
yup
I'm using DOREPLIFETIME_CONDITION(URacingTankMovementComp, ReplicatedState, COND_SkipOwner);
should it be COND_SimulatedOnly?
other clients aren't the owners of the server's pawn so it shouldn't be skipped with this either
๐ฅน
I honestly haven't tried, but I guess your RTT compute would be more precise with this method therefore you might be able to avoid a rollback
I'm so puzzled
nevermind it works now by some kind of magic
wth
FReplicatedState NewReplicatedState;
NewReplicatedState.Location = TankBody->GetComponentLocation();
NewReplicatedState.Rotation = TankBody->GetComponentRotation();
NewReplicatedState.AngularVelocity = TankBody->GetPhysicsAngularVelocityInRadians();
NewReplicatedState.LinearVelocity = TankBody->GetPhysicsLinearVelocity();
if (!OwnerTank->HasAuthority())
{
Server_ReplicateState(NewReplicatedState);
}
else
{
ReplicatedState = NewReplicatedState;
}```
I changed the tick to this
shouldn't modifying the existing struct in the server trigger a replication too?
so weird
although the initial code was a bit confusing, i like it better now
I was thinking that maybe your onrep wasn't getting called because the values where equivalent due to the predictive setting
but you unpiezed me after saying you were skipping the owner
wait nevermind ReplicatesMovement was set
it might still not be solved
I had commented it in code but I forgot it's set to true by default
nevermind the issue is still here
I sooo don't get it now
what predictive setting?
@chrome bay I need to include UnrealEd in the module dependencies (public or private) to use your wonderful hack right?
oh yeah
well now we can be sure the value differs no?
the only solution I'm thinking of is a multicast gasps
but I really don't want to use a multicast
For some reason adding it to the dependencies breaks my compile xD
Sometimes unreal really does not make sense.
@pallid mesa do you give up?
welp I guess this means yes
wtf
turning the struct into a blueprint type fixed it?
or recompiling yet again
I have no clue
I'm doing many things parallely and trying to assemble a chair x'D not the best time now @rocky topaz
well it got fixed for some reason
Could anyone confirm this?
From reading the docs, ownership of an actor is not really the same as the actor's netrole. If you, the player, controls a pawn, you'll have ownership of the pawn, but the netrole could still be authorative on the server, and proxy for your local client.
If the above is true, would anyone know the reason why calling a client RPC on a pawn controlled by a local player from the server fail? Testing in PIE as a local client, and I get no logs that should appear
Ownership essentially means "who is allowed to call Server RPC's on this actor", and is the "NetOwner"
A client can "own" an actor, but if it's a replicated actor created by the server, they do not have authority over it.
Authority != Ownership
Owner also dictates which connection will receive the client RPC, if any
Possessed pawns are by default also "owned" by the controller, so clients RPC's should arrive and execute
So if you were to place a blueprint actor in the world and within that blueprint actor there's some sort of overlap event. Does that overlap run on server? client? both?
both
Okay so if that overlap needs to affect your character, would it make more sense to add on to the character's capsule overlap event and check for that actor instead?
or I guess that's when it starts to become "it depends" as the answer because other aspects of the game will influence how it should be designed?
Went on a deep dive with the debugger and the reason why I'm not getting my client RPC seems to be due the following inside the NetDriver
const FFieldNetCache* FieldCache = ClassCache->GetFromField(Function);
if (!FieldCache)
{
DEBUG_REMOTEFUNCTION(TEXT("FieldCache empty, not calling %s::%s"), *GetNameSafe(Actor), *GetNameSafe(Function));
return;
}
Field cache is null, anyone know what could possibly be the reason for this?
It may execute on both, but you can still enclose any functionality in a HasAuthority check to ensure that you only do X, Y or Z on the server, call a function in the overlapping character, run an RPC, etc, etc
For trigger boxes, I only spawn them on the server.
Yea I'm already using HasAuthority checks all throughout my project. I'm mostly curious about which overlap event to use. The player controlled character's capsule OnBeginOverlap or the level placed blueprint actor's box collider OnBeginOverlap if the end goal is to change something about the character.
But I'm liking the idea of @quasi tide to only spawn the box collider server side. You can save resources client side but not having anything to check and still have server side checking.
Sounds more like a design question.
I'd have the box collider change it personally. With the character exposing a method that allows something from the outside to change its state.
I'd have the box collider change it personally. With the character exposing a method that allows something from the outside to change its state.
This is the way I'd go about it too IMO
Yea okay, makes sense. I'm at a point in my game where I've learned a lot and made a lot, but now its time to go back and refactor some of my older work to be more optimized.
๐ I do love me a good refactor of "junk I made a year ago" session 
Since the level placed actor doesn't move the OnBeginOverlap event only runs when a character or something else that can move triggers it, whereas the character's capsule is pretty much always overlapping as they move around the level. So yes it makes way more sense to have the gameplay logic to reside on the static level placed actor then have it send an interface message to ANY actor that overlaps it. Then on the character an interface event is implemented with a HasAuthority check then whatever needs to happen can happen.
much appreciated. Indeed that was the problem
If you do the authority check in the character, you have the potential for the event to be fired twice, if you're not only spawning the box collider on the server anyway, this could lead to unintended side effects (client code running before the server, or the other way around), if something needs to happen client side, do it via an RPC as a result of the servers decisions from the server
Don't need the has auth check if you only have the trigger on the server or if you do the has auth check in the tirgger
Yes, exactly, simple change, big side effects, if not thought through
Hey Does Anyone know
How to make in app currency?
If you know can you give me some.links abt tutorials..
int MyMoney = 1000;
For in app purchase
As in, real money?
Yes
That's a topic much larger than the scope of a discord message/basic tutorial 
Who's your payment processor?
Whaaat?
- Make in-game currency, like you would for an RPG or any game that involves money in games.
- Now, make a backend (or use a 3rd party service) that updates the client's account's money after they make a purchase.
- Update on the client their account money
Playstore?
Epic games ?
No i mean the payment processor, like who accepts and processes the credit cards if its real money.
Maybe. Idk - I haven't looked.
Client - Myself?
Ummm
Where are you publishing your game?
I don't think you have partnerships with the major credit card providers so...
Steam, Playstore, Epic Store, etc?
The concept is really just adding an API call to some server that will update your in-game currency.
I would have thought the playstore or whatever mac uses has some sort of api for taking your money.
Isn't that were you just buy the app?
Playstore
PlayStore probably has an in-app purchase API
Yes
You will need to look into it yourself, but that's the place to start
If you just want "Gold" for your game then its like this stuff #multiplayer message
Can you explain more
Epic has a guide on this
Yeah Done a small game with no money making thing
Okay
Now How Should I set up the value of my game currency to the real money?
100% completely up to you
#define REAL_MONEY_TO_GAME_MONEY 50
If I'm having like a dollar equal to a 1 unit of my game currency
How could I go about debugging the correspondence of two actors in a client/server?
I have a situation where the units in my formation are assigned to different spots in the client and the server, and seeing how it is happening would help a lot to figure out (and test) how to fix it
Oh
UE_LOG?
Potentially, I'll need a way to order those units in a deterministic way using an ID or similar that is common to server/client
Okay
Revenge by proxy, huh?! ๐
Then like for playstore
With the UE_LOG I cannot "see" the units names or IDs or whatever on screen. Since I am debugging positions, a visual helper would be more useful in the long run than a console log.
You can see them on screen if you look at the output log! /troll
Just draw a debug dot at the point on the server (assume listen) and the client
hahaha touche. But seriously, I think thr best would be to see it in top of the units
Like $10 = 1 Game currency
I have lots of debug shapes for the boid simulation, it's the text one that seems bugged (doesn't change position with the movement updates unlike the other ones)
They Should Buy X game currency for some amount right?
Then Where Should I set the real amount , for playstore?
DrawDebugText (can't remember the BP counterpart, probably the same) will move with the actor/objects if you have the actor reference set, I use it to debug my games vehicle positions
Just to rewind the convo a little bit, if you were to have something like a damage zone actor which can damage the player when they overlap it. Does that mean I should have two separate actors. One which contains the timelines for visuals and audio and another actor which contains only the box collider for overlap events to drive gameplay logic. The box collider actor would have Net Load On Client set to false?
I've been adding box collider components to level placed blueprint actors, but I guess those are running both client and server side even though I only need to check data during the overlap on the server.
How ?
nice will try that, without the actor reference it was not working. Since the rest of debug shapes do not require an actor, I expected the same here
You can use the same actor, just ensure that only the trigger box itself is created on the server (or do if !HasAuthority ->DestroyComponent)
Now I Have Finished a big game u know , did everything, setted up in game currency
After that what's the next step for in app money
This part with blueprints?
Components don't have Net Load On Client option like entire actors do.
Confused
I suppose somethings could change on EventBeginPlay
It's the same in BP as C++, BP is SwitchHasAuthority and DestroyComponent also exists
Yea I was hoping for some editor level checkbox for the component I want to skip loading on the client
Yes, just destroy the trigger client side on begin play, or only spawn it (Add XXX Component) on the server
Tech Jesus ๐
Even better - you can only add the component if it is client using one of those fancy macros in C++ land.
I want to say it is something like UE_CLIENT but idk. Would have to search. Maybe UE_SERVER or something like that.
Yea I'm going to start migrating the heavy stuff first into c++ soon
Look at the character class on how they are adding the arrow component. Just do that, but with w/e the server/client macro is
Now this is for the players buying - the clients , the customers
Hey Jambax, do you plan to add more snippets to this repo? Maybe it could be nice to pin it ๐
Yeah probably will now I've actually made it :d
Honestly just lack of any kind of familiarity with Git
Gists look quite cool tbh
Easy to copy-pasta straight in. Do they end up in a repro somewhere where you can modify them etc or is it just pastebin but better?
oooh
I prefer the repo tbh ๐ samples can be indexed in a master-readme easier (less hassle)
rather than a list of gists
It's a good initiative ๐ Thanks James
I also believe (maybe incorrect), there isn't a way to see another users gists without the link? A repo is just right there
Oh, it's a separate sub domain 
That's significantly less convenient than just having a "Gists" button like they do for repositories on a user profile
are gist just single-files
or can they be a combo of files?
muuh uh i don't like it :(
That works, but still a minor inconvenience 
hello, i'm having some problems with show a widgets to the player that collides with an object and has a specific role attack to it(multiplayer). The problem is when the player collides with it, the widget get show on the other clients screen that has the role.
Collisions can happen on all clients. If this collider is only checking for players, and you only want your widget to show to the player doing the overlapping, cast "Other Actor" to your character, and then check if it is locally controlled. If true, then show the widget.
thanks was able to get it working (as you said, the event was called for all clients and server)
Having some issues because obviously I'm misunderstanding something, but I made a dedicated server, I have 2 clients and a server, I made an object called a Bookshelf that is just out in the world, and it holds however many books the math calculates out it can, I was generating them on BeginPlay() procedurally and putting them on the shelf. I'm having a hard time understanding where the logic goes now I'm in multiplayer land. I had it all mastered on the client. My current goal is to have the bookshelf contain the same exact books on all clients. I tried to make the CreateBook() a UFUCTION(Server, Reliable) moved function logic to CreateBook_Implementation. Then I set the Book object to replicate. But no one owns the bookshelf its just out in the world so that method doesnt work, because the server version ticking doesnt have an owner? I'm strugglign with this. So I changed it to a UFUCTION(Multicast) just experimenting, and it does now start spawning the books on the client, but of course the order is different, etc because it appears to be taking place on the client, called from the Server ( which as I understand it is exactly what multicast does ) so I feel like I want a UFUCTION(Server) but honestly I have no idea at this point. Willing to show all the code, etc..
You might want to do something like this instead of using an RPC.
void AMyBookShelf::BeginPlay()
{
Super::BeginPlay();
if (HasAuthority())
{
// Generate books here.
}
}
This way, only the server will generate the books
Lastly, just as a note, always try and prefix your RPCs where they should be executed, I.E a Server RPC will be called ServerMySomething, likewise a client RPC will be ClientMySomething and a Multicast would be MulticastMySomething helps with readability
Always appreciated.
๐ Happy to help
One thing I'd like to say, if these books aren't gameplay relevant, I'd personally just have them local to each client, most players won't be too fussed if the top shelf doesn't have a large book 3rd from the right for them but their friend does ๐
If it's a must, but they don't do anything special, you can just drop down the Net Update Frequency to a very small number so they're not hogging your bandwidth
Part of my problem may have been I was trying what you suggest as well, but in the tick -- does the server not Tick objects?
i just moved it to begin play with 1 book to test as you mentioned.
The server will tick objects as long as you've got it enabled on the server
(By default it will tick everywhere anyway so it's not something you manually need to do)
alright alright .. hmm still digging -- was shared a PDF on networking in cpp channel will read and experiment a bit here
You'll get there eventually ๐
My suggestion, if you wanted these books to be "visually" correct on each client, but they serve no purpose other than decoration, you *could* have the server generate an array of books with their indexes matching the shelf, then just send that information over to clients (via an OnRep) to create locally so the books won't need to be replicated at all (which will save more bandwidth over however many shelves you intend on having)
Alright I think I understand the route you're mentioning there... I did that OnRep to sync my healthbars I will give that a try, wasnt sure you could do that with complex types *custom classes
Is it possible to make completely TakeDamage() execute only on the server?
As you can see, the following implementation is not efficient because these two lines are still executed on the clients.
float NewCurrentHealth = CurrentHealth - DamageTaken;
return NewCurrentHealth;
Here is the complete code:
void AMyCharacter::SetCurrentHealth(float HealthValue)
{
if (GetLocalRole() == ROLE_Authority)
{
CurrentHealth = FMath::Clamp(HealthValue, 0.f, MaxHealth);
OnHealthUpdate();
}
}
float AMyCharacter::TakeDamage(float DamageTaken, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float NewCurrentHealth = CurrentHealth - DamageTaken;
SetCurrentHealth(NewCurrentHealth);
return NewCurrentHealth;
}
You can OnRep almost anything you like, what I'd likely do for a solution for racks that have a different number of shelves is something like this.
enum EBookSize;
struct FBookShelf
{
// Indexes for book order (0 is far left of the shelf, etc).
TArray<EBookSize> BooksForThisShelf;
}
// Bookshelf actor class.
// Index corresponds to what shelf books belong on, 0 for bottom, 1 top, etc, etc.
UPROP(ReplicatedUsing = OnRep_Shelves)
TArray<FBookShelf> Shelves;
How're you applying the damage?
// Called when the game starts or when spawned
void AMyProjectile::BeginPlay()
{
Super::BeginPlay();
if (GetLocalRole() == ROLE_Authority)
{
SphereComponent->OnComponentHit.AddDynamic(this, &ThisClass::OnProjectileImpact);
}
}
void AMyProjectile::Destroyed()
{
FVector SpawnLocation = GetActorLocation();
UGameplayStatics::SpawnEmitterAtLocation(
this,
ExplosionEffect,
SpawnLocation,
FRotator::ZeroRotator,
true,
EPSCPoolMethod::AutoRelease);
}
void AMyProjectile::OnProjectileImpact(
UPrimitiveComponent* HitComponent,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
FVector NormalImpulse,
const FHitResult& Hit)
{
if (OtherActor)
{
UGameplayStatics::ApplyPointDamage(
OtherActor,
Damage,
NormalImpulse,
Hit,
GetInstigator()->Controller,
this,
DamageType);
}
Destroy();
}
Huh, so ApplyDamage is calling TakeDamage client side too?
I was over complicating the living shit out of it.... smh.... bReplicates on the Actor ( my book and my bookshelf ) then like you said in the BeginPlay, make the books if there is authoirty ( ie: on the server )
done deal, works. thanks lol
Really appreciate the help @weak linden
Nicely done! ๐ You're welcome
Oh my ghost. TakeDamage() is executed only on the server. @weak linden ๐
does fps affect server cost?
I don't think so. FPS is related on clients that simulate the shared world.
If you mean client side FPS, then no, server and client framerate are independent
That being said, the server does also have a framerate, so if you have a weaker performing machine, you will have a lower server-side framerate (which would mean you'd need a more expensive one)
When I possess something new(a drone), the character(soldier) left behind is always "owned" by the server, and when I shoot it with the server it's like I shoot myself. How would I fix this?
You might be able to set the instigator to null on the old character when you de-possess it
I'm in APlayerState and I wanted to let know my UI that something has changed.
Is it okay to broadcast a delegate from OnRep_SomeProperty() so my UI can update whenever playerstate changes or are there some better alternatives?
That's perfectly fine to do, just be sure to check !UE_SERVER to ensure it happens only on the client
void APlayerState::OnRep_SomeProperty()
{
#if !UE_SERVER
// Do your UI update here.
#endif
}
Keep in mind OnRep doesn't call on servers anyway if done via c++
If you don't explicitly call it at least
With that in mind actually, I've always called my OnReps explicitly after changing the value, is that not needed?
On server, it is.
I just do a HasAuth check here and then do it. Server spawns everything, so server will always have auth
I thought so, so it's still a good idea to guard it then?
๐
I also pretty much only work with listen servers.
I always second guess things now, I've learnt a ton of stuff in the last week, stuff I thought was correct for the last 5 years ๐คฃ
Hi Chat
ACoolActor::SetTheProperty(bool NewProperty)
{
TheProperty = NewProperty;
if (HasAuthority())
{
OnRep_TheProperty();
}
}
ACoolActor::OnRep_TheProperty()
{
UpdateUiDelegate.Broadcast();
}
๐ This is my general flow.
I pretty much always update my UI with a delegate. So, the listen server will update the UI correctly as well as clients. Won't matter on dedicated server, just nothing will be subscribed to the delegate.
Any way around UI not updating immediately because OnRep_ / replication drags behind for whatever reason?
iirc replication isn't guaranteed to be up to date at any given time.
You locally predict and then do more custom logic inside of the onrep on if you accept the servers value or not
Most people are okay and understand why UI could take a second to update if they are lagging
Now that you mentioned lagging I wonder how often do replicated variables skip a value or lag behind considering stable internet connection and decent ping ๐ค
hello im hans from Indonesia.
i want to ask about replication pawn between client and server.
when i set actor location on pawn actor in client instance, the pawn actor on the server instance doesnt move. But when the client call custom event RPC run on server and set actor location the pawn actor move on the both instance (client instance and server instance) but in client instance the pawn move is not smooth.
how to achieve smoothness set actor location between client and server ?
i already try to set actor location first on client instance and every tick i call rpc (on server) to send the actor pawn location. but it still caused rollback movement because the server has a delay latency to client so the location that client send was "the past" pawn location on the server
@green fjord are you making your own movement system by setting the actor location every frame?
yes that is correct
im working on multiplayer VR, because my VR character is made from pawn
As far as I know... That is going to be a big challenge. Smooth replicated movement requires a lot of calculation, prediction, and algorithms. Are you unable to make your players a character? I don't really know how vr programming works
yes I have considered that. I thought there might be an easier way than resetting the pawn actor to the character actor. but thank you very much for your answer, I will try to change the pawn actor to a character actor
there really shouldn't be any issue converting a pawn to a character, if you need any help please ask. Also I do want to make it clear that I'm no expert on movement, someone may possibly come along soon and tell you something different. But when you look at Character movement component's code... It's complicated, and it's big, and there's a reason for that lol
Which part in UE source code makes AActor::TakeDamage() execute only on servers?
float AActor::TakeDamage(/**/)
{
float ActualDamage = DamageAmount;
UDamageType const *const DamageTypeCDO = DamageEvent.DamageTypeClass ? DamageEvent.DamageTypeClass->GetDefaultObject<UDamageType>() : GetDefault<UDamageType>();
if (DamageEvent.IsOfType(FPointDamageEvent::ClassID))
{
FPointDamageEvent *const PointDamageEvent = (FPointDamageEvent *)&DamageEvent;
ActualDamage = InternalTakePointDamage(/**/);
if (ActualDamage != 0.f)
{
ReceivePointDamage(/**/);
OnTakePointDamage.Broadcast(/**/);
UPrimitiveComponent *const PrimComp = PointDamageEvent->HitInfo.Component.Get();
if (PrimComp)
PrimComp->ReceiveComponentDamage(/**/);
}
}
else if (DamageEvent.IsOfType(FRadialDamageEvent::ClassID))
{
//...
}
if (ActualDamage != 0.f)
{
//...
}
return ActualDamage;
}
Nothing, you can run it client side if you want (but not from Blueprint)
The engine just expects you to call the "take damage" functions from the Server only, but it doesn't enforce it.
Apart from in Blueprint, where all the damage functions are tagged as "BlueprintAuthorityOnly" so won't run on network clients
But if you're making MP games in Blueprint you've already lost tbh
Should Super::XYZ() be invoked when overriding?
Super::Tick(DeltaTime);YesSuper::BeginPlay();YesSuper::TakeDamage(/**/);????
Typically, yes, unless you explicitly know why you don't want to call it
in blueprint character how to check if this character is my character or other player's character that replicated on my instance?
what are the best practices to make your game communicate with a backend? Would something like regular HTTP requests to an ASPNET Core endpoint be ok or you need more specific workflows? I'm talking mostly about data retrieval if you are building a multiplayer game
Just be careful. People will reverse engineer your api and try to cheat.
Unless your http communication only happens from dedicated servers which are not available to the public.
Unless you don't strip out the requests / code properly lol.
Although really depends on how big your game is, small games tend to not have those issues. Except just random bots that crawl through the entire internet.
ok thanks, for sure I will have to research on this topic
Is this the MMORPG version of how to deal with locally controlled characters? ๐
Yes, made in BP-only
Oof.
It has a wizard button, right?
haha, that's my fav gif of all times
Hi everyone, I have an actor component on my character pawn. Is there a way to know if it is local ?
My goal is that the actor component should act a certain way only for it's owner. I have tried "Is Actor Local" but it doesn't work on the owner (always return false)
Never seen "Is Actor Local". I've seen this instead: #multiplayer message
Well I'm in blueprint so I'm kinda fucked :p. But I think the issue I have is to access my pawn from the actor component so I would be able to know if I'm local. I wasn't able to use IsLocallyControlled since I need to access the control which I don't have access to (I think)
That has nothing to with BP though. It's literally GetOwner -> Cast to Pawn -> Check if IslocallyContrrolled
ok let me check
Though that might fail due to the pawn not being possessed yet by a PlayerController
Depends on what point in time you check that
in the begin play of the actor component
Yes that smells bad
BeginPlay for pawn or its comp fires before a pawn is possessed usually
so if I just create an event that I call from the pawn it might be best
from the pawn I can verify if my local
The component is added before runtime, right?
I'm not sure
Is it a replicated component that is spawned during runtime?
Or was it added through the simple construction script before runtime?
it is a replicated component that is added by default in the character blueprint
So yeah it was added before
ok
Then it should be there if you fire client RPC called from event Possessed that accesses it
Or you could have a replicated property that tells that your character is possessed and your component just listens to it
Is WizardCell back? ๐ค
I don't like both approaches but that's how it is in BP
Or is this just in passing?
I will try this ๐
In cpp it's much more neat
yeah I bet, since it's for a prototype we will try that dirty way ๐
It's me trying to cope with the easy problems, so I forget the harsh problems I've been going through recently ๐
you are a smurf !
Guys How I can change normal thirdperson character for plane in game? in MP bcs when I used pawn I didnt see other players seems like pawn is not replicated
when I use normal Character I see others but I need play as (human) I wanna replace it with plane
Question is just if I should make plane from Character or try to replicate pawn which totally good fit for plane
bcs now when I join session with 2 pawn I dont see each other ๐
was fiddling around with the packetlag command and set it to 200. Does this represent a ping of 200?
Probably a ping of 400. Since ping is round time, not a to b.
making a plane from a character feels so cursed, but it could work
it depends on your requirements
yes I know its curse but I have problem my already finished pawn(my plane) is not replicating on session when I join session I dont see each other but when I test from editor and run 2 instances of clients and listen server is behind I See each other
I dont understand
cause pawns, unlike characters, dont bundle with a replicated movement component
you have to make your own
they are in but they are not visible for each other
but when I try run as Net Mode: Play as Client and I run 2 instances
they are visible
why I see them then on PLay as client
? its also server @pallid mesa
hi all, when my listen server host possesses a pawn the controller inherits the pawns rotation. when a client possesses a pawn the pawn inherits the control rotation. what might cause this difference?
I see the controller gets set to pawn rotation in OnPossess, but that might be server side only?
in general when server sets client controller rotation does that trickle down to client machines, or does that get overrwrote on server side next update from client?
setting control rotation to match pawn rotation on clients acknowledgepossession function seems to help
I find it more useful to use the editor network emulation to setup the values
Isn't that the same?
Yeah but I found it quicker to iterate and also more detailed. You can setup differebt settings for client and server for example. I am sure the command does the same, but maybe it is less intuitive
I see
Just never leave the "bad" profile. Boom problem solved. Design your game around 200 ping and surely 30 ping will be fine, right?
I actually do that, also test with like 700 ping
Nah - 700 ping is in the realm of the player's problem, not mine ๐
I know but sometimes it helps to detect hard to catch problems
Hi I am having problems with my code I think
i am trying to add an impulse to my pawn's mesh but for some reason i cant make the server read the clients rotation
void UAction_CanicaLaunch::StopAction_Implementation(AActor* Instigator)
{
Super::StopAction_Implementation(Instigator);
ASCanicaPawn* Pawn = Cast<ASCanicaPawn>(Instigator);
if (Pawn)
{
GetWorld()->GetTimerManager().ClearAllTimersForObject(this);
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, "Stoping Impulse");
bIsPressed = false;
if (!bIsPressed && Pawn->HasAuthority())
{
FVector RotationVector = Pawn->GetControlRotation().Vector();
DrawDebugLine(GetWorld(), Pawn->GetActorLocation(), RotationVector*5000.f, FColor::Red, true);
}
Impulse = 0.f;
GetOwningComponent()->OnActionStopped.Broadcast(GetOwningComponent(), this, Impulse);
}
}
anyone knows why is this happening?
that action is called once by the client and once by the server but only the server can add the impulse (i havent add the code for impulse yet)
Have you tried using GetBaseAimRotation() instead of GetControlRotation()? If I remember correctly, GetControlRotation() is ZeroRotator on the server
Im using UE 5 with Data layers, I cannot figure out how to implement a loading screen and determining when a data layer is loaded. Im trying to add a dungeon to my game where an individual player loads the dungeon data layer while another player is roaming around the over world. I cant figure out from the docs a good solution, does anyone know of some good multiplayer data layer resources?
Hey Me Again
When I press a button ,($10) I want to make a in app purchase
How to do that
And the product is just some integer var
On button press, send an RPC with the player controller to the server. Validate that the player has enough money, the product is available etc, then do the corresponding changes in the state (whatever they are) and replicate the state back to the player if necessary
@sonic python
Oh not that
I want to know abt that Make In App Purchase, Read , Restore...
When I press the button
Purchase what
The Game Currency
He wants to add a button to spend real world money to buy ingame currency for his mobile game.
Yep Correct
Oh Sorry Didn't See Multiplayer
Do you know where should I ask?
Epic - online - services?
That's not related.
Online subsystem?
Ohkay
tried that now bust still is not getting the correct rotation
Have you tried debugging the values of the rotators?
What are the results?
On the client is always X: -1, Y: 0.0, Z: 0.0
for the server
That's not good, it seems like there is a problem with the rotation update code
On the server do you have the same result?
no, in the server it changes normally
If you use the GetControlRotation() method do you have that value on client? Or the right one?
im gettin that one too
but i have an error when i compile
ObjectProperty FActionRepData::Instigator is not initialized properly. Module:Videojuego_Canicas File:Public/SAction.h
Display LogClass BoolProperty FActionRepData::bIsRunning is not initialized properly. Module:Videojuego_Canicas File:Public/SAction.h
Display LogClass 2 Uninitialized script struct members found including 1 object properties
Warning LogAutomationTest ObjectProperty FActionRepData::Instigator is not initialized properly. Module:Videojuego_Canicas File:Public/SAction.h
maybe that is what causing it?
You have to check that SAction.h at the specified row
Have you initialized bIsRunning correctly inside FActionRepData?
And Instigator too
USTRUCT()
struct FActionRepData
{
GENERATED_BODY()
public:
UPROPERTY()
AActor* Instigator;
UPROPERTY()
bool bIsRunning;
};
thats how i wrote the struct
Make a default constructor
FActionRepData()
{
bIsRunning = false;
Instigator = nullptr;
}
Under bIsRunning;
And try to compile
ok i got rid of the error, thank you
also i have this one
Failed to load '/Game/RollingCPP/RollingOverview': Can't find file.
not sure what that is
but the rotation is not updating correctly yet
I don't know what RollingOverview is, but something is trying to load it from the Content folder
What is the Rotation value with GetControlRotation()? Do you have that -1, 0, 0 vector again or the correct vector pointing in the right direction?
if GetControlRotation() is working on the client, you have something not working with GetPlayerViewPoint(), which is the function used by GetBaseAimRotation() to get the player's eyes view point
At the end it should use GetControlRotation() anyway on the local client, because it's calling GetViewRotation() on the pawn, which returns GetControlRotation() if the Controller is not null
that one is with GetControlRotation()
the blue one is de client and the green one the server
bool USActionComponent::StopActionByName(AActor* Instigator, FName ActionName)
{
for (USAction* OtherAction : Actions)
{
if (OtherAction && OtherAction->ActionName == ActionName)
{
if (OtherAction->IsRunning())
{
if (!GetOwner()->HasAuthority())
{
ServerStopAction(Instigator, ActionName);
}
OtherAction->StopAction(Instigator);
return true;
}
}
}
void USActionComponent::ServerStopAction_Implementation(AActor* Instigator, FName ActionName)
{
StopActionByName(Instigator, ActionName);
}
that is how i wrote the code in the action component calling the action
and that is why is been call 2 time in the picture
it seems the server is not updating the rotation
but when the server is calling the action
Probably a dumb question but i cant seem to find a google response, How would i use Get Ping In MS from the server ? I know its from the Session Class but im not sure how i access the server's session. ?
So i have it atm the player clicks Host Session and Goes tto the lobby area and I want to show the servers ping in a scroll list Player A : 12ms, Player B 35ms, Player C 100ms etc. (Player A would be the server itself in this instance)
I know you can access the Ping via the player state iirc
Get Player State - > Get Session -> Get Ping In MS? something like this.
Not sure how it is calculated exactly, it is not a trivial calculation
I have the code somewhere, wait a sec
Thank you
It's PlayerState->GetExactPing()
Ahh thanks !
Hmm, I don't know, it's not clear what it's happening
What's that Server: 0.0 print string?
ah thats the impulse i am adding. it has nothing to do with the rotation
@dry orchid ok, in the last screen the green and blue values seem correct (except for the first blue one, but I don't know where it comes from), so what is not working?
Yo guys,
Just wanted to know I just released a nice resource for the BP multiplayer community, where BP projects can replicate UObjects without having to use c++. I don't know if I'm allowed to send marketplace links here ๐
oh yes ๐ I'll let people go there instead.
Posted there now, if people wanna check it out ^^
the first one is coming from a OnRep that is been called wuehn the server runs the action
in the last pic is the server, the server is working well
thos one is the client. when the client runs te action it has the correct rotation but when the server calls the action trough the RPC
the rotation goes to 1 , 0, 0'
dont know why
is OtherAction->StopAction() calling this?
yes
yes it s
Maybe there is something else that sets a bad rotation in your code, anyway I don't know what to think, if the server is getting the right rotation, it should work, and if you have the right rotation on the client too, why when you call an RPC should the rotation be different?
You need to debug the code and see where the things are breaking, maybe you can even debug the engine code and see what's wrong there
I mean, the engine code usually works, but maybe you are passing bad things somewhere, and it's returning something wrong in those functions
Ok so for vehicles
Is it better for them to simulate physics and replicate
Or better to have a custom component and fake it
Dependsโข๏ธ
If you're game is meant to be a physics playground then use physics. That's what I'm doing.
If it's meant to be vehicles GTA style then fake it
Hmm
This is what I got going on if you want to take a look. It works in multiplayer but I'm NOT doing prediction as that'd be an entire can of worms. So there's ping delay between inputs and the vehicle doing the thing.
because it doesn't have prediction
So I don't need to do prediction on player-designed vehicles which would be an absolute career in and of itself.
prediction is bad enough when you know the limits of what the pawn can do
when it's people building big kerbal twisted metal style contraptions it'd be a nightmare
I find it really hard outside of very specific contexts. FPS predicition is quite figured out and Rollback as well for fight games, but for other simulations I find it really complex
Yeah now imagine prediction a garrysmod style contraption
no thanks lol
and even with great prediction you always have trouble when it comes to pawn to pawn collisions
I'd rather just have the delay and be done with it. It's not a racing game, it's not like tanks and artillery really need to respond THAT quickly
yeah, anything that resembles physics is a nightmare
Rocket league seems to do it well
They're also big ๐ง
Even without prediction physics replication is a nightmare
Rocket league spent probably thousands of engineer hours on it and their vehicles are very predictable and are basically spheres in a vacuum
Right
What I'm trying to make is closer to Kerbal Space Program with engines and tires and it's already a nightmare since everything is so nonlinear.
Ye. Also Frost Giant is doing prediction (via rollback) for Stormgate, but good luck assembling a team that can do lockstep, let alone lockstep and rollback in a RTS context
Guessing GTA5 is similar?
There's a reason why we had great flight and space sims decades before realistic driving physics. Tires are hard man.
Do players feel the difference when playing a modern vs older driving game (in terms of more complex physic simulations)? I almost never played driving games and never in multiplayer
What information should be on player pawn vs. player state vs. game state?
I'm making a single player game, but trying to get used to doing things the "right way" for when I do a multiplayer game in the future that will require network replication
Reading the docs, and network compendium, but it's still not clear to me
My instinct is that everything player related should go on the player state
Awesome thanks!
Is there a known bug in 5.1 that shows black screens for clients?
not specifically that I know of. I use 5.1 and my clients connect. You'll need to check your logs etc.
Key word is player related, not their pawn related
Score is on player state. HP is on pawn
Can you create multicast methods in UAnimNotifyState?
yes, but I hear it's terrible. It's supposedly very capable of crashing servers
I've used it once for a small multiplayer game I made and it worked fine. However the quality was terrible, like even worse then Apex legends
and apex legends voice chat quality is straight booty
Disgusting
you can but those won't be replicated, so multicasts won't work
Is it possible/advisable to build a net system such that bandwidth is "manually" limited?
Let me explain the context. After some tests in real conditions, I am quite sure that our current replication system for RTS is viable with relatively big unit counts. However, it is not very efficient or smart, in the sense that it basically updates all units equally no matter the context. After some research, I came again into Glenn Fidler's articles about networked physics, and the "state synchronization" approach that he describes fits our usecase really well. He describes the idea of a "priority accumulator" (an array of items with a dynamic priority, which gets sorted each time that we are doing an update).
The basic idea is that you define a max size for the update, and pick items from the array starting with the highest priority, until all items are picked or the max size is reached. In this way, important items get updated more frequently, but never exceeding a certain packet size
Since internet connections are quite variable, and I am not sure that it is easy to automatically detect the connection strength as to define a different max limit for each player, I was considering putting a setting that each player can pick or similar. But still, I am not sure that is a good approach
that can come around to bite you
without a panic mechanism
and it is more or less what unreal does for replicating actors already
what are you units in gameplay framework terms, and how much data is there per unit?
Units are MassEntities, basically. There are Pawns on top of them which have some AI logic and combat stuff (GAS), but all the movement is handled manually in Mass and the position replication (which is the one I mention) too
how many players?
Each unit has a 16bit ID (same for server and clients), and positions are compressed to 16bit for X and 16bit for Y
For player count, ideally up to 8, but to be honest reaching 4 would be already enough.
And unit count, max 2k, although usually it's going to be between 100-500
Yes, ofc
with c++ and simplified movement components, i'd go for dedicated actor for replicating units per connection, relevant only for that connection
Yes, no cmc
That is not viable, I tried it at the beggining but 2k open actor connections was horrible
I need to replicate through a helper actor, that is totally necessary
in it, i'd put a fastarray for each interface a unit might need to replicate stuff from, plus one for the basics, (ID, position)
every fast array item would have either an ID or a weakpointer to the unit pawn if you can make those net addressable
and i'd turn off unit replication off completely
yeha that's already done
yeah, I also do that (manually) via a id generator, that the server uses when spawning entities
currently, each unit gets updated once per second, so thats 16+16+16 * 2000 = 96kbit/s
how are you replicating the data?
dunno how crazy it is honestly, a 2 player test we made with 1k units ran well
right now, sending an unreliable RPC every 100ms, with 1/10th of the unit count (so 200 unit array 10 times)
try a fast array, i don't think it will have a problem handling that
But from testing, there are times where the update is just not necessary, and others where more frequent updates would be benefitial
that's why some variable approach sounded appealing
fast array will only send over items you have marked dirty on server each update
yeah that sounds useful. Also will solve the issue of rpcs, which sadly are kot stateful so
I'll give it a try and make some tests
also I'm making some tests to see if sending full position is worse than sending deltas
i don't think there will be any difference there
that means that I could mark items as dirty on a timer and trigger the replication manually even, if I don't want to replicate asap. Can you throttle bandwith/replication for a single actor/property?
my network managers are handling literally thousands of actors, and never had a single hitch
same but going to try
that's nice to know!!
basically
how many thousands, and how many players?
8 players, can have 6-7k actors if someone dropped a nuke
and never had a problem with hotjoining after either
do you have dedicated servers?
note that my actors don't need such frequent updates
no
but basically, whenever something above some significance threashold happens
Yeah I understand, but I also think that we don't need, just in some specific scenarios (big battles in concrete spots)
you update its item in the array and mark it dirty
there is also oodle built into UE5
that should help too
ye I was planning to make some system to detect "hot areas" (basically spots where combat is likely to happen) and focus updates on that
yeah I want to use it, but wanna see if what we are making is viable before extra compression
I also was considering writing a serialization system for those 16ints bcs many times I can get away with less
and nothing else interfered with the unit
its movement is quite predictable
and would not need to be updated
what I realized in our context, is that even if units collide between them (with no combat involved) the only difference is that they arrive to location slighlty later. Not even noticeable unless playing with 2 screens and slow mo
So positions only get out of sync when cluster collision scenarios happen and even then it is not important unless we are fighting
There's a detail about the FFastArraySerializer that I don't find clarified, when they say it does "delta" updates, do they mean:
- Only the dirty structs are replicated, not the whole array
- Only the changed properties from the dirty structs are replicated
- Only the change/diff between the changed properties of the dirty structs are replicated.
So if I have a struct with int A = 10 and int B = 5, there is a change and now B is 6.
What will he actually be sent across the net, the two values, only value B, or the old B value minus the new one (in this case, a single 1)
I can at least say that the third option is not correct
That wouldn't make sense for other properties :P
Yeah, I was quite sure of it but one can dream
I think it sends the element itself. But not sure if that gets cut down even smaller by only sending the inner property that changed
I'm gonna make some tests so I'll test that as well
you can manually implement delta serialization on fast array item
yeah, I'll do if there is a real benefit. Deltas have the added complexity of ensuring that the past state to compare with is valid
@winged badger Just caught up - are you saying you are replicating like 1K+ actors that are moving around and what not through your network manager?
Yeah, I could make 1k without many issues, and without compression
I'd imagine yours comes from a more simplified movement component though, no?
(I'm always lookin' for ways for maximum zombies ๐)
Even if I don't actually need it
(I already knew about network managers, as an FYI)
Just getting them to work with movement, hadn't tried ๐ข
A MassEntity-based movement simulation. It is all 2D, uses boid rules to get complex behaviour, and also handles collisions
with EOS plugin is it possbile to create a chat system
CMC is very heavy
maybe the floating pawn component is more performant for zombi hordes
Ahh - nah, CMC is fine for me honestly. I only plan on having like, max, 40-ish for this zombie game I'm doing. But I always enjoy pushing things ๐
I already know that I'd want to do an entirely custom movement component if I wanted to go much higher.
ohhhh then CMC is perfect
I think CMC fell appart in mp when we had something like 100 units
but that was default settings
Yeah - I'm doing more Resident Evil scale ๐
maybe with a much lower update rate and appropiate settings it can do more
also if it is a 1st/3rd person game, only the zombies that are close are reslly relevant so you can optimize around that
Yup
Should PlayerState be a glorified bag of properties that are public read/write accessible and let the GameMode handle validation, or should it validate its own data with custom setters so that health can't go below 0, etc.?
Do as much on the client as you can
PlayerState should be things that you want other people to know about the player as well as pawn agnostic things
You could have health in there as well mind you. You just have to reset it when you get a new pawn and handle the current pawn when it gets <= 0
No properties should be public. You should use getters and setters.
Unless they're (static) const.
(except maybe on structs :p)
Why not have public properties? If I will be handling validation on the game mode. Because the getters and setters will just be transparent return statements or member var assignment.
It will just cause problems later.
It's not necessarily about validation (though it could be), it's more about having some buffer between the code setting the variable and the variable being set, so you can add callbacks or validate or whatever.
It takes no time at all to add a setter/getter, but it takes ages to adjuts code when you need to add them after the fact.
Oh that makes sense, so like if I want to broadcast a change in player health. Better to just mediate through getters/setters so the interface is set up for it from the beginning
Exactly!
This is my reply to someone who was asking why you technically should be using SetRootComponent() instead of just RootComponent =. Take the same logic and apply it to your own code.
This made me chuckle. So basically we know we should be using getters/setters for everything, but we can't be arsed?
- Know the rules
- Evaluate if you give a care about said rules ๐
If it is my code - I do w/e I want. It's my travesty. If I'm working on a team, I do it the "correct" way.
For my own code - I can count on one hand how many times I've went back and was like, "Dang - I really need to do additional logic for this field"
(Not saying I don't use getters/setters mind you)
Hi guys, I need some help on an issue I am having:
So I have a PauseMenu where a button can make a player leave the lobby or, if it's the server, destroy the session (means = kick everyone). Now when I use this button in my LobbyLevel everything works fine but when clicking while on GameplayLevel everybody gets kicked even when a Client uses the button, which certainly should not happen.
I couldn't find anything on Reddit or the ue4 forum so I attached some pics of my BPs:
(The branch I used after my MultiplayerLeaveSession Event is copied from a forum post but doesn't really do anything the DestroySession node wouldn't handle on it's own)
Thanks for any help in advance
Without multicast it's the same. And the Multicast just fires if it's the server, which works fine, but the problem is on the client
And Multicast can't be fired from a client
I mean
You shouldn't destroy sessions like this anyway
If the Server crashes or similar, the Clients will be booted to the MainMenu without calling this
You aren't catching all edge cases with this
And a Client with a Session can't Join or Host anymore
Maybe, but best is to just Destroy it in your MainMenu GameMode and/or before calling Host/Join/Search
Either way, you also wouldn't need to multicast this
If the Server leaves, the Rest is moved to the MainMenu anyway
- the Server might also leave before the RPC is even processed, and the Clients will be moved to the MainMenu naturally anyway
It's just not the safest/cleanest way
The session even gets destroyed in the MainMenu just for safety reasons you mentioned. But even removing the Multicast doesn't remove the problem
Hm, strange indeed
Ok so I should just do a OpenLevel?
Still the same problem
What does your log say
I am testing it in the editor but had a friend tets it once packaged and the problem persists
Opening level as Client should not disconnect anyone but that Client
When I just open the level without a DestroySession in the MainMenu it still disconnects everyone. And this problem only appears after switching from Lobby to Gameplay Level.
But.. when you are testing multiplayer
In PIE
And you travel
That means you aren't using Seamless Travel
Which is kinda bad
99% of the time you should Seamless Server Travel
And that is not available in PIE
Yeah, but if you can travel in PIE that means you aren't Seamless Traveling
No it's not by default
Seamless has to be enabled on the GameMode you are travling with
It also changes a lot of the functions that are called
E.g. PostLogin in the GameMode doesn't call for this
And CopyProperties in the PlayerState is now available to move data over
Yeah
You can't do that in PIE though, it's disabled
And some Subsystems, like Steam, require this
Otherwise your Clients disconnect on Travel
Yeah i see, so I need someone to test this with?
Or rather
Don'T reconnect
No, you just need to do it outside PIE
E.g. by starting standalone
or rightclicking the Uproject file and launchign the game
Or even packaging fwiw
Usually, once the traveling is "working", one only works in the current map in PIE anyway
So it's not too big if a hazzle
No, that was just a side comment
I did need to disable SteamSub, but the problem persists still. Do I need to call something else then OpenLevel eg servertravel
Not for Disconnecting
Only if you want to travel from Lobby to Gameplay, Gameplay to Gameplay or Gameplay to Lobby
And only on the Server then
what do I need to call if I want to seamlessly leave the gameplay section as a client?
still OpenLevel?
OpenLevel
Because that doesn't work either, kicks everyone
Can you test that in Standalone ?
That was in standalone
Have an issue where server and client are in the correct custom Movement Mode (climbing) but simulated proxy knows we're in the right movement mode for one frame, then exits it to the falling logic. Even though the server knows we're still in the climbing mode. Any ideas for that?
I would say find out what's changing the mode to falling.
Iirc SimulatedProxy still runs its own simulation of the movement code
@undone kindle another reason setters are good ^
So it could indeed manually decide that it's falling
Cause it might be missing some information
Given most of the time you only share information between server and autonomous
You might just have some condition to start falling that is never false for the simulated, cause you rely on something only those two know?
Just a wild guess
This is what changes it to falling in PhysClimb()
if (ShouldStopClimbing())
{
StopClimbing(deltaTime, Iterations);
return;
}
If I comment this out, the simulated proxy knows we're in climbing and never leaves it. But if I leave it on server + client say climbing and sim proxy says falling.
And this is:
bool UMMOCharacterMovementComponent::ShouldStopClimbing() const
{
const bool bIsOnCeiling = FVector::Parallel(CurrentClimbingNormal, FVector::UpVector);
return !Safe_bWantsToClimb || CurrentClimbingNormal.IsZero() || bIsOnCeiling;```
And
```cpp
void UMMOCharacterMovementComponent::StopClimbing(float deltaTime, int32 Iterations)
{
Safe_bWantsToClimb = false;
SetMovementMode(EMovementMode::MOVE_Falling);
StartNewPhysics(deltaTime, Iterations);
}```
And Safe_bWantsToClimb is only set to true when I click "E" and face a wall. I never set it to false
And it's added to compresed flags etc too
I'm gonna assume b_WantsToClimb is false on the simulated proxies. or the normal is zero.
But isn't PhysClimb not called on sim proxies? only server and client?
And only movement mode is replicated? (+ velocity, acceleration etc.)
And yes Safe_bWantsToClimb turns false which exits to falling state, the rest remain the same in ShouldStopClimbing() when I break point it.
Then it's calling should stop climbing on the simulated proxies and causing the error. Maybe add an owner check to changing movement modes?
nice idea, will try it!
Pretty sure Simulated runs some code too
Role != SimulatedProxy or whatever
CharacterOwner->GetLocalRole() != ROLE_SimulatedProxy)
Oh really? I thought I heard someone say only server + local client runs it, but I could be wrong
OMG IT WORKED!
Adding the simulated proxy check ๐
Normally the red circle would say "Falling"
thank you so much!
I gotta go read up about sim proxies running physics functions now lol
It doesn't make sense for simulated proxies to be changing movement modes themselves anyway, so this is probably a good general fix.
exactly, server should change the movement mode to send to sim proxies. Now I wanna make sure I always have that check
The OutputLog or the one that appears when openinga standalone game
because both display nothing when leaving
Since PlayerState and their Pawns are replicated to all clients, does that mean a client can see other player positions through walls using some client-side patch to the game (aka "wallhacks")?
In theory, yup
Thatโs how Wallhacks work fundamentally
If you're super concerned about that, you could be very strict on relevancy.
It will delete actors and not replicate changes when actors become non-relevant.
Well, maybe the delete part. Probably delete.
If they are dynamic net actors they will get deleted
Which is the case with pawns
You can take a look at what Valo did
So I just added this to my PhysClimb functions so none of this code runs for simulated proxy and everything works. Is there a case where simulated proxies should call the custom Phys functions?
if (deltaTime < MIN_TICK_TIME && CharacterOwner->GetLocalRole() == ROLE_SimulatedProxy)
{
return;
}```
As I notice the while loop in PhysWalking checks if you ARE a sim prox
while ( (remainingTime >= MIN_TICK_TIME) && (Iterations < MaxSimulationIterations) && CharacterOwner && (CharacterOwner->Controller || bRunPhysicsWithNoController || (CharacterOwner->GetLocalRole() == ROLE_SimulatedProxy)) )
{```
Very cool, thanks for this
So I have game mode updating game states array of team scores, and team scores is set to replicate but the array doesn't change from their default values?
Server is fine, client doesn't see the updated scores
Probably forgot to tell GetLifetimeReplicatedProps about the array
I don't think UHT rants over you if you forget to do that
I'm prototyping and doing this all in blueprints. Is this an issue with blueprints and I should try to do this in c++?
I'll end up moving in. CPP but I'm just prototyping right now and I thought this array replication works in blueprints
Does it matter how you set the array?
I think you have to SET the array in BP for replication to work, prolly just adding doesn't trigger replication?
Cuz I at least know that happens if you use the increment operator in BP it won't
I tried via the set array element and set by ref
Sorry I'm not a BP geek, and BP is full of networking landmines so I'm just guessing
not for this reason specifically, but i originally did this for the portfolio piece i'm working on. part of my design was pawns shouldn't even be spawn in when they are irrelevant to the client, and relevancy doesn't change often in my design, so when certain factors are recalculated i recheck the replicated actors and close channels on the server. this IMMEDIATELY closes them, and when they become relevant again they pop back in
outside of closing the channel, relevancy still has a threshold time where, after being deemed irrelevant, the channel stays open for a little for the server to be able to preserve it in case it becomes relevant in a short amount of time. this can be adjusted, but i found better reliability in just closing the channel myself
Sad day for my MMO dev career 
So I think it is replicating but there is a delay, of like 5 seconds?
IDK if its an editor testing issue in 5.1 or something else
uh, also i remember reading somewhere that array replication is atomized in UE
so, for example, if an array goes from {0, 0} {0, 1} {1,1}, that exact order isn't guaranteed?
clients might receive the replication in unexpected order
i'm not saying that's the current issue, but it's something to be aware of when replicating an array
... i think 
I switch to float and now testing with int32
notice the delay with iint32 replication
it's getting there but delayed
compiling now to test on individual hardware
Fyi not as an array
@fresh cloud Correct, there is no guarantee that a Replicated Array will be order consistent across Clients.
If you need consistency of order you would need to setup support for that by some other means yourself.
What Actor does the Replicated property exist on?
A delay in replication time could mean a couple of things.
A standard AActor that only server has, then that goes to the game mode to call update score and then sets replicated integers on game state
So they are on the GameState?
Have you checked that the GameStates NetUpdateFrequency is relatively high? A low NetUpdateFrequency can give the appearance of delay when replicating variable values.
Also verify that you arent testing with simulated Latency in the Editor.
This would also contribute.
Keep in mind that a variable will only replicate (by default) if its value has changed.
Can you repro the issue in a blank project?
What are you using to verify there is a delay?
Hello everyone. Having an issue trying to a player's steam ID with a dedicated server.
I see the message on the server after the onjoin "LogBlueprintUserMessages: [DarkRP_GameMode_C_2147482482] Steam ID: 76561198099278132 joined the game."
But when I try and access the SteamID from the player, I get a "Bad Unique Net ID" error.
PostLogin only runs on the Server.
Looks like you are using Keyboard input to fire the event that would print out the SteamID on your InventoryController, this would result in the Client doing this.
In such a case, because SteamID is only set on the server (due to PostLogin) it does not have a valid value on the Client.
You would likely want to Replicated the SteamID variable, or access the Steam Id locally on the Client from the OSS, since the Client should have its Steam Id locally as well.
That makes a lot of sense. That's a stupid mistake on my part
The Steam Id should be set on the Client via the PlayerState exposed through UniqueNetId
Gotcha. I'll switch that around and give it a shot. Thanks!
Can someone get back to my problem please
If you're calling Open Level on a single client, then only that single client is leaving. If you're calling Open Level on the host or server, then it would kick everyone. Did you check the logs to see why everyone may be leaving?
oh also very basic question, but does your host happen to be a listen server?
if a listen server opens a new map, they aren't just a plain client, that will kick everyone too
What are my options? I don't want to add an Anim instance only for that?
no, but the anim notify can call a function on something that is replicated and able to MC, like the pawn
I'm trying to avoid any casting.
to avoid blueprint dependencies?
you can call a c++ multicast, it really doesn't matter if you cast to native class
they are all loaded at all times
To keep the integration simple. So no need to re-parent anything.
If I can override a function from notifier in AnimBP that will work but then I have to access the notifier from animbp somehow
So you mean a !listen server gives clients the ability to kick everyone?
yeah, they count as client and server at the same time, if you want them to function as ONLY a client, the server has to be set and dedicated and hosted elsewhere ๐ฆ
you can get verification from one of the more knowledgeable members, but to my understanding that's the case
Can I say Bad word
Eh
ok sry
Not related to the f word
A ListenServer does not provide the ability for other clients to kick
but if the listen server abandons by loading the map, it should kick everyone else right?
This whole thing would only work if the ListenServer disconnects. That will then disconnect everyone else cause no Server available.
Yeah but they have the issue that a client causes everyone to leave
oh exi i was asking that under the assumption that the "client" that was causing everyone to leave was a listen server "client"
which in this case would cause that to happen
How can a client be a listen server client? A player that creates a listen server?
They are calling locally OpenLevel. I'm pretty sure there is other stuff going on that we either can't see or isn't obvious
I can create a new project now, let 2 clients connect to a ListenServer, and then let one Client leave and it won't break, I'm pretty sure
Otherwise a lot of games would have huge issues
Yeah but the chance is high that it's caused by code from you
Thats for sure
Does a beginPlay node in a level BP get called from Server or Owning Client, in the MainMenu for example?
Because I now did this and it only prints out 'mmmmmmmmmmmmmm' one time
Put a print string on begin play and run as client. If you see the print say "Server: <whatever you printed>" and "Client: <whatever you printed>" that means it'll run on clients and the server.
It does print out Server, Client1 and Client 2 while I am only playing as 2 Players
BeginPlay gets called for everyone who has an Instance of the specific Actor
LevelBP would be called for everyone who is on that level
why does pawn's actor get destroyed when on level reset is called, the default implementation shouldnt do this right?
So because the server spawns in first, it fires a print string from the server. Now, I am playing as two clients and no server, how does this work?
How do you get IsLocallyControlled in AnimInstace?
get owning player of some sort
It should by looking at APawn::Reset
TryGetPawnOwner
I should be able to access IsLocallyControlled directly in anim instance but i can't
Last I checked I found AnimInstance != Pawn so yes you can't
I get undefined
