#LethalNetworkAPI
1 messages · Page 2 of 1
haven't seen that so will take a look after work today
ah I see
yeah I likely am still good since it uses custom messages instead of rpcs, but I will likely need to adjust a little here and there so I'm still gonna take a looksies
cool, thanks for the quick reply, hope for you its not much to do!
request to bump dependencies: https://github.com/Xilophor/LethalNetworkAPI/issues/32
Thanks!
I feel like I'm probably being silly but I can't seem to figure this out. All I want to do, is have a synced bool. When someone joins the lobby it is false for everyone while some code of mine runs, then it becomes true for everyone. When the next person joins, it goes back to false for everyone and when they're finished, it becomes true again.
Here's where I have that bool.
namespace MaterialAssetRestorerCore
{
internal static class MaterialsNetworkSync
{
public static LNetworkVariable<bool> materialsInitialized = LNetworkVariable<bool>.Connect(
identifier: "materialsInitialized",
onValueChanged: OnMaterialsInitializedChanged,
offlineValue: false,
writePerms: LNetworkVariableWritePerms.Everyone
);
private static void OnMaterialsInitializedChanged(bool oldValue, bool newValue)
{
MaterialAssetRestorerCore.Logger.LogWarning($"Materials initialized changed from {oldValue} to {newValue}");
}
}
}
And here's in theory where it changes
[HarmonyPatch(typeof(StartOfRound))]
public class MaterialInit
{
public static List<MaterialInformationContainer> materialInformationContainers = new List<MaterialInformationContainer>();
//after StartOfRound, initialize the materials
[HarmonyPostfix]
[HarmonyPatch(typeof(StartOfRound), nameof(StartOfRound.Start))]
public static void InitializeMaterialsPatch()
{
CoroutineHelper.Instance.StartCoroutine(MaterialInit.InitializeMaterialsCoroutine());
}
public static IEnumerator InitializeMaterialsCoroutine()
{
MaterialsNetworkSync.materialsInitialized.Value = false;
MaterialAssetRestorerCore.Logger.LogInfo("Initializing materials...");
foreach (MaterialInformationContainer container in materialInformationContainers)
{
yield return MaterialGet.GET_material(container.BaseMaterial, container.PrefabName, container.SceneName, (foundMaterial) =>
{
if (foundMaterial != null)
{
container.replacementMaterial = foundMaterial;
}
});
}
yield return new WaitForSeconds(10); //debug testing. REMOVE THIS
MaterialAssetRestorerCore.Logger.LogInfo("Finished initializing materials.");
MaterialsNetworkSync.materialsInitialized.Value = true;
}
}
All I want to do is use that bool to determine if the ship lever can be pulled. It seems to work fine for the host, but then they can pull the lever when they're done even if another player joins and hasn't finished the initialization process
there's a couple things that could be the cause here, I'll do some testing/investigating on my end and see whats happening
Alrighty! Thanks!
okay so I think I figured it out, seems like a logic issue on my part, and then a "race" condition (that always happens); I'll make a write-up and work on publishing the fixes once I get some food
Oh interesting. Thanks!
okay, so I think I have a fix on my end - doing some validating to make sure
but essentially, the network variables weren't getting correctly updated when a client joined the server, which in your case would have the variable still be false, and wouldn't actually update the variable since it believed it was still the same value
got a fix so that it correctly updates the variable, as well as gives an error when it hasn't synchronized yet, as well as a new property to see if it's synchronized
the race condition on your end is that StartOfRound.Start is before the variables are synced from the server, and thus it isn't actually connected yet
I would either a.) wait for the variable to show as synchronizing (I'll add an event to make this easy as well)
or b.) use a combination of LNetworkVariables and LNetworkEvents - have the variable controlled by the server which dictates whether the game can start or not, and use the event for clients to let the server know that they have initialized the materials
which would fix an issue I noticed where someone could join right before someone else finished initializing materials, and the bool would be true even though someone is still loading (client 1 joins -> false -> client 2 joines -> no change -> client 1 finishes -> true -> client 2 finishes -> no change)
aight, I pushed my changes to a branch on the repo, will review tomorrow to make sure I'm not missing anything and release
Interesting. I’ll check it out sometime. Thanks!
maybe this is why i was sometimes seeing some oddities before... like the client was always 2 steps behind the host... hmm 😮
Hey, sorry, but I don’t think this ever got uploaded to Thunderstore. Is it still being worked on?
sorry got caught up in other stuff - took another look and made some bug fixes - pushing through now
I'll see if I can get wiki update tonight, but otherwise the two main additional things is IsInitialized - whether the variable is connected to the server or not; and OnInitialized - event that gets called when the variable gets initialized (value gets updated on client join, then event is called)
lmk if to run into any bugs with the new version
should be v3.4.1 (v3.4.0 will work too but not deployed to nuget - issues with workflow fixed in the .1)
Ok! I’ll try to look into it tomorrow . Thanks!
does OnInitialized not run for the hosting player? In a StartOfRound.Start postfix I thought MaterialsNetworkSync.waitingPlayerCount.OnInitialized += InitializeMaterialsPatch; would invoke that function but it never seems to until another player joins and then it does run for them (but not the host). I'm probably doing something wrong though unless LAN for some reason is breaking stuff
it should, I'll double check
sorry to get back so late, it seems fine working on my end (LAN); where are you running that code?
you should see any logs appear just before [Debug :LethalNetworkAPI] Created UnnamedMessageHandler instance. on the server
it'll happen later on the client
there is one bit that I overlooked though, and would like your opinion - should the client run the OnValueChanged event, even if the variable isn't synchronized yet (it'll run when the client's value gets updated to match the server value when joining), or should it only run when the variable is synchronized (ignoring the first update to get it to match the server)?
I’ll check and see sometime. I probably just did something wrong on my end then.
For this, I feel like maybe it should only run once synchronized. Not sure though
I was thinking this myself, just wanted to get a second opinion - made the one-line change and pushed the update so that it doesn't call the OnValueChanged upon the client joining (would occur previously if the value was different than the offline value)
ok, I feel like I need some help. I'm probably doing something wrong but I can't exactly figure out what. So, a piece of current code. In my mind, this should postfix StartOfRound and subscribe to waitingPlayerCount's OnInitialized event (I switched from a bool to a num to avoid person A finishing before B and setting it true) and once it's inititialized the coroutine basically gets kicked off. I'm testing just solo and nothing ever prints beyond "Waiting for network variables...". It just doesn't seem the event ever invokes.
[HarmonyPostfix]
[HarmonyPatch(typeof(StartOfRound), nameof(StartOfRound.Start))]
public static void WaitForNetworkVariables()
{
MaterialAssetRestorerCore.Logger.LogDebug("Waiting for network variables to initialize before starting material caching...");
MaterialsNetworkSync.waitingPlayerCount.OnInitialized += InitializeMaterialsPatch;
}
public static void InitializeMaterialsPatch()
{
CoroutineHelper.Instance.StartCoroutine(MaterialInit.InitializeMaterialsCoroutine());
}
public static IEnumerator InitializeMaterialsCoroutine()
{
MaterialsNetworkSync.waitingPlayerCount.Value++;
SceneLoadPatches.MuteSceneStateChangeEvents(); //prevent other mods from running code on scene load/unload
MaterialAssetRestorerCore.Logger.LogInfo("Initializing materials...");
now, it seems this prints first by quite a bit. is it I'm subscribing too late?
I do believe that's the case
in my test, I subscribed in my plugin's awake method - you can subscribe at anytime as long as the game's running; just if you subscribe after the variable is initialized, it won't run (until you rehost/rejoin)
Got it. Alright I’ll try that
I could make it easier by supplying a param in the constructor, although I have to be careful as I don't want to break compatibility with mods not referencing the new version when compiled
and the way to get around it looks a bit bad imo (not that it's really a reason to not implement it)
Subscribing in the awake makes sense tbh. I just didn’t think to do that 🙃
wait wait wait, actually I can't do that. I need to run in StartOfRound because the prefabs I'm trying to grab materials out of don't seem to exist until then. When I tried subscribing in the awake it seemed it invoked way too early still in the menu. What I'm kind of confused about though is how that invoked seemingly before I was in a game but going somewhat back to the old way, IsInitialized is false in StartOfRound. I should not be doing this so late