lightyear icon indicating copy to clipboard operation
lightyear copied to clipboard

Steam does not work in headless mode

Open SueHeir opened this issue 4 months ago • 10 comments

Recently switched code to allow game to run the server with minimal plugins. Switching from a 'fake' headless server to a true headless server without a render breaks steam connections.

Discovered this by testing a gui-server and a client on a different computer and noticed it was working when nothing else was working.

pub fn new_fake_headless_app() -> App {
    let mut app = App::new();

    app.add_plugins(
        DefaultPlugins
            .set(LogPlugin {
                custom_layer,
                level: Level::INFO,
                filter: "lightyear_sync=debug".to_string(),
                ..default() //lightyear::client::prediction::rollback=debug,lightyear::server::prediction=debug
            })
            .set(ImagePlugin::default_nearest())
            // replaces the bevy_winit app runner and so a window is never created.
            .set(WindowPlugin {
                primary_window: None,
                exit_condition: bevy::window::ExitCondition::DontExit,
                ..default()
            })

            // WinitPlugin will panic in environments without a display server.
            .disable::<WinitPlugin>(),

    );

    // ScheduleRunnerPlugin provides an alternative to the default bevy_winit app runner, which
    // manages the loop without creating a window.

    // // ScheduleRunnerPlugin provides an alternative to the default bevy_winit app runner, which
    // // manages the loop without creating a window.
    app.add_plugins(ScheduleRunnerPlugin::run_loop(
        // Run 60 times per second.
        Duration::from_secs_f64(1.0 / FIXED_TIMESTEP_HZ),
    ));
    // app.add_plugins(ScheduleRunnerPlugin::default());
    app
}

pub fn new_headless_app() -> App {
    let mut app = App::new();

    app.add_plugins((
        MinimalPlugins,
        log_plugin(),
        StatesPlugin,
        DiagnosticsPlugin,
        AssetPlugin::default(),
        ScenePlugin::default(),
        ImagePlugin::default_nearest(),
        // SpritePlugin::default(),
    ));
    app.init_asset::<image::Image>();
    app.init_asset::<image::TextureAtlasLayout>();
    app.insert_resource(Time::<Fixed>::from_hz(FIXED_TIMESTEP_HZ));

    app
}

SueHeir avatar Aug 12 '25 01:08 SueHeir

That seems strange because I ran the examples using steam in headless mode, what errors do you see?

cBournhonesque avatar Aug 12 '25 04:08 cBournhonesque

Console log from server when trying to connect:

2025-08-12T04:27:31.301332Z  INFO bevy_code_gnome::networking::server: remote id added, adding replication sender 17851v1
2025-08-12T04:27:31.301520Z  INFO bevy_code_gnome::networking::server: New connected client, client_id: 76561199800574028. Spawning player entity..
2025-08-12T04:27:31.320701Z  WARN aeronet_io::packet: 17850v1 has 1 received packets which have not been consumed - this indicates a bug in code above the IO layer  

The client never spawns a player and seems to keep its connection going

SueHeir avatar Aug 12 '25 04:08 SueHeir

So far, I have tried commenting out UdpServerIo and NetcodeServer, and with a fake_headless_app it works, with a headless_app it doesn't work. Might first see if I can replicate it in my menu example, so I wouldn't worry about it too much right now. A lot of my code has changed from the no render rework

SueHeir avatar Aug 12 '25 04:08 SueHeir

This is currently happening in lightyear-menu

SueHeir avatar Aug 12 '25 05:08 SueHeir

I also noticed that your examples don't use peer-to-peer if I'm recalling correctly

SueHeir avatar Aug 13 '25 00:08 SueHeir

I also noticed that your examples don't use peer-to-peer if I'm recalling correctly

I believe they do when steam is enabled: https://github.com/cBournhonesque/lightyear/blob/main/lightyear_steam/src/lib.rs#L62

cBournhonesque avatar Aug 13 '25 02:08 cBournhonesque

Here is what I was talking about. I'm using ListenTarget::Peer not ListenTarget::Addr, I connect via steam with the steamId so players don't have to worry about port forwarding. I doubt this is the issue but thats the only difference I can think of

SueHeir avatar Aug 13 '25 03:08 SueHeir

This is the full trace from when the player connects 2025-08-13T034839.011108Z TRACE lig.txt

SueHeir avatar Aug 13 '25 03:08 SueHeir

So far, I have tested the following for the steam.run_callbacks() Adding a NonSend resource to the function to make sure it runs on the same thread (my steam_singleclient is in a arc mutex and I call lock().run_callbacks(), but in this situation nothing else has the arc so lock should always work) Setting system to run before LinkSet::Receive, and both before or after IoSet::Poll

SueHeir avatar Aug 13 '25 04:08 SueHeir

I cannot help without a full reproducing example. The examples work with steam server running in headless mode: https://github.com/cBournhonesque/lightyear/pull/1161 Can you reproduce this in the examples?

cBournhonesque avatar Aug 16 '25 03:08 cBournhonesque