Major - Join In Progress Has Multiple Issues

How is this STILL happening. Even with a code fix, the Team 1 bug is breaking all of my maps. Once people join and leave frequently, everything completely breaks and the team balance code is struggling. This is making me not feeling like making maps anymore

I’m getting reports from public matchmaking players that they are unable to join completely even though I have join in progress turned on in the island settings And I have tried changing it to join in progress - spawn as well as join in progress - teamindex 1 and neither allow players to match make into the game.
For example, my island was posted public listed, and a few players found my information to contact me and told me that they were unable to join the game completely blocking them from joining. Sometimes they are forced to close Fortnite all together so that they can try again.

Update:

Players spawn in, players choose teams. Players spawn in game on the Join in Progress Spawn Pads are disabled Prioriity 2, and Game Start Spawn Pads are enabled (They are still spawning on the Priority 2 disabled Join in Progress Player Spawn Devices only on a public published version.

  • Team 1 (some choose team some dont because of spawn pads bugged) NO players on Team 1 teleport into game, mutators dont affect Team 1, and other devices do not recognize team 1.
  • Timer device and player reference once activaed doesnt respond to team 1 players.

Rebel is on team Gold

@Rebel on Team 2 is teleported into game, Team 1 stuck, team 1 respawns and breaks game further, still stuck on spawn pads in pregame no matter what.

  • Team 1 colors became team 2 colors on Scoreboard.
  • Team 1 still stuck in pregame spawn waiting area
  • Scoreboard All Players suddenly bugged and switched to the opposite team, however the Team DATA is Broken and Bugged really bad.

Rebel, in this case, undesireably switches to team Silver because a player respawned on new enabled Join in Progress Priority 2 Gameplay Spawn Pad. Along with every other player on teams, switched to opposite team with broken data, the culprit being one player respawning

My Setup:

Pregame Area:

  • Spawn Pads, enabled - Priority 1 (Game Start)
  • Spawn Pads Disabled - Priority 2 (Join In Progress)
    • The GS Disable and JIP Enable after 30 seconds.
  • AFK (Auto Assign Player to Team): Automatically Assign Team and kill to respawn player
  • Class Selectors: Team 1 and Team 2 (Class selector Team 3 assigned at Game Start.)
  • Team 1: Silver, Team 2: Gold
  • Team 3: White ( Only used for game start).

Waiting Area

Players that have chosen teams then teleport from the Class Selector to the Waiting Area.

  • Player Reference Devices Register each player through Class Selector on “Team Switched”
  • Player References Activate on Timer 30 Seconds
  • On Activated Player Reference Teleport Players into the game.
  • Now the GameStart Spawner Devices Disable (Priority1) and JoinInProgress Spawner Devices Enable (Priority2)
  • Join in Progress: JIP Players Spawn Directly in Waiting Area, bypassing GameStart Spawners, Spawning on JIP spawners, and Teleport into game by spawning in mutator zone, timer device, teleporter device
    (Player Reference Devices Linked to Class Selectors was only for Game Start Players)

Order of Sequential events occuring which caused the bug:

  • All players chose teams with class selectors
  • Team 2 Spawned into game
  • Team 1 was left behind: Could not teleporting at all.
  • Team 1 respawned (Fornite menu, settings, respawn)
  • New Player JoinedInProgress and spawned in game on the Join in progress spawn pads.
  • All players on each team changed team colors, Team Data was broken, and Devices all reset to their game start behaviors, all progress was enabled or disabled as if the game forgot all the devices events assigned.
  • Scoreboard swapped all players to a different team or the same team and the Team itself changed color and # on its own due to a player spawning in game.
  • JIP PLAYER and or player respawning on Spawn pad Priority 2 spawn pad caused the following behavior
  • (re-enabling or re-disabling re-triggering all devices in the game)

Since you reply to this post, this bug is still happening…
When people join in my map they only see whats in front of the spawn pads…
I’ve set Join in progress to Spectate, and this happens, I set to Spawn next round, this happens, I set to Spawn on Team 1 (Is for choosing team) this still happens!
How and when we’ll get a fix for this?
The only thing we want here, is the Spectate Option to Work!
There’s no super “logic” on it, or super changes you need to make.
Only make the Spectate to spectate, and not be starring at one place the whole round until it ends!

TL;DR
    ValidatePlayer<private>(Agent:agent)<suspends>:void=
        TimeoutPeriod:float=180.0
        race:
            block:
                loop:
                    if(Player:=player[Agent],Player.IsActive[]):
                        HandleValidPlayer(Player)
                        break
                    else:
                        Sleep(0.33) 
            block:
                Sleep(TimeoutPeriod)
                Print("Warning: ValidatePlayer: Timeout")

I have a proposed solution to this issue as well as supportive reasoning and a really nice infographic for you all today.

Essentially what is happening is that Epic has been focused on getting players into the game fast and that means that asynchronous sub processes of the Player Joins process can complete as quickly as possible, but this sanic speed optimization comes at a price.
A player controller, agent, camera, eta are being prepared in parallel to a player initializing over the network, and it seems that can all complete and get passed along with a reference to the Player through the Player Joined Playspace function for handling BUT without the player object actually being valid. :scream_cat:

This implies inheritance from Agent which is the super of Player, which in laymens terms means its a package deal. What happens to Player must also happen to Agent. As such, you’ll notice that you’ll also get spawned triggers from player spawners passing the agent before its ready:

Where the error occurs is that the Player and Agent in these cases aren’t valid.

… Or
If you would please put on your tinfoil hat as a safety precaution for this next part…
image we may proceed.
rather, my presumption is that they are actually placeholder objects which allow Epic to pass fake dependencies into initialization processes and swap them out with the real deal to optimize load times.
image
You may now remove your tinfoil hats… :saluting_face:… thank you.

So onto the tangible results of what this all means:

The Problem:

Invalid Player and Agent references are passed through Epics hacky initialization process into devices in the game allowing invalid Player/Agent references to attempt to be used prior to them being ready for use.

The Solution:

A player validation loop that ensures that the Player/Agent that you're referencing and hope to pass along into subsequent functions is actually going to work before you pass it.
    ValidatePlayer<private>(Agent:agent)<suspends>:void=
        TimeoutPeriod:float=180.0 # <- Time (seconds) before we abandon
        Interval:float=0.33 # <- Time (s) between attempts
        race: # <- race means whichever of the next 2 blocks finishes
              # first reigns supreme and the other is cancelled
            block: # <- Block 1 in the race
                loop:
                    if:
                        Player:=player[Agent] # <- Cast to player
                        Player.IsActive[] # <- Confirm player is active
                    then: # <- On Successful IsActive check
                        HandleValidPlayer(Player) # <- Pass them onto init
                        break # <- Break the loop
                    else: # <- On Failed IsActive check
                        Sleep(Interval) # <- See top: Interval
            block: # <- Block 2 in the race
                Sleep(TimeoutPeriod) # <- See top: TimeoutPeriod
                Print("Warning! ValidatePlayer: Timeout") # <- Logging
Without Comments / Scoping / Const Declarations
    ValidatePlayer(Agent:agent)<suspends>:void=
        race:
            block:
                loop:
                    if(Player:=player[Agent],Player.IsActive[]):
                        HandleValidPlayer(Player)
                        break
                    else:
                        Sleep(0.33)
            block:
                Sleep(180.0)

In Summary:

By passing players from the server join event or player spawner event into a validation function prior to forwarding them through any other initialization we can compensate for Epic's OSHA violat- "safety circumvention" so our players can enjoy the load time optimizations without simultaneously breaking our game logic or player init flow.

What this might look like in practice:

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Fortnite.com/Playspaces }

