Facepunch / Facepunch.Steamworks

Another fucking c# Steamworks implementation
MIT License
2.83k stars 341 forks source link

NullReferenceException D:/a/Facepunch.Steamworks/Facepunch.Steamworks/Facepunch.Steamworks/SteamNetworkingSockets.cs:105 #768

Open DarrelCusey opened 2 months ago

DarrelCusey commented 2 months ago

Describe the bug I have searched for this error in both open and closed issues, and did not find it.

I am on Unity 2021.3.37f1. I am receiving the NullReferenceException in title after following the installation instructions exactly. I have /Assets/Plugins/Facepunch.Steamworks/ and under there is the contents of the "Unity" folder from the archive (it has the redistibutable_bin folder and the Facepunch.Steamworks.Win64.dll along with the other platform DLLs).

To Reproduce Steps to reproduce the behavior:

  1. Create the "MyServer.cs" exactly as shown in the example on https://wiki.facepunch.com/steamworks/Creating_A_Socket_Server (Code for this is shown below)

  2. Create "MyServerManager.cs" as a Monobehaviour that can be attached as a component to an empty object in the scene hierarchy. (Code for this is shown below).

  3. Attach MyServerManager.cs to an empty game object in the scene hierarchy.

  4. Click Run

  5. See error:

NullReferenceException: Object reference not set to an instance of an object Steamworks.SteamNetworkingSockets.CreateNormalSocket[T] (Steamworks.Data.NetAddress address) (at D:/a/Facepunch.Steamworks/Facepunch.Steamworks/Facepunch.Steamworks/SteamNetworkingSockets.cs:105) MyServerManager.Start () (at Assets/Scripts/Steam/MyServerManager.cs:11)

Calling Code

(just copy-pasted example code as seen on https://wiki.facepunch.com/steamworks/Creating_A_Socket_Server)

MyServer server = SteamNetworkingSockets.CreateNormalSocket<MyServer>(Steamworks.Data.NetAddress.AnyIp(27862));

MyServer.cs:
--------------
using System;
using Steamworks;
using Steamworks.Data;

public class MyServer : SocketManager
{
    public override void OnConnecting(Connection connection, ConnectionInfo data)
    {
        connection.Accept();
        Console.WriteLine($"{data.Identity} is connecting");
    }

    public override void OnConnected(Connection connection, ConnectionInfo data)
    {
        Console.WriteLine($"{data.Identity} has joined the game");
    }

    public override void OnDisconnected(Connection connection, ConnectionInfo data)
    {
        Console.WriteLine($"{data.Identity} is out of here");
    }

    public override void OnMessage(Connection connection, NetIdentity identity, IntPtr data, int size, long messageNum, long recvTime, int channel)
    {
        Console.WriteLine($"We got a message from {identity}!");

        // Send it right back
        connection.SendMessage(data, size, SendType.Reliable);
    }
}

MyServerManager.cs:
-------------------------
using Steamworks;
using UnityEngine;

public class MyServerManager: MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        MyServer server = SteamNetworkingSockets.CreateNormalSocket<MyServer>(Steamworks.Data.NetAddress.AnyIp(27862));
    }
}

Expected behavior I do not expect to receive a NullReferenceException

Desktop (please complete the following information):

Additional context When I double-click on the NullReferenceException in the console, it attempts to open D:/a/Facepunch.Steamworks/Facepunch.Steamworks/Facepunch.Steamworks/SteamNetworkingSockets.cs. which, of course, it cannot do because I am not the developer of this plugin :)

Things I have Tried to Resolve Issue

  1. Attempted to remove the /Assets/Plugins/Facepunch.Steamworks folder and re-install (have tried this 3 times)
  2. Reimported all Assets from the Unity Editor
  3. Deleted the .sln and csproj files from the project root and had Unity rebuild them
  4. Manually searched all files in the project for the "D:/a/Facepunch.Steamworks" path prefix, but was unable to find it in any files
DarrelCusey commented 2 months ago

Ahh, I see the new way to startup a server is below. So, it looks like this is just wiki documentation issue.

var serverInit = new SteamServerInit( "gmod", "Garry Mode" ) { GamePort = 28015, Secure = true, QueryPort = 28016 };

