#multiplayer
1 messages ยท Page 462 of 1
the worst I've seen so far was a server with 25% packet loss
surprisingly, it worked mostly fine
but slowly
It all still works it's just unpleasant to see things being corrected and also knowing you could be unlucky and fire your shot when there is a moment of loss
Happens in Fortnite too though
character movement can easily recover from a little loss
it's mostly unaffected even
Isnt unreal networking accounds for packet loss via the Ack packets where it repeats the transmission until it completes (or something like that) ?
for reliable rpcs yes
When I play Fortnite on wifi, I get a lot of rubberbanding (chests opening late, glitching to where I wasn't, shots straight up not seeming to register)
But then when I plug in my ethernet it's flawless
I can see from the indicators I'm dropping packets on wifi
But yeah not a pleasant experience
๐ค
add a "packet loss defense" feature that sends every packet 3 times just in case
the server will filter out the duplicates anyway
Oh no it's unavoidable, it happens in many games that I play
Just always is an unpleasant experience when I encounter it
ye but that might be a way to make it less of a problem
I mean if it happens on Fortnite, it'll happen everywhere
It's a good idea though
unless the loss happens in bursts
But really it's just the loss of not important packets that causes the unpleasant feeling (small skips here and there)
Light corrections
The feeling that you are shooting but you never know if you'll miss due to some loss
maybe stop using the crappy wifi ๐ค
Lol I pay 100 a month for it

It's really fast just seems to suck when not direcly next to it
kylekatarn you can bring up the wifi device's detail panel and play with the settings, such as allowed power for the device. Windows on a notebook might using your wifi on a reduced rate only for preserving battery. Even if you are powering your notebook from a cord.
But yeah ethernet fixes it
Yeah that's what I mean
I'm paying per month for the service
@rotund sapphire I'm pretty sure it's just proximity, it's in the next room, and my computer has a great wifi adapter
It's funnily actually faster speedwise on wifi
But less reliable
A magnificent wifi adapter
I use it to download things at like 20+ MB/s but on ethernet I only get 4
But ethernet is fully stable in games
I don't even know ๐
It is what it is
that sounds like something is configured wrongly
That could be a faulty of your eth cable, since there are at least two different types. duplex and not
Very true I should look in to a new cable
I have difficulties to recall it tho
ethernet is never slower than wifi unless you broke something
makes no difference
I also have a plug in the wall cable that has similar performance
I use that recently mostly
they can be like 100m long without problems
I wouldnt say that Zeblote :)
*assuming non-garbage cable
The amount of interference the cable picks up can be severe on that distance
Actually I probably have been using the wall plug ethernet adapter when I was playing Fortnite, so it's expected to not have as much speed
But it is fully reliable
Yes there are better and worse cables indeed that is true
Anyway point being of all this, packet loss feels bad in games and I'm sure there are many people on far worse connections playing
They're probably used to it already
Yeah I know I was back in the day playing on xbox
It was part of the experience ๐
medium ping peer to peer lobbies
Your shot MIGHT count ๐
I have one of those crappy flat ethernet cables with no shielding going through multiple rooms to reach the router and it works without problems ๐ค
I think I misremembered and I had been using the shorter cable from the wall, that's most likely it
Had to tidy away the long one ๐
But yeah I'd say it's quite a luxury to have an ethernet connection for most typical gamers unless they are lucky enough to be next to the router
Most people probably don't even consider it
Especially if gaming on console etc.
using garbage wifi: ๐ซ
drilling holes through walls and ceilings for that low latency: โ
well even better would be to have all the rooms wired up properly inside the walls
one apartment had that and it was really nice
It's possible to use the power outlets to transfer net in a house, but that's where i draw the line
fancy ethernet wall socket in every room
No i mean the actual power outlets can be used for this purpose i see it on the internet
ye but you can also hide ethernet cables in the walls much like the power cables
That'd be the dream
That's different, and indeed a much more favored option
How would I network this appropriately
right now hosts saves overwrite the clients
even though its just loading
all saving happens offline and in the options menu
@agile lotus I'd use IsLocallyControlled to ensure that the save is happening on the machine that is controlling the player (A client or a listen server host)
Well if you are loading data for each client separately then you'd load it "offline"
As in the client would load it
You could then pass that info to the server if you need to
Otherwise the server will load the same file for everyone
Question: when a pawn dies in ShooterGame, these two lines are called: NetUpdateFrequency = GetDefault<AShooterCharacter>()->NetUpdateFrequency; GetCharacterMovement()->ForceReplicationUpdate();
What would be the primary purpose here? To ensure all players see the pawn in the exact position he died at?
grabbing the client controller index from server worked
What is the create session thing used for?
Can someone explain to me what the logic behind calling "ChoosePlayerStart" before Login and PostLogin is? Because I'm dumbfounded. I have 4 teams in my game, I assign the players their teams in Postlogin, heck I even tried in Login, and then each team has a playerstart, but since chooseplayerstart is called first, no teams have been assigned and its dumb af
How would one get around this?
Find something called before choose player start. Assign teams in choose player start. Probably designed that way so it knows where you're going before logging you in.
You can't really think it's "dumb af" to not design something around the way you do things especially since ue4 came first
Don't see why you can't override the player start at post login either
that does sound dumb though
obvious flow would be log in > chose spawn > spawn not the other way around
Yeah
I just hope or assume there's a good reason
Maybe it is actually just done wrong
Like CMC not being modular and pawn possession system ๐คญ
char movement is ultimate 
My multiplayer when steam is active keeps giving me the error
Invalid session info for session GameSession in GetResolvedConnectString()
when joining
@grand kestrel Its not really possible since the player doesnt truly exist until Login or PostLogin, so thats the earliest you can assign them a team or name or whatever
But for some reason chooseplayerstart is called before both of these functions
So I cant choose a start based on the team they are on
Im sure there is some workaround since games before have solved this
But what that workaround is... I dont know
you can probably execute your logic first before calling Super::Login @past rain , GameModeBase calls InitNewPlayer from Login and InitNewPlayer finds the player start
there is also a PreLogin you can use
So you're firstly saying Postlogin is way too late, right?
yes, postlogin has already executed the spawn logic
I cant figure out what to do with Login, since it returns a player controller
you can also not call super and do the logic in your login:
ErrorMessage = GameSession->ApproveLogin(Options);
if (!ErrorMessage.IsEmpty())
{
return nullptr;
}
APlayerController* const NewPlayerController = SpawnPlayerController(InRemoteRole, Options);
if (NewPlayerController == nullptr)
{
// Handle spawn failure.
UE_LOG(LogGameMode, Log, TEXT("Login: Couldn't spawn player controller of class %s"), PlayerControllerClass ? *PlayerControllerClass->GetName() : TEXT("NULL"));
ErrorMessage = FString::Printf(TEXT("Failed to spawn player controller"));
return nullptr;
}
/// Assign team here for example
// Customize incoming player based on URL options
ErrorMessage = InitNewPlayer(NewPlayerController, UniqueId, Options, Portal);
if (!ErrorMessage.IsEmpty())
{
NewPlayerController->Destroy();
return nullptr;
}
return NewPlayerController;```
well... if you need the player controller for the team assignment for example
I do, I assign it in playerstate
which needs the playercontroller to get to
So I'd use NewPlayerController as the controller
yep
okay let me try
you can also let your custom PlayerController assign its own team in PostInitializeComponents
PlayerState is spawned in PostInitializeComponents, right?
void APlayerController::PostInitializeComponents()
{
Super::PostInitializeComponents();
if ( !IsPendingKill() && (GetNetMode() != NM_Client) )
{
// create a new player replication info
InitPlayerState();
}```
yeah, seamless travel is with state migration and such
and you only have the playerstate guaranteed on the server after PostInitializeComponents, otherwise you need to wait for the replication event
but to spawn a player on a startspot of your choosing, taking information not available at construction into consideration
i think you just need to override a single GM function
would be weird to override ChoosePlayerStart and do team assignment there though
/** Return true of FindPlayerStart should use the StartSpot stored on Player instead of calling ChoosePlayerStart */
virtual bool ShouldSpawnAtStartSpot(AController* Player);
that one
just needs to return false
by the time you normally spawn pawns when the game starts that information is ready
problem is PC does FindPlayerStart before anything is ready and caches it
won't it spawn at 0, 0, 0 then though?
no, ChoosePlayerStart will exec
AActor* AGameModeBase::FindPlayerStart_Implementation(AController* Player, const FString& IncomingName)
{
UWorld* World = GetWorld();
// If incoming start is specified, then just use it
if (!IncomingName.IsEmpty())
{
const FName IncomingPlayerStartTag = FName(*IncomingName);
for (TActorIterator<APlayerStart> It(World); It; ++It)
{
APlayerStart* Start = *It;
if (Start && Start->PlayerStartTag == IncomingPlayerStartTag)
{
return Start;
}
}
}
// Always pick StartSpot at start of match
if (ShouldSpawnAtStartSpot(Player))
{
if (AActor* PlayerStartSpot = Player->StartSpot.Get())
{
return PlayerStartSpot;
}
else
{
UE_LOG(LogGameMode, Error, TEXT("FindPlayerStart: ShouldSpawnAtStartSpot returned true but the Player StartSpot was null."));
}
}
AActor* BestStart = ChoosePlayerStart(Player);
if (BestStart == nullptr)
{
// No player start found
UE_LOG(LogGameMode, Log, TEXT("FindPlayerStart: PATHS NOT DEFINED or NO PLAYERSTART with positive rating"));
// This is a bit odd, but there was a complex chunk of code that in the end always resulted in this, so we may as well just
// short cut it down to this. Basically we are saying spawn at 0,0,0 if we didn't find a proper player start
BestStart = World->GetWorldSettings();
}
return BestStart;
}```
๐ค
need to take some care with ChoosePlayerStart so you don't break the PlayFromHere in editor
basically needs to return default implementation if its PIE
@grave kayak
but judging from that code he'll need to do team assignment in ChoosePlayerStart, which is a weird
no problem ๐
Just out of curioisty
is there a reason behind this madness of design?
You'd think logically you'd choose a player start after the player exists
you can also do team assignment in the PostInitializeComponents of PlayerState
Is postInitialize called before choose player start?
think that's the cleaner design, since then you can encapsulate the team logic in PlayerState
yes
am I suppose to override that function in playerstart or in game mode?
PlayerState
and only assign the team on the server and let it replicate to the clients
hmm
Im currently assigning players their team based on NumPlayers, which I increment at Login/PostLogin
Im gonna have to find another system then I assume?
Or just create a NumPlayers variable in playerstate
and increment it in postinit?
no that wont make sense
NumPlayers is exposed in game mode, you can get the game mode from the world
yup
Yeah that definitely seems like a clean design, Lets see if I can do it
GM tracks number of players on its own
you probably want to change it based on amount of team members if you want to have fair teams, but i'll leave that to you
right, in that case use the already existing NumPlayerse of GameMode, it's based on the amount of non-spectating playercontrollers
Yup, I made the post init function, removed login
now im just using postlogin
gonna compile and see if this bad boy runs
Hmm
auto GM = Cast<ACS_GameMode>(GetWorld()->GetAuthGameMode());
It returns null in the post init component
Is it possible the game mode doesnt exist yet?
Let me check
eh
it was just a dumb bug
had to restart editor
and it works now!!
Much cleaner design
make sure you put that within a HasAuthority block, game mode only exists on server, would return null on clients
in PostInitializeComponents?
Authority check won't work there, no Roles are set yet
has to do a NetMode check
I've tested it on dedicated servers and Im not getting any errors
so it seems like the client isnt trying to get the auth game mode
or something like that
Anyways thank you for both the help, and Im sure I'll be seeing you again soon ๐
no problem
In general do people use HUD classes as a nice way to store all client UI widgets and have logic to add / remove them from the screen, or do many just do that in the PlayerController?
I imagine it's preference to some degree at this point
It does seem nice that the HUD is client only so you can never accidently try to add a widget to the viewport on the server
But then again it saves a cast every time you want to call a HUD function if you just want to do it on the PC instead
Or else you could have intermediate PC functions that just call HUD functions, but I'm sure that's bad practice
HUD can subscribe to delegates, you know
and its more then just a preference, managing UI from PC/Pawn is clutter
violates the single responsibility principle
That principle being things shouldn't be multipurpose if possible and hold their own specific purpose instead?
I only bring it up seeing stuff like this in shootergame:
AShooterPlayerController* MyPC = Cast<AShooterPlayerController>(Controller);
AShooterHUD* MyHUD = MyPC ? Cast<AShooterHUD>(MyPC->GetHUD()) : NULL;
if (MyHUD)
{
MyHUD->NotifyWeaponHit(DamageTaken, DamageEvent, PawnInstigator);
}
makes them unmaintainable
That double cast could be saved if it's on the PC but yeah I agree
if you mix stuff up
It'd be nice to have ALL client UI stuff in the HUD class
Frees up the PC for being a PC!
once you start managing UI from different objects you'll find yourself spending an hour looking for an object that manages some piece of UI before long
Well I have all client UI in the PC so I know it'll always be there
But I like the idea of it being in a HUD class too
in tiny/hobby/leaning project that is not much of a problem
but when you have over 1k custom classes in the project, ouch
I def won't have that many custom classes, but in my eyes it's either get controller and cast to hud and then call the function or get controller and call it directly
It's just a bit easier to get ahold of
But also easier to call it in the wrong place like on the server
HUD can also hook into delegates, as an alternative
Would you recommend I for example make the HUD subscribe to a delegate that gets broadcast when a client calls an OnRep_TakeDamage event?
That'd then pass in the damage taken for example
That'd skip the need to cast etc.
i prefer using delegates for frequent updates
I thought a big point of using them would be to avoid things like binding on tick for infrequent things like updating health or ammo?
UMG is exceptionally bad at... performance
function bindings are just year 2000 terrible
direct variable bindings are better, but just
just an average RPG game UI, nothing elaborate, will take 5-6ms on gamethread just to keep itself up to date when you use UMG function bindings
Yeah binding on tick seems to be the worst idea ever
Do you mean function bindings as in on begin play the widget casts to the owning pawn and binds a custom event to OnHealthUpdated for example?
That'd pass in a single float only when health is updated and set the text, once
Is that still awful?
I thought that was the way to go to prevent tons of needless updating
Ah yeah I'll stay way from that
I always use SetText()
So it only sets it once, usually from a delegate broadcast
Another slight negative on using the HUD- if you only need say one or two extra widgets for different game modes, you'd either have to pack all possible widgets into a single master HUD class, or else have lots of extra HUD classes per mode that makes it a bit harder to navigate your project
Whereas there'll usually be a unique PC for each mode in my case, and in the master PC I have a create / add widget function so it's a very small bit of extra code to add
But as you said, harder to keep track and it's not fully separate
Though if the mode is TeamDeathmatch for example, I'll know any team deathmatch specific UI will be in TeamDeathmatch_PlayerController for example
you can have a HUD base with most of the stuff, then just extend when you need a change
Yeah I guess it really depends on the complexity of the project
If you need 10s or 100s of widgets, then HUD is the way to go to keep it separate
If you only need like 2 - 6 widgets on screen during gameplay like in my case, it's probably fine to just have a UI section on the PC
Since most modes only need a single specific widget, it wouldn't warrent creating a new HUD class for each one
There's no actual technical downside to not using the HUD class right?
Just purely a workflow decision
it tends to get out of hand
If I do see that happening I'll migrate to HUDs
I just hate jumping through hoops when possible
It's one less step, one less cast and one less class to worry about for the time being which makes life a bit simpler when dealing with UI
But then I can definitely see what you mean- with a large project it could get horrible
Will monitor and switch if needed
Looking through my PC, it's almost all UI anyway, quite a sparse class for what I need at the moment
@grizzled stirrup Was the issue from a few days ago where the client was stuttering locally only on listen-server, while it was fine on a dedicated server ever solved?
Something about having to build from source and change something in the CPC?
@past rain I tried many things, some worked but all had downsides
The thing that worked the best to stop the stuttering and have frame perfect movement from the perspective of the listen server is p.NetEnableMoveCombining 0
However keep in mind this appears to send a client RPC on tick to the server
So it uses significantly more bandwidth and isn't really a great option
There are other tricks to smooth only the animation since that also only gets updated on each net update and not interpolated but it messes with the timing of animations and also doesn't look that much smoother since the location / rotation updates are the most jarring
I'm honestly not sure why it doesn't work out of the box because the server should in theory be easily able to interpolate between client updates, maybe it's something Epic didn't quite finish up as listen servers weren't their priority
I know plenty of games made in unreal that uses client server model
take dead by daylight for example
No clue how they get around this
Keep in mind other clients see each other and the server completely smoothly
This only affects the listen server's view of clients
But yeah I'd love an interp solution that worked like it does on dedicated
Reading what you just said, we might be talking about different issues
Let me quickly describe what Im talking about - Client-server mode only - Server sees all clients smoothly, All clients see other clients + server smoothly
the only issue is that the client sees ITSELF as stuttering
and only itself
So only your own player is stuttering, and only from your own point of view
Ah yeah I remember your post- that is definitely something to do with you setting values on the client but the server disagreeing and moving them back
It shouldn't happen for example on the default third person template right?
You had some rotation logic happening on tick right?
The way I have it is that, GameState holds the player speed value
Because every 30 seconds, all palyers in the game change speed
So at the begin play of the character, I get the speed from the gamestate, and set it to my player
This is how Im currently doing it, but I guess something Im doing here is wrong
SetSpeed is called by the server
Have you logged both the client and server speed values to verify this is working?
I have multiple times, but I will do it agian now to check
Something like Speed should be done via an OnRep
I mean 1. you need everyone to update it 2. if you have late joiners or people getting relevant suddenly, they won't get the RPC anymore
No late joiners
Im doing it in beginplay and have the gamestate keep the player speedso I can set it accordingly
if they die and respawn
And they are all in relevancy range?
Just making sure you don't build something that will break
Either way you'd need to multicast the change then though
Im setting the speed on the server, then having an RPC on the client
Also is that SetSpeed called on BeginPlay?
No it's not enough
What's with the other players?
They should walk with the wrong speed?
- BeginPlay is too early
Then it's okay I guess
Cause BeginPlay of the Pawn itself is too early
It's not possessed at that point
- you still need the Multicast
So once setspeed is called from the server, it should call a multicast function that does the same thing?
Well yeah, you need to update the MaxWalkSpeed on all players
Isnt that what I already do? The function ClientSetSpeed_Implementation will be called on the owning client or am I wrong?
You could just replicate this value and create an onrep call on it
Already suggested that
honestly, it's easier to just use a replicated var for this ๐
as robert mentioned
The logic is this - the game state called setSpeed 4 times because there are 4 players, and at the end of the setspeed function I call an RPC on the local owning client, so it should update for all clients too
I do have that sparkie, but in the end I still need to update max walk speed, since im using the cpc
If you only call it these 4 times on the server + 4 times the ClientRPC, you basically always leave out the other 2-3 players
And if you use an OnRep, as suggested, it would properly call on all Clients for all Pawns
Which is kinda like a Multicast anyway
Point is the same
Let me ask this then, does any of this explain why on a dedicated server it works fine
but on a listen server it doesnt
can you show where you're executing movement?
I wouldn't directly explain that. But it's still not enough to only update on the owning Client
The versions of the pawn on the other clients won't get the update
^
I can repeat this another 20 times if you want :D
Are you saying Im not updating on all the owning clients, but instead just 1 of them?
No
You are not understanding how a replicated Actor works apparently
If you have 4 Clients. 1 ListenServer and 3 Clients connected.
And you spawn ONE Pawn for one of the Clients.
Then this Pawn exists 1x on the Server
And 1x on EACH Client
WIth the SetSpeed function you affect the Server one
WIth the Owning Client one you affect the owner
And the other 2 are left out
I thought the CPC max walk speed was replicated behind the scenes
No, then you wouldn't need the ClientRPC in the first place
It's not replicated
You need to update MaxWalkSpeed by hand everywhere
That's why we suggest an OnRep float "CurrentSpeed"
That just updates the MaxWalkSpeed
i've got a question. I'm trying to replicate a speed multiplier
{
AddMovementInput(GetActorForwardVector() * Value / SpeedMultiplier);
}
void ASCharacter::MoveRight(float Value)
{
AddMovementInput(GetActorRightVector() * Value / SpeedMultiplier);
}```
but if i try do DOREPLIFETIME the SpeedMultiplier, i hit a breakpoint in UnrealType.h
Let me tell you that directly: This is the wrong way to do that.
.___.
Everything that affects the CMC
you up to explain how do it properly?
Needs to be strictly build into it
It's a chunk more complex
I can link you a Wiki post
You need to make your own child of the CMC
i couldn't find SetMaxSpeed in C++
This literally has a SpeedMultiplier example
So you should be good with that
Tbh even Sendans changing of the Speed is wrong
But well
What is the cheapest way to replicate a took damage UI notification event from the serverside character after taking damage to the cilent character which can then call the necessary UI functions locally? A ClientRPC or an incrementing uint8 RepNotify property set to COND_OwnerOnly?
Thinking the RPC is easiest since no one else has to see it right?
you're already replicating health
just broadcast a delegate when health changes and hook into it
@thin stratus How would you change the speed correctly from scratch?
It can be increased though, I guess I can store the old local health before changing it? Would I have to change my CurrentHealth property to be an OnRep property or is there a way to broadcast the delegate another way?
I have already a delegate for OnHealthUpdated that the server calls when taking damage
But that's a manual specific one
so, broadcast it from OnRep_Health
so I should change my CurrentHealth property from Replicated to ReplicatedUsing = OnRep_Health ?
it is a simple approach, and one that doesn't add any extra network overhead
Even doing so, how can I know if I took damage or gained health from a pickup?
its c++, right?
Yeah, I guess I could look into the way Jamsh showed a few days ago
Passing in the old health also
UFUNCTION() void OnRep_Health(float OldValue);
yes
@thin stratus This is pretty much the first time I dabble with multiplayer, and my game will be very simplistic and minimm multiplayer stuff, I dont really want to dabble yet in things like that
Last thing- how does the OldValue get passed in?
Since the server will set CurrentHealth
Which will then trigger the on rep event
the DataChannel checks how many parameters the OnRep function has when DispatchingRepNotifies
and adjusts accordingly
Oh so it'll literally match and automatically pass in the old CurrentHealth before it got updated?
yes
That's incredible
Wow
Thank you so much
That's a much more elegant way to do it
its why the OnRep_Something has to be a UFUNCTION @grizzled stirrup
Makes sense!
It's working great
Only slight downside is having to create local OldCurrentHealth floats before setting CurrentHealth on the listen server so he can pass it in when calling his own OnRep_CurrentHealth manually
But it's by far the best solution
Thank you very much!
does anyone know why changing the max walk speed of the client makes it super stuttery?
like at max walk speed 600 it's fine, but as soon as i set it to 200 (crouch) or 800 (sprint)
it's stutter city
nvm, solved it
if anyone's looking, it's because the speed variables had to be set on both the server and the client
another replication question ๐
my ADS is compromised solely of an animation
which i set using a variable, IsAiming
however, i can't get both the server and the client to show the animation themselves and see the other show it when the other is ADSing
if (WantsToAim == true && CanAim == true)
{
if (Role < ROLE_Authority)
{
ServerSetAimingTrue();
}
else
{
IsAiming = true;
}
}
else
{
if (Role < ROLE_Authority)
{
ServerSetAimingFalse();
}
else
{
IsAiming = false;
}
}
//```
this is what i'm trying for now, with my implementations being just IsAiming = false/true;
alongside that i'm replicating the IsAiming variable using DOREPLIFETIME
DOREPLIFETIME(ASCharacter, IsAiming);
any idea why my server can't see my client executing the animation?
@wanton pebble Server probably doesn't know about WantsToAim so it won't get set (if you are running this same function via the server)
No probs ๐
one final replication question before i get banned from this channel xD
i'm trying to do a dual mesh system
i've got it all set up with one exception
i'm using this system within my anim BP to make the TPS mesh bend down
but while the server sees the client executing this, the client can't see the server lean
but if i run just a singleplayer game and go into an external camera, the TPS mesh moves as it should
any idea what the issue could be?
this happens whether Aim Rotation is replicated or not
It's just in the animbp for the tps mesh
AnimBPs aren't replicated
You need to replicate stuff in the Character and then pull it into the AnimBP
So I'll need to do my function within the animbp in the character?
Anim Blueprint and Character BP are two different things
The AnimBP is not replicated.
You need to do all replication in the Character.
And then grab the Variable from the Character inside of the AnimBP
Hello friends - Anyone know if I can override a PostNetReceiveVelocity event on a projectile in Blueprint? I'm having some projectile location jitter on clients
does anyone know why when I get the resolved connection string I get the steam id but not the map url despite having loaded one on the hosting server?
I've read its supposed to look like "steam.123456789:7777//Game/Maps/MainMenu_Entry" instead
NVM its because you should have seamless travel turned off
For initial connection it should be a hard travel yes.
yeah, realised in the end
thanks though
you wouldnt happen to know why using OnlineSubsystemSteam makes the clients lag around but without its buttery smooth
they rubberband back constantly
๐คท that could be anything
agh ๐
Whats their ping?
it happens when testing in the editor
and through steam alike
the stats look ok I think
looking at a fresh project I've noticed on my project the in rate never goes above 300. I'm not sure what could be causing this
I dont think so. havent messed with the networking settings
but the in rate is super low which might be whats causing it
try something like this for testing
[/Script/OnlineSubsystemUtils.IpNetDriver]
MaxClientRate=100000
MaxInternetClientRate=100000
[/Script/Engine.Player]
ConfiguredInternetSpeed=100000
ConfiguredLanSpeed=100000
DefaultEngine.ini
yeah im more concerned about your out rate being 9.998KB/s, which is suspiciously close to the 10kb/s limit
that actually fixed it
thanks
so much!
is the initial limit just low or am I doing somethign wrong do you think?
great!
hmm i think the initial limit is legacy maybe... its very easy to go past it
i believe e.g. fortnite uses 40KB/s
once the client goes past it, he starts dropping packages
instead of sending them to the server
since the movement component is the one using the most bandwidth, its affected the most
I have a question about seamless level transitions and voip. I'm running into a weird edge case
In order to debug the issue I broke down the problem into a simple sandbox project. I have a simple multiplayer game with voiptalkers on the player pawns
but when I transition between levels, if I'm talking on the mic it causes a stacktrace, that is sometimes fatal but sometimes recovered from
it usually recovers on the server and goes to the next level but the voice buffer is perpetually full
and so the voice stops working
the error is
[2019.05.13-09.42.06:750][548]LogOutputDevice: Error: Component Name: AudioComponent /Engine/Transient.VoipListenerSynthComponent_0:AudioComponent_0 World Name: World None.None Component Asset: /Engine/Transient.VoipListenerSynthComponent_0:Synth```
it looks like it has something to do with registering the voip talker to the player and the component it is being attached to being destroyed during teardown of the level
Do bots and their PlayerState survive SeamlessTravel?
I kinda doubt. In CopyProperties I'm moving my TeamState over to the next PlayerState
And that works for Clients, but bots seem to be resetted
I wouldn't think that bots would persist
hmm yeah it adds the entire PlayerArray
I assume AIControllers are not kept, so the PlayerState isn't either
Yeah so "HandleSeamlessTravelPlayer" passes an AController
But handles only a PlayerController
It skips the CopyProperties stuff for everything else
Maybe it does indeed keep the AIs, but doesn't handle it properly to reinit them
Hm nvm, it does
Wtf
Does what?
WEll in the GameMode class in HandleSeamlessTravelPlayer, it filters between PC and non PC
Now I'm not sure if that is called for AIControllers
Okay it is. The TeamState is just null
Weird that it works for the Client
I have an issue where when you select number of players 2 and the server is interacting with one client my stuff seems to replicate fine but when i try dedicated server client's can't damage each other.. anyone have any ideas?
Hello everyone!
when I run mygame.exe -server
it listens on the wrong ip (a vnet I have set up)
is there a way to bind it to the right ip address?
I've never used this yet, but there's this: PORT: Tells the engine to use a specific port number.
about to ditch this ability system and go back to C++ replication lol
thx
In the CMC, if I wanted to override any rotation that a RootMotion montage applied, with the Player's input rotation, is there a simple way to do that?
hey all, im having a bit of a moment here. enabled the built in steam plugin and put in the defaultengine.ini the correct variables to define my own appid, but doesnt matter what i do or set, when launched either via a built development build or standalone in the editor it always launches as the spacewar app. I have been trying various things now for a few hours
hey, I have an error everytime i Package the Project
ERROR: Unable to compile source files.
ERROR: UnrealBuildTool failed. See log for more details. (C:\Users
Hey all, does anyone know if using a RepNotify is more efficient than a Multicast? Same?
I've got a heavy multicast that's eating up network bandwidth. Looking for alternatives.
its certainly not less efficient
and it allows you to specify how often to do the update(net update frequency) etc.
but if youve a multicast thats that heavy then you might have a design problem to begin with
Could be. It syncs prop transforms across all clients. Lots of props in my map and they get moved and shifted around a lot during gameplay. I'm not sure how else to sync things.
whats the current RPC argument
It's a rotation and a vector_NetQuantize_10.
per object right, so its in a tarray?
Yes well, there's one that syncs everything when a new client joins (that one uses an array). The one I'm currently trying to fix is called on the actual prop class and only passes with its own location/rotation.
why didnt you just replicate the location and rotation directly?
or is it non replicated classes
It's a non-replicated class.
mmm what you could do is looking into delta serialization
its a tarray version that only replicates changed indices
hmm... ok that sounds interesting. Thanks! ๐
still the same information that needs to be sent obviously, but you wont have all the overhead related to actual rpc calls
Nice! thank you!
i have problems with the "advandes steam sessions"
I cant package project after I turn the plugin on
Networking question: I remember hearing in a training livestream a few months ago that the best practice for multiplayer is not to rely on multicasted events or on replicated events in general, but rather to rely on OnRep variables and replicated variables of as small a size as you can go (e.g. Bytes, Chars, and Booleans) and then simply reacting to changes in those variables.
If that's the best practice, then doesn't that imply, then, that all of our framework classes are gonna be a mess of variables like bWantsToFaceDirection or Behavior_State? I just want to make sure that that's a correct interpretation of what they're saying.
I assume it means that if both ways are possible, that OnRep is the one to take.
If it makes 0 sense to use an OnRep variable, then don't do that.
Neither use an RPC if it makes no sense.
Technically it's no magic to find out what to use.
Is it just a bad design decision to try to override Root Motion Montage rotation from the CMC?
Stupid follow-up question: how do I know if it makes 0 sense to use an OnRep variable?
when you're doing a one time thing that leaves no lasting changes
and it won't matter if clients miss it
Any clever ways to work out shotgun damage without sending a gigantic amount of info per shot?
Assuming we want say 20 pellets in the shotgun with each individual trace capable of damaging a different actor
No matter what way I think about it, there's going to be 20 RPCs going up at once unless I can pack them into a single RPC?
Definitely pack them
Just trying to imagine how to sort them so that the server knows how much damge to deal each actor in the array of hit actors that's sent
Assuming it's fine for my client to work out how much each actor should be damaged (in my case that is fine)
My client can run a for loop of traces, populate an array of hit results, check each one if hit a damageable actor, then populate an array of actors damaged
If I also populate an array of damage floats as I'm populating the array of actors damaged, maybe they'll stay in order and I can do a for loop on the server and damage HitActor[0] by DamageAmount[0] ?
It's still potentially quite heavy sending an array of actors and an array of floats in one RPC I'd imagine
sending 10 actors (netguid) and 10 damages (float?) is 60 bytes
that's nothing
client side hit detection is very sketchy tho
@fleet raven can you elaborate on netguid?
I have an array of AActor* atm
And yep float damages
Also client hit detection is fine in this case (co op game not PvP)
Against server AI
I'm having clients do as much as possible locally but this is one case where they will have to send a bunch of data per shot
I guess a realistic shotgun scenario would only be say 3 actors hit with 8 pellets each or something, so it's not as bad as it seems, just unsure of how to "link" which actors get which damage when sending to the server
a replicated actor will have a netguid which is sent as 2 or 3 bytes
Oh that is super cheap!
Much less scary than I imagined
So even in the worst case scenario it'll be fine
even if it was sending 1KB per shot it wouldn't matter
unless you got some magical minigun-shotgun combo
Haha nope this'll be by far the most expensive operation
Well maybe rapidly firing rifles will be just as expensive since they send many separate RPCs in a short timeframe
But I also think I'm underestimating the speed of networks and overestimating how large the data is
Any ideas on how the server can know how much damage to deal to each sent actor? Just hit me that some actors will be hit multiple times so the order of the array won't match, maybe this is where TMaps come in?
well
replicating an actor is only cheap if that actor has already been replicated
well why not just sum up the damage to each actor and send that
also
@gleaming vector well in this case they are AI enemies that are already replicated from the server to the client, so should be cheap right?
when doing shooting
yeah
what I mean is the first replication of the actor is the whole actor
after that point, it's done by guid
anyway
I've implemented shotguns
and other shooter mechanics
I never replicate the bullets
I replicate the shots
the server sends down information about the projectiles to the client so that it can simulate it
you can start predicting a projectile if you want, and then correct that predicted projectile when you get the authority in
@fleet raven I'm not sure how to "link" them, imagine pellet 1 hits Actor A, pellet 2 hits Actor B and pellet 3 hits Actor A again, not sure how to tell it to add it to his existing damage float and also correctly tell the server- deal X damage to Actor A, B etc.
@gleaming vector Oh you are miles more complex- I'm just using simple clientside traces in my case ๐
make a temp map on the client side to sort it out
And the client can make the call on damage too as it's not PvP
not replicating the projectiles is interesting
oh
Ok will look into maps, thanks!!
then replicate from client to server impacts
i kinda sorta did this on squad when I worked on that game
you mean like instead of using replicated actors, you send a multicast rpc to spawn a projectile somewhere?
the shot was replicated to the server (with a shotid), and then the impact was replicated up (with the corrisponding shot id)
I'm not even going that far, this is purely the damage amount on server- there will only be one normalized impact replicated
I just want to have each pellet count in terms of damage
sure
The cosmetic fx will be cheap and simple
then batch your impacts
or, well, you really can't in some cases
there is some code I've seen in the engine (i forget where) that counts outgoing RPCs and if it's over a certain number, it batches a bunch of events into a single RPC
Cheaper / simpler just to send one FVector_NetQuantize for the impact loc and have the clients simulate the impact normal + do a big impact FX in the center average of where the pellets hit- not as nice visually but nice and simple
But of course for more realism you'd have to send more
oh, i see what you are trying to do
but what happens if you shoot at a corner
and half the bullets go past the corner and the other half impact it?
the bullets that keep going may impact another person a few frames later
oh
The client who shoots can spawn more detailed FX if he wants
just replicate the shot event for remotes
and then spawn projectiles that don't care about impacts
Oh yeah that too, at the moment I have everyone doing the simple blocky FX
just for effects
I'll probably spawn a decal for each impact
But only one centralized particle system
i use "spawn projectiles" here but I mean however you carry that damage event over distance (can be a line trace)
From what I've tested at least, it's not usually worth spawning 20+ separate impact fx in each impact location in terms of what you get in performance
The decals are worth it
sure
But in many cases a big centralized single FX works great
you can get away with a number of particle effects
since particle effects are actually much cheaper than decals
It's a shame that decals are quite costly but they give the most visual impact imo for shotguns to see the spread like that
20+ particle systems can work great too but if they want to look decent usually it involves a separate mesh emitter for each impact hole as well as sparks/ lingering heat spot
I'd be curious on the performance differences between them, either way shotguns are just creating a lot of stuff in one frame ๐
yeah
well
do it and profile it
then turn it off and do it another way and profile it ๐
that is, honestly, the best path forward in this situation
Yep!! Will likely go cheap and cheerful (no decals, one centralized impact fx)
But first, gotta figure out sending the actual separate damage amounts / actors to the server
Thanks for the help though, got some good ideas to test for FX when I come to it later
Is epics cross platform sdk3a master server/online subsystem?
And is it a better idea to not implement steamworks and wait for them to release it?
no
and if you stick to the online subsystem abstraction, switching will probably be nothing more than an ini change
@thin stratus @jolly siren thanks for looking at it. it seems like the bug has something to do specifically with server travel while someone is talking on the mic
i'm trying to repro without seamless travel
i also can't figure out why when i have a voiptalker component on the pawn i dont need to manually call the register with player state function
it just works without
when i do call that function it crashes, but even without calling that function it still doesn't work when someone is talking
hey, if anyone here happens to have a solid understanding of this diagram, pls feel free to PM me if you wouldn't mind answering a few questions
just put your question here
iight so basically 2 things:
1.) What do the diamonds represent in this graph?
2.) is there a generally agreed upon "best practices" for passing data around in this system?
example for #2:
let's say I have some GameState data like the score, and some PlayerState data like health. Both of these need to be fed into the UI, preferably via event dispatchers. Should I just have dispatchers anywhere that I need to send data from, and then pull it wherever I need it, or is it better to go through some kind of hierarchy?
additionally, I could go through some kind of general event manager service, but there will presumably be a ton of different events per gamemode, and as far as I can tell, I can't put the binding of events behind an interface (I can do the calling, though)
Do I need my eyes to be checked? I don't see a single diamond
I see circles which seem to represent server/client. and i see rounded rectangles
it's probably explained near where you found this diagram
ownership/"created by" would make sense
that's what I'm thinking as well, but is there no ownership of pawn ?
not really, since they can be arbitrarily spawned and you can then possess/unpossess them
can have pawns in the world that aren't related to any player
i see. admittedly pawn is probably what I'm the most hazy about in terms of what type of information goes where
ahh that's a good point. a player may have a pawn or may not
in that case yeah, i think ownership is the relation
oo wow those were hard to see
honestly they were driving me so crazy that when you said that, i thought maybe i imagined them
You can think of Pawn as the visual representation of the player.
right, separate from things like input control etc
so an example of useful info from the pawn would be like, if you were making a minimap--relative location on the map
Health is probably a better example.
hmmm...my initial instinct was that that would go in PlayerState
Since the Player can still exist as a Spectator when they die, you want the Pawn to have Health that then allows it to be "Killed"
PlayerState is better for information that is specific to a Player that all Clients would want to know.
Health is specific to a Pawn, not a Player, since a Player can control arbitrary Pawns with different abstractions of what Health might be.
Score is a better example of something to store on the PlayerState
Since other Clients might want to know other Players scores to display that cosmetically.
okay. so i had some misconceptions but i'm understanding better now
it seems in this case like i may want to be able to call/receive events from any one of these framework classes tbh
There is no single point of contact thats going to supply you with everything you need. All these classes work together to create the framework.
Its more about figuring out the best place for information and then how to provide it to external systems as seamlessly as possible.
right. the latter part of that is somewhat eluding me
is there anyone i can have an in depth conversation about voiptalkers with?
Its good to ask yourself what the information is doing, who might want to access it and why. This will help you decide where it should reside.
basically I tried to make an event service, but as far as I can tell, you can't return a delegate (at least in blueprints). perhaps with C++ i could finagle it
but now that you're saying this, i wonder if a better way wouldn't be to use the event system to reinforce the framework
PAWN_EVENT_*, GAME_STATE_EVENT_*, etc.
and listeners accordingly
Yes Event Driven Design is a good approach
hmm. done TDD but never EDD. i like it
It means that systems are querying data when they need them, instead of external systems strongly coupling themselves to other systems by forcefully providing that information.
oh yeah, that's exactly my goal right now
you've already got the wheels turning. if i only have event types relative to the framework classes, then I can just set up my eventing based on those classes
If your not familiar with the SOLID design principles i recommend doing a little research and at least being familiar with it.
yep, i know SOLID. that's kinda how I came to these questions, through my desire to adhere to it so badly
Your not going to write everything perfect the first time.
Iteration is your friend.
Also make sure you understand the networking context of each of the framework classes like the back of your hand.
yeah. the trickiest one was PlayerController imo. still gotta make sure i'm super comfortable with them all tho
yeah, i spent a while just console logging everything and seeing if it printed client or server, or both, and what could replicate and on which policy
you've really helped a lot. this discord is so nice
luv u all
I'm just gonna dump some stuff here
so, voiptalkers
I have a fps character. i have a voiptalker attached
theres one pretty important gotcha with this gameplay framework: replication sux and a client can have a pawn before he has a player or game state
yeah, i have a wait macro
to fix that very thing
it just hangs till the player state is valid
one can force its hand by changing around some NetPriorities on those actors @fleet raven
Pawn is default 3, actor 1
so i have two blueprints there
and GS/PS don't have the defaults altered
that's not 100% reliable though, if packets get dropped they can still replicate in different orders
I would like a feature that simply guarantees, 100%, for certain things to replicate before others
what exactly is register with player state doing?
i copied the bp wrong so it doesn't show the voip talker as connected to that block as the target but it is
i poured through the code last night
and i see the map of talkers linked to player ids
what confuses me is that the talker works fine without this mapping
i wasn't sure if there was some magic happening with the component setup
that is a tall order Zeblote
but i couldnt find any in the engine source
is it really tho
I wouldn't have a problem if it results in delaying a join by a few times latency by simply pausing the replicating until the client has confirmed receiving the game state
wait - can I not already do this by using the replication graph? 
How does one limit voice chat to certain players and not all players?
Or is that something that would require Vivox, for example?
@weak fog As stated in the Document, this is taken from an outside source (recreated).
The Compendium is meant as a collection of information that is spread around the internet, so while a lot of text and images in there are mine, I found these diagramms to be so good that I used them (see Source 2).
So I did solve my problem
I still don't understand the register with player state, since not using that seems to solve the problem.
but it was 2 problems
1 was, i had to not use that, and 2 was i was calling start networked voice in "begin play", which doesn't get called after map travel. so that's an embarrassing mistake but all working now.
When using Seamless Travel, is the GameMode the exact same one in the next level (if same class) or does it also pass over data from old to new?
Cause I'm kinda confused as to how UT manages their TeamInfo class.
They just copy it over from Old PlayerState to new PlayerState and never add it to the ActorList that should survive.
Now if I understand that correctly, it should survive anyway because it's referenced in the PlayerState?
Is there an easy check to see if an Actor is from a previous level?
Other thing is, that they don't even check if the TeamStates array is empty or not and always recreate it.
What is the OnCopyProperties call for then >.>
I'm currently checking if the array is empty or not and post seamless travel it seems to be.
So either my GetSeamlessTravelActorList doesn't work (which technicallly it should do already cause the states are referenced in PlayerState, GameState and GameMode) or this is a new GameMode.
Gnah, it should be possible to make the TeamStates survive a travel so that everyone just keeps their Team.
@thin stratus being referenced by player state doesn't necessarily guarantee it survives afaik
I'm adding it to the list of actors that should survive anyway
Literally what I wrote not even a minute ago :D
lol yup
im confirming that, the reason is the reference gets saved but not the actor being referenced.
I think the way I set everything up is already wrong. I need a proper way of creating the Teams and then reusing them later.
And that has to work for Players and Bots.
Currently bots only join a team if they are created, sadly they also survive (which is technically okay) the travel, which never adds them to a team again.
oh i see
Which technically is also okay, if the freaking TeamStates would survive properly
why don't you have the team state be an enum var on the various controllers
Cause it does a lot more than just keeping score.
i see
i mean
it sounds like you want to have a score state, that is for the game as a whole
Keeps track of leaders, top scorer, party members etc.
that is one piece of information
and the individual team information for the players
team state sounds like it is doing too much
Na, it's the same thing that Unreal Tournament does
oh ok
It's a solid system if it would survive the travel
gotcha
I'm just again a bit too lost with all the gotchas of travelin seamless
Yeah
hrm, yeah i exposed the actor list in the game mode to blueprints to debug what i was working on
was a dead end but i did get the pawns surviving the travel
as a thought
there are some functions for when an actor finishes travelling
add some debugs there to the team stats class
Right now it works like this:
- GameMode::InitGame creates a TeamState per needed Team.
- GameMode::InitGameState passes the TeamState Array to the GameState so everyone can access it.
- When the Player leaves the Spectator State (In PlayerController) it asks for a Team to join.
- TeamState array is added to list of surviving actors.
- PlayerState is passing TeamState over in CopyProperties.
and see if maybe the actors are surviving but the references need to be reset on the players
Yeah that would be helpful
Have to check AActor api to see what exists for that
Just for debugging
let me pull up my project, i am doing a much simpler thing, but i know the game mode had a function you could override
Seems like actors have a "bActorSeamlessTraveled" boolean
At least for debugging yeah, but still not sure about the whole process of when to create the states and when not, what function is best for that etc.
i suggest putting something debug logic wise in the actor that it'll self fire.
are you sure game mode init game wont be called post seamless travel?
e.g. InitGame calls even after the travel
Yeah it does, which is one of the points why I think UT doesn't really persist the Teams anyway
Even though they pass the TeamState via PlayerState
ยฏ_(ใ)_/ยฏ
i see
but you are checking if a new one is needed
and not generating a new one if not
i assume
Yeah i check if the Array is already setup
Which it isn't
Which makes me believe the TeamStates array isn't surviving or at least not as I want it to
Idk if the GameMode has a function to move over stuff
I only know about the PC and PS stuff
So "bActorSeamlessTraveled" is false for GameModes post SeamlessTravel
.>
yeah
yeah im looking through the github code for gamemodebase
it looks like maybe you can use the game state class
but im not seeing how tbh
Can't see any function here either though
SeamlessTravelTransitionCheckpoint was my best guess
but by the time you hit the transition map
the game mode will have changed
There is also no way to access old and new GS or GM
it's weird cause the docs def say the game mode actor should persist
on the server anyway
are you only looking at the server
or the client gamemode as well
Client has no gameMode
sorry, yeah, i was confused
i thought it was reped for some reason
try setting a bool in the game mode on begin play, seemless travel and see if the bool is still set
im just grasping
I wonder if I can grab the CurrentWorld in the new GameMode
But that also sounds so hacky
/** the world we are travelling from */
UWorld* CurrentWorld;
/** set to the loaded world object inside that package. This is added to the root set (so that if a GC gets in between it won't break loading) */
UWorld* LoadedWorld;
LoadedWorld is the new one that the new GM is in
if I can grab the CurrentWorld (and it's still valid) and get the GM of it, I could access it
But that sounds wrong too
I feel more like I need to ge the same path PlayerState is going somehow
So instead of keeping the TeamState, I need to copy over the data at some point
But where the fuck is the entry point for something like that
I feel like you should be able to keep the team state via GetSeamlessTravelActorList, and then just find all actors of team state post seamless travel
and rebuild your array
Let me try to use PostSeamlessTravel to just print the amount of TeamStates in the World
sounds like a good start
Cause technically, it should be 4 instead of 2
gl man, i gotta get some sleep. hope you figure it out
np!
Welp, it's indeed 4 teamstates
cool, so def being added to the list
i was just thinking you maybe added them wrong
Welp, now I have to find out how to properly get a grab on them.
It's easy to just find and reinit them, but I have to stop the other 2 from spawning again.
This freaking boolean should be true for a seamless travel gamemode >.>
no arguments here
Wait what
// scope because after GC the kept pointers will be bad
AGameModeBase* KeptGameMode = nullptr;
AGameStateBase* KeptGameState = nullptr;
// Second pass to rename and move actors that need to transition into the new world
// This is done after cleaning up actors that aren't transitioning in case those actors depend on these
// actors being in the same world.
for (AActor* const TheActor : ActuallyKeptActors)
{
KeepAnnotation.Clear(TheActor);
TheActor->Rename(nullptr, LoadedWorld->PersistentLevel);
// if it's a Controller or a Pawn, add it to the appropriate list in the new world's WorldSettings
if (TheActor->IsA<AController>())
{
LoadedWorld->AddController(static_cast<AController*>(TheActor));
}
else if (TheActor->IsA<APawn>())
{
LoadedWorld->AddPawn(static_cast<APawn*>(TheActor));
}
else if (TheActor->IsA<AGameModeBase>())
{
KeptGameMode = static_cast<AGameModeBase*>(TheActor);
}
else if (TheActor->IsA<AGameStateBase>())
{
KeptGameState = static_cast<AGameStateBase*>(TheActor);
}
TheActor->bActorSeamlessTraveled = true;
}```
So the old gameMode is marked as Traveled
Are you shitting me
Weirdly enough, the GameMode is copied over to the new world usually
if (KeptGameMode)
{
LoadedWorld->CopyGameState(KeptGameMode, KeptGameState);
bCreateNewGameMode = false;
}
so whats yours doing?
We will soon find out :P just breakpointing it
gotcha
Just in case someone is/was interested in what shit is being moved over
So it does indeed completely survive the travel
Not even recreated, it's the same actor
Now the question is ,why is the obvious bActorSeamlessTraveld false in InitGame post travel
Man I need a new coffee
I hope all of you just reading this are actually learning something
half awake but excited to learn how it ends
So, before I go further through the breakpoints: Yes it is keeping it and the TeamStates are still in the array at that point.
Now the question is: Why is the Number of TeamStates etcl not work anymore post seamlesstravel
Cause I'm doing this in the InitGame function: if (TeamStates.Num() < NumTeams && !bActorSeamlessTraveled)
And right now, if I open the inspector, TeamStates is of num 2 and NumTeams is 2
Even bActorSeamlessTraveled is true
// Init the game mode.
if (AuthorityGameMode && !AuthorityGameMode->IsActorInitialized())
{
AuthorityGameMode->InitGame( FPaths::GetBaseFilename(InURL.Map), Options, Error );
}
This should never call as the Actor is initialized at this point
And it indeed doesn't go in there. Now I'm confused. How am I able to break point that function if it's skipped
Magic?
wait, hold on, weren't controllers and ULocalPlayers the only ones meant to survive to seamless travels o_O
By the looks of it, the LocalPlayer isn't even teared down
So it doesn't have to persist ?
PlayerState def persist
that... should be new, I don't recall this behaviour lol
Well I only add the TeamStates by hand
The list above from Visual Studio is otherwise untouched
lmc
Oha now it makes more sense
This SeamlessTravel stuff calls twice
Once from A to Transition and then from Transition to B
And A to Transition the GameMode survives, Transition to B it doesn't.
Now is that my bad for not setting something up properly is the question
do both game modes exist in the transition map?
Both?
the game mode for the end map
I never touched the Transistion map
when does the final game mode come online
Thought that just uses the same GameMode and that's it
during transition
or on final map load
if it is during transition you can copy everything over
if both actors exist in that map
i dont know if they would
As far as I understand, it should keep the GameMode from T to B too
i agree
Cause from A to T it's one and the same GameMode
maybe the transition map doesnt have a game mode assigned
and T to B GameModeBase?
is it an empty map?
Well I sadly skipped the loop
Gotta have to run a travel again to see what actors survive from T to B
I tell you, develop a Splitscreen, LAN, Online, heavily UT inspired game nearly alone
And you will sooner or later know the freaking engine
you got splitscreen? nice
Yeah....
Would rather not have it, cause UI is a mess with this
And they want Online Splitscreen at some point
I will die
Okay, I'm going to debug a side project to see if I get 1:1
I don't do gamemode discovery in this one, but not sure if because my url option impl I got the right behav
or just because the engine handles it for me
All I do in this one is ServerTravel with the ?game=TDM url iirc
So it keeps the GameMode
yeah, that seems right, iirc
try to read the built in options string
to see if it has your settings, while this thing boot up
Yeah also checking the point where they try to keep all actors
single process, right?
Launch Game via uproject file
Actually just offline splitscreen atm
Doesn't really matter if you listen to something or not
well yeah, there are a couple shenanigans implied on empty servers and dc that can give you headaches, but gona try purely SP
I already found the problem
void AGameModeBase::GetSeamlessTravelActorList(bool bToTransition, TArray<AActor*>& ActorList)
{
// Get allocations for the elements we're going to add handled in one go
const int32 ActorsToAddCount = GameState->PlayerArray.Num() + (bToTransition ? 3 : 0);
ActorList.Reserve(ActorsToAddCount);
// Always keep PlayerStates, so that after we restart we can keep players on the same team, etc
ActorList.Append(GameState->PlayerArray);
if (bToTransition)
{
// Keep ourselves until we transition to the final destination
ActorList.Add(this);
// Keep general game state until we transition to the final destination
ActorList.Add(GameState);
// Keep the game session state until we transition to the final destination
ActorList.Add(GameSession);
// If adding in this section best to increase the literal above for the ActorsToAddCount
}
}
It doesn't keep itself when traveling from transition
Only if toTransition
Now please someone tell me why
I can easily keep these three in my own gamemode with !bTransition or just overriding everything
๐ค
But not sure if that's a good idea
Do I want to keep the GameMode?
It's most likely in a late MatchState
Doubt they reset it already
If anything, debug T->B and look for the initialization code
Well you can clearly see that they don't keep the GameMode from T to B
yeah no they don't but the URL I guess stands for something