game_manager:=class(creative_device):
    @editable
    Spawners:[]player_spawner_device=array{}

    OnBegin<override>()<suspends>:void=
        for(Player:GetPlayspace().GetPlayers()):
            ValidatePlayer(Player)
            spawn. OnPlayerJoined()
        for(Spawner:Spawners):
            spawn. OnPlayerSpawned(Spawner)

    # Player Spawner Variation
    OnPlayerSpawned(Spawner:player_spawner_device)<suspends>:void=
        loop:
            Agent:=Spawner.SpawnedEvent.Await()
            spawn. ValidatePlayer(Agent)

    # Playspace Joined Variation
    OnPlayerJoined()<suspends>:void=
        loop:
            Player:=GetPlayspace().PlayerAddedEvent().Await()
            spawn. ValidatePlayer(Player)

    ValidatePlayer(Agent:agent)<suspends>:void=
        race:
            block:
                loop:
                    if(Player:=player[Agent],Player.IsActive[]):
                        HandleValidPlayer(Player)
                        break
                    else:
                        Sleep(0.33)
            block:
                Sleep(180.0)

    HandleValidPlayer(Player:player):void=
        block:
        # This is where your normal initialization would go
        # Aka make your custom player, map it, etc

PS:
Please note that any Epic internal processes related to players being added to ongoing games in between rounds or at other inappropriate times for the game are outside of our control for as long as we use their broken systems. Unfortunately there is no way to prevent these issues outside of not using their premade round system, and creating custom initialization and player handling wherever possible. Yes, this may mean creating your own custom round system.