try { Steamworks.SteamServer.Init( 4000, serverInit ); } catch ( System.Exception ) { // Couldn't init for some reason (dll errors, blocked ports) }

DarrelCusey commented 2 months ago

However, I am still experiencing an issue with trying to get the server list from the client.

My core issue is that either (1) The SteamServer is not properly listing or advertising itself or (2) The SteamClient is not correctly querying the server list. So, effectively, my server cannot be discovered.

Here is some more information about my setup. Maybe this will help troubleshoot the issue?

  1. I updated the SDK to 159, and that took care of the NRE in the original ticket. The client and server now successfully connect to Steam.

  2. I am running the server on a Window 10 workstation, and the client on a Windows 11 laptop - so they are separate machines.

  3. The server is using Anonymous login, and the Steam application is not running on the server.

  4. The client IS logging in as my regular Steam account and I have the Steam application running normally on the client laptop.

  5. I am using Unity and Facepunch.Steamworks (both latest versions)

  6. My updated server and client code are shown below

  7. For the server, the "IsValid" flag does set to true, and I do receive the message "Steam Server details set" and "Steam Server Connected" which is from a callback, so I know that Steam is at least responding to the server as-expected.

  8. Game.steamID is: public static readonly uint steamID = <this is my correct steam id, I triple-checked>;

  9. I do have the ports opened on the Windows firewall for UDP and TCP as both inbound and outbound rules for both the workstation and the laptop. Steam should handle the NAT transversal, so I'm stumped as to why I can't retrieve a server list. I'm sure it's me, but I'm stumped.

ZCPServer.cs

`using System; using Steamworks; using UnityEngine;

public class ZCPServer : MonoBehaviour { public bool IsValid = false; void Start() { var serverInit = new SteamServerInit("zombiecityplanner", "Zombie City Planner") { GamePort = 28315, Secure = true, QueryPort = 28316, };

    try
    {
        SteamServer.Init(Game.steamID, serverInit);
        SteamServer.LogOnAnonymous();
        SteamServer.ServerName = "Zombie City Planner Public Test Build";
        SteamServer.MapName = "Main";
        //SteamServer.SetKey("doorSeed","posx_posz"); // next step
        SteamServer.MaxPlayers = 8;
        SteamServer.Passworded = false;
        SteamServer.OnSteamServerConnectFailure += OnConnectFailure;
        SteamServer.OnSteamServersConnected += OnConnected;
        SteamServer.OnSteamServersDisconnected += OnDisconnected;
        SteamServer.GameTags = "secure,version:0.0.1";
        SteamServer.AdvertiseServer = true;
        Debug.Log("Steam Server details set");
    }
    catch (System.Exception e)
    {
        Debug.LogErrorFormat("Could not initialize SteamServer: {0}", e.ToString());
        // Couldn't init for some reason (dll errors, blocked ports)
    }
}

private void OnDisconnected(Result result)
{
    Debug.LogFormat("Steam Server Disconnected: {0}", result.ToString());
}

private void OnConnected()
{
    Debug.LogFormat("Steam Server Connected");
}

private void OnConnectFailure(Result result, bool arg2)
{
    Debug.LogFormat("Steam Server Connect Failure: {0}, {1}", result.ToString(), arg2.ToString());
}

void Update()
{
    SteamServer.RunCallbacks();
    IsValid = SteamServer.IsValid;
}

void OnApplicationQuit()
{
    Debug.Log("Application is quitting. Steam Server performing cleanup.");
    Debug.Log("Shutting down SteamServer");
    Steamworks.SteamServer.Shutdown();

    // Example: Save game data
    // SaveGameData();
}

} `

ZCPClient.cs

`using UnityEngine; using Steamworks; using Steamworks.Data;

public class ZCPClient : MonoBehaviour { Steamworks.ServerList.Internet RequestServerList;

void Start()
{
    try
    {
        SteamClient.Init(Game.steamID);
    }
    catch (System.Exception e)
    {
        Debug.LogErrorFormat("Steam Client Init Failed with exception {0}", e.ToString());
    }
}

void Update()
{

    SteamClient.RunCallbacks();

    if (Input.GetKeyDown(KeyCode.P))
    {
        Debug.Log("Received request for server list");

        RequestServerList = new Steamworks.ServerList.Internet();
        RequestServerList.AddFilter("secure", "1");
        RequestServerList.AddFilter("and", "1");
        RequestServerList.AddFilter("version", "0.0.1");
        RequestServerList.OnChanges += OnServersUpdated;
        RequestServerList.RunQueryAsync(30);
    }
}

void OnServersUpdated()
{
    Debug.Log("RequestServerList.OnChanges received");

    // No reponsive servers yet, bail
    if (RequestServerList.Responsive.Count == 0)
        return;

    // Process each responsive server
    foreach (var s in RequestServerList.Responsive)
    {
        ServerResponded(s);
    }

    Debug.Log("Clearing RequestServerList");
    RequestServerList.Responsive.Clear();
}

void ServerResponded(ServerInfo server)
{
    Debug.LogFormat("{0} Responded!", server.Name);
}

void OnApplicationQuit()
{
    Debug.Log("Application is quitting. Steam Client performing cleanup.");
    Debug.Log("Shutting down Steam Client");
    SteamClient.Shutdown();

    // Example: Save game data
    // SaveGameData();
}

} `

Fobri commented 2 months ago

Have you set your "Product name" in Steamworks app config in the dedicated server section to your appId? Thats what did the trick for me.

DarrelCusey commented 2 months ago

Thanks for the reply Fobri - yes, I have that set, and I seem to be able to login with the server as anonymous now. The server seems to be up and running, and it seems to be advertising itself.

However, when the client requests a server list, nothing is returned. Basically, my server is undiscoverable.