#[WIP] LobbyCompatibility
1 messages · Page 1 of 1 (latest)
LethalAPI and LC_API both have some utilities for dealing with this, but they're far from ubiquitous right now.
in my opinion, the best solution is a single-purpose, fairly light network compatibility library. the benefits would be:
- fairly easy to update upon game updates
- likely won't break anything if you add it as a dependency
- should be as easy as adding a single attribute to define how compatible your mod is
- can be finished in a matter of days
I'm willing to work on this, i just want to make sure something is made that properly works for the entire community, and can be maintained long term
with the goals being:
- an easy way to browse public modded lobbies, with an alert that tells you what mods to change if it fails
- a centralized place to block server-side mods from doing challenge runs
- a better way to block vanilla users from seeing lobbies that they won't be able to join
Attributes would probably look like this, a slightly modified version of what Jotunn uses:
public enum CompatibilityLevel
{
/// <summary>
/// Mod is not checked at all, VersionStrictness does not apply.
/// </summary>
ClientSide = 0
/// <summary>
/// Mod is only required by the server. VersionStrictness does not apply.
/// </summary>
ServerSide = 1
/// <summary>
/// Mod must be loaded on server and client. Version checking depends on the VersionStrictness.
/// </summary>
EveryoneMustHaveMod = 2,
/// <summary>
/// If mod is loaded on the client, it must be loaded on the server. Not every client needs to have the mod installed. Fairly niche and only applies if your mod works fine when a client doesn't have it. Version checking depends on the VersionStrictness.
/// </summary>
ServerMustHaveMod = 3
}
public enum VersionStrictness : int
{
/// <summary>
/// No version check is done
/// </summary>
None = 0,
/// <summary>
/// Mod must have the same Major version
/// </summary>
Major = 1,
/// <summary>
/// Mods must have the same Minor version
/// </summary>
Minor = 2,
/// <summary>
/// Mods must have the same Patch version
/// </summary>
Patch = 3
}
example usage would be [NetworkCompatibility(CompatibilityLevel.EveryoneMustHaveMod, VersionStrictness.Minor)]
the big questions I have are:
- what should default network compatibility be? we could either have it be ClientSide or ServerSide. IMO ClientSide would be better, just to avoid EVERY client side mod having to label itself
- do those attributes above cover every common usecase?
- are people actually willing to adopt the attributes, or is it too late?
this could also be put into an existing library (CompatibilityChecker, LC_API, LethalAPI) but IMO starting fresh with a simple, easy-to-update mod would be the way to go
as far as I'm aware no mod has tried to implement proper plugin-defined lobby syncing like this yet
pinging semi-relevant people for comment @sharp ridge @lament perch @dense forum @humble elm @earnest pilot
seems like how r2api handles it in risk of rain
imo defaults should be
Compat: - ClientSide
Version: -Major
but this is definitely a necessity
Yeah, I've never modded ror but it seems like it used a similar system
Are mods server side by default in ror ooc? How's that handled
Is r2api just used everywhere so it doesn't really matter
it is where EveryoneMustHaveMod comes from
lol
also there likely is a way to "enforce" this on all mods with the defaults
though whether that should be done or not is an important question
it doesn't define serverside or clientside
because there isn't really a reason to do so, since they are just unsynced by their nature
hmm, I still feel like having the difference between clientside and serverside could be useful somewhere but idk
mostly for the cheating in challenge runs bit, but I'm not sure the best way to handle it in general
ror just blocks any mods from prismatic trials right
i do think being able to use clientside qol mods on challenges could be nice but that obviously comes with some problems
especially if mods are labeled clientside by default
yeah, infinite sprint it client side
the problem with having a serverside or clientside tag will always have those problems
if there is no defaults they can just not tag their mods
clientside default is bad tho
that'll for sure cause issues, because it is really hard to establish standards, i would assume most people won't add the attributes
idk, serverside default seems like the correct option
but EVERY client mod developed (likely thousands at this point) breaking lobby compatibility until they update seems like it's going to be a disaster
Yeah it's probably too late, I think even having the top 20 mods labeled would help massively though
this modding community is too scattered to push any kinds of standards
idk, I think it could happen if:
- we updated the wiki
- ping announcements were made in both modding servers
- some people made PRs for larger mods
i think the best solution would be to just not worry about it and have default behaviour be noneedforsync
because that'll cause the least issues out of the box
sadly i don't think this'll be a solution for cheating or anything either way
because they could just not install this mod
:p
Oh yeah I'm not worried about stopping cheating, it's probably not possible, I just want to be able to find public lobbies lol
I can port my features to a standalone mod tbh. Can probably have it done in a day? I've been wanting to expand the lobby functionality anyway.
my point is, what you really should be doing is making it opt-in, and having it be as unintrusive as possible
yeah
yeah, that's probably the best option
#1194412635932856440 message
opt in with large mods that will break (biggerlobby, morecompany, lethallib) marked as needed syncing
yeah
worst case it can just show your different mods on error
That could work, ideally im thinking something like
DEAD simple
Just the attributes and a few networking/UI patches
at least for now
@gleaming ice I think you were also talking about something similar earlier, do you have any opinions on what to do if a new system like this was being made
I think:
- ClientSide
- ServerSide
- Everyone
Are the three important ones tbh?
Basically just a truth table of
---------------------------
| Client | Server |
| X | |
| | X |
| X | X |
---------------------------
Either those three, or the two values of no sync/sync
the second option is what r2api does
and it makes sense because in reality, there is not a lot of situations where you need to know whether a mod is server or clientside
because either one is just no sync
It's useful for other mods to know, I feel like?
maybe, but i cannot actually think of a case where a mod needed to know it
The system I was working on in LethalAPI was a simple attribute you add (akin to BepInEx attributes) to indicate whether a mod is required. The rest of the functionality surrounding it then added plugin info to the lobby (GUID + version). If any required mods are found, it was set to unjoinable / invisible for vanilla. Modded users of the API do a check with the lobby's plugin data and compare versions.
I felt like that was a relatively elegant solution.
I had some plans to add an on-hover list of required mods for lobbies
definitely something we should try to think of now
since whatever is decided on probably can't be changed
I'll port over my stuff to a separate mod and toss it up as a repository?
sure, i'll probably have some input/changes once it's up
i need to make some mockups of some UI ideas i had
enforce it but default it to the mod defaultign to ClientSide, so that you don't piss off people
at appropriate time just iterate through the chainloader loaded plugins list
the enums looks fine to me
I'm not a fan of overcomplicating it tbh. The enums at the top seem a bit too much.
easiest way to do so is the nosync/sync; default nosync, and have mods add an attribute to set it to sync
the fourth enum value is probably almost never going to be used tbh
and even if it would, it really should be everyone must have/sync
the last one seems a bit weird but the other 3 make sense, client side server side and both
Doesn't it basically boil down to "This mod is required" and "This mod isn't required", in practice?
yeah
yeah
pretty much
(Is that yeah @ me or HD)
you
at you lol
So, do we want to go with a simple "required" tag, then?
It's what I had for LethalAPI
But I don't mind cutting it out
And then have some "smart" logic to check versioning and the like
I think the slightly more detailed enums would probably do the trick, I could see the specific difference between Client side and Server side coming in handy
plus the ability to define version strictness
but bare minimum, the required tag would probably work
the last one i saw suggested for r2api actually when i was looking around in the r2 modding discord lol
basically it boils down to, you can use this mod only if the server has it installed, for example in the case of a cheat menu that requires client -> host messages or something, but people don't need it installed in order to join
Or, realistically, give me like 15 - 20
A mod that is flagged required should block a user that has it from joining a server that doesn't have it (which is how I did it in LethalAPI)
which makes sense
Not Required
- User: Can join any server
- Server: Anyone can join server
Required
- User: Can join any server that also has it
- Server: Anyone that has it can join
With the stipulation that versions also match
(E.g. major version matches)
i think version strictness settings is something that would be nice
def
As in, perfect matching versions?
Ah
A setting
Yeah, that's definitely very doable
yeah, that's what the version compatibility attribute was for
i'm not sure what should be default, probably minor?
I can probably get it to work within the next hour or so. No UI stuff was written for the API yet though - if anyone wants to experiment with that.
yeah
major seems like a lot, 99% of mods are always going to be on major version 1
Agreed
i'm permanently on major version 0
forever in beta
because i never rewrite my mod
based on the semantic versioning if mods used it correctly it should be major; but whether devs do that or not is another thing
yeah thats what i go by
lol
the only time i increase my major version is if i rewrite my code
If they're using BepInEx, I'm pretty sure they're also automatically using System.Version, so no funky custom versions afaik
definitly do minor version by default
yeah
which also supports build numbers
0.10.4.2355 
it just parses the version string
I see that make sense, it won't be used that much but there are definitly use case
yeah in reality i don't think it would be used much
maybe like 10 mods would use it, but it's still something to consider
what actually happens when you run a client rpc if not everyone has a mod installed
this is not something i have tried
i would assume it wouldn't freak out
custom one (in most cases) the object owning it wouldn't even be spawned in
idk how mirror does it but worth checking if it doesnt keep resending it too
oh actually the error would come way earlier
which likely would cause its own errors
when the prefab was attempted to be spawned
if you try to join with desynced network prefabs it won't let you
yeah, it wouldn't even let you join
so networkbehaviours couldn't even be used for messaging in the servermusthavemod type mods
lol
that's like the only thing I'd ask the dev to put them in themselves, a customizable message box so that the server can send arbitrary text to client so that they know why they got disconnected
for vanilla clients
definitely would be nice
there might be a way to do that already with lobby data, i'm not sure
thing is
I think max's lobby thing for lethalAPI did that?
to actually give an accurate message of missing mods or something, the server would have to receive a list of mods from the client, in which case the client would have to have the mod installed aswell in order to send that list
in which case you can just implement the custom message boxes yourself anyway
lol
I did something similar-ish
But it's simple enough to do
It'd be great if zeekerss added a simple "modded" field that he checks in vanilla tbh.
doesn't the new version have lobby tags?
It has tags, but I generally don't use public lobbies, so I haven't used them yet
Not sure how they work?
definitely would be nice to have a modded field in vanilla
is there no other way to hide modded lobbies from vanilla as-is
There is
iirc you can just set the joinable lobby data to false
Which is what I did with LethalAPI
And then had a custom modded_joinable field that I made users of the API check
If that was joinable, it then did the plugin data comparison
honestly seems like all we need to do is tack on version strictness and it's mostly finish tbh
Vanilla Joinable?
- Yes -> Check if client has any required plugins
- Yes -> Do not join
- No -> Join
- No -> Modded Joinable?
- No -> Do not join
- Yes -> Plugin requirements match?
- Yes -> Join
- No -> Do not join
That was the current flow I have
Just needs the version strictness added and the requirements check changed to take it into account, then.
How does this differ from CompatibilityChecker, though?
Not entirely sure what that mod does.
CompatibilityChecker makes a list of mods and shows you the differences when you error out on joining a lobby
Ah, so it requires a perfect match?
technically no, it will let you join any lobby
it just displays the data if you error out
i assume this mod would have a similar error screen, i'm working on some UI concepts right now
The error screen I gave was a list of mod mismatches iirc
Not sure if I ever got around to pushing that, though.
E.g. "Missing X mod" and "Y mod is out of date. Requires version A.B.C"
Can probably make it fancy tbh
Like a diff, but of required mods only
- Missing "MoreCompany" version 1.2.3
- Missing "LateCompany" version 2.3.4
! "MoonOfTheDay" version mismatch. Needs version 3.4.5
+ Required mod "UncertainCompany" was not found on the server
That's roughly what I had in mind as well.
I was thinking a hover box for the lobbies to show the mismatching mods would be nice.
for sure
So you don't have to go through the join / error loop to find out what you're missing.
we might have to expand the error box, ideally you should be able to see:
- the full list of mods they have installed
- the mods YOU have that they don't
- the mods THEY have that you don't
Yeah, a diff
could be nice to have a "filter compatible" to only see servers you can join too
so question, I've got a config option for my networked mod setup that can make it act as a client-side mod (removes all networking elements and players can join vanilla lobbies with it). Would I be able to define two separate compatbility strings based on the config option?
i think default should filter compatible
and a checkbox to show incompatible
thats how most games handle it
I'd show something like this on error:
Client side | Server side | Reason
________________________________________________
+ Mod 1 (1.2.3) | Mod 1 (1.2.4) |
- Mod 2 (1.2.3 | | Server missing mod
- | Mod 3 (1.2.3) | Client missing mod
- Mod 4 (1.2.3) | Mod 4 (1.3.1) | Client mod outdated
+ Mod 5 (1.2.3) | Mod 5 (1.2.3) |
(Low key proud of this 👌)
default filter compatible, maybe filter incompatible automatically if 0 exist
people who have too many mods should be able to see what they need to change to join a public lobby
It's been on my to-do list for a while: https://github.com/steven4547466/LC-API/issues/11
yeah, i remember you talking about it before
hmm, maybe an option to change the type at runtime could be added
instead of using the attribute, for mods that need it
i think it is good for it to be standalone from any api
Thoughts? @cyan flame
Agreed
could always add a bepin dependency for it to things like lethallib force a lot of people to install it
lol
definitely would be nice, I have two mods that I plan on doing this for
that looks good, i'd have to see how it looks when displayed ingame
ideally grandma should be able to parse it
It's a simple enough system, and APIs might be incompatible with each other
Locking it down to one popular API would low key suck
We were just going to do what jotunn does ¯_(ツ)_/¯
@humble elm @lament perch ?
i think this is probably going to be very similar to what jotunn does
the enums i proposed are basically identical
i mean yeah that makes sense
Yeah jotunn is also an api is what I was getting at.
yeah it makes sense
For better or for worse, Lethal Company's API landscape is fairly fractured. I wouldn't put extremely useful functionality like this in any one API at this point.
yeah
speaking of this, originally i thought this game having all the different apis was messy, but it turned out pretty okay
compatibility wise
tbh I would probably push to add it to LC-API but there's so much completely false information about it going around that people WILL violently resist depending on it
just have major apis/libs have a dependency in thunderstore (or even bepinex dependency)
yeah that is what i was suggesting
Sounds like a fair plan
doesn't have to be a mod dependency, just a dependency in the manifest
Aye
so people who use modmanager will automatically install it
(which is most)
I've honestly stopped paying attention to people who think LC API is still breaking their games lol ¯_(ツ)_/¯
yeah i don't really understand where that came from
the assetbundle issue ages ago
if anything it would be more company xd
mainly
because an old version of LC API did break the game lol
there was like 3 days where LC API broke every single mod
Early LC API was... interesting
But the original dev doesn't even work on the api atm
apparently 3 days was enough to lose confidence of a bunch of modders lol
I mean it's still the most downloaded mod, is it not?
yeah
Mostly due to BiggerLobbies, afaik
no, bepinex is /s
(i actually have no idea what mods use lcapi, sorry)
lol
I just do stuff myself
mostly biggerlobby/brutalcompany + forks
in reality i have no idea what lc api does, since the only time i looked at it was back when the assetbundle issues were happening
Like, a good 95% of its download count came from BiggerLobbies as far as I recall. No clue what uses it nowadays.
bigger lobby has 4mil, LCAPI is nearing 10 mil I think
how does it have twice the downloads of bepinex what the fuck
bepinex is never updated
And the early days of that mod, and LC_API had a fair bit of drama / questionability. I can attest that that left a "Eh, probably won't touch it" impression on me at least. (No hard feelings, y'all are doing cool stuff nowadays)
every update counts as a redownload
I figure it's probably a similar sentiment with others tbh
That's... huh
yeah, I'm on the same boat
tend to avoid any dependencies tbh
another reason for high download count is the fact that it is at the top of the list in the first place
everyone adds it to their modpacks for no reason
because people just mass add anything at the top lmao
I'm just trying to provide a high level api that will prevent mods from breaking when the game updates lol
that is my only goal atm
day can attest to that lol
Let's get back on topic, though.
What should I name the mod & repo? 
PluginChecker?
RequirementsChecker?
Modded Lobbies?
but yeah, i think a standalone mod which is added as a "dependency" by the main API mods will be a good solution. as long as it won't do anything that will easily break other mods
make it seem more necessary to get it out there
If major APIs add it as dependency, it'll get it out there
i can add it to biggerlobby
Are you maintaining BiggerLobby? 
barely
Huh, the more you know
i forgot biggerlobby existed 😭
This would require everyone in the server to download it, to work properly, right?
If no required mods that use it are found, it won't do anything (to connectivity)
lobby type 3 here would let it retain compatibility with older versions/people who don't have the compatibility mod
i think it won't be pushed to the top though
ModdedLobbies, then?
i guess if it's making lobbies unjoinable to vanilla it will break if you're not hosting though
the best name would be CompatibilityChecker but thats taken 
maybe remove the "unjoinable to vanilla" bit in private lobbies
It'd only do that if a required mod is found
So if you're using it, and no required mods are installed, it won't block vanilla
i guess updated required mods would depend on the mod
I'm just asking because soon the vanilla compatibility of LCAPI will probably be deprecated and eventually removed since it's just causing me great pain in implementing server-related things and networking them lol
idk ModdedLobbies doesn't sound like a library to me
i don't have any great ideas though
Agreed
"Requirements"
dev name time until someone comes up with something

lol
LethalCompatibility, LobbyCompatibility
"NoMoreLobbyPain"
once this is done you can probably just remove it
Lethal is the least searchable mod name prefix
i regret naming lethalthings lethalthings
if you search lethal you do not find it lol
you really chose the most 2 generic words for that huh
lol ye
Alright, I need a dev name
fun fact, if you search lethal things on google my mod shows up before the poison control information page
classic
Ah yes
CompatWombats
LobbyCompatibility seems fine for a dev name
maybe LobbyLibrary because it sounds goofy
BetterCompatibility doesn't sound "OH I URGENTLY NEED THIS" enough to me
sounds more like an improvement
INSTALL_OR_DIE
The ServerMustHaveMod enum would have a pretty niche use case, but still something mods using NamedMessages could use.
The talk about the mod/lib potentially making non-modded players unable to find the lobbies is slightly problematic imo, a potential fix for this would be to check if a host only has client side mods/noneedforsync mods and setting the lobby to public instead of it being hidden, and only hide it when the host has a server-side/needsync mod.
For the weekly trials, the only ideas I have with them are pretty intrusive:
eg:
- Allow server-sided/server and client must have mods but not client side ones (unless if the host allows it via a checkbox)
- If a user has the mod, they won't be able to join weekly challenges unless if the server meets specific conditions such as: Host has the mod, and allows client-side mods
These ideas will overcomplicate how server listing works, and is still pretty flawed. Just my ideas though 😊
yeah i'm not really sure the best method for dealing with weekly trials
ideally people won't get mad and be like "oh, i'm not depending on this because I want to my users to be able to do weekly trials"
but realistically, you probably just shouldn't be able to do the weekly trials with mods
or at the least if you have any mods, the leaderboards should be completely separate
somebody could always ask zeekerss how they want things handled too
no way for us to stop cheaters, but we could at least prevent people accidentally doing it
agreed that lobbies should probably only be hidden if you have mods that need syncing
The talk about the mod/lib potentially making non-modded players unable to find the lobbies is slightly problematic imo, a potential fix for this would be to check if a host only has client side mods/noneedforsync mods and setting the lobby to public instead of it being hidden, and only hide it when the host has a server-side/needsync mod.
This was already the plan.
although I do want to keep vanilla and modded mostly separate, the ideal situation IMO would be a "modded lobby" toggle in vanilla that's off by default
was looking through game files to see how the leaderboard is added to; found out you can predict the seed used for each week
is there a way to add custom leaderboards that will never be rolled in vanilla ooc
Likewise with the fixes to determinism I did
Maybe?
No clue how the Steam API works for that
What do we want as attribute name btw?
To summarise
just NetworkCompatibility would work fine if we're rolling clientside/serverside/everyone IMO
- Server/Clientside compatibility enum
- Version compatibility enum
Thoughts on [LobbyCompatibility(...)]?
lobby compatibility sounds nice
Or do we want to use [NetworkCompatibility(...)]?
i think lobbycompatibility would work, but I don't think that should be the attribute name if that's the final library name
i do like it a bit better than NetworkCompatibility though
name lib this, use LobbyCompatibility attribute
🤔 looking through the challenge file stuff, currently only see it saving the file as LCChallengeFile, haven't found any method to add to some sort of leaderboard yet
leaderboard could be a prefab
No idea how the leaderboard actually works. I haven't even seen it ingame yet 😂
could maybe just replace the leaderboard element entirely rather than hook into it?
Thoughts on this?
/// <summary>
/// Specifies the compatibility level of the plugin.
/// </summary>
public enum CompatibilityLevel
{
/// <summary>
/// Mod only impacts the client.
/// Mod is not checked at all, VersionStrictness does not apply.
/// </summary>
ClientOnly = 0,
/// <summary>
/// Mod only impacts the server, and might implicitly impact the client without the client needing to have it installed
/// for it to work.
/// Mod is only required by the server. VersionStrictness does not apply.
/// </summary>
ServerOnly = 1,
/// <summary>
/// Mod impacts both the client and the server, and adds functionality that requires the mod to be installed on both.
/// Mod must be loaded on server and client. Version checking depends on the VersionStrictness.
/// </summary>
ClientServer = 2,
/// <summary>
/// If mod is loaded on the client, it must be loaded on the server. Not every client needs to have the mod installed.
/// Fairly niche and only applies if your mod works fine when a client doesn't have it. Version checking depends on the
/// VersionStrictness.
/// </summary>
ServerIfClient = 3
}
Slightly more explicit naming
It basically boils down to the server needing the mod if the client has it
But not the client if the server has it
I feel, for our purposes, it's clear enough?
yup got that part, the name of it is still confusing when you look at it for the first time without reading the summary
so I'll have a few mods that fit either ClientOnly or ClientServer depending on a config option. Would I be able to set this variable around the same time as the config option?
Hm
hmm, ServerOnly makes me think "this will break things if used on the client"
maybe OnlyRequiredOnServer ?
I like EveryoneMustHaveMod better than ClientServer because it's more immediately obvious what it means
It has a summary
I hope modders read those when working with something like a compatibility flag
Maybe I should rename the enum to "RequiredLevel"?
ideally yes but I do not have faith everyone will lol
What is "ServerMustHaveMod" though
Is that server-only required?
Or required if the client has it?
That feels more confusing to me imo
server must have mod is like this:
- Server can have the mod but it wont be intrusive to those that dont have it, but its functionality wont work for them
and those that have the mod will be able to use its specific functionality
so the config options are defined at Awake and then used later to determine whether or not to load in/spawn the netobject https://github.com/darmuh/TerminalStuff/blob/f862568c599b32ef54aa9f6f12cc84ff9179f2b4/DarmuhsTerminalCommands/netObject.cs#L15
its like a gatekept function 😂
trying to figure out where that would fit in here
We can probably sort this out, yeah
Perhaps another enum that implies the mod has a method?
okay i think I found the leaderboard part
Or I can add an interface
i think what you posted would be fine if you renamed ClientServer to EveryoneMustHaveMod/RequiredByEveryone/RequiredByAll or something
Ok cool, I figure I wont be the only person to try this to make their mod as compatible as possible in various situations
I have it planned for another mod i'm working on too
/// <summary>
/// Specifies the compatibility level of the plugin.
/// </summary>
public enum CompatibilityLevel
{
/// <summary>
/// Mod only impacts the client.
/// Mod is not checked at all, VersionStrictness does not apply.
/// </summary>
ClientOnly = 0,
/// <summary>
/// Mod only impacts the server, and might implicitly impact the client without the client needing to have it installed
/// for it to work.
/// Mod is only required by the server. VersionStrictness does not apply.
/// </summary>
ServerOnly = 1,
/// <summary>
/// Mod impacts both the client and the server, and adds functionality that requires the mod to be installed on both.
/// Mod must be loaded on server and client. Version checking depends on the VersionStrictness.
/// </summary>
Everyone = 2,
/// <summary>
/// If mod is loaded on the client, it must be loaded on the server. Not every client needs to have the mod installed.
/// Fairly niche and only applies if your mod works fine when a client doesn't have it. Version checking depends on the
/// VersionStrictness.
/// </summary>
ServerIfClient = 3
}
?
that seems fine
it's probably worth asking everyone who's given feedback to 1 billion percent solidify the names before launch, since we won't be able to change them
but that can come later
i literally have no idea how you would get the last one across. it's a weird situation
How about ClientOptional?
actually nvm, think serveronly would apply there
i like ClientOptional
the leaderboards are gonna be a pain in the but to transpile
but do you think it's theoretically possible
yes
names make it seem that way lol
- If the server has it, but the client doesn't, it's fine.
- If the client has it, the server needs it.
no, ClientOptional means if it's installed on the client it must be installed on the server
would it be? I was assuming they'd go through fine
if it has required behaviour on the client it would be Everyone
I say keep it in, and add a remark saying to only use if you know what you're doing
/// <summary>
/// Not every client needs to have the mod installed, but if it is installed, the server also needs to have it.
/// Generally used for mods that add extra (optional) functionality to the client if the server has it installed.
/// Mod must be loaded on server. Version checking depends on the VersionStrictness.
/// </summary>
ClientOptional = 3
I'm still not entirely convinced this doesn't come down to the same as ServerOnly, as far as compatibility goes 
/// <summary>
/// Mod only impacts the server, and might implicitly impact the client without the client needing to have it installed
/// for it to work.
+ /// Mod is only required by the server. VersionStrictness only applies if the mod is installed on the client.
/// </summary>
ServerOnly = 1,
Changed this for ServerOnly btw.
ik someone was mentioning a mod that works on all clients if any single client has it, and although the server doesn't require it, it could be a contender for the enum
clientoptional mod would be like
talk to server optionally, will break if server does not exist
if (server)
do some behaviour```
server only would be
```if (client)
do nothing, this doesn't matter
if (server)
do some behaviour
Fair enough
I understand the use-case
If clientoptional, still allows joins, but only join if server has it
I think we can create custom leaderboards through steam; don't quite know how steam side operates, so I'm hesitant to do so
Whereas if serverOnly, allow any joins
Yeah, I'm curious as to whether this would effectively cause problems for Zeekerss?
Though also, I kind of assume there's some kind of network guards in place?
Maybe?
i can always ask something like
We're curious if there's any way you'd prefer weekly challenge moons to be handled. We could probably do any of the following:
Option 1: Prevent anybody using any mods from entering the challenge moons at all.
Option 2: Allow people with mods to enter challenge moons, but publish results to a separate leaderboard (we think this is possible, not 100% sure)
Option 3: Do nothing and put people with mods onto the same challenge moon/leaderboards
this creates/loads leaderboards
generally(?) steam will just let you do whatever, so it would probably work
but i'm not sure
Okay, but like
Is there a "RemoveLeaderboard"?
And can modders use that?
Because it sounds very wacky right now
i hope there's no clientside removeleaderboard because that would plunge things into chaos
Like, anyone could grab that code and literally pre-make leaderboards for the next 1 million challenges
Or submit bogus results
if there's no guards in place for that, I'm honestly kind of concerned
yeah, you could probably do that
Guess you could create a private leaderboard mod 
I'll take a deep look
this sounds like a good idea
it's not really something we can stop, it's just an inherit problem with how steam leaderboards work unfortunately
i mean that's a pretty common problem in any game with leaderboards. People will always want to cheat them
I might give it a go after I'm done with this tbh
even highly competitive games have that problem with all the safeguards they have
Song 5 of the boombox in Lethal Company, 8-bitified. We makin' it outta Titan with this one.
Credit to @ZedFox for composing the original song: https://youtu.be/15JghGgECoE?si=fly162Oig0Gm7Yt7
SoundCloud: https://soundcloud.com/rockm-822270000
Bandcamp: https://rockm.bandcamp.com/
#lethalcompany #8bit #cover
i'll probably send this to zeekerss just to see if he cares
if it's a "I don't care, i'm fine with the leaderboards being kinda fucked" could just leave it as-is
it didn't seem designed to be super competitive
I know we can at least stop modded leaderboards from being sent to the steam servers (if they have this mod)
Does he actually reply to you?
In DMs?
idk about dms
nah i just pinged him in his server before with an official-ish looking question
idk if he'll actually reply i'm sure he's flooded
I swear to god, I don't know what I've done, but by all accounts he seems to ignore me 😅
you aren't bobbie
he answered me once in the bug reports channel on his discord when I brought up an update broke kicking functionality completely
Genuinely - no clue what I've done, but I haven't received any replies in public either
i doubt you've done anything he's probably just insanely flooded
oh was that you
Maybe? Idk, kind of feel like I somehow annoyed him or something
Genuinely no clue what it could have been though
Anyway
Back to programming
yea back then I had literally just got done working on a terminal kick command and the game update broke it 
/// <summary>
/// Specifies the compatibility of a plugin.
/// </summary>
/// <example>
/// <code>
/// [LobbyCompatibilityAttribute(CompatibilityLevel.ServerOnly, VersionStrictness.Minor)]
/// class MyPlugin : BaseUnityPlugin
/// {
/// }
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Class)]
public sealed class LobbyCompatibilityAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="LobbyCompatibilityAttribute" /> class.
/// </summary>
/// <param name="compatibilityLevel">The compatibility level.</param>
/// <param name="versionStrictness">The version strictness.</param>
public LobbyCompatibilityAttribute(CompatibilityLevel compatibilityLevel = CompatibilityLevel.ClientOnly,
VersionStrictness versionStrictness = VersionStrictness.None)
{
CompatibilityLevel = compatibilityLevel;
VersionStrictness = versionStrictness;
}
/// <summary>
/// Gets the compatibility level.
/// </summary>
/// <value>
/// The compatibility level.
/// </value>
public CompatibilityLevel CompatibilityLevel { get; }
/// <summary>
/// Gets the version strictness.
/// </summary>
/// <value>
/// The version strictness.
/// </value>
public VersionStrictness VersionStrictness { get; }
}
Thoughts?
lgtm
do you think doing just CompatibilityLevel with no VersionStrictness should be a supported usecase
or should we force the modder to define that so they know the behaviour
oh, i see, i didn't read the constructor close enough
the default versionstrictness should probably be Minor
[LobbyCompatibility(ClientOnly)] // normal client only behaviour, same for serveronly
[LobbyCompatibility(Everyone)] // should be the default VersionStrictness, ideally "Minor" from conversation earlier
Should the default be minor? 
conversation is up here #1194412635932856440 message
I feel like if we're setting the compat level the lowest by default, the version strictness should be as well?
hmm
i think if I did [LobbyCompatibility(Everyone)] I would expect some version checking by default
I can also just remove the defaults
I was about to say if we don't have defaults it'll cause issues with adoption potentially, but then I realized the default of ClientOnly would practically be the same as no default
ye
Just got back, are we removing the fourth enum to replace it with serveronly?
I believe not
Nah there was just a bit of confusion on the usecase
ah alright. ill be back reading again 😸
Repo is up
do we want to prevent leaderboard upload in this or not?
leaderboard prevention is simpler
Not sure if that's within scope for this mod tbh?
a sperate leaderboard is 🫠
Actually
Separate leaderboard might be a simple one
A single transpiler to change the leaderboard string to something like modded_(original)
yeah
oh thats great then
If a plugin is added that is >= serverside, use the custom leaderboard
Can do
Can you make an issue for this? @lament perch
yep, may even begin work on it
I'd like to use enums for lobby data keys, to keep it simple:
/// <summary>
/// Metadata keys for use when setting lobby data.
/// </summary>
public static class LobbyMetadata
{
/// <summary>
/// The tag for the lobby name.
/// </summary>
public const string Name = "name";
/// <summary>
/// The tag for the host's game version.
/// </summary>
/// <remarks>
/// Users who try to join compare against this. Mismatches cause a failure to join.
/// This should generally not be overridden.
/// </remarks>
public const string Version = "vers";
/// <summary>
/// The tag for the lobby being joinable for vanilla clients.
/// </summary>
public const string Joinable = "joinable";
/// <summary>
/// The tag for the lobby being modded.
/// </summary>
public const string Modded = "modded";
/// <summary>
/// The tag for the lobby being joinable for modded clients.
/// </summary>
public const string JoinableModded = "_joinable";
/// <summary>
/// The tag for plugin information.
/// </summary>
public const string Plugins = "plugins";
}
Ah, heh, was about to start myself
You wanna go for it?
sure
I'll look into leaderboards to real quick just to make sure it's okay to do so
Sounds good!
Everyone happy with these tags? @lament perch @cyan flame
@humble elm
The top 3 are vanilla tags, the bottom 3 are tags we would use
looks good
if it seems easy we might as well have it on hand
we can always choose not to
@cyan flame
ye
i'll see if zeekerss responds, if not I think we should default to seperate leaderboard
no leaderboard at all seems a bit overkill to me, but if he wants that done it'll happen
got as far as an external call to steam_api64, but that dll is unmanaged & giving me issues
Doesn't Steam have docs?
I'll look at steam docs 
Steamworks is a set of APIs made available by Valve to allow developers to create integrations with Steam.
This ranges from the simple things like getting the local player's name, to more complicated things like server lists and UGC (Workshop Stuff)...
there's these too for the library that's being used
Steam docs:
You must call either this or FindLeaderboard to obtain the leaderboard handle which is valid for the game session for each leaderboard you wish to access prior to calling any other Leaderboard functions.
Leaderboards created with this function will not automatically show up in the Steam Community. You must manually set the Community Name field in the App Admin panel of the Steamworks website. As such it's generally recommended to prefer creating the leaderboards in the App Admin panel on the Steamworks website and using FindLeaderboard unless you're expected to have a large amount of dynamically created leaderboards.
You should never pass k_ELeaderboardSortMethodNone for eLeaderboardSortMethod or k_ELeaderboardDisplayTypeNone for eLeaderboardDisplayType as this is undefined behavior.
was looking through that dll
so I think we can
but it's iffy
Let's test it ✨
only one way to know
Does your IDE toss you some kind of "Delete" or "Remove" method btw?
i looked through and didn't see one in the leaderboard area
The docs don't mention one
That makes me concerned as to whether someone could essentially spam new leaderboards tbh
E.g. with slurs or other spam names
I think they could
want me to try with some random name?
"HiZeekerssJustTesting"? 
i mean if a user is creating a custom leaderboard i don't think it'll display
without like, a mod that redirects to that leaderboard
It won't display on the user side
But on the administration side?
Heck, what if someone creates 1 million leaderboards?
I can't imagine Steam will just go "Oh, that's fine, carry on"
I'm actually surprised there's no precedent for this
you can create leaderboards for all future weekly challenges
idk steam has like 40 billion dollars somewhere, there's probably precedent in some other game's leaderboards
i also think they can just eat whatever the cost is
Also
Low key will use this for other games now
It'd be neat to add leaderboards for some other games
steam provides a bunch of nice stuff for "free"
I need to look into it more tbh
(30% cut)
That API alone is great
same
and the stuff with The Day Before
Can we add Newtonsoft.Json somehow? 
steam themselves refunding all buyers
wdym?
newtonsoft ships with the game
^
it does
Lmfao
I use it for my networking api
We actually went through some trouble to add it to the dll for LethalAPI when we were messing with this
Dear god
I should have just checked the Managed folder
xd
classic blunder
if you need to use unity types with newtonsoft I found some random solution on the internet that works
fyi @sharp ridge you can just set the main plugin class with the internal attribute modifier and just refer to it as Plugin or whatever class name you want internally
Wdym?
I set it as public so other mods can touch it if necessary
I do the same with all of my mods tbh
do they need to touch the plugin class?
They need to be able to access the instance inside of it, if they want to touch it in whatever way
oh yeah ryoo sent me some stuff that could be useful to you @sharp ridge #dev-general message
I was just going to use the GUID based on the ChainLoader's plugins list
that works
I am confusion
public class LobbyCompatibilityPlugin : BaseUnityPlugin
{
public static LobbyCompatibilityPlugin? Instance { get; private set; }
^
maybe don't know enough about modding, but again, why do they need access to the instance?
hmm
If they need to, I'd rather I make it easily accessible that force some wacky shenanigans
It doesn't change anything for development on my end
I might reflect to do the same with my mods then
just leads to longer typing and I couldn't be bothered at first
i leave mine as public because that's what the template does
lmk once you have some of the basic patches ported over @sharp ridge i'll see if I can cook up some UI
(unless you were going to do that already)
max, you're killing me
you don't even have an assembly-csharp reference or lord's game libs yet xd
Right, about that
I was going to use environment variables
But I was wondering what y'all think is best?
if gamelibs works i would just use that
is lord's actually finished
I think it''s called dehumidifer
I seem to have missed something
Huh, damn
what's the difference between this and the other gamelibs
Are we sure this is good?
lord made it
@dusty root opinions if you're on
publicizes assembly-csharp
realized slight issue with leaderboard stuff, I'll look into it
You wanna add Lord's stuff in a quick PR? @lament perch
made @sharp ridge
Right, these are also stripped
Hm
That's mildly annoying for checking things with Rider's decompiler tbh
Wasn't there some kind of user-specific csproj system you can use to override things locally? @lament perch @cyan flame
you can use .csproj.user files
yeah
i think one of xilo's repos did that
I can set you up
Please do, I love the idea of these publicised, stripped assemblies for general project management / collaboration, but I personally prefer being able to jump into the decompiled source using Rider and having a read :P
@sharp ridge instuctions only in pr, but added
user file will also automatically add your (debug) built assembly & pdb to your plugin folder (unless you remove that portion)
I'll probably make a Record to store the plugin information, like I did for LethalAPI.
I'll add:
- GUID
- Version
- Compatibility Enum
- Version Strictness Enum
@lament perch @cyan flame
for internal use or for plugins to define
For internal use
To serialise and unserialise / compare to
So we serialise a list of those for plugin information
IRL?
ye
RIP
went long enough to turn off my monitor for a sec but not long enough to turn off my pc
issue isn't even power going out, just power flicker
we got a generator here just cause it's the boonies
oh yeah my power's been going out intermittently in wa
storm went through today in ga
maybe overkill but dll hash?
Seems overkill tbh
would probably be only useful if we added a like
Could be added as a check and logged as a warning?
"MAXMIMUM COMPATIBILITY EMERGENCY MODE", I wouldn't worry about it for now
who wants to send checksums that may be incorrect /s-ish
thankfully no modders have ever updated their mod without changing the internal version
in the manifest, not the dll
which method
MenuManager.GetLeaderboardForChallenge
and RemoveLeaderboardScore as well
I got async IL lmao
ik there's a harmonyx helper for enumerators
but I don't think this counts
may have found a solution
Please use a CodeMatcher
It's clean, easy to maintain, and less prone to user error
What's there to dislike?
@lament perch @cyan flame
Clean this up ✨
if (pluginInfo.Any(plugin => plugin.CompatibilityLevel is CompatibilityLevel.ServerOnly
or CompatibilityLevel.Everyone or CompatibilityLevel.ClientOptional) &&
!lobby.GetData(LobbyMetadata.Name).Contains("modded"))
lobby.SetData(LobbyMetadata.Name, "modded // " + lobby.GetData(LobbyMetadata.Name));
I swear to god, I've put it into curly braces, but Rider insists on making it as compact as possible

if (!lobby.GetData(LobbyMetadata.Name).Contains("modded") && pluginInfo.Any(plugin => plugin.CompatibilityLevel is not CompatibilityLevel.ClientOnly))
{
lobby.SetData(LobbyMetadata.Name, "modded // " + lobby.GetData(LobbyMetadata.Name));
}
tbf it assumes we won't add more compatibility levels
that would affect that at least
(which we probably won't but idk)
Yeah, that was my reasoning for being explicit
wdym
As in, like I've been doing here:
/// <summary>
/// Patches <see cref="GameNetworkManager.SteamMatchmaking_OnLobbyCreated" />.
/// Adds extra lobby metadata to be used for dependency checking.
/// </summary>
/// <seealso cref="GameNetworkManager.SteamMatchmaking_OnLobbyCreated" />
[HarmonyPatch(typeof(GameNetworkManager), nameof(GameNetworkManager.SteamMatchmaking_OnLobbyCreated))]
[HarmonyPriority(Priority.Last)]
[HarmonyWrapSafe]
internal static class SteamMatchmakingOnLobbyCreatedPostfix
{
[HarmonyPostfix]
private static void Postfix(Result result, ref Lobby lobby)
{
// lobby has not yet been created or something went wrong
if (result != Result.OK)
return;
var pluginInfo = PluginHelper.GetAllPluginInfo().ToList();
// Modded is flagged as true, since we're using mods
lobby.SetData(LobbyMetadata.Modded, "true");
// Add plugin metadata to the lobby so clients can check if they have the required plugins
lobby.SetData(LobbyMetadata.Plugins, PluginHelper.GetLobbyPluginsMetadata());
// Set the joinable modded metadata to the same value as the original joinable metadata, in case it wasn't originally joinable
lobby.SetData(LobbyMetadata.JoinableModded, lobby.GetData(LobbyMetadata.Joinable));
// Add a prefix to the lobby name to indicate that it's modded, if it doesn't already have some kind of modded mention
if (pluginInfo.Any(plugin => plugin.CompatibilityLevel is CompatibilityLevel.ServerOnly
or CompatibilityLevel.Everyone or CompatibilityLevel.ClientOptional) &&
!lobby.GetData(LobbyMetadata.Name).Contains("modded"))
lobby.SetData(LobbyMetadata.Name, "modded // " + lobby.GetData(LobbyMetadata.Name));
// Disable vanilla joining if any plugins are present that clients need
if (pluginInfo.Any(plugin => plugin.CompatibilityLevel == CompatibilityLevel.Everyone))
{
LobbyCompatibilityPlugin.Logger?.LogWarning(
"You are hosting a lobby with plugins required by everyone. Disabling vanilla clients from joining.");
lobby.SetData(LobbyMetadata.Joinable, "false");
}
}
}
Probably just because I've been doing it manually for well over 5 years in modding days lmao
switching just doesn't feel right
Gotta move along with new technology ✨
never had problems with the old ways ¯_(ツ)_/¯
I'm not generally a fan of too much in-code documentation, since it tends to become outdated if not updated diligently. But perhaps it's important for this mod?
yeah i'd say to keep things fairly documented since it's very important that it remains maintained
is it possible to patch a struct? haven't tried and having difficulty targeting it
Preference?
switch (source.VersionStrictness)
{
case VersionStrictness.None:
return true;
case VersionStrictness.Major when target.Version.Major != source.Version.Major:
case VersionStrictness.Minor when target.Version.Major != source.Version.Major ||
target.Version.Minor != source.Version.Minor:
case VersionStrictness.Patch when target.Version != source.Version:
return false;
default:
return true;
}
internal static bool MatchesVersion(PluginInfoRecord source, PluginInfoRecord target)
{
if (source.VersionStrictness == VersionStrictness.None)
return true;
if (source.VersionStrictness == VersionStrictness.Major)
{
if (target.Version.Major != source.Version.Major)
return false;
}
else if (source.VersionStrictness == VersionStrictness.Minor)
{
if (target.Version.Major != source.Version.Major ||
target.Version.Minor != source.Version.Minor)
return false;
}
else if (source.VersionStrictness == VersionStrictness.Patch)
{
if (target.Version != source.Version) return false;
}
return true;
}
Sometimes, Rider truly suggests something I can only describe as horror 
Kinda neat you can get it that compact, though.
But I assume we're all in favour of #2?
yeah that switch case is kind of hurting my brain
I like switch statements but the second is easier to read
I didn't even know you could write switch cases like that tbh
i'm honestly not sure, i've never tried
i assume you're trying to patch a method on a struct
ye
also has the slight issue of being compiler generated, so I have to access it somehow 💀
wtf are you trying to patch
an async method
I'm trying to use harmonyx's enumerator patch thingy, but it just seems like it doesn't want to target
maybe cause it's not designed for asyncs
💀
not in the version of BepInEx we use
oh no is it bepinex 6
imma take a look at what it does tho
@lament perch @cyan flame
Please review: https://github.com/MaxWasUnavailable/LobbyCompatibility/pull/6
I'm gonna get some sleep now, since it's 6 AM
I'm sure there's some stuff in there that I'll have to fix in the morning
I've got the patches mostly moved over, but they depend on the PluginHelper
If y'all want to do a quick review, I can toss a PR up with the initial patch at least
i can find almost no info on async patching
yep
it might be reasonable/possible to do but you'd probably have to ask a bepinex person
i assume you can't just patch another submethod and it NEEDS to be a transpiler
since it's async it definitely needs to be a transpiler I believe
(also a lot of code that can cause breaking on update)
are you just trying to change the name
yep, trying to change a single string
hmm, could you prefix SteamUserStats.FindOrCreateLeaderboardAsync with like
ref name => name = name.Replace("challenge", X)
🤔
no wont work
actually also have to patch several other things in the method
relating to save files
unless I patch that too
you could just patch that too
but it starts getting real finnicky
yeah it's not ideal
if you're just looking for a POC you could just patch string.format lol
i guess if you have to change other save file things it wouldn't matter tho
I think I may have found a way to patch it, I'll https://tryitands.ee
preloader patches/monomod always an option if there's truly no way
@lament perch thoughts on https://github.com/MaxWasUnavailable/LobbyCompatibility/pull/6
sorry looked through it but got disctracted, will write in gh rq
@lament perch @cyan flame
https://github.com/MaxWasUnavailable/LobbyCompatibility/tree/feat_joinable-patches
Have a peek at the patches here
I still need to do some cleaning / testing tomorrow, but this should be roughly the logic
sure thing, I might play with the UI a bit
i will probably just buy a second copy of the game and use my steam deck unless there's a better way to test pubs lol
have friends 
The game doesn't have any copyright protection
You can just boot it up through the .exe, and connect on LAN
It's how I locally test my stuff
yeah I usually do that, I need to specifically mess with the lobby list though
don't think you can do that through LAN
...fair point
not that I've been able to do
night night
(Ping me if you need me)
nighty night
lol
need to figure out this async thing, huh
running into a confusing issue
I got the MoveNext method
which has the code I need to patch
but I get an error from harmony saying that the method is null
but I check to see if the method is null beforehand, and it isn't
nvm
im an idiot
the method I said to use to transpile was private xd
okay it works
@cyan flame
I can transpile async methods now
what's the meta
this shit

I'll comment and give text
i'm gonna have to REALLY fuck up SteamLobbyManager.LoadServerList probably
transpiling async? whuhuh
internal static void AsyncPatcher(Harmony harmony)
{
// Get the Method Info of the target Async Method; Can replace Type & Method with any async method
var getLeaderboard = AccessTools.Method(typeof(MenuManager), nameof(MenuManager.GetLeaderboardForChallenge))
// Find the AsyncStateMachine class from target method
.GetCustomAttribute<AsyncStateMachineAttribute>()
// Get the struct type (random compiler junk), and then get the <GetLeaderboardForChallenge>d__80::MoveNext
.StateMachineType.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.NonPublic);
#if DEBUG
// Make sure we get it
LobbyCompatibilityPlugin.Logger?.LogDebug($"{getLeaderboard} - {getLeaderboard == null}");
#endif
// Use a manual patch to patch the MoveNext method - transpiler must be public
harmony.Patch(getLeaderboard, transpiler: new HarmonyMethod(typeof(LeaderboardPatch).GetMethod(nameof(ModdedLeaderboards))));
}
terrifying
thank you random person
and updated harmonyx that we dont get to use
it would force everyone to use it, no?
which can cause a lot of compat. problems
Is it backwards compatible?
no
Alas
it's fairly different
if the major incremented, I assume not
What are ya trying to do?
looking into lobby filtering options for the lobbylist UI
I'm gonna make this a lib rq
Okay, back to sleep I go
yeah, i might reuse tags or add some new lobby data
it does seem like it's going to be fairly extensible
welp imma head to bed too
i'll probably cook up a concept or two but I doubt i'll get much done tonight
the sort area is already getting a bit crowded in vanilla
Feel free to look over my code - the significant stuff is in build/program.cs
the readme of the Dehumidifier describes what it does :)
Yeah they have to be stripped so I can redist :(
Hang on, you might be interested in my project setup
'network syncing lib'? What are we network syncing
in terms of mod compatability, Lc-api has an open issue for networkcompatability
the title kind of sucks. it's for lobby compatibility with different mods though
that's basically what this is
i think ideally it's separate and fairly light, to make as many people as possible depend on it
but that's the thing, people just won't
oh yeah we won't be able to get everyone
it's not possible at this point
but like, maximize the amount of people who are willing
whereas if it's a feature integrated into a helpful API that is used for its other features
but
what we could do is make it separate
and then have lcapi depend on it
yeah, agreed
that's probably the best of both worlds
hmmm
@dense forum I think lcapi needs to become separate modules
because this would benefit from making use of lcapi networking
specifically the custom net messages
tbh we can do everything with custom lobby data, it's not really necessary
true
I dunno, I kinda prefer the Forge approach
Which is a superset of that
- lobby data to provide info prior to connect
- attempting to connect is allowed in some cases even if lobby data implies incompatibility (because this mod, and mod authors are fallible)
- host options for allowing/disallowing incompatible clients and what counts as incompatible
- on connect, the host checks the modlist and rejects connection if it fails verification
i posted some concepts a bit higher up in the chat
#1194412635932856440 message
[WIP] Proposed Lobby Mod List Syncing Library
yeah the concept looks great
I still stand by this
in terms of behaviour
this is all I have so far, i'll go ahead and push it before sleeping though
the join button is REALLY wide, it's going to be kind of annoying to work around
either we're going to have to accept a massive gap, move it slightly, or scale it down horizontally
@sharp ridge i forsee needing to get/otherwise use lobby mod data in the following places:
SteamLobbyManager.LoadServerListfor filtering lobbies initially. probably will ask steam to check for_joinableto filter out vanilla lobbies, if the user requests itSteamLobbyManager.loadLobbyListAndFilterfor displaying the above lobby data (is state Compatible/Incompatible/Unknown?)- Need diff data whereever we decide to hook up that modal where the question mark is currently
- Need diff data if join failed (even if lobby was labeled compatible, failures can happen)
so, ideally we'd have some diff/status that's cached per lobby id so we don't have to keep calculating it
Can I also recommend following Jotunn's lead on the enums
CompatabilityLevel
NotEnforced: The compatibility check ignores if the mod is installed or not and also does not check the version at all. VersionStrictness value is ignored.
VersionCheckOnly: The compatibility check ignores the mod if it is not installed on both sides. If it is installed on both sides the version is checked according to the VersionStrictness value.
EveryoneMustHaveMod: It is checked if the mod is installed and if the version matches the requirements of the VersionStrictness value.
ClientMustHaveMod: If the mod is installed on the server, every client must have it, too. VersionStrictness does apply when installed on both sides.
ServerMustHaveMod: If the mod is installed on the client, the server must have it, too. VersionStrictness does apply when installed on both sides.
I think it would be good to use consistent naming across the communities
oh ServerMustHaveMod is a lot more understandable than what we have rn lol
I agree with this since we already have the same enums basically
Oh btw, slightly off topic but I would suggest to have a toggle for a functionality wherein:
If the game updates to a new version/version number changes the mod will revert all its changes to vanilla functionality unless the user enables the config to allow for possible issues (if a game update breaks the mod for example),
Ideally if this config is toggled off by default and the game updates, it will show a notification that the mod functionality is disabled, and how to enable it if you want
This would lead to people not using mod managers to be informed whether or not to update the mod in the future
I'm half beginning to think that it may just be worth it to stop updating LC API and move to a new project so that LC API doesn't break any more and we can start with a proper fragmented framework essentially releasing each root namespace as a different package
no matter what I do with LC API it will break pretty much every plugin using it if I make an update like this
at least separating the server sided stuff from the client sided stuff
you could just keep publishing it to two places 🤣🤣
one that appears unaffiliated to lcapi
But yeah, I get what you're saying
it's probably a good idea
idk what I'd call the new library tho
valheim kinda has a Viking setting
and jotunn is a mythical creature from germaic (Viking, I think) mythology
you could go the Minecraft route and call it Lethal_Forge 😂
What if I called it "Experimentation" lol
you can't just drop that and not say your idea
he sent it to me lol
I had to secure the namespaces and stuff hahaha
lol ok
I wanna know what it's called now xd
Perfectly understandable, no worries!
That was the idea behind LethalAPI, originally. Fragmented small libraries under the same top level namespace, but different repos and hence easier to keep most of the library working between updates.
That was the idea already, yeah 😄
We had a discussion about it a couple hundred messages up
this leaderboard patch sort is larger than I first though lol
Can't we use hover / overlayed UI elements? If the empty space is a problem?
I think
would work
Can patch that later today
we could, but overlaying on top of the join button probably won't be feasible (it's so wide)
hover is a good option but coding that without assetbundles would be fairly annoying
nice room name
oh yeah i didn't even check it
Would it be?
Rectangle with some text
i could do it, creating new UI elements through code only is a lot of trial and error though
recttransforms were NOT meant to be fucked with through code
i mostly just didn't feel like it last night. i'll see about today
it would need to do this thing too
Easy enough, no?
ye
Create the rect separately
Could always just opt to always place it in the top right, as well
Or left side?
Actually, left side might be best?
So you can go through the joins
Far more space to work with, as well
hmm, i'll see how it looks (and how wide it ends up being)
there is a lot of empty space towards the right
Could put a disclaimer / info over there?
E.g. ⚠️ means X
Yeah, I need to cook up some icons
Do y'all generally agree that we should try to avoid using assetbundles for maintainability reasons
Should be able to convert an embedded dll PNG to a sprite at runtime
That's what most beat saber mods do for UI
Is there a reason you're trying to avoid asset bundles?
anytime you want to update something with ui or whatnot, you don't have to go into unity to update accordingly
I would ideally like things to be maintainable with as little specific knowledge as possible
If you ever need to update UI, you'll have to install unity/update things in there/create a new bundle
If it becomes necessary I don't mind using bundles, I don't think there's gonna be much UI though
Yes please
I can help with programmatical UIs if we want
I've done a little bit of work with it
@sharp ridge have you had any luck with transpilers working with the mod? currently trying to transpile, seems like it is running, but no noticible changes nor DumpedAssembly show up
my transpiler has worked fine
🤔
[HarmonyPatch]
[HarmonyPriority(Priority.First)]
[HarmonyWrapSafe]
internal class LoadLobbyListAndFilterTranspiler
{
[HarmonyTargetMethod]
private static MethodBase TargetMethod()
{
return AccessTools.EnumeratorMoveNext(AccessTools.Method(typeof(SteamLobbyManager), nameof(SteamLobbyManager.loadLobbyListAndFilter)));
}
[HarmonyTranspiler]
static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
// The method used to get the LobbySlot after instantiation (yes, it's accessed through GetComponentInChildren)
var lobbySlotMethod = AccessTools.Method(typeof(GameObject), nameof(GameObject.GetComponentInChildren), new Type[0], new Type[] { typeof(LobbySlot) });
return new CodeMatcher(instructions)
.SearchForward(instruction => instruction.Calls(lobbySlotMethod))
.ThrowIfInvalid("Could not find LobbySlot method")
.RemoveInstructions(1)
.Insert(new CodeInstruction(
OpCodes.Call,
AccessTools.Method(typeof(LoadLobbyListAndFilterTranspiler), nameof(InitializeLobbySlot))))
.InstructionEnumeration();
}```
make sure all the necessary attributes are in the proper place ig
[HarmonyPatch(typeof(MenuManager), nameof(MenuManager.SetIfChallengeMoonHasBeenCompleted))]
[HarmonyPriority(Priority.First)]
[HarmonyWrapSafe]
public class LeaderboardPatch
{
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
LobbyCompatibilityPlugin.Logger!.LogDebug("Attempting to change save file");
// For all instructions, do this: (for each)
var newInstructions = instructions.Select(codeInstruction =>
{
// If the operand is "LCChallengeFile", replace it with "LCModdedChallengeFile", otherwise leave as is
codeInstruction.operand = codeInstruction.Is(OpCodes.Ldstr, "LCChallengeFile")
? "LCModdedChallengeFile"
: codeInstruction.operand;
return codeInstruction;
}
);
newInstructions.Do(inst => LobbyCompatibilityPlugin.Logger.LogDebug(inst));
return newInstructions;
}
}
(mostly) what I got rn, I can see debug output, but it just doesn't seem to actually do anything in game
is it actually modifying the IL
I see the updated values in the output
[Debug :LobbyCompatibility] ldstr "SetChallengeFileMoney"
[Debug :LobbyCompatibility] ldc.i4.0 NULL
[Debug :LobbyCompatibility] ldstr "LCModdedChallengeFile"
[Debug :LobbyCompatibility] call static void ES3::Save(string key, bool value, string filePath)
[Debug :LobbyCompatibility] ldstr "ChallengeWeekNum"
[Debug :LobbyCompatibility] ldloc.0 NULL
[Debug :LobbyCompatibility] ldstr "LCModdedChallengeFile"
[Debug :LobbyCompatibility] call static void ES3::Save(string key, int value, string filePath)
[Debug :LobbyCompatibility] ldstr "FinishedChallenge"
[Debug :LobbyCompatibility] ldc.i4.0 NULL
[Debug :LobbyCompatibility] ldstr "LCModdedChallengeFile"
[Debug :LobbyCompatibility] call static void ES3::Save(string key, bool value, string filePat
What issues are you having with transpilers?
The async method?
just a normal transpiler in general
it's called, gets the right info, modifies the IL, but it seems like the IL isn't actually modified in-game
just as a sanity check, if you set your bepinex cfg to dump the assemblies, it dumps Assembly-CSharp right?
i think that's just for preloader patches
not harmony
I may have been dumb then, lemme check some'in rq