Also note that if you set Join in Progress to Spectator epic spawns and immediately eliminates your fort_char which will trigger your listeners to begin initialization. Without additional validation checks such as Player.IsActive[] or FortCharacter.IsActive[] this can lead to failed or partially failed initialization.

6 Likes

Thank you for teaching this excellent lesson!
The last update broke disabling island start spawn pads, and enable Join in progress spawn pads are borken set to team index 1, and Island settings join in progress: team index 1 forces players on Team index 3 joining in progress.

I have Join in progress set to Team Index 1.
The players joining in progress are joining team 3 which is a player placement empty team, and is neither friedly, enemy, or neutral. Then the game mechanics throughout the game only allow team 1 and 2.

(I have tried two teams with team balancing, but players then spawn in the sky with join in progress set to spawn, which wont work as they are required to teleport in order to be assigned weapons, spawn location choice, animations, team based sepecific objectives, etc…)

Is there a way to force join in progress players to spawn on specific spawn pads as a designated team 1? Then team balance Team 1 and 2 afterwards only for join in progress?

P.S. Can you teach classes on this? Like make a video on the playspace and teams data in Verse? On udemy? :wink:

Do you have shuffle teams on? That setting is cursed and definitely dont use it. I dont really know the details but you can search the forums. (consider doing all the team stuff manually yourself or getting rid of that 3rd team imo)

I can’t really offer much help here outside of that and you should try using these utility functions for teams if you’re going to try to assign them yourself.

# Get Team From Index
(Device : creative_object_interface).GetTeam<public>(Index : int)<transacts><decides>:team =
    Teams := Device.GetPlayspace().GetTeamCollection().GetTeams()
    Teams[Index]

# Get Team From Agent
(Device : creative_object_interface).GetTeam<public>(Agent : agent)<transacts><decides>:team =
    Teams := Device.GetPlayspace().GetTeamCollection()
    Teams.GetTeam[Agent]

# Get Team Index Number From Agent
(Device:creative_object_interface).GetTeamIndex<public>(Agent:agent)<transacts><decides>:int=
    var TeamIndex : ?int = false
    GetTeams:=Device.GetPlayspace().GetTeamCollection()
    Teams:[]team=GetTeams.GetTeams()
    for (Idx := 0..Teams.Length - 1):
        if (Team := Teams[Idx]):
            if(GetTeams.GetTeam[Agent]=Team):
                set TeamIndex=option{Idx}
    TeamIndex?
2 Likes

Do you have limited spawns? Apparently theres an issue where if the teams out of spawns wonky stuff can happen. was just hearing about that.
Unfortuantely, no solution yet.

I will add that join in progress also causes TPS drop on the server, ref: TPS Drop on Player Joining Server

Thank you very much, you are super smart.
That verse is extremely helpful to know because I am planning on converting to Verse to assign teams but could not figure it out until now seeing how you gave operational sytax!
I am relatively new to verse, and this greatly helps me understand the functions of playspace better regarding get teams and playspace.

So far,
All devices rerouted and game behaves better following your great advice!
I have outed Team 3 in the game and only use team 1 and 2 now as you suggested, players spawn on either team and choose team 1 or 2 with class selector, and if they exist on team 1 they pass through the class selector even if they already belong on the team they spawned on.
Game Settings: No Shuffle Team and No limited spawns assigned.

One more question regarding teams.
Team 1 : Color Silver
Team 2 : Color Gold

When players on team 1 choose team 2, the scoreboard Team Color for the entire team (Color : Gold) changes to (Color : Silver).
Same occurs when Player on team 2 changes to team 1 after choosing a team. The Scoreboard Team Color Changes to the opposing team color.

This is especially the case when a player joins in progress and when spawning. is assigned a team during a round of gameplay, which also Changes the Scoreboard Team Colors for Every player on that dedicated team.

I was wondering, gosh I could use help with a few bugs occuring in my game and engine but they are not relevant to teams and verse.

Thank you @LionUnchained

1 Like

Hey @LionUnchained,
I have a question about Initializing the player and making the custom player on spawning into the round.
What would I add after block if I am only now assigning teams 1 and 2 at game start?

You would replace block: that’s just stating that you’re writing a code block which is actually inferred whenever you write code.

MyFunction():void=
   Print("Hello")

is the same as

MyFunction():void=
   block:
        Print("Hello")

And you’d write whatever initialization you have to write here. If you want to learn how to assign teams I suggest the documentation where there are examples and tutorials showing you how to do this.